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