diff options
-rw-r--r-- | lib/tdb/common/transaction.c | 8 | ||||
-rw-r--r-- | source4/dsdb/repl/drepl_out_helpers.c | 3 | ||||
-rw-r--r-- | source4/dsdb/repl/replicated_objects.c | 35 | ||||
-rw-r--r-- | source4/lib/ldb/common/ldb.c | 78 | ||||
-rw-r--r-- | source4/lib/ldb/common/ldb_parse.c | 3 | ||||
-rw-r--r-- | source4/lib/ldb/include/ldb.h | 5 | ||||
-rw-r--r-- | source4/lib/ldb/include/ldb_private.h | 2 |
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 */ |