aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
authorAndrew Chow <achow101-github@achow101.com>2020-05-26 20:53:24 -0400
committerAndrew Chow <achow101-github@achow101.com>2020-10-14 11:28:18 -0400
commit3bfa0fe1259280f8c32b41a798c9453b73f89b02 (patch)
tree66228e67c4ea659fd7abb7c71eef9da3d26fd765 /src/wallet
parent5a488b3d77326a0d957c1233493061da1b6ec207 (diff)
Initialize and Shutdown sqlite3 globals
sqlite3 recommends that sqlite3_initialize be called when the application starts, and sqlite3_shutdown when it stops. Since we don't always use sqlite3, we initialize it when a SQLiteDatabse is constructed (calling sqlite3_initialize after initialized is a no-op). We call sqlite3_shutdown when we see that there are no databases opened. The number of open databases is tracked by an atomic g_dbs_open.
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/sqlite.cpp57
-rw-r--r--src/wallet/sqlite.h2
2 files changed, 55 insertions, 4 deletions
diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp
index 9a9904e17d..ed331b6470 100644
--- a/src/wallet/sqlite.cpp
+++ b/src/wallet/sqlite.cpp
@@ -5,6 +5,7 @@
#include <wallet/sqlite.h>
#include <logging.h>
+#include <sync.h>
#include <util/memory.h>
#include <util/strencodings.h>
#include <util/translation.h>
@@ -15,18 +16,66 @@
static const char* const DATABASE_FILENAME = "wallet.dat";
+static Mutex g_sqlite_mutex;
+static int g_sqlite_count GUARDED_BY(g_sqlite_mutex) = 0;
+
+static void ErrorLogCallback(void* arg, int code, const char* msg)
+{
+ // From sqlite3_config() documentation for the SQLITE_CONFIG_LOG option:
+ // "The void pointer that is the second argument to SQLITE_CONFIG_LOG is passed through as
+ // the first parameter to the application-defined logger function whenever that function is
+ // invoked."
+ // Assert that this is the case:
+ assert(arg == nullptr);
+ LogPrintf("SQLite Error. Code: %d. Message: %s\n", code, msg);
+}
+
SQLiteDatabase::SQLiteDatabase(const fs::path& dir_path, const fs::path& file_path, bool mock)
: WalletDatabase(), m_mock(mock), m_dir_path(dir_path.string()), m_file_path(file_path.string())
{
- LogPrintf("Using SQLite Version %s\n", SQLiteDatabaseVersion());
- LogPrintf("Using wallet %s\n", m_dir_path);
-
- Open();
+ {
+ LOCK(g_sqlite_mutex);
+ LogPrintf("Using SQLite Version %s\n", SQLiteDatabaseVersion());
+ LogPrintf("Using wallet %s\n", m_dir_path);
+
+ if (++g_sqlite_count == 1) {
+ // Setup logging
+ int ret = sqlite3_config(SQLITE_CONFIG_LOG, ErrorLogCallback, nullptr);
+ if (ret != SQLITE_OK) {
+ throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup error log: %s\n", sqlite3_errstr(ret)));
+ }
+ }
+ int ret = sqlite3_initialize(); // This is a no-op if sqlite3 is already initialized
+ if (ret != SQLITE_OK) {
+ throw std::runtime_error(strprintf("SQLiteDatabase: Failed to initialize SQLite: %s\n", sqlite3_errstr(ret)));
+ }
+ }
+
+ try {
+ Open();
+ } catch (const std::runtime_error&) {
+ // If open fails, cleanup this object and rethrow the exception
+ Cleanup();
+ throw;
+ }
}
SQLiteDatabase::~SQLiteDatabase()
{
+ Cleanup();
+}
+
+void SQLiteDatabase::Cleanup() noexcept
+{
Close();
+
+ LOCK(g_sqlite_mutex);
+ if (--g_sqlite_count == 0) {
+ int ret = sqlite3_shutdown();
+ if (ret != SQLITE_OK) {
+ LogPrintf("SQLiteDatabase: Failed to shutdown SQLite: %s\n", sqlite3_errstr(ret));
+ }
+ }
}
void SQLiteDatabase::Open()
diff --git a/src/wallet/sqlite.h b/src/wallet/sqlite.h
index e56533b7b6..8171cf27d6 100644
--- a/src/wallet/sqlite.h
+++ b/src/wallet/sqlite.h
@@ -51,6 +51,8 @@ private:
const std::string m_file_path;
+ void Cleanup() noexcept;
+
public:
SQLiteDatabase() = delete;