GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/sqlitemem.cc
Date: 2025-06-22 02:36:02
Exec Total Coverage
Lines: 154 159 96.9%
Branches: 80 122 65.6%

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