From 80c4b1e43e67249996cea61cc761911ff9fecbde Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 15 Sep 2009 14:06:07 -0700 Subject: s4-repl: don't do double replication When we replicate from a remote DC, we need to note the new uSN that the local changes have resulted in, and modify the uSN that the notify task uses to determine if it should send a ReplicaSync message back to the remote DC. Otherwise we end up always triggering a ReplicaSync every time we replicate from another DC --- source4/dsdb/repl/drepl_out_helpers.c | 3 ++- source4/dsdb/repl/replicated_objects.c | 35 +++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) (limited to 'source4') 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))); -- cgit From a99e216a47259ca2c2837b1ea95c995c5e5a4968 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 15 Sep 2009 14:07:06 -0700 Subject: s4-ldb: expose ldb_transaction_prepare_commit() in ldb 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 | 78 +++++++++++++++++++++++++---------- source4/lib/ldb/include/ldb.h | 5 +++ source4/lib/ldb/include/ldb_private.h | 2 + 3 files changed, 64 insertions(+), 21 deletions(-) (limited to 'source4') 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); @@ -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 */ 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 @@ -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 */ 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 */ -- cgit From f2b5b5bb17910c8a2b709fd62e214c96da3fdd2d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 15 Sep 2009 14:07:43 -0700 Subject: s4-ldb: ldap attribute names can contain a '.' When they are of the form of OIDs --- source4/lib/ldb/common/ldb_parse.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4') 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++; } -- cgit