Bug 1919608 – Add Nathan Barrett and Maxx Crawford as New Tab Page peers. r=thecount...
[gecko.git] / toolkit / xre / AutoSQLiteLifetime.cpp
blobc46bdf3d9e035f42882d404e93fb4bbe9e873e0a
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsDebug.h"
7 #include "AutoSQLiteLifetime.h"
8 #include "sqlite3.h"
9 #include "sqlite3_static_ext.h"
10 #include "mozilla/DebugOnly.h"
12 #ifdef MOZ_MEMORY
13 # include "mozmemory.h"
14 # ifdef MOZ_DMD
15 # include "nsIMemoryReporter.h"
16 # include "DMD.h"
18 namespace mozilla {
19 namespace storage {
20 extern mozilla::Atomic<size_t> gSqliteMemoryUsed;
22 } // namespace mozilla
24 using mozilla::storage::gSqliteMemoryUsed;
26 # endif
28 namespace {
30 // By default, SQLite tracks the size of all its heap blocks by adding an extra
31 // 8 bytes at the start of the block to hold the size. Unfortunately, this
32 // causes a lot of 2^N-sized allocations to be rounded up by jemalloc
33 // allocator, wasting memory. For example, a request for 1024 bytes has 8
34 // bytes added, becoming a request for 1032 bytes, and jemalloc rounds this up
35 // to 2048 bytes, wasting 1012 bytes. (See bug 676189 for more details.)
37 // So we register jemalloc as the malloc implementation, which avoids this
38 // 8-byte overhead, and thus a lot of waste. This requires us to provide a
39 // function, sqliteMemRoundup(), which computes the actual size that will be
40 // allocated for a given request. SQLite uses this function before all
41 // allocations, and may be able to use any excess bytes caused by the rounding.
43 // Note: the wrappers for malloc, realloc and moz_malloc_usable_size are
44 // necessary because the sqlite_mem_methods type signatures differ slightly
45 // from the standard ones -- they use int instead of size_t. But we don't need
46 // a wrapper for free.
48 # ifdef MOZ_DMD
50 // sqlite does its own memory accounting, and we use its numbers in our memory
51 // reporters. But we don't want sqlite's heap blocks to show up in DMD's
52 // output as unreported, so we mark them as reported when they're allocated and
53 // mark them as unreported when they are freed.
55 // In other words, we are marking all sqlite heap blocks as reported even
56 // though we're not reporting them ourselves. Instead we're trusting that
57 // sqlite is fully and correctly accounting for all of its heap blocks via its
58 // own memory accounting. Well, we don't have to trust it entirely, because
59 // it's easy to keep track (while doing this DMD-specific marking) of exactly
60 // how much memory SQLite is using. And we can compare that against what
61 // SQLite reports it is using.
63 MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(SqliteMallocSizeOfOnAlloc)
64 MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(SqliteMallocSizeOfOnFree)
66 # endif
68 static void* sqliteMemMalloc(int n) {
69 void* p = ::malloc(n);
70 # ifdef MOZ_DMD
71 gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(p);
72 # endif
73 return p;
76 static void sqliteMemFree(void* p) {
77 # ifdef MOZ_DMD
78 gSqliteMemoryUsed -= SqliteMallocSizeOfOnFree(p);
79 # endif
80 ::free(p);
83 static void* sqliteMemRealloc(void* p, int n) {
84 # ifdef MOZ_DMD
85 gSqliteMemoryUsed -= SqliteMallocSizeOfOnFree(p);
86 void* pnew = ::realloc(p, n);
87 if (pnew) {
88 gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(pnew);
89 } else {
90 // realloc failed; undo the SqliteMallocSizeOfOnFree from above
91 gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(p);
93 return pnew;
94 # else
95 return ::realloc(p, n);
96 # endif
99 static int sqliteMemSize(void* p) { return ::moz_malloc_usable_size(p); }
101 static int sqliteMemRoundup(int n) {
102 n = malloc_good_size(n);
104 // jemalloc can return blocks of size 2 and 4, but SQLite requires that all
105 // allocations be 8-aligned. So we round up sub-8 requests to 8. This
106 // wastes a small amount of memory but is obviously safe.
107 return n <= 8 ? 8 : n;
110 static int sqliteMemInit(void* p) { return 0; }
112 static void sqliteMemShutdown(void* p) {}
114 const sqlite3_mem_methods memMethods = {
115 &sqliteMemMalloc, &sqliteMemFree, &sqliteMemRealloc, &sqliteMemSize,
116 &sqliteMemRoundup, &sqliteMemInit, &sqliteMemShutdown, nullptr};
118 } // namespace
120 #endif // MOZ_MEMORY
122 namespace mozilla {
124 AutoSQLiteLifetime::AutoSQLiteLifetime() {
125 if (++AutoSQLiteLifetime::sSingletonEnforcer != 1) {
126 MOZ_CRASH("multiple instances of AutoSQLiteLifetime constructed!");
129 Init();
132 // static
133 void AutoSQLiteLifetime::Init() {
134 #ifdef MOZ_MEMORY
135 sResult = ::sqlite3_config(SQLITE_CONFIG_MALLOC, &memMethods);
136 #else
137 sResult = SQLITE_OK;
138 #endif
140 if (sResult == SQLITE_OK) {
141 // TODO (bug 1191405): do not preallocate the connections caches until we
142 // have figured the impact on our consumers and memory.
143 ::sqlite3_config(SQLITE_CONFIG_PAGECACHE, NULL, 0, 0);
145 // Load the carray extension.
146 DebugOnly<int> srv =
147 ::sqlite3_auto_extension((void (*)(void))sqlite3_carray_init);
148 MOZ_ASSERT(srv == SQLITE_OK, "Should succeed loading carray extension");
150 // Explicitly initialize sqlite3. Although this is implicitly called by
151 // various sqlite3 functions (and the sqlite3_open calls in our case),
152 // the documentation suggests calling this directly. So we do.
153 sResult = ::sqlite3_initialize();
157 AutoSQLiteLifetime::~AutoSQLiteLifetime() {
158 // Shutdown the sqlite3 API. Warn if shutdown did not turn out okay, but
159 // there is nothing actionable we can do in that case.
160 sResult = ::sqlite3_shutdown();
161 NS_WARNING_ASSERTION(sResult == SQLITE_OK,
162 "sqlite3 did not shutdown cleanly.");
165 int AutoSQLiteLifetime::sSingletonEnforcer = 0;
166 int AutoSQLiteLifetime::sResult = SQLITE_MISUSE;
168 } // namespace mozilla