From 33e97813d72996d22a295773c64261f5588ce9dd Mon Sep 17 00:00:00 2001 From: "Neal H. Walfield" Date: Mon, 29 Aug 2016 15:13:45 +0200 Subject: [PATCH] g10: Support nested transactions on the TOFU DB. * g10/gpg.h (struct server_control_s): New field in_transaction. * g10/tofu.c (struct tofu_dbs_s): Remove fields savepoint_inner and savepoint_inner_commit. (begin_transaction): Increment CTRL->TOFU.IN_TRANSACTION. Name the savepoint according to the nesting level. (end_transaction): Name the savepoint according to the nesting level. Decrement CTRL->TOFU.IN_TRANSACTION. (rollback_transaction): Likewise. Only ever rollback a non-batch transaction. (opendbs): Assert that there are no outstanding transactions. -- Signed-off-by: Neal H. Walfield --- g10/gpg.h | 1 + g10/tofu.c | 41 +++++++++++++++++++++-------------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/g10/gpg.h b/g10/gpg.h index 1aaff2f4f..154da0de4 100644 --- a/g10/gpg.h +++ b/g10/gpg.h @@ -82,6 +82,7 @@ struct server_control_s /* Local data for tofu.c */ struct { tofu_dbs_t dbs; + int in_transaction; int batch_update_ref; time_t batch_update_started; } tofu; diff --git a/g10/tofu.c b/g10/tofu.c index e15b564f7..809dac9b8 100644 --- a/g10/tofu.c +++ b/g10/tofu.c @@ -70,9 +70,6 @@ struct tofu_dbs_s sqlite3_stmt *savepoint_batch; sqlite3_stmt *savepoint_batch_commit; - sqlite3_stmt *savepoint_inner; - sqlite3_stmt *savepoint_inner_commit; - sqlite3_stmt *record_binding_get_old_policy; sqlite3_stmt *record_binding_update; sqlite3_stmt *record_binding_update2; @@ -209,9 +206,12 @@ begin_transaction (ctrl_t ctrl, int only_batch) if (only_batch) return 0; - rc = gpgsql_stepx (dbs->db, &dbs->s.savepoint_inner, - NULL, NULL, &err, - "savepoint inner;", SQLITE_ARG_END); + log_assert(ctrl->tofu.in_transaction >= 0); + ctrl->tofu.in_transaction ++; + + rc = gpgsql_exec_printf (dbs->db, NULL, NULL, &err, + "savepoint inner%d;", + ctrl->tofu.in_transaction); if (rc) { log_error (_("error beginning transaction on TOFU database: %s\n"), @@ -263,9 +263,9 @@ end_transaction (ctrl_t ctrl, int only_batch) if (only_batch) return 0; - rc = gpgsql_stepx (dbs->db, &dbs->s.savepoint_inner_commit, - NULL, NULL, &err, - "release inner;", SQLITE_ARG_END); + log_assert (ctrl->tofu.in_transaction > 0); + rc = gpgsql_exec_printf (dbs->db, NULL, NULL, &err, + "release inner%d;", ctrl->tofu.in_transaction); if (rc) { log_error (_("error committing transaction on TOFU database: %s\n"), @@ -274,6 +274,8 @@ end_transaction (ctrl_t ctrl, int only_batch) return gpg_error (GPG_ERR_GENERAL); } + ctrl->tofu.in_transaction --; + return 0; } @@ -287,18 +289,15 @@ rollback_transaction (ctrl_t ctrl) if (!dbs) return 0; /* Shortcut to allow for easier cleanup code. */ + log_assert (ctrl->tofu.in_transaction > 0); - if (dbs->batch_update) - { - /* Just undo the most recent update; don't revert any progress - made by the batch transaction. */ - rc = sqlite3_exec (dbs->db, "rollback to inner;", NULL, NULL, &err); - } - else - { - /* Rollback the whole she-bang. */ - rc = sqlite3_exec (dbs->db, "rollback;", NULL, NULL, &err); - } + /* Be careful to not any progress made by closed transactions in + batch mode. */ + rc = gpgsql_exec_printf (dbs->db, NULL, NULL, &err, + "rollback to inner%d;", + ctrl->tofu.in_transaction); + + ctrl->tofu.in_transaction --; if (rc) { @@ -694,6 +693,8 @@ tofu_closedbs (ctrl_t ctrl) tofu_dbs_t dbs; sqlite3_stmt **statements; + log_assert(ctrl->tofu.in_transaction == 0); + dbs = ctrl->tofu.dbs; if (!dbs) return; /* Not initialized. */