diff --git a/test/MemoryRiver.hpp b/test/MemoryRiver.hpp index 85c1a8a..dbb8d5e 100644 --- a/test/MemoryRiver.hpp +++ b/test/MemoryRiver.hpp @@ -16,16 +16,27 @@ using std::string; template class MemoryRiver { private: - union Page { + struct ElementPair { T data; + size_t nxt_blank; + }; + const static size_t max_element_in_page = (4096 - sizeof(size_t)) / sizeof(ElementPair); + struct DataType { + size_t elements_count; + ElementPair elements[max_element_in_page]; + }; + union Page { + DataType dat; char filler[4096]; }; + // data_id = frame_id * max_element_in_page + element_id std::string file_name; DiskManager *disk_manager; BufferPoolManager *bpm; + size_t first_blank_element_pair_id; char *raw_mem; static_assert(info_len * sizeof(int) <= 4000, "info_len should be less than 4000"); - static_assert(sizeof(T) <= 4096, "T should be less than 4096"); + static_assert(sizeof(T) <= 4088, "T should be less than 4088"); public: MemoryRiver() : disk_manager(nullptr), bpm(nullptr), file_name("") {} @@ -34,8 +45,10 @@ class MemoryRiver { disk_manager = new DiskManager(file_name); bpm = new BufferPoolManager(100, 5, disk_manager); raw_mem = bpm->RawDataMemory(); + memcpy(&first_blank_element_pair_id, raw_mem, sizeof(size_t)); } void CloseFile() { + memcpy(raw_mem, &first_blank_element_pair_id, sizeof(size_t)); bpm->FlushAllPages(); file_name = ""; delete bpm; @@ -49,7 +62,7 @@ class MemoryRiver { void initialise(string FN = "") { if (file_name != "") { - std::string name_bak=file_name; + std::string name_bak = file_name; CloseFile(); file_name = name_bak; } @@ -59,40 +72,74 @@ class MemoryRiver { bpm = new BufferPoolManager(100, 5, disk_manager); raw_mem = bpm->RawDataMemory(); memset(raw_mem, 0, bpm->RawDatMemorySize()); + first_blank_element_pair_id = 0; } void get_info(int &tmp, int n) { if (n > info_len) return; - n--; + n += 2; memcpy(&tmp, raw_mem + n * sizeof(int), sizeof(int)); } void write_info(int tmp, int n) { if (n > info_len) return; - n--; + n += 2; memcpy(raw_mem + n * sizeof(int), &tmp, sizeof(int)); } int write(T &t) { - frame_id_t frame_id; - BasicPageGuard guard = bpm->NewPageGuarded(&frame_id); - guard.AsMut()->data = t; - return frame_id; + size_t element_id = first_blank_element_pair_id; + size_t res_id = 0; + if (element_id != 0) { + res_id = element_id; + frame_id_t frame_id = element_id / max_element_in_page; + element_id %= max_element_in_page; + WritePageGuard guard = bpm->FetchPageWrite(frame_id); + first_blank_element_pair_id = guard.AsMut()->dat.elements[element_id].nxt_blank; + guard.AsMut()->dat.elements[element_id].data = t; + guard.AsMut()->dat.elements_count++; + } else { + frame_id_t frame_id; + BasicPageGuard guard = bpm->NewPageGuarded(&frame_id); + guard.AsMut()->dat.elements[0].data = t; + element_id = frame_id * max_element_in_page; + res_id = element_id; + if (max_element_in_page > 1) first_blank_element_pair_id = element_id + 1; + for (size_t i = 1; i < max_element_in_page - 1; i++) { + guard.AsMut()->dat.elements[i].nxt_blank = element_id + i + 1; + } + guard.AsMut()->dat.elements[max_element_in_page - 1].nxt_blank = 0; + guard.AsMut()->dat.elements_count = 1; + } + return res_id; } void update(T &t, const int index) { - WritePageGuard guard = bpm->FetchPageWrite(index); - guard.AsMut()->data = t; + size_t frame_id = index / max_element_in_page; + WritePageGuard guard = bpm->FetchPageWrite(frame_id); + guard.AsMut()->dat.elements[index % max_element_in_page].data = t; } //读出位置索引index对应的T对象的值并赋值给t,保证调用的index都是由write函数产生 void read(T &t, const int index) { - ReadPageGuard guard = bpm->FetchPageRead(index); - t = guard.As()->data; + size_t frame_id = index / max_element_in_page; + ReadPageGuard guard = bpm->FetchPageRead(frame_id); + t = guard.As()->dat.elements[index % max_element_in_page].data; } //删除位置索引index对应的对象(不涉及空间回收时,可忽略此函数),保证调用的index都是由write函数产生 - void Delete(int index) { bpm->DeletePage(index); } + void Delete(int index) { + size_t frame_id = index / max_element_in_page; + WritePageGuard guard = bpm->FetchPageWrite(frame_id); + size_t element_id = index % max_element_in_page; + guard.AsMut()->dat.elements[element_id].nxt_blank = first_blank_element_pair_id; + first_blank_element_pair_id = index; + guard.AsMut()->dat.elements_count--; + if (guard.AsMut()->dat.elements_count == 0) { + guard.Drop(); + bpm->DeletePage(frame_id); + } + } }; #endif // BPT_MEMORYRIVER_HPP \ No newline at end of file diff --git a/test/buffer_pool_manager_test.cpp b/test/buffer_pool_manager_test.cpp index fd836f4..d9d3e9e 100644 --- a/test/buffer_pool_manager_test.cpp +++ b/test/buffer_pool_manager_test.cpp @@ -1,14 +1,16 @@ #include "bpt/buffer_pool_manager.h" #include +#include #include #include #include #include #include +#include +#include "MemoryRiver.hpp" #include "bpt/bpt_page.hpp" #include "bpt/config.h" #include "bpt/disk_manager.h" -#include "MemoryRiver.hpp" // Demonstrate some basic assertions. TEST(HelloTest, BasicAssertions) { // Expect two strings not to be equal. @@ -190,15 +192,26 @@ TEST(StoreTest, Test1) { delete disk_manager_ptr; } -TEST(MemoryRiver,T1) { - MemoryRiver river; +TEST(MemoryRiver, T1) { + remove("/tmp/test2.db"); + typedef unsigned long long DataType; + MemoryRiver river; river.initialise("/tmp/test2.db"); - int x=3; - river.write_info(x,1); - unsigned long long dat1=0x1f2f3f4f5f6f7f8f; - frame_id_t frame_id = river.write(dat1); - for(int i=0;i<100;i++) { - dat1++; - river.write(dat1); + int x = 3; + river.write_info(x, 1); + DataType dat1 = 0x1f2f3f4f5f6f7f8f; + std::vector record; + std::vector id_record; + int test_cnt = 3; + for (int i = 0; i < test_cnt; i++) { + DataType tmp = dat1 + i; + size_t element_id = river.write(tmp); + record.push_back(tmp); + id_record.push_back(element_id); + } + for (int i = 0; i < test_cnt; i++) { + DataType tmp; + river.read(tmp, id_record[i]); + EXPECT_EQ(record[i], tmp); } } \ No newline at end of file