[389-commits] ldap/servers

Nathan Kinder nkinder at fedoraproject.org
Tue Jan 18 17:03:25 UTC 2011


 ldap/servers/plugins/replication/repl5.h         |    3 
 ldap/servers/plugins/replication/repl5_plugins.c |   41 +++++++---
 ldap/servers/plugins/replication/repl5_replica.c |   91 +++++++++++++++++++++--
 ldap/servers/slapd/back-ldbm/ldbm_add.c          |   48 +++++++++++-
 ldap/servers/slapd/back-ldbm/ldbm_delete.c       |   46 +++++++++++
 ldap/servers/slapd/back-ldbm/ldbm_modify.c       |   47 +++++++++++
 ldap/servers/slapd/back-ldbm/ldbm_modrdn.c       |   49 ++++++++++++
 ldap/servers/slapd/back-ldbm/misc.c              |   64 ++++++++++++++++
 ldap/servers/slapd/back-ldbm/proto-back-ldbm.h   |    2 
 ldap/servers/slapd/pblock.c                      |    7 +
 ldap/servers/slapd/slap.h                        |    1 
 ldap/servers/slapd/slapi-plugin.h                |    1 
 12 files changed, 381 insertions(+), 19 deletions(-)

New commits:
commit e9fa82493548d84ac7bd2fa1f857db0023ac800d
Author: Nathan Kinder <nkinder at redhat.com>
Date:   Tue Jan 18 08:29:50 2011 -0800

    Bug 543633 - replication problems if supplier is killed under update load
    
    This patch was provided by Ulf Weltman of HP.  It has been ported to the
    current 389 code.
    
    The RUV for each replica lives in-memory while the server is running and they
    are flushed to disk every 30 seconds.  After disorderly shutdown, this can
    cause two problems if updates were arriving from a client or another replica
    when slapd goes down:
    
    1) After starting back up, the RUV will frequently have a max CSN in the past
    as compared to the changelog and compared to remote replicas.  This means that
    any updates in the changelog that were not yet sent before the crash will
    continue to not be sent after slapd comes back up, until a new update arrives.
    Then the RUV will leap ahead, the incremental protocol will position replay at
    the remote replica's max CSN, and the unsent updates from before the crash and
    also the new update will be replayed.
    
    2) If slapd went down in the window between writing to the datastore and
    writing to the changelog, then the last update against the replica will never
    appear on remote replicas.  The incremental protocol will continue once tickled
    as described above, but the last change made before the crash will be missing
    and this is not detected by the protocol.
    
    My fix is to synchronize the writing of the RUV with the writing of the data
    store.  This is accomplished as follows:
    
    1) Add a function to the replication plugin that returns the required updates
    to the RUV for a given operation, as well as the unique ID of the RUV entry for
    convenience sake.  The function is registered by the replication plugin in a
    new field in the common parameter block.
    
    2) Add a callback handler in the backend functions that handle LDAP add,
    delete, modify and rename operations.  They check whether the parameter block
    has a RUV update handler registered and if so, call it.  If it gets the set of
    modifications back it will add the updates to the client update request.
    Note: The periodic RUV update thread is still needed, in order to write RUV to
    disk when a replica is first configured but no update has been made.

diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
index da85cbf..54d3952 100644
--- a/ldap/servers/plugins/replication/repl5.h
+++ b/ldap/servers/plugins/replication/repl5.h
@@ -33,6 +33,7 @@
  * 
  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  * Copyright (C) 2010 Red Hat, Inc.
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  * All rights reserved.
  * END COPYRIGHT BLOCK **/
 
@@ -188,6 +189,8 @@ int multimaster_preop_compare (Slapi_PBlock *pb);
 int multimaster_bepreop_add (Slapi_PBlock *pb);
 int multimaster_bepreop_delete (Slapi_PBlock *pb);
 int multimaster_bepreop_modify (Slapi_PBlock *pb);
+int replica_ruv_smods_for_op (Slapi_PBlock *pb, char **uniqueid,
+	Slapi_Mods **smods);
 int multimaster_bepreop_modrdn (Slapi_PBlock *pb);
 int multimaster_bepostop_modrdn (Slapi_PBlock *pb);
 int multimaster_bepostop_delete (Slapi_PBlock *pb);
diff --git a/ldap/servers/plugins/replication/repl5_plugins.c b/ldap/servers/plugins/replication/repl5_plugins.c
index 226e91d..8b47011 100644
--- a/ldap/servers/plugins/replication/repl5_plugins.c
+++ b/ldap/servers/plugins/replication/repl5_plugins.c
@@ -33,6 +33,7 @@
  * 
  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  * All rights reserved.
  * END COPYRIGHT BLOCK **/
 
@@ -692,7 +693,7 @@ multimaster_bepreop_add (Slapi_PBlock *pb)
 {
 	int rc= 0;
 	Slapi_Operation *op;
-    int is_replicated_operation;
+	int is_replicated_operation;
 	int is_fixup_operation;
 
 	slapi_pblock_get(pb, SLAPI_OPERATION, &op);
@@ -700,9 +701,13 @@ multimaster_bepreop_add (Slapi_PBlock *pb)
 	is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
 
 	/* For replicated operations, apply URP algorithm */
-	if (is_replicated_operation && !is_fixup_operation)
+	if (!is_fixup_operation)
 	{
-		rc = urp_add_operation(pb);
+		slapi_pblock_set(pb, SLAPI_TXN_RUV_MODS_FN,
+			(void *)replica_ruv_smods_for_op);
+		if (is_replicated_operation) { 
+			rc = urp_add_operation(pb);
+		}
 	}
 
 	return rc;
@@ -713,7 +718,7 @@ multimaster_bepreop_delete (Slapi_PBlock *pb)
 {
 	int rc= 0;
 	Slapi_Operation *op;
-    int is_replicated_operation;
+	int is_replicated_operation;
 	int is_fixup_operation;
 
 	slapi_pblock_get(pb, SLAPI_OPERATION, &op);
@@ -721,9 +726,13 @@ multimaster_bepreop_delete (Slapi_PBlock *pb)
 	is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
 
 	/* For replicated operations, apply URP algorithm */
-	if(is_replicated_operation && !is_fixup_operation)
+	if(!is_fixup_operation)
 	{
-		rc = urp_delete_operation(pb);
+		slapi_pblock_set(pb, SLAPI_TXN_RUV_MODS_FN,
+			(void *)replica_ruv_smods_for_op);
+		if (is_replicated_operation) {
+			rc = urp_delete_operation(pb);
+		}
 	}
 
 	return rc;
@@ -734,7 +743,7 @@ multimaster_bepreop_modify (Slapi_PBlock *pb)
 {
 	int rc= 0;
 	Slapi_Operation *op;
-    int is_replicated_operation;
+	int is_replicated_operation;
 	int is_fixup_operation;
 
 	slapi_pblock_get(pb, SLAPI_OPERATION, &op);
@@ -742,9 +751,13 @@ multimaster_bepreop_modify (Slapi_PBlock *pb)
 	is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
 
 	/* For replicated operations, apply URP algorithm */
-	if(is_replicated_operation && !is_fixup_operation)
+	if(!is_fixup_operation)
 	{
-		rc = urp_modify_operation(pb);
+		slapi_pblock_set(pb, SLAPI_TXN_RUV_MODS_FN,
+			(void *)replica_ruv_smods_for_op);
+		if (is_replicated_operation) {
+			rc = urp_modify_operation(pb);
+		}
 	}
 
 	/* Clean up old state information */
@@ -758,7 +771,7 @@ multimaster_bepreop_modrdn (Slapi_PBlock *pb)
 {
 	int rc= 0;
 	Slapi_Operation *op;
-    int is_replicated_operation;
+	int is_replicated_operation;
 	int is_fixup_operation;
 
 	slapi_pblock_get(pb, SLAPI_OPERATION, &op);
@@ -766,9 +779,13 @@ multimaster_bepreop_modrdn (Slapi_PBlock *pb)
 	is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
 
 	/* For replicated operations, apply URP algorithm */
-	if(is_replicated_operation && !is_fixup_operation)
+	if(!is_fixup_operation)
 	{
-		rc = urp_modrdn_operation(pb);
+		slapi_pblock_set(pb, SLAPI_TXN_RUV_MODS_FN,
+			(void *)replica_ruv_smods_for_op);
+		if (is_replicated_operation) {
+			rc = urp_modrdn_operation(pb);
+		}
 	}
 
 	/* Clean up old state information */
diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c
index 3de6775..bd02dfe 100644
--- a/ldap/servers/plugins/replication/repl5_replica.c
+++ b/ldap/servers/plugins/replication/repl5_replica.c
@@ -33,6 +33,7 @@
  * 
  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  * All rights reserved.
  * END COPYRIGHT BLOCK **/
 
@@ -1477,19 +1478,36 @@ int replica_check_for_data_reload (Replica *r, void *arg)
             cl_cover_be = ruv_covers_ruv (upper_bound_ruv, r_ruv);
             if (!cl_cover_be)
             {
-                /* the data was reloaded and we can no longer use existing changelog */
-				char ebuf[BUFSIZ];
+                /* the data was reloaded, or we had disorderly shutdown between
+                 * writing RUV and CL, and we can no longer use existing CL */
+                char ebuf[BUFSIZ];
+                char cl_csn_str[CSN_STRSIZE] = {0};
+                char be_csn_str[CSN_STRSIZE] = {0};
+                CSN *cl_csn = NULL;
+                CSN *be_csn = NULL;
+ 
+                if (ruv_get_max_csn( r_ruv, &be_csn ) == RUV_SUCCESS) {
+                    csn_as_string( be_csn, PR_FALSE, be_csn_str );
+                    csn_free( &be_csn );
+                }
+
+                if (ruv_get_max_csn( upper_bound_ruv, &cl_csn ) == RUV_SUCCESS) {
+                    csn_as_string( cl_csn, PR_FALSE, cl_csn_str );
+                    csn_free( &cl_csn );
+                }
 
                 /* create a temporary replica object to conform to the interface */
                 r_obj = object_new (r, NULL);
 
                 /* We can't use existing changelog - remove existing file */
                 slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_check_for_data_reload: "
-                    "Warning: data for replica %s was reloaded and it no longer matches the data "
-                    "in the changelog (replica data %s changelog). Recreating the changelog file. This could affect replication "
-                    "with replica's consumers in which case the consumers should be reinitialized.\n",
+                    "Warning: data for replica %s does not match the data in the changelog "
+                    "(replica data (%s) %s changelog (%s)). Recreating the changelog file. "
+                    "This could affect replication with replica's consumers in which case the "
+                    "consumers should be reinitialized.\n",
                     escape_string(slapi_sdn_get_dn(r->repl_root),ebuf),
-                    ((!be_cover_cl) ? "<>" : ">") );
+                    (*be_csn_str=='\0' ? "unknown" : be_csn_str),
+                    ((!be_cover_cl) ? "<>" : ">"), (*cl_csn_str=='\0' ? "unknown" : cl_csn_str));
 
                 rc = cl5DeleteDBSync (r_obj);
 
@@ -2365,6 +2383,67 @@ replica_write_ruv (Replica *r)
 }
 
 
+/* This routine figures out if an operation is for a replicated area and if so,
+ * pulls out the operation CSN and returns it through the smods parameter.
+ * It also informs the caller of the RUV entry's unique ID, since the caller
+ * may not have access to the macro in repl5.h. */
+int
+replica_ruv_smods_for_op( Slapi_PBlock *pb, char **uniqueid, Slapi_Mods **smods )
+{
+    int rc = 0;
+    Object *replica_obj;
+    Object *ruv_obj;
+    Replica *replica;
+    RUV *ruv;
+    RUV *ruv_copy;
+    CSN *opcsn = NULL;
+    Slapi_Mod smod;
+    Slapi_Mod smod_last_modified;
+    Slapi_Operation *op;
+
+    replica_obj = replica_get_replica_for_op (pb);
+    slapi_pblock_get( pb, SLAPI_OPERATION, &op );
+
+    if (NULL != replica_obj && NULL != op) {
+        opcsn = operation_get_csn( op );
+    }
+
+    /* If the op has no CSN then it's not in a replicated area, so we're done */
+    if (NULL == opcsn) {
+        return (0);
+    }
+
+    replica = (Replica*)object_get_data(replica_obj);
+    PR_ASSERT (replica);
+
+    ruv_obj = replica_get_ruv(replica);
+    PR_ASSERT (ruv_obj);
+
+    ruv = (RUV*)object_get_data(ruv_obj);
+    PR_ASSERT (ruv);
+
+    ruv_copy = ruv_dup( ruv );
+
+    object_release (ruv_obj);
+    object_release (replica_obj);
+
+    ruv_set_max_csn( ruv_copy, opcsn, NULL );
+
+    ruv_to_smod( ruv_copy, &smod );
+    ruv_last_modified_to_smod( ruv_copy, &smod_last_modified );
+
+    ruv_destroy( &ruv_copy );
+
+    *smods = slapi_mods_new();
+    slapi_mods_add_smod(*smods, &smod);
+    slapi_mods_add_smod(*smods, &smod_last_modified);
+    *uniqueid = slapi_ch_strdup( RUV_STORAGE_ENTRY_UNIQUEID );
+
+    return (1);
+}
+
+
+
 const CSN *
 _get_deletion_csn(Slapi_Entry *e)
 {
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c
index c2e86f2..20578ba 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c
@@ -33,6 +33,7 @@
  * 
  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  * All rights reserved.
  * END COPYRIGHT BLOCK **/
 
@@ -97,7 +98,9 @@ ldbm_back_add( Slapi_PBlock *pb )
 	int	retry_count = 0;
 	int	disk_full = 0;
 	modify_context parent_modify_c = {0};
+	modify_context ruv_c = {0};
 	int parent_found = 0;
+	int ruv_c_init = 0;
 	int rc;
 	int addingentry_id_assigned= 0;
 	int addingentry_in_cache= 0;
@@ -626,6 +629,20 @@ ldbm_back_add( Slapi_PBlock *pb )
 		parent_found = 1;
 		parententry = NULL;
 	}
+
+	if (!is_ruv && !is_fixup_operation) {
+		ruv_c_init = ldbm_txn_ruv_modify_context( pb, &ruv_c );
+		if (-1 == ruv_c_init) {
+			LDAPDebug( LDAP_DEBUG_ANY,
+				"ldbm_back_add: ldbm_txn_ruv_modify_context "
+				"failed to construct RUV modify context\n",
+				0, 0, 0);
+			ldap_result_code= LDAP_OPERATIONS_ERROR;
+			retval = 0;
+			goto error_return;
+		}
+	}
+
 	/*
  	 * So, we believe that no code up till here actually added anything
 	 * to persistent store. From now on, we're transacted
@@ -795,6 +812,24 @@ ldbm_back_add( Slapi_PBlock *pb )
 				goto error_return; 
 			}
 		}
+
+		if (ruv_c_init) {
+			retval = modify_update_all( be, pb, &ruv_c, &txn );
+			if (DB_LOCK_DEADLOCK == retval) {
+				/* Abort and re-try */
+				continue;
+			}
+			if (0 != retval) {
+				LDAPDebug( LDAP_DEBUG_ANY,
+					"modify_update_all failed, err=%d %s\n", retval,
+					(msg = dblayer_strerror( retval )) ? msg : "", 0 );
+				if (LDBM_OS_ERR_IS_DISKFULL(retval))
+					disk_full = 1;
+				ldap_result_code= LDAP_OPERATIONS_ERROR;
+				goto error_return;
+			}
+		}
+
 		if (retval == 0) {
 			break;
 		}
@@ -839,6 +874,15 @@ ldbm_back_add( Slapi_PBlock *pb )
 		modify_switch_entries( &parent_modify_c,be);
 	}
 
+	if (ruv_c_init) {
+		if (modify_switch_entries(&ruv_c, be) != 0 ) {
+			ldap_result_code= LDAP_OPERATIONS_ERROR;
+			LDAPDebug( LDAP_DEBUG_ANY,
+				"ldbm_back_add: modify_switch_entries failed\n", 0, 0, 0);
+			goto error_return;
+		}
+	}
+
 	retval = dblayer_txn_commit(li,&txn);
 	if (0 != retval)
 	{
@@ -920,7 +964,9 @@ common_return:
 	slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
 	/* JCMREPL - The bepostop is called even if the operation fails. */
 	plugin_call_plugins (pb, SLAPI_PLUGIN_BE_POST_ADD_FN);
-
+	if (ruv_c_init) {
+		modify_term(&ruv_c, be);
+	}
 	modify_term(&parent_modify_c,be);
 	done_with_pblock_entry(pb,SLAPI_ADD_EXISTING_DN_ENTRY);
 	done_with_pblock_entry(pb,SLAPI_ADD_EXISTING_UNIQUEID_ENTRY);
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
index e19d6f4..f2454be 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
@@ -33,6 +33,7 @@
  * 
  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  * All rights reserved.
  * END COPYRIGHT BLOCK **/
 
@@ -68,7 +69,9 @@ ldbm_back_delete( Slapi_PBlock *pb )
 	int retry_count = 0;
 	int disk_full = 0;
 	int parent_found = 0;
+	int ruv_c_init = 0;
 	modify_context parent_modify_c = {0};
+	modify_context ruv_c = {0};
 	int rc = 0;
 	int ldap_result_code= LDAP_SUCCESS;
 	char *ldap_result_message= NULL;
@@ -419,6 +422,19 @@ ldbm_back_delete( Slapi_PBlock *pb )
 		/* JCMREPL - Add a description of what's going on? */
 	}
 
+	if (!is_ruv && !is_fixup_operation && !delete_tombstone_entry) {
+		ruv_c_init = ldbm_txn_ruv_modify_context( pb, &ruv_c );
+		if (-1 == ruv_c_init) {
+			LDAPDebug( LDAP_DEBUG_ANY,
+				"ldbm_back_delete: ldbm_txn_ruv_modify_context "
+				"failed to construct RUV modify context\n",
+				0, 0, 0);
+			ldap_result_code= LDAP_OPERATIONS_ERROR;
+			retval = 0;
+			goto error_return;
+		}
+	}
+
 	/*
 	 * So, we believe that no code up till here actually added anything
 	 * to the persistent store. From now on, we're transacted
@@ -810,6 +826,24 @@ ldbm_back_delete( Slapi_PBlock *pb )
 				goto error_return;
 			}
 		}
+
+		if (ruv_c_init) {
+			retval = modify_update_all( be, pb, &ruv_c, &txn );
+			if (DB_LOCK_DEADLOCK == retval) {
+				/* Abort and re-try */
+				continue;
+			}
+			if (0 != retval) {
+				LDAPDebug( LDAP_DEBUG_ANY,
+					"modify_update_all failed, err=%d %s\n", retval,
+					(msg = dblayer_strerror( retval )) ? msg : "", 0 );
+				if (LDBM_OS_ERR_IS_DISKFULL(retval))
+					disk_full = 1;
+				ldap_result_code= LDAP_OPERATIONS_ERROR;
+				goto error_return;
+			}
+		}
+
 		if (retval == 0 ) {
 			break;
 		}
@@ -846,6 +880,14 @@ ldbm_back_delete( Slapi_PBlock *pb )
 		modify_switch_entries( &parent_modify_c,be);
 	}
 	
+	if (ruv_c_init) {
+		if (modify_switch_entries(&ruv_c, be) != 0 ) {
+			ldap_result_code= LDAP_OPERATIONS_ERROR;
+			LDAPDebug( LDAP_DEBUG_ANY,
+				"ldbm_back_delete: modify_switch_entries failed\n", 0, 0, 0);
+			goto error_return;
+		}
+	}
 
 	rc= 0;
 	goto common_return;
@@ -902,6 +944,10 @@ common_return:
 		plugin_call_plugins (pb, SLAPI_PLUGIN_BE_POST_DELETE_FN);
 	}
 
+	if (ruv_c_init) {
+		modify_term(&ruv_c, be);
+	}
+
 diskfull_return:
     if(ldap_result_code!=-1)
 	{
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
index 9ee7525..f3b351f 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
@@ -33,6 +33,7 @@
  * 
  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  * All rights reserved.
  * END COPYRIGHT BLOCK **/
 
@@ -198,6 +199,8 @@ ldbm_back_modify( Slapi_PBlock *pb )
 	Slapi_Mods smods = {0};
 	back_txn txn;
 	back_txnid		parent_txn;
+	modify_context		ruv_c = {0};
+	int			ruv_c_init = 0;
 	int			retval = -1;
 	char			*msg;
 	char			*errbuf = NULL;
@@ -383,6 +386,19 @@ ldbm_back_modify( Slapi_PBlock *pb )
 		goto error_return;
 	}
 
+	if (!is_ruv && !is_fixup_operation) {
+		ruv_c_init = ldbm_txn_ruv_modify_context( pb, &ruv_c );
+		if (-1 == ruv_c_init) {
+			LDAPDebug( LDAP_DEBUG_ANY,
+				"ldbm_back_modify: ldbm_txn_ruv_modify_context "
+				"failed to construct RUV modify context\n",
+				0, 0, 0);
+			ldap_result_code= LDAP_OPERATIONS_ERROR;
+			retval = 0;
+			goto error_return;
+		}
+	}
+
 	for (retry_count = 0; retry_count < RETRY_TIMES; retry_count++) {
 
 		if (retry_count > 0) {
@@ -460,6 +476,24 @@ ldbm_back_modify( Slapi_PBlock *pb )
 			}
 
 		}
+
+		if (ruv_c_init) {
+			retval = modify_update_all( be, pb, &ruv_c, &txn );
+			if (DB_LOCK_DEADLOCK == retval) {
+				/* Abort and re-try */
+				continue;
+			}
+			if (0 != retval) {
+				LDAPDebug( LDAP_DEBUG_ANY,
+					"modify_update_all failed, err=%d %s\n", retval,
+					(msg = dblayer_strerror( retval )) ? msg : "", 0 );
+				if (LDBM_OS_ERR_IS_DISKFULL(retval))
+					disk_full = 1;
+				ldap_result_code= LDAP_OPERATIONS_ERROR;
+				goto error_return;
+			}
+		}
+
 		if (0 == retval) {
 			break;
 		}
@@ -469,6 +503,15 @@ ldbm_back_modify( Slapi_PBlock *pb )
 	   	ldap_result_code= LDAP_OPERATIONS_ERROR;
 		goto error_return;
 	}
+
+	if (ruv_c_init) {
+		if (modify_switch_entries(&ruv_c, be) != 0 ) {
+			ldap_result_code= LDAP_OPERATIONS_ERROR;
+			LDAPDebug( LDAP_DEBUG_ANY,
+				"ldbm_back_modify: modify_switch_entries failed\n", 0, 0, 0);
+			goto error_return;
+		}
+	}
 	
 	if (cache_replace( &inst->inst_cache, e, ec ) != 0 ) {
 		MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
@@ -557,6 +600,10 @@ common_return:
 	if (!disk_full)
 		plugin_call_plugins (pb, SLAPI_PLUGIN_BE_POST_MODIFY_FN);
 
+	if (ruv_c_init) {
+		modify_term(&ruv_c, be);
+	}
+
 	if(dblock_acquired)
 	{
 		dblayer_unlock_backend(be);
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
index e62a8b5..54b3125 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
@@ -33,6 +33,7 @@
  * 
  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  * All rights reserved.
  * END COPYRIGHT BLOCK **/
 
@@ -83,6 +84,9 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
     struct backentry *existingentry= NULL;
     modify_context parent_modify_context = {0};
     modify_context newparent_modify_context = {0};
+    modify_context ruv_c = {0};
+    int ruv_c_init = 0;
+    int is_ruv = 0;
     IDList *children= NULL;
     struct backentry **child_entries = NULL;
     struct backdn **child_dns = NULL;
@@ -120,6 +124,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
     slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
     slapi_pblock_get( pb, SLAPI_OPERATION, &operation );
     slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation );
+    is_ruv = operation_is_flag_set(operation, OP_FLAG_REPL_RUV);
     is_fixup_operation = operation_is_flag_set(operation, OP_FLAG_REPL_FIXUP);
 
     /* dblayer_txn_init needs to be called before "goto error_return" */
@@ -658,6 +663,19 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
         /* JCM - A subtree move could break ACIs, static groups, and dynamic groups. */
     }
 
+    if (!is_ruv && !is_fixup_operation) {
+        ruv_c_init = ldbm_txn_ruv_modify_context( pb, &ruv_c );
+        if (-1 == ruv_c_init) {
+            LDAPDebug( LDAP_DEBUG_ANY,
+                "ldbm_back_modrdn: ldbm_txn_ruv_modify_context "
+                "failed to construct RUV modify context\n",
+                0, 0, 0);
+            ldap_result_code = LDAP_OPERATIONS_ERROR;
+            retval = 0;
+            goto error_return;
+        }
+    }
+
     /* 
      * So, we believe that no code up till here actually added anything
      * to persistent store. From now on, we're transacted
@@ -841,6 +859,24 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
             goto error_return;
         }
 
+        if (ruv_c_init) {
+            retval = modify_update_all( be, pb, &ruv_c, &txn );
+            if (DB_LOCK_DEADLOCK == retval) {
+                /* Abort and re-try */
+                continue;
+            }
+            if (0 != retval) {
+                LDAPDebug( LDAP_DEBUG_ANY,
+                    "modify_update_all failed, err=%d %s\n", retval,
+                    (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+                if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
+                    disk_full = 1;
+                }
+                ldap_result_code= LDAP_OPERATIONS_ERROR;
+                goto error_return;
+            }
+        }
+
         break; /* retval==0, Done, Terminate the loop */
     }
     if (retry_count == RETRY_TIMES)
@@ -905,6 +941,15 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
         }
     }
 
+    if (ruv_c_init) {
+        if (modify_switch_entries(&ruv_c, be) != 0 ) {
+            ldap_result_code= LDAP_OPERATIONS_ERROR;
+            LDAPDebug( LDAP_DEBUG_ANY,
+                "ldbm_back_modrdn: modify_switch_entries failed\n", 0, 0, 0);
+            goto error_return;
+        }
+    }
+
     retval= 0;
 #if 0 /* this new entry in the cache can be used for future; don't remove it */
     /* remove from cache so that memory can be freed by cache_return */
@@ -1003,6 +1048,10 @@ common_return:
      */
     plugin_call_plugins (pb, SLAPI_PLUGIN_BE_POST_MODRDN_FN);
 
+    if (ruv_c_init) {
+        modify_term(&ruv_c, be);
+    }
+
     if (ldap_result_code!=-1)
     {
         slapi_send_ldap_result( pb, ldap_result_code, ldap_result_matcheddn,
diff --git a/ldap/servers/slapd/back-ldbm/misc.c b/ldap/servers/slapd/back-ldbm/misc.c
index 13b87fd..c8b3b7f 100644
--- a/ldap/servers/slapd/back-ldbm/misc.c
+++ b/ldap/servers/slapd/back-ldbm/misc.c
@@ -33,6 +33,7 @@
  * 
  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  * All rights reserved.
  * END COPYRIGHT BLOCK **/
 
@@ -386,6 +387,69 @@ mkdir_p(char *dir, unsigned int mode)
     }
 }
 
+/* This routine checks to see if there is a callback registered for retrieving
+ * RUV updates to add to the datastore transaction.  If so, it allocates a
+ * modify_context for consumption by the caller. */
+int
+ldbm_txn_ruv_modify_context( Slapi_PBlock *pb, modify_context *mc )
+{
+    char *uniqueid = NULL;
+    backend *be;
+    Slapi_Mods *smods = NULL;
+    struct backentry *bentry;
+    entry_address bentry_addr;
+    IFP fn = NULL;
+    int rc = 0;
+
+    slapi_pblock_get(pb, SLAPI_TXN_RUV_MODS_FN, (void *)&fn);
+
+    if (NULL == fn) {
+        return (0);
+    }
+
+    rc = (*fn)(pb, &uniqueid, &smods);
+
+    /* Either something went wrong when the RUV callback tried to assemble
+     * the updates for us, or there were no updates because the op doesn't
+     * target a replica. */
+    if (1 != rc || NULL == smods || NULL == uniqueid) {
+        return (rc);
+    }
+
+    slapi_pblock_get( pb, SLAPI_BACKEND, &be);
+
+    bentry_addr.dn = NULL;
+    bentry_addr.uniqueid = uniqueid;
+
+    /* Note: if we find the bentry, it will stay locked until someone calls
+     * modify_term on the mc we'll be associating the bentry with */
+    bentry = find_entry2modify_only( pb, be, &bentry_addr, NULL );
+
+    if (NULL == bentry) {
+	/* Uh oh, we couldn't find and lock the RUV entry! */
+        LDAPDebug( LDAP_DEBUG_ANY, "Error: ldbm_txn_ruv_modify_context failed to retrieve and lock RUV entry\n",
+            0, 0, 0 );
+        rc = -1;
+        goto done;
+    }
+
+    modify_init( mc, bentry );
+
+    if (modify_apply_mods( mc, smods )) {
+        LDAPDebug( LDAP_DEBUG_ANY, "Error: ldbm_txn_ruv_modify_context failed to apply updates to RUV entry\n",
+            0, 0, 0 );
+        rc = -1;
+        modify_term( mc, be );
+    }
+
+done:
+    slapi_ch_free_string( &uniqueid );
+    /* No need to free smods; they get freed along with the modify context */
+
+    return (rc);
+}
+
+
 int
 is_fullpath(char *path)
 {
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
index c5df007..b2dce18 100644
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
@@ -33,6 +33,7 @@
  * 
  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  * All rights reserved.
  * END COPYRIGHT BLOCK **/
 
@@ -365,6 +366,7 @@ int ldbm_delete_dirs(char *path);
 int mkdir_p(char *dir, unsigned int mode);
 int is_fullpath(char *path);
 char get_sep(char *path);
+int ldbm_txn_ruv_modify_context(Slapi_PBlock *pb, modify_context *mc);
 int get_value_from_string(const char *string, char *type, char **value);
 int get_values_from_string(const char *string, char *type, char ***valuearray);
 void normalize_dir(char *dir);
diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c
index 2418b71..256b6d2 100644
--- a/ldap/servers/slapd/pblock.c
+++ b/ldap/servers/slapd/pblock.c
@@ -33,6 +33,7 @@
  * 
  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  * All rights reserved.
  * END COPYRIGHT BLOCK **/
 
@@ -1551,6 +1552,9 @@ slapi_pblock_get( Slapi_PBlock *pblock, int arg, void *value )
 	case SLAPI_TXN:
 		(*(void **)value) = pblock->pb_txn;
 		break;
+	case SLAPI_TXN_RUV_MODS_FN:
+		(*(IFP*)value) = pblock->pb_txn_ruv_mods_fn;
+		break;
 
 	/* Search results set */
 	case SLAPI_SEARCH_RESULT_SET:
@@ -2964,6 +2968,9 @@ slapi_pblock_set( Slapi_PBlock *pblock, int arg, void *value )
 	case SLAPI_TXN:
 		pblock->pb_txn = (void *)value;
 		break;
+	case SLAPI_TXN_RUV_MODS_FN:
+		pblock->pb_txn_ruv_mods_fn = (IFP) value;
+		break;
 
 	/* Search results set */
 	case SLAPI_SEARCH_RESULT_SET:
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 1678f45..c79eae8 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -1508,6 +1508,7 @@ typedef struct slapi_pblock {
 	void		*pb_plugin_identity; /* identifies plugin for internal operation */
 	void		*pb_parent_txn;	/* parent transaction ID */
 	void		*pb_txn;		/* transaction ID */
+	IFP		pb_txn_ruv_mods_fn; /* Function to fetch RUV mods for txn */
 
 	/* Size of the database on disk, in kilobytes */
 	unsigned int	pb_dbsize;
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index fd2bf11..6a17d82 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -6036,6 +6036,7 @@ typedef struct slapi_plugindesc {
 /* transaction arguments */
 #define SLAPI_PARENT_TXN			190
 #define SLAPI_TXN				191
+#define SLAPI_TXN_RUV_MODS_FN			1901
 
 /*
  * The following are used to pass information back and forth




More information about the 389-commits mailing list