Try to use tdb transactions when updating a record and record header inside the ctdb...
authorRonnie Sahlberg <ronniesahlberg@gmail.com>
Mon, 12 May 2008 03:37:31 +0000 (13:37 +1000)
committerRonnie Sahlberg <ronniesahlberg@gmail.com>
Mon, 12 May 2008 03:37:31 +0000 (13:37 +1000)
If a transaction could be started, do safe transaction store when updating the record inside the daemon.
If the transaction could not be started (maybe another samba process has a lock on the database?) then just do a normal store instead (instead of blocking the ctdb daemon).

The client can "signal" ctdb that updates to this database should, if possible, be done using safe transactions by specifying the TDB_NOSYNC flag when attaching to the database.
The TDB flags are passed to ctdb in the "srvid" field of the control header when attaching using the CTDB_CONTROL_DB_ATTACH_PERSISTENT.

Currently, samba3.2 does not yet tell ctdbd to handle any persistent databases using safe transactions.

If samba3.2 wants a particular persistent database to be handled using
safe transactions inside the ctdbd daemon, it should pass
TDB_NOSYNC as the flags to the call to attach to a persistent database
in ctdbd_db_attach()     it currently specifies 0 as the srvid

common/ctdb_ltdb.c
include/ctdb_private.h
server/ctdb_control.c
server/ctdb_ltdb_server.c

index e8a334afecafad5a591fe91b5d5962041ad94235..a3df65ebd486b827dfe97dab4ec0409a0f9f1780 100644 (file)
@@ -150,7 +150,31 @@ int ctdb_ltdb_store(struct ctdb_db_context *ctdb_db, TDB_DATA key,
        memcpy(rec.dptr, header, sizeof(*header));
        memcpy(rec.dptr + sizeof(*header), data.dptr, data.dsize);
 
-       ret = tdb_store(ctdb_db->ltdb->tdb, key, rec, TDB_REPLACE);
+       /* if this is a persistent database without NOSYNC then we
+          will do this via a transaction */
+       if (ctdb_db->persistent && !(ctdb_db->client_tdb_flags & TDB_NOSYNC)) {
+               bool transaction_started = true;
+
+               ret = tdb_transaction_start(ctdb_db->ltdb->tdb);
+               if (ret != 0) {
+                       transaction_started = false;
+                       DEBUG(DEBUG_NOTICE, ("Failed to start local transaction\n"));
+               }
+               ret = tdb_store(ctdb_db->ltdb->tdb, key, rec, TDB_REPLACE);
+               if (ret != 0) {
+                       if (transaction_started) {
+                               tdb_transaction_cancel(ctdb_db->ltdb->tdb);
+                       }
+                       goto failed;
+               }
+               if (transaction_started) {
+                       ret = tdb_transaction_commit(ctdb_db->ltdb->tdb);
+               }
+       } else {
+               ret = tdb_store(ctdb_db->ltdb->tdb, key, rec, TDB_REPLACE);
+       }
+
+failed:
        talloc_free(rec.dptr);
 
        return ret;
index d31b148fcaaa91a63efb582f5aad3c2b320d53d3..bc8bde3b4527d292f94988d54b7999b09913a99d 100644 (file)
@@ -410,6 +410,7 @@ struct ctdb_db_context {
        struct ctdb_registered_call *calls; /* list of registered calls */
        uint32_t seqnum;
        struct timed_event *te;
+       uint32_t client_tdb_flags;
 };
 
 
@@ -921,7 +922,7 @@ int ctdb_daemon_send_control(struct ctdb_context *ctdb, uint32_t destnode,
                             void *private_data);
 
 int32_t ctdb_control_db_attach(struct ctdb_context *ctdb, TDB_DATA indata, 
-                              TDB_DATA *outdata, bool persistent);
+                              TDB_DATA *outdata, uint64_t tdb_flags, bool persistent);
 
 int ctdb_daemon_set_call(struct ctdb_context *ctdb, uint32_t db_id,
                         ctdb_fn_t fn, int id);
index 6a2a9ce6c94dd7d662c9f179617d283e7ac31ef0..7d554132c9cb7c3b638f760771e42cfcddfbce05 100644 (file)
@@ -206,10 +206,10 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
        }
 
        case CTDB_CONTROL_DB_ATTACH:
-               return ctdb_control_db_attach(ctdb, indata, outdata, false);
+               return ctdb_control_db_attach(ctdb, indata, outdata, srvid, false);
 
        case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
-               return ctdb_control_db_attach(ctdb, indata, outdata, true);
+               return ctdb_control_db_attach(ctdb, indata, outdata, srvid, true);
 
        case CTDB_CONTROL_SET_CALL: {
                struct ctdb_control_set_call *sc = 
index e900f7b9ca8c80b839e4498263864e62569b191f..5146ed86dae60bef1b20ebd56e63e01e917752da 100644 (file)
@@ -296,12 +296,19 @@ static int ctdb_local_attach(struct ctdb_context *ctdb, const char *db_name, boo
   a client has asked to attach a new database
  */
 int32_t ctdb_control_db_attach(struct ctdb_context *ctdb, TDB_DATA indata,
-                              TDB_DATA *outdata, bool persistent)
+                              TDB_DATA *outdata, uint64_t tdb_flags, 
+                              bool persistent)
 {
        const char *db_name = (const char *)indata.dptr;
        struct ctdb_db_context *db;
        struct ctdb_node *node = ctdb->nodes[ctdb->pnn];
 
+       /* the client can optionally pass additional tdb flags, but we
+          only allow a subset of those on the database in ctdb. Note
+          that tdb_flags is passed in via the (otherwise unused)
+          srvid to the attach control */
+       tdb_flags &= TDB_NOSYNC;
+
        /* If the node is inactive it is not part of the cluster
           and we should not allow clients to attach to any
           databases
@@ -317,6 +324,7 @@ int32_t ctdb_control_db_attach(struct ctdb_context *ctdb, TDB_DATA indata,
        if (db) {
                outdata->dptr  = (uint8_t *)&db->db_id;
                outdata->dsize = sizeof(db->db_id);
+               db->client_tdb_flags |= tdb_flags;
                return 0;
        }
 
@@ -330,6 +338,9 @@ int32_t ctdb_control_db_attach(struct ctdb_context *ctdb, TDB_DATA indata,
                return -1;
        }
 
+       /* remember the flags the client has specified */
+       db->client_tdb_flags = tdb_flags;
+
        outdata->dptr  = (uint8_t *)&db->db_id;
        outdata->dsize = sizeof(db->db_id);