-
Notifications
You must be signed in to change notification settings - Fork 1
/
PageCache.cpp
108 lines (88 loc) · 2.39 KB
/
PageCache.cpp
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
#include "PageCaceh.h"
PageCache PageCache::_inst;
Span* PageCache::NewSpan(size_t npage)
{
if (!_pagelist[npage].Empty())
{
return _pagelist[npage].PopFront();
}
for (size_t i = npage+1; i < NPAGES; ++i)
{
SpanList* pagelist = &_pagelist[i];
if (!pagelist->Empty())
{
Span* span = pagelist->PopFront();
Span* split = new Span;
split->_pageid = span->_pageid + span->_npage - npage;
split->_npage = npage;
span->_npage -= npage;
_pagelist[span->_npage].PushFront(span);
for (size_t i = 0; i < split->_npage; ++i)
{
_id_span_map[split->_pageid + i] = split;
}
return split;
}
}
// 需要向系统申请内存
void* ptr = VirtualAlloc(NULL, (NPAGES - 1) << PAGE_SHIFT, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (ptr == nullptr)
{
throw std::bad_alloc();
}
Span* largespan = new Span;
largespan->_pageid = (PageID)ptr >> PAGE_SHIFT;
largespan->_npage = NPAGES - 1;
_pagelist[NPAGES - 1].PushFront(largespan);
for (size_t i = 0; i < largespan->_npage; ++i)
{
_id_span_map[largespan->_pageid+i] = largespan;
}
return NewSpan(npage);
}
// 获取从对象到span的映射
Span* PageCache::MapObjectToSpan(void* obj)
{
PageID pageid = (PageID)obj >> PAGE_SHIFT;
auto it = _id_span_map.find(pageid);
assert(it != _id_span_map.end());
return it->second;
}
// 释放空闲span回到Pagecache,并合并相邻的span
void PageCache::ReleaseSpanToPageCahce(Span* span)
{
auto previt = _id_span_map.find(span->_pageid - 1);
while (previt != _id_span_map.end())
{
Span* prevspan = previt->second;
// 不是空闲,则直接跳出
if (prevspan->_usecount != 0)
break;
// 如果合并出超过NPAGES页的span,则不合并,否则没办法管理
if (prevspan->_npage + span->_npage >= NPAGES)
break;
_pagelist[prevspan->_npage].Erase(prevspan);
prevspan->_npage += span->_npage;
delete span;
span = prevspan;
previt = _id_span_map.find(span->_pageid - 1);
}
auto nextit = _id_span_map.find(span->_pageid + span->_npage);
while (nextit != _id_span_map.end())
{
Span* nextspan = nextit->second;
if (nextspan->_usecount != 0)
break;
if (span->_npage + nextspan->_npage >= NPAGES)
break;
_pagelist[nextspan->_npage].Erase(nextspan);
span->_npage += nextspan->_npage;
delete nextspan;
nextit = _id_span_map.find(span->_pageid + span->_npage);
}
for (size_t i = 0; i < span->_npage; ++i)
{
_id_span_map[span->_pageid + i] = span;
}
_pagelist[span->_npage].PushFront(span);
}