s4-ldb: expose ldb_transaction_prepare_commit() in ldb
authorAndrew Tridgell <tridge@samba.org>
Tue, 15 Sep 2009 21:07:06 +0000 (14:07 -0700)
committerAndrew Tridgell <tridge@samba.org>
Tue, 15 Sep 2009 21:07:06 +0000 (14:07 -0700)
It is useful to be able to control the 2 phase commit from application
code (s4 replication uses it)

source4/lib/ldb/common/ldb.c
source4/lib/ldb/include/ldb.h
source4/lib/ldb/include/ldb_private.h

index 6939cefb59389d0797c2e05f4f21beb1757a71c5..613451a7c2a2cba9ce634f7fc478fe95a52aae7b 100644 (file)
@@ -316,6 +316,7 @@ int ldb_transaction_start(struct ldb_context *ldb)
 
        /* start a new transaction */
        ldb->transaction_active++;
+       ldb->prepare_commit_done = false;
 
        FIRST_OP(ldb, start_transaction);
 
@@ -334,6 +335,57 @@ int ldb_transaction_start(struct ldb_context *ldb)
        return status;
 }
 
+/*
+  prepare for transaction commit (first phase of two phase commit)
+*/
+int ldb_transaction_prepare_commit(struct ldb_context *ldb)
+{
+       struct ldb_module *module;
+       int status;
+
+       if (ldb->prepare_commit_done) {
+               return LDB_SUCCESS;
+       }
+
+       /* commit only when all nested transactions are complete */
+       if (ldb->transaction_active > 1) {
+               return LDB_SUCCESS;
+       }
+
+       ldb->prepare_commit_done = true;
+
+       if (ldb->transaction_active < 0) {
+               ldb_debug(ldb, LDB_DEBUG_FATAL,
+                         "prepare commit called but no ldb transactions are active!");
+               ldb->transaction_active = 0;
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       /* call prepare transaction if available */
+       FIRST_OP_NOERR(ldb, prepare_commit);
+       if (module == NULL) {
+               return LDB_SUCCESS;
+       }
+
+       status = module->ops->prepare_commit(module);
+       if (status != LDB_SUCCESS) {
+               /* if a module fails the prepare then we need
+                  to call the end transaction for everyone */
+               FIRST_OP(ldb, end_transaction);
+               module->ops->end_transaction(module);
+               if (ldb->err_string == NULL) {
+                       /* no error string was setup by the backend */
+                       ldb_asprintf_errstring(ldb,
+                                              "ldb transaction prepare commit: %s (%d)",
+                                              ldb_strerror(status),
+                                              status);
+               }
+       }
+
+       return status;
+}
+
+
 /*
   commit a transaction
 */
@@ -342,6 +394,10 @@ int ldb_transaction_commit(struct ldb_context *ldb)
        struct ldb_module *module;
        int status;
 
+       status = ldb_transaction_prepare_commit(ldb);
+       if (status != LDB_SUCCESS) {
+               return status;
+       }
 
        ldb->transaction_active--;
 
@@ -361,27 +417,6 @@ int ldb_transaction_commit(struct ldb_context *ldb)
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       /* call prepare transaction if available */
-       FIRST_OP_NOERR(ldb, prepare_commit);
-       if (module != NULL) {
-               status = module->ops->prepare_commit(module);
-               if (status != LDB_SUCCESS) {
-                       /* if a module fails the prepare then we need
-                          to call the end transaction for everyone */
-                       /* preserve err string */
-                       FIRST_OP(ldb, end_transaction);
-                       module->ops->end_transaction(module);
-                       if (ldb->err_string == NULL) {
-                               /* no error string was setup by the backend */
-                               ldb_asprintf_errstring(ldb,
-                                                      "ldb transaction prepare commit: %s (%d)",
-                                                      ldb_strerror(status),
-                                                      status);
-                       }
-                       return status;
-               }
-       }
-
        ldb_reset_err_string(ldb);
 
        FIRST_OP(ldb, end_transaction);
@@ -401,6 +436,7 @@ int ldb_transaction_commit(struct ldb_context *ldb)
        return status;
 }
 
+
 /*
   cancel a transaction
 */
index 04b0a22fc1fbe73ed054cf27ffd08a8546f3e58b..2c890319192bf9cb633172557cf46cc5cd2fbd1e 100644 (file)
@@ -1283,6 +1283,11 @@ int ldb_sequence_number(struct ldb_context *ldb, enum ldb_sequence_type type, ui
 */
 int ldb_transaction_start(struct ldb_context *ldb);
 
+/**
+   first phase of two phase commit
+ */
+int ldb_transaction_prepare_commit(struct ldb_context *ldb);
+
 /**
   commit a transaction
 */
index c12f33495bfef97a04eec723ad38d4087b5be00b..1fb3109b1bd7457ae804fe45ad678b78fee32f67 100644 (file)
@@ -114,6 +114,8 @@ struct ldb_context {
        char *modules_dir;
 
        struct tevent_context *ev_ctx;
+
+       bool prepare_commit_done;
 };
 
 /* The following definitions come from lib/ldb/common/ldb.c  */