GCC Code Coverage Report


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