Browse Source

Ticket 525 - Introducing a user visible configuration variable for controlling replication retry time

RFE Description:  The current replication backoff timer is hardcoded to have a minimum of 3 seconds,
                  and a max of 300 seconds.  Added two new config attributes to the replication config:

                     nsds5ReplicaBackoffMin
                     nsds5ReplicaBackoffMax

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

Reviewed by: nhosoi(Thanks!)
Mark Reynolds 12 years ago
parent
commit
41d95f84b1

+ 4 - 2
ldap/schema/01core389.ldif

@@ -149,7 +149,9 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2148 NAME 'rootdn-deny-host' DESC 'Netsc
 attributeTypes: ( 2.16.840.1.113730.3.1.2149 NAME 'rootdn-allow-ip' 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.2150 NAME 'rootdn-deny-ip' 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.2151 NAME 'nsslapd-plugin-depends-on-type' 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.2152 NAME 'nsds5ReplicaProtocolTimeout' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2152 NAME 'nsds5ReplicaProtocolTimeout' 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.2154 NAME 'nsds5ReplicaBackoffMin' 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.2155 NAME 'nsds5ReplicaBackoffMax' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
 #
 # objectclasses
 #
@@ -159,7 +161,7 @@ objectClasses: ( 2.16.840.1.113730.3.2.44 NAME 'nsIndex' DESC 'Netscape defined
 objectClasses: ( 2.16.840.1.113730.3.2.109 NAME 'nsBackendInstance' DESC 'Netscape defined objectclass' SUP top  MUST ( CN ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.110 NAME 'nsMappingTree' DESC 'Netscape defined objectclass' SUP top  MUST ( CN ) X-ORIGIN 'Netscape Directory Server' )
 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 $ nsds5ReplicaProtocolTimeout ) 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 $ nsds5ReplicaProtocolTimeout $ nsds5ReplicaBackoffMin $ nsds5ReplicaBackoffMax ) 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 $ nsds5ReplicaProtocolTimeout ) 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' )

+ 6 - 0
ldap/servers/plugins/replication/repl5.h

@@ -169,6 +169,8 @@ extern const char *type_nsds5ReplicaEnabled;
 extern const char *type_nsds5ReplicaStripAttrs;
 extern const char *type_nsds5ReplicaCleanRUVnotified;
 extern const char *type_replicaProtocolTimeout;
+extern const char *type_replicaBackoffMin;
+extern const char *type_replicaBackoffMax;
 
 /* Attribute names for windows replication agreements */
 extern const char *type_nsds7WindowsReplicaArea;
@@ -594,6 +596,10 @@ void replica_check_for_tasks(Replica*r, Slapi_Entry *e);
 void replica_update_state (time_t when, void *arg);
 void replica_reset_csn_pl(Replica *r);
 int replica_get_protocol_timeout(Replica *r);
+int replica_get_backoff_min(Replica *r);
+int replica_get_backoff_max(Replica *r);
+void replica_set_backoff_min(Replica *r, int min);
+void replica_set_backoff_max(Replica *r, int max);
 
 /* The functions below handles the state flag */
 /* Current internal state flags */

+ 54 - 8
ldap/servers/plugins/replication/repl5_inc_protocol.c

@@ -179,7 +179,6 @@ static const char* event2name (int event);
 static const char* op2string (int op);
 static int 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);
 
-
 /* Push a newly sent operation onto the tail of the list */
 static void repl5_int_push_operation(result_data *rd, repl5_inc_operation *it)
 {
@@ -261,7 +260,8 @@ repl5_inc_log_operation_failure(int operation_code, int ldap_error, char* ldap_e
 #endif
 
 /* Thread that collects results from async operations sent to the consumer */
-static void repl5_inc_result_threadmain(void *param) 
+static void
+repl5_inc_result_threadmain(void *param)
 {
 	result_data *rd = (result_data*) param;
 	ConnResult conres = 0;
@@ -529,12 +529,12 @@ repl5_inc_delete(Private_Repl_Protocol **prpp)
 
 /* helper function */
 void
-set_pause_and_busy_time(long *pausetime, long *busywaittime)
+set_pause_and_busy_time(Private_Repl_Protocol *prp, long *pausetime, long *busywaittime)
 {
   /* If neither are set, set busy time to its default */
   if (!*pausetime && !*busywaittime)
     {
-      *busywaittime = PROTOCOL_BUSY_BACKOFF_MINIMUM;
+      *busywaittime = repl5_get_backoff_min(prp);
     }
   /* pause time must be at least 1 more than the busy backoff time */
   if (*pausetime && !*busywaittime)
@@ -683,7 +683,7 @@ repl5_inc_run(Private_Repl_Protocol *prp)
               busywaittime = agmt_get_busywaittime(prp->agmt);
               if (pausetime || busywaittime){
                   /* helper function to make sure they are set correctly */
-                  set_pause_and_busy_time(&pausetime, &busywaittime);
+                  set_pause_and_busy_time(prp, &pausetime, &busywaittime);
               }
               break;
 
@@ -842,12 +842,12 @@ repl5_inc_run(Private_Repl_Protocol *prp)
               if (use_busy_backoff_timer){
                   /* we received a busy signal from the consumer, wait for a while */
                   if (!busywaittime){
-                      busywaittime = PROTOCOL_BUSY_BACKOFF_MINIMUM;
+                      busywaittime = repl5_get_backoff_min(prp);
                   }
                   prp_priv->backoff = backoff_new(BACKOFF_FIXED, busywaittime, busywaittime);
               } else {
-                  prp_priv->backoff = backoff_new(BACKOFF_EXPONENTIAL, PROTOCOL_BACKOFF_MINIMUM,
-					                              PROTOCOL_BACKOFF_MAXIMUM);
+                  prp_priv->backoff = backoff_new(BACKOFF_EXPONENTIAL, repl5_get_backoff_min(prp),
+                		  repl5_get_backoff_max(prp));
               }
               next_state = STATE_BACKOFF;
               backoff_reset(prp_priv->backoff, repl5_inc_backoff_expired, (void *)prp);
@@ -2227,3 +2227,49 @@ op2string(int op)
 
 	return "unknown";
 }
+
+void
+repl5_set_backoff_min(Private_Repl_Protocol *prp, int min)
+{
+	Replica *replica;
+
+	replica = (Replica *)object_get_data(prp->replica_object);
+	if(replica){
+		replica_set_backoff_min(replica, min);
+	}
+}
+
+void
+repl5_set_backoff_max(Private_Repl_Protocol *prp, int max)
+{
+	Replica *replica;
+
+	replica = object_get_data(prp->replica_object);
+	if(replica){
+		replica_set_backoff_max(replica, max);
+	}
+}
+
+int
+repl5_get_backoff_min(Private_Repl_Protocol *prp)
+{
+	Replica *replica;
+
+	replica = object_get_data(prp->replica_object);
+	if(replica){
+		return (int)replica_get_backoff_min(replica);
+	}
+	return PROTOCOL_BACKOFF_MINIMUM;
+}
+
+int
+repl5_get_backoff_max(Private_Repl_Protocol *prp)
+{
+	Replica *replica;
+
+	replica = object_get_data(prp->replica_object);
+	if(replica){
+		return (int)replica_get_backoff_max(replica);
+	}
+	return PROTOCOL_BACKOFF_MAXIMUM;
+}

+ 4 - 0
ldap/servers/plugins/replication/repl5_prot_private.h

@@ -108,5 +108,9 @@ char* protocol_response2string (int response);
 int repl5_strip_fractional_mods(Repl_Agmt *agmt, LDAPMod **);
 void windows_release_replica(Private_Repl_Protocol *prp);
 int windows_acquire_replica(Private_Repl_Protocol *prp, RUV **ruv, int check_ruv);
+void repl5_set_backoff_min(Private_Repl_Protocol *prp, int min);
+void repl5_set_backoff_max(Private_Repl_Protocol *prp, int max);
+int repl5_get_backoff_min(Private_Repl_Protocol *prp);
+int repl5_get_backoff_max(Private_Repl_Protocol *prp);
 
 #endif /* _REPL5_PROT_PRIVATE_H_ */

+ 160 - 135
ldap/servers/plugins/replication/repl5_replica.c

@@ -82,12 +82,14 @@ struct replica {
 	PRUint32 repl_purge_delay;		/* When purgeable, CSNs are held on to for this many extra seconds */
 	PRBool tombstone_reap_stop;		/* TRUE when the tombstone reaper should stop */
 	PRBool tombstone_reap_active;	/* TRUE when the tombstone reaper is running */
-	long tombstone_reap_interval; /* Time in seconds between tombstone reaping */
+	long tombstone_reap_interval; 	/* Time in seconds between tombstone reaping */
 	Slapi_ValueSet *repl_referral;  /* A list of administrator provided referral URLs */
 	PRBool state_update_inprogress; /* replica state is being updated */
-	PRLock *agmt_lock;          /* protects agreement creation, start and stop */
-	char *locking_purl;			/* supplier who has exclusive access */
-	PRUint64 protocol_timeout;           /* protocol shutdown timeout */
+	PRLock *agmt_lock;          	/* protects agreement creation, start and stop */
+	char *locking_purl;				/* supplier who has exclusive access */
+	PRUint64 protocol_timeout;		/* protocol shutdown timeout */
+	PRUint64 backoff_min;			/* backoff retry minimum */
+	PRUint64 backoff_max;			/* backoff retry maximum */
 };
 
 
@@ -1631,64 +1633,86 @@ _replica_check_validity (const Replica *r)
 static int 
 _replica_init_from_config (Replica *r, Slapi_Entry *e, char *errortext)
 {
-	int rc;
-	Slapi_Attr *attr;
-	char *val;
-	CSNGen *gen; 
+    Slapi_Attr *a = NULL;
+    Slapi_Attr *attr;
+    CSNGen *gen;
     char buf [SLAPI_DSE_RETURNTEXT_SIZE];
     char *errormsg = errortext? errortext : buf;
-	Slapi_Attr *a = NULL;
+    char *val;
+    int backoff_min;
+    int backoff_max;
+    int rc;
 
-	PR_ASSERT (r && e);
+    PR_ASSERT (r && e);
 
     /* get replica root */
-	val = slapi_entry_attr_get_charptr (e, attr_replicaRoot);
-    if (val == NULL)
-    {
+    val = slapi_entry_attr_get_charptr (e, attr_replicaRoot);
+    if (val == NULL){
         PR_snprintf (errormsg, SLAPI_DSE_RETURNTEXT_SIZE, "failed to retrieve %s attribute from (%s)\n", 
                  attr_replicaRoot,
 				 (char*)slapi_entry_get_dn ((Slapi_Entry*)e));
         slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_replica_init_from_config: %s\n",
                         errormsg);
-                        
         return -1;	
     }
     
     r->repl_root = slapi_sdn_new_dn_passin (val);
 
-	/* get replica type */
+    /* get replica type */
     val = slapi_entry_attr_get_charptr (e, attr_replicaType);
-    if (val)
-    {
+    if (val){
 	    r->repl_type = atoi(val);
         slapi_ch_free ((void**)&val);
-    }
-    else
-    {
+    } else {
         r->repl_type = REPLICA_TYPE_READONLY;
     }
 
     /* get legacy consumer flag */
     val = slapi_entry_attr_get_charptr (e, type_replicaLegacyConsumer);
-    if (val)
-    {
+    if (val){
         if (strcasecmp (val, "on") == 0 || strcasecmp (val, "yes") == 0 ||
             strcasecmp (val, "true") == 0 || strcasecmp (val, "1") == 0)
         {
 	        r->legacy_consumer = PR_TRUE;
-        }
-        else
-        {
+        } else {
             r->legacy_consumer = PR_FALSE;
         }
-
         slapi_ch_free ((void**)&val);
-    }
-    else
-    {
+    } else {
         r->legacy_consumer = PR_FALSE;
     }
 
+    /* grab and validate the backoff retry settings */
+    backoff_min = slapi_entry_attr_get_int(e, type_replicaBackoffMin);
+    if(backoff_min <= 0){
+        if (backoff_min != 0){
+            slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Invalid value for %s: %d  Using default value (%d)\n",
+                type_replicaBackoffMin, backoff_min, PROTOCOL_BACKOFF_MINIMUM );
+        }
+        backoff_min = PROTOCOL_BACKOFF_MINIMUM;
+    }
+
+    backoff_max = slapi_entry_attr_get_int(e, type_replicaBackoffMax);
+    if(backoff_max <= 0){
+        if(backoff_max != 0) {
+            slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Invalid value for %s: %d  Using default value (%d)\n",
+                type_replicaBackoffMax, backoff_max, PROTOCOL_BACKOFF_MAXIMUM );
+        }
+        backoff_max = PROTOCOL_BACKOFF_MAXIMUM;
+    }
+    if(backoff_min > backoff_max){
+        /* Ok these values are invalid, reset back the defaults */
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Backoff minimum (%d) can not be greater than "
+            "the backoff maximum (%d).  Using default values: min (%d) max (%d)\n", backoff_min, backoff_max,
+            PROTOCOL_BACKOFF_MINIMUM, PROTOCOL_BACKOFF_MAXIMUM);
+        r->backoff_min = PROTOCOL_BACKOFF_MINIMUM;
+        r->backoff_max = PROTOCOL_BACKOFF_MAXIMUM;
+    } else {
+        r->backoff_min = backoff_min;
+        r->backoff_max = backoff_max;
+    }
+
+    /* get the protocol timeout */
     r->protocol_timeout = slapi_entry_attr_get_int(e, type_replicaProtocolTimeout);
     if(r->protocol_timeout == 0){
         r->protocol_timeout = DEFAULT_PROTOCOL_TIMEOUT;
@@ -1697,131 +1721,108 @@ _replica_init_from_config (Replica *r, Slapi_Entry *e, char *errortext)
     /* get replica flags */
     r->repl_flags = slapi_entry_attr_get_ulong(e, attr_flags);
 
-	/* get replicaid */
-	/* the replica id is ignored for read only replicas and is set to the
-	   special value READ_ONLY_REPLICA_ID */
-	if (r->repl_type == REPLICA_TYPE_READONLY)
-	{
-		r->repl_rid = READ_ONLY_REPLICA_ID;
-		slapi_entry_attr_set_uint(e, attr_replicaId, (unsigned int)READ_ONLY_REPLICA_ID);
-	}
-	/* a replica id is required for updatable and primary replicas */
-	else if (r->repl_type == REPLICA_TYPE_UPDATABLE ||
-			 r->repl_type == REPLICA_TYPE_PRIMARY)
-	{
-		if ((val = slapi_entry_attr_get_charptr (e, attr_replicaId)))
-		{
-			int temprid = atoi (val);
-			slapi_ch_free ((void**)&val);
-			if (temprid <= 0 || temprid >= READ_ONLY_REPLICA_ID)
-			{
-				PR_snprintf (errormsg, SLAPI_DSE_RETURNTEXT_SIZE,
-						 "attribute %s must have a value greater than 0 "
-						 "and less than %d: entry %s",
-						 attr_replicaId, READ_ONLY_REPLICA_ID,
-						 (char*)slapi_entry_get_dn ((Slapi_Entry*)e));
-				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
-								"_replica_init_from_config: %s\n",
-								errormsg);
-				return -1;
-			}
-			else
-			{
-				r->repl_rid = (ReplicaId)temprid;
-			}
-		}
-		else
-		{
-			PR_snprintf (errormsg, SLAPI_DSE_RETURNTEXT_SIZE,
-						 "failed to retrieve required %s attribute from %s",
-					 attr_replicaId,
-					 (char*)slapi_entry_get_dn ((Slapi_Entry*)e));
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
-							"_replica_init_from_config: %s\n",
-							errormsg);
-			return -1;
-		}
-	}
+    /*
+     * Get replicaid
+     * The replica id is ignored for read only replicas and is set to the
+     * special value READ_ONLY_REPLICA_ID
+     */
+    if (r->repl_type == REPLICA_TYPE_READONLY){
+        r->repl_rid = READ_ONLY_REPLICA_ID;
+        slapi_entry_attr_set_uint(e, attr_replicaId, (unsigned int)READ_ONLY_REPLICA_ID);
+    }
+    /* a replica id is required for updatable and primary replicas */
+    else if (r->repl_type == REPLICA_TYPE_UPDATABLE ||
+             r->repl_type == REPLICA_TYPE_PRIMARY)
+    {
+	    if ((val = slapi_entry_attr_get_charptr (e, attr_replicaId))){
+            int temprid = atoi (val);
+            slapi_ch_free ((void**)&val);
+            if (temprid <= 0 || temprid >= READ_ONLY_REPLICA_ID){
+                PR_snprintf (errormsg, SLAPI_DSE_RETURNTEXT_SIZE,
+                    "attribute %s must have a value greater than 0 "
+                    "and less than %d: entry %s",
+                    attr_replicaId, READ_ONLY_REPLICA_ID,
+                    (char*)slapi_entry_get_dn ((Slapi_Entry*)e));
+                    slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+                        "_replica_init_from_config: %s\n", errormsg);
+                return -1;
+            } else {
+                r->repl_rid = (ReplicaId)temprid;
+            }
+        } else {
+            PR_snprintf (errormsg, SLAPI_DSE_RETURNTEXT_SIZE,
+                "failed to retrieve required %s attribute from %s",
+                attr_replicaId,(char*)slapi_entry_get_dn ((Slapi_Entry*)e));
+            slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+                "_replica_init_from_config: %s\n", errormsg);
+            return -1;
+        }
+    }
 
-	attr = NULL;
-	rc = slapi_entry_attr_find(e, attr_state, &attr);
-	gen = csngen_new (r->repl_rid, attr);
-	if (gen == NULL)
-	{
+    attr = NULL;
+    rc = slapi_entry_attr_find(e, attr_state, &attr);
+    gen = csngen_new (r->repl_rid, attr);
+    if (gen == NULL){
         PR_snprintf (errormsg, SLAPI_DSE_RETURNTEXT_SIZE,
-					 "failed to create csn generator for replica (%s)",
-					 (char*)slapi_entry_get_dn ((Slapi_Entry*)e));
+            "failed to create csn generator for replica (%s)",
+            (char*)slapi_entry_get_dn ((Slapi_Entry*)e));
         slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
-						"_replica_init_from_config: %s\n",
-						errormsg);
-		return -1;
-	}
-	r->repl_csngen = object_new((void*)gen, (FNFree)csngen_free);
+            "_replica_init_from_config: %s\n", errormsg);
+        return -1;
+    }
+    r->repl_csngen = object_new((void*)gen, (FNFree)csngen_free);
 
-	/* Hook generator so we can maintain min/max CSN info */
-	r->csn_pl_reg_id = csngen_register_callbacks(gen, assign_csn_callback, r, abort_csn_callback, r);
+    /* Hook generator so we can maintain min/max CSN info */
+    r->csn_pl_reg_id = csngen_register_callbacks(gen, assign_csn_callback, r, abort_csn_callback, r);
 
-	/* get replication bind dn */
-	r->updatedn_list = replica_updatedn_list_new(e);
+    /* get replication bind dn */
+    r->updatedn_list = replica_updatedn_list_new(e);
 
     /* get replica name */
     val = slapi_entry_attr_get_charptr (e, attr_replicaName);
     if (val) {
-		r->repl_name = val;
-	}
-    else
-    {
+        r->repl_name = val;
+    } else {
         rc = slapi_uniqueIDGenerateString (&r->repl_name);
-        if (rc != UID_SUCCESS)
-	    {
+        if (rc != UID_SUCCESS){
             PR_snprintf (errormsg, SLAPI_DSE_RETURNTEXT_SIZE,
-						 "failed to assign replica name for replica (%s); "
-                     "uuid generator error - %d ",
-					 (char*)slapi_entry_get_dn ((Slapi_Entry*)e),
-					 rc);
+                "failed to assign replica name for replica (%s); uuid generator error - %d ",
+                (char*)slapi_entry_get_dn ((Slapi_Entry*)e), rc);
             slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_replica_init_from_config: %s\n",
-                            errormsg);
+                errormsg);
 		    return -1;
-	    }  
-        else
+        } else
             r->new_name = PR_TRUE;          
     }
 
-	/* get the list of referrals */
-	slapi_entry_attr_find( e, attr_replicaReferral, &attr );
-	if(attr!=NULL)
-	{
-		slapi_attr_get_valueset(attr, &r->repl_referral);
-	}
+    /* get the list of referrals */
+    slapi_entry_attr_find( e, attr_replicaReferral, &attr );
+    if(attr!=NULL){
+        slapi_attr_get_valueset(attr, &r->repl_referral);
+    }
 
-	/*
-	 * Set the purge offset (default 7 days). This is the extra
-	 * time we allow purgeable CSNs to stick around, in case a
-	 * replica regresses. Could also be useful when LCUP happens,
-	 * since we don't know about LCUP replicas, and they can just
-	 * turn up whenever they want to.
-	 */
-	if (slapi_entry_attr_find(e, type_replicaPurgeDelay, &a) == -1)
-	{
-		/* No purge delay provided, so use default */
-		r->repl_purge_delay = 60 * 60 * 24 * 7; /* One week, in seconds */
-	}
-	else
-	{
-		r->repl_purge_delay = slapi_entry_attr_get_uint(e, type_replicaPurgeDelay);
-	}
+    /*
+     * Set the purge offset (default 7 days). This is the extra
+     * time we allow purgeable CSNs to stick around, in case a
+     * replica regresses. Could also be useful when LCUP happens,
+     * since we don't know about LCUP replicas, and they can just
+     * turn up whenever they want to.
+     */
+    if (slapi_entry_attr_find(e, type_replicaPurgeDelay, &a) == -1){
+        /* No purge delay provided, so use default */
+        r->repl_purge_delay = 60 * 60 * 24 * 7; /* One week, in seconds */
+    } else {
+        r->repl_purge_delay = slapi_entry_attr_get_uint(e, type_replicaPurgeDelay);
+    }
 
-	if (slapi_entry_attr_find(e, type_replicaTombstonePurgeInterval, &a) == -1)
-	{
-		/* No reap interval provided, so use default */
-		r->tombstone_reap_interval = 3600 * 24; /* One day */
-	}
-	else
-	{
-		r->tombstone_reap_interval = slapi_entry_attr_get_int(e, type_replicaTombstonePurgeInterval);
-	}
+    if (slapi_entry_attr_find(e, type_replicaTombstonePurgeInterval, &a) == -1){
+        /* No reap interval provided, so use default */
+        r->tombstone_reap_interval = 3600 * 24; /* One day */
+    } else {
+        r->tombstone_reap_interval = slapi_entry_attr_get_int(e, type_replicaTombstonePurgeInterval);
+    }
 
-	r->tombstone_reap_stop = r->tombstone_reap_active = PR_FALSE;
+    r->tombstone_reap_stop = r->tombstone_reap_active = PR_FALSE;
 
     return (_replica_check_validity (r));
 }
@@ -3828,3 +3829,27 @@ replica_get_attr ( Slapi_PBlock *pb, const char* type, void *value )
 
 	return rc;
 }
+
+int
+replica_get_backoff_min(Replica *r)
+{
+	return (int)r->backoff_min;
+}
+
+int
+replica_get_backoff_max(Replica *r)
+{
+	return (int)r->backoff_max;
+}
+
+void
+replica_set_backoff_min(Replica *r, int min)
+{
+	r->backoff_min = min;
+}
+
+void
+replica_set_backoff_max(Replica *r, int max)
+{
+	r->backoff_max = max;
+}

+ 2 - 0
ldap/servers/plugins/replication/repl_globals.c

@@ -113,6 +113,8 @@ const char *type_ruvElementUpdatetime = "nsruvReplicaLastModified";
 const char *type_replicaCleanRUV = "nsds5ReplicaCleanRUV";
 const char *type_replicaAbortCleanRUV = "nsds5ReplicaAbortCleanRUV";
 const char *type_replicaProtocolTimeout = "nsds5ReplicaProtocolTimeout";
+const char *type_replicaBackoffMin = "nsds5ReplicaBackoffMin";
+const char *type_replicaBackoffMax = "nsds5ReplicaBackoffMax";
 
 /* Attribute names for replication agreement attributes */
 const char *type_nsds5ReplicaHost = "nsds5ReplicaHost";

+ 9 - 11
ldap/servers/plugins/replication/windows_inc_protocol.c

@@ -182,13 +182,13 @@ windows_inc_delete(Private_Repl_Protocol **prpp)
 
 /* helper function */
 void
-w_set_pause_and_busy_time(long *pausetime, long *busywaittime)
+w_set_pause_and_busy_time(Private_Repl_Protocol *prp, long *pausetime, long *busywaittime)
 {
 	LDAPDebug0Args( LDAP_DEBUG_TRACE, "=> w_set_pause_and_busy_time\n" );
   /* If neither are set, set busy time to its default */
   if (!*pausetime && !*busywaittime)
     {
-      *busywaittime = PROTOCOL_BUSY_BACKOFF_MINIMUM;
+      *busywaittime = repl5_get_backoff_min(prp);
     }
   /* pause time must be at least 1 more than the busy backoff time */
   if (*pausetime && !*busywaittime)
@@ -354,7 +354,7 @@ windows_inc_run(Private_Repl_Protocol *prp)
 				if (pausetime || busywaittime)
 				{
 					/* helper function to make sure they are set correctly */
-					w_set_pause_and_busy_time(&pausetime, &busywaittime);
+					w_set_pause_and_busy_time(prp, &pausetime, &busywaittime);
 				}
 
 				/* Check if the interval changed */
@@ -609,17 +609,15 @@ windows_inc_run(Private_Repl_Protocol *prp)
 					if (use_busy_backoff_timer)
 					{
 					  /* we received a busy signal from the consumer, wait for a while */
-					  if (!busywaittime)
-						{
-					  busywaittime = PROTOCOL_BUSY_BACKOFF_MINIMUM;
-						}
-					  prp_priv->backoff = backoff_new(BACKOFF_FIXED, busywaittime,
-									  busywaittime);
+					  if (!busywaittime){
+						  busywaittime = repl5_get_backoff_min(prp);
+					  }
+					  prp_priv->backoff = backoff_new(BACKOFF_FIXED, busywaittime, busywaittime);
 					}
 					else
 					{
-					  prp_priv->backoff = backoff_new(BACKOFF_EXPONENTIAL, PROTOCOL_BACKOFF_MINIMUM,
-									  PROTOCOL_BACKOFF_MAXIMUM);
+					  prp_priv->backoff = backoff_new(BACKOFF_EXPONENTIAL, repl5_get_backoff_min(prp),
+									  repl5_get_backoff_max(prp) );
 					}
 					next_state = STATE_BACKOFF;
 					backoff_reset(prp_priv->backoff, windows_inc_backoff_expired, (void *)prp);