ldap/servers/plugins/replication/cl5_api.c | 95 +++++++++++------ ldap/servers/plugins/replication/cl5_api.h | 19 +++ ldap/servers/plugins/replication/repl5.h | 4 ldap/servers/plugins/replication/repl5_init.c | 21 +++ ldap/servers/plugins/replication/repl5_plugins.c | 126 ++++++++++++++--------- ldap/servers/slapd/back-ldbm/ldbm_add.c | 20 +++ ldap/servers/slapd/back-ldbm/ldbm_delete.c | 20 +++ ldap/servers/slapd/back-ldbm/ldbm_modify.c | 19 +++ ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 19 +++ ldap/servers/slapd/pblock.c | 104 ++++++++++++++++++ ldap/servers/slapd/plugin.c | 21 +++ ldap/servers/slapd/slap.h | 29 +++++ ldap/servers/slapd/slapi-plugin.h | 14 ++ 13 files changed, 431 insertions(+), 80 deletions(-)
New commits: commit 056cc3551f59b9724b10e8ff21ec43e49d947280 Author: Rich Megginson rmeggins@redhat.com Date: Mon Sep 12 09:48:17 2011 -0600
Add support for pre/post db transaction plugins
There are two new plugin types: betxnpreoperation - these plugins are called just after the database calls txn_begin - they are passed in SLAPI_TXN the DB_TXN* just created - they can use this as a parent transaction in a nested transaction if the plugin wishes to cause the parent to abort, the plugin should return a non-zero return code, and set the ldap error code to a meaningful error value betxnpostoperation - called just before the database calls txn_commit The changelog code uses the betxnpostoperation to create a nested transaction for the changelog write Reviewed by: nhosoi (Thanks!)
diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c index 4c88ee5..c360444 100644 --- a/ldap/servers/plugins/replication/cl5_api.c +++ b/ldap/servers/plugins/replication/cl5_api.c @@ -93,7 +93,9 @@ #define HASH_BACKETS_COUNT 16 /* number of buckets in a hash table */
#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 4100 -#define DEFAULT_DB_OP_FLAGS DB_AUTO_COMMIT +#define USE_DB_TXN 1 /* use transactions */ +#define DEFAULT_DB_ENV_OP_FLAGS DB_AUTO_COMMIT +#define DEFAULT_DB_OP_FLAGS 0 #define DB_OPEN(oflags, db, txnid, file, database, type, flags, mode, rval) \ { \ if (((oflags) & DB_INIT_TXN) && ((oflags) & DB_INIT_LOG)) \ @@ -303,6 +305,8 @@ static PRBool _cl5ReplicaInList (Object *replica, Object **replicas); static int _cl5Entry2DBData (const CL5Entry *entry, char **data, PRUint32 *len); static int _cl5WriteOperation(const char *replName, const char *replGen, const slapi_operation_parameters *op, PRBool local); +static int _cl5WriteOperationTxn(const char *replName, const char *replGen, + const slapi_operation_parameters *op, PRBool local, void *txn); static int _cl5GetFirstEntry (Object *obj, CL5Entry *entry, void **iterator, DB_TXN *txnid); static int _cl5GetNextEntry (CL5Entry *entry, void *iterator); static int _cl5CurrentDeleteEntry (void *iterator); @@ -1376,7 +1380,7 @@ void cl5DestroyIterator (void *iterator) slapi_ch_free ((void**)&it); }
-/* Name: cl5WriteOperation +/* Name: cl5WriteOperationTxn Description: writes operation to changelog Parameters: replName - name of the replica to which operation applies replGen - replica generation for the operation @@ -1385,14 +1389,15 @@ void cl5DestroyIterator (void *iterator) is in progress (if the data is reloaded). !!! op - operation to write local - this is a non-replicated operation + txn - the transaction containing this operation Return: CL5_SUCCESS if function is successfull; CL5_BAD_DATA if invalid op is passed; CL5_BAD_STATE if db has not been initialized; CL5_MEMORY_ERROR if memory allocation failed; CL5_DB_ERROR if any other db error occured; */ -int cl5WriteOperation(const char *replName, const char *replGen, - const slapi_operation_parameters *op, PRBool local) +int cl5WriteOperationTxn(const char *replName, const char *replGen, + const slapi_operation_parameters *op, PRBool local, void *txn) { int rc;
@@ -1421,7 +1426,7 @@ int cl5WriteOperation(const char *replName, const char *replGen, if (rc != CL5_SUCCESS) return rc;
- rc = _cl5WriteOperation(replName, replGen, op, local); + rc = _cl5WriteOperationTxn(replName, replGen, op, local, txn);
/* update the upper bound ruv vector */ if (rc == CL5_SUCCESS) @@ -1440,6 +1445,27 @@ int cl5WriteOperation(const char *replName, const char *replGen, return rc; }
+/* Name: cl5WriteOperation + Description: writes operation to changelog + Parameters: replName - name of the replica to which operation applies + replGen - replica generation for the operation + !!!Note that we pass name and generation rather than + replica object since generation can change while operation + is in progress (if the data is reloaded). !!! + op - operation to write + local - this is a non-replicated operation + Return: CL5_SUCCESS if function is successfull; + CL5_BAD_DATA if invalid op is passed; + CL5_BAD_STATE if db has not been initialized; + CL5_MEMORY_ERROR if memory allocation failed; + CL5_DB_ERROR if any other db error occured; + */ +int cl5WriteOperation(const char *replName, const char *replGen, + const slapi_operation_parameters *op, PRBool local) +{ + return cl5WriteOperationTxn(replName, replGen, op, local, NULL); +} + /* Name: cl5CreateReplayIterator Description: creates an iterator that allows to retireve changes that should to be sent to the consumer identified by ruv. The iteration is peformed by @@ -2050,7 +2076,7 @@ static int _cl5DBOpen () PR_snprintf(fullpathname, MAXPATHLEN, "%s/%s", s_cl5Desc.dbDir, entry->name); rc = s_cl5Desc.dbEnv->dbremove(s_cl5Desc.dbEnv, 0, fullpathname, 0, - DEFAULT_DB_OP_FLAGS); + DEFAULT_DB_ENV_OP_FLAGS); if (rc != 0) { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, @@ -3248,7 +3274,7 @@ static int _cl5Delete (const char *clDir, int rmDir) } else { /* DB files */ rc = s_cl5Desc.dbEnv->dbremove(s_cl5Desc.dbEnv, 0, filename, 0, - DEFAULT_DB_OP_FLAGS); + DEFAULT_DB_ENV_OP_FLAGS); if (rc) { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "_cl5Delete: failed to remove "%s"; " @@ -4450,8 +4476,8 @@ _cl5LDIF2Operation (char *ldifEntry, slapi_operation_parameters *op, char **repl return rval; }
-static int _cl5WriteOperation(const char *replName, const char *replGen, - const slapi_operation_parameters *op, PRBool local) +static int _cl5WriteOperationTxn(const char *replName, const char *replGen, + const slapi_operation_parameters *op, PRBool local, void *txn) { int rc; int cnt; @@ -4463,6 +4489,7 @@ static int _cl5WriteOperation(const char *replName, const char *replGen, CL5DBFile *file = NULL; Object *file_obj = NULL; DB_TXN *txnid = NULL; + DB_TXN *parent_txnid = (DB_TXN *)txn;
rc = _cl5GetDBFileByReplicaName (replName, replGen, &file_obj); if (rc == CL5_NOTFOUND) @@ -4472,14 +4499,14 @@ static int _cl5WriteOperation(const char *replName, const char *replGen, if (rc != CL5_SUCCESS) { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, - "_cl5WriteOperation: failed to find or open DB object for replica %s\n", replName); + "_cl5WriteOperationTxn: failed to find or open DB object for replica %s\n", replName); return rc; } } else if (rc != CL5_SUCCESS) { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, - "_cl5WriteOperation: failed to get db file for target dn (%s)", + "_cl5WriteOperationTxn: failed to get db file for target dn (%s)", op->target_address.dn); return CL5_OBJSET_ERROR; } @@ -4499,7 +4526,7 @@ static int _cl5WriteOperation(const char *replName, const char *replGen, { char s[CSN_STRSIZE]; slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, - "_cl5WriteOperation: failed to convert entry with csn (%s) " + "_cl5WriteOperationTxn: failed to convert entry with csn (%s) " "to db format\n", csn_as_string(op->csn,PR_FALSE,s)); goto done; } @@ -4514,7 +4541,7 @@ static int _cl5WriteOperation(const char *replName, const char *replGen, if (rc != 0) { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, - "_cl5WriteOperation: failed to write entry; db error - %d %s\n", + "_cl5WriteOperationTxn: failed to write entry; db error - %d %s\n", rc, db_strerror(rc)); if (CL5_OS_ERR_IS_DISKFULL(rc)) { @@ -4533,13 +4560,13 @@ static int _cl5WriteOperation(const char *replName, const char *replGen, { if (cnt != 0) { -#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100 +#if USE_DB_TXN /* abort previous transaction */ - rc = txn_abort (txnid); + rc = TXN_ABORT (txnid); if (rc != 0) { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, - "_cl5WriteOperation: failed to abort transaction; db error - %d %s\n", + "_cl5WriteOperationTxn: failed to abort transaction; db error - %d %s\n", rc, db_strerror(rc)); rc = CL5_DB_ERROR; goto done; @@ -4549,13 +4576,13 @@ static int _cl5WriteOperation(const char *replName, const char *replGen, interval = PR_MillisecondsToInterval(slapi_rand() % 100); DS_Sleep(interval); } -#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100 +#if USE_DB_TXN /* begin transaction */ - rc = txn_begin(s_cl5Desc.dbEnv, NULL /*pid*/, &txnid, 0); + rc = TXN_BEGIN(s_cl5Desc.dbEnv, parent_txnid, &txnid, 0); if (rc != 0) { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, - "_cl5WriteOperation: failed to start transaction; db error - %d %s\n", + "_cl5WriteOperationTxn: failed to start transaction; db error - %d %s\n", rc, db_strerror(rc)); rc = CL5_DB_ERROR; goto done; @@ -4574,7 +4601,7 @@ static int _cl5WriteOperation(const char *replName, const char *replGen, if (CL5_OS_ERR_IS_DISKFULL(rc)) { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, - "_cl5WriteOperation: changelog (%s) DISK FULL; db error - %d %s\n", + "_cl5WriteOperationTxn: changelog (%s) DISK FULL; db error - %d %s\n", s_cl5Desc.dbDir, rc, db_strerror(rc)); cl5_set_diskfull(); rc = CL5_DB_ERROR; @@ -4584,11 +4611,11 @@ static int _cl5WriteOperation(const char *replName, const char *replGen, { if (rc == 0) { - slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "_cl5WriteOperation: retry (%d) the transaction (csn=%s) succeeded\n", cnt, (char*)key.data); + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "_cl5WriteOperationTxn: retry (%d) the transaction (csn=%s) succeeded\n", cnt, (char*)key.data); } else if ((cnt + 1) >= MAX_TRIALS) { - slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "_cl5WriteOperation: retry (%d) the transaction (csn=%s) failed (rc=%d (%s))\n", cnt, (char*)key.data, rc, db_strerror(rc)); + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "_cl5WriteOperationTxn: retry (%d) the transaction (csn=%s) failed (rc=%d (%s))\n", cnt, (char*)key.data, rc, db_strerror(rc)); } } cnt ++; @@ -4596,23 +4623,23 @@ static int _cl5WriteOperation(const char *replName, const char *replGen,
if (rc == 0) /* we successfully added entry */ { -#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100 - rc = txn_commit (txnid, 0); +#if USE_DB_TXN + rc = TXN_COMMIT (txnid, 0); #endif } else { char s[CSN_STRSIZE]; slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, - "_cl5WriteOperation: failed to write entry with csn (%s); " + "_cl5WriteOperationTxn: failed to write entry with csn (%s); " "db error - %d %s\n", csn_as_string(op->csn,PR_FALSE,s), rc, db_strerror(rc)); -#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100 - rc = txn_abort (txnid); +#if USE_DB_TXN + rc = TXN_ABORT (txnid); if (rc != 0) { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, - "_cl5WriteOperation: failed to abort transaction; db error - %d %s\n", + "_cl5WriteOperationTxn: failed to abort transaction; db error - %d %s\n", rc, db_strerror(rc)); } #endif @@ -4627,7 +4654,7 @@ static int _cl5WriteOperation(const char *replName, const char *replGen, _cl5UpdateRUV (file_obj, op->csn, PR_TRUE, PR_TRUE);
slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl, - "cl5WriteOperation: successfully written entry with csn (%s)\n", csnStr); + "cl5WriteOperationTxn: successfully written entry with csn (%s)\n", csnStr); rc = CL5_SUCCESS; done: if (data->data) @@ -4640,6 +4667,12 @@ done: return rc; }
+static int _cl5WriteOperation(const char *replName, const char *replGen, + const slapi_operation_parameters *op, PRBool local) +{ + return _cl5WriteOperationTxn(replName, replGen, op, local, NULL); +} + static int _cl5GetFirstEntry (Object *obj, CL5Entry *entry, void **iterator, DB_TXN *txnid) { int rc; @@ -5861,9 +5894,9 @@ static void _cl5DBCloseFile (void **data) * run into problems when we try to checkpoint transactions later. */ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5DBCloseFile: " "removing the changelog %s (flag %d)\n", - file->name, DEFAULT_DB_OP_FLAGS); + file->name, DEFAULT_DB_ENV_OP_FLAGS); rc = s_cl5Desc.dbEnv->dbremove(s_cl5Desc.dbEnv, 0, file->name, 0, - DEFAULT_DB_OP_FLAGS); + DEFAULT_DB_ENV_OP_FLAGS); if (rc != 0) { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5DBCloseFile: " diff --git a/ldap/servers/plugins/replication/cl5_api.h b/ldap/servers/plugins/replication/cl5_api.h index 3a59111..6f2552f 100644 --- a/ldap/servers/plugins/replication/cl5_api.h +++ b/ldap/servers/plugins/replication/cl5_api.h @@ -321,6 +321,25 @@ int cl5GetNextOperation (slapi_operation_parameters *op, void *iterator); */ void cl5DestroyIterator (void *iterator);
+/* Name: cl5WriteOperationTxn + Description: writes operation to changelog as part of a containing transaction + Parameters: repl_name - name of the replica to which operation applies + repl_gen - replica generation for the operation + !!!Note that we pass name and generation rather than + replica object since generation can change while operation + is in progress (if the data is reloaded). !!! + op - operation to write + local - this is a non-replicated operation + txn - the containing transaction + Return: CL5_SUCCESS if function is successfull; + CL5_BAD_DATA if invalid op is passed; + CL5_BAD_STATE if db has not been initialized; + CL5_MEMORY_ERROR if memory allocation failed; + CL5_DB_ERROR if any other db error occured; + */ +int cl5WriteOperationTxn(const char *repl_name, const char *repl_gen, + const slapi_operation_parameters *op, PRBool local, void *txn); + /* Name: cl5WriteOperation Description: writes operation to changelog Parameters: repl_name - name of the replica to which operation applies diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h index 1a3672f..79abb7a 100644 --- a/ldap/servers/plugins/replication/repl5.h +++ b/ldap/servers/plugins/replication/repl5.h @@ -199,6 +199,10 @@ int multimaster_postop_add (Slapi_PBlock *pb); int multimaster_postop_delete (Slapi_PBlock *pb); int multimaster_postop_modify (Slapi_PBlock *pb); int multimaster_postop_modrdn (Slapi_PBlock *pb); +int multimaster_betxnpostop_modrdn (Slapi_PBlock *pb); +int multimaster_betxnpostop_delete (Slapi_PBlock *pb); +int multimaster_betxnpostop_add (Slapi_PBlock *pb); +int multimaster_betxnpostop_modify (Slapi_PBlock *pb);
/* In repl5_init.c */ char* get_thread_private_agmtname (); diff --git a/ldap/servers/plugins/replication/repl5_init.c b/ldap/servers/plugins/replication/repl5_init.c index 2b6ebdf..883c3e6 100644 --- a/ldap/servers/plugins/replication/repl5_init.c +++ b/ldap/servers/plugins/replication/repl5_init.c @@ -133,6 +133,7 @@ static Slapi_PluginDesc multimasterinternalpreopdesc = {"replication-multimaster static Slapi_PluginDesc multimasterinternalpostopdesc = {"replication-multimaster-internalpostop", VENDOR, DS_PACKAGE_VERSION, "Multimaster replication internal post-operation plugin"}; static Slapi_PluginDesc multimasterbepreopdesc = {"replication-multimaster-bepreop", VENDOR, DS_PACKAGE_VERSION, "Multimaster replication bepre-operation plugin"}; static Slapi_PluginDesc multimasterbepostopdesc = {"replication-multimaster-bepostop", VENDOR, DS_PACKAGE_VERSION, "Multimaster replication bepost-operation plugin"}; +static Slapi_PluginDesc multimasterbetxnpostopdesc = {"replication-multimaster-betxnpostop", VENDOR, DS_PACKAGE_VERSION, "Multimaster replication be transaction post-operation plugin"}; static Slapi_PluginDesc multimasterextopdesc = { "replication-multimaster-extop", VENDOR, DS_PACKAGE_VERSION, "Multimaster replication extended-operation plugin" };
static int multimaster_stopped_flag; /* A flag which is set when all the plugin threads are to stop */ @@ -329,6 +330,25 @@ multimaster_bepostop_init( Slapi_PBlock *pb ) }
int +multimaster_betxnpostop_init( Slapi_PBlock *pb ) +{ + int rc= 0; /* OK */ + + if( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 || + slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterbetxnpostopdesc ) != 0 || + slapi_pblock_set( pb, SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN, (void *) multimaster_betxnpostop_modrdn ) != 0 || + slapi_pblock_set( pb, SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN, (void *) multimaster_betxnpostop_delete ) != 0 || + slapi_pblock_set( pb, SLAPI_PLUGIN_BE_TXN_POST_ADD_FN, (void *) multimaster_betxnpostop_modrdn ) != 0 || + slapi_pblock_set( pb, SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN, (void *) multimaster_betxnpostop_delete ) != 0 ) + { + slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_betxnpostop_init failed\n" ); + rc= -1; + } + + return rc; +} + +int multimaster_start_extop_init( Slapi_PBlock *pb ) { int rc= 0; /* OK */ @@ -591,6 +611,7 @@ int replication_multimaster_plugin_init(Slapi_PBlock *pb) rc= slapi_register_plugin("postoperation", 1 /* Enabled */, "multimaster_postop_init", multimaster_postop_init, "Multimaster replication postoperation plugin", NULL, identity); rc= slapi_register_plugin("bepreoperation", 1 /* Enabled */, "multimaster_bepreop_init", multimaster_bepreop_init, "Multimaster replication bepreoperation plugin", NULL, identity); rc= slapi_register_plugin("bepostoperation", 1 /* Enabled */, "multimaster_bepostop_init", multimaster_bepostop_init, "Multimaster replication bepostoperation plugin", NULL, identity); + rc= slapi_register_plugin("betxnpostoperation", 1 /* Enabled */, "multimaster_betxnpostop_init", multimaster_betxnpostop_init, "Multimaster replication betxnpostoperation plugin", NULL, identity); rc= slapi_register_plugin("internalpreoperation", 1 /* Enabled */, "multimaster_internalpreop_init", multimaster_internalpreop_init, "Multimaster replication internal preoperation plugin", NULL, identity); rc= slapi_register_plugin("internalpostoperation", 1 /* Enabled */, "multimaster_internalpostop_init", multimaster_internalpostop_init, "Multimaster replication internal postoperation plugin", NULL, identity); rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_start_extop_init", multimaster_start_extop_init, "Multimaster replication start extended operation plugin", NULL, identity); diff --git a/ldap/servers/plugins/replication/repl5_plugins.c b/ldap/servers/plugins/replication/repl5_plugins.c index 8b47011..a036b0a 100644 --- a/ldap/servers/plugins/replication/repl5_plugins.c +++ b/ldap/servers/plugins/replication/repl5_plugins.c @@ -851,6 +851,29 @@ multimaster_postop_modrdn (Slapi_PBlock *pb) return process_postop(pb); }
+int +multimaster_betxnpostop_delete (Slapi_PBlock *pb) +{ + return write_changelog_and_ruv(pb); +} + +int +multimaster_betxnpostop_modrdn (Slapi_PBlock *pb) +{ + return write_changelog_and_ruv(pb); +} + +int +multimaster_betxnpostop_add (Slapi_PBlock *pb) +{ + return write_changelog_and_ruv(pb); +} + +int +multimaster_betxnpostop_modify (Slapi_PBlock *pb) +{ + return write_changelog_and_ruv(pb); +}
/* Helper functions */
@@ -943,42 +966,63 @@ update_ruv_component(Replica *replica, CSN *opcsn, Slapi_PBlock *pb) static int write_changelog_and_ruv (Slapi_PBlock *pb) { + Slapi_Operation *op = NULL; int rc; slapi_operation_parameters *op_params = NULL; - Object *repl_obj; + Object *repl_obj; int return_value = 0; - Replica *r; + Replica *r; + Slapi_Backend *be; + int is_replicated_operation = 0;
- /* we only log changes for operations applied to a replica */ + /* we just let fixup operations through */ + slapi_pblock_get( pb, SLAPI_OPERATION, &op ); + if ((operation_is_flag_set(op, OP_FLAG_REPL_FIXUP)) || + (operation_is_flag_set(op, OP_FLAG_TOMBSTONE_ENTRY))) + { + return 0; + } + + /* ignore operations intended for chaining backends - they will be + replicated back to us or should be ignored anyway + replicated operations should be processed normally, as they should + be going to a local backend */ + is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED); + slapi_pblock_get(pb, SLAPI_BACKEND, &be); + if (!is_replicated_operation && + slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)) + { + return 0; + } + + /* we only log changes for operations applied to a replica */ repl_obj = replica_get_replica_for_op (pb); - if (repl_obj == NULL) - return 0; + if (repl_obj == NULL) + return 0;
- r = (Replica*)object_get_data (repl_obj); - PR_ASSERT (r); + r = (Replica*)object_get_data (repl_obj); + PR_ASSERT (r);
if (replica_is_flag_set (r, REPLICA_LOG_CHANGES) && (cl5GetState () == CL5_STATE_OPEN)) { - supplier_operation_extension *opext = NULL; - const char *repl_name; - char *repl_gen; - Slapi_Operation *op; + supplier_operation_extension *opext = NULL; + const char *repl_name; + char *repl_gen;
- slapi_pblock_get(pb, SLAPI_OPERATION, &op); opext = (supplier_operation_extension*) repl_sup_get_ext (REPL_SUP_EXT_OP, op); PR_ASSERT (opext);
- /* get replica generation and replica name to pass to the write function */ - repl_name = replica_get_name (r); - repl_gen = opext->repl_gen; - PR_ASSERT (repl_name && repl_gen); + /* get replica generation and replica name to pass to the write function */ + repl_name = replica_get_name (r); + repl_gen = opext->repl_gen; + PR_ASSERT (repl_name && repl_gen);
/* for replicated operations, we log the original, non-urp data which is saved in the operation extension */ if (operation_is_flag_set(op,OP_FLAG_REPLICATED)) { - PR_ASSERT (opext->operation_parameters); + PR_ASSERT (opext->operation_parameters); op_params = opext->operation_parameters; } else /* since client operations don't go through urp, we log the operation data in pblock */ @@ -1013,21 +1057,23 @@ write_changelog_and_ruv (Slapi_PBlock *pb) op_params->target_address.uniqueid = slapi_ch_strdup (uniqueid); }
- /* we might have stripped all the mods - in that case we do not - log the operation */ - if (op_params->operation_type != SLAPI_OPERATION_MODIFY || - op_params->p.p_modify.modify_mods != NULL) - { + /* we might have stripped all the mods - in that case we do not + log the operation */ + if (op_params->operation_type != SLAPI_OPERATION_MODIFY || + op_params->p.p_modify.modify_mods != NULL) + { + void *txn = NULL; if (cl5_is_diskfull() && !cl5_diskspace_is_available()) { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, - "write_changelog_and_ruv: Skipped due to DISKFULL\n"); + "write_changelog_and_ruv: Skipped due to DISKFULL\n"); return 0; } - rc = cl5WriteOperation(repl_name, repl_gen, op_params, - !operation_is_flag_set(op, OP_FLAG_REPLICATED)); - if (rc != CL5_SUCCESS) - { + slapi_pblock_get(pb, SLAPI_TXN, &txn); + rc = cl5WriteOperationTxn(repl_name, repl_gen, op_params, + !operation_is_flag_set(op, OP_FLAG_REPLICATED), txn); + if (rc != CL5_SUCCESS) + { char csn_str[CSN_STRSIZE]; /* ONREPL - log error */ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, @@ -1036,10 +1082,10 @@ write_changelog_and_ruv (Slapi_PBlock *pb) op_params->target_address.dn, op_params->target_address.uniqueid, op_params->operation_type, - csn_as_string(op_params->csn, PR_FALSE, csn_str)); - return_value = 1; - } - } + csn_as_string(op_params->csn, PR_FALSE, csn_str)); + return_value = 1; + } + }
if (!operation_is_flag_set(op,OP_FLAG_REPLICATED)) { @@ -1056,7 +1102,6 @@ write_changelog_and_ruv (Slapi_PBlock *pb) just read from the changelog in either the supplier or consumer ruv */ if (0 == return_value) { - Slapi_Operation *op; CSN *opcsn;
slapi_pblock_get( pb, SLAPI_OPERATION, &op ); @@ -1107,24 +1152,9 @@ process_postop (Slapi_PBlock *pb) get_repl_session_id (pb, sessionid, &opcsn);
slapi_pblock_get(pb, SLAPI_RESULT_CODE, &rc); - /* - * Don't abandon writing changelog since we'd do everything - * possible to keep the changelog in sync with the backend - * db which was committed before this function was called. - * - * if (rc == LDAP_SUCCESS && !slapi_op_abandoned(pb)) - */ if (rc == LDAP_SUCCESS) { - rc = write_changelog_and_ruv(pb); - if (rc == 0) - { - agmtlist_notify_all(pb); - } - else - { - slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "%s process postop: error writing changelog and ruv\n", sessionid); - } + agmtlist_notify_all(pb); } else if (opcsn) { diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c index 20578ba..274e3d7 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_add.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c @@ -671,6 +671,18 @@ ldbm_back_add( Slapi_PBlock *pb ) ldap_result_code= LDAP_OPERATIONS_ERROR; goto error_return; } + + /* stash the transaction */ + slapi_pblock_set(pb, SLAPI_TXN, (void *)txn.back_txn_txn); + + /* call the transaction pre add plugins just after creating the transaction */ + if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN))) { + LDAPDebug1Arg( LDAP_DEBUG_ANY, "SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN plugin " + "returned error code %d\n", retval ); + slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); + goto error_return; + } + retval = id2entry_add( be, addingentry, &txn ); if (DB_LOCK_DEADLOCK == retval) { @@ -883,6 +895,14 @@ ldbm_back_add( Slapi_PBlock *pb ) } }
+ /* call the transaction post add plugins just before the commit */ + if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_ADD_FN))) { + LDAPDebug1Arg( LDAP_DEBUG_ANY, "SLAPI_PLUGIN_BE_TXN_POST_ADD_FN plugin " + "returned error code %d\n", retval ); + slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); + goto error_return; + } + retval = dblayer_txn_commit(li,&txn); if (0 != retval) { diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c index f2edf1e..088d1b5 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c @@ -467,6 +467,18 @@ ldbm_back_delete( Slapi_PBlock *pb ) ldap_result_code= LDAP_OPERATIONS_ERROR; goto error_return; } + + /* stash the transaction */ + slapi_pblock_set(pb, SLAPI_TXN, (void *)txn.back_txn_txn); + + /* call the transaction pre delete plugins just after creating the transaction */ + if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_PRE_DELETE_FN))) { + LDAPDebug1Arg( LDAP_DEBUG_ANY, "SLAPI_PLUGIN_BE_TXN_PRE_DELETE_FN plugin " + "returned error code %d\n", retval ); + slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); + goto error_return; + } + if(create_tombstone_entry) { /* @@ -868,6 +880,14 @@ ldbm_back_delete( Slapi_PBlock *pb ) goto error_return; }
+ /* call the transaction post delete plugins just before the commit */ + if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN))) { + LDAPDebug1Arg( LDAP_DEBUG_ANY, "SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN plugin " + "returned error code %d\n", retval ); + slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); + goto error_return; + } + retval = dblayer_txn_commit(li,&txn); if (0 != retval) { diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c index f3b351f..9dbf2b9 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c @@ -422,6 +422,17 @@ ldbm_back_modify( Slapi_PBlock *pb ) goto error_return; }
+ /* stash the transaction */ + slapi_pblock_set(pb, SLAPI_TXN, (void *)txn.back_txn_txn); + + /* call the transaction pre modify plugins just after creating the transaction */ + if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN))) { + LDAPDebug1Arg( LDAP_DEBUG_ANY, "SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN plugin " + "returned error code %d\n", retval ); + slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); + goto error_return; + } + /* * Update the ID to Entry index. * Note that id2entry_add replaces the entry, so the Entry ID stays the same. @@ -537,6 +548,14 @@ ldbm_back_modify( Slapi_PBlock *pb ) */ e = NULL; + /* call the transaction post modify plugins just before the commit */ + if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN))) { + LDAPDebug1Arg( LDAP_DEBUG_ANY, "SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN plugin " + "returned error code %d\n", retval ); + slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); + goto error_return; + } + retval = dblayer_txn_commit(li,&txn); if (0 != retval) { if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1; diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c index 54b3125..be5787a 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c @@ -695,6 +695,17 @@ ldbm_back_modrdn( Slapi_PBlock *pb ) goto error_return; }
+ /* stash the transaction */ + slapi_pblock_set(pb, SLAPI_TXN, (void *)txn.back_txn_txn); + + /* call the transaction pre modrdn plugins just after creating the transaction */ + if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_PRE_MODRDN_FN))) { + LDAPDebug1Arg( LDAP_DEBUG_ANY, "SLAPI_PLUGIN_BE_TXN_PRE_MODRDN_FN plugin " + "returned error code %d\n", retval ); + slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); + goto error_return; + } + /* * Update the indexes for the entry. */ @@ -898,6 +909,14 @@ ldbm_back_modrdn( Slapi_PBlock *pb ) modify_switch_entries( &newparent_modify_context,be); }
+ /* call the transaction post modrdn plugins just before the commit */ + if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN))) { + LDAPDebug1Arg( LDAP_DEBUG_ANY, "SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN plugin " + "returned error code %d\n", retval ); + slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); + goto error_return; + } + retval = dblayer_txn_commit(li,&txn); if (0 != retval) { diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c index 215b7df..d068132 100644 --- a/ldap/servers/slapd/pblock.c +++ b/ldap/servers/slapd/pblock.c @@ -1062,6 +1062,58 @@ slapi_pblock_get( Slapi_PBlock *pblock, int arg, void *value ) (*(IFP *)value) = pblock->pb_plugin->plg_internal_post_delete; break;
+ /* backend pre txn operation plugin */ + case SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN: + if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNPREOPERATION) { + return( -1 ); + } + (*(IFP *)value) = pblock->pb_plugin->plg_betxnpremodify; + break; + case SLAPI_PLUGIN_BE_TXN_PRE_MODRDN_FN: + if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNPREOPERATION) { + return( -1 ); + } + (*(IFP *)value) = pblock->pb_plugin->plg_betxnpremodrdn; + break; + case SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN: + if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNPREOPERATION) { + return( -1 ); + } + (*(IFP *)value) = pblock->pb_plugin->plg_betxnpreadd; + break; + case SLAPI_PLUGIN_BE_TXN_PRE_DELETE_FN: + if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNPREOPERATION) { + return( -1 ); + } + (*(IFP *)value) = pblock->pb_plugin->plg_betxnpredelete; + break; + + /* backend post txn operation plugin */ + case SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN: + if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNPOSTOPERATION) { + return( -1 ); + } + (*(IFP *)value) = pblock->pb_plugin->plg_betxnpostmodify; + break; + case SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN: + if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNPOSTOPERATION) { + return( -1 ); + } + (*(IFP *)value) = pblock->pb_plugin->plg_betxnpostmodrdn; + break; + case SLAPI_PLUGIN_BE_TXN_POST_ADD_FN: + if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNPOSTOPERATION) { + return( -1 ); + } + (*(IFP *)value) = pblock->pb_plugin->plg_betxnpostadd; + break; + case SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN: + if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNPOSTOPERATION) { + return( -1 ); + } + (*(IFP *)value) = pblock->pb_plugin->plg_betxnpostdelete; + break; + /* target address & controls for all operations should be normalized */ case SLAPI_TARGET_ADDRESS: if(pblock->pb_op!=NULL) @@ -2497,6 +2549,58 @@ slapi_pblock_set( Slapi_PBlock *pblock, int arg, void *value ) pblock->pb_plugin->plg_internal_post_delete = (IFP) value; break; + /* backend preoperation plugin - called just after creating transaction */ + case SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN: + if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNPREOPERATION) { + return( -1 ); + } + pblock->pb_plugin->plg_betxnpremodify = (IFP) value; + break; + case SLAPI_PLUGIN_BE_TXN_PRE_MODRDN_FN: + if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNPREOPERATION) { + return( -1 ); + } + pblock->pb_plugin->plg_betxnpremodrdn = (IFP) value; + break; + case SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN: + if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNPREOPERATION) { + return( -1 ); + } + pblock->pb_plugin->plg_betxnpreadd = (IFP) value; + break; + case SLAPI_PLUGIN_BE_TXN_PRE_DELETE_FN: + if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNPREOPERATION) { + return( -1 ); + } + pblock->pb_plugin->plg_betxnpredelete = (IFP) value; + break; + + /* backend postoperation plugin - called just before committing transaction */ + case SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN: + if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNPOSTOPERATION) { + return( -1 ); + } + pblock->pb_plugin->plg_betxnpostmodify = (IFP) value; + break; + case SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN: + if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNPOSTOPERATION) { + return( -1 ); + } + pblock->pb_plugin->plg_betxnpostmodrdn = (IFP) value; + break; + case SLAPI_PLUGIN_BE_TXN_POST_ADD_FN: + if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNPOSTOPERATION) { + return( -1 ); + } + pblock->pb_plugin->plg_betxnpostadd = (IFP) value; + break; + case SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN: + if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNPOSTOPERATION) { + return( -1 ); + } + pblock->pb_plugin->plg_betxnpostdelete = (IFP) value; + break; + /* syntax plugin functions */ case SLAPI_PLUGIN_SYNTAX_FILTER_AVA: if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) { diff --git a/ldap/servers/slapd/plugin.c b/ldap/servers/slapd/plugin.c index a8a52cd..c145eff 100644 --- a/ldap/servers/slapd/plugin.c +++ b/ldap/servers/slapd/plugin.c @@ -373,6 +373,20 @@ plugin_call_plugins( Slapi_PBlock *pb, int whichfunction ) case SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN: plugin_list_number= PLUGIN_LIST_INTERNAL_POSTOPERATION; break; + case SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN: + case SLAPI_PLUGIN_BE_TXN_PRE_MODRDN_FN: + case SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN: + case SLAPI_PLUGIN_BE_TXN_PRE_DELETE_FN: + plugin_list_number= PLUGIN_LIST_BETXNPREOPERATION; + do_op = 1; /* always allow backend callbacks (even during startup) */ + break; + case SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN: + case SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN: + case SLAPI_PLUGIN_BE_TXN_POST_ADD_FN: + case SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN: + plugin_list_number= PLUGIN_LIST_BETXNPOSTOPERATION; + do_op = 1; /* always allow backend callbacks (even during startup) */ + break; } if(plugin_list_number!=-1 && do_op) { @@ -1440,6 +1454,7 @@ plugin_call_func (struct slapdplugin *list, int operation, Slapi_PBlock *pb, int { if (SLAPI_PLUGIN_PREOPERATION == list->plg_type || SLAPI_PLUGIN_INTERNAL_PREOPERATION == list->plg_type || + SLAPI_PLUGIN_BETXNPREOPERATION == list->plg_type || SLAPI_PLUGIN_START_FN == operation ) { /* @@ -1653,6 +1668,12 @@ plugin_get_type_and_list( } else if ( strcasecmp( plugintype, "bepostoperation" ) == 0 ) { *type = SLAPI_PLUGIN_BEPOSTOPERATION; plugin_list_index= PLUGIN_LIST_BEPOSTOPERATION; + } else if ( strcasecmp( plugintype, "betxnpreoperation" ) == 0 ) { + *type = SLAPI_PLUGIN_BETXNPREOPERATION; + plugin_list_index= PLUGIN_LIST_BETXNPREOPERATION; + } else if ( strcasecmp( plugintype, "betxnpostoperation" ) == 0 ) { + *type = SLAPI_PLUGIN_BETXNPOSTOPERATION; + plugin_list_index= PLUGIN_LIST_BETXNPOSTOPERATION; } else if ( strcasecmp( plugintype, "internalpreoperation" ) == 0 ) { *type = SLAPI_PLUGIN_INTERNAL_PREOPERATION; plugin_list_index= PLUGIN_LIST_INTERNAL_PREOPERATION; diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h index ce95b1b..4dce915 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -702,7 +702,9 @@ struct matchingRuleList { #define PLUGIN_LIST_REVER_PWD_STORAGE_SCHEME 16 #define PLUGIN_LIST_LDBM_ENTRY_FETCH_STORE 17 #define PLUGIN_LIST_INDEX 18 -#define PLUGIN_LIST_GLOBAL_MAX 19 +#define PLUGIN_LIST_BETXNPREOPERATION 19 +#define PLUGIN_LIST_BETXNPOSTOPERATION 20 +#define PLUGIN_LIST_GLOBAL_MAX 21
/* plugin configuration attributes */ #define ATTR_PLUGIN_PATH "nsslapd-pluginPath" @@ -1108,6 +1110,31 @@ struct slapdplugin { } plg_un_entry_fetch_store; #define plg_entryfetchfunc plg_un.plg_un_entry_fetch_store.plg_un_entry_fetch_func #define plg_entrystorefunc plg_un.plg_un_entry_fetch_store.plg_un_entry_store_func + + /* backend txn pre-operation plugin structure */ + struct plg_un_betxnpre_operation { + IFP plg_un_betxnpre_modify; /* modify */ + IFP plg_un_betxnpre_modrdn; /* modrdn */ + IFP plg_un_betxnpre_add; /* add */ + IFP plg_un_betxnpre_delete; /* delete */ + } plg_un_betxnpre; +#define plg_betxnpremodify plg_un.plg_un_betxnpre.plg_un_betxnpre_modify +#define plg_betxnpremodrdn plg_un.plg_un_betxnpre.plg_un_betxnpre_modrdn +#define plg_betxnpreadd plg_un.plg_un_betxnpre.plg_un_betxnpre_add +#define plg_betxnpredelete plg_un.plg_un_betxnpre.plg_un_betxnpre_delete + + /* backend txn post-operation plugin structure */ + struct plg_un_betxnpost_operation { + IFP plg_un_betxnpost_modify; /* modify */ + IFP plg_un_betxnpost_modrdn; /* modrdn */ + IFP plg_un_betxnpost_add; /* add */ + IFP plg_un_betxnpost_delete; /* delete */ + } plg_un_betxnpost; +#define plg_betxnpostmodify plg_un.plg_un_betxnpost.plg_un_betxnpost_modify +#define plg_betxnpostmodrdn plg_un.plg_un_betxnpost.plg_un_betxnpost_modrdn +#define plg_betxnpostadd plg_un.plg_un_betxnpost.plg_un_betxnpost_add +#define plg_betxnpostdelete plg_un.plg_un_betxnpost.plg_un_betxnpost_delete + } plg_un; };
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index 1c7cc7d..4764e50 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -5778,6 +5778,8 @@ time_t slapi_current_time( void ); #define SLAPI_PLUGIN_REVER_PWD_STORAGE_SCHEME 16 #define SLAPI_PLUGIN_LDBM_ENTRY_FETCH_STORE 17 #define SLAPI_PLUGIN_INDEX 18 +#define SLAPI_PLUGIN_BETXNPREOPERATION 19 +#define SLAPI_PLUGIN_BETXNPOSTOPERATION 20
/* * special return values for extended operation plugins (zero or positive @@ -5926,6 +5928,12 @@ typedef struct slapi_plugindesc { #define SLAPI_PLUGIN_BE_PRE_CLOSE_FN 454 #define SLAPI_PLUGIN_BE_PRE_BACKUP_FN 455
+/* preoperation plugin to the backend - just after transaction creation */ +#define SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN 460 +#define SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN 461 +#define SLAPI_PLUGIN_BE_TXN_PRE_MODRDN_FN 462 +#define SLAPI_PLUGIN_BE_TXN_PRE_DELETE_FN 463 + /* postoperation plugin functions */ #define SLAPI_PLUGIN_POST_BIND_FN 501 #define SLAPI_PLUGIN_POST_UNBIND_FN 502 @@ -5955,6 +5963,12 @@ typedef struct slapi_plugindesc { #define SLAPI_PLUGIN_BE_POST_OPEN_FN 554 #define SLAPI_PLUGIN_BE_POST_BACKUP_FN 555
+/* postoperation plugin to the backend - just before transaction commit */ +#define SLAPI_PLUGIN_BE_TXN_POST_ADD_FN 560 +#define SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN 561 +#define SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN 562 +#define SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN 563 + /* matching rule plugin functions */ #define SLAPI_PLUGIN_MR_FILTER_CREATE_FN 600 #define SLAPI_PLUGIN_MR_INDEXER_CREATE_FN 601