From fb97047a840037c2c7237b9de681e386eeedffae Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Fri, 18 Jul 2008 18:50:16 +1000 Subject: Use transaction start/cancel for persistent writes to avoid leaving the database in an inconsistent state if we crash during the operation Signed-off-by: Ronnie Sahlberg (This used to be commit 09329f1f9114af44fc4e5e4f29a7315912313125) --- source3/include/ctdbd_conn.h | 2 ++ source3/lib/ctdbd_conn.c | 41 +++++++++++++++++++++++++++++++++++++---- source3/lib/dbwrap_ctdb.c | 11 +++++++++-- 3 files changed, 48 insertions(+), 6 deletions(-) (limited to 'source3') diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h index 6e1b2f737a..3ea895d133 100644 --- a/source3/include/ctdbd_conn.h +++ b/source3/include/ctdbd_conn.h @@ -66,5 +66,7 @@ NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, NTSTATUS ctdbd_register_reconfigure(struct ctdbd_connection *conn); NTSTATUS ctdbd_persistent_store(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key, TDB_DATA data); +NTSTATUS ctdbd_start_persistent_update(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key, TDB_DATA data); +NTSTATUS ctdbd_cancel_persistent_update(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key, TDB_DATA data); #endif /* _CTDBD_CONN_H */ diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index e8d3fd1159..51fefa93d4 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -1207,9 +1207,9 @@ NTSTATUS ctdbd_register_reconfigure(struct ctdbd_connection *conn) } /* - persstent store. Used when we update a record in a persistent database + persistent call. Used to start, store or cancel persistent updates. */ -NTSTATUS ctdbd_persistent_store(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key, TDB_DATA data) +static NTSTATUS ctdbd_persistent_call(struct ctdbd_connection *conn, uint32_t opcode, uint32_t db_id, TDB_DATA key, TDB_DATA data) { int cstatus=0; struct ctdb_rec_data *rec; @@ -1232,8 +1232,7 @@ NTSTATUS ctdbd_persistent_store(struct ctdbd_connection *conn, uint32_t db_id, T recdata.dptr = (uint8_t *)rec; recdata.dsize = length; - status = ctdbd_control(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_PERSISTENT_STORE, + status = ctdbd_control(conn, CTDB_CURRENT_NODE, opcode, 0, recdata, NULL, NULL, &cstatus); if (cstatus != 0) { return NT_STATUS_INTERNAL_DB_CORRUPTION; @@ -1241,6 +1240,40 @@ NTSTATUS ctdbd_persistent_store(struct ctdbd_connection *conn, uint32_t db_id, T return status; } +/* + persistent store. Used when we update a record in a persistent database + */ +NTSTATUS ctdbd_persistent_store(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key, TDB_DATA data) +{ + return ctdbd_persistent_call(conn, + CTDB_CONTROL_PERSISTENT_STORE, + db_id, key, data); +} + +/* + tell the ctdb daemon that we are starting a persistent update operation. + If we terminate/disconnect from the daemon without first performing + either a persistent_store or a cancel ctdbd will perform recovery. + */ +NTSTATUS ctdbd_start_persistent_update(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key, TDB_DATA data) +{ + return ctdbd_persistent_call(conn, + CTDB_CONTROL_START_PERSISTENT_UPDATE, + db_id, key, data); + +} + +/* + Cancel a persistent update operation. This is used if we have started a + persistent update but we want to abort it before we have made changes to + the tdb database. + */ +NTSTATUS ctdbd_cancel_persistent_update(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key, TDB_DATA data) +{ + return ctdbd_persistent_call(conn, + CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE, + db_id, key, data); +} #else diff --git a/source3/lib/dbwrap_ctdb.c b/source3/lib/dbwrap_ctdb.c index cb4c573eb0..aa2f9d371c 100644 --- a/source3/lib/dbwrap_ctdb.c +++ b/source3/lib/dbwrap_ctdb.c @@ -79,12 +79,19 @@ static NTSTATUS db_ctdb_store_persistent(struct db_record *rec, TDB_DATA data, i memcpy(cdata.dptr, &crec->header, sizeof(crec->header)); memcpy(cdata.dptr + sizeof(crec->header), data.dptr, data.dsize); - ret = tdb_store(crec->ctdb_ctx->wtdb->tdb, rec->key, cdata, TDB_REPLACE); - status = (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION; + status = ctdbd_start_persistent_update(messaging_ctdbd_connection(), crec->ctdb_ctx->db_id, rec->key, cdata); + /* now tell ctdbd to update this record on all other nodes */ + if (NT_STATUS_IS_OK(status)) { + ret = tdb_store(crec->ctdb_ctx->wtdb->tdb, rec->key, cdata, TDB_REPLACE); + status = (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION; + } + /* now tell ctdbd to update this record on all other nodes */ if (NT_STATUS_IS_OK(status)) { status = ctdbd_persistent_store(messaging_ctdbd_connection(), crec->ctdb_ctx->db_id, rec->key, cdata); + } else { + ctdbd_cancel_persistent_update(messaging_ctdbd_connection(), crec->ctdb_ctx->db_id, rec->key, cdata); } SAFE_FREE(cdata.dptr); -- cgit