From 7d562ce85c9e58d54a467299d85f90e8c829b284 Mon Sep 17 00:00:00 2001 From: Cory McWilliams Date: Thu, 15 Jun 2023 00:27:49 +0000 Subject: [PATCH] Allow the DB writer to be used from a worker thread. Not well tested, just still trying to charge forward on moving all blocking work off the main thread. git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4325 ed5197a5-7fde-0310-b194-c3ffbd925b24 --- src/database.js.c | 46 +++++++++++++++++++---------- src/ssb.c | 38 +++++++++++++++++------- src/ssb.connections.c | 26 +++++++++------- src/ssb.db.c | 69 ++++++++++++++++++++++++++++--------------- src/ssb.export.c | 6 ++-- src/ssb.h | 3 +- src/ssb.import.c | 33 +++++++++++---------- src/ssb.js.c | 6 ++-- src/ssb.rpc.c | 12 +++++--- src/ssb.tests.c | 14 ++++----- src/tests.c | 2 +- 11 files changed, 163 insertions(+), 92 deletions(-) diff --git a/src/database.js.c b/src/database.js.c index 861e3148..efe70b12 100644 --- a/src/database.js.c +++ b/src/database.js.c @@ -19,7 +19,6 @@ typedef struct _database_t JSContext* context; JSValue object; void* task; - sqlite3* db; const char* id; } database_t; @@ -62,16 +61,12 @@ static JSValue _database_create(JSContext* context, JSValueConst this_val, int a ++_database_count; JSValue object = JS_NewObjectClass(context, _database_class_id); - tf_task_t* task = tf_task_get(context); - sqlite3* db = tf_ssb_get_db(tf_task_get_ssb(task)); - database_t* database = tf_malloc(sizeof(database_t)); *database = (database_t) { .task = JS_GetContextOpaque(context), .context = context, .object = object, - .db = db, }; const char* id = JS_ToCString(context, argv[0]); database->id = tf_strdup(id); @@ -105,8 +100,10 @@ static JSValue _database_get(JSContext* context, JSValueConst this_val, int argc database_t* database = JS_GetOpaque(this_val, _database_class_id); if (database) { + tf_ssb_t* ssb = tf_task_get_ssb(database->task); sqlite3_stmt* statement; - if (sqlite3_prepare(database->db, "SELECT value FROM properties WHERE id = ? AND key = ?", -1, &statement, NULL) == SQLITE_OK) + sqlite3* db = tf_ssb_acquire_db_reader(ssb); + if (sqlite3_prepare(db, "SELECT value FROM properties WHERE id = ? AND key = ?", -1, &statement, NULL) == SQLITE_OK) { size_t length; const char* keyString = JS_ToCStringLen(context, &length, argv[0]); @@ -119,6 +116,7 @@ static JSValue _database_get(JSContext* context, JSValueConst this_val, int argc JS_FreeCString(context, keyString); sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); } return entry; } @@ -129,7 +127,9 @@ JSValue _database_set(JSContext* context, JSValueConst this_val, int argc, JSVal if (database) { sqlite3_stmt* statement; - if (sqlite3_prepare(database->db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES ($1, $2, $3)", -1, &statement, NULL) == SQLITE_OK) + tf_ssb_t* ssb = tf_task_get_ssb(database->task); + sqlite3* db = tf_ssb_acquire_db_writer(ssb); + if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES ($1, $2, $3)", -1, &statement, NULL) == SQLITE_OK) { size_t keyLength; const char* keyString = JS_ToCStringLen(context, &keyLength, argv[0]); @@ -145,6 +145,7 @@ JSValue _database_set(JSContext* context, JSValueConst this_val, int argc, JSVal JS_FreeCString(context, valueString); sqlite3_finalize(statement); } + tf_ssb_release_db_writer(ssb, db); } return JS_UNDEFINED; } @@ -156,9 +157,11 @@ static JSValue _database_exchange(JSContext* context, JSValueConst this_val, int if (database) { sqlite3_stmt* statement; + tf_ssb_t* ssb = tf_task_get_ssb(database->task); + sqlite3* db = tf_ssb_acquire_db_writer(ssb); if (JS_IsNull(argv[1]) || JS_IsUndefined(argv[1])) { - if (sqlite3_prepare(database->db, "INSERT INTO properties (id, key, value) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING", -1, &statement, NULL) == SQLITE_OK) + if (sqlite3_prepare(db, "INSERT INTO properties (id, key, value) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING", -1, &statement, NULL) == SQLITE_OK) { size_t key_length; size_t set_length; @@ -169,14 +172,14 @@ static JSValue _database_exchange(JSContext* context, JSValueConst this_val, int sqlite3_bind_text(statement, 3, set, set_length, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_DONE) { - exchanged = sqlite3_changes(database->db) != 0 ? JS_TRUE : JS_FALSE; + exchanged = sqlite3_changes(db) != 0 ? JS_TRUE : JS_FALSE; } JS_FreeCString(context, key); JS_FreeCString(context, set); sqlite3_finalize(statement); } } - else if (sqlite3_prepare(database->db, "UPDATE properties SET value = $1 WHERE id = $2 AND key = $3 AND value = $4", -1, &statement, NULL) == SQLITE_OK) + else if (sqlite3_prepare(db, "UPDATE properties SET value = $1 WHERE id = $2 AND key = $3 AND value = $4", -1, &statement, NULL) == SQLITE_OK) { size_t key_length; size_t expected_length; @@ -190,13 +193,14 @@ static JSValue _database_exchange(JSContext* context, JSValueConst this_val, int sqlite3_bind_text(statement, 4, expected, expected_length, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_DONE) { - exchanged = sqlite3_changes(database->db) != 0 ? JS_TRUE : JS_FALSE; + exchanged = sqlite3_changes(db) != 0 ? JS_TRUE : JS_FALSE; } JS_FreeCString(context, key); JS_FreeCString(context, expected); JS_FreeCString(context, set); sqlite3_finalize(statement); } + tf_ssb_release_db_writer(ssb, db); } return exchanged; } @@ -207,7 +211,9 @@ JSValue _database_remove(JSContext* context, JSValueConst this_val, int argc, JS if (database) { sqlite3_stmt* statement; - if (sqlite3_prepare(database->db, "DELETE FROM properties WHERE id = $1 AND key = $2", -1, &statement, NULL) == SQLITE_OK) + tf_ssb_t* ssb = tf_task_get_ssb(database->task); + sqlite3* db = tf_ssb_acquire_db_writer(ssb); + if (sqlite3_prepare(db, "DELETE FROM properties WHERE id = $1 AND key = $2", -1, &statement, NULL) == SQLITE_OK) { size_t keyLength; const char* keyString = JS_ToCStringLen(context, &keyLength, argv[0]); @@ -219,6 +225,7 @@ JSValue _database_remove(JSContext* context, JSValueConst this_val, int argc, JS JS_FreeCString(context, keyString); sqlite3_finalize(statement); } + tf_ssb_release_db_writer(ssb, db); } return JS_UNDEFINED; } @@ -230,7 +237,9 @@ JSValue _database_get_all(JSContext* context, JSValueConst this_val, int argc, J if (database) { sqlite3_stmt* statement; - if (sqlite3_prepare(database->db, "SELECT key, value FROM properties WHERE id = $1", -1, &statement, NULL) == SQLITE_OK) + tf_ssb_t* ssb = tf_task_get_ssb(database->task); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); + if (sqlite3_prepare(db, "SELECT key, value FROM properties WHERE id = $1", -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_bind_text(statement, 1, database->id, -1, NULL) == SQLITE_OK) { @@ -243,6 +252,7 @@ JSValue _database_get_all(JSContext* context, JSValueConst this_val, int argc, J } sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); } return array; } @@ -254,7 +264,9 @@ JSValue _database_get_like(JSContext* context, JSValueConst this_val, int argc, if (database) { sqlite3_stmt* statement; - if (sqlite3_prepare(database->db, "SELECT key, value FROM properties WHERE id = ? AND KEY LIKE ?", -1, &statement, NULL) == SQLITE_OK) + tf_ssb_t* ssb = tf_task_get_ssb(database->task); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); + if (sqlite3_prepare(db, "SELECT key, value FROM properties WHERE id = ? AND KEY LIKE ?", -1, &statement, NULL) == SQLITE_OK) { const char* pattern = JS_ToCString(context, argv[0]); if (sqlite3_bind_text(statement, 1, database->id, -1, NULL) == SQLITE_OK && @@ -273,6 +285,7 @@ JSValue _database_get_like(JSContext* context, JSValueConst this_val, int argc, JS_FreeCString(context, pattern); sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); } return result; } @@ -280,8 +293,8 @@ JSValue _database_get_like(JSContext* context, JSValueConst this_val, int argc, static JSValue _databases_list(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* data) { tf_task_t* task = tf_task_get(context); - sqlite3* db = tf_ssb_get_db(tf_task_get_ssb(task)); - + tf_ssb_t* ssb = tf_task_get_ssb(task); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); JSValue array = JS_UNDEFINED; sqlite3_stmt* statement; if (sqlite3_prepare(db, "SELECT DISTINCT id FROM properties WHERE id LIKE ?", -1, &statement, NULL) == SQLITE_OK) @@ -299,5 +312,6 @@ static JSValue _databases_list(JSContext* context, JSValueConst this_val, int ar JS_FreeCString(context, pattern); sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); return array; } diff --git a/src/ssb.c b/src/ssb.c index ca236569..27a85fbc 100644 --- a/src/ssb.c +++ b/src/ssb.c @@ -180,9 +180,10 @@ typedef struct _tf_ssb_t tf_trace_t* trace; const char* db_path; - sqlite3* db; uv_mutex_t db_readers_lock; + uv_mutex_t db_writer_lock; + sqlite3* db_writer; sqlite3** db_readers; int db_readers_count; @@ -2099,6 +2100,7 @@ tf_ssb_t* tf_ssb_create(uv_loop_t* loop, JSContext* context, const char* db_path } uv_mutex_init(&ssb->db_readers_lock); + uv_mutex_init(&ssb->db_writer_lock); JS_NewClassID(&_connection_class_id); JSClassDef def = @@ -2109,7 +2111,7 @@ tf_ssb_t* tf_ssb_create(uv_loop_t* loop, JSContext* context, const char* db_path JS_NewClass(JS_GetRuntime(ssb->context), _connection_class_id, &def); ssb->db_path = tf_strdup(db_path); - sqlite3_open(db_path, &ssb->db); + sqlite3_open_v2(db_path, &ssb->db_writer, SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI, NULL); tf_ssb_db_init(ssb); if (loop) @@ -2142,11 +2144,6 @@ tf_ssb_t* tf_ssb_create(uv_loop_t* loop, JSContext* context, const char* db_path return ssb; } -sqlite3* tf_ssb_get_db(tf_ssb_t* ssb) -{ - return ssb->db; -} - sqlite3* tf_ssb_acquire_db_reader(tf_ssb_t* ssb) { sqlite3* db = NULL; @@ -2157,7 +2154,7 @@ sqlite3* tf_ssb_acquire_db_reader(tf_ssb_t* ssb) } else { - sqlite3_open_v2(ssb->db_path, &db, SQLITE_OPEN_READONLY, NULL); + sqlite3_open_v2(ssb->db_path, &db, SQLITE_OPEN_READONLY | SQLITE_OPEN_URI, NULL); tf_ssb_db_init_reader(db); tf_trace_sqlite(ssb->trace, db); } @@ -2173,6 +2170,22 @@ void tf_ssb_release_db_reader(tf_ssb_t* ssb, sqlite3* db) uv_mutex_unlock(&ssb->db_readers_lock); } +sqlite3* tf_ssb_acquire_db_writer(tf_ssb_t* ssb) +{ + uv_mutex_lock(&ssb->db_writer_lock); + sqlite3* writer = ssb->db_writer; + assert(writer); + ssb->db_writer = NULL; + return writer; +} + +void tf_ssb_release_db_writer(tf_ssb_t* ssb, sqlite3* db) +{ + assert(ssb->db_writer == NULL); + ssb->db_writer = db; + uv_mutex_unlock(&ssb->db_writer_lock); +} + uv_loop_t* tf_ssb_get_loop(tf_ssb_t* ssb) { return ssb->loop; @@ -2205,10 +2218,12 @@ void tf_ssb_get_private_key(tf_ssb_t* ssb, uint8_t* out_private, size_t private_ void tf_ssb_set_trace(tf_ssb_t* ssb, tf_trace_t* trace) { ssb->trace = trace; - if (trace && ssb->db) + sqlite3* db = tf_ssb_acquire_db_writer(ssb); + if (trace && db) { - tf_trace_sqlite(trace, ssb->db); + tf_trace_sqlite(trace, db); } + tf_ssb_release_db_writer(ssb, db); } tf_trace_t* tf_ssb_get_trace(tf_ssb_t* ssb) @@ -2336,7 +2351,7 @@ void tf_ssb_destroy(tf_ssb_t* ssb) JS_FreeContext(ssb->context); JS_FreeRuntime(ssb->runtime); } - sqlite3_close(ssb->db); + sqlite3_close(ssb->db_writer); while (ssb->broadcasts) { tf_ssb_broadcast_t* broadcast = ssb->broadcasts; @@ -2357,6 +2372,7 @@ void tf_ssb_destroy(tf_ssb_t* ssb) } tf_free(ssb->db_readers); uv_mutex_destroy(&ssb->db_readers_lock); + uv_mutex_destroy(&ssb->db_writer_lock); tf_free((void*)ssb->db_path); tf_free(ssb); } diff --git a/src/ssb.connections.c b/src/ssb.connections.c index 17b58983..e7c28ed9 100644 --- a/src/ssb.connections.c +++ b/src/ssb.connections.c @@ -16,7 +16,6 @@ typedef struct _tf_ssb_connections_t { tf_ssb_t* ssb; - sqlite3* db; uv_timer_t timer; } tf_ssb_connections_t; @@ -55,7 +54,8 @@ static bool _tf_ssb_connections_get_next_connection(tf_ssb_connections_t* connec { bool result = false; sqlite3_stmt* statement; - if (sqlite3_prepare(connections->db, "SELECT host, port, key FROM connections WHERE last_attempt IS NULL OR (strftime('%s', 'now') - last_attempt > $1) ORDER BY last_attempt LIMIT 1", -1, &statement, NULL) == SQLITE_OK) + sqlite3* db = tf_ssb_acquire_db_reader(connections->ssb); + if (sqlite3_prepare(db, "SELECT host, port, key FROM connections WHERE last_attempt IS NULL OR (strftime('%s', 'now') - last_attempt > $1) ORDER BY last_attempt LIMIT 1", -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_bind_int(statement, 1, 60000) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW) @@ -69,8 +69,9 @@ static bool _tf_ssb_connections_get_next_connection(tf_ssb_connections_t* connec } else { - tf_printf("prepare: %s\n", sqlite3_errmsg(connections->db)); + tf_printf("prepare: %s\n", sqlite3_errmsg(db)); } + tf_ssb_release_db_reader(connections->ssb, db); return result; } @@ -100,7 +101,6 @@ tf_ssb_connections_t* tf_ssb_connections_create(tf_ssb_t* ssb) tf_ssb_connections_t* connections = tf_malloc(sizeof(tf_ssb_connections_t)); memset(connections, 0, sizeof(*connections)); connections->ssb = ssb; - connections->db = tf_ssb_get_db(ssb); tf_ssb_add_connections_changed_callback(ssb, _tf_ssb_connections_changed_callback, NULL, connections); @@ -128,7 +128,8 @@ void tf_ssb_connections_destroy(tf_ssb_connections_t* connections) void tf_ssb_connections_store(tf_ssb_connections_t* connections, const char* host, int port, const char* key) { sqlite3_stmt* statement; - if (sqlite3_prepare(connections->db, "INSERT INTO connections (host, port, key) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING", -1, &statement, NULL) == SQLITE_OK) + sqlite3* db = tf_ssb_acquire_db_writer(connections->ssb); + if (sqlite3_prepare(db, "INSERT INTO connections (host, port, key) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING", -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_bind_text(statement, 1, host, -1, NULL) == SQLITE_OK && sqlite3_bind_int(statement, 2, port) == SQLITE_OK && @@ -137,17 +138,19 @@ void tf_ssb_connections_store(tf_ssb_connections_t* connections, const char* hos int r = sqlite3_step(statement); if (r != SQLITE_DONE) { - tf_printf("tf_ssb_connections_store: %d, %s.\n", r, sqlite3_errmsg(connections->db)); + tf_printf("tf_ssb_connections_store: %d, %s.\n", r, sqlite3_errmsg(db)); } } sqlite3_finalize(statement); } + tf_ssb_release_db_writer(connections->ssb, db); } void tf_ssb_connections_set_attempted(tf_ssb_connections_t* connections, const char* host, int port, const char* key) { sqlite3_stmt* statement; - if (sqlite3_prepare(connections->db, "UPDATE connections SET last_attempt = strftime('%s', 'now') WHERE host = $1 AND port = $2 AND key = $3", -1, &statement, NULL) == SQLITE_OK) + sqlite3* db = tf_ssb_acquire_db_writer(connections->ssb); + if (sqlite3_prepare(db, "UPDATE connections SET last_attempt = strftime('%s', 'now') WHERE host = $1 AND port = $2 AND key = $3", -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_bind_text(statement, 1, host, -1, NULL) == SQLITE_OK && sqlite3_bind_int(statement, 2, port) == SQLITE_OK && @@ -155,17 +158,19 @@ void tf_ssb_connections_set_attempted(tf_ssb_connections_t* connections, const c { if (sqlite3_step(statement) != SQLITE_DONE) { - tf_printf("tf_ssb_connections_set_attempted: %s.\n", sqlite3_errmsg(connections->db)); + tf_printf("tf_ssb_connections_set_attempted: %s.\n", sqlite3_errmsg(db)); } } sqlite3_finalize(statement); } + tf_ssb_release_db_writer(connections->ssb, db); } void tf_ssb_connections_set_succeeded(tf_ssb_connections_t* connections, const char* host, int port, const char* key) { sqlite3_stmt* statement; - if (sqlite3_prepare(connections->db, "UPDATE connections SET last_success = strftime('%s', 'now') WHERE host = $1 AND port = $2 AND key = $3", -1, &statement, NULL) == SQLITE_OK) + sqlite3* db = tf_ssb_acquire_db_writer(connections->ssb); + if (sqlite3_prepare(db, "UPDATE connections SET last_success = strftime('%s', 'now') WHERE host = $1 AND port = $2 AND key = $3", -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_bind_text(statement, 1, host, -1, NULL) == SQLITE_OK && sqlite3_bind_int(statement, 2, port) == SQLITE_OK && @@ -173,9 +178,10 @@ void tf_ssb_connections_set_succeeded(tf_ssb_connections_t* connections, const c { if (sqlite3_step(statement) != SQLITE_DONE) { - tf_printf("tf_ssb_connections_set_succeeded: %s.\n", sqlite3_errmsg(connections->db)); + tf_printf("tf_ssb_connections_set_succeeded: %s.\n", sqlite3_errmsg(db)); } } sqlite3_finalize(statement); } + tf_ssb_release_db_writer(connections->ssb, db); } diff --git a/src/ssb.db.c b/src/ssb.db.c index d68a06c0..8fc128ef 100644 --- a/src/ssb.db.c +++ b/src/ssb.db.c @@ -67,7 +67,7 @@ void tf_ssb_db_init_reader(sqlite3* db) void tf_ssb_db_init(tf_ssb_t* ssb) { - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_writer(ssb); _tf_ssb_db_init_internal(db); _tf_ssb_db_exec(db, "CREATE TABLE IF NOT EXISTS messages (" @@ -222,6 +222,7 @@ void tf_ssb_db_init(tf_ssb_t* ssb) tf_printf("Adding sequence_before_author column.\n"); _tf_ssb_db_exec(db, "ALTER TABLE messages ADD COLUMN sequence_before_author INTEGER"); } + tf_ssb_release_db_writer(ssb, db); } static bool _tf_ssb_db_previous_message_exists(sqlite3* db, const char* author, int64_t sequence, const char* previous) @@ -266,7 +267,7 @@ bool tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, JS_ToInt64(context, &sequence, sequenceval); JS_FreeValue(context, sequenceval); - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_writer(ssb); sqlite3_stmt* statement; int64_t last_row_id = -1; @@ -315,7 +316,7 @@ bool tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, } else { - tf_printf("prepare failed: %s\n", sqlite3_errmsg(db)); + tf_printf("%s: prepare failed: %s\n", __FUNCTION__, sqlite3_errmsg(db)); } JS_FreeCString(context, contentstr); @@ -348,9 +349,10 @@ bool tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, } else { - tf_printf("prepare failed: %s\n", sqlite3_errmsg(db)); + tf_printf("%s: prepare failed: %s\n", __FUNCTION__, sqlite3_errmsg(db)); } } + tf_ssb_release_db_writer(ssb, db); JS_FreeCString(context, author); JS_FreeCString(context, previous); @@ -361,8 +363,9 @@ bool tf_ssb_db_message_content_get(tf_ssb_t* ssb, const char* id, uint8_t** out_ { bool result = false; sqlite3_stmt* statement; + sqlite3* db = tf_ssb_acquire_db_reader(ssb); const char* query = "SELECT content FROM messages WHERE id = ?"; - if (sqlite3_prepare(tf_ssb_get_db(ssb), query, -1, &statement, NULL) == SQLITE_OK) + if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW) @@ -383,6 +386,7 @@ bool tf_ssb_db_message_content_get(tf_ssb_t* ssb, const char* id, uint8_t** out_ } sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); return result; } @@ -390,8 +394,9 @@ bool tf_ssb_db_blob_has(tf_ssb_t* ssb, const char* id) { bool result = false; sqlite3_stmt* statement; + sqlite3* db = tf_ssb_acquire_db_reader(ssb); const char* query = "SELECT COUNT(*) FROM blobs WHERE id = $1"; - if (sqlite3_prepare(tf_ssb_get_db(ssb), query, -1, &statement, NULL) == SQLITE_OK) + if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW) @@ -400,6 +405,7 @@ bool tf_ssb_db_blob_has(tf_ssb_t* ssb, const char* id) } sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); return result; } @@ -407,8 +413,9 @@ bool tf_ssb_db_blob_get(tf_ssb_t* ssb, const char* id, uint8_t** out_blob, size_ { bool result = false; sqlite3_stmt* statement; + sqlite3* db = tf_ssb_acquire_db_reader(ssb); const char* query = "SELECT content FROM blobs WHERE id = $1"; - if (sqlite3_prepare(tf_ssb_get_db(ssb), query, -1, &statement, NULL) == SQLITE_OK) + if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW) @@ -432,13 +439,14 @@ bool tf_ssb_db_blob_get(tf_ssb_t* ssb, const char* id, uint8_t** out_blob, size_ } sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); return result; } bool tf_ssb_db_blob_store(tf_ssb_t* ssb, const uint8_t* blob, size_t size, char* out_id, size_t out_id_size, bool* out_new) { bool result = false; - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_writer(ssb); sqlite3_stmt* statement; uint8_t hash[crypto_hash_sha256_BYTES]; @@ -468,8 +476,9 @@ bool tf_ssb_db_blob_store(tf_ssb_t* ssb, const uint8_t* blob, size_t size, char* } else { - tf_printf("prepare failed: %s\n", sqlite3_errmsg(db)); + tf_printf("%s: prepare failed: %s\n", __FUNCTION__, sqlite3_errmsg(db)); } + tf_ssb_release_db_writer(ssb, db); if (rows) { @@ -496,7 +505,8 @@ bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* aut bool found = false; sqlite3_stmt* statement; const char* query = "SELECT id, timestamp, content FROM messages WHERE author = $1 AND sequence = $2"; - if (sqlite3_prepare(tf_ssb_get_db(ssb), query, -1, &statement, NULL) == SQLITE_OK) + sqlite3* db = tf_ssb_acquire_db_reader(ssb); + if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_bind_text(statement, 1, author, -1, NULL) == SQLITE_OK && sqlite3_bind_int64(statement, 2, sequence) == SQLITE_OK && @@ -520,8 +530,9 @@ bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* aut } else { - tf_printf("prepare failed: %s\n", sqlite3_errmsg(tf_ssb_get_db(ssb))); + tf_printf("%s: prepare failed: %s\n", __FUNCTION__, sqlite3_errmsg(db)); } + tf_ssb_release_db_reader(ssb, db); return found; } @@ -529,8 +540,9 @@ bool tf_ssb_db_get_latest_message_by_author(tf_ssb_t* ssb, const char* author, i { bool found = false; sqlite3_stmt* statement; + sqlite3* db = tf_ssb_acquire_db_reader(ssb); const char* query = "SELECT id, sequence FROM messages WHERE author = $1 AND sequence = (SELECT MAX(sequence) FROM messages WHERE author = $1)"; - if (sqlite3_prepare(tf_ssb_get_db(ssb), query, -1, &statement, NULL) == SQLITE_OK) + if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_bind_text(statement, 1, author, -1, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW) @@ -549,8 +561,9 @@ bool tf_ssb_db_get_latest_message_by_author(tf_ssb_t* ssb, const char* author, i } else { - tf_printf("prepare failed: %s\n", sqlite3_errmsg(tf_ssb_get_db(ssb))); + tf_printf("%s: prepare failed: %s\n", __FUNCTION__, sqlite3_errmsg(db)); } + tf_ssb_release_db_reader(ssb, db); return found; } @@ -686,7 +699,7 @@ static int _tf_ssb_sqlite_authorizer(void* user_data, int action_code, const cha JSValue tf_ssb_db_visit_query(tf_ssb_t* ssb, const char* query, const JSValue binds, void (*callback)(JSValue row, void* user_data), void* user_data) { JSValue result = JS_UNDEFINED; - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); JSContext* context = tf_ssb_get_context(ssb); sqlite3_stmt* statement; sqlite3_set_authorizer(db, _tf_ssb_sqlite_authorizer, ssb); @@ -721,6 +734,7 @@ JSValue tf_ssb_db_visit_query(tf_ssb_t* ssb, const char* query, const JSValue bi result = JS_ThrowInternalError(context, "SQL Error %s: preparing \"%s\".", sqlite3_errmsg(db), query); } sqlite3_set_authorizer(db, NULL, NULL); + tf_ssb_release_db_reader(ssb, db); return result; } @@ -874,7 +888,7 @@ bool tf_ssb_db_check(sqlite3* db, const char* check_author) int tf_ssb_db_identity_get_count_for_user(tf_ssb_t* ssb, const char* user) { int count = 0; - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); sqlite3_stmt* statement = NULL; if (sqlite3_prepare(db, "SELECT COUNT(*) FROM identities WHERE user = ?", -1, &statement, NULL) == SQLITE_OK) { @@ -887,6 +901,7 @@ int tf_ssb_db_identity_get_count_for_user(tf_ssb_t* ssb, const char* user) } sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); return count; } @@ -911,7 +926,7 @@ bool tf_ssb_db_identity_create(tf_ssb_t* ssb, const char* user, uint8_t* out_pub bool tf_ssb_db_identity_add(tf_ssb_t* ssb, const char* user, const char* public_key, const char* private_key) { bool added = false; - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_writer(ssb); sqlite3_stmt* statement = NULL; if (sqlite3_prepare(db, "INSERT INTO identities (user, public_key, private_key) VALUES (?, ?, ?) ON CONFLICT DO NOTHING", -1, &statement, NULL) == SQLITE_OK) { @@ -929,12 +944,13 @@ bool tf_ssb_db_identity_add(tf_ssb_t* ssb, const char* user, const char* public_ } sqlite3_finalize(statement); } + tf_ssb_release_db_writer(ssb, db); return added; } void tf_ssb_db_identity_visit(tf_ssb_t* ssb, const char* user, void (*callback)(const char* identity, void* user_data), void* user_data) { - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); sqlite3_stmt* statement = NULL; if (sqlite3_prepare(db, "SELECT public_key FROM identities WHERE user = ? ORDER BY public_key", -1, &statement, NULL) == SQLITE_OK) { @@ -947,11 +963,12 @@ void tf_ssb_db_identity_visit(tf_ssb_t* ssb, const char* user, void (*callback)( } sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); } void tf_ssb_db_identity_visit_all(tf_ssb_t* ssb, void (*callback)(const char* identity, void* user_data), void* user_data) { - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); sqlite3_stmt* statement = NULL; if (sqlite3_prepare(db, "SELECT public_key FROM identities ORDER BY public_key", -1, &statement, NULL) == SQLITE_OK) { @@ -961,13 +978,14 @@ void tf_ssb_db_identity_visit_all(tf_ssb_t* ssb, void (*callback)(const char* id } sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); } bool tf_ssb_db_identity_get_private_key(tf_ssb_t* ssb, const char* user, const char* public_key, uint8_t* out_private_key, size_t private_key_size) { bool success = false; memset(out_private_key, 0, crypto_sign_SECRETKEYBYTES); - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); sqlite3_stmt* statement = NULL; if (sqlite3_prepare(db, "SELECT private_key FROM identities WHERE user = ? AND public_key = ?", -1, &statement, NULL) == SQLITE_OK) { @@ -983,6 +1001,7 @@ bool tf_ssb_db_identity_get_private_key(tf_ssb_t* ssb, const char* user, const c } sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); return success; } @@ -1050,7 +1069,7 @@ static following_t* _get_following(tf_ssb_t* ssb, const char* id, following_t*** if (depth < max_depth && !already_populated) { - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); sqlite3_stmt* statement = NULL; if (sqlite3_prepare(db, "SELECT json_extract(content, '$.contact'), json_extract(content, '$.following'), json_extract(content, '$.blocking') FROM messages WHERE author = ? AND json_extract(content, '$.type') = 'contact' ORDER BY sequence", -1, &statement, NULL) == SQLITE_OK) { @@ -1081,6 +1100,7 @@ static following_t* _get_following(tf_ssb_t* ssb, const char* id, following_t*** } sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); } return entry; } @@ -1147,7 +1167,7 @@ JSValue tf_ssb_db_get_message_by_id( tf_ssb_t* ssb, const char* id, bool is_keys { JSValue result = JS_UNDEFINED; JSContext* context = tf_ssb_get_context(ssb); - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); sqlite3_stmt* statement; if (sqlite3_prepare(db, "SELECT previous, author, id, sequence, timestamp, hash, content, signature, sequence_before_author FROM messages WHERE id = ?", -1, &statement, NULL) == SQLITE_OK) { @@ -1182,12 +1202,13 @@ JSValue tf_ssb_db_get_message_by_id( tf_ssb_t* ssb, const char* id, bool is_keys } sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); return result; } tf_ssb_db_stored_connection_t* tf_ssb_db_get_stored_connections(tf_ssb_t* ssb, int* out_count) { - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); tf_ssb_db_stored_connection_t* result = NULL; int count = 0; @@ -1207,6 +1228,7 @@ tf_ssb_db_stored_connection_t* tf_ssb_db_get_stored_connections(tf_ssb_t* ssb, i } sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); *out_count = count; return result; @@ -1214,7 +1236,7 @@ tf_ssb_db_stored_connection_t* tf_ssb_db_get_stored_connections(tf_ssb_t* ssb, i void tf_ssb_db_forget_stored_connection(tf_ssb_t* ssb, const char* address, int port, const char* pubkey) { - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_writer(ssb); sqlite3_stmt* statement; if (sqlite3_prepare(db, "DELETE FROM connections WHERE host = ? AND port = ? AND key = ?", -1, &statement, NULL) == SQLITE_OK) { @@ -1227,4 +1249,5 @@ void tf_ssb_db_forget_stored_connection(tf_ssb_t* ssb, const char* address, int } sqlite3_finalize(statement); } + tf_ssb_release_db_writer(ssb, db); } diff --git a/src/ssb.export.c b/src/ssb.export.c index f3b679d3..435ea1cb 100644 --- a/src/ssb.export.c +++ b/src/ssb.export.c @@ -87,9 +87,10 @@ void tf_ssb_export(tf_ssb_t* ssb, const char* key) } char app_blob_id[64] = { 0 }; - sqlite3_busy_timeout(tf_ssb_get_db(ssb), 10000); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); + sqlite3_busy_timeout(db, 10000); sqlite3_stmt* statement; - if (sqlite3_prepare(tf_ssb_get_db(ssb), "SELECT value FROM properties WHERE id = $1 AND key = 'path:' || $2", -1, &statement, NULL) == SQLITE_OK) + if (sqlite3_prepare(db, "SELECT value FROM properties WHERE id = $1 AND key = 'path:' || $2", -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, path, -1, NULL) == SQLITE_OK && @@ -105,6 +106,7 @@ void tf_ssb_export(tf_ssb_t* ssb, const char* key) } sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); if (!*app_blob_id) { diff --git a/src/ssb.h b/src/ssb.h index 168330f2..569f8855 100644 --- a/src/ssb.h +++ b/src/ssb.h @@ -69,9 +69,10 @@ typedef struct _tf_ssb_blob_wants_t tf_ssb_t* tf_ssb_create(uv_loop_t* loop, JSContext* context, const char* db_path); void tf_ssb_destroy(tf_ssb_t* ssb); -sqlite3* tf_ssb_get_db(tf_ssb_t* ssb); sqlite3* tf_ssb_acquire_db_reader(tf_ssb_t* ssb); void tf_ssb_release_db_reader(tf_ssb_t* ssb, sqlite3* db); +sqlite3* tf_ssb_acquire_db_writer(tf_ssb_t* ssb); +void tf_ssb_release_db_writer(tf_ssb_t* ssb, sqlite3* db); uv_loop_t* tf_ssb_get_loop(tf_ssb_t* ssb); void tf_ssb_generate_keys(tf_ssb_t* ssb); diff --git a/src/ssb.import.c b/src/ssb.import.c index b775da87..eca5d30a 100644 --- a/src/ssb.import.c +++ b/src/ssb.import.c @@ -20,7 +20,8 @@ static void _tf_ssb_import_add_app(tf_ssb_t* ssb, const char* user, const char* sqlite3_stmt* statement; JSContext* context = tf_ssb_get_context(ssb); JSValue apps = JS_UNDEFINED; - if (sqlite3_prepare(tf_ssb_get_db(ssb), "SELECT value FROM properties WHERE id = $1 AND key = 'apps'", -1, &statement, NULL) == SQLITE_OK) + sqlite3* db = tf_ssb_acquire_db_writer(ssb); + if (sqlite3_prepare(db, "SELECT value FROM properties WHERE id = $1 AND key = 'apps'", -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW) @@ -68,7 +69,7 @@ static void _tf_ssb_import_add_app(tf_ssb_t* ssb, const char* user, const char* JSValue json = JS_JSONStringify(context, out_apps, JS_NULL, JS_NULL); const char* text = JS_ToCString(context, json); - if (sqlite3_prepare(tf_ssb_get_db(ssb), "INSERT OR REPLACE INTO properties (id, key, value) VALUES ($1, 'apps', $2)", -1, &statement, NULL) == SQLITE_OK) + if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES ($1, 'apps', $2)", -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, text, -1, NULL) == SQLITE_OK && @@ -77,6 +78,7 @@ static void _tf_ssb_import_add_app(tf_ssb_t* ssb, const char* user, const char* } sqlite3_finalize(statement); } + tf_ssb_release_db_writer(ssb, db); JS_FreeCString(context, text); JS_FreeValue(context, json); @@ -160,19 +162,21 @@ static void _tf_ssb_import_recursive_add_files(tf_ssb_t* ssb, uv_loop_t* loop, J static bool _tf_ssb_register_app(tf_ssb_t* ssb, const char* user, const char* app, const char* id) { bool result = false; - sqlite3_stmt* statement; - if (sqlite3_prepare(tf_ssb_get_db(ssb), "INSERT OR REPLACE INTO properties (id, key, value) VALUES ($1, 'path:' || $2, $3)", -1, &statement, NULL) == SQLITE_OK) - { - if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK && + sqlite3_stmt* statement; + sqlite3* db = tf_ssb_acquire_db_writer(ssb); + if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES ($1, 'path:' || $2, $3)", -1, &statement, NULL) == SQLITE_OK) + { + if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, app, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 3, id, -1, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_DONE) - { - result = sqlite3_changes(tf_ssb_get_db(ssb)) != 0; - } - sqlite3_finalize(statement); - } - return result; + { + result = sqlite3_changes(db) != 0; + } + sqlite3_finalize(statement); + } + tf_ssb_release_db_writer(ssb, db); + return result; } static void _tf_ssb_import_app_json(tf_ssb_t* ssb, uv_loop_t* loop, JSContext* context, const char* user, const char* path) @@ -206,7 +210,7 @@ static void _tf_ssb_import_app_json(tf_ssb_t* ssb, uv_loop_t* loop, JSContext* c if (_tf_ssb_register_app(ssb, user, app, id)) { - tf_printf("Registered %s path:%s as %s.\n", user, app, id); + tf_printf("Registered %s path:%s as %s.\n", user, app, id); _tf_ssb_import_add_app(ssb, user, app); } } @@ -229,7 +233,6 @@ static void _tf_ssb_import_app_json(tf_ssb_t* ssb, uv_loop_t* loop, JSContext* c void tf_ssb_import(tf_ssb_t* ssb, const char* user, const char* path) { uv_fs_t req = { 0 }; - sqlite3_busy_timeout(tf_ssb_get_db(ssb), 10000); int r = uv_fs_scandir(tf_ssb_get_loop(ssb), &req, path, 0, NULL); if (r >= 0) { @@ -334,7 +337,7 @@ static void _tf_ssb_import_app_json_from_zip(tf_ssb_t* ssb, unzFile zip, JSConte if (_tf_ssb_register_app(ssb, user, app, id)) { - tf_printf("Registered %s path:%s as %s.\n", user, app, id); + tf_printf("Registered %s path:%s as %s.\n", user, app, id); _tf_ssb_import_add_app(ssb, user, app); } } diff --git a/src/ssb.js.c b/src/ssb.js.c index 07a1d935..c7b12e2a 100644 --- a/src/ssb.js.c +++ b/src/ssb.js.c @@ -1091,7 +1091,7 @@ static JSValue _tf_ssb_private_message_encrypt(JSContext* context, JSValueConst if (JS_IsUndefined(result)) { tf_ssb_t* ssb = JS_GetOpaque(this_val, _tf_ssb_classId); - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); uint8_t private_key[crypto_sign_SECRETKEYBYTES] = { 0 }; if (_tf_ssb_get_private_key_curve25519(db, signer_user, signer_identity, private_key)) @@ -1167,6 +1167,7 @@ static JSValue _tf_ssb_private_message_encrypt(JSContext* context, JSValueConst { result = JS_ThrowInternalError(context, "Unable to get key for ID %s of user %s.", signer_identity, signer_user); } + tf_ssb_release_db_reader(ssb, db); } JS_FreeCString(context, signer_user); @@ -1187,7 +1188,7 @@ static JSValue _tf_ssb_private_message_decrypt(JSContext* context, JSValueConst uint8_t private_key[crypto_sign_SECRETKEYBYTES] = { 0 }; tf_ssb_t* ssb = JS_GetOpaque(this_val, _tf_ssb_classId); - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); if (_tf_ssb_get_private_key_curve25519(db, user, identity, private_key)) { uint8_t* decoded = tf_malloc(message_size); @@ -1238,6 +1239,7 @@ static JSValue _tf_ssb_private_message_decrypt(JSContext* context, JSValueConst { result = JS_ThrowInternalError(context, "Private key not found for user %s with id %s.", user, identity); } + tf_ssb_release_db_reader(ssb, db); JS_FreeCString(context, user); JS_FreeCString(context, identity); diff --git a/src/ssb.rpc.c b/src/ssb.rpc.c index 86ee2333..11884682 100644 --- a/src/ssb.rpc.c +++ b/src/ssb.rpc.c @@ -141,7 +141,7 @@ static void _tf_ssb_rpc_request_more_blobs(tf_ssb_connection_t* connection) JSContext* context = tf_ssb_connection_get_context(connection); tf_ssb_blob_wants_t* blob_wants = tf_ssb_connection_get_blob_wants_state(connection); tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection); - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); sqlite3_stmt* statement; if (sqlite3_prepare(db, "SELECT id FROM blob_wants_view WHERE id > ? ORDER BY id LIMIT 32", -1, &statement, NULL) == SQLITE_OK) { @@ -160,6 +160,7 @@ static void _tf_ssb_rpc_request_more_blobs(tf_ssb_connection_t* connection) } sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); } static void _tf_ssb_rpc_blobs_createWants(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data) @@ -192,7 +193,7 @@ static bool _get_global_setting_bool(tf_ssb_t* ssb, const char* name, bool defau { bool result = default_value; JSContext* context = tf_ssb_get_context(ssb); - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); sqlite3_stmt* statement; if (sqlite3_prepare(db, "SELECT value FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK) { @@ -209,6 +210,7 @@ static bool _get_global_setting_bool(tf_ssb_t* ssb, const char* name, bool defau } sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); return result; } @@ -216,7 +218,7 @@ static bool _get_global_setting_string(tf_ssb_t* ssb, const char* name, char* ou { bool result = false; JSContext* context = tf_ssb_get_context(ssb); - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); sqlite3_stmt* statement; if (sqlite3_prepare(db, "SELECT value FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK) { @@ -236,6 +238,7 @@ static bool _get_global_setting_string(tf_ssb_t* ssb, const char* name, char* ou } sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); return result; } @@ -698,7 +701,7 @@ static void _tf_ssb_connection_send_history_stream_internal(tf_ssb_connection_t* { tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection); JSContext* context = tf_ssb_get_context(ssb); - sqlite3* db = tf_ssb_get_db(ssb); + sqlite3* db = tf_ssb_acquire_db_reader(ssb); sqlite3_stmt* statement; const int k_max = 32; int64_t max_sequence_seen = 0; @@ -740,6 +743,7 @@ static void _tf_ssb_connection_send_history_stream_internal(tf_ssb_connection_t* } sqlite3_finalize(statement); } + tf_ssb_release_db_reader(ssb, db); if (max_sequence_seen == sequence + k_max - 1) { diff --git a/src/ssb.tests.c b/src/ssb.tests.c index abce7438..8881df31 100644 --- a/src/ssb.tests.c +++ b/src/ssb.tests.c @@ -127,9 +127,9 @@ void tf_ssb_test_ssb(const tf_test_options_t* options) uv_loop_t loop = { 0 }; uv_loop_init(&loop); - tf_ssb_t* ssb0 = tf_ssb_create(&loop, NULL, ":memory:"); + tf_ssb_t* ssb0 = tf_ssb_create(&loop, NULL, "file:db0?mode=memory&cache=shared"); tf_ssb_register(tf_ssb_get_context(ssb0), ssb0); - tf_ssb_t* ssb1 = tf_ssb_create(&loop, NULL, ":memory:"); + tf_ssb_t* ssb1 = tf_ssb_create(&loop, NULL, "file:db1?mode=memory&cache=shared"); tf_ssb_register(tf_ssb_get_context(ssb1), ssb1); uv_idle_t idle0 = { .data = ssb0 }; @@ -311,11 +311,11 @@ void tf_ssb_test_rooms(const tf_test_options_t* options) uv_loop_t loop = { 0 }; uv_loop_init(&loop); - tf_ssb_t* ssb0 = tf_ssb_create(&loop, NULL, ":memory:"); + tf_ssb_t* ssb0 = tf_ssb_create(&loop, NULL, "file:db0?mode=memory&cache=shared"); tf_ssb_register(tf_ssb_get_context(ssb0), ssb0); - tf_ssb_t* ssb1 = tf_ssb_create(&loop, NULL, ":memory:"); + tf_ssb_t* ssb1 = tf_ssb_create(&loop, NULL, "file:db1?mode=memory&cache=shared"); tf_ssb_register(tf_ssb_get_context(ssb1), ssb1); - tf_ssb_t* ssb2 = tf_ssb_create(&loop, NULL, ":memory:"); + tf_ssb_t* ssb2 = tf_ssb_create(&loop, NULL, "file:db2?mode=memory&cache=shared"); tf_ssb_register(tf_ssb_get_context(ssb2), ssb2); uv_idle_t idle0 = { .data = ssb0 }; @@ -555,7 +555,7 @@ void tf_ssb_test_bench(const tf_test_options_t* options) uv_loop_t loop = { 0 }; uv_loop_init(&loop); - tf_ssb_t* ssb0 = tf_ssb_create(&loop, NULL, ":memory:"); + tf_ssb_t* ssb0 = tf_ssb_create(&loop, NULL, "file:db0?mode=memory&cache=shared"); tf_ssb_generate_keys(ssb0); char id0[k_id_base64_len] = { 0 }; @@ -579,7 +579,7 @@ void tf_ssb_test_bench(const tf_test_options_t* options) clock_gettime(CLOCK_REALTIME, &end_time); tf_printf("insert = %f seconds\n", (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_nsec - start_time.tv_nsec) / 1e9); - tf_ssb_t* ssb1 = tf_ssb_create(&loop, NULL, ":memory:"); + tf_ssb_t* ssb1 = tf_ssb_create(&loop, NULL, "file:db1?mode=memory&cache=shared"); tf_ssb_generate_keys(ssb1); uint8_t id0bin[k_id_bin_len]; tf_ssb_id_str_to_bin(id0bin, id0); diff --git a/src/tests.c b/src/tests.c index 5eeb962f..d7abae16 100644 --- a/src/tests.c +++ b/src/tests.c @@ -236,7 +236,7 @@ static void _test_database(const tf_test_options_t* options) unlink("out/testdb.sqlite"); char command[256]; - snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=:memory: --db-path=out/testdb.sqlite -s out/test.js", options->exe_path); + snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=file:db?mode=memory\\&cache=shared -s out/test.js", options->exe_path); tf_printf("%s\n", command); int result = system(command); tf_printf("returned %d\n", WEXITSTATUS(result));