-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathPageCache.cpp
More file actions
211 lines (178 loc) · 4.27 KB
/
PageCache.cpp
File metadata and controls
211 lines (178 loc) · 4.27 KB
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
#include"PageCache.h"
//类内声明,类外初始化
PageCache PageCache::_sInst;
// 向系统申请k页内存
void* PageCache::SystemAllocPage(size_t k)
{
return ::SystemAlloc(k);
}
//申请num页的内存
Span* PageCache::NewSpan(size_t num)
{
std::lock_guard<std::recursive_mutex> lock(_mtx);
//针对直接申请大于128页的内存,直接向系统要
if (num >= 128)
{
//在系统申请
void* ptr = SystemAllocPage(num);
Span* span = new Span;
span->_pageId = (ADDRES_INT)ptr >> PAGE_SHIFT;
span->_n = num;
{
//std::lock_guard<std::mutex> lock(_map_mtx);
_idSpanMap[span->_pageId] = span;
}
return span;
}
else
{
if (!_spanList[num - 1].isEmpty())
_spanList[num - 1].isEmpty();
//走到这里说明没有内存,需要向后判断是否有num页的内存
//向后找
for (int i = num; i < 128; i++)
{
if (!_spanList[i].isEmpty())
{
//切num页给_spanList[num - 1]
Span* span = _spanList[i].PopFront();
//切出来的内存---采用尾切
Span* split = new Span;
split->_n = num;
split->_next = nullptr;
//span中有多页,它存储的页号是第一页的页号,因此这里的页号应该是切出来的页数+初始页号
split->_pageId = span->_pageId+span->_n-num;
// 改变切出来span的页号和span的映射关系
{
//std::lock_guard<std::mutex> lock(_map_mtx);
for (PageID i = 0; i < num; ++i)
{
_idSpanMap[split->_pageId + i] = split;
}
}
//将Span剩余的页挂在对应的位置
span->_n -= num;
_spanList[span->_n - 1].PushFront(span);
return split;
}
}
//走到这里说明page cache中没有内存,向系统申请
Span* bigSpan = new Span;
void* memory = SystemAllocPage(MAX_PAGE);
//计算出页号
bigSpan->_pageId = (size_t)memory >> 12;
bigSpan->_n = MAX_PAGE;
// 按页号和span映射关系建立,也就是这么多个页都映射在这个span中
{
//std::lock_guard<std::mutex> lock(_map_mtx);
for (PageID i = 0; i < bigSpan->_n; ++i)
{
PageID id = bigSpan->_pageId + i;
_idSpanMap[id] = bigSpan;
}
}
//将内存链接到spanlist中
_spanList[MAX_PAGE - 1].Insert(_spanList[MAX_PAGE - 1].Begin(), bigSpan);
//重新切割
return NewSpan(num);
}
}
//通过内存地址在map中查找对应的span
Span* PageCache::GetSpanToMap(void* mem)
{
//根据内存计算页号
PageID id = (ADDRES_INT)mem >> PAGE_SHIFT;
//在map中查找
auto ret = _idSpanMap.get(id);
if (ret != nullptr)
{
return ret;
}
else
{
assert(false);
return nullptr;
}
}
// 释放空闲span回到Pagecache,并合并相邻的span
void PageCache::ReleaseSpanToPageCache(Span* span)
{
if (span->_n >= MAX_PAGE)
{
//大于128页的内存直接还给系统内存
_idSpanMap.erase(span->_pageId);
//根据页号计算地址
void* ptr = (void*)(span->_pageId << PAGE_SHIFT);
SystemFree(ptr);
delete span;
return;
}
std::lock_guard<std::recursive_mutex> lock(_mtx);
// 检查前后空闲span页,进行合并,解决内存碎片问题
// 向前合并
while (1)
{
PageID preId = span->_pageId - 1;
Span* preSpan = _idSpanMap.get(preId);
if (preSpan == nullptr)
{
break;
}
// 如果前一个页的span还在使用中,结束向前合并
if (preSpan->_usecount != 0)
{
break;
}
// 开始合并...
// 超过128页,不需要合并了
if (preSpan->_n + span->_n >= MAX_PAGE)
{
break;
}
// 从对应的span链表中解下来,再合并
_spanList[preSpan->_n].Erase(preSpan);
span->_pageId = preSpan->_pageId;
span->_n += preSpan->_n;
// 更新页之间映射关系
{
//std::lock_guard<std::mutex> lock(_map_mtx);
for (PageID i = 0; i < preSpan->_n; ++i)
{
_idSpanMap[preSpan->_pageId + i] = span;
}
}
delete preSpan;
}
// 向后合并
while (1)
{
PageID nextId = span->_pageId + span->_n;
Span* nextSpan = _idSpanMap.get(nextId);
if (nextSpan == nullptr)
{
break;
}
//Span* nextSpan = ret->second;
if (nextSpan->_usecount != 0)
{
break;
}
// 超过128页,不需要合并了
if (nextSpan->_n + span->_n >= MAX_PAGE)
{
break;
}
_spanList[nextSpan->_n].Erase(nextSpan);
span->_n += nextSpan->_n;
{
//std::lock_guard<std::mutex> lock(_map_mtx);
for (PageID i = 0; i < nextSpan->_n; ++i)
{
_idSpanMap[nextSpan->_pageId + i] = span;
}
}
delete nextSpan;
}
// 合并出的大span,插入到对应的链表中
_spanList[span->_n].PushFront(span);
}