forked from cory/tildefriends
		
	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:
		
							
								
								
									
										153
									
								
								src/ssb.c
									
									
									
									
									
								
							
							
						
						
									
										153
									
								
								src/ssb.c
									
									
									
									
									
								
							@@ -188,6 +188,7 @@ typedef struct _tf_ssb_t
 | 
			
		||||
	uv_timer_t broadcast_cleanup_timer;
 | 
			
		||||
	uv_timer_t broadcast_timer;
 | 
			
		||||
	uv_timer_t trace_timer;
 | 
			
		||||
	uv_timer_t settings_timer;
 | 
			
		||||
	uv_tcp_t server;
 | 
			
		||||
 | 
			
		||||
	uint8_t pub[crypto_sign_PUBLICKEYBYTES];
 | 
			
		||||
@@ -236,6 +237,8 @@ typedef struct _tf_ssb_t
 | 
			
		||||
	int ref_count;
 | 
			
		||||
 | 
			
		||||
	uv_thread_t thread_self;
 | 
			
		||||
	bool is_room;
 | 
			
		||||
	char* room_name;
 | 
			
		||||
} tf_ssb_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_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_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)
 | 
			
		||||
{
 | 
			
		||||
@@ -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);
 | 
			
		||||
 | 
			
		||||
	_tf_ssb_update_settings(ssb);
 | 
			
		||||
	tf_ssb_rpc_register(ssb);
 | 
			
		||||
	_tf_ssb_start_update_settings(ssb, 5000);
 | 
			
		||||
	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);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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 ||
 | 
			
		||||
		ssb->broadcast_sender.data ||
 | 
			
		||||
		ssb->broadcast_timer.data ||
 | 
			
		||||
		ssb->broadcast_cleanup_timer.data ||
 | 
			
		||||
		ssb->trace_timer.data ||
 | 
			
		||||
		ssb->settings_timer.data ||
 | 
			
		||||
		ssb->server.data ||
 | 
			
		||||
		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_writer_lock);
 | 
			
		||||
	tf_free((void*)ssb->db_path);
 | 
			
		||||
	tf_free(ssb->room_name);
 | 
			
		||||
	ssb->room_name = NULL;
 | 
			
		||||
	tf_free(ssb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -3646,9 +3661,9 @@ void tf_ssb_unref(tf_ssb_t* ssb)
 | 
			
		||||
	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
 | 
			
		||||
@@ -3713,3 +3728,137 @@ void tf_ssb_connection_run_work(
 | 
			
		||||
		_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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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_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);
 | 
			
		||||
 
 | 
			
		||||
@@ -45,55 +45,6 @@ static int64_t _get_global_setting_int64(tf_ssb_t* ssb, const char* name, int64_
 | 
			
		||||
	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)
 | 
			
		||||
{
 | 
			
		||||
	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)
 | 
			
		||||
{
 | 
			
		||||
	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");
 | 
			
		||||
		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);
 | 
			
		||||
	JSContext* context = tf_ssb_get_context(ssb);
 | 
			
		||||
	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);
 | 
			
		||||
		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);
 | 
			
		||||
		JSValue features = JS_NewArray(context);
 | 
			
		||||
		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)
 | 
			
		||||
{
 | 
			
		||||
	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");
 | 
			
		||||
		return;
 | 
			
		||||
 
 | 
			
		||||
@@ -638,8 +638,8 @@ void tf_ssb_test_bench(const tf_test_options_t* options)
 | 
			
		||||
	uint8_t id0bin[k_id_bin_len];
 | 
			
		||||
	tf_ssb_id_str_to_bin(id0bin, id0);
 | 
			
		||||
 | 
			
		||||
	tf_ssb_set_main_thread(ssb0);
 | 
			
		||||
	tf_ssb_set_main_thread(ssb1);
 | 
			
		||||
	tf_ssb_set_main_thread(ssb0, true);
 | 
			
		||||
	tf_ssb_set_main_thread(ssb1, true);
 | 
			
		||||
 | 
			
		||||
	uv_idle_t idle0 = { .data = ssb0 };
 | 
			
		||||
	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);
 | 
			
		||||
	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);
 | 
			
		||||
	if (count < k_messages)
 | 
			
		||||
	{
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user