|
|
- //
- // Created by 马也驰 on 2024/12/9.
- //
-
- #ifndef LEVELDB_SLOTPAGE_H
- #define LEVELDB_SLOTPAGE_H
-
- #include <cassert>
- #include <cstdint>
- #include <cstdlib>
- #include <vector>
- #include <iostream>
- #include <fstream>
- #include <mutex>
-
- #define BITMAP_SIZE 8192
- #define BITS_PER_BYTE 8
-
- #define POSMASK(off) (0x01 << (BITS_PER_BYTE-(off)-1))
- #define SETBIT(byte, off) (*(byte) |= POSMASK(off))
- #define RESETBIT(byte, off) (*(byte) &= (0xff ^ POSMASK(off)))
- #define HASFREESLOT(byte) ((byte) != ~0x0)
-
- struct slot_content {
- uint32_t vlog_num;
- uint32_t value_offset;
- slot_content(uint32_t vn, uint32_t vo) {
- vlog_num = vn;
- value_offset = vo;
- }
- };
-
- class SlotCache {
- // slot number -> slot content
- #define BLOCK_NUM 16
- #define BLOCK_SIZE 4096
- #define SLOT_PER_BLOCK (BLOCK_SIZE/sizeof(slot_content))
- #define SLOT_OFFSET_IN_BLOCK(slot_num) ((slot_num)%SLOT_PER_BLOCK)
- public:
- SlotCache() {
- for (auto i = 0; i < BLOCK_NUM; i++) {
- block_cache[i] = static_cast<struct slot_content*>(malloc(BLOCK_SIZE));
- access_time[i] = 0;
- info[i] = block_info();
- }
- }
-
- void get_slot(std::string &slotpage_fname, size_t slot_num, struct slot_content *sc) {
- auto block_num = slotnum_hash2_blocknum(slot_num);
- auto blockcache_num = block_num % BLOCK_NUM;
- mtx.lock();
- if (info[blockcache_num].slotpage_fname != slotpage_fname) { // cache miss
- write_back_block(blockcache_num);
- read_in_block(blockcache_num, slotpage_fname, block_num);
- }
- read_slot(sc, blockcache_num, SLOT_OFFSET_IN_BLOCK(slot_num));
- access_time[blockcache_num]++;
- mtx.unlock();
- }
-
- void set_slot(std::string &slotpage_fname, size_t slot_num, struct slot_content *sc) {
- auto block_num = slotnum_hash2_blocknum(slot_num);
- auto blockcache_num = block_num % BLOCK_NUM;
- mtx.lock();
- if (info[blockcache_num].slotpage_fname != slotpage_fname) {
- write_back_block(blockcache_num);
- read_in_block(blockcache_num, slotpage_fname, block_num);
- }
- set_slot(sc, blockcache_num, SLOT_OFFSET_IN_BLOCK(slot_num));
- access_time[blockcache_num]++;
- info[blockcache_num].is_dirty = true;
- mtx.unlock();
- }
-
- private:
- struct block_info {
- std::string slotpage_fname;
- size_t block_num;
- bool is_dirty;
- block_info() {}
- block_info(std::string &slotpage_fname, size_t block_num, bool is_dirty=false) {
- this->slotpage_fname = slotpage_fname;
- this->block_num = block_num;
- this->is_dirty = is_dirty;
- }
- };
-
- private:
- inline static size_t slotnum_hash2_blocknum(size_t slot_num) {
- return slot_num * sizeof(slot_content) / BLOCK_SIZE;
- }
- void write_back_block(size_t blockcache_num) {
- auto &fname = info[blockcache_num].slotpage_fname;
- auto write_pos = info[blockcache_num].block_num * BLOCK_SIZE;
- auto slotpage_handler = std::fstream(fname, std::ios::in | std::ios::out);
- slotpage_handler.seekp(write_pos);
- slotpage_handler.write(
- reinterpret_cast<const char*>(block_cache[blockcache_num]), BLOCK_SIZE);
- }
- void read_in_block(size_t blockcache_num, std::string &slotpage_fname, size_t block_num) {
- auto slotpage_handler = std::fstream(slotpage_fname, std::ios::in | std::ios::out);
- slotpage_handler.seekp(block_num*BLOCK_SIZE);
- slotpage_handler.read(reinterpret_cast<char*>(block_cache[blockcache_num]), BLOCK_SIZE);
- access_time[blockcache_num] = 0;
- info[blockcache_num] = block_info(slotpage_fname, block_num);
- }
- inline void read_slot(struct slot_content *sc, size_t blockcache_num, size_t slot_num_offset) {
- auto src = &block_cache[blockcache_num][slot_num_offset];
- memcpy(sc, src, sizeof(slot_content));
- }
- inline void set_slot(struct slot_content *sc, size_t blockcache_num, size_t slot_num_offset) {
- auto src = &block_cache[blockcache_num][slot_num_offset];
- memcpy(src, sc, sizeof(slot_content));
- }
-
- private:
- std::mutex mtx;
- struct slot_content *block_cache[BLOCK_NUM];
- size_t access_time[BLOCK_NUM];
- struct block_info info[BLOCK_NUM];
- };
-
-
- class BitMap {
- // in memory bitmap
- public:
- BitMap() {
- char *bitmap = static_cast<char*>(malloc(BITMAP_SIZE*sizeof(char)));
- bitmaps_.push_back(bitmap);
- size = BITMAP_SIZE;
- first_empty_slot = 0;
- }
-
- void dealloc_slot(size_t slot_num) {
- mtx.lock();
- const size_t byte = slot2byte(slot_num);
- const size_t off = slot2offset(slot_num);
- char *target_byte = get_bitmap_byte(byte);
- assert(*target_byte & POSMASK(off));
- RESETBIT(target_byte, off);
- // set_bitmap_byte(byte, target_byte);
- first_empty_slot = first_empty_slot < slot_num ? first_empty_slot:slot_num;
- mtx.unlock();
- }
-
- size_t alloc_slot() {
- mtx.lock();
- size_t target_slot = first_empty_slot;
- char *start_byte = get_bitmap_byte(slot2byte(first_empty_slot));
- const size_t off = slot2offset(first_empty_slot);
- SETBIT(start_byte, off);
- if (HASFREESLOT(*start_byte)) {
- auto bit_off = find_first_free_slot_inbyte(*start_byte);
- first_empty_slot += bit_off - off;
- } else {
- size_t i;
- for (i = slot2byte(first_empty_slot)+1; i < size; i++) {
- char *byte = get_bitmap_byte(i);
- if (HASFREESLOT(*byte)) {
- auto bit_off = find_first_free_slot_inbyte(*byte);
- first_empty_slot = byte2slot(i) + bit_off;
- }
- }
- // scale the bitmap
- if (i >= size) {
- alloc_new_bitmap();
- char *byte = get_bitmap_byte(i);
- SETBIT(byte, 0);
- first_empty_slot = byte2slot(i) + 1;
- }
- }
- mtx.unlock();
- return target_slot;
- }
-
- private:
- static inline size_t slot2byte(size_t slot_num) { return slot_num / BITS_PER_BYTE; }
- static inline size_t byte2slot(uint8_t byte_num) { return byte_num * BITS_PER_BYTE; }
- static inline size_t slot2offset(size_t slot_num) { return slot_num % BITS_PER_BYTE; }
- inline char *get_bitmap_byte(size_t byte_num) {
- char *bitmap = bitmaps_.at(byte_num / BITMAP_SIZE);
- return &bitmap[byte_num % BITMAP_SIZE];
- }
- // inline void set_bitmap_byte(size_t byte_num, char byte) {
- // char *bitmap = bitmaps_.at(byte_num / BITMAP_SIZE);
- // bitmap[byte_num % BITMAP_SIZE] = byte;
- // }
- static inline size_t find_first_free_slot_inbyte(uint8_t byte) {
- uint32_t rbyte = __builtin_bswap32((uint32_t)byte) >> 24; // 使用 32 位变量
- return BITS_PER_BYTE - __builtin_ctz(~rbyte) - 1; // 使用 GCC 内建函数找到最低位 1 的位置
- }
- void alloc_new_bitmap() {
- char *bitmap = static_cast<char*>(malloc(BITMAP_SIZE*sizeof(char)));
- bitmaps_.push_back(bitmap);
- size += BITMAP_SIZE;
- }
-
- private:
- std::vector<char *> bitmaps_;
- size_t size;
- size_t first_empty_slot;
- std::mutex mtx;
- };
-
-
- // read and write slot in disk
- // first version with no cache
- class SlotPage {
- public:
- SlotPage(std::string &dbname) {
- slotpage_fname = slotpage_handler_name(dbname);
- bitmap = new BitMap();
- }
-
- public:
- void get_slot(size_t slot_num, struct slot_content *sc) {
- slotcache->get_slot(slotpage_fname, slot_num, sc);
- }
- void set_slot(size_t slot_num, struct slot_content *sc) {
- slotcache->set_slot(slotpage_fname, slot_num, sc);
- }
- size_t alloc_slot() { return bitmap->alloc_slot(); }
- void dealloc_slot(size_t slot_num) { bitmap->dealloc_slot(slot_num); }
-
- private:
- static std::string slotpage_handler_name(std::string &dbname) {
- return "./" + dbname + "_slotpage";
- }
- inline static size_t slotpage_pos(size_t slot_num) {
- return slot_num * sizeof(slot_content);
- }
-
- private:
- std::string slotpage_fname;
- BitMap *bitmap;
- static SlotCache *slotcache;
- };
-
- SlotCache *SlotPage::slotcache = new SlotCache();
-
- #endif // LEVELDB_SLOTPAGE_H
|