summaryrefslogtreecommitdiff
path: root/source4/lib/ldb/common/ldb.c
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2009-09-03 18:29:58 +1000
committerAndrew Tridgell <tridge@samba.org>2009-09-03 18:36:09 +1000
commitbfccc4590dc94b37258b7225d153c4c01d1a28d6 (patch)
tree901027032373df9aaffc0ee1b3e44c57bd93d46e /source4/lib/ldb/common/ldb.c
parentc37f290043c55ec6428a313b4ec3ca2f91e5e98e (diff)
downloadsamba-bfccc4590dc94b37258b7225d153c4c01d1a28d6.tar.gz
samba-bfccc4590dc94b37258b7225d153c4c01d1a28d6.tar.bz2
samba-bfccc4590dc94b37258b7225d153c4c01d1a28d6.zip
always use prepare_commit in ldb transaction commits if possible
The reason we need this is to make multi-tdb transactions safe, with the partition module. The linked_attributes and repl_meta_data modules now do extra processing when the transaction ends, and that processing can fail. When it fails we need to cancel the transaction, which we can only do if the hook is on the prepare commit instead of the end transaction call. Otherwise the partition module cannot ensure that no commit has been done on another partition.
Diffstat (limited to 'source4/lib/ldb/common/ldb.c')
-rw-r--r--source4/lib/ldb/common/ldb.c37
1 files changed, 33 insertions, 4 deletions
diff --git a/source4/lib/ldb/common/ldb.c b/source4/lib/ldb/common/ldb.c
index 38cc0c880b..dc3032643c 100644
--- a/source4/lib/ldb/common/ldb.c
+++ b/source4/lib/ldb/common/ldb.c
@@ -282,15 +282,20 @@ void ldb_reset_err_string(struct ldb_context *ldb)
}
}
-#define FIRST_OP(ldb, op) do { \
+#define FIRST_OP_NOERR(ldb, op) do { \
module = ldb->modules; \
while (module && module->ops->op == NULL) module = module->next; \
- if (module == NULL) { \
+} while (0)
+
+#define FIRST_OP(ldb, op) do { \
+ FIRST_OP_NOERR(ldb, op); \
+ if (module == NULL) { \
ldb_asprintf_errstring(ldb, "unable to find module or backend to handle operation: " #op); \
return LDB_ERR_OPERATIONS_ERROR; \
} \
} while (0)
+
/*
start a transaction
*/
@@ -337,6 +342,7 @@ int ldb_transaction_commit(struct ldb_context *ldb)
struct ldb_module *module;
int status;
+
ldb->transaction_active--;
ldb_debug(ldb, LDB_DEBUG_TRACE,
@@ -355,10 +361,30 @@ int ldb_transaction_commit(struct ldb_context *ldb)
return LDB_ERR_OPERATIONS_ERROR;
}
- FIRST_OP(ldb, end_transaction);
+ /* 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);
status = module->ops->end_transaction(module);
if (status != LDB_SUCCESS) {
if (ldb->err_string == NULL) {
@@ -368,6 +394,9 @@ int ldb_transaction_commit(struct ldb_context *ldb)
ldb_strerror(status),
status);
}
+ /* cancel the transaction */
+ FIRST_OP(ldb, del_transaction);
+ module->ops->del_transaction(module);
}
return status;
}
@@ -393,7 +422,7 @@ int ldb_transaction_cancel(struct ldb_context *ldb)
if (ldb->transaction_active < 0) {
ldb_debug(ldb, LDB_DEBUG_FATAL,
- "commit called but no ldb transactions are active!");
+ "cancel called but no ldb transactions are active!");
ldb->transaction_active = 0;
return LDB_ERR_OPERATIONS_ERROR;
}