[SCM] CTDB repository - branch tridge updated - b6d9a0396fb4b325778d3810dc656f719f31b9f1

Ronnie Sahlberg sahlberg at samba.org
Mon Aug 4 05:04:15 GMT 2008


The branch, tridge has been updated
       via  b6d9a0396fb4b325778d3810dc656f719f31b9f1 (commit)
       via  f7a70a5f9043b1d7293a515abf5b5228365693da (commit)
       via  aefcb1f817581ac8cd67712d07159fc802f96623 (commit)
       via  fe55bfc8fb6dc628f72f220843e829a251d09936 (commit)
       via  3a71844cfdb9fe69208030432ddb547b0e215726 (commit)
       via  306af4ccef132ea023f1f01e11f877a3a742ee4c (commit)
       via  bad53b2d342bb9760497e6f4a61e64ca50d6e771 (commit)
       via  9806d18b93218c216d538e28f9ed495269f0a938 (commit)
       via  71d9d24abae62f70acbd7c1ded8af0b817607c2a (commit)
       via  12087e7d751a8756076662cd8db5dcf35316c0c5 (commit)
       via  2bc7f3aef4668bd1680db87ef215c349280a84f2 (commit)
       via  aab710f1c6bcdfd8ff2992f8adc15933276dc39e (commit)
       via  9ff3380099fe6f4d39de126db0826971a10ee692 (commit)
       via  d5dcb46e182466e4b51c106f2491178c23babd8d (commit)
       via  4d205476d286570a6e1f52b59af42858ce051106 (commit)
       via  008533d971aec9c28c6e4750ef4677dd943633ff (commit)
       via  d3f5d75665a78ae0081fda57e58384b27a6ae396 (commit)
       via  22f737be0e70fc043affaa4f953f60d852b7999a (commit)
       via  ded1a974cdd86b436c6e5cba27069d1a3796dbe9 (commit)
       via  795c190b004d404b84dda053593139ed51d345e5 (commit)
       via  b1fed105ad780e89a128a611ef0bd659818eeebf (commit)
       via  8fed021d11160b137f4140ea02947347250e2959 (commit)
       via  e8ef9891aa31c374921b23cc74e1eda1f8218bf0 (commit)
       via  0de79352c9b36c118e36905f08ebbe38ecbb957e (commit)
       via  b08a988fbdad0da850c9b79791c1a8970555147f (commit)
       via  eca73bcaa33f88c683b79d57d85b590659018ad8 (commit)
       via  e24152fbd06ba4c2b6cfd473751c7f00a676b9ae (commit)
       via  c5035657606283d2e35bea40992505e84ca8e7be (commit)
       via  60e2cb175c449ae65793a3e1ffb60cf030a3a0d5 (commit)
       via  3d58f9b524a40c7b43a2a855212db090e9becefa (commit)
       via  554dcf16d37c8b9e4704df11d21fb272f30f5cec (commit)
       via  52716d26eb84104d65828bed38e69f214a5fa824 (commit)
       via  52a38487f981fd5981c02a7a063ad2c598591c10 (commit)
       via  af38c8d4cc03e1b5a314ea2338346c5f8c80aa95 (commit)
       via  05918bcb58acd2add7e13c028de09641a7519cd1 (commit)
       via  9478852f2b4f530994b2211fff45413d1da82dd9 (commit)
      from  ccf9334bd20b1398623dd649987aa15119dac14e (commit)

http://gitweb.samba.org/?p=sahlberg/ctdb.git;a=shortlog;h=tridge


- Log -----------------------------------------------------------------
commit b6d9a0396fb4b325778d3810dc656f719f31b9f1
Author: Andrew Tridgell <tridge at samba.org>
Date:   Mon Aug 4 14:51:51 2008 +1000

    implemented replayable transactions in ctdb to prevent deadlock

commit f7a70a5f9043b1d7293a515abf5b5228365693da
Author: Andrew Tridgell <tridge at samba.org>
Date:   Fri Aug 1 14:23:15 2008 +1000

    we need an additional gratuitous arp before the NFS tickles

commit aefcb1f817581ac8cd67712d07159fc802f96623
Author: Andrew Tridgell <tridge at samba.org>
Date:   Fri Aug 1 14:17:50 2008 +1000

    ensure we use killtcp on non-NFS/non-CIFS ports for faster failover of
    other protocols

commit fe55bfc8fb6dc628f72f220843e829a251d09936
Author: Andrew Tridgell <tridge at samba.org>
Date:   Wed Jul 30 19:59:54 2008 +1000

    fixed some warnings

commit 3a71844cfdb9fe69208030432ddb547b0e215726
Author: Andrew Tridgell <tridge at samba.org>
Date:   Wed Jul 30 19:59:42 2008 +1000

    fixed a warning

commit 306af4ccef132ea023f1f01e11f877a3a742ee4c
Author: Andrew Tridgell <tridge at samba.org>
Date:   Wed Jul 30 19:59:34 2008 +1000

    cleanup of the old persistent db test

commit bad53b2d342bb9760497e6f4a61e64ca50d6e771
Author: Andrew Tridgell <tridge at samba.org>
Date:   Wed Jul 30 19:59:18 2008 +1000

    renamed the pulldb structure to a ctdb_marshall_buffer

commit 9806d18b93218c216d538e28f9ed495269f0a938
Author: Andrew Tridgell <tridge at samba.org>
Date:   Wed Jul 30 19:58:49 2008 +1000

    make sure we honor the TDB_NOSYNC flag from clients in the server

commit 71d9d24abae62f70acbd7c1ded8af0b817607c2a
Author: Andrew Tridgell <tridge at samba.org>
Date:   Wed Jul 30 19:58:27 2008 +1000

    new prototypes

commit 12087e7d751a8756076662cd8db5dcf35316c0c5
Author: Andrew Tridgell <tridge at samba.org>
Date:   Wed Jul 30 19:58:17 2008 +1000

    added marshalling helper functions

commit 2bc7f3aef4668bd1680db87ef215c349280a84f2
Author: Andrew Tridgell <tridge at samba.org>
Date:   Wed Jul 30 19:58:03 2008 +1000

    we don't need ctdb_ltdb_persistent_store() any more

commit aab710f1c6bcdfd8ff2992f8adc15933276dc39e
Author: Andrew Tridgell <tridge at samba.org>
Date:   Wed Jul 30 19:57:48 2008 +1000

    added client side functions for new transaction code

commit 9ff3380099fe6f4d39de126db0826971a10ee692
Author: Andrew Tridgell <tridge at samba.org>
Date:   Wed Jul 30 19:57:00 2008 +1000

    added new multi-record transaction commit code

commit d5dcb46e182466e4b51c106f2491178c23babd8d
Author: Andrew Tridgell <tridge at samba.org>
Date:   Wed Jul 30 19:55:54 2008 +1000

    added a new persistent transaction test program

commit 4d205476d286570a6e1f52b59af42858ce051106
Author: Andrew Tridgell <tridge at samba.org>
Date:   Wed Jul 30 14:24:56 2008 +1000

    rename the structure we use for marshalling multiple records

-----------------------------------------------------------------------

Summary of changes:
 Makefile.in                                     |    7 +-
 client/ctdb_client.c                            |  311 +++++++++++++++++++++++
 common/ctdb_ltdb.c                              |   59 -----
 common/ctdb_util.c                              |  100 ++++++++
 config/events.d/10.interface                    |    1 +
 config/events.d/50.samba                        |   96 +++++++-
 config/events.d/61.nfstickle                    |    3 +
 config/functions                                |   35 ++-
 include/ctdb.h                                  |   21 ++
 include/ctdb_private.h                          |   25 ++-
 lib/events/events_signal.c                      |   10 +-
 packaging/RPM/ctdb.spec                         |   22 ++-
 server/ctdb_control.c                           |    9 +
 server/ctdb_daemon.c                            |    2 +-
 server/ctdb_logging.c                           |   39 ++--
 server/ctdb_ltdb_server.c                       |    4 +-
 server/ctdb_persistent.c                        |  218 ++++++++++++----
 server/ctdb_recover.c                           |   22 +-
 server/ctdb_recoverd.c                          |   59 +++--
 tcp/tcp_connect.c                               |    3 -
 tests/ctdb_persistent.c                         |   28 +-
 tests/{ctdb_persistent.c => ctdb_transaction.c} |   50 +++--
 tests/ctdb_traverse.c                           |    2 +-
 tests/fetch.sh                                  |    2 +
 tests/persistent.sh                             |    8 +-
 tests/rb_test.c                                 |   40 ++--
 tests/run_tests.sh                              |    2 +
 tests/transaction.sh                            |   28 ++
 tools/ctdb_vacuum.c                             |   18 +-
 29 files changed, 956 insertions(+), 268 deletions(-)
 copy tests/{ctdb_persistent.c => ctdb_transaction.c} (84%)
 create mode 100755 tests/transaction.sh


Changeset truncated at 500 lines:

diff --git a/Makefile.in b/Makefile.in
index 9b5ebe0..cf1240b 100755
--- a/Makefile.in
+++ b/Makefile.in
@@ -56,7 +56,8 @@ CTDB_SERVER_OBJ = server/ctdbd.o server/ctdb_daemon.o server/ctdb_lockwait.o \
 	server/ctdb_keepalive.o server/ctdb_logging.o server/ctdb_uptime.c \
 	$(CTDB_CLIENT_OBJ) $(CTDB_TCP_OBJ) @INFINIBAND_WRAPPER_OBJ@
 
-TEST_BINS=bin/ctdb_bench bin/ctdb_fetch bin/ctdb_store bin/ctdb_randrec bin/ctdb_persistent bin/ctdb_traverse bin/rb_test \
+TEST_BINS=bin/ctdb_bench bin/ctdb_fetch bin/ctdb_store bin/ctdb_randrec bin/ctdb_persistent \
+	bin/ctdb_traverse bin/rb_test bin/ctdb_transaction \
 	@INFINIBAND_BINS@
 
 BINS = bin/ctdb @CTDB_SCSI_IO@ bin/ctdb_ipmux bin/smnotify
@@ -141,6 +142,10 @@ bin/ctdb_persistent: $(CTDB_CLIENT_OBJ) tests/ctdb_persistent.o
 	@echo Linking $@
 	@$(CC) $(CFLAGS) -o $@ tests/ctdb_persistent.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
 
+bin/ctdb_transaction: $(CTDB_CLIENT_OBJ) tests/ctdb_transaction.o 
+	@echo Linking $@
+	@$(CC) $(CFLAGS) -o $@ tests/ctdb_transaction.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
+
 bin/ibwrapper_test: $(CTDB_CLIENT_OBJ) ib/ibwrapper_test.o
 	@echo Linking $@
 	@$(CC) $(CFLAGS) -o $@ ib/ibwrapper_test.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
diff --git a/client/ctdb_client.c b/client/ctdb_client.c
index 544f5d1..48eb19d 100644
--- a/client/ctdb_client.c
+++ b/client/ctdb_client.c
@@ -1787,6 +1787,11 @@ static void traverse_handler(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA
 		return;
 	}
 
+	if (data.dsize == sizeof(struct ctdb_ltdb_header)) {
+		/* empty records are deleted records in ctdb */
+		return;
+	}
+
 	if (state->fn(ctdb, key, data, state->private_data) != 0) {
 		state->done = True;
 	}
@@ -2948,3 +2953,309 @@ int ctdb_ctrl_getcapabilities(struct ctdb_context *ctdb, struct timeval timeout,
 	talloc_free(tmp_ctx);
 	return ret;
 }
+
+struct ctdb_transaction_handle {
+	struct ctdb_db_context *ctdb_db;
+	bool in_replay;
+	/* we store the reads and writes done under a transaction one
+	   list stores both reads and writes, the other just writes
+	*/
+	struct ctdb_marshall_buffer *m_all;
+	struct ctdb_marshall_buffer *m_write;
+};
+
+/* start a transaction on a database */
+static int ctdb_transaction_destructor(struct ctdb_transaction_handle *h)
+{
+	tdb_transaction_cancel(h->ctdb_db->ltdb->tdb);
+	return 0;
+}
+
+/* start a transaction on a database */
+static int ctdb_transaction_fetch_start(struct ctdb_transaction_handle *h)
+{
+	struct ctdb_record_handle *rh;
+	TDB_DATA key;
+	struct ctdb_ltdb_header header;
+	TALLOC_CTX *tmp_ctx;
+	const char *keyname = CTDB_TRANSACTION_LOCK_KEY;
+	int ret;
+	struct ctdb_db_context *ctdb_db = h->ctdb_db;
+
+	key.dptr = discard_const(keyname);
+	key.dsize = strlen(keyname);
+
+	if (!ctdb_db->persistent) {
+		DEBUG(DEBUG_ERR,(__location__ " Attempted transaction on non-persistent database\n"));
+		return -1;
+	}
+
+again:
+	tmp_ctx = talloc_new(h);
+
+	rh = ctdb_fetch_lock(ctdb_db, tmp_ctx, key, NULL);
+	if (rh == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to fetch_lock database\n"));		
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+	talloc_free(rh);
+
+	ret = tdb_transaction_start(ctdb_db->ltdb->tdb);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to start tdb transaction\n"));
+		talloc_free(tmp_ctx);
+		return -1;
+	}
+
+	ret = ctdb_ltdb_fetch(ctdb_db, key, &header, tmp_ctx, NULL);
+	if (ret != 0 || header.dmaster != ctdb_db->ctdb->pnn) {
+		tdb_transaction_cancel(ctdb_db->ltdb->tdb);
+		talloc_free(tmp_ctx);
+		goto again;
+	}
+
+	talloc_free(tmp_ctx);
+
+	return 0;
+}
+
+
+/* start a transaction on a database */
+struct ctdb_transaction_handle *ctdb_transaction_start(struct ctdb_db_context *ctdb_db,
+						       TALLOC_CTX *mem_ctx)
+{
+	struct ctdb_transaction_handle *h;
+	int ret;
+
+	/* we have a good transaction */
+	h = talloc_zero(mem_ctx, struct ctdb_transaction_handle);
+	if (h == NULL) {
+		DEBUG(DEBUG_ERR,(__location__ " oom for transaction handle\n"));		
+		return NULL;
+	}
+
+	h->ctdb_db = ctdb_db;
+
+	ret = ctdb_transaction_fetch_start(h);
+	if (ret != 0) {
+		talloc_free(h);
+		return NULL;
+	}
+
+	talloc_set_destructor(h, ctdb_transaction_destructor);
+
+	return h;
+}
+
+
+
+/*
+  fetch a record inside a transaction
+ */
+int ctdb_transaction_fetch(struct ctdb_transaction_handle *h, 
+			   TALLOC_CTX *mem_ctx, 
+			   TDB_DATA key, TDB_DATA *data)
+{
+	struct ctdb_ltdb_header header;
+	int ret;
+
+	ZERO_STRUCT(header);
+
+	ret = ctdb_ltdb_fetch(h->ctdb_db, key, &header, mem_ctx, data);
+	if (ret == -1 && header.dmaster == (uint32_t)-1) {
+		/* record doesn't exist yet */
+		*data = tdb_null;
+		ret = 0;
+	}
+	
+	if (ret != 0) {
+		return ret;
+	}
+
+	if (!h->in_replay) {
+		h->m_all = ctdb_marshall_add(h, h->m_all, h->ctdb_db->db_id, 1, key, NULL, *data);
+		if (h->m_all == NULL) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to add to marshalling record\n"));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/*
+  stores a record inside a transaction
+ */
+int ctdb_transaction_store(struct ctdb_transaction_handle *h, 
+			   TDB_DATA key, TDB_DATA data)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(h);
+	struct ctdb_ltdb_header header;
+	int ret;
+
+	ZERO_STRUCT(header);
+
+	/* we need the header so we can update the RSN */
+	ret = ctdb_ltdb_fetch(h->ctdb_db, key, &header, tmp_ctx, NULL);
+	if (ret == -1 && header.dmaster == (uint32_t)-1) {
+		/* the record doesn't exist - create one with us as dmaster.
+		   This is only safe because we are in a transaction and this
+		   is a persistent database */
+		header.dmaster = h->ctdb_db->ctdb->pnn;
+		header.rsn = 0;
+	} else if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to fetch record\n"));
+		talloc_free(tmp_ctx);
+		return ret;
+	}
+
+	header.rsn++;
+
+	if (!h->in_replay) {
+		h->m_all = ctdb_marshall_add(h, h->m_all, h->ctdb_db->db_id, 0, key, NULL, data);
+		if (h->m_all == NULL) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to add to marshalling record\n"));
+			talloc_free(tmp_ctx);
+			return -1;
+		}
+		
+		h->m_write = ctdb_marshall_add(h, h->m_write, h->ctdb_db->db_id, 0, key, &header, data);
+		if (h->m_write == NULL) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to add to marshalling record\n"));
+			talloc_free(tmp_ctx);
+			return -1;
+		}
+	}
+	
+	ret = ctdb_ltdb_store(h->ctdb_db, key, &header, data);
+
+	talloc_free(tmp_ctx);
+	
+	return ret;
+}
+
+/*
+  replay a transaction
+ */
+static int ctdb_replay_transaction(struct ctdb_transaction_handle *h)
+{
+	int ret, i;
+	struct ctdb_rec_data *rec = NULL;
+
+	h->in_replay = true;
+
+	ret = ctdb_transaction_fetch_start(h);
+	if (ret != 0) {
+		return ret;
+	}
+
+	for (i=0;i<h->m_all->count;i++) {
+		TDB_DATA key, data;
+
+		rec = ctdb_marshall_loop_next(h->m_all, rec, NULL, NULL, &key, &data);
+		if (rec == NULL) {
+			DEBUG(DEBUG_ERR, (__location__ " Out of records in ctdb_replay_transaction?\n"));
+			goto failed;
+		}
+
+		if (rec->reqid == 0) {
+			/* its a store */
+			if (ctdb_transaction_store(h, key, data) != 0) {
+				goto failed;
+			}
+		} else {
+			TDB_DATA data2;
+			TALLOC_CTX *tmp_ctx = talloc_new(h);
+
+			if (ctdb_transaction_fetch(h, tmp_ctx, key, &data2) != 0) {
+				talloc_free(tmp_ctx);
+				goto failed;
+			}
+			if (data2.dsize != data.dsize ||
+			    memcmp(data2.dptr, data.dptr, data.dsize) != 0) {
+				/* the record has changed on us - we have to give up */
+				talloc_free(tmp_ctx);
+				goto failed;
+			}
+			talloc_free(tmp_ctx);
+		}
+	}
+	
+	return 0;
+
+failed:
+	tdb_transaction_cancel(h->ctdb_db->ltdb->tdb);
+	return -1;
+}
+
+
+/*
+  commit a transaction
+ */
+int ctdb_transaction_commit(struct ctdb_transaction_handle *h)
+{
+	int ret;
+	int32_t status;
+	struct ctdb_context *ctdb = h->ctdb_db->ctdb;
+	struct timeval timeout;
+
+	talloc_set_destructor(h, NULL);
+
+	if (h->m_write == NULL) {
+		/* no changes were made */
+		talloc_free(h);
+		return 0;
+	}
+
+	/* our commit strategy is quite complex.
+
+	   - we first try to commit the changes to all other nodes
+
+	   - if that works, then we commit locally and we are done
+
+	   - if a commit on another node fails, then we need to cancel
+	     the transaction, then restart the transaction (thus
+	     opening a window of time for a pending recovery to
+	     complete), then replay the transaction, checking all the
+	     reads and writes (checking that reads give the same data,
+	     and writes succeed). Then we retry the transaction to the
+	     other nodes
+	*/
+
+again:
+	/* tell ctdbd to commit to the other nodes */
+	timeout = timeval_current_ofs(1, 0);
+	ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, h->ctdb_db->db_id, 
+			   CTDB_CONTROL_TRANS2_COMMIT, 0, 
+			   ctdb_marshall_finish(h->m_write), NULL, NULL, &status, 
+			   &timeout, NULL);
+	if (ret != 0 || status != 0) {
+		tdb_transaction_cancel(h->ctdb_db->ltdb->tdb);
+		sleep(1);
+		if (ctdb_replay_transaction(h) != 0) {
+			DEBUG(DEBUG_ERR,(__location__ " Failed to replay transaction\n"));
+			talloc_free(h);
+			return -1;
+		}
+		goto again;
+	}
+
+	/* do the real commit locally */
+	ret = tdb_transaction_commit(h->ctdb_db->ltdb->tdb);
+	if (ret != 0) {
+		DEBUG(DEBUG_ERR,(__location__ " Failed to commit transaction\n"));
+		ctdb_control(ctdb, CTDB_CURRENT_NODE, h->ctdb_db->db_id, 
+			     CTDB_CONTROL_TRANS2_ERROR, CTDB_CTRL_FLAG_NOREPLY, 
+			     tdb_null, NULL, NULL, NULL, NULL, NULL);		
+		talloc_free(h);
+		return ret;
+	}
+
+	/* tell ctdbd that we are finished with our local commit */
+	ctdb_control(ctdb, CTDB_CURRENT_NODE, h->ctdb_db->db_id, 
+		     CTDB_CONTROL_TRANS2_FINISHED, CTDB_CTRL_FLAG_NOREPLY, 
+		     tdb_null, NULL, NULL, &status, NULL, NULL);
+	talloc_free(h);
+	return 0;
+}
diff --git a/common/ctdb_ltdb.c b/common/ctdb_ltdb.c
index f360458..12fcf52 100644
--- a/common/ctdb_ltdb.c
+++ b/common/ctdb_ltdb.c
@@ -158,65 +158,6 @@ int ctdb_ltdb_store(struct ctdb_db_context *ctdb_db, TDB_DATA key,
 }
 
 /*
-  write a record to a persistent database
-  this is done by a child process
-*/
-int ctdb_ltdb_persistent_store(struct ctdb_db_context *ctdb_db, TDB_DATA key, 
-		    struct ctdb_ltdb_header *header, TDB_DATA data)
-{
-	struct ctdb_context *ctdb = ctdb_db->ctdb;
-	TDB_DATA rec;
-	int ret;
-
-	if (ctdb->flags & CTDB_FLAG_TORTURE) {
-		struct ctdb_ltdb_header *h2;
-		rec = tdb_fetch(ctdb_db->ltdb->tdb, key);
-		h2 = (struct ctdb_ltdb_header *)rec.dptr;
-		if (rec.dptr && rec.dsize >= sizeof(h2) && h2->rsn > header->rsn) {
-			DEBUG(DEBUG_CRIT,("RSN regression! %llu %llu\n",
-				 (unsigned long long)h2->rsn, (unsigned long long)header->rsn));
-		}
-		if (rec.dptr) free(rec.dptr);
-	}
-
-	rec.dsize = sizeof(*header) + data.dsize;
-	rec.dptr = talloc_size(ctdb, rec.dsize);
-	CTDB_NO_MEMORY(ctdb, rec.dptr);
-
-	memcpy(rec.dptr, header, sizeof(*header));
-	memcpy(rec.dptr + sizeof(*header), data.dptr, data.dsize);
-
-	/* if this is a persistent database without NOSYNC then we
-	   will do this via a transaction */
-	if (!(ctdb_db->client_tdb_flags & TDB_NOSYNC)) {
-		ret = tdb_transaction_start(ctdb_db->ltdb->tdb);
-		if (ret != 0) {
-			DEBUG(DEBUG_ERR, (__location__ " Failed to start local transaction\n"));
-			goto failed;
-		}
-		ret = tdb_store(ctdb_db->ltdb->tdb, key, rec, TDB_REPLACE);
-		if (ret != 0) {
-			DEBUG(DEBUG_ERR, (__location__ " Failed to store persistent data\n"));
-			tdb_transaction_cancel(ctdb_db->ltdb->tdb);
-			goto failed;
-		}
-		ret = tdb_transaction_commit(ctdb_db->ltdb->tdb);
-		if (ret != 0) {
-			DEBUG(DEBUG_ERR, (__location__ " Failed to commit persistent store transaction.\n"));
-			tdb_transaction_cancel(ctdb_db->ltdb->tdb);
-			goto failed;
-		}
-	} else {
-		ret = tdb_store(ctdb_db->ltdb->tdb, key, rec, TDB_REPLACE);
-	}
-
-failed:
-	talloc_free(rec.dptr);
-
-	return ret;
-}
-
-/*
   lock a record in the ltdb, given a key
  */
 int ctdb_ltdb_lock(struct ctdb_db_context *ctdb_db, TDB_DATA key)
diff --git a/common/ctdb_util.c b/common/ctdb_util.c
index 1b0988d..b096a52 100644
--- a/common/ctdb_util.c
+++ b/common/ctdb_util.c
@@ -200,6 +200,106 @@ struct ctdb_rec_data *ctdb_marshall_record(TALLOC_CTX *mem_ctx, uint32_t reqid,
 	return d;
 }
 
+
+/* helper function for marshalling multiple records */
+struct ctdb_marshall_buffer *ctdb_marshall_add(TALLOC_CTX *mem_ctx, 
+					       struct ctdb_marshall_buffer *m,
+					       uint64_t db_id,
+					       uint32_t reqid,
+					       TDB_DATA key,
+					       struct ctdb_ltdb_header *header,
+					       TDB_DATA data)
+{
+	struct ctdb_rec_data *r;
+	size_t m_size, r_size;
+	struct ctdb_marshall_buffer *m2;
+
+	r = ctdb_marshall_record(mem_ctx, reqid, key, header, data);
+	if (r == NULL) {
+		talloc_free(m);
+		return NULL;
+	}
+
+	if (m == NULL) {
+		m = talloc_zero_size(mem_ctx, offsetof(struct ctdb_marshall_buffer, data));
+		if (m == NULL) {
+			return NULL;
+		}
+		m->db_id = db_id;
+	}
+
+	m_size = talloc_get_size(m);
+	r_size = talloc_get_size(r);
+
+	m2 = talloc_realloc_size(mem_ctx, m,  m_size + r_size);
+	if (m2 == NULL) {
+		talloc_free(m);
+		return NULL;
+	}
+
+	memcpy(m_size + (uint8_t *)m2, r, r_size);
+
+	talloc_free(r);
+
+	m2->count++;
+
+	return m2;
+}
+
+/* we've finished marshalling, return a data blob with the marshalled records */
+TDB_DATA ctdb_marshall_finish(struct ctdb_marshall_buffer *m)
+{
+	TDB_DATA data;
+	data.dptr = (uint8_t *)m;
+	data.dsize = talloc_get_size(m);
+	return data;
+}
+
+/* 
+   loop over a marshalling buffer 
+   
+     - pass r==NULL to start
+     - loop the number of times indicated by m->count
+*/
+struct ctdb_rec_data *ctdb_marshall_loop_next(struct ctdb_marshall_buffer *m, struct ctdb_rec_data *r,
+					      uint32_t *reqid,
+					      struct ctdb_ltdb_header *header,
+					      TDB_DATA *key, TDB_DATA *data)
+{
+	if (r == NULL) {
+		r = (struct ctdb_rec_data *)&m->data[0];
+	} else {
+		r = (struct ctdb_rec_data *)(r->length + (uint8_t *)r);
+	}


-- 
CTDB repository


More information about the samba-cvs mailing list