diff --git a/src/observer/storage/buffer/buffer_LRU.cpp b/src/observer/storage/buffer/buffer_LRU.cpp new file mode 100644 index 000000000..8a74708d7 --- /dev/null +++ b/src/observer/storage/buffer/buffer_LRU.cpp @@ -0,0 +1,163 @@ +#include "pch.h" +#include "buffer_LRU.h" +#include "time.h" +#define CLOCKS_PER_SEC ((clock_t)1000) +clock_t start, t_end; double duration; + +void str2int(int& int_temp, const string& string_temp) +{ + stringstream stream(string_temp); + stream >> int_temp; +} + +vector split(const string& str, const string& delim) { + vector res; + if ("" == str) return res; + char* strs = new char[str.length() + 1]; + strcpy(strs, str.c_str()); + + char* d = new char[delim.length() + 1]; + strcpy(d, delim.c_str()); + + char* p = strtok(strs, d); + while (p) { + string s = p; + res.push_back(s); + p = strtok(NULL, d); + } + delete strs, d; + return res; +} + +void CreateBlockWRTest(int blocks) +{ + FILE* fstream_w; + char dbfile[] = "database.dbf"; + fstream_w = fopen(dbfile, "wb"); + if (fstream_w == NULL) + { + printf("open or create file failed!\n"); + exit(1); + } + else { + //cout << "Open " << dbfile << " successfully!" << endl; + } + // 数据块号 + unsigned int block_num = 0; + // 时间戳 + unsigned int btimestamp = 0; + // 偏移量表 + unsigned short int offset[FRAMESIZE / RECORDSIZE]; + int BLOCK_HEAD = sizeof(btimestamp) + sizeof(offset); + for (int i = 0; i < FRAMESIZE / RECORDSIZE; i++) { offset[i] = BLOCK_HEAD + i * RECORDSIZE; }; + + for (int j = 0; j < blocks; j++) + { + // 写入块首部 + block_num = j; + int writeCnt = fwrite(&block_num, sizeof(block_num), 1, fstream_w); // // 数据块号 + writeCnt = fwrite(&btimestamp, sizeof(btimestamp), 1, fstream_w); // 时间戳 + writeCnt = fwrite(&offset, sizeof(offset), 1, fstream_w); // 块内偏移表 + // 写入记录 + char* p_schema = NULL; + unsigned int timestamp = j; + unsigned int length = 316; + char namePtr[32]; + char adrressPtr[256]; + char genderPtr[4]; + char birthdayPtr[12]; + for (int i = 0; i < FRAMESIZE / RECORDSIZE; i++) + { + writeCnt = fwrite(&fstream_w, sizeof(fstream_w), 1, fstream_w); + writeCnt = fwrite(&length, sizeof(length), 1, fstream_w); + writeCnt = fwrite(×tamp, sizeof(timestamp), 1, fstream_w); + writeCnt = fwrite(&namePtr, sizeof(namePtr), 1, fstream_w); + writeCnt = fwrite(&adrressPtr, sizeof(adrressPtr), 1, fstream_w); + writeCnt = fwrite(&genderPtr, sizeof(genderPtr), 1, fstream_w); + writeCnt = fwrite(&birthdayPtr, sizeof(birthdayPtr), 1, fstream_w); + } + char null[272]; // 填充字节使得4KB对齐 + writeCnt = fwrite(&null, sizeof(null), 1, fstream_w); + } + + + fclose(fstream_w); +} + + +void NoIndexQuery(int find_block_num) +{ + FILE* fstream_r; + fstream_r = fopen("database.dbf", "rb"); + unsigned int blocknum = 0; + cout << "query target: " << find_block_num << endl; + int offset = find_block_num * FRAMESIZE; + fseek(fstream_r, offset, SEEK_SET); + int readCnt = fread(&blocknum, sizeof(blocknum), 1, fstream_r); + cout << " query result: " << blocknum << endl; + + fclose(fstream_r); +} + +void processTrace(int page_id, int operation, LRU* LRUCache) { + if (operation == 0) + { +#if VERBOSE + cout << "---[trace 读操作] 读取page_id:" << page_id << " 的数据---" << endl; +#endif + LRUCache->readData(page_id); + } + else if (operation == 1) + { +#if VERBOSE + cout << "---[trace 写操作] 修改page_id:" << page_id << " 的数据---" << endl; +#endif + LRUCache->writeData(page_id, NULL); + } +} + + +int main() +{ + cout << "*****************************************" << endl; + cout << "*****************************************" << endl; + cout << "\n"; + CreateBlockWRTest(50000); + string tracefilename = "data-5w-50w-zipf.txt"; + ifstream traceFile(tracefilename.c_str()); + if (!traceFile) + { + cout << "Error opening " << tracefilename << " for input" << endl; + exit(-1); + } + else { + cout << "Open " << tracefilename << " successfully!" << endl; + } + char dbpath[] = "database.dbf"; + LRU LRU(BUFFSIZE, dbpath); + int wr = 0; + int page_id = 0; + string trace; + int request_num = 0; + cout << "缓冲区大小:" << BUFFSIZE << endl; + start = clock(); + while (!traceFile.eof()) + { + getline(traceFile, trace); + std::vector res = split(trace, ","); + str2int(wr, res[0]); + str2int(page_id, res[1]); + processTrace(page_id, wr, &LRU); + request_num++; + } + t_end = clock(); + LRU.saveDirty2Disk(); + cout << "读写总数:" << request_num << endl; + cout << "IO总数:" << LRU.getIOnum() << endl; + cout << "命中总数:" << LRU.getHitNum() << endl; + printf("命中率:%f%%\n", 100 * LRU.getHitNum() / float(request_num)); + duration = ((double)t_end - start) / CLOCKS_PER_SEC; + printf("平均读写时间: %f ms\n", duration); + system("pause"); + traceFile.close(); +} diff --git a/src/observer/storage/buffer/buffer_LRU.h b/src/observer/storage/buffer/buffer_LRU.h new file mode 100644 index 000000000..3efc1b451 --- /dev/null +++ b/src/observer/storage/buffer/buffer_LRU.h @@ -0,0 +1,329 @@ +#include "stdio.h" +#include +#include +#include +#include +#include +#include +#include + +#define VERBOSE 0 +#define RECORDSIZE 316 +#define FRAMESIZE 4096 +#define BUFFSIZE 1024 // 可修改缓冲区大小 +#define MAXSIZE FRAMESIZE*BUFFSIZE + +using namespace std; + +struct bFrame +{ + char field[FRAMESIZE]; +}; + +struct bBuff +{ + bFrame frames[BUFFSIZE]; +}; + + + +struct Record +{ + int page_id; + int slot_num; +}; + +struct Frame +{ + int frame_id; + int offset; +}; + + +class DiskSpaceManager { +private: + FILE* fstream; +public: + DiskSpaceManager() :fstream(NULL) {} + + void openFile(char filepath[]) { + fstream = fopen(filepath, "rb+"); + } + + void readDisk(int page_id, int frame_id, bBuff* buff) { + bFrame bframe; + unsigned int block_num = 0; + fseek(fstream, page_id * FRAMESIZE, SEEK_SET); + if (fread(&bframe.field, sizeof(bframe.field), 1, fstream) == 1) { +#if VERBOSE + cout << "读取 page_id:" << page_id << " 到 frame_id:" << frame_id << " ... 缓存成功。" << endl; +#endif + } + else { +#if VERBOSE + cout << "读取 page_id:" << page_id << " 到 frame_id:" << frame_id << " ... 缓存失败!" << endl; +#endif + } + buff->frames[frame_id] = bframe; + } + + void writeDisk(int page_id, int frame_id, bBuff* buff) { + bFrame bframe = buff->frames[frame_id]; + fseek(fstream, page_id * FRAMESIZE, SEEK_SET); + if (fwrite(&bframe.field, sizeof(bframe.field), 1, fstream) == 1) { +#if VERBOSE + cout << "写入 frame_id:" << frame_id << " 到 page_id:" << page_id << " 磁盘成功。" << endl; +#endif + } + else { +#if VERBOSE + cout << "写入 frame_id:" << frame_id << " 到 page_id:" << page_id << " 磁盘失败!" << endl; +#endif + } + } +}; + +//双向链表+哈希表实现LRU +struct BufferControlBlocks +{ + int page_id, frame_id, ref, count, time, dirty; + BufferControlBlocks* _prev; + BufferControlBlocks* _next; + BufferControlBlocks() : _next(NULL), _prev(NULL) {} + BufferControlBlocks(int page_id, int frame_id) : page_id(page_id), frame_id(frame_id), count(0), time(0), dirty(0) { BufferControlBlocks(); } + void disconnect() { + if (_prev) _prev->_next = _next; + if (_next) _next->_prev = _prev; + } + void Insert(BufferControlBlocks* node) { + if (_next) { + node->_prev = this; // this + _next->_prev = node; + node->_next = _next; + _next = node; + } + } +}; +// 储存frames和pages的元数据Buffer Control Blocks +class LRU { +private: + int size, capacity; //当前大小,容量上限 + unordered_map hashmap; + stack frame_ids; + BufferControlBlocks* head, * tail; + int hitNum; // 命中数 + int IONum; // 磁盘IO + bBuff* buff; + int f2p[BUFFSIZE]; // frame_id到page_id的映射 + DiskSpaceManager diskSpaceManager; +public: + LRU(int capacity, char dbpath[]) : size(0), capacity(capacity) { + head = new BufferControlBlocks; + tail = new BufferControlBlocks; + head->_next = tail; + tail->_prev = head; + hitNum = IONum = 0; + buff = new bBuff; + diskSpaceManager.openFile(dbpath); + for (int i = 0; i < BUFFSIZE; i++)f2p[i] = 0; + for (int i = 0; i < capacity; i++)frame_ids.push(i); + } + int read(int page_id) { + if (hashmap.find(page_id) == hashmap.end()) { +#if VERBOSE + cout << "该page_id: " << page_id << " 未存在于缓存中!" << endl; +#endif + return -1; + } + BufferControlBlocks* node = hashmap[page_id]; + node->disconnect(); + head->Insert(node); + int fid = node->frame_id; + return fid; + } + + int read_id(int page_id) { + if (hashmap.find(page_id) == hashmap.end()) { +#if VERBOSE + cout << "该page_id: " << page_id << " 未存在于缓存中!"; +#endif + return -1; + } + BufferControlBlocks* node = hashmap[page_id]; + return node->frame_id; + } + + int put(int page_id, int frame_id = 0) { + BufferControlBlocks* node; + if (page_id == -1) { cout << "申请磁盘新page" << endl; }; + if (hashmap.find(page_id) == hashmap.end()) { + if (size < capacity) { + frame_id = frame_ids.top(); + frame_ids.pop(); + node = new BufferControlBlocks(page_id, frame_id); + size++; + } + else + { + // 置换 + node = tail->_prev; + int i = 0; + for (; node->ref > 1 || node->count > 1; node = node->_next) + { + node->ref = 0; i++; if (i == capacity - 1) { cout << "警告:缓存溢出!进行强行置换"; }; + break; + }; + // 脏数据写入磁盘 + if (node->dirty) + { + node->dirty = 0; + diskSpaceManager.writeDisk(node->page_id, node->frame_id, buff); +#if VERBOSE + cout << "缓存区满,发生置换,已将page_id:" << node->page_id << " 数据块写入磁盘!" << endl; +#endif + } + frame_id = node->frame_id; + node->disconnect(); + hashmap.erase(node->page_id); + node->page_id = page_id; + node->frame_id = frame_id; + } + hashmap[page_id] = node; + head->Insert(node); + } + else { + node = hashmap[page_id]; + node->disconnect(); + head->Insert(node); + frame_id = node->frame_id; + } + return frame_id; + } + + int selectVictim() { + BufferControlBlocks* node; + node = tail->_prev; + int i = 0; + for (; node->ref > 1 || node->count > 1; node = node->_next) + { + node->ref = 0; i++; if (i == capacity) { cout << "缓存溢出!即将进行强行置换"; }; + }; + return node->frame_id; + } + + void remove(int page_id) { + if (hashmap.find(page_id) == hashmap.end()) { + cout << "错误!page_id: " << page_id << " 不存在缓存中!" << endl; + } + + BufferControlBlocks* node = hashmap[page_id]; + frame_ids.push(node->frame_id); + node->disconnect(); + hashmap.erase(node->page_id); + size--; + } + + int setDirty(int page_id) { + if (hashmap.find(page_id) == hashmap.end()) { + return -1; + } + BufferControlBlocks* node = hashmap[page_id]; + node->dirty = 1; + node->time += 1; + node->disconnect(); // �����ײ� + head->Insert(node); + return node->frame_id; + } + + int setCount(int page_id) { + if (hashmap.find(page_id) == hashmap.end()) { + return -1; + } + BufferControlBlocks* node = hashmap[page_id]; + node->count += 1; + node->time += 1; + node->disconnect(); + head->Insert(node); + return node->frame_id; + } + + unsigned int readData(int page_id) { + int frame_id = read(page_id); + if (frame_id == -1) + { + + IONum++; + frame_id = put(page_id); + diskSpaceManager.readDisk(page_id, frame_id, buff); + } + else { + + hitNum++; + } +#if VERBOSE + unsigned int* bln_ptr; + char bln[4]; + for (int i = 0; i < 4; i++) + { + bln[i] = buff->frames[frame_id].field[i]; + } + bln_ptr = (unsigned int*)&bln; + cout << "读到的数据(块号):" << *bln_ptr << " (指针指向块头,读取长度为4bit,记录着该块在整个.dbf文件的块号)" << endl; + if (*bln_ptr == page_id) cout << "读取数据验证通过!" << endl; +#endif + return 1; + } + + int writeData(int page_id, char* data) { + int frame_id = read(page_id); + if (frame_id == -1) + { + + IONum++; + frame_id = put(page_id); + diskSpaceManager.readDisk(page_id, frame_id, buff); + } + else { + + hitNum++; + } + buff->frames[frame_id].field[1]++; + BufferControlBlocks* node = hashmap[page_id]; + node->dirty = 1; +#if VERBOSE + unsigned int* timestamp; + char ts[4]; + for (int i = 0; i < 4; i++) + { + ts[i] = buff->frames[frame_id].field[4 + i]; + } + timestamp = (unsigned int*)&ts; + cout << "即将写入的数据(时间戳):" << *timestamp << " (指针指向距离块头4bit位置,写入长度为4bit,记录着该块的时间戳)" << endl;; +#endif + return 1; + } + + int getIOnum() { + return IONum; + } + + int getHitNum() { + return hitNum; + } + + void saveDirty2Disk() { + for (BufferControlBlocks* node = head->_next; node != tail; node = node->_next) + { + if (node->dirty == 1) + { + diskSpaceManager.writeDisk(node->page_id, node->frame_id, buff); + IONum++; + node->dirty = 0; + } + } + delete tail, head, buff; +#if VERBOSE + cout << "即将关闭LRUCache: 已将全部脏数据写进磁盘!" << endl; +#endif + } +};