GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/sqlitemem.cc Lines: 157 161 97.5 %
Date: 2019-02-03 02:48:13 Branches: 63 88 71.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 "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
}