2 Commits

Author SHA1 Message Date
899605c860 ssb: Actually prevent the sqlite WAL file from growing out of control by truncating when it grows to about 64MB of pages.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 33m59s
2025-06-07 11:39:31 -04:00
dc9a279991 ssb: Free sqlite3_exec errors. 2025-06-07 10:36:44 -04:00
3 changed files with 43 additions and 23 deletions

View File

@@ -31,6 +31,10 @@ static int _tf_ssb_db_try_exec(sqlite3* db, const char* statement)
{ {
tf_printf("Error running '%s': %s.\n", statement, error ? error : sqlite3_errmsg(db)); tf_printf("Error running '%s': %s.\n", statement, error ? error : sqlite3_errmsg(db));
} }
if (error)
{
sqlite3_free(error);
}
return result; return result;
} }
@@ -41,6 +45,13 @@ static void _tf_ssb_db_exec(sqlite3* db, const char* statement)
if (result != SQLITE_OK) if (result != SQLITE_OK)
{ {
tf_printf("Error running '%s': %s.\n", statement, error ? error : sqlite3_errmsg(db)); tf_printf("Error running '%s': %s.\n", statement, error ? error : sqlite3_errmsg(db));
}
if (error)
{
sqlite3_free(error);
}
if (result != SQLITE_OK)
{
abort(); abort();
} }
} }
@@ -76,6 +87,26 @@ static int _tf_ssb_db_busy_handler(void* user_data, int count)
return 1; return 1;
} }
static int _tf_ssb_db_wal_hook(void* user_data, sqlite3* db, const char* db_name, int log_pages)
{
/* Keeps the log below about 64MB with default 4096 byte pages. */
if (log_pages >= 16384)
{
int log = 0;
int checkpointed = 0;
uint64_t checkpoint_start_ns = uv_hrtime();
if (sqlite3_wal_checkpoint_v2(db, NULL, SQLITE_CHECKPOINT_TRUNCATE, &log, &checkpointed) == SQLITE_OK)
{
tf_printf("Checkpointed %d pages in %d ms. Log is now %d frames.\n", log_pages, (int)((uv_hrtime() - checkpoint_start_ns) / 1000000LL), log);
}
else
{
tf_printf("Checkpoint: %s.\n", sqlite3_errmsg(db));
}
}
return SQLITE_OK;
}
static void _tf_ssb_db_init_internal(sqlite3* db) static void _tf_ssb_db_init_internal(sqlite3* db)
{ {
sqlite3_extended_result_codes(db, 1); sqlite3_extended_result_codes(db, 1);
@@ -93,6 +124,7 @@ void tf_ssb_db_init(tf_ssb_t* ssb)
{ {
sqlite3* db = tf_ssb_acquire_db_writer(ssb); sqlite3* db = tf_ssb_acquire_db_writer(ssb);
_tf_ssb_db_init_internal(db); _tf_ssb_db_init_internal(db);
sqlite3_wal_hook(db, _tf_ssb_db_wal_hook, NULL);
sqlite3_stmt* statement = NULL; sqlite3_stmt* statement = NULL;
int auto_vacuum = 0; int auto_vacuum = 0;

View File

@@ -279,10 +279,14 @@ static void _tf_ssb_swap_with_server_identity_work(tf_ssb_t* ssb, void* user_dat
sqlite3_bind_text(statement, 2, work->user, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 3, work->id, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, work->user, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 3, work->id, -1, NULL) == SQLITE_OK &&
sqlite3_step(statement) == SQLITE_DONE && sqlite3_changes(db) == 1) sqlite3_step(statement) == SQLITE_DONE && sqlite3_changes(db) == 1)
{ {
error = NULL; char* commit_error = NULL;
if (sqlite3_exec(db, "COMMIT TRANSACTION", NULL, NULL, &error) != SQLITE_OK) if (sqlite3_exec(db, "COMMIT TRANSACTION", NULL, NULL, &commit_error) != SQLITE_OK)
{ {
work->error = error ? tf_strdup(error) : tf_strdup(sqlite3_errmsg(db)); work->error = commit_error ? tf_strdup(commit_error) : tf_strdup(sqlite3_errmsg(db));
}
if (commit_error)
{
sqlite3_free(commit_error);
} }
} }
else else
@@ -300,6 +304,10 @@ static void _tf_ssb_swap_with_server_identity_work(tf_ssb_t* ssb, void* user_dat
{ {
work->error = error ? tf_strdup(error) : tf_strdup(sqlite3_errmsg(db)); work->error = error ? tf_strdup(error) : tf_strdup(sqlite3_errmsg(db));
} }
if (error)
{
sqlite3_free(error);
}
} }
else else
{ {

View File

@@ -1463,23 +1463,6 @@ static void _tf_ssb_rpc_broadcasts_changed_callback(tf_ssb_t* ssb, void* user_da
tf_ssb_visit_broadcasts(ssb, _tf_ssb_rpc_broadcasts_changed_visit, ssb); tf_ssb_visit_broadcasts(ssb, _tf_ssb_rpc_broadcasts_changed_visit, ssb);
} }
static void _tf_ssb_rpc_checkpoint(tf_ssb_t* ssb)
{
int64_t checkpoint_start_ms = uv_hrtime();
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
int log = 0;
int checkpointed = 0;
if (sqlite3_wal_checkpoint_v2(db, NULL, SQLITE_CHECKPOINT_PASSIVE, &log, &checkpointed) == SQLITE_OK)
{
tf_printf("Checkpointed %d frames in %d ms. Log is now %d frames.\n", checkpointed, (int)((uv_hrtime() - checkpoint_start_ms) / 1000000LL), log);
}
else
{
tf_printf("Checkpoint: %s.\n", sqlite3_errmsg(db));
}
tf_ssb_release_db_writer(ssb, db);
}
typedef struct _delete_t typedef struct _delete_t
{ {
int deleted; int deleted;
@@ -1495,7 +1478,6 @@ static void _tf_ssb_rpc_delete_blobs_work(tf_ssb_t* ssb, void* user_data)
tf_ssb_release_db_reader(ssb, db); tf_ssb_release_db_reader(ssb, db);
if (age <= 0) if (age <= 0)
{ {
_tf_ssb_rpc_checkpoint(ssb);
return; return;
} }
int64_t start_ns = uv_hrtime(); int64_t start_ns = uv_hrtime();
@@ -1546,7 +1528,6 @@ static void _tf_ssb_rpc_delete_blobs_work(tf_ssb_t* ssb, void* user_data)
tf_ssb_release_db_writer(ssb, db); tf_ssb_release_db_writer(ssb, db);
delete->duration_ms = (uv_hrtime() - start_ns) / 1000000LL; delete->duration_ms = (uv_hrtime() - start_ns) / 1000000LL;
tf_printf("Deleted %d blobs in %d ms.\n", deleted, (int)delete->duration_ms); tf_printf("Deleted %d blobs in %d ms.\n", deleted, (int)delete->duration_ms);
_tf_ssb_rpc_checkpoint(ssb);
} }
static void _tf_ssb_rpc_delete_blobs_after_work(tf_ssb_t* ssb, int status, void* user_data) static void _tf_ssb_rpc_delete_blobs_after_work(tf_ssb_t* ssb, int status, void* user_data)
@@ -1632,7 +1613,6 @@ static void _tf_ssb_rpc_delete_feeds_work(tf_ssb_t* ssb, void* user_data)
delete->duration_ms = (uv_hrtime() - start_ns) / 1000000LL; delete->duration_ms = (uv_hrtime() - start_ns) / 1000000LL;
tf_printf("Deleted %d message in %d ms.\n", delete->deleted, (int)delete->duration_ms); tf_printf("Deleted %d message in %d ms.\n", delete->deleted, (int)delete->duration_ms);
_tf_ssb_rpc_checkpoint(ssb);
} }
static void _tf_ssb_rpc_delete_feeds_after_work(tf_ssb_t* ssb, int status, void* user_data) static void _tf_ssb_rpc_delete_feeds_after_work(tf_ssb_t* ssb, int status, void* user_data)