From 7a4016d2820e5b8740817783a56b19311b16075c Mon Sep 17 00:00:00 2001
From: Ludwig Krispenz <lkrispen@redhat.com>
Date: Fri, 20 Dec 2013 14:52:44 +0100
Subject: [PATCH] Ticket 47629 - random crashes related to sync repl

Bug Description:  if there is no cookie, the persist thread starts
        before the initial refresh is complete, both threads use the
	same operation structure and there is a race condition
	on setting and freeing the search entry.

Fix Description:   ensure that the persist thread only starts sending
	updates once the refresh is complete

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

Reviewed by: ?
---
 ldap/servers/plugins/sync/sync.h         |  7 ++++---
 ldap/servers/plugins/sync/sync_persist.c |  3 ++-
 ldap/servers/plugins/sync/sync_refresh.c | 18 ++++++++++++------
 3 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/ldap/servers/plugins/sync/sync.h b/ldap/servers/plugins/sync/sync.h
index cf73ce9..8cdc7d0 100644
--- a/ldap/servers/plugins/sync/sync.h
+++ b/ldap/servers/plugins/sync/sync.h
@@ -115,7 +115,7 @@ int sync_is_active (Slapi_Entry *e, Slapi_PBlock *pb);
 int sync_is_active_scope (const Slapi_DN *dn, Slapi_PBlock *pb);
 
 int sync_refresh_update_content(Slapi_PBlock *pb, Sync_Cookie *client_cookie, Sync_Cookie *session_cookie);
-int sync_refresh_initial_content(Slapi_PBlock *pb, int persist, Sync_Cookie *session_cookie);
+int sync_refresh_initial_content(Slapi_PBlock *pb, int persist, PRThread *tid, Sync_Cookie *session_cookie);
 int sync_read_entry_from_changelog( Slapi_Entry *cl_entry, void *cb_data);
 int sync_send_entry_from_changelog( Slapi_PBlock *pb, int chg_req, char *uniqueid);
 void sync_send_deleted_entries (Slapi_PBlock *pb, Sync_UpdateNode *upd, int chg_count, Sync_Cookie *session_cookie);
@@ -190,7 +190,8 @@ typedef struct sync_request_list {
 #define SYNC_FLAG_SEND_INTERMEDIATE	0x08
 
 typedef struct sync_op_info {
-	int send_flag; /* hint for preop plugins what to send */
-	Sync_Cookie *cookie; /* cookie to add in control */
+	int send_flag;		/* hint for preop plugins what to send */
+	Sync_Cookie	*cookie;/* cookie to add in control */
+	PRThread	*tid;	/* thread for persistent phase */
 } SyncOpInfo;
 
diff --git a/ldap/servers/plugins/sync/sync_persist.c b/ldap/servers/plugins/sync/sync_persist.c
index 7cd65c8..680bcf6 100644
--- a/ldap/servers/plugins/sync/sync_persist.c
+++ b/ldap/servers/plugins/sync/sync_persist.c
@@ -351,7 +351,8 @@ sync_persist_terminate (PRThread *tid)
 	  	cur = sync_request_list->sync_req_head;
 	  	while ( NULL != cur ) {
 			if ( cur->req_tid == tid ) {
-				cur->req_active = PR_TRUE;
+				cur->req_active = PR_FALSE;
+				cur->req_complete = PR_TRUE;
 				rc = 0;
 				break;
 			}
diff --git a/ldap/servers/plugins/sync/sync_refresh.c b/ldap/servers/plugins/sync/sync_refresh.c
index 71a0edd..18f7884 100644
--- a/ldap/servers/plugins/sync/sync_refresh.c
+++ b/ldap/servers/plugins/sync/sync_refresh.c
@@ -37,7 +37,7 @@
 
 #include "sync.h"
 
-static SyncOpInfo *new_SyncOpInfo(int flag, Sync_Cookie *cookie);
+static SyncOpInfo *new_SyncOpInfo(int flag, PRThread *tid, Sync_Cookie *cookie);
 
 static int sync_extension_type;
 static int sync_extension_handle;
@@ -157,7 +157,7 @@ int sync_srch_refresh_pre_search(Slapi_PBlock *pb)
 					sync_result_err(pb,rc, "Invalid session cookie");
 				}
 			} else {
-				rc = sync_refresh_initial_content (pb, sync_persist, session_cookie);
+				rc = sync_refresh_initial_content (pb, sync_persist,  tid, session_cookie);
 				if (rc == 0 && !sync_persist)
 					/* maintained in postop code */
 					session_cookie = NULL;
@@ -172,8 +172,9 @@ int sync_srch_refresh_pre_search(Slapi_PBlock *pb)
 				Slapi_Operation *operation;
 
 				slapi_pblock_get(pb, SLAPI_OPERATION, &operation);
-				rc = sync_persist_startup(tid, session_cookie);
-				
+				if (client_cookie) {
+					rc = sync_persist_startup(tid, session_cookie);
+				}
 				if (rc == 0) {
 					session_cookie = NULL; /* maintained in persist code */
 					slapi_operation_set_flag(operation, OP_FLAG_SYNC_PERSIST);
@@ -216,6 +217,8 @@ int sync_srch_refresh_post_search(Slapi_PBlock *pb)
 		 * depending on the operation type, reset flag
 		 */
 		info->send_flag &= ~SYNC_FLAG_ADD_STATE_CTRL;
+		/* activate the persistent phase thread*/
+		sync_persist_startup(info->tid, info->cookie);
 	}
 	if (info->send_flag & SYNC_FLAG_ADD_DONE_CTRL) {
 		LDAPControl **ctrl = (LDAPControl **)slapi_ch_calloc(2, sizeof (LDAPControl *));
@@ -320,7 +323,7 @@ sync_refresh_update_content(Slapi_PBlock *pb, Sync_Cookie *client_cookie, Sync_C
 }
 
 int
-sync_refresh_initial_content(Slapi_PBlock *pb, int sync_persist, Sync_Cookie *sc)
+sync_refresh_initial_content(Slapi_PBlock *pb, int sync_persist, PRThread *tid, Sync_Cookie *sc)
 {
 	/* the entries will be sent in the normal search process, but
 	 * - a control has to be sent with each entry
@@ -341,11 +344,13 @@ sync_refresh_initial_content(Slapi_PBlock *pb, int sync_persist, Sync_Cookie *sc
 			(SYNC_FLAG_ADD_STATE_CTRL |
 				SYNC_FLAG_SEND_INTERMEDIATE |
 				SYNC_FLAG_NO_RESULT,
+				tid,
 				sc);
 	} else {
 		info = new_SyncOpInfo
 			(SYNC_FLAG_ADD_STATE_CTRL |
 				SYNC_FLAG_ADD_DONE_CTRL,
+				tid,
 				sc);
 	}
 	sync_set_operation_extension(pb, info);
@@ -672,10 +677,11 @@ sync_send_entry_from_changelog(Slapi_PBlock *pb,int chg_req, char *uniqueid)
 }
 
 static SyncOpInfo*
-new_SyncOpInfo(int flag, Sync_Cookie *cookie) {
+new_SyncOpInfo(int flag, PRThread *tid, Sync_Cookie *cookie) {
     SyncOpInfo *spec = (SyncOpInfo *)slapi_ch_calloc(1, sizeof(SyncOpInfo));
     spec->send_flag = flag;
     spec->cookie = cookie;
+    spec->tid = tid;
 
     return spec;
 }
-- 
1.7.11.7

