tinySQL  0.1
A self-contained database management system
buffer_manager.cpp
1 
11 #include "buffer/buffer_manager.h"
12 #include <cstring>
13 #include <utility>
14 
20  initialize();
21 }
27  file_name_ = "";
28  block_id_ = -1;
29  pin_count_ = 0;
30  dirty_ = false;
31  avaliable_ = true;
32  timeb t;
33  ftime(&t);
34  last_access_time = t.time * 1000 + t.millitm;
35  memset(buffer_, 0, sizeof(char) * PAGESIZE);
36 // for (char & i : buffer_)
37 // i = '\0';
38 }
39 
40 
41 inline void Page::setFileName(std::string file_name) {
42  file_name_ = std::move(file_name);
43 }
44 
45 inline std::string Page::getFileName() const {
46  return file_name_;
47 }
48 
49 inline void Page::setBlockId(int block_id) {
50  block_id_ = block_id;
51 }
52 
53 inline int Page::getBlockId() const {
54  return block_id_;
55 }
56 
57 inline void Page::setPinCount(int pin_count) {
58  pin_count_ = pin_count;
59 }
60 
61 inline int Page::getPinCount() const {
62  return pin_count_;
63 }
64 
65 inline void Page::setDirty(bool dirty) {
66  dirty_ = dirty;
67 }
68 
69 inline bool Page::isDirty() const {
70  return dirty_;
71 }
72 
73 inline void Page::setAvaliable(bool avaliable) {
74  avaliable_ = avaliable;
75 }
76 
77 inline bool Page::getAvaliable() const {
78  return avaliable_;
79 }
80 inline void Page::setTime(){
81  timeb t;
82  ftime(&t);
83  last_access_time = t.time * 1000 + t.millitm;
84 }
85 inline long long Page::getTime(){
86  return last_access_time;
87 }
88 inline char* Page::getBuffer() {
89  return buffer_;
90 }
91 
97  initialize(MAXFRAMESIZE);
98 }
99 
100 BufferManager::BufferManager(int frame_size) {
101  initialize(frame_size);
102 }
103 
109  for (int i = 0;i < frame_size_;i++) {
110  std::string file_name;
111  flushPage(i);
112  }
113 }
114 
115 
116 void BufferManager::initialize(int frame_size) {
117  Frames = new Page[frame_size];//在堆上分配内存
118  frame_size_ = frame_size;
119  current_position_ = 0;
120 }
121 
130 char* BufferManager::getPage(const std::string& file_name , int block_id){
131  int page_id = getPageId(file_name , block_id);
132  if (page_id == -1) {
133  page_id = getEmptyPageId();
134  loadDiskBlock(page_id , file_name , block_id);
135  }
136  Frames[page_id].setTime();
137  return Frames[page_id].getBuffer();
138 }
139 
140 char* BufferManager::getPage(const std::string& file_name , int block_id , pageId_t& pageId){
141  pageId_t page_id = getPageId(file_name , block_id);
142  if (page_id == -1) {
143  page_id = getEmptyPageId();
144  loadDiskBlock(page_id , file_name , block_id);
145  }
146  pageId = page_id;
147  Frames[page_id].setTime();
148  return Frames[page_id].getBuffer();
149 }
155 void BufferManager::modifyPage(int page_id) {
156  Frames[page_id].setDirty(true);
157 }
163 void BufferManager::pinPage(int page_id) {
164  int pin_count = Frames[page_id].getPinCount();
165  Frames[page_id].setPinCount(pin_count + 1);
166 }
173 int BufferManager::unpinPage(int page_id) {
174  int pin_count = Frames[page_id].getPinCount();
175  if (pin_count <= 0)
176  return -1;
177  else
178  Frames[page_id].setPinCount(pin_count - 1);
179  return 0;
180 }
181 
190 int BufferManager::loadDiskBlock(int page_id , const std::string& file_name , int block_id) {
191  // 初始化一个页
192  Frames[page_id].initialize();
193  // 打开磁盘文件
194  FILE* f = fopen(file_name.c_str() , "r");
195  // 打开失败返回-1
196  if (f == nullptr)
197  throw DB_FILE_NOT_FOUND;
198 
199  // 将文件指针定位到对应位置
200  fseek(f , PAGESIZE * block_id , SEEK_SET);
201  // 获取页的句柄
202  char* buffer = Frames[page_id].getBuffer();
203  // 读取对应磁盘块到内存页
204  fread(buffer , PAGESIZE , 1 , f);
205  // 关闭文件
206  fclose(f);
207  // 对新载入的页进行相应设置
208  Frames[page_id].setFileName(file_name);
209  Frames[page_id].setBlockId(block_id);
210  Frames[page_id].setPinCount(0);
211  Frames[page_id].setDirty(false);
212  Frames[page_id].setAvaliable(false);
213 
214  fname_page_map.emplace(Frames[page_id].getPageStrId(), page_id);
215 
216  return 0;
217 }
218 
227 int BufferManager::flushPage(pageId_t page_id) {
228  // Add this to avoid write of an empty file_name, a file that has been deleted, etc.
229  auto file_path = Frames[page_id].getFileName();
230  auto block_id = Frames[page_id].getBlockId();
231 
232  auto iter = fname_page_map.find(Frames[page_id].getPageStrId());
233  if (iter == fname_page_map.end()) return -1;
234 
235  // 打开文件
236  FILE* f = fopen(file_path.c_str() , "r+");
237  // 其实这里有写多余,因为打开一个文件读总是能成功。
238  if (f == nullptr)
239  throw DB_FILE_NOT_FOUND;
240  // 将文件指针定位到对应位置
241  fseek(f , PAGESIZE * block_id , SEEK_SET);
242  // 获取页的句柄
243  char* buffer = Frames[page_id].getBuffer();
244  // 将内存页的内容写入磁盘块
245  fwrite(buffer , PAGESIZE , 1 , f);
246  // 关闭文件
247  fclose(f);
248  return 0;
249 }
250 
258 pageId_t BufferManager::getPageId(const std::string& file_name , int block_id) {
259  auto page_id_iter = fname_page_map.find(Page::generatePageStrId(file_name, block_id));
260  if (page_id_iter != fname_page_map.end()) return page_id_iter->second;
261  else return -1;
262 }
263 
270 int BufferManager::getBlockNum(const std::string& file_name){
271  char* p;
272  int block_num = -1;
273  do {
274  p = getPage(file_name, block_num + 1);
275  block_num++;
276  } while(p[0] != '\0');
277  return block_num;
278 }
284 pageId_t BufferManager::getEmptyPageId(){
285  for (int i = 0;i < frame_size_;i++) {
286  // Avaliable means the page doesn't hold a disk block.
287  if (Frames[i].getAvaliable())
288  return i;
289  }
290  int check = 0;
291  for (int i = 0;i < frame_size_;i++) {
292  if (Frames[i].getPinCount() == 0){
293  check = 1;
294  break;
295  }
296  }
297  if(check == 0)
298  throw DB_ALL_PAGES_PINNED;
299 
300  while(true){
301  timeb t;
302  ftime(&t);
303  long long now = t.time * 1000 + t.millitm + 1;
304  for (int i = 0; i < frame_size_; i++){
305  if(Frames[i].getPinCount() == 0 && Frames[i].getTime() < now){
306  current_position_ = i;
307  now = Frames[i].getTime();
308  }
309  }
310  if (Frames[current_position_].isDirty()) {
311  std::string file_name = Frames[current_position_].getFileName();
312  int block_id = Frames[current_position_].getBlockId();
313  flushPage(current_position_);
314  }
315  // 删除页
316  fname_page_map.erase(Frames[current_position_].getPageStrId());
317  Frames[current_position_].initialize();
318  // 返回页号
319  return current_position_;
320  }
321 }
322 
BufferManager::getBlockNum
int getBlockNum(const std::string &fileName)
获取文件块数
Definition: buffer_manager.cpp:270
BufferManager::unpinPage
int unpinPage(int page_id)
解钉一次
Definition: buffer_manager.cpp:173
BufferManager::getPageId
int getPageId(const std::string &file_name, int block_id)
简单遍历获取页号
Definition: buffer_manager.cpp:258
Page::dirty_
bool dirty_
Definition: buffer_manager.h:52
Page::initialize
void initialize()
初始化
Definition: buffer_manager.cpp:26
Page
The storage details of each page in the memory.
Definition: buffer_manager.h:30
BufferManager::~BufferManager
~BufferManager()
Destroy the Buffer Manager:: Buffer Manager object.
Definition: buffer_manager.cpp:108
Page::file_name_
std::string file_name_
Definition: buffer_manager.h:49
BufferManager::flushPage
int flushPage(pageId_t page_id)
核心函数之一。内存和磁盘交互的接口。
Definition: buffer_manager.cpp:227
Page::pin_count_
int pin_count_
Definition: buffer_manager.h:51
BufferManager::modifyPage
void modifyPage(int page_id)
标记页是否被修改
Definition: buffer_manager.cpp:155
BufferManager::BufferManager
BufferManager()
Construct a new Buffer Manager:: Buffer Manager object.
Definition: buffer_manager.cpp:96
Page::block_id_
int block_id_
Definition: buffer_manager.h:50
Page::avaliable_
bool avaliable_
Definition: buffer_manager.h:53
BufferManager::pinPage
void pinPage(int page_id)
钉住一页
Definition: buffer_manager.cpp:163
BufferManager::getPage
char * getPage(const std::string &file_name, int block_id)
获取一页
Definition: buffer_manager.cpp:130
Page::Page
Page()
Construct a new Page:: Page object.
Definition: buffer_manager.cpp:19
Page::buffer_
char buffer_[PAGESIZE]
Definition: buffer_manager.h:48