andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 4 months ago
Clone
Blob Blame History Raw
From 752242e11be84f3ed9ad24dd02f593ce2591af90 Mon Sep 17 00:00:00 2001
From: Ludwig Krispenz <lkrispen@redhat.com>
Date: Thu, 12 Jan 2017 10:20:08 +0100
Subject: [PATCH 426/427] Ticket 49020 - v1.2.11 do not treat missing csn as
 fatal

    This patch removes the automatic choice of an alternative csn when
    the calculated anchor csn is not found.

    In that case it does no longer go to fatal state but will retry later.

    It also adds a configuration parameter to thr replication agreement to
    allow to pick a "next best" anchorcsn if the original is not found to
    keep replicatio going.

    Reviewed by: Noriko, William

(cherry picked from commit 55aa091b4b7ae812aff1fb7378374c02fdf478b3)
---
 ldap/schema/01core389.ldif                         |   3 +-
 ldap/servers/plugins/replication/cl5_api.c         |  16 ++-
 ldap/servers/plugins/replication/cl5_clcache.c     |  43 ++++----
 ldap/servers/plugins/replication/cl5_clcache.h     |   2 +-
 ldap/servers/plugins/replication/repl5.h           |   4 +
 ldap/servers/plugins/replication/repl5_agmt.c      | 115 ++++++++++++++++++++-
 ldap/servers/plugins/replication/repl5_agmtlist.c  |  13 +++
 .../plugins/replication/repl5_inc_protocol.c       |   7 +-
 ldap/servers/plugins/replication/repl_globals.c    |   1 +
 9 files changed, 168 insertions(+), 36 deletions(-)

diff --git a/ldap/schema/01core389.ldif b/ldap/schema/01core389.ldif
index afa4ee6..94dd6c6 100644
--- a/ldap/schema/01core389.ldif
+++ b/ldap/schema/01core389.ldif
@@ -160,6 +160,7 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2310 NAME 'nsds5ReplicaFlowControlWindow
 attributeTypes: ( 2.16.840.1.113730.3.1.2311 NAME 'nsds5ReplicaFlowControlPause' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' ) 
 attributeTypes: ( 2.16.840.1.113730.3.1.2332 NAME 'allowWeakDHParam' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2333 NAME 'nsds5ReplicaReleaseTimeout' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2335 NAME 'nsds5ReplicaIgnoreMissingChange' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
 #
 # objectclasses
 #
@@ -171,7 +172,7 @@ objectClasses: ( 2.16.840.1.113730.3.2.110 NAME 'nsMappingTree' DESC 'Netscape d
 objectClasses: ( 2.16.840.1.113730.3.2.104 NAME 'nsContainer' DESC 'Netscape defined objectclass' SUP top  MUST ( CN ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.108 NAME 'nsDS5Replica' DESC 'Netscape defined objectclass' SUP top  MUST ( nsDS5ReplicaRoot $  nsDS5ReplicaId ) MAY (cn $ nsds5ReplicaCleanRUV $ nsds5ReplicaAbortCleanRUV $ nsDS5ReplicaType $ nsDS5ReplicaBindDN $ nsState $ nsDS5ReplicaName $ nsDS5Flags $ nsDS5Task $ nsDS5ReplicaReferral $ nsDS5ReplicaAutoReferral $ nsds5ReplicaPurgeDelay $ nsds5ReplicaTombstonePurgeInterval $ nsds5ReplicaChangeCount $ nsds5ReplicaLegacyConsumer $ nsds5ReplicaReleaseTimeout) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.113 NAME 'nsTombstone' DESC 'Netscape defined objectclass' SUP top MAY ( nsParentUniqueId $ nscpEntryDN ) X-ORIGIN 'Netscape Directory Server' )
-objectClasses: ( 2.16.840.1.113730.3.2.103 NAME 'nsDS5ReplicationAgreement' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsds5ReplicaCleanRUVNotified $ nsDS5ReplicaHost $ nsDS5ReplicaPort $ nsDS5ReplicaTransportInfo $ nsDS5ReplicaBindDN $ nsDS5ReplicaCredentials $ nsDS5ReplicaBindMethod $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicatedAttributeListTotal $ nsDS5ReplicaUpdateSchedule $ nsds5BeginReplicaRefresh $ description $ nsds50ruv $ nsruvReplicaLastModified $ nsds5ReplicaTimeout $ nsds5replicaChangesSentSinceStartup $ nsds5replicaLastUpdateEnd $ nsds5replicaLastUpdateStart $ nsds5replicaLastUpdateStatus $ nsds5replicaUpdateInProgress $ nsds5replicaLastInitEnd $ nsds5ReplicaEnabled $ nsds5replicaLastInitStart $ nsds5replicaLastInitStatus $ nsds5debugreplicatimeout $ nsds5replicaBusyWaitTime $ nsds5ReplicaStripAttrs $ nsds5replicaSessionPauseTime  $ nsds5ReplicaFlowControlWindow $ nsds5ReplicaFlowControlPause ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.103 NAME 'nsDS5ReplicationAgreement' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsds5ReplicaCleanRUVNotified $ nsDS5ReplicaHost $ nsDS5ReplicaPort $ nsDS5ReplicaTransportInfo $ nsDS5ReplicaBindDN $ nsDS5ReplicaCredentials $ nsDS5ReplicaBindMethod $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicatedAttributeListTotal $ nsDS5ReplicaUpdateSchedule $ nsds5BeginReplicaRefresh $ description $ nsds50ruv $ nsruvReplicaLastModified $ nsds5ReplicaTimeout $ nsds5replicaChangesSentSinceStartup $ nsds5replicaLastUpdateEnd $ nsds5replicaLastUpdateStart $ nsds5replicaLastUpdateStatus $ nsds5replicaUpdateInProgress $ nsds5replicaLastInitEnd $ nsds5ReplicaEnabled $ nsds5replicaLastInitStart $ nsds5replicaLastInitStatus $ nsds5debugreplicatimeout $ nsds5replicaBusyWaitTime $ nsds5ReplicaStripAttrs $ nsds5replicaSessionPauseTime  $ nsds5ReplicaFlowControlWindow $ nsds5ReplicaFlowControlPause $ nsds5ReplicaIgnoreMissingChange ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.39 NAME 'nsslapdConfig' DESC 'Netscape defined objectclass' SUP top MAY ( cn ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.317 NAME 'nsSaslMapping' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSaslMapRegexString $ nsSaslMapBaseDNTemplate $ nsSaslMapFilterTemplate ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.43 NAME 'nsSNMP' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSNMPEnabled ) MAY ( nsSNMPOrganization $ nsSNMPLocation $ nsSNMPContact $ nsSNMPDescription $ nsSNMPName $ nsSNMPMasterHost $ nsSNMPMasterPort ) X-ORIGIN 'Netscape Directory Server' )
diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
index 9b2ef37..a97f626 100644
--- a/ldap/servers/plugins/replication/cl5_api.c
+++ b/ldap/servers/plugins/replication/cl5_api.c
@@ -337,7 +337,7 @@ static int _cl5WriteBervals (struct berval **bv, char** buff, unsigned int *size
 static PRBool _cl5ValidReplayIterator (const CL5ReplayIterator *iterator);
 #endif
 static int _cl5PositionCursorForReplay (ReplicaId consumerRID, const RUV *consumerRuv,
-			Object *replica, Object *fileObject, CL5ReplayIterator **iterator);
+		Object *replica, Object *fileObject, CL5ReplayIterator **iterator, int *continue_on_missing);
 static int _cl5CheckMissingCSN (const CSN *minCsn, const RUV *supplierRUV, CL5DBFile *file);
 
 /* changelog trimming */
@@ -1544,7 +1544,7 @@ int cl5CreateReplayIteratorEx (Private_Repl_Protocol *prp, const RUV *consumerRu
     	/* iterate through the ruv in csn order to find first master for which 
 	       we can replay changes */		    
 		
-		rc = _cl5PositionCursorForReplay (consumerRID, consumerRuv, replica, obj, iterator);
+		rc = _cl5PositionCursorForReplay (consumerRID, consumerRuv, replica, obj, iterator, NULL);
 	}
 	else
 	{
@@ -1605,7 +1605,13 @@ int cl5CreateReplayIterator (Private_Repl_Protocol *prp, const RUV *consumerRuv,
     	/* iterate through the ruv in csn order to find first master for which 
 	       we can replay changes */		    
 		ReplicaId consumerRID = agmt_get_consumer_rid ( prp->agmt, prp->conn );
-		rc = _cl5PositionCursorForReplay (consumerRID, consumerRuv, replica, obj, iterator);
+		int continue_on_missing = agmt_get_ignoremissing ( prp->agmt);
+		int save_cont_miss = continue_on_missing;
+		rc = _cl5PositionCursorForReplay (consumerRID, consumerRuv, replica, obj, iterator, &continue_on_missing);
+		if (save_cont_miss == 1 && continue_on_missing ==0) {
+			/* the option to continue once on a missing csn was used, rest */
+			agmt_set_ignoremissing ( prp->agmt, 0);
+		}
 	}
 	else
 	{
@@ -5445,7 +5451,7 @@ struct replica_hash_entry
 
 
 static int _cl5PositionCursorForReplay (ReplicaId consumerRID, const RUV *consumerRuv,
-		Object *replica, Object *fileObj, CL5ReplayIterator **iterator)
+		Object *replica, Object *fileObj, CL5ReplayIterator **iterator, int *continue_on_missing)
 {
 	CLC_Buffer *clcache = NULL;
 	CL5DBFile *file;
@@ -5489,7 +5495,7 @@ static int _cl5PositionCursorForReplay (ReplicaId consumerRID, const RUV *consum
 	rc = clcache_get_buffer ( &clcache, file->db, consumerRID, consumerRuv, supplierRuv );
 	if ( rc != 0 ) goto done;
 
-	rc = clcache_load_buffer (clcache, &startCSN);
+	rc = clcache_load_buffer (clcache, &startCSN, continue_on_missing);
 
         if (rc == 0) {
 		haveChanges = PR_TRUE;
diff --git a/ldap/servers/plugins/replication/cl5_clcache.c b/ldap/servers/plugins/replication/cl5_clcache.c
index f6c56a9..44b2817 100644
--- a/ldap/servers/plugins/replication/cl5_clcache.c
+++ b/ldap/servers/plugins/replication/cl5_clcache.c
@@ -354,7 +354,7 @@ clcache_return_buffer ( CLC_Buffer **buf )
  *		       historic reason.
  */
 int
-clcache_load_buffer ( CLC_Buffer *buf, CSN **anchorCSN )
+clcache_load_buffer ( CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss )
 {
 	int rc = 0;
         int flag = DB_NEXT;
@@ -375,6 +375,22 @@ clcache_load_buffer ( CLC_Buffer *buf, CSN **anchorCSN )
 		if (anchorCSN) *anchorCSN = buf->buf_current_csn;
 		rc = clcache_load_buffer_bulk ( buf, flag );
 
+		if (rc == DB_NOTFOUND && continue_on_miss && *continue_on_miss) {
+			/* make replication going using next best startcsn */
+			slapi_log_error(SLAPI_LOG_FATAL, buf->buf_agmt_name,
+					"clcache_load_buffer - Can't load changelog buffer starting at CSN %s with flag(%s). "
+					"Trying to use an alterantive start CSN.\n",
+					(char*)buf->buf_key.data,
+					flag==DB_NEXT?"DB_NEXT":"DB_SET" );
+			rc = clcache_load_buffer_bulk ( buf, DB_SET_RANGE );
+			if (rc == 0) {
+				slapi_log_error(SLAPI_LOG_FATAL, buf->buf_agmt_name,
+					"clcache_load_buffer - Using alternative start iteration csn: %s \n",
+					(char*)buf->buf_key.data);
+			}
+			/* the use of alternative start csns can be limited, record its usage */
+			(*continue_on_miss)--;
+		}
 		/* Reset some flag variables */
 		if ( rc == 0 ) {
 			int i;
@@ -437,23 +453,6 @@ retry:
 								 & buf->buf_key,
 								 & buf->buf_data,
 								 DB_SET );
-			if (rc == DB_NOTFOUND) {
-				/* the start position in the changelog is not found
-				 * 1. log an error
-				 * 2. try to find another starting position as close
-				 *    as possible
-				 */
-				slapi_log_error ( SLAPI_LOG_FATAL, "clcache_load_buffer_bulk",
-							"changelog record with csn (%s) not found for DB_NEXT\n",
-							(char *)buf->buf_key.data );
-				rc = cursor->c_get ( cursor, & buf->buf_key, & buf->buf_data,
-							 DB_SET_RANGE );
-				/* this moves the cursor ahead of the tageted csn,
-				 * so we achieved what was intended with DB_SET/DB_NEXT
-				 * continute at this csn.
-				 */
-				use_flag = DB_CURRENT;
-			}
 		}
 
 		/*
@@ -462,12 +461,6 @@ retry:
 		 */
 		if ( 0 == rc || DB_BUFFER_SMALL == rc ) {
 			rc = clcache_cursor_get ( cursor, buf, use_flag );
-			if ( rc == DB_NOTFOUND && use_flag == DB_SET) {
-				slapi_log_error ( SLAPI_LOG_FATAL, "clcache_load_buffer_bulk",
-							"changelog record with csn (%s) not found for DB_SET\n",
-							(char *)buf->buf_key.data );
-				rc = clcache_cursor_get ( cursor, buf, DB_SET_RANGE );
-			}
 		}
 
 	}
@@ -541,7 +534,7 @@ clcache_get_next_change ( CLC_Buffer *buf, void **key, size_t *keylen, void **da
 		 * We're done with the current buffer. Now load the next chunk.
 		 */
 		if ( NULL == *key && CLC_STATE_READY == buf->buf_state ) {
-			rc = clcache_load_buffer ( buf, NULL );
+			rc = clcache_load_buffer ( buf, NULL, NULL );
 			if ( 0 == rc && buf->buf_record_ptr ) {
 				DB_MULTIPLE_KEY_NEXT ( buf->buf_record_ptr, &buf->buf_data,
 								   *key, *keylen, *data, *datalen );
diff --git a/ldap/servers/plugins/replication/cl5_clcache.h b/ldap/servers/plugins/replication/cl5_clcache.h
index 5cab3cb..3ce210b 100644
--- a/ldap/servers/plugins/replication/cl5_clcache.h
+++ b/ldap/servers/plugins/replication/cl5_clcache.h
@@ -52,7 +52,7 @@ typedef struct clc_buffer CLC_Buffer;
 int	 clcache_init ( DB_ENV **dbenv );
 void clcache_set_config ();
 int	 clcache_get_buffer ( CLC_Buffer **buf, DB *db, ReplicaId consumer_rid, const RUV *consumer_ruv, const RUV *local_ruv );
-int	 clcache_load_buffer ( CLC_Buffer *buf, CSN **anchorCSN );
+int	 clcache_load_buffer ( CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss );
 void clcache_return_buffer ( CLC_Buffer **buf );
 int	 clcache_get_next_change ( CLC_Buffer *buf, void **key, size_t *keylen, void **data, size_t *datalen, CSN **csn );
 void clcache_destroy ();
diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
index 0db632e..80ef757 100644
--- a/ldap/servers/plugins/replication/repl5.h
+++ b/ldap/servers/plugins/replication/repl5.h
@@ -175,6 +175,7 @@ extern const char *type_nsds5ReplicaCleanRUVnotified;
 extern const char *type_nsds5ReplicaFlowControlWindow;
 extern const char *type_nsds5ReplicaFlowControlPause;
 extern const char *type_replicaReleaseTimeout;
+extern const char *type_replicaIgnoreMissingChange;
 
 /* Attribute names for windows replication agreements */
 extern const char *type_nsds7WindowsReplicaArea;
@@ -321,6 +322,7 @@ long agmt_get_busywaittime(const Repl_Agmt *ra);
 long agmt_get_pausetime(const Repl_Agmt *ra);
 long agmt_get_flowcontrolwindow(const Repl_Agmt *ra);
 long agmt_get_flowcontrolpause(const Repl_Agmt *ra);
+long agmt_get_ignoremissing(const Repl_Agmt *ra);
 int agmt_start(Repl_Agmt *ra);
 int windows_agmt_start(Repl_Agmt *ra); 
 int agmt_stop(Repl_Agmt *ra);
@@ -343,6 +345,7 @@ int agmt_set_schedule_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
 int agmt_set_timeout_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
 int agmt_set_flowcontrolwindow_from_entry(Repl_Agmt *ra, const Slapi_Entry *e);
 int agmt_set_flowcontrolpause_from_entry(Repl_Agmt *ra, const Slapi_Entry *e);
+int agmt_set_ignoremissing_from_entry(Repl_Agmt *ra, const Slapi_Entry *e);
 int agmt_set_busywaittime_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
 int agmt_set_pausetime_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
 int agmt_set_credentials_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
@@ -388,6 +391,7 @@ int agmt_set_enabled_from_entry(Repl_Agmt *ra, Slapi_Entry *e, char *returntext)
 char **agmt_get_attrs_to_strip(Repl_Agmt *ra);
 int agmt_set_attrs_to_strip(Repl_Agmt *ra, Slapi_Entry *e);
 int agmt_set_timeout(Repl_Agmt *ra, long timeout);
+int agmt_set_ignoremissing(Repl_Agmt *ra, long ignoremissing);
 void agmt_update_done(Repl_Agmt *ra, int is_total);
 
 typedef struct replica Replica;
diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c
index 41a81ca..4c67e57 100644
--- a/ldap/servers/plugins/replication/repl5_agmt.c
+++ b/ldap/servers/plugins/replication/repl5_agmt.c
@@ -150,6 +150,7 @@ typedef struct repl5agmt {
 	long flowControlPause; /* When nb of not acknowledged entries overpass totalUpdateWindow
 	                        * This is the duration (in msec) that the RA will pause before sending the next entry
 	                        */
+	long ignoreMissingChange;	/* if set replication will try to continue even if change cannot be found in changelog */
 } repl5agmt;
 
 /* Forward declarations */
@@ -159,7 +160,7 @@ static int get_agmt_status(Slapi_PBlock *pb, Slapi_Entry* e,
 	Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
 static int agmt_set_bind_method_no_lock(Repl_Agmt *ra, const Slapi_Entry *e);
 static int agmt_set_transportinfo_no_lock(Repl_Agmt *ra, const Slapi_Entry *e);
-
+static void agmt_replica_reset_ignoremissing (const Repl_Agmt *agmt);
 
 /*
 Schema for replication agreement:
@@ -362,6 +363,21 @@ agmt_new_from_entry(Slapi_Entry *e)
 		}
 	}
 
+	/* continue on missing change ? */
+	ra->ignoreMissingChange = 0;
+	tmpstr = slapi_entry_attr_get_charptr(e, type_replicaIgnoreMissingChange);
+	if (NULL != tmpstr)
+	{
+		if (strcasecmp(tmpstr,"off") == 0 || strcasecmp(tmpstr,"never") == 0) {
+			ra->ignoreMissingChange = 0;
+		} else if (strcasecmp(tmpstr,"on") == 0 || strcasecmp(tmpstr,"once") == 0) {
+			ra->ignoreMissingChange = 1;
+		} else if (strcasecmp(tmpstr,"always") == 0) {
+			ra->ignoreMissingChange = -1;
+		}
+		slapi_ch_free_string(&tmpstr);
+	}
+
 	/* DN of entry at root of replicated area */
 	tmpstr = slapi_entry_attr_get_charptr(e, type_nsds5ReplicaRoot);
 	if (NULL != tmpstr)
@@ -1012,6 +1028,16 @@ agmt_get_flowcontrolpause(const Repl_Agmt *ra)
 	PR_Unlock(ra->lock);
 	return return_value;
 }
+long
+agmt_get_ignoremissing(const Repl_Agmt *ra)
+{
+	long return_value;
+	PR_ASSERT(NULL != ra);
+	PR_Lock(ra->lock);
+	return_value = ra->ignoreMissingChange;
+	PR_Unlock(ra->lock);
+	return return_value;
+}
 /*
  * Warning - reference to the long name of the agreement is returned.
  * The long name of an agreement is the DN of the agreement entry,
@@ -1826,6 +1852,48 @@ agmt_set_flowcontrolpause_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
 	}
 	return return_value;
 }
+/* add comment here */
+int
+agmt_set_ignoremissing_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
+{
+	Slapi_Attr *sattr = NULL;
+	int return_value = -1;
+
+	PR_ASSERT(NULL != ra);
+	PR_Lock(ra->lock);
+	if (ra->stop_in_progress)
+	{
+		PR_Unlock(ra->lock);
+		return return_value;
+	}
+
+	slapi_entry_attr_find(e, type_replicaIgnoreMissingChange, &sattr);
+	if (NULL != sattr)
+	{
+		Slapi_Value *sval = NULL;
+		slapi_attr_first_value(sattr, &sval);
+		if (NULL != sval)
+		{
+			const char *tmpval = slapi_value_get_string(sval);
+			if (strcasecmp(tmpval,"off") == 0 || strcasecmp(tmpval,"never") == 0) {
+				ra->ignoreMissingChange = 0;
+				return_value = 0;
+			} else if (strcasecmp(tmpval,"on") == 0 || strcasecmp(tmpval,"once") == 0) {
+				ra->ignoreMissingChange = 1;
+				return_value = 0;
+			} else if (strcasecmp(tmpval,"always") == 0) {
+				ra->ignoreMissingChange = -1;
+				return_value = 0;
+			}
+		}
+	}
+	PR_Unlock(ra->lock);
+	if (return_value == 0)
+	{
+		prot_notify_agmt_changed(ra->protocol, ra->long_name);
+	}
+	return return_value;
+}
 
 int
 agmt_set_timeout(Repl_Agmt *ra, long timeout)
@@ -1867,6 +1935,20 @@ agmt_set_flowcontrolpause(Repl_Agmt *ra, long pause)
 
     return 0;
 }
+int
+agmt_set_ignoremissing(Repl_Agmt *ra, long ignoremissing)
+{
+    PR_Lock(ra->lock);
+    if (ra->stop_in_progress){
+        PR_Unlock(ra->lock);
+        return -1;
+    }
+    ra->ignoreMissingChange = ignoremissing;
+    PR_Unlock(ra->lock);
+    /* if reset to 0 update the entry */
+    agmt_replica_reset_ignoremissing(ra);
+    return 0;
+}
 
 /*
  * Set or reset the busywaittime
@@ -2101,6 +2183,37 @@ agmt_replica_init_done (const Repl_Agmt *agmt)
     slapi_pblock_destroy (pb);
 }
 
+
+/* delete nsds5replicaIgnoreMissingChange attribute */
+static void
+agmt_replica_reset_ignoremissing (const Repl_Agmt *agmt)
+{
+    int rc;
+    Slapi_PBlock *pb = slapi_pblock_new ();
+    LDAPMod *mods [2];
+    LDAPMod mod;
+
+    mods[0] = &mod;
+    mods[1] = NULL;
+    mod.mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
+    mod.mod_type = (char*)type_replicaIgnoreMissingChange;
+    mod.mod_bvalues = NULL;
+
+    slapi_modify_internal_set_pb_ext(pb, agmt->dn, mods, NULL/* controls */,
+          NULL/* uniqueid */, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0/* flags */);
+    slapi_modify_internal_pb (pb);
+
+    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+    if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_ATTRIBUTE)
+    {
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmt_replica_ignoremissing: "
+                        "failed to remove (%s) attribute from (%s) entry; LDAP error - %d\n",
+                        type_replicaIgnoreMissingChange, slapi_sdn_get_ndn (agmt->dn), rc);
+    }
+
+    slapi_pblock_destroy (pb);
+}
+
 /* Agreement object is acquired on behalf of the caller.
    The caller is responsible for releasing the object
    when it is no longer used */
diff --git a/ldap/servers/plugins/replication/repl5_agmtlist.c b/ldap/servers/plugins/replication/repl5_agmtlist.c
index caa41af..7789c3f 100644
--- a/ldap/servers/plugins/replication/repl5_agmtlist.c
+++ b/ldap/servers/plugins/replication/repl5_agmtlist.c
@@ -371,6 +371,19 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry
 			}
 		}
 		else if (slapi_attr_types_equivalent(mods[i]->mod_type,
+					type_replicaIgnoreMissingChange))
+		{
+			/* New replica timeout */
+			if (agmt_set_ignoremissing_from_entry(agmt, e) != 0)
+			{
+				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmtlist_modify_callback - "
+						"Failed to update the ignorMissingChange attribute for agreement %s\n",
+						agmt_get_long_name(agmt));
+				*returncode = LDAP_OPERATIONS_ERROR;
+				rc = SLAPI_DSE_CALLBACK_ERROR;
+			}
+		}
+		else if (slapi_attr_types_equivalent(mods[i]->mod_type,
 					type_nsds5ReplicaBusyWaitTime))
 		{
 			/* New replica busywaittime */
diff --git a/ldap/servers/plugins/replication/repl5_inc_protocol.c b/ldap/servers/plugins/replication/repl5_inc_protocol.c
index e6920e8..8cf72a1 100644
--- a/ldap/servers/plugins/replication/repl5_inc_protocol.c
+++ b/ldap/servers/plugins/replication/repl5_inc_protocol.c
@@ -1709,13 +1709,14 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu
 				"%s: Data required to update replica has been purged. "
 				"The replica must be reinitialized.\n",
 				agmt_get_long_name(prp->agmt));
-			return_value = UPDATE_FATAL_ERROR;
+			return_value = UPDATE_TRANSIENT_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",
+				"send_updates - %s: Missing data encountered. "
+				"If the error persists the replica must be reinitialized.\n",
 				agmt_get_long_name(prp->agmt));
-			return_value = UPDATE_FATAL_ERROR;
+			return_value = UPDATE_TRANSIENT_ERROR;
 			break;
 		case CL5_UNKNOWN_ERROR:   /* unclassified error */
 			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
diff --git a/ldap/servers/plugins/replication/repl_globals.c b/ldap/servers/plugins/replication/repl_globals.c
index 1d35241..4c9f274 100644
--- a/ldap/servers/plugins/replication/repl_globals.c
+++ b/ldap/servers/plugins/replication/repl_globals.c
@@ -135,6 +135,7 @@ const char *type_nsds5ReplicaCleanRUVnotified = "nsds5ReplicaCleanRUVNotified";
 const char* type_nsds5ReplicaFlowControlWindow = "nsds5ReplicaFlowControlWindow";
 const char* type_nsds5ReplicaFlowControlPause = "nsds5ReplicaFlowControlPause";
 
+const char* type_replicaIgnoreMissingChange = "nsds5ReplicaIgnoreMissingChange";
 
 /* windows sync specific attributes */
 const char *type_nsds7WindowsReplicaArea = "nsds7WindowsReplicaSubtree";
-- 
2.9.3