// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_LIBRBD_CACHE_PWL_LOG_ENTRY_H #define CEPH_LIBRBD_CACHE_PWL_LOG_ENTRY_H #include "common/ceph_mutex.h" #include "librbd/Utils.h" #include "librbd/cache/pwl/Types.h" #include #include namespace librbd { namespace cache { class ImageWritebackInterface; namespace pwl { class SyncPointLogEntry; class GenericWriteLogEntry; class WriteLogEntry; typedef std::list> GenericWriteLogEntries; class GenericLogEntry { public: WriteLogCacheEntry ram_entry; WriteLogCacheEntry *cache_entry = nullptr; uint64_t log_entry_index = 0; bool completed = false; BlockGuardCell* m_cell = nullptr; GenericLogEntry(uint64_t image_offset_bytes = 0, uint64_t write_bytes = 0) : ram_entry(image_offset_bytes, write_bytes) { }; virtual ~GenericLogEntry() { }; GenericLogEntry(const GenericLogEntry&) = delete; GenericLogEntry &operator=(const GenericLogEntry&) = delete; virtual bool can_writeback() const { return false; } virtual bool can_retire() const { return false; } virtual void set_flushed(bool flushed) { ceph_assert(false); } virtual unsigned int write_bytes() const { return 0; }; virtual unsigned int bytes_dirty() const { return 0; }; virtual std::shared_ptr get_sync_point_entry() { return nullptr; } virtual void writeback(librbd::cache::ImageWritebackInterface &image_writeback, Context *ctx) { ceph_assert(false); }; virtual void writeback_bl(librbd::cache::ImageWritebackInterface &image_writeback, Context *ctx, ceph::bufferlist &&bl) { ceph_assert(false); } virtual bool is_write_entry() const { return false; } virtual bool is_writesame_entry() const { return false; } virtual bool is_sync_point() const { return false; } virtual unsigned int get_aligned_data_size() const { return 0; } virtual void remove_cache_bl() {} virtual std::ostream& format(std::ostream &os) const; friend std::ostream &operator<<(std::ostream &os, const GenericLogEntry &entry); }; class SyncPointLogEntry : public GenericLogEntry { public: /* Writing entries using this sync gen number */ std::atomic writes = {0}; /* Total bytes for all writing entries using this sync gen number */ std::atomic bytes = {0}; /* Writing entries using this sync gen number that have completed */ std::atomic writes_completed = {0}; /* Writing entries using this sync gen number that have completed flushing to the writeback interface */ std::atomic writes_flushed = {0}; /* All writing entries using all prior sync gen numbers have been flushed */ std::atomic prior_sync_point_flushed = {true}; std::shared_ptr next_sync_point_entry = nullptr; SyncPointLogEntry(uint64_t sync_gen_number) { ram_entry.sync_gen_number = sync_gen_number; ram_entry.set_sync_point(true); }; ~SyncPointLogEntry() override {}; SyncPointLogEntry(const SyncPointLogEntry&) = delete; SyncPointLogEntry &operator=(const SyncPointLogEntry&) = delete; bool can_retire() const override { return this->completed; } bool is_sync_point() const override { return true; } std::ostream& format(std::ostream &os) const; friend std::ostream &operator<<(std::ostream &os, const SyncPointLogEntry &entry); }; class GenericWriteLogEntry : public GenericLogEntry { public: uint32_t referring_map_entries = 0; std::shared_ptr sync_point_entry; GenericWriteLogEntry(std::shared_ptr sync_point_entry, uint64_t image_offset_bytes, uint64_t write_bytes) : GenericLogEntry(image_offset_bytes, write_bytes), sync_point_entry(sync_point_entry) { } GenericWriteLogEntry(uint64_t image_offset_bytes, uint64_t write_bytes) : GenericLogEntry(image_offset_bytes, write_bytes), sync_point_entry(nullptr) { } ~GenericWriteLogEntry() override {}; GenericWriteLogEntry(const GenericWriteLogEntry&) = delete; GenericWriteLogEntry &operator=(const GenericWriteLogEntry&) = delete; unsigned int write_bytes() const override { /* The valid bytes in this ops data buffer. Discard and WS override. */ return ram_entry.write_bytes; }; unsigned int bytes_dirty() const override { /* The bytes in the image this op makes dirty. Discard and WS override. */ return write_bytes(); }; BlockExtent block_extent() { return ram_entry.block_extent(); } uint32_t get_map_ref() { return(referring_map_entries); } void inc_map_ref() { referring_map_entries++; } void dec_map_ref() { referring_map_entries--; } bool can_writeback() const override; std::shared_ptr get_sync_point_entry() override { return sync_point_entry; } virtual void copy_cache_bl(bufferlist *out_bl) = 0; void set_flushed(bool flushed) override { m_flushed = flushed; } bool get_flushed() const { return m_flushed; } std::ostream &format(std::ostream &os) const; friend std::ostream &operator<<(std::ostream &os, const GenericWriteLogEntry &entry); private: bool m_flushed = false; /* or invalidated */ }; class WriteLogEntry : public GenericWriteLogEntry { protected: bool is_writesame = false; buffer::ptr cache_bp; buffer::list cache_bl; std::atomic bl_refs = {0}; /* The refs held on cache_bp by cache_bl */ /* Used in WriteLogEntry::get_cache_bl() to syncronize between threads making entries readable */ mutable ceph::mutex m_entry_bl_lock; virtual void init_cache_bp() {} virtual void init_bl(buffer::ptr &bp, buffer::list &bl) {} public: uint8_t *cache_buffer = nullptr; WriteLogEntry(std::shared_ptr sync_point_entry, uint64_t image_offset_bytes, uint64_t write_bytes) : GenericWriteLogEntry(sync_point_entry, image_offset_bytes, write_bytes), m_entry_bl_lock(ceph::make_mutex(pwl::unique_lock_name( "librbd::cache::pwl::WriteLogEntry::m_entry_bl_lock", this))) { } WriteLogEntry(uint64_t image_offset_bytes, uint64_t write_bytes) : GenericWriteLogEntry(nullptr, image_offset_bytes, write_bytes), m_entry_bl_lock(ceph::make_mutex(pwl::unique_lock_name( "librbd::cache::pwl::WriteLogEntry::m_entry_bl_lock", this))) { } WriteLogEntry(std::shared_ptr sync_point_entry, uint64_t image_offset_bytes, uint64_t write_bytes, uint32_t data_length) : WriteLogEntry(sync_point_entry, image_offset_bytes, write_bytes) { ram_entry.set_writesame(true); ram_entry.ws_datalen = data_length; is_writesame = true; }; WriteLogEntry(uint64_t image_offset_bytes, uint64_t write_bytes, uint32_t data_length) : WriteLogEntry(nullptr, image_offset_bytes, write_bytes) { ram_entry.set_writesame(true); ram_entry.ws_datalen = data_length; is_writesame = true; }; ~WriteLogEntry() override {}; WriteLogEntry(const WriteLogEntry&) = delete; WriteLogEntry &operator=(const WriteLogEntry&) = delete; unsigned int write_bytes() const override { // The valid bytes in this ops data buffer. if(is_writesame) { return ram_entry.ws_datalen; } return ram_entry.write_bytes; }; unsigned int bytes_dirty() const override { // The bytes in the image this op makes dirty. return ram_entry.write_bytes; }; void init(bool has_data, uint64_t current_sync_gen, uint64_t last_op_sequence_num, bool persist_on_flush); virtual void init_cache_buffer(std::vector::iterator allocation) {} virtual void init_cache_bl(bufferlist &src_bl, uint64_t off, uint64_t len) {} /* Returns a ref to a bl containing bufferptrs to the entry cache buffer */ virtual buffer::list &get_cache_bl() = 0; BlockExtent block_extent(); virtual unsigned int reader_count() const = 0; /* Constructs a new bl containing copies of cache_bp */ bool can_retire() const override { return (this->completed && this->get_flushed() && (0 == reader_count())); } bool is_write_entry() const override { return true; } bool is_writesame_entry() const override { return is_writesame; } std::ostream &format(std::ostream &os) const; friend std::ostream &operator<<(std::ostream &os, const WriteLogEntry &entry); }; class DiscardLogEntry : public GenericWriteLogEntry { public: DiscardLogEntry(std::shared_ptr sync_point_entry, uint64_t image_offset_bytes, uint64_t write_bytes, uint32_t discard_granularity_bytes) : GenericWriteLogEntry(sync_point_entry, image_offset_bytes, write_bytes), m_discard_granularity_bytes(discard_granularity_bytes) { ram_entry.set_discard(true); }; DiscardLogEntry(uint64_t image_offset_bytes, uint64_t write_bytes) : GenericWriteLogEntry(nullptr, image_offset_bytes, write_bytes) { ram_entry.set_discard(true); }; DiscardLogEntry(const DiscardLogEntry&) = delete; DiscardLogEntry &operator=(const DiscardLogEntry&) = delete; unsigned int write_bytes() const override { /* The valid bytes in this ops data buffer. */ return 0; }; unsigned int bytes_dirty() const override { /* The bytes in the image this op makes dirty. */ return ram_entry.write_bytes; }; bool can_retire() const override { return this->completed; } void copy_cache_bl(bufferlist *out_bl) override { ceph_assert(false); } void writeback(librbd::cache::ImageWritebackInterface &image_writeback, Context *ctx) override; void init(uint64_t current_sync_gen, bool persist_on_flush, uint64_t last_op_sequence_num); std::ostream &format(std::ostream &os) const; friend std::ostream &operator<<(std::ostream &os, const DiscardLogEntry &entry); private: uint32_t m_discard_granularity_bytes; }; } // namespace pwl } // namespace cache } // namespace librbd #endif // CEPH_LIBRBD_CACHE_PWL_LOG_ENTRY_H