From 8812148e2436b5ad9120181797e432285ccbb983 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 25 Mar 2011 00:29:42 +0100 Subject: s3:dbwrap_ctdb: fix non-locked fetch on persistent db's causing corruption When doing a non-locking fetch on a record of a persistent db when no transaction is running, the old behaviour was to fetch locally and do a ctdb call when the record was not found in the local db. The call is useless for persistent dbs anyway since they are only written to using transactions and hence kept in sync, but it is also harmful, because a ctdb call will bump the record RSN when it does actually migrate the record from one node to another. Recently, ctdb has been changed to make all calls do a migration. This uncovered the client misbehaviour for persistent dbs, because now _each_ non-locking fetch will render the persistent db inconsistent: A subsequent transaction which touches the record in question will fail because the RSNs are out of sync. This patch fixes this old bug. Autobuild-User: Michael Adam Autobuild-Date: Fri Mar 25 01:26:32 CET 2011 on sn-devel-104 --- source3/lib/dbwrap_ctdb.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/source3/lib/dbwrap_ctdb.c b/source3/lib/dbwrap_ctdb.c index 67425dcb79..46ec6dec29 100644 --- a/source3/lib/dbwrap_ctdb.c +++ b/source3/lib/dbwrap_ctdb.c @@ -474,6 +474,34 @@ static int db_ctdb_transaction_fetch(struct db_ctdb_ctx *db, return 0; } +/** + * Fetch a record from a persistent database + * without record locking and without an active transaction. + * + * This just fetches from the local database copy. + * Since the databases are kept in syc cluster-wide, + * there is no point in doing a ctdb call to fetch the + * record from the lmaster. It does even harm since migration + * of records bump their RSN and hence render the persistent + * database inconsistent. + */ +static int db_ctdb_fetch_persistent(struct db_ctdb_ctx *db, + TALLOC_CTX *mem_ctx, + TDB_DATA key, TDB_DATA *data) +{ + NTSTATUS status; + bool found; + + status = db_ctdb_ltdb_fetch(db, key, NULL, mem_ctx, data); + + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + *data = tdb_null; + } else if (!NT_STATUS_IS_OK(status)) { + return -1; + } + + return 0; +} static NTSTATUS db_ctdb_store_transaction(struct db_record *rec, TDB_DATA data, int flag); static NTSTATUS db_ctdb_delete_transaction(struct db_record *rec); @@ -1075,6 +1103,10 @@ static int db_ctdb_fetch(struct db_context *db, TALLOC_CTX *mem_ctx, return db_ctdb_transaction_fetch(ctx, mem_ctx, key, data); } + if (db->persistent) { + return db_ctdb_fetch_persistent(ctx, mem_ctx, key, data); + } + /* try a direct fetch */ ctdb_data = tdb_fetch(ctx->wtdb->tdb, key); @@ -1085,8 +1117,8 @@ static int db_ctdb_fetch(struct db_context *db, TALLOC_CTX *mem_ctx, */ if ((ctdb_data.dptr != NULL) && (ctdb_data.dsize >= sizeof(struct ctdb_ltdb_header)) && - (db->persistent || - ((struct ctdb_ltdb_header *)ctdb_data.dptr)->dmaster == get_my_vnn())) { + ((struct ctdb_ltdb_header *)ctdb_data.dptr)->dmaster == get_my_vnn()) + { /* we are the dmaster - avoid the ctdb protocol op */ data->dsize = ctdb_data.dsize - sizeof(struct ctdb_ltdb_header); -- cgit