Blob Blame Raw
From e48616639e254b698edaa778d41597094243ced5 Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Fri, 26 Aug 2016 15:04:02 -0400
Subject: [PATCH 44/45] Ticket 48957 - set proper update status to replication 
 agreement in case of failure

Bug Description:  If a replication agreement fails to send updates it always returns
                  a generic error message even though there are many ways it could be
                  failing.

Fix Description:  Set a proper error message when we fail to update a replica.  Also made
                  all the messages consistent in format, and added new response strings
                  for known errors.

                  Also fixed some minor compiler warnings.

https://fedorahosted.org/389/ticket/48957

Reviewed by: nhosoi(Thanks!)

(cherry picked from commit cdf4fb4ea6f26b4198d2d6b146ca51dcd51a31ef)
---
 ldap/servers/plugins/replication/repl5.h           | 15 +++--
 ldap/servers/plugins/replication/repl5_agmt.c      | 26 ++++----
 .../plugins/replication/repl5_inc_protocol.c       | 70 ++++++++++++++--------
 .../plugins/replication/repl5_protocol_util.c      | 65 ++++++++++++++++++--
 .../plugins/replication/repl5_replica_config.c     |  4 +-
 ldap/servers/plugins/replication/repl5_total.c     |  5 +-
 6 files changed, 132 insertions(+), 53 deletions(-)

diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
index 6f6c81a..13a38fd 100644
--- a/ldap/servers/plugins/replication/repl5.h
+++ b/ldap/servers/plugins/replication/repl5.h
@@ -91,11 +91,16 @@
 #define NSDS50_REPL_BELOW_PURGEPOINT 0x07 /* Supplier provided a CSN below the consumer's purge point */
 #define NSDS50_REPL_INTERNAL_ERROR 0x08 /* Something bad happened on consumer */
 #define NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED 0x09 /* Replica released successfully */
-#define NSDS50_REPL_LEGACY_CONSUMER 0x0A    /* replica is a legacy consumer */
-#define NSDS50_REPL_REPLICAID_ERROR 0x0B	/* replicaID doesn't seem to be unique */
-#define NSDS50_REPL_DISABLED 0x0C	/* replica suffix is disabled */
-#define NSDS50_REPL_UPTODATE 0x0D	/* replica is uptodate */
-#define NSDS50_REPL_BACKOFF 0x0E        /* replica wants master to go into backoff mode */
+#define NSDS50_REPL_LEGACY_CONSUMER 0x0A /* replica is a legacy consumer */
+#define NSDS50_REPL_REPLICAID_ERROR 0x0B /* replicaID doesn't seem to be unique */
+#define NSDS50_REPL_DISABLED 0x0C /* replica suffix is disabled */
+#define NSDS50_REPL_UPTODATE 0x0D /* replica is uptodate */
+#define NSDS50_REPL_BACKOFF 0x0E /* replica wants master to go into backoff mode */
+#define NSDS50_REPL_CL_ERROR 0x0F /* Problem reading changelog */
+#define NSDS50_REPL_CONN_ERROR 0x10 /* Problem with replication connection*/
+#define NSDS50_REPL_CONN_TIMEOUT 0x11 /* Connection timeout */
+#define NSDS50_REPL_TRANSIENT_ERROR 0x12 /* Transient error */
+#define NSDS50_REPL_RUV_ERROR 0x13 /* Problem with the RUV */
 #define NSDS50_REPL_REPLICA_NO_RESPONSE 0xff /* No response received */
 
 /* Protocol status */
diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c
index 76d26a1..52cc8b6 100644
--- a/ldap/servers/plugins/replication/repl5_agmt.c
+++ b/ldap/servers/plugins/replication/repl5_agmt.c
@@ -2460,9 +2460,9 @@ agmt_set_last_update_status (Repl_Agmt *ra, int ldaprc, int replrc, const char *
 					replmsg = NULL;
 				}
 			}
-			PR_snprintf(ra->last_update_status, STATUS_LEN, "%d %s%sLDAP error: %s%s%s",
+			PR_snprintf(ra->last_update_status, STATUS_LEN, "Error (%d) %s%s - LDAP error: %s%s%s%s",
 				ldaprc, message?message:"",message?"":" - ",
-				slapi_err2string(ldaprc), replmsg ? " - " : "", replmsg ? replmsg : "");
+				slapi_err2string(ldaprc), replmsg ? " (" : "", replmsg ? replmsg : "", replmsg ? ")" : "");
 		}
 		/* ldaprc == LDAP_SUCCESS */
 		else if (replrc != 0)
@@ -2470,16 +2470,15 @@ agmt_set_last_update_status (Repl_Agmt *ra, int ldaprc, int replrc, const char *
 			if (replrc == NSDS50_REPL_REPLICA_BUSY)
 			{
 				PR_snprintf(ra->last_update_status, STATUS_LEN,
-					"%d Can't acquire busy replica", replrc ); 
+					"Error (%d) Can't acquire busy replica", replrc );
 			}
 			else if (replrc == NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED)
 			{
-				PR_snprintf(ra->last_update_status, STATUS_LEN, "%d %s",
-					ldaprc, "Replication session successful");
+				PR_snprintf(ra->last_update_status, STATUS_LEN, "Error (0) Replication session successful");
 			}
 			else if (replrc == NSDS50_REPL_DISABLED)
 			{
-				PR_snprintf(ra->last_update_status, STATUS_LEN, "%d Incremental update aborted: "
+				PR_snprintf(ra->last_update_status, STATUS_LEN, "Error (%d) Incremental update aborted: "
 					"Replication agreement for %s\n can not be updated while the replica is disabled.\n"
 					"(If the suffix is disabled you must enable it then restart the server for replication to take place).",
 					replrc, ra->long_name ? ra->long_name : "a replica");
@@ -2493,20 +2492,18 @@ agmt_set_last_update_status (Repl_Agmt *ra, int ldaprc, int replrc, const char *
 			else
 			{
 				PR_snprintf(ra->last_update_status, STATUS_LEN,
-					"%d Replication error acquiring replica: %s%s%s",
-					replrc, protocol_response2string(replrc),
-					message?" - ":"",message?message:"");
+					"Error (%d) Replication error acquiring replica: %s%s(%s)",
+					replrc, message?message:"", message?" ":"", protocol_response2string(replrc));
 			}
 		}
 		else if (message != NULL) /* replrc == NSDS50_REPL_REPLICA_READY == 0 */
 		{
-			PR_snprintf(ra->last_update_status, STATUS_LEN, 
-						"%d Replica acquired successfully: %s",
-						ldaprc, message);
+			PR_snprintf(ra->last_update_status, STATUS_LEN,
+				"Error (0) Replica acquired successfully: %s", message);
 		}
 		else
 		{ /* agmt_set_last_update_status(0,0,NULL) to reset agmt */
-			PR_snprintf(ra->last_update_status, STATUS_LEN, "%d", ldaprc);
+			ra->last_update_status[0] = '\0';
 		}
 	}
 }
@@ -2737,7 +2734,8 @@ get_agmt_status(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
 		slapi_entry_add_string(e, "nsds5replicaChangesSentSinceStartup", changecount_string);
 		if (ra->last_update_status[0] == '\0')
 		{
-			slapi_entry_add_string(e, "nsds5replicaLastUpdateStatus", "0 No replication sessions started since server startup");
+			slapi_entry_add_string(e, "nsds5replicaLastUpdateStatus",
+			                       "Error (0) No replication sessions started since server startup");
 		}
 		else
 		{
diff --git a/ldap/servers/plugins/replication/repl5_inc_protocol.c b/ldap/servers/plugins/replication/repl5_inc_protocol.c
index 27bac5d..d1de6c5 100644
--- a/ldap/servers/plugins/replication/repl5_inc_protocol.c
+++ b/ldap/servers/plugins/replication/repl5_inc_protocol.c
@@ -671,7 +671,6 @@ repl5_inc_run(Private_Repl_Protocol *prp)
   int wait_change_timer_set = 0;
   int current_state = STATE_START;
   int next_state = STATE_START;
-  int optype, ldaprc;
   int done;
   int e1;
 
@@ -838,14 +837,6 @@ repl5_inc_run(Private_Repl_Protocol *prp)
           } else if (rc == ACQUIRE_FATAL_ERROR){
               next_state = STATE_STOP_FATAL_ERROR;
           }
-
-          if (rc != ACQUIRE_SUCCESS){
-              int optype, ldaprc;
-              conn_get_error(prp->conn, &optype, &ldaprc);
-              agmt_set_last_update_status(prp->agmt, ldaprc,
-                  prp->last_acquire_response_code, "Unable to acquire replica");
-          }
-
           object_release(prp->replica_object);
           break;
 
@@ -934,10 +925,6 @@ repl5_inc_run(Private_Repl_Protocol *prp)
               } else if (rc == ACQUIRE_FATAL_ERROR){
                   next_state = STATE_STOP_FATAL_ERROR;
               }
-              if (rc != ACQUIRE_SUCCESS){
-                  conn_get_error(prp->conn, &optype, &ldaprc);
-                  agmt_set_last_update_status(prp->agmt, ldaprc, prp->last_acquire_response_code, "Unable to acquire replica");
-              }
               /*
                * We either need to step the backoff timer, or
                * destroy it if we don't need it anymore
@@ -1037,7 +1024,8 @@ repl5_inc_run(Private_Repl_Protocol *prp)
                   slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
                       "%s: Replica has no update vector. It has never been initialized.\n",
                       agmt_get_long_name(prp->agmt));
-                  agmt_set_last_update_status(prp->agmt, 0, rc, "Replica is not initialized");
+                  agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_RUV_ERROR,
+                      "Replica is not initialized");
                   next_state = STATE_BACKOFF_START;
                   break;
               case EXAMINE_RUV_GENERATION_MISMATCH:
@@ -1045,8 +1033,9 @@ repl5_inc_run(Private_Repl_Protocol *prp)
                       "%s: The remote replica has a different database generation ID than "
                       "the local database.  You may have to reinitialize the remote replica, "
                       "or the local replica.\n", agmt_get_long_name(prp->agmt));
-                  agmt_set_last_update_status(prp->agmt, 0, rc, "Replica has different database "
-                      "generation ID, remote replica may need to be initialized");
+                  agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_RUV_ERROR,
+                      "Replica has different database generation ID, remote "
+                      "replica may need to be initialized");
                   next_state = STATE_BACKOFF_START;
                   break;
               case EXAMINE_RUV_REPLICA_TOO_OLD:
@@ -1054,7 +1043,8 @@ repl5_inc_run(Private_Repl_Protocol *prp)
                       "%s: Replica update vector is too out of date to bring "
                       "into sync using the incremental protocol. The replica "
                       "must be reinitialized.\n", agmt_get_long_name(prp->agmt));
-                  agmt_set_last_update_status(prp->agmt, 0, rc, "Replica needs to be reinitialized");
+                  agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_RUV_ERROR,
+                      "Replica needs to be reinitialized");
                   next_state = STATE_BACKOFF_START;
                   break;
               case EXAMINE_RUV_OK:
@@ -1069,11 +1059,15 @@ repl5_inc_run(Private_Repl_Protocol *prp)
                       slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
                           "%s: Incremental protocol: fatal error - too much time skew between replicas!\n",
                           agmt_get_long_name(prp->agmt));
+                      agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_EXCESSIVE_CLOCK_SKEW,
+                          "fatal error - too much time skew between replicas");
                       next_state = STATE_STOP_FATAL_ERROR;
                   } else if (rc != 0) /* internal error */ {
                       slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
                           "%s: Incremental protocol: fatal internal error updating the CSN generator!\n",
                           agmt_get_long_name(prp->agmt));
+                      agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_INTERNAL_ERROR,
+                          "fatal internal error updating the CSN generator");
                       next_state = STATE_STOP_FATAL_ERROR;
                   } else {
                       /*
@@ -1097,7 +1091,8 @@ repl5_inc_run(Private_Repl_Protocol *prp)
                           next_state = STATE_BACKOFF_START;
                       } else if (rc == UPDATE_TRANSIENT_ERROR){
                           dev_debug("repl5_inc_run(STATE_SENDING_UPDATES) -> send_updates = UPDATE_TRANSIENT_ERROR -> STATE_BACKOFF_START");
-                          agmt_set_last_update_status(prp->agmt, 0, rc, "Incremental update transient error.  Backing off, will retry update later.");
+                          agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_TRANSIENT_ERROR,
+                              "Incremental update transient error.  Backing off, will retry update later.");
                           next_state = STATE_BACKOFF_START;
                       } else if (rc == UPDATE_FATAL_ERROR){
                           dev_debug("repl5_inc_run(STATE_SENDING_UPDATES) -> send_updates = UPDATE_FATAL_ERROR -> STATE_STOP_FATAL_ERROR");
@@ -1114,11 +1109,13 @@ repl5_inc_run(Private_Repl_Protocol *prp)
                           conn_disconnect (prp->conn);
                       } else if (rc == UPDATE_CONNECTION_LOST){
                           dev_debug("repl5_inc_run(STATE_SENDING_UPDATES) -> send_updates = UPDATE_CONNECTION_LOST -> STATE_BACKOFF_START");
-                          agmt_set_last_update_status(prp->agmt, 0, rc, "Incremental update connection error.  Backing off, will retry update later.");
+                          agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_CONN_ERROR,
+                              "Incremental update connection error.  Backing off, will retry update later.");
                           next_state = STATE_BACKOFF_START;
                       } else if (rc == UPDATE_TIMEOUT){
                           dev_debug("repl5_inc_run(STATE_SENDING_UPDATES) -> send_updates = UPDATE_TIMEOUT -> STATE_BACKOFF_START");
-                          agmt_set_last_update_status(prp->agmt, 0, rc, "Incremental update timeout error.  Backing off, will retry update later.");
+                          agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_CONN_TIMEOUT,
+                              "Incremental update timeout error.  Backing off, will retry update later.");
                           next_state = STATE_BACKOFF_START;
                       }
                       /* Set the updates times based off the result of send_updates() */
@@ -1173,8 +1170,6 @@ repl5_inc_run(Private_Repl_Protocol *prp)
           /*
            * We encountered some sort of a fatal error. Suspend.
            */
-          /* XXXggood update state in replica */
-          agmt_set_last_update_status(prp->agmt, -1, 0, "Incremental update has failed and requires administrator action");
           dev_debug("repl5_inc_run(STATE_STOP_FATAL_ERROR)");
           slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
               "%s: Incremental update failed and requires administrator action\n",
@@ -1630,30 +1625,40 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
 			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
 				"%s: Invalid parameter passed to cl5CreateReplayIterator\n",
 				agmt_get_long_name(prp->agmt));
+			agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_CL_ERROR,
+				"Invalid parameter passed to cl5CreateReplayIterator");
 			return_value = UPDATE_FATAL_ERROR;
 			break;
 		case CL5_BAD_FORMAT:     /* db data has unexpected format */
 			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
 				"%s: Unexpected format encountered in changelog database\n",
 				agmt_get_long_name(prp->agmt));
+			agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_CL_ERROR,
+				"Unexpected format encountered in changelog database");
 			return_value = UPDATE_FATAL_ERROR;
 			break;
 		case CL5_BAD_STATE: /* changelog is in an incorrect state for attempted operation */
 			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
 				"%s: Changelog database was in an incorrect state\n",
 				agmt_get_long_name(prp->agmt));
+			agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_CL_ERROR,
+				"Changelog database was in an incorrect state");
 			return_value = UPDATE_FATAL_ERROR;
 			break;
 		case CL5_BAD_DBVERSION:  /* changelog has invalid dbversion */
 			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
 				"%s: Incorrect dbversion found in changelog database\n",
 				agmt_get_long_name(prp->agmt));
+			agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_CL_ERROR,
+				"Incorrect dbversion found in changelog database");
 			return_value = UPDATE_FATAL_ERROR;
 			break;
 		case CL5_DB_ERROR:       /* database error */
 			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
 				"%s: A changelog database error was encountered\n",
 				agmt_get_long_name(prp->agmt));
+			agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_CL_ERROR,
+				"Changelog database error was encountered");
 			return_value = UPDATE_FATAL_ERROR;
 			break;
 		case CL5_NOTFOUND:       /* we have no changes to send */
@@ -1666,6 +1671,8 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
 			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
 				"%s: Memory allocation error occurred\n",
 				agmt_get_long_name(prp->agmt));
+			agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_CL_ERROR,
+				"changelog memory allocation error occurred");
 			return_value = UPDATE_FATAL_ERROR;
 			break;
 		case CL5_SYSTEM_ERROR:   /* NSPR error occurred: use PR_GetError for further info */
@@ -1694,15 +1701,20 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
 			break;
 		case CL5_PURGED_DATA:    /* requested data has been purged */
 			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
-				"%s: Data required to update replica has been purged. "
+				"%s: Data required to update replica has been purged from the changelog. "
 				"The replica must be reinitialized.\n",
 				agmt_get_long_name(prp->agmt));
+			agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_CL_ERROR,
+				"Data required to update replica has been purged from the changelog. "
+				"The replica must be reinitialized.");
 			return_value = UPDATE_FATAL_ERROR;
 			break;
 		case CL5_MISSING_DATA:   /* data should be in the changelog, but is missing */
 			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
 				"%s: Missing data encountered\n",
 				agmt_get_long_name(prp->agmt));
+			agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_CL_ERROR,
+				"Changelog data is missing");
 			return_value = UPDATE_FATAL_ERROR;
 			break;
 		case CL5_UNKNOWN_ERROR:   /* unclassified error */
@@ -1738,8 +1750,9 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
 			rc = repl5_inc_create_async_result_thread(rd);
 			if (rc) {
 				slapi_log_error (SLAPI_LOG_FATAL, repl_plugin_name, "%s: repl5_inc_run: "
-							 "repl5_tot_create_async_result_thread failed; error - %d\n", 
+							 "repl5_inc_create_async_result_thread failed; error - %d\n",
 							 agmt_get_long_name(prp->agmt), rc);
+				agmt_set_last_update_status(prp->agmt, 0, rc, "Failed to create result thread");
 				return_value = UPDATE_FATAL_ERROR;
 			}
 		}
@@ -1898,6 +1911,8 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
 				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
 					"%s: Invalid parameter passed to cl5GetNextOperationToReplay\n",
 					agmt_get_long_name(prp->agmt));
+				agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_CL_ERROR,
+					"Invalid parameter passed to cl5GetNextOperationToReplay");
 				return_value = UPDATE_FATAL_ERROR;
 				finished = 1;
 				break;
@@ -1912,6 +1927,8 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
 				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
 					"%s: A database error occurred (cl5GetNextOperationToReplay)\n",
 					agmt_get_long_name(prp->agmt));
+				agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_CL_ERROR,
+					"Database error occurred while getting the next operation to replay");
 				return_value = UPDATE_FATAL_ERROR;
 				finished = 1;
 				break;
@@ -1922,8 +1939,10 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
 				break;
 			case CL5_MEMORY_ERROR:
 				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
-					"%s: A memory allocation error occurred (cl5GetNextOperationToRepla)\n",
+					"%s: A memory allocation error occurred (cl5GetNextOperationToReplay)\n",
 					agmt_get_long_name(prp->agmt));
+				agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_CL_ERROR,
+					"Memory allocation error occurred (cl5GetNextOperationToReplay)");
 				return_value = UPDATE_FATAL_ERROR;
 				break;
 			case CL5_IGNORE_OP:
@@ -1985,6 +2004,7 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
 			if (!replarea_sdn) {
 				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
 				                "send_updates: Unknown replication area due to agreement not found.");
+				agmt_set_last_update_status(prp->agmt, 0, -1, "Agreement is corrupted: missing suffix");
 				return_value = UPDATE_FATAL_ERROR;
 			} else {
 				replica_subentry_update(replarea_sdn, rid);
diff --git a/ldap/servers/plugins/replication/repl5_protocol_util.c b/ldap/servers/plugins/replication/repl5_protocol_util.c
index ce27a8a..ce6281a 100644
--- a/ldap/servers/plugins/replication/repl5_protocol_util.c
+++ b/ldap/servers/plugins/replication/repl5_protocol_util.c
@@ -140,10 +140,18 @@ acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv)
 	crc = conn_connect(conn);
 	if (CONN_OPERATION_FAILED == crc)
 	{
+		int operation, error;
+		conn_get_error(conn, &operation, &error);
+		agmt_set_last_update_status(prp->agmt, error, NSDS50_REPL_CONN_ERROR,
+			"Problem connecting to replica");
 		return_value = ACQUIRE_TRANSIENT_ERROR;
 	}
 	else if (CONN_SSL_NOT_ENABLED == crc)
 	{
+		int operation, error;
+		conn_get_error(conn, &operation, &error);
+		agmt_set_last_update_status(prp->agmt, error, NSDS50_REPL_CONN_ERROR,
+			"Problem connecting to replica (SSL not enabled)");
 		return_value = ACQUIRE_FATAL_ERROR;
 	}
 	else
@@ -295,6 +303,9 @@ acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv)
 								"an internal error occurred on the remote replica. "
 								"Replication is aborting.\n",
 								agmt_get_long_name(prp->agmt));
+							agmt_set_last_update_status(prp->agmt, 0, extop_result,
+								"Failed to acquire replica: "
+								"Internal error occurred on the remote replica");
 							return_value = ACQUIRE_FATAL_ERROR;
 							break;
 					case NSDS50_REPL_PERMISSION_DENIED:
@@ -307,6 +318,11 @@ acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv)
 								"supply replication updates to the replica. "
 								"Will retry later.\n",
 								agmt_get_long_name(prp->agmt), repl_binddn);
+							agmt_set_last_update_status(prp->agmt, 0, extop_result,
+								"Unable to acquire replica: permission denied. "
+								"The bind dn does not have permission to "
+								"supply replication updates to the replica. "
+								"Will retry later.");
 							slapi_ch_free((void **)&repl_binddn);
 							return_value = ACQUIRE_TRANSIENT_ERROR;
 							break;
@@ -321,6 +337,10 @@ acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv)
 								"Replication is aborting.\n",
 								agmt_get_long_name(prp->agmt),
 								slapi_sdn_get_dn(repl_root));
+							agmt_set_last_update_status(prp->agmt, 0, extop_result,
+								"Unable to acquire replica: there is no "
+								"replicated area on the consumer server. "
+								"Replication is aborting.");
 							slapi_sdn_free(&repl_root);
 							return_value = ACQUIRE_FATAL_ERROR;
 							break;
@@ -342,6 +362,11 @@ acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv)
 							"startReplicationRequest extended operation sent by the "
 							"supplier. Replication is aborting.\n",
 							agmt_get_long_name(prp->agmt));
+						agmt_set_last_update_status(prp->agmt, 0, extop_result,
+							"Unable to acquire replica: "
+							"the consumer was unable to decode the "
+							"startReplicationRequest extended operation sent "
+							"by the supplier. Replication is aborting.");
 						return_value = ACQUIRE_FATAL_ERROR;
 						break;
 					case NSDS50_REPL_REPLICA_BUSY:
@@ -365,6 +390,10 @@ acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv)
 								"by another supplier. Will try later\n",
 								agmt_get_long_name(prp->agmt));
 						}
+						agmt_set_last_update_status(prp->agmt, 0, extop_result,
+							"Unable to acquire replica: "
+							"the replica is currently being updated by another "
+							"supplier.");
 						return_value = ACQUIRE_REPLICA_BUSY;
 						break;
 					case NSDS50_REPL_LEGACY_CONSUMER:
@@ -373,6 +402,9 @@ acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv)
 							"%s: Unable to acquire replica: the replica "
 							"is supplied by a legacy supplier. "
 							"Replication is aborting.\n", agmt_get_long_name(prp->agmt));
+						agmt_set_last_update_status(prp->agmt, 0, extop_result,
+							"Unable to acquire replica: the replica is supplied "
+							"by a legacy supplier.  Replication is aborting.");
 						return_value = ACQUIRE_FATAL_ERROR;
 						break;
 					case NSDS50_REPL_REPLICAID_ERROR:
@@ -382,6 +414,9 @@ acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv)
 							"has the same Replica ID as this one. "
 							"Replication is aborting.\n",
 							agmt_get_long_name(prp->agmt));
+						agmt_set_last_update_status(prp->agmt, 0, 0,
+							"Unable to aquire replica: the replica has the same "
+							"Replica ID as this one. Replication is aborting.");
 						return_value = ACQUIRE_FATAL_ERROR;
 						break;
 					case NSDS50_REPL_BACKOFF:
@@ -392,6 +427,9 @@ acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv)
                                                         "the replica instructed us to go into "
                                                         "backoff mode. Will retry later.\n",
                                                         agmt_get_long_name(prp->agmt));
+						agmt_set_last_update_status(prp->agmt, 0, extop_result,
+							"Unable to acquire replica: the replica instructed "
+							"us to go into backoff mode. Will retry later.");
 						return_value = ACQUIRE_TRANSIENT_ERROR;
 						break;
 					case NSDS50_REPL_REPLICA_READY:
@@ -450,6 +488,8 @@ acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv)
 						return_value = ACQUIRE_SUCCESS;
 						break;
 					default:
+						agmt_set_last_update_status(prp->agmt, 0, extop_result,
+							"Unable to acquire replica");
 						return_value = ACQUIRE_FATAL_ERROR;
 					}
 				}
@@ -461,6 +501,10 @@ acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv)
 						"startReplication extended operation. "
 						"Replication is aborting.\n", 
 						agmt_get_long_name(prp->agmt));
+					agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_DECODING_ERROR,
+						"Unable to parse the response to the "
+						"startReplication extended operation. "
+						"Replication is aborting.");
 					prp->last_acquire_response_code = NSDS50_REPL_INTERNAL_ERROR;
 					return_value = ACQUIRE_FATAL_ERROR;
 				}
@@ -477,6 +521,9 @@ acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv)
 					"extended operation to consumer (%s). Will retry later.\n",
 					agmt_get_long_name(prp->agmt),
 					error ? ldap_err2string(error) : "unknown error");
+				agmt_set_last_update_status(prp->agmt, error, NSDS50_REPL_CONN_ERROR,
+					"Unable to receive the response for a startReplication "
+					"extended operation to consumer. Will retry later.");
 			}
 		}
 		else
@@ -486,6 +533,9 @@ acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv)
 				"%s: Unable to obtain current CSN. "
 				"Replication is aborting.\n",
 				agmt_get_long_name(prp->agmt));
+			agmt_set_last_update_status(prp->agmt, 0, 0,
+				"Unable to obtain current CSN. "
+				"Replication is aborting.");
 			return_value = ACQUIRE_FATAL_ERROR;
 		}
 	}
@@ -535,8 +585,8 @@ release_replica(Private_Repl_Protocol *prp)
 	PR_ASSERT(NULL != prp);
 	PR_ASSERT(NULL != prp->conn);
 
-    if (!prp->replica_acquired)
-        return;
+	if (!prp->replica_acquired)
+		return;
     
 	replarea_sdn = agmt_get_replarea(prp->agmt);
 	payload = NSDS50EndReplicationRequest_new((char *)slapi_sdn_get_dn(replarea_sdn)); /* XXXggood had to cast away const */
@@ -650,9 +700,14 @@ protocol_response2string (int response)
         case NSDS50_REPL_BELOW_PURGEPOINT:          return "csn below purge point";
         case NSDS50_REPL_INTERNAL_ERROR:            return "internal error";
         case NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED: return "replica released";
-        case NSDS50_REPL_LEGACY_CONSUMER:           return "replica is a legacy consumer";						
-		case NSDS50_REPL_REPLICAID_ERROR:			return "duplicate replica ID detected";
-		case NSDS50_REPL_UPTODATE:					return "no change to send";
+        case NSDS50_REPL_LEGACY_CONSUMER:           return "replica is a legacy consumer";
+        case NSDS50_REPL_REPLICAID_ERROR:           return "duplicate replica ID detected";
+        case NSDS50_REPL_UPTODATE:                  return "no change to send";
+        case NSDS50_REPL_CL_ERROR:                  return "changelog error";
+        case NSDS50_REPL_CONN_ERROR:                return "connection error";
+        case NSDS50_REPL_CONN_TIMEOUT:              return "connection timeout";
+        case NSDS50_REPL_TRANSIENT_ERROR:           return "transient error";
+        case NSDS50_REPL_RUV_ERROR:                 return "RUV error";
         default:                                    return "unknown error";
     }
 }
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
index 011e4ca..59e5298 100644
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
@@ -639,8 +639,8 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
 	}
 
 done:
-    if (mtnode_ext->replica)
-        object_release (mtnode_ext->replica);
+	if (mtnode_ext->replica)
+		object_release (mtnode_ext->replica);
 
 	/* slapi_ch_free accepts NULL pointer */
 	slapi_ch_free_string(&replica_root);
diff --git a/ldap/servers/plugins/replication/repl5_total.c b/ldap/servers/plugins/replication/repl5_total.c
index 0512dfa..dcb7af5 100644
--- a/ldap/servers/plugins/replication/repl5_total.c
+++ b/ldap/servers/plugins/replication/repl5_total.c
@@ -533,8 +533,9 @@ my_ber_scanf_value(BerElement *ber, Slapi_Value **value, PRBool *deleted)
 		goto loser;
 	}
 	
-    if (attrval)
-        ber_bvfree(attrval); 
+	if (attrval)
+		ber_bvfree(attrval);
+
 	return 0;
 
 loser:
-- 
2.4.11