diff options
author | Michael Adam <obnox@samba.org> | 2011-03-25 00:29:42 +0100 |
---|---|---|
committer | Michael Adam <obnox@samba.org> | 2011-03-25 01:26:32 +0100 |
commit | 8812148e2436b5ad9120181797e432285ccbb983 (patch) | |
tree | 925c41bda6838ea999f83f7926a5031f7c23fdef /source3 | |
parent | 68529bc14efd077531086b3e8bcaf85287cfa6ba (diff) | |
download | samba-8812148e2436b5ad9120181797e432285ccbb983.tar.gz samba-8812148e2436b5ad9120181797e432285ccbb983.tar.bz2 samba-8812148e2436b5ad9120181797e432285ccbb983.zip |
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 <obnox@samba.org>
Autobuild-Date: Fri Mar 25 01:26:32 CET 2011 on sn-devel-104
Diffstat (limited to 'source3')
-rw-r--r-- | source3/lib/dbwrap_ctdb.c | 36 |
1 files 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); |