1 |
|
|
/** |
2 |
|
|
* This file is part of the CernVM File System. |
3 |
|
|
*/ |
4 |
|
|
|
5 |
|
|
#define __STDC_FORMAT_MACROS |
6 |
|
|
|
7 |
|
|
#include "cvmfs_config.h" |
8 |
|
|
#include "sqlitemem.h" |
9 |
|
|
|
10 |
|
|
#include <cassert> |
11 |
|
|
#include <cstddef> |
12 |
|
|
#include <cstring> |
13 |
|
|
#include <new> |
14 |
|
|
|
15 |
|
|
#include "malloc_arena.h" |
16 |
|
|
#include "smalloc.h" |
17 |
|
|
#include "util_concurrency.h" |
18 |
|
|
|
19 |
|
|
using namespace std; // NOLINT |
20 |
|
|
|
21 |
|
|
|
22 |
|
1352 |
void *SqliteMemoryManager::LookasideBufferArena::GetBuffer() { |
23 |
✓✓ |
3316 |
for (unsigned i = 0; i < kNoBitmaps; ++i) { |
24 |
|
3304 |
int bit_set = ffs(freemap_[i]); |
25 |
✓✓ |
3304 |
if (bit_set != 0) { |
26 |
|
1340 |
freemap_[i] &= ~(1 << (bit_set - 1)); // set bit to zero |
27 |
|
1340 |
const int nbuffer = i * sizeof(int) * 8 + bit_set - 1; |
28 |
|
1340 |
return reinterpret_cast<char *>(arena_) + nbuffer * kBufferSize; |
29 |
|
|
} |
30 |
|
|
} |
31 |
|
12 |
return NULL; |
32 |
|
|
} |
33 |
|
|
|
34 |
|
|
|
35 |
|
532 |
bool SqliteMemoryManager::LookasideBufferArena::IsEmpty() { |
36 |
✓✓ |
1364 |
for (unsigned i = 0; i < kNoBitmaps; ++i) { |
37 |
✓✓ |
1348 |
if (~freemap_[i] != 0) |
38 |
|
516 |
return false; |
39 |
|
|
} |
40 |
|
16 |
return true; |
41 |
|
|
} |
42 |
|
|
|
43 |
|
|
|
44 |
|
1352 |
bool SqliteMemoryManager::LookasideBufferArena::Contains(void *buffer) { |
45 |
✓✗✓✓
|
1352 |
if ((buffer == NULL) || (buffer < arena_)) |
46 |
|
4 |
return false; |
47 |
|
|
return (static_cast<uint64_t>( |
48 |
|
|
(reinterpret_cast<char *>(buffer) - reinterpret_cast<char *>(arena_))) < |
49 |
|
1348 |
kArenaSize); |
50 |
|
|
} |
51 |
|
|
|
52 |
|
|
|
53 |
|
165 |
SqliteMemoryManager::LookasideBufferArena::LookasideBufferArena() |
54 |
|
165 |
: arena_(sxmmap(kArenaSize)) |
55 |
|
|
{ |
56 |
|
|
// All buffers unused, i.e. all bits set |
57 |
|
165 |
memset(freemap_, 0xFF, kNoBitmaps * sizeof(int)); |
58 |
|
165 |
} |
59 |
|
|
|
60 |
|
|
|
61 |
|
162 |
SqliteMemoryManager::LookasideBufferArena::~LookasideBufferArena() { |
62 |
|
162 |
sxunmap(arena_, kArenaSize); |
63 |
|
162 |
} |
64 |
|
|
|
65 |
|
|
|
66 |
|
1340 |
void SqliteMemoryManager::LookasideBufferArena::PutBuffer(void *buffer) { |
67 |
✗✓ |
1340 |
assert(buffer >= arena_); |
68 |
|
|
ptrdiff_t nbuffer = |
69 |
|
|
(reinterpret_cast<char *>(buffer) - reinterpret_cast<char *>(arena_)) |
70 |
|
1340 |
/ kBufferSize; |
71 |
✗✓ |
1340 |
assert(static_cast<uint64_t>(nbuffer) < kBuffersPerArena); |
72 |
|
1340 |
const int nfreemap = nbuffer / (sizeof(int) * 8); |
73 |
|
1340 |
freemap_[nfreemap] |= 1 << (nbuffer % (sizeof(int) * 8)); |
74 |
|
1340 |
} |
75 |
|
|
|
76 |
|
|
|
77 |
|
|
//------------------------------------------------------------------------------ |
78 |
|
|
|
79 |
|
|
|
80 |
|
|
SqliteMemoryManager *SqliteMemoryManager::instance_ = NULL; |
81 |
|
|
|
82 |
|
|
|
83 |
|
|
/** |
84 |
|
|
* Sqlite ensures that size > 0. |
85 |
|
|
*/ |
86 |
|
125555 |
void *SqliteMemoryManager::xMalloc(int size) { |
87 |
|
125555 |
return instance_->GetMemory(size); |
88 |
|
|
} |
89 |
|
|
|
90 |
|
|
|
91 |
|
|
/** |
92 |
|
|
* Sqlite ensures that ptr != NULL. |
93 |
|
|
*/ |
94 |
|
125378 |
void SqliteMemoryManager::xFree(void *ptr) { |
95 |
|
125378 |
instance_->PutMemory(ptr); |
96 |
|
125378 |
} |
97 |
|
|
|
98 |
|
|
|
99 |
|
|
/** |
100 |
|
|
* Sqlite ensures that ptr != NULL and new_size > 0. |
101 |
|
|
*/ |
102 |
|
83144 |
void *SqliteMemoryManager::xRealloc(void *ptr, int new_size) { |
103 |
|
83144 |
int old_size = xSize(ptr); |
104 |
✓✓ |
83144 |
if (old_size >= new_size) |
105 |
|
2134 |
return ptr; |
106 |
|
|
|
107 |
|
81010 |
void *new_ptr = xMalloc(new_size); |
108 |
|
81010 |
memcpy(new_ptr, ptr, old_size); |
109 |
|
81010 |
xFree(ptr); |
110 |
|
81010 |
return new_ptr; |
111 |
|
|
} |
112 |
|
|
|
113 |
|
|
|
114 |
|
|
/** |
115 |
|
|
* Sqlite ensures that ptr != NULL. |
116 |
|
|
*/ |
117 |
|
184434 |
int SqliteMemoryManager::xSize(void *ptr) { |
118 |
|
184434 |
return instance_->GetMemorySize(ptr); |
119 |
|
|
} |
120 |
|
|
|
121 |
|
|
|
122 |
|
47685 |
int SqliteMemoryManager::xRoundup(int size) { |
123 |
|
47685 |
return RoundUp8(size); |
124 |
|
|
} |
125 |
|
|
|
126 |
|
|
|
127 |
|
137 |
int SqliteMemoryManager::xInit(void *app_data __attribute__((unused))) { |
128 |
|
137 |
return SQLITE_OK; |
129 |
|
|
} |
130 |
|
|
|
131 |
|
|
|
132 |
|
134 |
void SqliteMemoryManager::xShutdown(void *app_data __attribute__((unused))) { |
133 |
|
134 |
} |
134 |
|
|
|
135 |
|
|
|
136 |
|
137 |
void SqliteMemoryManager::AssignGlobalArenas() { |
137 |
✗✓ |
137 |
if (assigned_) return; |
138 |
|
|
int retval; |
139 |
|
|
|
140 |
|
|
retval = sqlite3_config(SQLITE_CONFIG_SCRATCH, scratch_memory_, |
141 |
|
137 |
kScratchSlotSize, kScratchNoSlots); |
142 |
✗✓ |
137 |
assert(retval == SQLITE_OK); |
143 |
|
|
|
144 |
|
|
retval = sqlite3_config(SQLITE_CONFIG_PAGECACHE, page_cache_memory_, |
145 |
|
137 |
kPageCacheSlotSize, kPageCacheNoSlots); |
146 |
✗✓ |
137 |
assert(retval == SQLITE_OK); |
147 |
|
|
|
148 |
|
137 |
retval = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &sqlite3_mem_vanilla_); |
149 |
✗✓ |
137 |
assert(retval == SQLITE_OK); |
150 |
|
137 |
retval = sqlite3_config(SQLITE_CONFIG_MALLOC, &mem_methods_); |
151 |
✗✓ |
137 |
assert(retval == SQLITE_OK); |
152 |
|
|
|
153 |
|
137 |
assigned_ = true; |
154 |
|
|
} |
155 |
|
|
|
156 |
|
|
|
157 |
|
|
/** |
158 |
|
|
* Needs to be the first operation on an opened sqlite database. Returns the |
159 |
|
|
* location of the buffer. |
160 |
|
|
*/ |
161 |
|
52 |
void *SqliteMemoryManager::AssignLookasideBuffer(sqlite3 *db) { |
162 |
|
52 |
MutexLockGuard lock_guard(lock_); |
163 |
|
|
|
164 |
|
52 |
void *buffer = GetLookasideBuffer(); |
165 |
✗✓ |
52 |
assert(buffer != NULL); |
166 |
|
|
int retval = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, |
167 |
|
52 |
buffer, kLookasideSlotSize, kLookasideSlotsPerDb); |
168 |
✗✓ |
52 |
assert(retval == SQLITE_OK); |
169 |
|
52 |
return buffer; |
170 |
|
|
} |
171 |
|
|
|
172 |
|
|
|
173 |
|
154 |
void SqliteMemoryManager::CleanupInstance() { |
174 |
✓✗ |
154 |
delete instance_; |
175 |
|
154 |
instance_ = NULL; |
176 |
|
154 |
} |
177 |
|
|
|
178 |
|
|
|
179 |
|
|
/** |
180 |
|
|
* Opens a new arena if necessary. |
181 |
|
|
*/ |
182 |
|
568 |
void *SqliteMemoryManager::GetLookasideBuffer() { |
183 |
|
|
void *result; |
184 |
|
|
vector<LookasideBufferArena *>::reverse_iterator reverse_iter = |
185 |
|
568 |
lookaside_buffer_arenas_.rbegin(); |
186 |
|
|
vector<LookasideBufferArena *>::reverse_iterator i_rend = |
187 |
|
568 |
lookaside_buffer_arenas_.rend(); |
188 |
✓✓ |
572 |
for (; reverse_iter != i_rend; ++reverse_iter) { |
189 |
|
568 |
result = (*reverse_iter)->GetBuffer(); |
190 |
✓✓ |
568 |
if (result != NULL) |
191 |
|
564 |
return result; |
192 |
|
|
} |
193 |
|
|
|
194 |
|
4 |
LookasideBufferArena *new_arena = new LookasideBufferArena(); |
195 |
|
4 |
lookaside_buffer_arenas_.push_back(new_arena); |
196 |
|
4 |
return new_arena->GetBuffer(); |
197 |
|
|
} |
198 |
|
|
|
199 |
|
|
|
200 |
|
184450 |
int SqliteMemoryManager::GetMemorySize(void *ptr) { |
201 |
|
184450 |
return MallocArena::GetMallocArena(ptr, kArenaSize)->GetSize(ptr); |
202 |
|
|
} |
203 |
|
|
|
204 |
|
|
|
205 |
|
|
/** |
206 |
|
|
* Opens new arenas as necessary. |
207 |
|
|
*/ |
208 |
|
205579 |
void *SqliteMemoryManager::GetMemory(int size) { |
209 |
|
205579 |
void *p = malloc_arenas_[idx_last_arena_]->Malloc(size); |
210 |
✓✓ |
205579 |
if (p != NULL) |
211 |
|
205575 |
return p; |
212 |
|
4 |
unsigned N = malloc_arenas_.size(); |
213 |
✓✓ |
8 |
for (unsigned i = 0; i < N; ++i) { |
214 |
|
4 |
p = malloc_arenas_[i]->Malloc(size); |
215 |
✗✓ |
4 |
if (p != NULL) { |
216 |
|
|
idx_last_arena_ = i; |
217 |
|
|
return p; |
218 |
|
|
} |
219 |
|
|
} |
220 |
|
4 |
idx_last_arena_ = N; |
221 |
|
4 |
MallocArena *M = new MallocArena(kArenaSize); |
222 |
|
4 |
malloc_arenas_.push_back(M); |
223 |
|
4 |
p = M->Malloc(size); |
224 |
✗✓ |
4 |
assert(p != NULL); |
225 |
|
4 |
return p; |
226 |
|
|
} |
227 |
|
|
|
228 |
|
|
|
229 |
|
157 |
SqliteMemoryManager::SqliteMemoryManager() |
230 |
|
|
: assigned_(false) |
231 |
|
|
, scratch_memory_(sxmmap(kScratchSize)) |
232 |
|
|
, page_cache_memory_(sxmmap(kPageCacheSize)) |
233 |
|
157 |
, idx_last_arena_(0) |
234 |
|
|
{ |
235 |
|
157 |
memset(&sqlite3_mem_vanilla_, 0, sizeof(sqlite3_mem_vanilla_)); |
236 |
|
157 |
int retval = pthread_mutex_init(&lock_, NULL); |
237 |
✗✓ |
157 |
assert(retval == 0); |
238 |
|
|
|
239 |
|
157 |
lookaside_buffer_arenas_.push_back(new LookasideBufferArena()); |
240 |
|
157 |
malloc_arenas_.push_back(new MallocArena(kArenaSize)); |
241 |
|
|
|
242 |
|
157 |
memset(&mem_methods_, 0, sizeof(mem_methods_)); |
243 |
|
157 |
mem_methods_.xMalloc = xMalloc; |
244 |
|
157 |
mem_methods_.xFree = xFree; |
245 |
|
157 |
mem_methods_.xRealloc = xRealloc; |
246 |
|
157 |
mem_methods_.xSize = xSize; |
247 |
|
157 |
mem_methods_.xRoundup = xRoundup; |
248 |
|
157 |
mem_methods_.xInit = xInit; |
249 |
|
157 |
mem_methods_.xShutdown = xShutdown; |
250 |
|
157 |
mem_methods_.pAppData = NULL; |
251 |
|
157 |
} |
252 |
|
|
|
253 |
|
|
|
254 |
|
|
/** |
255 |
|
|
* Must be executed only after sqlite3_shutdown. |
256 |
|
|
*/ |
257 |
|
154 |
SqliteMemoryManager::~SqliteMemoryManager() { |
258 |
✓✓ |
154 |
if (assigned_) { |
259 |
|
|
// Reset sqlite to default values |
260 |
|
|
int retval; |
261 |
|
134 |
retval = sqlite3_config(SQLITE_CONFIG_SCRATCH, NULL, 0, 0); |
262 |
✗✓ |
134 |
assert(retval == SQLITE_OK); |
263 |
|
134 |
retval = sqlite3_config(SQLITE_CONFIG_PAGECACHE, NULL, 0, 0); |
264 |
✗✓ |
134 |
assert(retval == SQLITE_OK); |
265 |
|
134 |
retval = sqlite3_config(SQLITE_CONFIG_MALLOC, &sqlite3_mem_vanilla_); |
266 |
✗✓ |
134 |
assert(retval == SQLITE_OK); |
267 |
|
|
} |
268 |
|
|
|
269 |
|
154 |
sxunmap(scratch_memory_, kScratchSize); |
270 |
|
154 |
sxunmap(page_cache_memory_, kPageCacheSize); |
271 |
✓✓ |
308 |
for (unsigned i = 0; i < lookaside_buffer_arenas_.size(); ++i) |
272 |
✓✗ |
154 |
delete lookaside_buffer_arenas_[i]; |
273 |
✓✓ |
308 |
for (unsigned i = 0; i < malloc_arenas_.size(); ++i) |
274 |
✓✗ |
154 |
delete malloc_arenas_[i]; |
275 |
|
154 |
pthread_mutex_destroy(&lock_); |
276 |
|
154 |
} |
277 |
|
|
|
278 |
|
|
|
279 |
|
|
/** |
280 |
|
|
* Only entirely empty arenas are freed to the system. In cvmfs, catalogs |
281 |
|
|
* are gradually opened and sometimes close altogether when a new root catalog |
282 |
|
|
* arrives. Hence there is no fragmentation. |
283 |
|
|
*/ |
284 |
|
568 |
void SqliteMemoryManager::PutLookasideBuffer(void *buffer) { |
285 |
|
568 |
unsigned N = lookaside_buffer_arenas_.size(); |
286 |
✓✗ |
568 |
for (unsigned i = 0; i < N; ++i) { |
287 |
✓✗ |
568 |
if (lookaside_buffer_arenas_[i]->Contains(buffer)) { |
288 |
|
568 |
lookaside_buffer_arenas_[i]->PutBuffer(buffer); |
289 |
✓✓✓✓ ✓✓ |
568 |
if ((N > 1) && lookaside_buffer_arenas_[i]->IsEmpty()) { |
290 |
✓✗ |
4 |
delete lookaside_buffer_arenas_[i]; |
291 |
|
4 |
lookaside_buffer_arenas_.erase(lookaside_buffer_arenas_.begin() + i); |
292 |
|
|
} |
293 |
|
568 |
return; |
294 |
|
|
} |
295 |
|
|
} |
296 |
|
|
assert(false); |
297 |
|
|
} |
298 |
|
|
|
299 |
|
|
|
300 |
|
|
/** |
301 |
|
|
* Closes empty areas. |
302 |
|
|
*/ |
303 |
|
125394 |
void SqliteMemoryManager::PutMemory(void *ptr) { |
304 |
|
125394 |
MallocArena *M = MallocArena::GetMallocArena(ptr, kArenaSize); |
305 |
|
125394 |
M->Free(ptr); |
306 |
|
125394 |
unsigned N = malloc_arenas_.size(); |
307 |
✓✓✓✗ ✓✓ |
125394 |
if ((N > 1) && M->IsEmpty()) { |
308 |
✓✗ |
8 |
for (unsigned i = 0; i < N; ++i) { |
309 |
✓✓ |
8 |
if (malloc_arenas_[i] == M) { |
310 |
✓✗ |
4 |
delete malloc_arenas_[i]; |
311 |
|
4 |
malloc_arenas_.erase(malloc_arenas_.begin() + i); |
312 |
|
4 |
idx_last_arena_ = 0; |
313 |
|
4 |
return; |
314 |
|
|
} |
315 |
|
|
} |
316 |
|
|
assert(false); |
317 |
|
|
} |
318 |
|
|
} |
319 |
|
|
|
320 |
|
|
|
321 |
|
|
/** |
322 |
|
|
* To be used after an sqlite database has been closed. |
323 |
|
|
*/ |
324 |
|
52 |
void SqliteMemoryManager::ReleaseLookasideBuffer(void *buffer) { |
325 |
|
52 |
MutexLockGuard lock_guard(lock_); |
326 |
|
52 |
PutLookasideBuffer(buffer); |
327 |
|
52 |
} |