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(a)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