// // Created by 马也驰 on 2025/1/4. // #ifndef LEVELDB_VLOG_CACHE_H #define LEVELDB_VLOG_CACHE_H #include #include #include #define BLOCK_SIZE 4096 struct frame_info { std::mutex info_latch_; bool used; std::string vlog_name; size_t vlog_block_num; bool is_dirty; inline void set_used() { info_latch_.lock(); assert(used == false); used = true; info_latch_.unlock(); } inline void set_unused() { info_latch_.lock(); assert(used == true); used = false; info_latch_.unlock(); } inline void set_dirty() { info_latch_.lock(); assert(is_dirty == false); is_dirty = true; info_latch_.unlock(); } inline void set_nondirty() { info_latch_.lock(); assert(is_dirty == true); is_dirty = false; info_latch_.unlock(); } inline void set_vlog_block_num(size_t vb) { info_latch_.lock(); vlog_block_num = vb; info_latch_.unlock(); } inline void set_vlog_name(std::string &vn) { info_latch_.lock(); vlog_name = vn; info_latch_.unlock(); } inline bool cache_hit(std::string &vn, size_t vbn) { return used && (vlog_name == vn) && (vlog_block_num == vbn); } }; struct block_frame { // 读,写,块置换 必须对这个mutex上锁,保证线性化 // 读写必须对这个mutex上锁,保证线性化 std::mutex mtx; frame_info frame_info_; char *block_buff; block_frame() { frame_info_.used = false; frame_info_.is_dirty = false; block_buff = static_cast(malloc(BLOCK_SIZE)); } void free_block_buff() { free(block_buff); } }; class VlogCache { #define BLOCK_NUMS 1024 #define VALUE_ACROSS_BLOCK(offset, len) (((offset)/BLOCK_SIZE) != (((offset)+(len)-1)/BLOCK_SIZE)) #define DATA_SIZE_MASK 0x7fff #define DATA_DELE_MASK 0x8000 public: VlogCache() { for (auto i = 0; i < BLOCK_NUMS; i++) { block_frames[i] = new block_frame(); } } ~VlogCache() { flush_all_blocks(); for (auto i = 0; i < BLOCK_NUMS; i++) { block_frames[i]->free_block_buff(); } } public: void read_data(std::string &vlog_name, std::string& value, size_t offset, size_t len); void write_data(std::string &vlog_name, std::string& value, size_t offset, size_t len); uint16_t delete_data(std::string &vlog_name, size_t offset); private: void read_data_inblock(std::string &vlog_name, std::string& value, size_t offset, size_t len); void write_data_inblock(std::string &vlog_name, std::string& value, size_t offset, size_t len); void write_back_block(size_t block_num); void read_in_block(size_t block_num, std::string &vlog_name, size_t vlog_block_num); private: void flush_all_blocks(); inline size_t offset_2_blocknum(size_t offset) { return (offset / BLOCK_SIZE) % BLOCK_NUMS; } inline size_t offset_2_inblock_offset(size_t offset) { return offset % BLOCK_SIZE; } private: block_frame *block_frames[BLOCK_NUMS]; }; #endif // LEVELDB_VLOG_CACHE_H