libfilezilla
writer.hpp
Go to the documentation of this file.
1 #ifndef LIBFILEZILLA_AIO_WRITER_HEADER
2 #define LIBFILEZILLA_AIO_WRITER_HEADER
3 
10 #include "aio.hpp"
11 #include "../buffer.hpp"
12 #include "../file.hpp"
13 #include "../thread_pool.hpp"
14 
15 #include <list>
16 
17 namespace fz {
18 
27 class FZ_PUBLIC_SYMBOL writer_base : public aio_base, public aio_waitable
28 {
29 public:
30  writer_base(writer_base const&) = delete;
31  writer_base& operator=(writer_base const&) = delete;
32 
34  virtual aio_result preallocate(uint64_t /*size*/) { return aio_result::ok; }
35 
46  aio_result add_buffer(buffer_lease && b, event_handler & h);
47 
58  aio_result finalize(event_handler & h);
59 
61  virtual bool set_mtime(datetime const&) { return false; }
62 
63  void close();
64 
75  using progress_cb_t = std::function<void(writer_base const*, uint64_t written)>;
76 
77 protected:
78  virtual aio_result do_add_buffer(scoped_lock & l, buffer_lease && b) = 0;
79  virtual aio_result do_finalize(scoped_lock & l) = 0;
80 
81  writer_base(std::wstring && name, aio_buffer_pool & pool, progress_cb_t && progress_cb, size_t max_buffers) noexcept
82  : buffer_pool_(pool)
83  , name_(name)
84  , progress_cb_(std::move(progress_cb))
85  , max_buffers_(max_buffers ? max_buffers : 1)
86  {}
87 
88  writer_base(std::wstring_view name, aio_buffer_pool & pool, progress_cb_t && progress_cb, size_t max_buffers) noexcept
89  : buffer_pool_(pool)
90  , name_(name)
91  , progress_cb_(std::move(progress_cb))
92  , max_buffers_(max_buffers ? max_buffers : 1)
93  {}
94 
95  virtual void do_close(scoped_lock &) {}
96 
97  mutex mtx_;
98  aio_buffer_pool & buffer_pool_;
99 
100  std::wstring const name_;
101 
102  progress_cb_t progress_cb_;
103 
104  size_t const max_buffers_{};
105  std::list<buffer_lease> buffers_;
106 
107  bool error_{};
108  uint8_t finalizing_{};
109 };
110 
112 class FZ_PUBLIC_SYMBOL writer_factory
113 {
114 public:
115  explicit writer_factory(std::wstring const& name)
116  : name_(name)
117  {}
118  explicit writer_factory(std::wstring && name)
119  : name_(std::move(name))
120  {}
121 
122  virtual ~writer_factory() noexcept = default;
123 
125  virtual std::unique_ptr<writer_factory> clone() const = 0;
126 
134  virtual std::unique_ptr<writer_base> open(aio_buffer_pool & pool, uint64_t offset = 0, writer_base::progress_cb_t progress_cb = nullptr, size_t max_buffers = 0) = 0;
135 
136  std::wstring const& name() const { return name_; }
137 
139  virtual bool offsetable() const { return false; }
140 
142  virtual uint64_t size() const { return writer_base::nosize; }
143  virtual datetime mtime() const { return datetime(); }
144 
146  virtual size_t min_buffer_usage() const { return 1; }
147 
149  virtual bool multiple_buffer_usage() const { return false; }
150 
151  virtual size_t preferred_buffer_count() const { return 1; }
152 
158  virtual bool set_mtime(datetime const&) { return false; }
159 protected:
160  writer_factory() = default;
161  writer_factory(writer_factory const&) = default;
162 
163 private:
164  std::wstring const name_;
165 };
166 
167 class FZ_PUBLIC_SYMBOL writer_factory_holder final
168 {
169 public:
170  writer_factory_holder() = default;
171  writer_factory_holder(std::unique_ptr<writer_factory> && factory);
172  writer_factory_holder(std::unique_ptr<writer_factory> const& factory);
173  writer_factory_holder(writer_factory const& factory);
174 
176  writer_factory_holder& operator=(writer_factory_holder const& op);
177 
179  writer_factory_holder& operator=(writer_factory_holder && op) noexcept;
180  writer_factory_holder& operator=(std::unique_ptr<writer_factory> && factory);
181 
182  writer_factory const* operator->() const { return impl_.get(); }
183  writer_factory* operator->() { return impl_.get(); }
184  writer_factory const& operator*() const { return *impl_; }
185  writer_factory & operator*() { return *impl_; }
186 
187  explicit operator bool() const { return impl_.operator bool(); }
188 
189  std::wstring name() const { return impl_ ? impl_->name() : std::wstring(); }
190  datetime mtime() const { return impl_ ? impl_->mtime() : datetime(); }
191  uint64_t size() const { return impl_ ? impl_->size() : aio_base::nosize; }
192 
193 private:
194  std::unique_ptr<writer_factory> impl_;
195 };
196 
197 
198 
199 class thread_pool;
200 
202 class FZ_PUBLIC_SYMBOL threaded_writer : public writer_base
203 {
204 public:
205  using writer_base::writer_base;
206 
207 protected:
208  virtual aio_result do_add_buffer(scoped_lock & l, buffer_lease && b) override;
209  virtual aio_result do_finalize(scoped_lock & l) override;
210  void wakeup(scoped_lock & l) {
211  cond_.signal(l);
212  }
213 
214  virtual void do_close(scoped_lock & l) override;
215 
216  virtual aio_result continue_finalize(scoped_lock &) {
217  return aio_result::ok;
218  }
219 
220  condition cond_;
221  async_task task_;
222 
223  bool quit_{};
224 };
225 
227 class FZ_PUBLIC_SYMBOL file_writer final : public threaded_writer
228 {
229 public:
230  file_writer(std::wstring && name, aio_buffer_pool & pool, file && f, thread_pool & tpool, bool fsync = false, progress_cb_t && progress_cb = nullptr, size_t max_buffers = 4) noexcept;
231  file_writer(std::wstring_view name, aio_buffer_pool & pool, file && f, thread_pool & tpool, bool fsync = false, progress_cb_t && progress_cb = nullptr, size_t max_buffers = 4) noexcept;
232 
233  virtual ~file_writer() override;
234 
235  virtual aio_result preallocate(uint64_t size) override;
236 
237  virtual bool set_mtime(datetime const&) override;
238 
239 private:
240  virtual void FZ_PRIVATE_SYMBOL do_close(scoped_lock & l) override;
241  virtual aio_result FZ_PRIVATE_SYMBOL continue_finalize(scoped_lock & l) override;
242 
243  void FZ_PRIVATE_SYMBOL entry();
244 
245  file file_;
246 
247  bool fsync_{};
248  bool preallocated_{};
249 };
250 
251 enum class file_writer_flags : unsigned {
252  fsync = 0x01,
253  permissions_current_user_only = 0x02,
254  permissions_current_user_and_admins_only = 0x04
255 };
256 inline bool operator&(file_writer_flags lhs, file_writer_flags rhs) {
257  return (static_cast<std::underlying_type_t<file_writer_flags>>(lhs) & static_cast<std::underlying_type_t<file_writer_flags>>(rhs)) != 0;
258 }
259 inline file_writer_flags operator|(file_writer_flags lhs, file_writer_flags rhs) {
260  return static_cast<file_writer_flags>(static_cast<std::underlying_type_t<file_writer_flags>>(lhs) | static_cast<std::underlying_type_t<file_writer_flags>>(rhs));
261 }
262 
264 class FZ_PUBLIC_SYMBOL file_writer_factory final : public writer_factory
265 {
266 public:
267  file_writer_factory(std::wstring const& file, thread_pool & tpool, file_writer_flags = {});
268 
269  virtual std::unique_ptr<writer_base> open(aio_buffer_pool & pool, uint64_t offset, writer_base::progress_cb_t progress_cb = nullptr, size_t max_buffers = 0) override;
270  virtual std::unique_ptr<writer_factory> clone() const override;
271 
272  virtual bool offsetable() const override { return true; }
273 
274  virtual uint64_t size() const override;
275  virtual datetime mtime() const override;
276 
277  virtual bool set_mtime(datetime const& t) override;
278 
279  virtual bool multiple_buffer_usage() const override { return true; }
280 
281  virtual size_t preferred_buffer_count() const override { return 4; }
282 
283 private:
284  thread_pool & thread_pool_;
285  file_writer_flags flags_{};
286 };
287 
294 class FZ_PUBLIC_SYMBOL buffer_writer final : public writer_base
295 {
296 public:
297  buffer_writer(buffer & buffer, std::wstring const& name, aio_buffer_pool & pool, size_t size_limit, progress_cb_t && progress_cb = nullptr);
298 
299  virtual aio_result preallocate(uint64_t size) override;
300 
301 private:
302  virtual aio_result FZ_PRIVATE_SYMBOL do_add_buffer(scoped_lock & l, buffer_lease && b) override;
303  virtual aio_result FZ_PRIVATE_SYMBOL do_finalize(scoped_lock &) override { return error_ ? aio_result::error : aio_result::ok; }
304 
305  buffer & buffer_;
306  size_t size_limit_{};
307 };
308 
315 class FZ_PUBLIC_SYMBOL buffer_writer_factory final : public writer_factory
316 {
317 public:
318  buffer_writer_factory(buffer & b, std::wstring const& name, size_t size_limit);
319 
320  virtual std::unique_ptr<writer_base> open(aio_buffer_pool & pool, uint64_t offset, writer_base::progress_cb_t progress_cb = nullptr, size_t max_buffers = 0) override;
321  virtual std::unique_ptr<writer_factory> clone() const override;
322 
323 private:
324  buffer & buffer_;
325  size_t size_limit_{};
326 };
327 
328 }
329 
330 #endif
virtual size_t min_buffer_usage() const
The writer requires at least this many buffers.
Definition: writer.hpp:146
Definition: writer.hpp:167
Base class for all writers.
Definition: writer.hpp:27
A simple scoped lock.
Definition: mutex.hpp:116
virtual aio_result preallocate(uint64_t)
Instructs writer to preallocate storage. May be a noop.
Definition: writer.hpp:34
virtual bool set_mtime(datetime const &)
Sets the mtime of the target.
Definition: writer.hpp:158
Definition: event_handler.hpp:60
Waitable condition variable.
Definition: mutex.hpp:233
Definition: aio.hpp:202
Definition: aio.hpp:68
Handle for asynchronous tasks.
Definition: thread_pool.hpp:24
A writer factory.
Definition: writer.hpp:112
Buffer management and wait machinery for asynchronous I/O.
Represents a point of time in wallclock, tracking the timestamps accuracy/precision.
Definition: time.hpp:40
Definition: writer.hpp:315
aio_result
Result of aio operations.
Definition: aio.hpp:189
virtual bool multiple_buffer_usage() const override
Whether the writer can benefit from multiple buffers.
Definition: writer.hpp:279
A buffer pool for use with async readers/writers.
Definition: aio.hpp:106
Factory for.
Definition: writer.hpp:264
virtual uint64_t size() const
Some writers, e.g. for files, may have a pre-existing size.
Definition: writer.hpp:142
Definition: writer.hpp:294
The namespace used by libfilezilla.
Definition: apply.hpp:17
virtual bool multiple_buffer_usage() const
Whether the writer can benefit from multiple buffers.
Definition: writer.hpp:149
Lean class for file access.
Definition: file.hpp:28
Definition: aio.hpp:25
virtual bool offsetable() const override
If true, writer can be opened from any position, not just the beginning, such as file_writer.
Definition: writer.hpp:272
File writer.
Definition: writer.hpp:227
Success, proceed.
virtual bool set_mtime(datetime const &)
Must be finalized already.
Definition: writer.hpp:61
The buffer class is a simple buffer where data can be appended at the end and consumed at the front...
Definition: buffer.hpp:26
virtual bool offsetable() const
If true, writer can be opened from any position, not just the beginning, such as file_writer.
Definition: writer.hpp:139
A dumb thread-pool for asynchronous tasks.
Definition: thread_pool.hpp:63
std::function< void(writer_base const *, uint64_t written)> progress_cb_t
Definition: writer.hpp:75
Operationf failed.
Base class for threaded writer.
Definition: writer.hpp:202