From 2c11c54dd22440d6781c782f6e5f3568fa1e9311 Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Wed, 18 Dec 2019 19:45:24 +0100 Subject: [PATCH] db: Track the data_version in the database This increments the `data_version` upon committing dirty transactions, reads the last data_version upon startup, and tracks the number in memory in parallel to the DB (see next commit for rationale). Changelog-Changed: JSON-RPC: Added a `data_version` field to the `db_write` hook which returns a numeric transaction counter. --- lightningd/plugin_hook.c | 2 ++ wallet/db.c | 28 ++++++++++++++++++++++++++++ wallet/db.h | 3 +++ wallet/db_common.h | 4 ++++ wallet/test/run-db.c | 5 +++++ wallet/test/run-wallet.c | 1 + 6 files changed, 43 insertions(+) diff --git a/lightningd/plugin_hook.c b/lightningd/plugin_hook.c index f6a8f8b85..271389c49 100644 --- a/lightningd/plugin_hook.c +++ b/lightningd/plugin_hook.c @@ -175,6 +175,8 @@ void plugin_hook_db_sync(struct db *db) ph_req->hook = hook; ph_req->db = db; + json_add_num(req->stream, "data_version", db_data_version_get(db)); + json_array_start(req->stream, "writes"); for (size_t i = 0; i < tal_count(changes); i++) json_add_string(req->stream, NULL, changes[i]); diff --git a/wallet/db.c b/wallet/db.c index ea67b4f15..6d0bee788 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -802,11 +802,27 @@ void db_begin_transaction_(struct db *db, const char *location) db->in_transaction = location; } +static void db_data_version_incr(struct db *db) +{ + struct db_stmt *stmt = db_prepare_v2( + db, SQL("UPDATE vars " + "SET intval = intval + 1 " + "WHERE name = 'data_version'")); + db_exec_prepared_v2(stmt); + tal_free(stmt); + db->data_version++; +} + void db_commit_transaction(struct db *db) { bool ok; assert(db->in_transaction); db_assert_no_outstanding_statements(db); + + /* Increment before reporting changes to an eventual plugin. */ + if (db->dirty) + db_data_version_incr(db); + db_report_changes(db, NULL, 0); ok = db->config->commit_tx_fn(db); @@ -954,7 +970,18 @@ static void db_migrate(struct lightningd *ld, struct db *db) db_exec_prepared_v2(stmt); tal_free(stmt); } +} +u32 db_data_version_get(struct db *db) +{ + struct db_stmt *stmt; + u32 version; + stmt = db_prepare_v2(db, SQL("SELECT intval FROM vars WHERE name = 'data_version'")); + db_query_prepared(stmt); + db_step(stmt); + version = db_column_int(stmt, 0); + tal_free(stmt); + return version; } struct db *db_setup(const tal_t *ctx, struct lightningd *ld) @@ -966,6 +993,7 @@ struct db *db_setup(const tal_t *ctx, struct lightningd *ld) db_migrate(ld, db); + db->data_version = db_data_version_get(db); db_commit_transaction(db); return db; } diff --git a/wallet/db.h b/wallet/db.h index 7061a3db8..5f352be2b 100644 --- a/wallet/db.h +++ b/wallet/db.h @@ -229,4 +229,7 @@ struct db_stmt *db_prepare_v2_(const char *location, struct db *db, */ const char **db_changes(struct db *db); +/* Get the current data version. */ +u32 db_data_version_get(struct db *db); + #endif /* LIGHTNING_WALLET_DB_H */ diff --git a/wallet/db_common.h b/wallet/db_common.h index 3d56d6b73..69fdd9da0 100644 --- a/wallet/db_common.h +++ b/wallet/db_common.h @@ -34,6 +34,10 @@ struct db { /* Were there any modifying statements in the current transaction? * Used to bump the data_version in the DB.*/ bool dirty; + + /* The current DB version we expect to update if changes are + * committed. */ + u32 data_version; }; struct db_query { diff --git a/wallet/test/run-db.c b/wallet/test/run-db.c index bf326366c..f45be5675 100644 --- a/wallet/test/run-db.c +++ b/wallet/test/run-db.c @@ -63,6 +63,7 @@ static struct db *create_test_db(void) dsn = tal_fmt(NULL, "sqlite3://%s", filename); db = db_open(NULL, dsn); + db->data_version = 0; tal_free(dsn); return db; } @@ -107,6 +108,10 @@ static bool test_primitives(void) CHECK_MSG(db_err, "Failing SQL command"); tal_free(stmt); db_err = tal_free(db_err); + + /* We didn't migrate the DB, so don't have the vars table. Pretend we + * didn't change anything so we don't bump the data_version. */ + db->dirty = false; db_commit_transaction(db); CHECK(!db->in_transaction); tal_free(db); diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 63db38de4..7928c3e55 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -749,6 +749,7 @@ static struct wallet *create_test_wallet(struct lightningd *ld, const tal_t *ctx CHECK_MSG(w->db, "Failed opening the db"); db_begin_transaction(w->db); db_migrate(ld, w->db); + w->db->data_version = 0; db_commit_transaction(w->db); CHECK_MSG(!wallet_err, "DB migration failed"); w->max_channel_dbid = 0;