|
|
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 |
|