From 8d66122d9168de6ed87c33db22ecc093669e0d46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20Georg=20Gisn=C3=A5s=20Gleditsch?= Date: Mon, 20 Sep 2021 11:49:34 +0200 Subject: [PATCH] dbd_sqlite: Don't shutdown sqlite3 db during init Ref https://www.sqlite.org/c3ref/initialize.html: The sqlite3_initialize() interface is threadsafe, but sqlite3_shutdown() is not. We currently call `sqlite3_shutdown` from all threads as part of `sqlite_init_multithreaded`, and this has been observed to have adversarial effects during startup if many threads receive their first inbound request at the same time. The apparent motivation behind calling shutdown is to make the subsequent calls to `sqlite3_config` succeed, since these ordinarily return SQLITE_MISUSE if called multiple times. However, this function is also documented to not be thread safe, so introduce a barrier that ensures we only initialize once over all threads. --- src/apps/relay/dbdrivers/dbd_sqlite.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/apps/relay/dbdrivers/dbd_sqlite.c b/src/apps/relay/dbdrivers/dbd_sqlite.c index 06da7c1b..09e23224 100644 --- a/src/apps/relay/dbdrivers/dbd_sqlite.c +++ b/src/apps/relay/dbdrivers/dbd_sqlite.c @@ -45,11 +45,13 @@ ////////////////////////////////////////////////// static pthread_mutex_t rc_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t rc_cond = PTHREAD_COND_INITIALIZER; static int read_threads = 0; static int write_level = 0; static pthread_t write_thread = 0; +static int sqlite_initialized = 0; static void sqlite_lock(int write) { @@ -96,11 +98,12 @@ static void sqlite_unlock(int write) ////////////////////////////////////////////////// static int sqlite_init_multithreaded(void) { + if (sqlite_initialized) { + return 0; + } + sqlite_initialized = 1; #if defined(SQLITE_CONFIG_MULTITHREAD) - - sqlite3_shutdown(); - if (sqlite3_threadsafe() > 0) { int retCode = sqlite3_config(SQLITE_CONFIG_MULTITHREAD); if (retCode != SQLITE_OK) { @@ -110,6 +113,7 @@ static int sqlite_init_multithreaded(void) { return -1; } } + sqlite3_initialize(); } else { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Your SQLite database is not compiled to be threadsafe.\n"); return -1; @@ -180,6 +184,8 @@ static sqlite3 * get_sqlite_connection(void) { sqlite3 *sqliteconnection = (sqlite3 *)pthread_getspecific(connection_key); if(!sqliteconnection) { + pthread_mutex_lock(&init_mutex); + fix_user_directory(pud->userdb); sqlite_init_multithreaded(); int rc = sqlite3_open(pud->userdb, &sqliteconnection); @@ -201,6 +207,8 @@ static sqlite3 * get_sqlite_connection(void) { if(sqliteconnection) { (void) pthread_setspecific(connection_key, sqliteconnection); } + + pthread_mutex_unlock(&init_mutex); } return sqliteconnection; }