summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/tdb/common/transaction.c8
-rw-r--r--source4/dsdb/repl/drepl_out_helpers.c3
-rw-r--r--source4/dsdb/repl/replicated_objects.c35
-rw-r--r--source4/lib/ldb/common/ldb.c78
-rw-r--r--source4/lib/ldb/common/ldb_parse.c3
-rw-r--r--source4/lib/ldb/include/ldb.h5
-rw-r--r--source4/lib/ldb/include/ldb_private.h2
7 files changed, 102 insertions, 32 deletions
diff --git a/lib/tdb/common/transaction.c b/lib/tdb/common/transaction.c
index e97fe67b4e..67a035879c 100644
--- a/lib/tdb/common/transaction.c
+++ b/lib/tdb/common/transaction.c
@@ -137,14 +137,6 @@ static int transaction_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
{
uint32_t blk;
- /* Only a commit is allowed on a prepared transaction */
- if (tdb->transaction->prepared) {
- tdb->ecode = TDB_ERR_EINVAL;
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_read: transaction already prepared, read not allowed\n"));
- tdb->transaction->transaction_error = 1;
- return -1;
- }
-
/* break it down into block sized ops */
while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
diff --git a/source4/dsdb/repl/drepl_out_helpers.c b/source4/dsdb/repl/drepl_out_helpers.c
index 168aacdde9..5c63c111f3 100644
--- a/source4/dsdb/repl/drepl_out_helpers.c
+++ b/source4/dsdb/repl/drepl_out_helpers.c
@@ -414,7 +414,8 @@ static void dreplsrv_op_pull_source_apply_changes_send(struct dreplsrv_op_pull_s
&rf1,
uptodateness_vector,
&drsuapi->gensec_skey,
- st, NULL);
+ st, NULL,
+ &st->op->source_dsa->notify_uSN);
if (!W_ERROR_IS_OK(status)) {
DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
composite_error(c, werror_to_ntstatus(status));
diff --git a/source4/dsdb/repl/replicated_objects.c b/source4/dsdb/repl/replicated_objects.c
index 2f4efc0fee..5ae622eeaa 100644
--- a/source4/dsdb/repl/replicated_objects.c
+++ b/source4/dsdb/repl/replicated_objects.c
@@ -212,7 +212,8 @@ WERROR dsdb_extended_replicated_objects_commit(struct ldb_context *ldb,
const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector,
const DATA_BLOB *gensec_skey,
TALLOC_CTX *mem_ctx,
- struct dsdb_extended_replicated_objects **_out)
+ struct dsdb_extended_replicated_objects **_out,
+ uint64_t *notify_uSN)
{
WERROR status;
const struct dsdb_schema *schema;
@@ -221,6 +222,7 @@ WERROR dsdb_extended_replicated_objects_commit(struct ldb_context *ldb,
const struct drsuapi_DsReplicaObjectListItemEx *cur;
uint32_t i;
int ret;
+ uint64_t seq_num1, seq_num2;
schema = dsdb_get_schema(ldb);
if (!schema) {
@@ -280,6 +282,14 @@ WERROR dsdb_extended_replicated_objects_commit(struct ldb_context *ldb,
return WERR_FOOBAR;
}
+ ret = dsdb_load_partition_usn(ldb, out->partition_dn, &seq_num1);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,(__location__ " Failed to load partition uSN\n"));
+ talloc_free(out);
+ ldb_transaction_cancel(ldb);
+ return WERR_FOOBAR;
+ }
+
ret = ldb_extended(ldb, DSDB_EXTENDED_REPLICATED_OBJECTS_OID, out, &ext_res);
if (ret != LDB_SUCCESS) {
DEBUG(0,("Failed to apply records: %s: %s\n",
@@ -290,6 +300,28 @@ WERROR dsdb_extended_replicated_objects_commit(struct ldb_context *ldb,
}
talloc_free(ext_res);
+ ret = ldb_transaction_prepare_commit(ldb);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,(__location__ " Failed to prepare commit of transaction\n"));
+ talloc_free(out);
+ return WERR_FOOBAR;
+ }
+
+ ret = dsdb_load_partition_usn(ldb, out->partition_dn, &seq_num2);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,(__location__ " Failed to load partition uSN\n"));
+ talloc_free(out);
+ ldb_transaction_cancel(ldb);
+ return WERR_FOOBAR;
+ }
+
+ /* if this replication partner didn't need to be notified
+ before this transaction then it still doesn't need to be
+ notified, as the changes came from this server */
+ if (seq_num2 > seq_num1 && seq_num1 <= *notify_uSN) {
+ *notify_uSN = seq_num2;
+ }
+
ret = ldb_transaction_commit(ldb);
if (ret != LDB_SUCCESS) {
DEBUG(0,(__location__ " Failed to commit transaction\n"));
@@ -297,6 +329,7 @@ WERROR dsdb_extended_replicated_objects_commit(struct ldb_context *ldb,
return WERR_FOOBAR;
}
+
DEBUG(2,("Replicated %u objects (%u linked attributes) for %s\n",
out->num_objects, out->linked_attributes_count,
ldb_dn_get_linearized(out->partition_dn)));
diff --git a/source4/lib/ldb/common/ldb.c b/source4/lib/ldb/common/ldb.c
index 6939cefb59..613451a7c2 100644
--- a/source4/lib/ldb/common/ldb.c
+++ b/source4/lib/ldb/common/ldb.c
@@ -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);
@@ -335,6 +336,57 @@ int ldb_transaction_start(struct ldb_context *ldb)
}
/*
+ 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
*/
int ldb_transaction_commit(struct ldb_context *ldb)
@@ -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
*/
diff --git a/source4/lib/ldb/common/ldb_parse.c b/source4/lib/ldb/common/ldb_parse.c
index 654a635abf..0fab0026f3 100644
--- a/source4/lib/ldb/common/ldb_parse.c
+++ b/source4/lib/ldb/common/ldb_parse.c
@@ -267,7 +267,8 @@ static enum ldb_parse_op ldb_parse_filtertype(void *mem_ctx, char **type, char *
p++;
}
- while ((isascii(*p) && isalnum((unsigned char)*p)) || (*p == '-')) { /* attribute names can only be alphanums */
+ while ((isascii(*p) && isalnum((unsigned char)*p)) || (*p == '-') || (*p == '.')) {
+ /* attribute names can only be alphanums */
p++;
}
diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h
index 04b0a22fc1..2c89031919 100644
--- a/source4/lib/ldb/include/ldb.h
+++ b/source4/lib/ldb/include/ldb.h
@@ -1284,6 +1284,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
*/
int ldb_transaction_commit(struct ldb_context *ldb);
diff --git a/source4/lib/ldb/include/ldb_private.h b/source4/lib/ldb/include/ldb_private.h
index c12f33495b..1fb3109b1b 100644
--- a/source4/lib/ldb/include/ldb_private.h
+++ b/source4/lib/ldb/include/ldb_private.h
@@ -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 */