summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Adam <obnox@samba.org>2011-03-25 00:29:42 +0100
committerMichael Adam <obnox@samba.org>2011-03-25 01:26:32 +0100
commit8812148e2436b5ad9120181797e432285ccbb983 (patch)
tree925c41bda6838ea999f83f7926a5031f7c23fdef
parent68529bc14efd077531086b3e8bcaf85287cfa6ba (diff)
downloadsamba-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
-rw-r--r--source3/lib/dbwrap_ctdb.c36
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);