From 87591d510cc6ff0cbd7fdde2b189c234858fcc2c Mon Sep 17 00:00:00 2001
From: Quanah Gibson-Mount <quanah@openldap.org>
Date: Tue, 17 Mar 2009 17:47:57 +0000
Subject: [PATCH] More for ITS#6011

---
 servers/slapd/syncrepl.c | 81 ++++++++++++++++++++++++----------------
 1 file changed, 49 insertions(+), 32 deletions(-)

diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c
index e6a9a43f7f..fdf79b0849 100644
--- a/servers/slapd/syncrepl.c
+++ b/servers/slapd/syncrepl.c
@@ -41,6 +41,7 @@ typedef struct cookie_state {
 	ldap_pvt_thread_mutex_t	cs_mutex;
 	int	cs_num;
 	int cs_age;
+	int cs_ref;
 	struct berval *cs_vals;
 	int *cs_sids;
 } cookie_state;
@@ -1258,11 +1259,11 @@ do_syncrepl(
 	int i, defer = 1, fail = 0;
 	Backend *be;
 
-	Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl %s\n", si->si_ridtxt, 0, 0 );
-
 	if ( si == NULL )
 		return NULL;
 
+	Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl %s\n", si->si_ridtxt, 0, 0 );
+
 	/* Don't get stuck here while a pause is initiated */
 	while ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
 		if ( slapd_shutdown )
@@ -1271,6 +1272,9 @@ do_syncrepl(
 			ldap_pvt_thread_yield();
 	}
 
+	if ( !si->si_ctype )
+		goto deleted;
+
 	switch( abs( si->si_type ) ) {
 	case LDAP_SYNC_REFRESH_ONLY:
 	case LDAP_SYNC_REFRESH_AND_PERSIST:
@@ -1358,6 +1362,7 @@ reload:
 			goto reload;
 		}
 
+deleted:
 		/* We got deleted while running on cn=config */
 		if ( !si->si_ctype ) {
 			if ( si->si_conn )
@@ -1449,24 +1454,22 @@ reload:
 	if ( rc ) {
 		if ( fail == RETRYNUM_TAIL ) {
 			Debug( LDAP_DEBUG_ANY,
-				"do_syncrepl: %s quitting\n",
-				si->si_ridtxt, 0, 0 );
+				"do_syncrepl: %s rc %d quitting\n",
+				si->si_ridtxt, rc, 0 );
 		} else if ( fail > 0 ) {
 			Debug( LDAP_DEBUG_ANY,
-				"do_syncrepl: %s retrying (%d retries left)\n",
-				si->si_ridtxt, fail, 0 );
+				"do_syncrepl: %s rc %d retrying (%d retries left)\n",
+				si->si_ridtxt, rc, fail );
 		} else {
 			Debug( LDAP_DEBUG_ANY,
-				"do_syncrepl: %s retrying\n",
-				si->si_ridtxt, 0, 0 );
+				"do_syncrepl: %s rc %d retrying\n",
+				si->si_ridtxt, rc, 0 );
 		}
 	}
 
 	/* Do final delete cleanup */
 	if ( !si->si_ctype ) {
-		cookie_state *cs = si->si_cookieState;
-		syncinfo_free( si, ( !be->be_syncinfo ||
-			be->be_syncinfo->si_cookieState != cs ));
+		syncinfo_free( si, 0 );
 	}
 	return NULL;
 }
@@ -2181,8 +2184,8 @@ retry_add:;
 
 			rc = op->o_bd->be_add( op, &rs_add );
 			Debug( LDAP_DEBUG_SYNC,
-					"syncrepl_entry: %s be_add (%d)\n", 
-					si->si_ridtxt, rc, 0 );
+					"syncrepl_entry: %s be_add %s (%d)\n", 
+					si->si_ridtxt, op->o_req_dn.bv_val, rc );
 			switch ( rs_add.sr_err ) {
 			case LDAP_SUCCESS:
 				if ( op->ora_e == entry ) {
@@ -2244,8 +2247,8 @@ retry_add:;
 
 			default:
 				Debug( LDAP_DEBUG_ANY,
-					"syncrepl_entry: %s be_add failed (%d)\n",
-					si->si_ridtxt, rs_add.sr_err, 0 );
+					"syncrepl_entry: %s be_add %s failed (%d)\n",
+					si->si_ridtxt, op->o_req_dn.bv_val, rs_add.sr_err );
 				break;
 			}
 			syncCSN = NULL;
@@ -2384,7 +2387,7 @@ retry_add:;
 					}
 				}
 			}
-					
+
 			/* RDNs must be NUL-terminated for back-ldap */
 			noldp = op->orr_newrdn;
 			ber_dupbv_x( &op->orr_newrdn, &noldp, op->o_tmpmemctx );
@@ -2441,8 +2444,8 @@ retry_add:;
 
 			slap_mods_free( op->orr_modlist, 1 );
 			Debug( LDAP_DEBUG_SYNC,
-					"syncrepl_entry: %s be_modrdn (%d)\n", 
-					si->si_ridtxt, rc, 0 );
+					"syncrepl_entry: %s be_modrdn %s (%d)\n", 
+					si->si_ridtxt, op->o_req_dn.bv_val, rc );
 			op->o_bd = be;
 			/* Renamed entries may still have other mods so just fallthru */
 			op->o_req_dn = entry->e_name;
@@ -2463,8 +2466,8 @@ retry_add:;
 			slap_mods_free( op->orm_modlist, 1 );
 			op->orm_no_opattrs = 0;
 			Debug( LDAP_DEBUG_SYNC,
-					"syncrepl_entry: %s be_modify (%d)\n", 
-					si->si_ridtxt, rc, 0 );
+					"syncrepl_entry: %s be_modify %s (%d)\n", 
+					si->si_ridtxt, op->o_req_dn.bv_val, rc );
 			if ( rs_modify.sr_err != LDAP_SUCCESS ) {
 				Debug( LDAP_DEBUG_ANY,
 					"syncrepl_entry: %s be_modify failed (%d)\n",
@@ -2490,8 +2493,8 @@ retry_add:;
 			op->o_bd = si->si_wbe;
 			rc = op->o_bd->be_delete( op, &rs_delete );
 			Debug( LDAP_DEBUG_SYNC,
-					"syncrepl_entry: %s be_delete (%d)\n", 
-					si->si_ridtxt, rc, 0 );
+					"syncrepl_entry: %s be_delete %s (%d)\n", 
+					si->si_ridtxt, op->o_req_dn.bv_val, rc );
 
 			while ( rs_delete.sr_err == LDAP_SUCCESS
 				&& op->o_delete_glue_parent ) {
@@ -3596,7 +3599,11 @@ syncinfo_free( syncinfo_t *sie, int free_all )
 {
 	syncinfo_t *si_next;
 
-	if ( free_all && sie->si_cookieState ) {
+	Debug( LDAP_DEBUG_TRACE, "syncinfo_free: %s\n",
+		sie->si_ridtxt, 0, 0 );
+
+	sie->si_cookieState->cs_ref--;
+	if ( !sie->si_cookieState->cs_ref ) {
 		ch_free( sie->si_cookieState->cs_sids );
 		ber_bvarray_free( sie->si_cookieState->cs_vals );
 		ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_mutex );
@@ -4380,6 +4387,7 @@ add_syncrepl(
 
 			c->be->be_syncinfo = si;
 		}
+		si->si_cookieState->cs_ref++;
 
 		si->si_next = NULL;
 
@@ -4578,13 +4586,11 @@ syncrepl_config( ConfigArgs *c )
 		}
 		return 1;
 	} else if ( c->op == LDAP_MOD_DELETE ) {
-		cookie_state *cs = NULL;
 		int isrunning = 0;
 		if ( c->be->be_syncinfo ) {
 			syncinfo_t *si, **sip;
 			int i;
 
-			cs = c->be->be_syncinfo->si_cookieState;
 			for ( sip = &c->be->be_syncinfo, i=0; *sip; i++ ) {
 				si = *sip;
 				if ( c->valx == -1 || i == c->valx ) {
@@ -4596,11 +4602,28 @@ syncrepl_config( ConfigArgs *c )
 					if ( si->si_re ) {
 						if ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
 							isrunning = 1;
+						} else if ( si->si_conn ) {
+							isrunning = 1;
+							/* If there's a persistent connection, we don't
+							 * know if it's already got a thread queued.
+							 * so defer the free, but reschedule the task.
+							 * If there's a connection thread queued, it
+							 * will cleanup as necessary. If not, then the
+							 * runqueue task will cleanup.
+							 */
+							ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+							if ( !ldap_pvt_runqueue_isrunning( &slapd_rq, si->si_re )) {
+								si->si_re->interval.tv_sec = 0;
+								ldap_pvt_runqueue_resched( &slapd_rq, si->si_re, 0 );
+								si->si_re->interval.tv_sec = si->si_interval;
+							}
+							ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+
 						} else {
 							ldap_pvt_thread_mutex_unlock( &si->si_mutex );
 						}
 					}
-					if ( si->si_re && isrunning ) {
+					if ( isrunning ) {
 						si->si_ctype = 0;
 						si->si_next = NULL;
 					} else {
@@ -4615,12 +4638,6 @@ syncrepl_config( ConfigArgs *c )
 		}
 		if ( !c->be->be_syncinfo ) {
 			SLAP_DBFLAGS( c->be ) &= ~SLAP_DBFLAG_SHADOW_MASK;
-			if ( cs && !isrunning ) {
-				ch_free( cs->cs_sids );
-				ber_bvarray_free( cs->cs_vals );
-				ldap_pvt_thread_mutex_destroy( &cs->cs_mutex );
-				ch_free( cs );
-			}
 		}
 		return 0;
 	}
-- 
GitLab