[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Fri Jun 21 05:46:03 UTC 2019


The branch, master has been updated
       via  feb96ee8e55 lib ldb key value: use TALLOC_FREE() per README.Coding
       via  b6b5b5fe355 lib ldb key value: fix index buffering
       via  1a52b03b2f4 lib ldb key value: Remove check_parent from ldb_kv_index_idxptr()
       via  201684e59fd lib ldb ldb_key_value tests: Add tests for wrapped operations
       via  565341baf53 lib ldb key value: add nested transaction support.
       via  d7dc4fde408 lib ldb key value backends: Add nested txn support
       via  d73bbf0b73f lib ldb tests: remove deprecation warning from api.py
       via  c3aed689896 lib ldb tests: Test nested transactions
      from  e121c14405f provision: Suggest "minimal-responses yes;" by default

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit feb96ee8e558797d68ad0af669eb9010c0487b9f
Author: Gary Lockyer <gary at catalyst.net.nz>
Date:   Fri Jun 21 14:32:08 2019 +1200

    lib ldb key value: use TALLOC_FREE() per README.Coding
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Fri Jun 21 05:45:02 UTC 2019 on sn-devel-184

commit b6b5b5fe355fee2a4096e9214831cb88c7a2a4c6
Author: Gary Lockyer <gary at catalyst.net.nz>
Date:   Wed Mar 6 15:28:45 2019 +1300

    lib ldb key value: fix index buffering
    
    As a performance enhancement the key value layer maintains a cache of
    the index records, which is written to disk as part of a prepare commit.
    This patch adds an extra cache at the operation layer to ensure that the
    cached indexes remain consistent in the event of an operation failing.
    
    Add test to test for index corruption in a failed modify.
    
    Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Pair-Programmed-With: Andrew Bartlett <abartlet at samba.org>
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>

commit 1a52b03b2f4c1503b52784f1a01f8291b78e7604
Author: Gary Lockyer <gary at catalyst.net.nz>
Date:   Fri Jun 21 14:52:24 2019 +1200

    lib ldb key value: Remove check_parent from ldb_kv_index_idxptr()
    
    The callers will soon have two possible parents for this pointer, so
    we need to remove this check, which was added out of caution given
    the rather strange pattern of putting an active memory pointer into a
    TDB (as a hash map).
    
    That is, the only callers that did call this with "true" would
    have to call this with "false", so just remove the complexity.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 201684e59fd417ca913cb1d2d099e91b57dace6c
Author: Gary Lockyer <gary at catalyst.net.nz>
Date:   Tue Mar 26 12:42:32 2019 +1300

    lib ldb ldb_key_value tests: Add tests for wrapped operations
    
    Add test exercising the sub/nested transactions wrapping the key value
    operations.
    
    Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 565341baf537c9b3145a882d6a23ad4f155c0036
Author: Gary Lockyer <gary at catalyst.net.nz>
Date:   Thu Mar 7 10:37:18 2019 +1300

    lib ldb key value: add nested transaction support.
    
    Use the nested transaction support added to the key value back ends to
    make key value operations atomic. This will ensure that rename
    operation failures, which delete the original record and add a new
    record, leave the database in a consistent state.
    
    Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit d7dc4fde4080513e2a62fabbdeee546bd74b9a0d
Author: Gary Lockyer <gary at catalyst.net.nz>
Date:   Thu Mar 7 10:18:00 2019 +1300

    lib ldb key value backends: Add nested txn support
    
    Add limited nested transaction support to the back ends to make the key value
    operations atomic (for those back ends that support nested transactions).
    
    Note: that only the lmdb backend currently supports nested transactions.
    
    Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit d73bbf0b73fcfb99880715df9e314ae5482d6828
Author: Gary Lockyer <gary at catalyst.net.nz>
Date:   Wed Mar 6 15:45:54 2019 +1300

    lib ldb tests: remove deprecation warning from api.py
    
    Remove the "DeprecationWarning: Please use assertEqual instead."
    warnings from api.py
    
    Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit c3aed68989662358ba493c1e89968a0eff15b442
Author: Gary Lockyer <gary at catalyst.net.nz>
Date:   Wed Mar 6 15:32:08 2019 +1300

    lib ldb tests: Test nested transactions
    
    Add a test to document that ldb does not currently support nested
    transactions.
    
    Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 lib/ldb/ldb_key_value/ldb_kv.c                     | 203 ++++-
 lib/ldb/ldb_key_value/ldb_kv.h                     |  18 +
 lib/ldb/ldb_key_value/ldb_kv_index.c               | 378 +++++++--
 lib/ldb/ldb_mdb/ldb_mdb.c                          |  33 +
 lib/ldb/ldb_tdb/ldb_tdb.c                          |  33 +
 .../tests/ldb_key_value_sub_txn_mdb_test.valgrind  |  97 +++
 lib/ldb/tests/ldb_key_value_sub_txn_test.c         | 843 +++++++++++++++++++++
 lib/ldb/tests/ldb_kv_ops_test.c                    |   8 +-
 lib/ldb/tests/ldb_kv_ops_test.valgrind             |  97 +++
 lib/ldb/tests/python/api.py                        | 205 ++++-
 lib/ldb/wscript                                    |  36 +-
 11 files changed, 1878 insertions(+), 73 deletions(-)
 create mode 100644 lib/ldb/tests/ldb_key_value_sub_txn_mdb_test.valgrind
 create mode 100644 lib/ldb/tests/ldb_key_value_sub_txn_test.c
 create mode 100644 lib/ldb/tests/ldb_kv_ops_test.valgrind


Changeset truncated at 500 lines:

diff --git a/lib/ldb/ldb_key_value/ldb_kv.c b/lib/ldb/ldb_key_value/ldb_kv.c
index 260087fbfc4..56316eb8975 100644
--- a/lib/ldb/ldb_key_value/ldb_kv.c
+++ b/lib/ldb/ldb_key_value/ldb_kv.c
@@ -469,6 +469,59 @@ static bool ldb_kv_single_valued(const struct ldb_schema_attribute *a,
 	return false;
 }
 
+/*
+ * Starts a sub transaction if they are supported by the backend
+ */
+static int ldb_kv_sub_transaction_start(struct ldb_kv_private *ldb_kv)
+{
+	int ret = LDB_SUCCESS;
+
+	ret = ldb_kv->kv_ops->begin_nested_write(ldb_kv);
+	if (ret == LDB_SUCCESS) {
+		ret = ldb_kv_index_sub_transaction_start(ldb_kv);
+	}
+	return ret;
+}
+
+/*
+ * Commits a sub transaction if they are supported by the backend
+ */
+static int ldb_kv_sub_transaction_commit(struct ldb_kv_private *ldb_kv)
+{
+	int ret = LDB_SUCCESS;
+
+	ret = ldb_kv_index_sub_transaction_commit(ldb_kv);
+	if (ret != LDB_SUCCESS) {
+		return ret;
+	}
+	ret = ldb_kv->kv_ops->finish_nested_write(ldb_kv);
+	return ret;
+}
+
+/*
+ * Cancels a sub transaction if they are supported by the backend
+ */
+static int ldb_kv_sub_transaction_cancel(struct ldb_kv_private *ldb_kv)
+{
+	int ret = LDB_SUCCESS;
+
+	ret = ldb_kv_index_sub_transaction_cancel(ldb_kv);
+	if (ret != LDB_SUCCESS) {
+		struct ldb_context *ldb = ldb_module_get_ctx(ldb_kv->module);
+		/*
+		 * In the event of a failure we log the failure and continue
+		 * as we need to cancel the database transaction.
+		 */
+		ldb_debug(ldb,
+			  LDB_DEBUG_ERROR,
+			  __location__": ldb_kv_index_sub_transaction_cancel "
+			  "failed: %s",
+			  ldb_errstring(ldb));
+	}
+	ret = ldb_kv->kv_ops->abort_nested_write(ldb_kv);
+	return ret;
+}
+
 static int ldb_kv_add_internal(struct ldb_module *module,
 			       struct ldb_kv_private *ldb_kv,
 			       const struct ldb_message *msg,
@@ -580,6 +633,15 @@ static int ldb_kv_add_internal(struct ldb_module *module,
 
 	ret = ldb_kv_modified(module, msg->dn);
 
+	/*
+	 * To allow testing of the error recovery code in ldb_kv_add
+	 * cmocka tests can define CMOCKA_UNIT_TEST_ADD_INTERNAL_FAIL
+	 * to inject failures at this point.
+	 */
+#ifdef CMOCKA_UNIT_TEST_ADD_INTERNAL_FAIL
+	CMOCKA_UNIT_TEST_ADD_INTERNAL_FAIL
+#endif
+
 	return ret;
 }
 
@@ -615,7 +677,23 @@ static int ldb_kv_add(struct ldb_kv_context *ctx)
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
+	ret = ldb_kv_sub_transaction_start(ldb_kv);
+	if (ret != LDB_SUCCESS) {
+		return ret;
+	}
 	ret = ldb_kv_add_internal(module, ldb_kv, req->op.add.message, true);
+	if (ret != LDB_SUCCESS) {
+		int r = ldb_kv_sub_transaction_cancel(ldb_kv);
+		if (r != LDB_SUCCESS) {
+			ldb_debug(
+				ldb_module_get_ctx(module),
+				LDB_DEBUG_FATAL,
+				__location__
+				": Unable to roll back sub transaction");
+		}
+		return ret;
+	}
+	ret = ldb_kv_sub_transaction_commit(ldb_kv);
 
 	return ret;
 }
@@ -695,6 +773,14 @@ static int ldb_kv_delete_internal(struct ldb_module *module, struct ldb_dn *dn)
 
 done:
 	talloc_free(msg);
+	/*
+	 * To allow testing of the error recovery code in ldb_kv_delete
+	 * cmocka tests can define CMOCKA_UNIT_TEST_DELETE_INTERNAL_FAIL
+	 * to inject failures at this point.
+	 */
+#ifdef CMOCKA_UNIT_TEST_DELETE_INTERNAL_FAIL
+	CMOCKA_UNIT_TEST_DELETE_INTERNAL_FAIL
+#endif
 	return ret;
 }
 
@@ -705,6 +791,9 @@ static int ldb_kv_delete(struct ldb_kv_context *ctx)
 {
 	struct ldb_module *module = ctx->module;
 	struct ldb_request *req = ctx->req;
+	void *data = ldb_module_get_private(module);
+	struct ldb_kv_private *ldb_kv =
+	    talloc_get_type(data, struct ldb_kv_private);
 	int ret = LDB_SUCCESS;
 
 	ldb_request_set_state(req, LDB_ASYNC_PENDING);
@@ -713,7 +802,23 @@ static int ldb_kv_delete(struct ldb_kv_context *ctx)
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
+	ret = ldb_kv_sub_transaction_start(ldb_kv);
+	if (ret != LDB_SUCCESS) {
+		return ret;
+	}
 	ret = ldb_kv_delete_internal(module, req->op.del.dn);
+	if (ret != LDB_SUCCESS) {
+		int r = ldb_kv_sub_transaction_cancel(ldb_kv);
+		if (r != LDB_SUCCESS) {
+			ldb_debug(
+				ldb_module_get_ctx(module),
+				LDB_DEBUG_FATAL,
+				__location__
+				": Unable to roll back sub transaction");
+		}
+		return ret;
+	}
+	ret = ldb_kv_sub_transaction_commit(ldb_kv);
 
 	return ret;
 }
@@ -1227,6 +1332,14 @@ int ldb_kv_modify_internal(struct ldb_module *module,
 
 done:
 	TALLOC_FREE(mem_ctx);
+	/*
+	 * To allow testing of the error recovery code in ldb_kv_modify
+	 * cmocka tests can define CMOCKA_UNIT_TEST_MODIFY_INTERNAL_FAIL
+	 * to inject failures at this point.
+	 */
+#ifdef CMOCKA_UNIT_TEST_MODIFY_INTERNAL_FAIL
+	CMOCKA_UNIT_TEST_MODIFY_INTERNAL_FAIL
+#endif
 	return ret;
 }
 
@@ -1237,6 +1350,9 @@ static int ldb_kv_modify(struct ldb_kv_context *ctx)
 {
 	struct ldb_module *module = ctx->module;
 	struct ldb_request *req = ctx->req;
+	void *data = ldb_module_get_private(module);
+	struct ldb_kv_private *ldb_kv =
+	    talloc_get_type(data, struct ldb_kv_private);
 	int ret = LDB_SUCCESS;
 
 	ret = ldb_kv_check_special_dn(module, req->op.mod.message);
@@ -1250,11 +1366,68 @@ static int ldb_kv_modify(struct ldb_kv_context *ctx)
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
+	ret = ldb_kv_sub_transaction_start(ldb_kv);
+	if (ret != LDB_SUCCESS) {
+		return ret;
+	}
 	ret = ldb_kv_modify_internal(module, req->op.mod.message, req);
+	if (ret != LDB_SUCCESS) {
+		int r = ldb_kv_sub_transaction_cancel(ldb_kv);
+		if (r != LDB_SUCCESS) {
+			ldb_debug(
+				ldb_module_get_ctx(module),
+				LDB_DEBUG_FATAL,
+				__location__
+				": Unable to roll back sub transaction");
+		}
+		return ret;
+	}
+	ret = ldb_kv_sub_transaction_commit(ldb_kv);
+
 
 	return ret;
 }
 
+static int ldb_kv_rename_internal(struct ldb_module *module,
+			   struct ldb_request *req,
+			   struct ldb_message *msg)
+{
+	void *data = ldb_module_get_private(module);
+	struct ldb_kv_private *ldb_kv =
+	    talloc_get_type(data, struct ldb_kv_private);
+	int ret = LDB_SUCCESS;
+
+	/* Always delete first then add, to avoid conflicts with
+	 * unique indexes. We rely on the transaction to make this
+	 * atomic
+	 */
+	ret = ldb_kv_delete_internal(module, msg->dn);
+	if (ret != LDB_SUCCESS) {
+		return ret;
+	}
+
+	msg->dn = ldb_dn_copy(msg, req->op.rename.newdn);
+	if (msg->dn == NULL) {
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+
+	/* We don't check single value as we can have more than 1 with
+	 * deleted attributes. We could go through all elements but that's
+	 * maybe not the most efficient way
+	 */
+	ret = ldb_kv_add_internal(module, ldb_kv, msg, false);
+
+	/*
+	 * To allow testing of the error recovery code in ldb_kv_rename
+	 * cmocka tests can define CMOCKA_UNIT_TEST_RENAME_INTERNAL_FAIL
+	 * to inject failures at this point.
+	 */
+#ifdef CMOCKA_UNIT_TEST_RENAME_INTERNAL_FAIL
+	CMOCKA_UNIT_TEST_RENAME_INTERNAL_FAIL
+#endif
+	return ret;
+}
+
 /*
   rename a record
 */
@@ -1355,28 +1528,26 @@ static int ldb_kv_rename(struct ldb_kv_context *ctx)
 	talloc_free(key_old.data);
 	talloc_free(key.data);
 
-	/* Always delete first then add, to avoid conflicts with
-	 * unique indexes. We rely on the transaction to make this
-	 * atomic
-	 */
-	ret = ldb_kv_delete_internal(module, msg->dn);
+
+	ret = ldb_kv_sub_transaction_start(ldb_kv);
 	if (ret != LDB_SUCCESS) {
 		talloc_free(msg);
 		return ret;
 	}
-
-	msg->dn = ldb_dn_copy(msg, req->op.rename.newdn);
-	if (msg->dn == NULL) {
+	ret = ldb_kv_rename_internal(module, req, msg);
+	if (ret != LDB_SUCCESS) {
+		int r = ldb_kv_sub_transaction_cancel(ldb_kv);
+		if (r != LDB_SUCCESS) {
+			ldb_debug(
+				ldb_module_get_ctx(module),
+				LDB_DEBUG_FATAL,
+				__location__
+				": Unable to roll back sub transaction");
+		}
 		talloc_free(msg);
-		return LDB_ERR_OPERATIONS_ERROR;
+		return ret;
 	}
-
-	/* We don't check single value as we can have more than 1 with
-	 * deleted attributes. We could go through all elements but that's
-	 * maybe not the most efficient way
-	 */
-	ret = ldb_kv_add_internal(module, ldb_kv, msg, false);
-
+	ret = ldb_kv_sub_transaction_commit(ldb_kv);
 	talloc_free(msg);
 
 	return ret;
diff --git a/lib/ldb/ldb_key_value/ldb_kv.h b/lib/ldb/ldb_key_value/ldb_kv.h
index 3de29039a98..7ebda13692e 100644
--- a/lib/ldb/ldb_key_value/ldb_kv.h
+++ b/lib/ldb/ldb_key_value/ldb_kv.h
@@ -51,6 +51,9 @@ struct kv_db_ops {
 	bool (*has_changed)(struct ldb_kv_private *ldb_kv);
 	bool (*transaction_active)(struct ldb_kv_private *ldb_kv);
 	size_t (*get_size)(struct ldb_kv_private *ldb_kv);
+	int (*begin_nested_write)(struct ldb_kv_private *);
+	int (*finish_nested_write)(struct ldb_kv_private *);
+	int (*abort_nested_write)(struct ldb_kv_private *);
 };
 
 /* this private structure is used by the key value backends in the
@@ -82,7 +85,19 @@ struct ldb_kv_private {
 
 	bool check_base;
 	bool disallow_dn_filter;
+	/*
+	 * To improve the performance of batch operations we maintain a cache
+	 * of index records, these entries get written to disk in the
+	 * prepare_commit phase.
+	 */
 	struct ldb_kv_idxptr *idxptr;
+	/*
+	 * To ensure that the indexes in idxptr are consistent we cache any
+	 * index updates during an operation, i.e. ldb_kv_add, ldb_kv_delete ...
+	 * Once the changes to the data record have been commited to disk
+	 * the contents of this cache are copied to idxptr
+	 */
+	struct ldb_kv_idxptr *nested_idx_ptr;
 	bool prepared_commit;
 	int read_lock_count;
 
@@ -301,4 +316,7 @@ int ldb_kv_init_store(struct ldb_kv_private *ldb_kv,
 		      struct ldb_context *ldb,
 		      const char *options[],
 		      struct ldb_module **_module);
+int ldb_kv_index_sub_transaction_start(struct ldb_kv_private *ldb_kv);
+int ldb_kv_index_sub_transaction_cancel(struct ldb_kv_private *ldb_kv);
+int ldb_kv_index_sub_transaction_commit(struct ldb_kv_private *ldb_kv);
 #endif /* __LDB_KV_H__ */
diff --git a/lib/ldb/ldb_key_value/ldb_kv_index.c b/lib/ldb/ldb_key_value/ldb_kv_index.c
index d0916387b11..4d2ad3b677b 100644
--- a/lib/ldb/ldb_key_value/ldb_kv_index.c
+++ b/lib/ldb/ldb_key_value/ldb_kv_index.c
@@ -163,6 +163,11 @@ struct dn_list {
 };
 
 struct ldb_kv_idxptr {
+	/*
+	 * In memory tdb to cache the index updates performed during a
+	 * transaction.  This improves the performance of operations like
+	 * re-index and join
+	 */
 	struct tdb_context *itdb;
 	int error;
 };
@@ -325,8 +330,7 @@ static int ldb_kv_dn_list_find_msg(struct ldb_kv_private *ldb_kv,
   alignment
  */
 static struct dn_list *ldb_kv_index_idxptr(struct ldb_module *module,
-					   TDB_DATA rec,
-					   bool check_parent)
+					   TDB_DATA rec)
 {
 	struct dn_list *list;
 	if (rec.dsize != sizeof(void *)) {
@@ -345,15 +349,14 @@ static struct dn_list *ldb_kv_index_idxptr(struct ldb_module *module,
 				       talloc_get_name(list));
 		return NULL;
 	}
-	if (check_parent && list->dn && talloc_parent(list->dn) != list) {
-		ldb_asprintf_errstring(ldb_module_get_ctx(module),
-				       "Bad parent '%s' for idxptr",
-				       talloc_get_name(talloc_parent(list->dn)));
-		return NULL;
-	}
 	return list;
 }
 
+enum dn_list_will_be_read_only {
+	DN_LIST_MUTABLE = 0,
+	DN_LIST_WILL_BE_READ_ONLY = 1,
+};
+
 /*
   return the @IDX list in an index entry for a dn as a
   struct dn_list
@@ -361,42 +364,122 @@ static struct dn_list *ldb_kv_index_idxptr(struct ldb_module *module,
 static int ldb_kv_dn_list_load(struct ldb_module *module,
 			       struct ldb_kv_private *ldb_kv,
 			       struct ldb_dn *dn,
-			       struct dn_list *list)
+			       struct dn_list *list,
+			       enum dn_list_will_be_read_only read_only)
 {
 	struct ldb_message *msg;
 	int ret, version;
 	struct ldb_message_element *el;
-	TDB_DATA rec;
+	TDB_DATA rec = {0};
 	struct dn_list *list2;
-	TDB_DATA key;
+	bool from_primary_cache = false;
+	TDB_DATA key = {0};
 
 	list->dn = NULL;
 	list->count = 0;
+	list->strict = false;
 
-	/* see if we have any in-memory index entries */
-	if (ldb_kv->idxptr == NULL || ldb_kv->idxptr->itdb == NULL) {
+	/*
+	 * See if we have an in memory index cache
+	 */
+	if (ldb_kv->idxptr == NULL) {
 		goto normal_index;
 	}
 
 	key.dptr = discard_const_p(unsigned char, ldb_dn_get_linearized(dn));
 	key.dsize = strlen((char *)key.dptr);
 
-	rec = tdb_fetch(ldb_kv->idxptr->itdb, key);
+	/*
+	 * Have we cached this index record?
+	 * If we have a nested transaction cache try that first.
+	 * then try the transaction cache.
+	 * if the record is not cached it will need to be read from disk.
+	 */
+	if (ldb_kv->nested_idx_ptr != NULL) {
+		rec = tdb_fetch(ldb_kv->nested_idx_ptr->itdb, key);
+	}
+	if (rec.dptr == NULL) {
+		from_primary_cache = true;
+		rec = tdb_fetch(ldb_kv->idxptr->itdb, key);
+	}
 	if (rec.dptr == NULL) {
 		goto normal_index;
 	}
 
 	/* we've found an in-memory index entry */
-	list2 = ldb_kv_index_idxptr(module, rec, true);
+	list2 = ldb_kv_index_idxptr(module, rec);
 	if (list2 == NULL) {
 		free(rec.dptr);
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 	free(rec.dptr);
 
-	*list = *list2;
+	/*
+	 * If this is a read only transaction the indexes will not be
+	 * changed so we don't need a copy in the event of a rollback
+	 *
+	 * In this case make an early return
+	 */
+	if (read_only == DN_LIST_WILL_BE_READ_ONLY) {
+		*list = *list2;
+		return LDB_SUCCESS;
+	}
+
+	/*
+	 * record was read from the sub transaction cache, so we have
+	 * already copied the primary cache record
+	 */
+	if (!from_primary_cache) {
+		*list = *list2;
+		return LDB_SUCCESS;
+	}
+
+	/*
+	 * No index sub transaction active, so no need to cache a copy
+	 */
+	if (ldb_kv->nested_idx_ptr == NULL) {
+		*list = *list2;
+		return LDB_SUCCESS;
+	}
+
+	/*
+	 * There is an active index sub transaction, and the record was
+	 * found in the primary index transaction cache.  A copy of the
+	 * record needs be taken to prevent the original entry being
+	 * altered, until the index sub transaction is committed.
+	 */
+
+	{
+		struct ldb_val *dns = NULL;
+		size_t x = 0;
+
+		dns = talloc_array(
+			list,
+			struct ldb_val,
+			list2->count);
+		if (dns == NULL) {
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
+		for (x = 0; x < list2->count; x++) {
+			dns[x].length = list2->dn[x].length;
+			dns[x].data = talloc_memdup(
+				dns,
+				list2->dn[x].data,
+				list2->dn[x].length);
+			if (dns[x].data == NULL) {
+				TALLOC_FREE(dns);
+				return LDB_ERR_OPERATIONS_ERROR;
+			}
+		}
+		list->dn = dns;
+		list->count = list2->count;


-- 
Samba Shared Repository



More information about the samba-cvs mailing list