andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone
dc8c34
From e8fad05507f04b517d464bbf4c559e9de4bad53f Mon Sep 17 00:00:00 2001
dc8c34
From: Mark Reynolds <mreynolds@redhat.com>
dc8c34
Date: Sun, 17 Jan 2016 19:33:44 -0500
dc8c34
Subject: [PATCH 375/375] Ticket 47788 - Supplier can skip a failing update,
dc8c34
 although it should retry
dc8c34
dc8c34
Bug Description:  If a replicated update fails on the consumer,
dc8c34
                  the update is never tried.  This is due to the
dc8c34
                  replication async result thread missing the failure
dc8c34
                  before another update is replicated and it succeeds.
dc8c34
dc8c34
                  This second update that succeeds updates the consumer
dc8c34
                  RUV.  This makes it appear that the consumer is caught
dc8c34
                  up, and the supplier never resends that original
dc8c34
                  failed update.
dc8c34
dc8c34
Fix Description:  When a replicated update fails, and its an error we can
dc8c34
                  not ignore, the connection is closed.  Which stops the
dc8c34
                  replication session, and prevents any further updates
dc8c34
                  coming in and updating the consumer RUV.  This allows
dc8c34
                  the supplier to correctly retry the operation that
dc8c34
                  failed on the next replication session.
dc8c34
dc8c34
https://fedorahosted.org/389/ticket/47788
dc8c34
dc8c34
Reviewed by: nhosoi, wibrown, and rmeggins (Thanks!!!)
dc8c34
dc8c34
(cherry picked from commit 80c68e202ff2b50a60f35b6683ef26b41609bc56)
dc8c34
(cherry picked from commit 96b3a5b76d9e9f3aa77627198c50741796fbe44c)
dc8c34
---
dc8c34
 ldap/servers/plugins/replication/repl5.h           |   1 +
dc8c34
 .../servers/plugins/replication/repl5_connection.c |  19 +--
dc8c34
 .../plugins/replication/repl5_inc_protocol.c       | 180 ++++++++++++---------
dc8c34
 ldap/servers/plugins/replication/repl5_plugins.c   |  60 ++++++-
dc8c34
 ldap/servers/plugins/replication/urp.c             |   2 +-
dc8c34
 5 files changed, 167 insertions(+), 95 deletions(-)
dc8c34
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
dc8c34
index 66006f6..ee161ef 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5.h
dc8c34
+++ b/ldap/servers/plugins/replication/repl5.h
dc8c34
@@ -589,6 +589,7 @@ void replica_set_ruv_dirty (Replica *r);
dc8c34
 int replica_write_ruv (Replica *r);
dc8c34
 char *replica_get_dn(Replica *r);
dc8c34
 void replica_check_for_tasks(Replica*r, Slapi_Entry *e);
dc8c34
+PRBool ignore_error_and_keep_going(int error);
dc8c34
 
dc8c34
 /* The functions below handles the state flag */
dc8c34
 /* Current internal state flags */
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5_connection.c b/ldap/servers/plugins/replication/repl5_connection.c
dc8c34
index e080a3f..0360f07 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5_connection.c
dc8c34
+++ b/ldap/servers/plugins/replication/repl5_connection.c
dc8c34
@@ -467,17 +467,17 @@ conn_read_result_ex(Repl_Connection *conn, char **retoidp, struct berval **retda
dc8c34
 					conn->last_ldap_error = rc;
dc8c34
 					close_connection_internal(conn); /* we already have the lock */
dc8c34
 					return_value = CONN_NOT_CONNECTED;
dc8c34
+					goto done;
dc8c34
 				}
dc8c34
 				else if (IS_DISCONNECT_ERROR(err))
dc8c34
 				{
dc8c34
 					conn->last_ldap_error = err;
dc8c34
 					close_connection_internal(conn); /* we already have the lock */
dc8c34
 					return_value = CONN_NOT_CONNECTED;
dc8c34
+					goto done;
dc8c34
 				}
dc8c34
 				/* Got a result */
dc8c34
-				if ((rc == LDAP_SUCCESS) && (err == LDAP_BUSY))
dc8c34
-				    	return_value = CONN_BUSY;
dc8c34
-				else if (retoidp)
dc8c34
+				if (retoidp /* total update */)
dc8c34
 				{
dc8c34
 					if (!((rc == LDAP_SUCCESS) && (err == LDAP_BUSY)))
dc8c34
 					{
dc8c34
@@ -506,16 +506,11 @@ conn_read_result_ex(Repl_Connection *conn, char **retoidp, struct berval **retda
dc8c34
 					}
dc8c34
 					return_value = LDAP_SUCCESS == conn->last_ldap_error ? CONN_OPERATION_SUCCESS : CONN_OPERATION_FAILED;
dc8c34
 				}
dc8c34
-				/*
dc8c34
-				 * XXXggood do I need to free matched, referrals,
dc8c34
-				 * anything else? Or can I pass NULL for the args
dc8c34
-				 * I'm not interested in?
dc8c34
-				 */
dc8c34
-				/* Good question! Meanwhile, as RTM aproaches, let's free them... */
dc8c34
-				slapi_ch_free((void **) &errmsg);
dc8c34
-				slapi_ch_free((void **) &matched);
dc8c34
-				charray_free(referrals);
dc8c34
 				conn->status = STATUS_CONNECTED;
dc8c34
+done:
dc8c34
+				slapi_ch_free_string(&errmsg);
dc8c34
+				slapi_ch_free_string(&matched);
dc8c34
+				charray_free(referrals);
dc8c34
 			}
dc8c34
 			if (res) ldap_msgfree(res);
dc8c34
 			PR_Unlock(conn->lock); /* release the conn lock */
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5_inc_protocol.c b/ldap/servers/plugins/replication/repl5_inc_protocol.c
dc8c34
index 3268bfd..02b54b3 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5_inc_protocol.c
dc8c34
+++ b/ldap/servers/plugins/replication/repl5_inc_protocol.c
dc8c34
@@ -174,7 +174,6 @@ static void protocol_sleep(Private_Repl_Protocol *prp, PRIntervalTime duration);
dc8c34
 static int send_updates(Private_Repl_Protocol *prp, RUV *ruv, PRUint32 *num_changes_sent);
dc8c34
 static void repl5_inc_backoff_expired(time_t timer_fire_time, void *arg);
dc8c34
 static int examine_update_vector(Private_Repl_Protocol *prp, RUV *ruv);
dc8c34
-static PRBool ignore_error_and_keep_going(int error);
dc8c34
 static const char* state2name (int state);
dc8c34
 static const char* event2name (int event);
dc8c34
 static const char* op2string (int op);
dc8c34
@@ -478,11 +477,13 @@ repl5_inc_flow_control_results(Repl_Agmt *agmt, result_data *rd)
dc8c34
     PR_Unlock(rd->lock);
dc8c34
 }
dc8c34
 
dc8c34
-static void
dc8c34
+static int
dc8c34
 repl5_inc_waitfor_async_results(result_data *rd)
dc8c34
 {
dc8c34
 	int done = 0;
dc8c34
 	int loops = 0;
dc8c34
+	int rc = UPDATE_NO_MORE_UPDATES;
dc8c34
+
dc8c34
 	/* Keep pulling results off the LDAP connection until we catch up to the last message id stored in the rd */
dc8c34
 	while (!done && !slapi_is_shutting_down())
dc8c34
 	{
dc8c34
@@ -501,6 +502,10 @@ repl5_inc_waitfor_async_results(result_data *rd)
dc8c34
 		{
dc8c34
 			done = 1; /* no connection == no more results */
dc8c34
 		}
dc8c34
+		/*
dc8c34
+		 * Return the last operation result
dc8c34
+		 */
dc8c34
+		rc = rd->result;
dc8c34
 		PR_Unlock(rd->lock);
dc8c34
 		/* If not then sleep a bit */
dc8c34
 		DS_Sleep(PR_SecondsToInterval(1));
dc8c34
@@ -516,6 +521,7 @@ repl5_inc_waitfor_async_results(result_data *rd)
dc8c34
 			done = 1;
dc8c34
 		}
dc8c34
 	}
dc8c34
+	return rc;
dc8c34
 }
dc8c34
 
dc8c34
 /*
dc8c34
@@ -1483,78 +1489,84 @@ static int
dc8c34
 repl5_inc_update_from_op_result(Private_Repl_Protocol *prp, ConnResult replay_crc, int connection_error, char *csn_str, char *uniqueid, ReplicaId replica_id, int* finished, PRUint32 *num_changes_sent)
dc8c34
 {
dc8c34
 	int return_value = 0;
dc8c34
-	
dc8c34
-	/* Indentation is wrong here so we can get a sensible cvs diff */
dc8c34
-				if (CONN_OPERATION_SUCCESS != replay_crc)
dc8c34
-				{
dc8c34
-					/* Figure out what to do next */
dc8c34
-					if (CONN_OPERATION_FAILED == replay_crc)
dc8c34
-					{
dc8c34
-						/* Map ldap error code to return value */
dc8c34
-						if (!ignore_error_and_keep_going(connection_error))
dc8c34
-						{
dc8c34
-							return_value = UPDATE_TRANSIENT_ERROR;
dc8c34
-							*finished = 1;
dc8c34
-						}
dc8c34
-						else
dc8c34
-						{
dc8c34
-							agmt_inc_last_update_changecount (prp->agmt, replica_id, 1 /*skipped*/);
dc8c34
-						}
dc8c34
-						slapi_log_error(*finished ? SLAPI_LOG_FATAL : slapi_log_urp, repl_plugin_name,
dc8c34
-							"%s: Consumer failed to replay change (uniqueid %s, CSN %s): %s (%d). %s.\n",
dc8c34
-							agmt_get_long_name(prp->agmt),
dc8c34
-							uniqueid, csn_str,
dc8c34
-							ldap_err2string(connection_error), connection_error,
dc8c34
-							*finished ? "Will retry later" : "Skipping");
dc8c34
-					}
dc8c34
-					else if (CONN_NOT_CONNECTED == replay_crc)
dc8c34
-					{
dc8c34
-						/* We lost the connection - enter backoff state */
dc8c34
 
dc8c34
-						return_value = UPDATE_CONNECTION_LOST;
dc8c34
-						*finished = 1;
dc8c34
-						slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
dc8c34
-							"%s: Consumer failed to replay change (uniqueid %s, CSN %s): "
dc8c34
-							"%s(%d). Will retry later.\n",
dc8c34
-							agmt_get_long_name(prp->agmt),
dc8c34
-							uniqueid, csn_str,
dc8c34
-							connection_error ? ldap_err2string(connection_error) : "Connection lost",
dc8c34
-							connection_error);
dc8c34
-					}
dc8c34
-					else if (CONN_TIMEOUT == replay_crc)
dc8c34
-					{
dc8c34
-						return_value = UPDATE_TIMEOUT;
dc8c34
-						*finished = 1;
dc8c34
-						slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
dc8c34
-							"%s: Consumer timed out to replay change (uniqueid %s, CSN %s): "
dc8c34
-							"%s.\n",
dc8c34
-							agmt_get_long_name(prp->agmt),
dc8c34
-							uniqueid, csn_str,
dc8c34
-							connection_error ? ldap_err2string(connection_error) : "Timeout");
dc8c34
-					}
dc8c34
-					else if (CONN_LOCAL_ERROR == replay_crc)
dc8c34
-					{
dc8c34
-						/*
dc8c34
-						 * Something bad happened on the local server - enter 
dc8c34
-						 * backoff state.
dc8c34
-						 */
dc8c34
-						return_value = UPDATE_TRANSIENT_ERROR;
dc8c34
-						*finished = 1;
dc8c34
-						slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
dc8c34
-							"%s: Failed to replay change (uniqueid %s, CSN %s): "
dc8c34
-							"Local error. Will retry later.\n",
dc8c34
-							agmt_get_long_name(prp->agmt),
dc8c34
-							uniqueid, csn_str);
dc8c34
-					}
dc8c34
-						
dc8c34
-				}
dc8c34
-				else
dc8c34
-				{
dc8c34
-					/* Positive response received */
dc8c34
-					(*num_changes_sent)++;
dc8c34
-					agmt_inc_last_update_changecount (prp->agmt, replica_id, 0 /*replayed*/);
dc8c34
-				}
dc8c34
-				return return_value;
dc8c34
+	if (CONN_OPERATION_SUCCESS != replay_crc)
dc8c34
+	{
dc8c34
+		/* Figure out what to do next */
dc8c34
+		if (CONN_OPERATION_FAILED == replay_crc)
dc8c34
+		{
dc8c34
+			/* Map ldap error code to return value */
dc8c34
+			if (!ignore_error_and_keep_going(connection_error))
dc8c34
+			{
dc8c34
+				return_value = UPDATE_TRANSIENT_ERROR;
dc8c34
+				*finished = 1;
dc8c34
+			}
dc8c34
+			else
dc8c34
+			{
dc8c34
+				agmt_inc_last_update_changecount (prp->agmt, replica_id, 1 /*skipped*/);
dc8c34
+			}
dc8c34
+			slapi_log_error(*finished ? SLAPI_LOG_FATAL : slapi_log_urp, repl_plugin_name,
dc8c34
+				"%s: Consumer failed to replay change (uniqueid %s, CSN %s): %s (%d). %s.\n",
dc8c34
+				agmt_get_long_name(prp->agmt),
dc8c34
+				uniqueid, csn_str,
dc8c34
+				ldap_err2string(connection_error), connection_error,
dc8c34
+				*finished ? "Will retry later" : "Skipping");
dc8c34
+		}
dc8c34
+		else if (CONN_NOT_CONNECTED == replay_crc)
dc8c34
+		{
dc8c34
+			/* We lost the connection - enter backoff state */
dc8c34
+
dc8c34
+			return_value = UPDATE_CONNECTION_LOST;
dc8c34
+			*finished = 1;
dc8c34
+			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
dc8c34
+				"%s: Consumer failed to replay change (uniqueid %s, CSN %s): "
dc8c34
+				"%s(%d). Will retry later.\n",
dc8c34
+				agmt_get_long_name(prp->agmt),
dc8c34
+				uniqueid, csn_str,
dc8c34
+				connection_error ? ldap_err2string(connection_error) : "Connection lost",
dc8c34
+				connection_error);
dc8c34
+		}
dc8c34
+		else if (CONN_TIMEOUT == replay_crc)
dc8c34
+		{
dc8c34
+			return_value = UPDATE_TIMEOUT;
dc8c34
+			*finished = 1;
dc8c34
+			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
dc8c34
+				"%s: Consumer timed out to replay change (uniqueid %s, CSN %s): "
dc8c34
+				"%s.\n",
dc8c34
+				agmt_get_long_name(prp->agmt),
dc8c34
+				uniqueid, csn_str,
dc8c34
+				connection_error ? ldap_err2string(connection_error) : "Timeout");
dc8c34
+		}
dc8c34
+		else if (CONN_LOCAL_ERROR == replay_crc)
dc8c34
+		{
dc8c34
+			/*
dc8c34
+			 * Something bad happened on the local server - enter
dc8c34
+			 * backoff state.
dc8c34
+			 */
dc8c34
+			return_value = UPDATE_TRANSIENT_ERROR;
dc8c34
+			*finished = 1;
dc8c34
+			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
dc8c34
+				"%s: Failed to replay change (uniqueid %s, CSN %s): "
dc8c34
+				"Local error. Will retry later.\n",
dc8c34
+				agmt_get_long_name(prp->agmt),
dc8c34
+				uniqueid, csn_str);
dc8c34
+		}
dc8c34
+		if (*finished){
dc8c34
+			/*
dc8c34
+			 * A serious error has occurred, the consumer might have closed
dc8c34
+			 * the connection already, but we need to close the conn on the
dc8c34
+			 * supplier side to properly set the conn structure as closed.
dc8c34
+			 */
dc8c34
+			conn_disconnect(prp->conn);
dc8c34
+		}
dc8c34
+	}
dc8c34
+	else
dc8c34
+	{
dc8c34
+		/* Positive response received */
dc8c34
+		(*num_changes_sent)++;
dc8c34
+		agmt_inc_last_update_changecount (prp->agmt, replica_id, 0 /*replayed*/);
dc8c34
+	}
dc8c34
+	return return_value;
dc8c34
 }
dc8c34
 
dc8c34
 /*
dc8c34
@@ -1572,7 +1584,7 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
dc8c34
 {
dc8c34
 	CL5Entry entry;
dc8c34
 	slapi_operation_parameters op;
dc8c34
-	int return_value;
dc8c34
+	int return_value = 0;
dc8c34
 	int rc;
dc8c34
 	CL5ReplayIterator *changelog_iterator;
dc8c34
 	int message_id = 0;
dc8c34
@@ -1937,8 +1949,22 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
dc8c34
 		{
dc8c34
 			/* We need to ensure that we wait until all the responses have been received from our operations */
dc8c34
 			if (return_value != UPDATE_CONNECTION_LOST) {
dc8c34
-				/* if connection was lost/closed, there will be nothing to read */
dc8c34
-				repl5_inc_waitfor_async_results(rd);
dc8c34
+				/*
dc8c34
+				 * If we already have an error, there is no need to check the
dc8c34
+				 * async result thread anymore.
dc8c34
+				 */
dc8c34
+				if (return_value == UPDATE_NO_MORE_UPDATES)
dc8c34
+				{
dc8c34
+					/*
dc8c34
+					 * We need to double check that an error hasn't popped up from
dc8c34
+					 * the async result thread since our last check.
dc8c34
+					 */
dc8c34
+					int final_result;
dc8c34
+
dc8c34
+					if((final_result = repl5_inc_waitfor_async_results(rd))){
dc8c34
+						return_value = final_result;
dc8c34
+					}
dc8c34
+				}
dc8c34
 			}
dc8c34
 
dc8c34
 			rc = repl5_inc_destroy_async_result_thread(rd);
dc8c34
@@ -2228,7 +2254,7 @@ examine_update_vector(Private_Repl_Protocol *prp, RUV *remote_ruv)
dc8c34
  * We stop if there's some indication that the server just completely
dc8c34
  * failed to process the operation, e.g. LDAP_OPERATIONS_ERROR.
dc8c34
  */
dc8c34
-static PRBool
dc8c34
+PRBool
dc8c34
 ignore_error_and_keep_going(int error)
dc8c34
 {
dc8c34
 	int return_value = PR_FALSE;
dc8c34
diff --git a/ldap/servers/plugins/replication/repl5_plugins.c b/ldap/servers/plugins/replication/repl5_plugins.c
dc8c34
index dddbf15..d49a666 100644
dc8c34
--- a/ldap/servers/plugins/replication/repl5_plugins.c
dc8c34
+++ b/ldap/servers/plugins/replication/repl5_plugins.c
dc8c34
@@ -1161,12 +1161,13 @@ write_changelog_and_ruv (Slapi_PBlock *pb)
dc8c34
 static int
dc8c34
 process_postop (Slapi_PBlock *pb)
dc8c34
 {
dc8c34
-    int rc = LDAP_SUCCESS;
dc8c34
-    Slapi_Operation *op;
dc8c34
+	Slapi_Operation *op;
dc8c34
 	Slapi_Backend *be;
dc8c34
-    int is_replicated_operation = 0;
dc8c34
+	int is_replicated_operation = 0;
dc8c34
 	CSN *opcsn = NULL;
dc8c34
 	char sessionid[REPL_SESSION_ID_SIZE];
dc8c34
+	int retval = LDAP_SUCCESS;
dc8c34
+	int rc = 0;
dc8c34
 
dc8c34
     /* we just let fixup operations through */
dc8c34
     slapi_pblock_get( pb, SLAPI_OPERATION, &op );
dc8c34
@@ -1190,8 +1191,8 @@ process_postop (Slapi_PBlock *pb)
dc8c34
 
dc8c34
 	get_repl_session_id (pb, sessionid, &opcsn);
dc8c34
 
dc8c34
-    slapi_pblock_get(pb, SLAPI_RESULT_CODE, &rc);
dc8c34
-	if (rc == LDAP_SUCCESS)
dc8c34
+	slapi_pblock_get(pb, SLAPI_RESULT_CODE, &retval);
dc8c34
+	if (retval == LDAP_SUCCESS)
dc8c34
 	{
dc8c34
         agmtlist_notify_all(pb);
dc8c34
 	}
dc8c34
@@ -1233,6 +1234,55 @@ process_postop (Slapi_PBlock *pb)
dc8c34
 			slapi_ch_free((void **) &op_params->p.p_modrdn.modrdn_newsuperior_address.uniqueid);
dc8c34
 		}
dc8c34
 	}
dc8c34
+	if (!ignore_error_and_keep_going(retval)){
dc8c34
+		/*
dc8c34
+		 * We have an error we can't ignore.  Release the replica and close
dc8c34
+		 * the connection to stop the replication session.
dc8c34
+		 */
dc8c34
+		consumer_connection_extension *connext = NULL;
dc8c34
+		Slapi_Connection *conn = NULL;
dc8c34
+		char csn_str[CSN_STRSIZE] = {'\0'};
dc8c34
+		PRUint64 connid = 0;
dc8c34
+		int opid = 0;
dc8c34
+
dc8c34
+		slapi_pblock_get(pb, SLAPI_CONNECTION, &conn;;
dc8c34
+		slapi_pblock_get(pb, SLAPI_OPERATION_ID, &opid);
dc8c34
+		slapi_pblock_get(pb, SLAPI_CONN_ID, &connid);
dc8c34
+		if (conn)
dc8c34
+		{
dc8c34
+			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
dc8c34
+				"process_postop: Failed to apply update (%s) error (%d).  "
dc8c34
+				"Aborting replication session(conn=%" NSPRIu64 " op=%d)\n",
dc8c34
+				csn_as_string(opcsn, PR_FALSE, csn_str), retval,
dc8c34
+				(long long unsigned int)connid, opid);
dc8c34
+			/*
dc8c34
+			 * Release this replica so new sessions can begin
dc8c34
+			 */
dc8c34
+			connext = consumer_connection_extension_acquire_exclusive_access(conn, connid, opid);
dc8c34
+			if (connext && connext->replica_acquired)
dc8c34
+			{
dc8c34
+				int zero = 0;
dc8c34
+				Replica *r = (Replica*)object_get_data ((Object*)connext->replica_acquired);
dc8c34
+
dc8c34
+				replica_relinquish_exclusive_access(r, connid, opid);
dc8c34
+				object_release ((Object*)connext->replica_acquired);
dc8c34
+				connext->replica_acquired = NULL;
dc8c34
+				connext->isreplicationsession = 0;
dc8c34
+				slapi_pblock_set( pb, SLAPI_CONN_IS_REPLICATION_SESSION, &zero );
dc8c34
+			}
dc8c34
+			if (connext){
dc8c34
+				consumer_connection_extension_relinquish_exclusive_access(conn, connid, opid, PR_FALSE);
dc8c34
+			}
dc8c34
+
dc8c34
+			/*
dc8c34
+			 * Close the connection to end the current session with the
dc8c34
+			 * supplier.  This prevents new updates from coming in and
dc8c34
+			 * updating the consumer RUV - which would cause this failed
dc8c34
+			 * update to be never be replayed.
dc8c34
+			 */
dc8c34
+			slapi_disconnect_server(conn);
dc8c34
+		}
dc8c34
+	}
dc8c34
 	if (NULL == opcsn)
dc8c34
 		opcsn = operation_get_csn(op);
dc8c34
 	if (opcsn)
dc8c34
diff --git a/ldap/servers/plugins/replication/urp.c b/ldap/servers/plugins/replication/urp.c
dc8c34
index 0182af3..527995c 100644
dc8c34
--- a/ldap/servers/plugins/replication/urp.c
dc8c34
+++ b/ldap/servers/plugins/replication/urp.c
dc8c34
@@ -146,7 +146,7 @@ urp_add_operation( Slapi_PBlock *pb )
dc8c34
 		slapi_log_error(slapi_log_urp, sessionid,
dc8c34
 		          "urp_add (%s): an entry with this uniqueid already exists.\n",
dc8c34
 		          slapi_entry_get_dn_const(existing_uniqueid_entry));
dc8c34
-		op_result= LDAP_UNWILLING_TO_PERFORM;
dc8c34
+		op_result= LDAP_ALREADY_EXISTS;
dc8c34
 		slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
dc8c34
 		rc= -1; /* Ignore this Operation */
dc8c34
 		PROFILE_POINT; /* Add Conflict; UniqueID Exists;  Ignore */
dc8c34
-- 
dc8c34
2.4.3
dc8c34