GCC Code Coverage Report


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