You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
7.5 KiB

2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
  1. //
  2. // Created by 马也驰 on 2024/12/9.
  3. //
  4. #ifndef LEVELDB_SLOTPAGE_H
  5. #define LEVELDB_SLOTPAGE_H
  6. #include <cassert>
  7. #include <cstdint>
  8. #include <cstdlib>
  9. #include <vector>
  10. #include <iostream>
  11. #include <fstream>
  12. #include <mutex>
  13. #define BITMAP_SIZE 8192
  14. #define BITS_PER_BYTE 8
  15. #define POSMASK(off) (0x01 << (BITS_PER_BYTE-(off)-1))
  16. #define SETBIT(byte, off) (*(byte) |= POSMASK(off))
  17. #define RESETBIT(byte, off) (*(byte) &= (0xff ^ POSMASK(off)))
  18. #define HASFREESLOT(byte) ((byte) != ~0x0)
  19. struct slot_content {
  20. uint32_t vlog_num;
  21. uint32_t value_offset;
  22. slot_content(uint32_t vn, uint32_t vo) {
  23. vlog_num = vn;
  24. value_offset = vo;
  25. }
  26. };
  27. class SlotCache {
  28. // slot number -> slot content
  29. #define BLOCK_NUM 16
  30. #define BLOCK_SIZE 4096
  31. #define SLOT_PER_BLOCK (BLOCK_SIZE/sizeof(slot_content))
  32. #define SLOT_OFFSET_IN_BLOCK(slot_num) ((slot_num)%SLOT_PER_BLOCK)
  33. public:
  34. SlotCache() {
  35. for (auto i = 0; i < BLOCK_NUM; i++) {
  36. block_cache[i] = static_cast<struct slot_content*>(malloc(BLOCK_SIZE));
  37. access_time[i] = 0;
  38. info[i] = block_info();
  39. }
  40. }
  41. void get_slot(std::string &slotpage_fname, size_t slot_num, struct slot_content *sc) {
  42. auto block_num = slotnum_hash2_blocknum(slot_num);
  43. auto blockcache_num = block_num % BLOCK_NUM;
  44. mtx.lock();
  45. if (info[blockcache_num].slotpage_fname != slotpage_fname) { // cache miss
  46. write_back_block(blockcache_num);
  47. read_in_block(blockcache_num, slotpage_fname, block_num);
  48. }
  49. read_slot(sc, blockcache_num, SLOT_OFFSET_IN_BLOCK(slot_num));
  50. access_time[blockcache_num]++;
  51. mtx.unlock();
  52. }
  53. void set_slot(std::string &slotpage_fname, size_t slot_num, struct slot_content *sc) {
  54. auto block_num = slotnum_hash2_blocknum(slot_num);
  55. auto blockcache_num = block_num % BLOCK_NUM;
  56. mtx.lock();
  57. if (info[blockcache_num].slotpage_fname != slotpage_fname) {
  58. write_back_block(blockcache_num);
  59. read_in_block(blockcache_num, slotpage_fname, block_num);
  60. }
  61. set_slot(sc, blockcache_num, SLOT_OFFSET_IN_BLOCK(slot_num));
  62. access_time[blockcache_num]++;
  63. info[blockcache_num].is_dirty = true;
  64. mtx.unlock();
  65. }
  66. private:
  67. struct block_info {
  68. std::string slotpage_fname;
  69. size_t block_num;
  70. bool is_dirty;
  71. block_info() {}
  72. block_info(std::string &slotpage_fname, size_t block_num, bool is_dirty=false) {
  73. this->slotpage_fname = slotpage_fname;
  74. this->block_num = block_num;
  75. this->is_dirty = is_dirty;
  76. }
  77. };
  78. private:
  79. inline static size_t slotnum_hash2_blocknum(size_t slot_num) {
  80. return slot_num * sizeof(slot_content) / BLOCK_SIZE;
  81. }
  82. void write_back_block(size_t blockcache_num) {
  83. auto &fname = info[blockcache_num].slotpage_fname;
  84. auto write_pos = info[blockcache_num].block_num * BLOCK_SIZE;
  85. auto slotpage_handler = std::fstream(fname, std::ios::in | std::ios::out);
  86. slotpage_handler.seekp(write_pos);
  87. slotpage_handler.write(
  88. reinterpret_cast<const char*>(block_cache[blockcache_num]), BLOCK_SIZE);
  89. }
  90. void read_in_block(size_t blockcache_num, std::string &slotpage_fname, size_t block_num) {
  91. auto slotpage_handler = std::fstream(slotpage_fname, std::ios::in | std::ios::out);
  92. slotpage_handler.seekp(block_num*BLOCK_SIZE);
  93. slotpage_handler.read(reinterpret_cast<char*>(block_cache[blockcache_num]), BLOCK_SIZE);
  94. access_time[blockcache_num] = 0;
  95. info[blockcache_num] = block_info(slotpage_fname, block_num);
  96. }
  97. inline void read_slot(struct slot_content *sc, size_t blockcache_num, size_t slot_num_offset) {
  98. auto src = &block_cache[blockcache_num][slot_num_offset];
  99. memcpy(sc, src, sizeof(slot_content));
  100. }
  101. inline void set_slot(struct slot_content *sc, size_t blockcache_num, size_t slot_num_offset) {
  102. auto src = &block_cache[blockcache_num][slot_num_offset];
  103. memcpy(src, sc, sizeof(slot_content));
  104. }
  105. private:
  106. std::mutex mtx;
  107. struct slot_content *block_cache[BLOCK_NUM];
  108. size_t access_time[BLOCK_NUM];
  109. struct block_info info[BLOCK_NUM];
  110. };
  111. class BitMap {
  112. // in memory bitmap
  113. public:
  114. BitMap() {
  115. char *bitmap = static_cast<char*>(malloc(BITMAP_SIZE*sizeof(char)));
  116. bitmaps_.push_back(bitmap);
  117. size = BITMAP_SIZE;
  118. first_empty_slot = 0;
  119. }
  120. void dealloc_slot(size_t slot_num) {
  121. mtx.lock();
  122. const size_t byte = slot2byte(slot_num);
  123. const size_t off = slot2offset(slot_num);
  124. char *target_byte = get_bitmap_byte(byte);
  125. assert(*target_byte & POSMASK(off));
  126. RESETBIT(target_byte, off);
  127. // set_bitmap_byte(byte, target_byte);
  128. first_empty_slot = first_empty_slot < slot_num ? first_empty_slot:slot_num;
  129. mtx.unlock();
  130. }
  131. size_t alloc_slot() {
  132. mtx.lock();
  133. size_t target_slot = first_empty_slot;
  134. char *start_byte = get_bitmap_byte(slot2byte(first_empty_slot));
  135. const size_t off = slot2offset(first_empty_slot);
  136. SETBIT(start_byte, off);
  137. if (HASFREESLOT(*start_byte)) {
  138. auto bit_off = find_first_free_slot_inbyte(*start_byte);
  139. first_empty_slot += bit_off - off;
  140. } else {
  141. size_t i;
  142. for (i = slot2byte(first_empty_slot)+1; i < size; i++) {
  143. char *byte = get_bitmap_byte(i);
  144. if (HASFREESLOT(*byte)) {
  145. auto bit_off = find_first_free_slot_inbyte(*byte);
  146. first_empty_slot = byte2slot(i) + bit_off;
  147. }
  148. }
  149. // scale the bitmap
  150. if (i >= size) {
  151. alloc_new_bitmap();
  152. char *byte = get_bitmap_byte(i);
  153. SETBIT(byte, 0);
  154. first_empty_slot = byte2slot(i) + 1;
  155. }
  156. }
  157. mtx.unlock();
  158. return target_slot;
  159. }
  160. private:
  161. static inline size_t slot2byte(size_t slot_num) { return slot_num / BITS_PER_BYTE; }
  162. static inline size_t byte2slot(uint8_t byte_num) { return byte_num * BITS_PER_BYTE; }
  163. static inline size_t slot2offset(size_t slot_num) { return slot_num % BITS_PER_BYTE; }
  164. inline char *get_bitmap_byte(size_t byte_num) {
  165. char *bitmap = bitmaps_.at(byte_num / BITMAP_SIZE);
  166. return &bitmap[byte_num % BITMAP_SIZE];
  167. }
  168. // inline void set_bitmap_byte(size_t byte_num, char byte) {
  169. // char *bitmap = bitmaps_.at(byte_num / BITMAP_SIZE);
  170. // bitmap[byte_num % BITMAP_SIZE] = byte;
  171. // }
  172. static inline size_t find_first_free_slot_inbyte(uint8_t byte) {
  173. uint32_t rbyte = __builtin_bswap32((uint32_t)byte) >> 24; // 使用 32 位变量
  174. return BITS_PER_BYTE - __builtin_ctz(~rbyte) - 1; // 使用 GCC 内建函数找到最低位 1 的位置
  175. }
  176. void alloc_new_bitmap() {
  177. char *bitmap = static_cast<char*>(malloc(BITMAP_SIZE*sizeof(char)));
  178. bitmaps_.push_back(bitmap);
  179. size += BITMAP_SIZE;
  180. }
  181. private:
  182. std::vector<char *> bitmaps_;
  183. size_t size;
  184. size_t first_empty_slot;
  185. std::mutex mtx;
  186. };
  187. // read and write slot in disk
  188. // first version with no cache
  189. class SlotPage {
  190. public:
  191. SlotPage(std::string &dbname) {
  192. slotpage_fname = slotpage_handler_name(dbname);
  193. bitmap = new BitMap();
  194. }
  195. public:
  196. void get_slot(size_t slot_num, struct slot_content *sc) {
  197. slotcache->get_slot(slotpage_fname, slot_num, sc);
  198. }
  199. void set_slot(size_t slot_num, struct slot_content *sc) {
  200. slotcache->set_slot(slotpage_fname, slot_num, sc);
  201. }
  202. size_t alloc_slot() { return bitmap->alloc_slot(); }
  203. void dealloc_slot(size_t slot_num) { bitmap->dealloc_slot(slot_num); }
  204. private:
  205. static std::string slotpage_handler_name(std::string &dbname) {
  206. return "./" + dbname + "_slotpage";
  207. }
  208. inline static size_t slotpage_pos(size_t slot_num) {
  209. return slot_num * sizeof(slot_content);
  210. }
  211. private:
  212. std::string slotpage_fname;
  213. BitMap *bitmap;
  214. static SlotCache *slotcache;
  215. };
  216. SlotCache *SlotPage::slotcache = new SlotCache();
  217. #endif // LEVELDB_SLOTPAGE_H