-
Notifications
You must be signed in to change notification settings - Fork 0
/
buffer_manager.cc
224 lines (198 loc) · 6.23 KB
/
buffer_manager.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
//
// buffer_manager.cc
// buffer_manager
//
// Created by Hys on 2017/5/21.
// Copyright © 2017年 Hys. All rights reserved.
//
#include "buffer_manager.h"
// Page类的实现
Page::Page() {
initialize();
}
// 初始化
void Page::initialize() {
file_name_ = "";
block_id_ = -1;
pin_count_ = -1;
dirty_ = false;
ref_ = false;
avaliable_ = true;
for (int i = 0;i < PAGESIZE;i++)
buffer_[i] = '\0';
}
// 下面是一些存取控制函数,较为简单就不赘述了
inline void Page::setFileName(std::string file_name) {
file_name_ = file_name;
}
inline std::string Page::getFileName() {
return file_name_;
}
inline void Page::setBlockId(int block_id) {
block_id_ = block_id;
}
inline int Page::getBlockId() {
return block_id_;
}
inline void Page::setPinCount(int pin_count) {
pin_count_ = pin_count;
}
inline int Page::getPinCount() {
return pin_count_;
}
inline void Page::setDirty(bool dirty) {
dirty_ = dirty;
}
inline bool Page::getDirty() {
return dirty_;
}
inline void Page::setRef(bool ref) {
ref_ = ref;
}
inline bool Page::getRef() {
return ref_;
}
inline void Page::setAvaliable(bool avaliable) {
avaliable_ = avaliable;
}
inline bool Page::getAvaliable() {
return avaliable_;
}
inline char* Page::getBuffer() {
return buffer_;
}
// BufferManager类的实现
// 构造函数均调用实际初始化函数完成初始化
BufferManager::BufferManager() {
initialize(MAXFRAMESIZE);
}
BufferManager::BufferManager(int frame_size) {
initialize(frame_size);
}
// 析构函数非常重要。在程序结束时需要将缓冲池里的所有页写回磁盘。
BufferManager::~BufferManager() {
for (int i = 0;i < frame_size_;i++) {
std::string file_name;
int block_id;
file_name = Frames[i].getFileName();
block_id = Frames[i].getBlockId();
flushPage(i , file_name , block_id);
}
}
// 实际初始化函数
void BufferManager::initialize(int frame_size) {
Frames = new Page[frame_size];//在堆上分配内存
frame_size_ = frame_size;
current_position_ = 0;
}
// 下面几个函数较为简单,也不赘述了
char* BufferManager::getPage(std::string file_name , int block_id) {
int page_id = getPageId(file_name , block_id);
if (page_id == -1) {
page_id = getEmptyPageId();
loadDiskBlock(page_id , file_name , block_id);
}
Frames[page_id].setRef(true);
return Frames[page_id].getBuffer();
}
void BufferManager::modifyPage(int page_id) {
Frames[page_id].setDirty(true);
}
void BufferManager::pinPage(int page_id) {
int pin_count = Frames[page_id].getPinCount();
Frames[page_id].setPinCount(pin_count + 1);
}
int BufferManager::unpinPage(int page_id) {
int pin_count = Frames[page_id].getPinCount();
if (pin_count <= 0)
return -1;
else
Frames[page_id].setPinCount(pin_count - 1);
return 0;
}
// 核心函数之一。内存和磁盘交互的接口。
int BufferManager::loadDiskBlock(int page_id , std::string file_name , int block_id) {
// 初始化一个页
Frames[page_id].initialize();
// 打开磁盘文件
FILE* f = fopen(file_name.c_str() , "r");
// 打开失败返回-1
if (f == NULL)
return -1;
// 将文件指针定位到对应位置
fseek(f , PAGESIZE * block_id , SEEK_SET);
// 获取页的句柄
char* buffer = Frames[page_id].getBuffer();
// 读取对应磁盘块到内存页
fread(buffer , PAGESIZE , 1 , f);
// 关闭文件
fclose(f);
// 对新载入的页进行相应设置
Frames[page_id].setFileName(file_name);
Frames[page_id].setBlockId(block_id);
Frames[page_id].setPinCount(1);
Frames[page_id].setDirty(false);
Frames[page_id].setRef(true);
Frames[page_id].setAvaliable(false);
return 0;
}
// 核心函数之一。内存和磁盘交互的接口。
int BufferManager::flushPage(int page_id , std::string file_name , int block_id) {
// 打开文件
FILE* f = fopen(file_name.c_str() , "r+");
// 其实这里有写多余,因为打开一个文件读总是能成功。
if (f == NULL)
return -1;
// 将文件指针定位到对应位置
fseek(f , PAGESIZE * block_id , SEEK_SET);
// 获取页的句柄
char* buffer = Frames[page_id].getBuffer();
// 将内存页的内容写入磁盘块
fwrite(buffer , PAGESIZE , 1 , f);
// 关闭文件
fclose(f);
return 0;
}
// 简单遍历获取页号
int BufferManager::getPageId(std::string file_name , int block_id) {
for (int i = 0;i < frame_size_;i++) {
std::string tmp_file_name = Frames[i].getFileName();
int tmp_block_id = Frames[i].getBlockId();
if (tmp_file_name == file_name && tmp_block_id == block_id)
return i;
}
return -1;
}
// 寻找一个闲置的页
int BufferManager::getEmptyPageId() {
// 先简单的遍历一遍,如果有闲置的直接返回其页号
for (int i = 0;i < frame_size_;i++) {
if (Frames[i].getAvaliable() == true)
return i;
}
// 如果所有页都已经被使用,那么需要找到一个页,将其删除掉。
// 这里需要使用一些策略来选择哪一个页应该被删除。
// 本程序中采用时钟替换策略。
while (1) {
// 如果页的ref为true,将其设为false
if (Frames[current_position_].getRef() == true) {
Frames[current_position_].setRef(false);
}
// 否则,如果页对应的pin_count为0,即页没有被锁住,那么这一页就
// 会被删除。
else if (Frames[current_position_].getPinCount() == 0) {
// 如果这一页被改动过,需要将其写回磁盘,然后删除
if (Frames[current_position_].getDirty() == true) {
std::string file_name = Frames[current_position_].getFileName();
int block_id = Frames[current_position_].getBlockId();
flushPage(current_position_ , file_name , block_id);
}
// 删除页
Frames[current_position_].initialize();
// 返回页号
return current_position_;
}
// 时钟指针顺时针转动
current_position_ = (current_position_ + 1) % frame_size_;
}
}