Move reading settings from the database off of the main thread. It now happens periodically in a worker, which means I don't think there's anything blocking the main thread anymore.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4504 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2023-10-11 15:44:40 +00:00
parent 13c8b05f9a
commit 29d2a45abc
4 changed files with 165 additions and 60 deletions

153
src/ssb.c
View File

@ -188,6 +188,7 @@ typedef struct _tf_ssb_t
uv_timer_t broadcast_cleanup_timer; uv_timer_t broadcast_cleanup_timer;
uv_timer_t broadcast_timer; uv_timer_t broadcast_timer;
uv_timer_t trace_timer; uv_timer_t trace_timer;
uv_timer_t settings_timer;
uv_tcp_t server; uv_tcp_t server;
uint8_t pub[crypto_sign_PUBLICKEYBYTES]; uint8_t pub[crypto_sign_PUBLICKEYBYTES];
@ -236,6 +237,8 @@ typedef struct _tf_ssb_t
int ref_count; int ref_count;
uv_thread_t thread_self; uv_thread_t thread_self;
bool is_room;
char* room_name;
} tf_ssb_t; } tf_ssb_t;
typedef struct _tf_ssb_connection_message_request_t typedef struct _tf_ssb_connection_message_request_t
@ -333,6 +336,8 @@ static void _tf_ssb_connection_close(tf_ssb_connection_t* connection, const char
static void _tf_ssb_nonce_inc(uint8_t* nonce); static void _tf_ssb_nonce_inc(uint8_t* nonce);
static void _tf_ssb_write(tf_ssb_connection_t* connection, void* data, size_t size); static void _tf_ssb_write(tf_ssb_connection_t* connection, void* data, size_t size);
static void _tf_ssb_connection_finalizer(JSRuntime* runtime, JSValue value); static void _tf_ssb_connection_finalizer(JSRuntime* runtime, JSValue value);
static void _tf_ssb_update_settings(tf_ssb_t* ssb);
static void _tf_ssb_start_update_settings(tf_ssb_t* ssb, int delay_ms);
static void _tf_ssb_add_debug_close(tf_ssb_t* ssb, tf_ssb_connection_t* connection, const char* reason) static void _tf_ssb_add_debug_close(tf_ssb_t* ssb, tf_ssb_connection_t* connection, const char* reason)
{ {
@ -2157,7 +2162,9 @@ tf_ssb_t* tf_ssb_create(uv_loop_t* loop, JSContext* context, const char* db_path
ssb->connections_tracker = tf_ssb_connections_create(ssb); ssb->connections_tracker = tf_ssb_connections_create(ssb);
_tf_ssb_update_settings(ssb);
tf_ssb_rpc_register(ssb); tf_ssb_rpc_register(ssb);
_tf_ssb_start_update_settings(ssb, 5000);
return ssb; return ssb;
} }
@ -2327,11 +2334,17 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
uv_close((uv_handle_t*)&ssb->server, _tf_ssb_on_handle_close); uv_close((uv_handle_t*)&ssb->server, _tf_ssb_on_handle_close);
} }
if (ssb->settings_timer.data && !uv_is_closing((uv_handle_t*)&ssb->settings_timer))
{
uv_close((uv_handle_t*)&ssb->settings_timer, _tf_ssb_on_handle_close);
}
while (ssb->broadcast_listener.data || while (ssb->broadcast_listener.data ||
ssb->broadcast_sender.data || ssb->broadcast_sender.data ||
ssb->broadcast_timer.data || ssb->broadcast_timer.data ||
ssb->broadcast_cleanup_timer.data || ssb->broadcast_cleanup_timer.data ||
ssb->trace_timer.data || ssb->trace_timer.data ||
ssb->settings_timer.data ||
ssb->server.data || ssb->server.data ||
ssb->ref_count) ssb->ref_count)
{ {
@ -2430,6 +2443,8 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
uv_mutex_destroy(&ssb->db_readers_lock); uv_mutex_destroy(&ssb->db_readers_lock);
uv_mutex_destroy(&ssb->db_writer_lock); uv_mutex_destroy(&ssb->db_writer_lock);
tf_free((void*)ssb->db_path); tf_free((void*)ssb->db_path);
tf_free(ssb->room_name);
ssb->room_name = NULL;
tf_free(ssb); tf_free(ssb);
} }
@ -3646,9 +3661,9 @@ void tf_ssb_unref(tf_ssb_t* ssb)
ssb->ref_count--; ssb->ref_count--;
} }
void tf_ssb_set_main_thread(tf_ssb_t* ssb) void tf_ssb_set_main_thread(tf_ssb_t* ssb, bool main_thread)
{ {
ssb->thread_self = uv_thread_self(); ssb->thread_self = main_thread ? uv_thread_self() : 0;
} }
typedef struct _connection_work_t typedef struct _connection_work_t
@ -3713,3 +3728,137 @@ void tf_ssb_connection_run_work(
_tf_ssb_connection_after_work_callback(&work->work, result); _tf_ssb_connection_after_work_callback(&work->work, result);
} }
} }
bool tf_ssb_is_room(tf_ssb_t* ssb)
{
return ssb->is_room;
}
void tf_ssb_set_is_room(tf_ssb_t* ssb, bool is_room)
{
ssb->is_room = is_room;
}
const char* tf_ssb_get_room_name(tf_ssb_t* ssb)
{
return ssb->room_name;
}
void tf_ssb_set_room_name(tf_ssb_t* ssb, const char* room_name)
{
tf_free(ssb->room_name);
ssb->room_name = tf_strdup(room_name);
}
typedef struct _update_settings_t
{
uv_work_t work;
tf_ssb_t* ssb;
bool is_room;
char room_name[1024];
} update_settings_t;
static bool _get_global_setting_string(tf_ssb_t* ssb, const char* name, char* out_value, size_t size)
{
bool result = false;
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
sqlite3_stmt* statement;
if (sqlite3_prepare(db, "SELECT json_extract(value, '$.' || ?) FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_text(statement, 1, name, -1, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
snprintf(out_value, size, "%s", sqlite3_column_text(statement, 0));
result = true;
}
}
sqlite3_finalize(statement);
}
else
{
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
}
tf_ssb_release_db_reader(ssb, db);
return result;
}
static bool _get_global_setting_bool(tf_ssb_t* ssb, const char* name, bool default_value)
{
bool result = default_value;
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
sqlite3_stmt* statement;
if (sqlite3_prepare(db, "SELECT json_extract(value, '$.' || ?) FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_text(statement, 1, name, -1, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
result = sqlite3_column_int(statement, 0) != 0;
}
}
sqlite3_finalize(statement);
}
else
{
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
}
tf_ssb_release_db_reader(ssb, db);
return result;
}
static void _tf_ssb_update_settings_work(uv_work_t* work)
{
update_settings_t* update = work->data;
update->is_room = _get_global_setting_bool(update->ssb, "room", true);
_get_global_setting_string(update->ssb, "room_name", update->room_name, sizeof(update->room_name));
}
static void _tf_ssb_update_settings_after_work(uv_work_t* work, int result)
{
update_settings_t* update = work->data;
tf_ssb_set_is_room(update->ssb, update->is_room);
tf_ssb_set_room_name(update->ssb, update->room_name);
tf_free(update);
}
static void _tf_ssb_start_update_settings_timer(uv_timer_t* timer)
{
update_settings_t* update = tf_malloc(sizeof(update_settings_t));
*update = (update_settings_t)
{
.work =
{
.data = update,
},
.ssb = timer->data,
};
int result = uv_queue_work(tf_ssb_get_loop(timer->data), &update->work, _tf_ssb_update_settings_work, _tf_ssb_update_settings_after_work);
if (result)
{
_tf_ssb_update_settings_after_work(&update->work, result);
}
}
static void _tf_ssb_update_settings(tf_ssb_t* ssb)
{
update_settings_t* update = tf_malloc(sizeof(update_settings_t));
*update = (update_settings_t)
{
.work =
{
.data = update,
},
.ssb = ssb,
};
_tf_ssb_update_settings_work(&update->work);
_tf_ssb_update_settings_after_work(&update->work, 0);
}
static void _tf_ssb_start_update_settings(tf_ssb_t* ssb, int delay_ms)
{
ssb->settings_timer.data = ssb;
uv_timer_init(ssb->loop, &ssb->settings_timer);
uv_timer_start(&ssb->settings_timer, _tf_ssb_start_update_settings_timer, delay_ms, delay_ms);
uv_unref((uv_handle_t*)&ssb->settings_timer);
}

View File

@ -216,4 +216,9 @@ tf_ssb_store_queue_t* tf_ssb_get_store_queue(tf_ssb_t* ssb);
void tf_ssb_ref(tf_ssb_t* ssb); void tf_ssb_ref(tf_ssb_t* ssb);
void tf_ssb_unref(tf_ssb_t* ssb); void tf_ssb_unref(tf_ssb_t* ssb);
void tf_ssb_set_main_thread(tf_ssb_t* ssb); void tf_ssb_set_main_thread(tf_ssb_t* ssb, bool main_thread);
bool tf_ssb_is_room(tf_ssb_t* ssb);
void tf_ssb_set_is_room(tf_ssb_t* ssb, bool is_room);
const char* tf_ssb_get_room_name(tf_ssb_t* ssb);
void tf_ssb_set_room_name(tf_ssb_t* ssb, const char* room_name);

View File

@ -45,55 +45,6 @@ static int64_t _get_global_setting_int64(tf_ssb_t* ssb, const char* name, int64_
return result; return result;
} }
static bool _get_global_setting_bool(tf_ssb_t* ssb, const char* name, bool default_value)
{
bool result = default_value;
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
sqlite3_stmt* statement;
if (sqlite3_prepare(db, "SELECT json_extract(value, '$.' || ?) FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_text(statement, 1, name, -1, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
result = sqlite3_column_int(statement, 0) != 0;
}
}
sqlite3_finalize(statement);
}
else
{
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
}
tf_ssb_release_db_reader(ssb, db);
return result;
}
static bool _get_global_setting_string(tf_ssb_t* ssb, const char* name, char* out_value, size_t size)
{
bool result = false;
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
sqlite3_stmt* statement;
if (sqlite3_prepare(db, "SELECT json_extract(value, '$.' || ?) FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_text(statement, 1, name, -1, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
snprintf(out_value, size, "%s", sqlite3_column_text(statement, 0));
result = true;
}
}
sqlite3_finalize(statement);
}
else
{
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
}
tf_ssb_release_db_reader(ssb, db);
return result;
}
static void _tf_ssb_rpc_gossip_ping_callback(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data) static void _tf_ssb_rpc_gossip_ping_callback(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
{ {
char buffer[256]; char buffer[256];
@ -328,7 +279,7 @@ void _tf_ssb_rpc_tunnel_cleanup(tf_ssb_t* ssb, void* user_data)
static void _tf_ssb_rpc_tunnel_connect(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data) static void _tf_ssb_rpc_tunnel_connect(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
{ {
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection); tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
if (!_get_global_setting_bool(ssb, "room", true)) if (!tf_ssb_is_room(ssb))
{ {
tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, "tunnel.connect"); tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, "tunnel.connect");
return; return;
@ -427,12 +378,10 @@ static void _tf_ssb_rpc_room_meta(tf_ssb_connection_t* connection, uint8_t flags
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection); tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
JSContext* context = tf_ssb_get_context(ssb); JSContext* context = tf_ssb_get_context(ssb);
JSValue response = JS_FALSE; JSValue response = JS_FALSE;
if (_get_global_setting_bool(ssb, "room", true)) if (tf_ssb_is_room(ssb))
{ {
char room_name[1024] = "tilde friends tunnel";
_get_global_setting_string(ssb, "room_name", room_name, sizeof(room_name));
response = JS_NewObject(context); response = JS_NewObject(context);
JS_SetPropertyStr(context, response, "name", JS_NewString(context, room_name)); JS_SetPropertyStr(context, response, "name", JS_NewString(context, tf_ssb_get_room_name(ssb)));
JS_SetPropertyStr(context, response, "membership", JS_FALSE); JS_SetPropertyStr(context, response, "membership", JS_FALSE);
JSValue features = JS_NewArray(context); JSValue features = JS_NewArray(context);
JS_SetPropertyUint32(context, features, 0, JS_NewString(context, "tunnel")); JS_SetPropertyUint32(context, features, 0, JS_NewString(context, "tunnel"));
@ -454,7 +403,7 @@ static void _tf_ssb_rpc_room_meta(tf_ssb_connection_t* connection, uint8_t flags
static void _tf_ssb_rpc_room_attendants(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data) static void _tf_ssb_rpc_room_attendants(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
{ {
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection); tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
if (!_get_global_setting_bool(ssb, "room", true)) if (!tf_ssb_is_room(ssb))
{ {
tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, "room.attendants"); tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, "room.attendants");
return; return;

View File

@ -638,8 +638,8 @@ void tf_ssb_test_bench(const tf_test_options_t* options)
uint8_t id0bin[k_id_bin_len]; uint8_t id0bin[k_id_bin_len];
tf_ssb_id_str_to_bin(id0bin, id0); tf_ssb_id_str_to_bin(id0bin, id0);
tf_ssb_set_main_thread(ssb0); tf_ssb_set_main_thread(ssb0, true);
tf_ssb_set_main_thread(ssb1); tf_ssb_set_main_thread(ssb1, true);
uv_idle_t idle0 = { .data = ssb0 }; uv_idle_t idle0 = { .data = ssb0 };
uv_idle_init(&loop, &idle0); uv_idle_init(&loop, &idle0);
@ -666,6 +666,8 @@ void tf_ssb_test_bench(const tf_test_options_t* options)
tf_ssb_remove_message_added_callback(ssb1, _message_added, &count); tf_ssb_remove_message_added_callback(ssb1, _message_added, &count);
clock_gettime(CLOCK_REALTIME, &end_time); clock_gettime(CLOCK_REALTIME, &end_time);
tf_ssb_set_main_thread(ssb0, false);
tf_ssb_set_main_thread(ssb1, false);
count = _ssb_test_count_messages(ssb1); count = _ssb_test_count_messages(ssb1);
if (count < k_messages) if (count < k_messages)
{ {