-
Notifications
You must be signed in to change notification settings - Fork 47
/
swap_space.cpp
128 lines (110 loc) · 3.08 KB
/
swap_space.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include "swap_space.hpp"
void serialize(std::iostream &fs, serialization_context &context, uint64_t x)
{
fs << x << " ";
assert(fs.good());
}
void deserialize(std::iostream &fs, serialization_context &context, uint64_t &x)
{
fs >> x;
assert(fs.good());
}
void serialize(std::iostream &fs, serialization_context &context, int64_t x)
{
fs << x << " ";
assert(fs.good());
}
void deserialize(std::iostream &fs, serialization_context &context, int64_t &x)
{
fs >> x;
assert(fs.good());
}
void serialize(std::iostream &fs, serialization_context &context, std::string x)
{
fs << x.size() << ",";
assert(fs.good());
fs.write(x.data(), x.size());
assert(fs.good());
}
void deserialize(std::iostream &fs, serialization_context &context, std::string &x)
{
size_t length;
char comma;
fs >> length >> comma;
assert(fs.good());
char *buf = new char[length];
assert(buf);
fs.read(buf, length);
assert(fs.good());
x = std::string(buf, length);
delete buf;
}
bool swap_space::cmp_by_last_access(swap_space::object *a, swap_space::object *b) {
return a->last_access < b->last_access;
}
swap_space::swap_space(backing_store *bs, uint64_t n) :
backstore(bs),
max_in_memory_objects(n),
objects(),
lru_pqueue(cmp_by_last_access)
{}
swap_space::object::object(swap_space *sspace, serializable * tgt) {
target = tgt;
id = sspace->next_id++;
bsid = 0;
is_leaf = false;
refcount = 1;
last_access = sspace->next_access_time++;
target_is_dirty = true;
pincount = 0;
}
void swap_space::set_cache_size(uint64_t sz) {
assert(sz > 0);
max_in_memory_objects = sz;
maybe_evict_something();
}
void swap_space::write_back(swap_space::object *obj)
{
assert(objects.count(obj->id) > 0);
debug(std::cout << "Writing back " << obj->id
<< " (" << obj->target << ") "
<< "with last access time " << obj->last_access << std::endl);
// This calls _serialize on all the pointers in this object,
// which keeps refcounts right later on when we delete them all.
// In the future, we may also use this to implement in-memory
// evictions, i.e. where we first "evict" an object by
// compressing it and keeping the compressed version in memory.
serialization_context ctxt(*this);
std::stringstream sstream;
serialize(sstream, ctxt, *obj->target);
obj->is_leaf = ctxt.is_leaf;
if (obj->target_is_dirty) {
std::string buffer = sstream.str();
uint64_t bsid = backstore->allocate(buffer.length());
std::iostream *out = backstore->get(bsid);
out->write(buffer.data(), buffer.length());
backstore->put(out);
if (obj->bsid > 0)
backstore->deallocate(obj->bsid);
obj->bsid = bsid;
obj->target_is_dirty = false;
}
}
void swap_space::maybe_evict_something(void)
{
while (current_in_memory_objects > max_in_memory_objects) {
object *obj = NULL;
for (auto it = lru_pqueue.begin(); it != lru_pqueue.end(); ++it)
if ((*it)->pincount == 0) {
obj = *it;
break;
}
if (obj == NULL)
return;
lru_pqueue.erase(obj);
write_back(obj);
delete obj->target;
obj->target = NULL;
current_in_memory_objects--;
}
}