sync

Backup service to store encrypted wallet databases (experimental)
Log | Files | Refs | Submodules | README | LICENSE

commit 8b63fe8d76052c9a2c47b154e8bdae45041d6803
parent 0df42cb55f6d2368affbb64b8777bfbd418134e7
Author: Iván Ávalos <avalos@disroot.org>
Date:   Wed,  1 Jul 2026 11:58:26 +0200

Revert "refactor to use new more robust GNUNET_PQ_init() style to handle database connection drops better"

This reverts commit ea203ef668ce4be4e92048b4b4ab8c8d2ff721bc.

Diffstat:
Msrc/include/sync/sync_database_lib.h | 6+++++-
Msrc/sync/sync-httpd.c | 3++-
Msrc/sync/sync-httpd2.c | 3++-
Msrc/syncdb/procedures.sql.in | 1-
Msrc/syncdb/sync-dbinit.c | 3++-
Msrc/syncdb/syncdb_create_tables.c | 37+++++++++++++++++--------------------
Msrc/syncdb/syncdb_drop_tables.c | 21+++++++++++++++++++--
Msrc/syncdb/syncdb_gc.c | 41++++++++++++++++++++++++-----------------
Dsrc/syncdb/syncdb_gc.sql | 34----------------------------------
Msrc/syncdb/syncdb_pg.c | 84++++++++++++++++++++++++-------------------------------------------------------
Msrc/syncdb/syncdb_pg.h | 5+++++
Msrc/syncdb/syncdb_preflight.c | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/syncdb/test_sync_db.c | 3++-
13 files changed, 163 insertions(+), 140 deletions(-)

diff --git a/src/include/sync/sync_database_lib.h b/src/include/sync/sync_database_lib.h @@ -37,10 +37,14 @@ * Initialize the sync database subsystem. * * @param cfg configuration to use + * @param skip_preflight true if we should skip the usual + * preflight check which assures us that the DB is actually + * operational; only sync-dbinit should use true here. * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure */ enum GNUNET_GenericReturnValue -SYNCDB_init (const struct GNUNET_CONFIGURATION_Handle *cfg); +SYNCDB_init (const struct GNUNET_CONFIGURATION_Handle *cfg, + bool skip_preflight); /** diff --git a/src/sync/sync-httpd.c b/src/sync/sync-httpd.c @@ -555,7 +555,8 @@ run (void *cls, } if (GNUNET_OK != - SYNCDB_init (config)) + SYNCDB_init (config, + false)) { global_ret = EXIT_NOTCONFIGURED; GNUNET_SCHEDULER_shutdown (); diff --git a/src/sync/sync-httpd2.c b/src/sync/sync-httpd2.c @@ -503,7 +503,8 @@ run (void *cls, } if (GNUNET_OK != - SYNCDB_init (config)) + SYNCDB_init (config, + false)) { global_ret = EXIT_NOTCONFIGURED; GNUNET_SCHEDULER_shutdown (); diff --git a/src/syncdb/procedures.sql.in b/src/syncdb/procedures.sql.in @@ -22,6 +22,5 @@ SET search_path TO sync; #include "syncdb_lookup_account_TR.sql" #include "syncdb_store_backup_TR.sql" #include "syncdb_update_backup_TR.sql" -#include "syncdb_gc.sql" COMMIT; diff --git a/src/syncdb/sync-dbinit.c b/src/syncdb/sync-dbinit.c @@ -55,7 +55,8 @@ run (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg) { if (GNUNET_OK != - SYNCDB_init (cfg)) + SYNCDB_init (cfg, + true)) { fprintf (stderr, "Failed to initialize database.\n"); diff --git a/src/syncdb/syncdb_create_tables.c b/src/syncdb/syncdb_create_tables.c @@ -24,27 +24,24 @@ enum GNUNET_GenericReturnValue SYNCDB_create_tables (void) { - if (GNUNET_SYSERR == - GNUNET_PQ_load_versioning (pg->conn)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_PQ_run_sql (pg->conn, - "sync-")) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_PQ_exec_sql (pg->conn, - "procedures")) - { - GNUNET_break (0); + struct GNUNET_PQ_Context *conn; + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("SET search_path TO sync;"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; + enum GNUNET_GenericReturnValue ret; + + conn = GNUNET_PQ_connect_with_cfg (pg->cfg, + "syncdb-postgres", + "sync-", + es, + NULL); + if (NULL == conn) return GNUNET_SYSERR; - } - return GNUNET_OK; + ret = GNUNET_PQ_exec_sql (conn, + "procedures"); + GNUNET_PQ_disconnect (conn); + return ret; } diff --git a/src/syncdb/syncdb_drop_tables.c b/src/syncdb/syncdb_drop_tables.c @@ -24,8 +24,25 @@ enum GNUNET_GenericReturnValue SYNCDB_drop_tables (void) { - return GNUNET_PQ_exec_sql (pg->conn, - "drop"); + struct GNUNET_PQ_Context *conn; + enum GNUNET_GenericReturnValue ret; + + if (NULL != pg->conn) + { + GNUNET_PQ_disconnect (pg->conn); + pg->conn = NULL; + } + conn = GNUNET_PQ_connect_with_cfg (pg->cfg, + "syncdb-postgres", + NULL, + NULL, + NULL); + if (NULL == conn) + return GNUNET_SYSERR; + ret = GNUNET_PQ_exec_sql (conn, + "drop"); + GNUNET_PQ_disconnect (conn); + return ret; } diff --git a/src/syncdb/syncdb_gc.c b/src/syncdb/syncdb_gc.c @@ -27,26 +27,33 @@ SYNCDB_gc (struct GNUNET_TIME_Absolute expire_backups, { struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_absolute_time (&expire_backups), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_QueryParam params2[] = { GNUNET_PQ_query_param_absolute_time (&expire_pending_payments), GNUNET_PQ_query_param_end }; - - if (GNUNET_OK != - GNUNET_PQ_prepare_anon ( - pg->conn, - "CALL sync.sync_do_gc ($1, $2);")) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (0 > GNUNET_PQ_eval_prepared_non_select (pg->conn, - "", - params)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; + enum GNUNET_DB_QueryStatus qs; + + SYNCDB_preflight (); + PREPARE ("gc_accounts", + "DELETE FROM accounts " + "WHERE" + " expiration_date < $1;"); + PREPARE ("gc_pending_payments", + "DELETE FROM payments " + "WHERE" + " paid=FALSE" + " AND" + " timestamp < $1;"); + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "gc_accounts", + params); + if (qs < 0) + return qs; + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "gc_pending_payments", + params2); } diff --git a/src/syncdb/syncdb_gc.sql b/src/syncdb/syncdb_gc.sql @@ -1,34 +0,0 @@ --- --- This file is part of TALER --- Copyright (C) 2026 Taler Systems SA --- --- TALER is free software; you can redistribute it and/or modify it under the --- terms of the GNU General Public License as published by the Free Software --- Foundation; either version 3, or (at your option) any later version. --- --- TALER is distributed in the hope that it will be useful, but WITHOUT ANY --- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR --- A PARTICULAR PURPOSE. See the GNU General Public License for more details. --- --- You should have received a copy of the GNU General Public License along with --- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> --- - -DROP PROCEDURE IF EXISTS sync_do_gc; -CREATE PROCEDURE sync_do_gc( - in_expire_backups INT8 - ,in_expire_pending_payments INT8) -LANGUAGE plpgsql -AS $$ -BEGIN - DELETE - FROM accounts - WHERE expiration_date < expire_backups; - DELETE - FROM payments - WHERE paid=FALSE - AND timestamp < in_expire_pending_payments; -END $$; -COMMENT ON PROCEDURE sync_do_gc - IS 'Performs garbage collection on sync data'; -COMMIT; diff --git a/src/syncdb/syncdb_pg.c b/src/syncdb/syncdb_pg.c @@ -18,10 +18,6 @@ * @brief shared database state and helpers for sync postgres * @author Christian Grothoff */ - -struct PostgresClosure; -#define GNUNET_PQ_RECONNECT_CALLBACK_CLOSURE \ - struct PostgresClosure #include "syncdb_pg.h" #include "sync/sync_util.h" @@ -29,63 +25,29 @@ struct PostgresClosure; /** * Global database closure. */ -// FIXME: prefix! struct PostgresClosure *pg; -/** - * Function called each time we connect or reconnect to the - * database. Gives the application a chance to run some - * per-connection initialization logic. - * - * @param pg_ database conntext in the auditor - * @param pq database connection handle - */ -static void -reconnect_cb (struct PostgresClosure *pg_, - struct GNUNET_PQ_Context *pq) -{ -#if AUTO_EXPLAIN - /* Enable verbose logging to see where queries do not - properly use indices */ - struct GNUNET_PQ_ExecuteStatement es[] = { - GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"), - GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"), - GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"), - GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"), - /* https://wiki.postgresql.org/wiki/Serializable suggests to really - force the default to 'serializable' if SSI is to be used. */ - GNUNET_PQ_make_try_execute ( - "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"), - GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"), - GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"), - GNUNET_PQ_make_execute ("SET search_path TO sync;"), - GNUNET_PQ_EXECUTE_STATEMENT_END - }; -#else - struct GNUNET_PQ_ExecuteStatement es[] = { - GNUNET_PQ_make_execute ("SET search_path TO sync;"), - GNUNET_PQ_EXECUTE_STATEMENT_END - }; -#endif - - if (GNUNET_OK != - GNUNET_PQ_exec_statements (pq, - es)) - { - GNUNET_break (0); - return; - } - pg_->prep_gen++; -} - - enum GNUNET_GenericReturnValue -SYNCDB_init (const struct GNUNET_CONFIGURATION_Handle *cfg) +SYNCDB_init (const struct GNUNET_CONFIGURATION_Handle *cfg, + bool skip_preflight) { pg = GNUNET_new (struct PostgresClosure); pg->cfg = cfg; if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "syncdb-postgres", + "SQL_DIR", + &pg->sql_dir)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "syncdb-postgres", + "SQL_DIR"); + GNUNET_free (pg); + pg = NULL; + return GNUNET_SYSERR; + } + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "sync", "CURRENCY", @@ -94,17 +56,19 @@ SYNCDB_init (const struct GNUNET_CONFIGURATION_Handle *cfg) GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "sync", "CURRENCY"); + GNUNET_free (pg->sql_dir); GNUNET_free (pg); + pg = NULL; return GNUNET_SYSERR; } - pg->conn = GNUNET_PQ_init (pg->cfg, - "merchantdb-postgres", - &reconnect_cb, - pg); - if (NULL == pg->conn) + if ( (! skip_preflight) && + (GNUNET_OK != + SYNCDB_preflight ()) ) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Database not ready. Try running sync-dbinit!\n"); SYNCDB_fini (); - return GNUNET_NO; + return GNUNET_SYSERR; } return GNUNET_OK; } @@ -118,7 +82,9 @@ SYNCDB_fini (void) if (NULL != pg->conn) GNUNET_PQ_disconnect (pg->conn); GNUNET_free (pg->currency); + GNUNET_free (pg->sql_dir); GNUNET_free (pg); + pg = NULL; } diff --git a/src/syncdb/syncdb_pg.h b/src/syncdb/syncdb_pg.h @@ -40,6 +40,11 @@ struct PostgresClosure struct GNUNET_PQ_Context *conn; /** + * Directory with SQL statements to run to create tables. + */ + char *sql_dir; + + /** * Underlying configuration. */ const struct GNUNET_CONFIGURATION_Handle *cfg; diff --git a/src/syncdb/syncdb_preflight.c b/src/syncdb/syncdb_preflight.c @@ -21,6 +21,53 @@ #include "syncdb_pg.h" +static enum GNUNET_GenericReturnValue +internal_setup (void) +{ + if (NULL == pg->conn) + { +#if AUTO_EXPLAIN + /* Enable verbose logging to see where queries do not + properly use indices */ + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"), + GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"), + GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"), + GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"), + /* https://wiki.postgresql.org/wiki/Serializable suggests to really + force the default to 'serializable' if SSI is to be used. */ + GNUNET_PQ_make_try_execute ( + "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"), + GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"), + GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"), + GNUNET_PQ_make_execute ("SET search_path TO sync;"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; +#else + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("SET search_path TO sync;"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; +#endif + struct GNUNET_PQ_Context *db_conn; + + db_conn = GNUNET_PQ_connect_with_cfg2 (pg->cfg, + "syncdb-postgres", + "sync-", + es, + NULL, + GNUNET_PQ_FLAG_CHECK_CURRENT); + if (NULL == db_conn) + return GNUNET_SYSERR; + pg->conn = db_conn; + pg->prep_gen++; + } + if (NULL == pg->transaction_name) + GNUNET_PQ_reconnect_if_down (pg->conn); + return GNUNET_OK; +} + + enum GNUNET_GenericReturnValue SYNCDB_preflight (void) { @@ -29,11 +76,22 @@ SYNCDB_preflight (void) GNUNET_PQ_EXECUTE_STATEMENT_END }; - if (NULL == pg->transaction_name) + if (NULL == pg->conn) + { + if (GNUNET_OK != + internal_setup ()) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to ensure DB is initialized\n"); + return GNUNET_SYSERR; + } + } + else { GNUNET_PQ_reconnect_if_down (pg->conn); - return GNUNET_OK; /* all good */ } + if (NULL == pg->transaction_name) + return GNUNET_OK; /* all good */ if (GNUNET_OK == GNUNET_PQ_exec_statements (pg->conn, es)) diff --git a/src/syncdb/test_sync_db.c b/src/syncdb/test_sync_db.c @@ -90,7 +90,8 @@ run (void *cls) void *b = NULL; if (GNUNET_OK != - SYNCDB_init (cfg)) + SYNCDB_init (cfg, + true)) { result = 77; return;