On 11.6.2016 20:36, Petr Spacek wrote:
> Hello,
> 
> Support fake_mname option in per-server configuration in LDAP.
> 
> https://fedorahosted.org/bind-dyndb-ldap/ticket/162
> 
> 
> Patch set contains necessary infrastructure changes so the configuration is
> read before zone loading starts.

This version fixes crash which could be triggered by failure in second
syncrepl session.

(I.e. config sync succeeded but data sync failed.)

-- 
Petr^2 Spacek
From d1c67a763f1d84599cfae8b222fd90e575bd1d87 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Fri, 10 Jun 2016 12:57:48 +0200
Subject: [PATCH] Do not log "connection to the LDAP server was lost" on forced
 reconnects.

This is a cosmetic change which will be used in code which opens and
closes multiple SyncRepl connections.

https://fedorahosted.org/bind-dyndb-ldap/ticket/162
---
 src/ldap_helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index af7f5c40500c7843dbf5e4533b83982b52088ced..b922371ae2392ca8bd1069df738d69617bb81905 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -2726,7 +2726,7 @@ handle_connection_error(ldap_instance_t *ldap_inst, ldap_connection_t *ldap_conn
 		/* Try to reconnect on other errors. */
 		log_ldap_error(ldap_conn->handle, "connection error");
 reconnect:
-		if (ldap_conn->handle == NULL)
+		if (ldap_conn->handle == NULL && force == ISC_FALSE)
 			log_error("connection to the LDAP server was lost");
 		result = ldap_connect(ldap_inst, ldap_conn, force);
 		if (result == ISC_R_SUCCESS)
-- 
2.5.5

From 78acc6cff0b506e8a1baf348ac8eca5ffc79a7d9 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Fri, 10 Jun 2016 13:59:26 +0200
Subject: [PATCH] Refactor LDAP SyncRepl connection handling to make it
 reusable.

Now it is easy to sequentially run more SyncRepl sessions with different
parameters. It will be handy for per-server config.

https://fedorahosted.org/bind-dyndb-ldap/ticket/126
---
 src/ldap_helper.c | 190 ++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 121 insertions(+), 69 deletions(-)

diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index b922371ae2392ca8bd1069df738d69617bb81905..aaaaef810de74094da0d3cbb6db1c52151f5c38f 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -4274,44 +4274,29 @@ ldap_sync_cleanup(ldap_sync_t **ldap_syncp) {
 	*ldap_syncp = NULL;
 }
 
-
+/**
+ * Initialize ldap_sync_t structure. Is has to be freed by ldap_sync_cleanup().
+ * In case of failure, the conn parameter may be invalid and LDAP connection
+ * needs to be re-established.
+ *
+ * @param[in]  filter  LDAP filter to be used in SyncRepl session
+ */
 static isc_result_t ATTR_NONNULLS ATTR_CHECKRESULT
 ldap_sync_prepare(ldap_instance_t *inst, settings_set_t *settings,
-		  ldap_connection_t *conn, ldap_sync_t **ldap_syncp) {
+		  const char *filter, ldap_connection_t *conn,
+		  ldap_sync_t **ldap_syncp) {
 	isc_result_t result;
 	const char *base = NULL;
-	isc_uint32_t reconnect_interval;
 	ldap_sync_t *ldap_sync = NULL;
-	const char *server_id = NULL;
-	char filter[1024];
-	const char filter_template[] =
-		"(|(objectClass=idnsConfigObject)"
-		"  (objectClass=idnsZone)"
-		"  (objectClass=idnsForwardZone)"
-		"  (objectClass=idnsRecord)"
-		"  %s%s%s"
-		")";
 
 	REQUIRE(inst != NULL);
 	REQUIRE(ldap_syncp != NULL && *ldap_syncp == NULL);
 
 	/* Remove stale zone & journal files. */
 	CHECK(cleanup_files(inst));
 
-	/* Try to connect. */
-	while (conn->handle == NULL) {
-		result = ISC_R_SHUTTINGDOWN;
-		CHECK_EXIT;
-		CHECK(setting_get_uint("reconnect_interval", settings,
-				       &reconnect_interval));
-
-		log_error("ldap_syncrepl will reconnect in %d second%s",
-			  reconnect_interval,
-			  reconnect_interval == 1 ? "": "s");
-		if (!sane_sleep(inst, reconnect_interval))
-			CLEANUP_WITH(ISC_R_SHUTTINGDOWN);
-		handle_connection_error(inst, conn, ISC_TRUE);
-	}
+	if(conn->handle == NULL)
+		CLEANUP_WITH(ISC_R_NOTCONNECTED);
 
 	ldap_sync = ldap_sync_initialize(NULL);
 	if (ldap_sync == NULL) {
@@ -4325,20 +4310,10 @@ ldap_sync_prepare(ldap_instance_t *inst, settings_set_t *settings,
 	if (ldap_sync->ls_base == NULL)
 		CLEANUP_WITH(ISC_R_NOMEMORY);
 	ldap_sync->ls_scope = LDAP_SCOPE_SUBTREE;
-
-	/* request idnsServerConfig object only if server_id is specified */
-	CHECK(setting_get_str("server_id", settings, &server_id));
-	if (strlen(server_id) == 0)
-		CHECK(isc_string_printf(filter, sizeof(filter), filter_template,
-				        "", "", ""));
-	else
-		CHECK(isc_string_printf(filter, sizeof(filter), filter_template,
-				        "  (&(objectClass=idnsServerConfigObject)"
-				        "    (idnsServerId=", server_id, "))"));
 	ldap_sync->ls_filter = ldap_strdup(filter);
 	if (ldap_sync->ls_filter == NULL)
 		CLEANUP_WITH(ISC_R_NOMEMORY);
-	log_debug(1, "LDAP syncrepl filter = %s", ldap_sync->ls_filter);
+	log_debug(1, "LDAP syncrepl filter = '%s'", ldap_sync->ls_filter);
 	ldap_sync->ls_timeout = -1; /* sync_poll is blocking */
 	ldap_sync->ls_ld = conn->handle;
 	/* This is a hack: ldap_sync_destroy() will call ldap_unbind().
@@ -4360,6 +4335,90 @@ cleanup:
 	return result;
 }
 
+/**
+ * Start one SyncRepl session and process all events produced by it.
+   LDAP_SYNC_REFRESH_AND_PERSIST mode returns only if an error occurred.
+ *
+ * @post Conn is unbound and invalid. The connection needs to be re-established.
+ *
+ * @param[in]  conn          Valid and bound LDAP connection.
+ * @param[in]  filter_objcs  LDAP filter specifying objects which should
+ *                           be retrieved during this session. The supplied
+ *                           filter will be ORed filter specifying configuration
+ *                           objects which always need to be retrieved.
+ * @param[in]  mode          LDAP_SYNC_REFRESH_AND_PERSIST
+ *                           or LDAP_SYNC_REFRESH_ONLY
+ *
+ * @retval ISC_R_SUCCESS      LDAP_SYNC_REFRESH_ONLY mode finished,
+ *                            all events were sent (not necessarily processed)
+ * @retval ISC_R_NOTCONNECTED Unable to start SyncRepl session.
+ * @retval others             Errors, some events might or might not be sent.
+ */
+static isc_result_t ATTR_NONNULLS ATTR_CHECKRESULT
+ldap_sync_doit(ldap_instance_t *inst, ldap_connection_t *conn,
+	       const char * const filter_objcs, int mode) {
+	isc_result_t result;
+	int ret;
+	ldap_sync_t *ldap_sync = NULL;
+	const char *err_hint = "";
+	char filter[1024];
+	const char config_template[] =
+		"(|"
+		"  (objectClass=idnsConfigObject)"
+		"  %s%s%s"
+		"%s"
+		")";
+	const char *server_id = NULL;
+
+	/* request idnsServerConfig object only if server_id is specified */
+	CHECK(setting_get_str("server_id", inst->server_ldap_settings, &server_id));
+	if (strlen(server_id) == 0)
+		CHECK(isc_string_printf(filter, sizeof(filter), config_template,
+				        "", "", "", filter_objcs));
+	else
+		CHECK(isc_string_printf(filter, sizeof(filter), config_template,
+					"  (&(objectClass=idnsServerConfigObject)"
+				        "    (idnsServerId=", server_id, "))",
+					filter_objcs));
+
+	result = ldap_sync_prepare(inst, inst->server_ldap_settings,
+				   filter, conn, &ldap_sync);
+	if (result != ISC_R_SUCCESS) {
+		log_error_r("ldap_sync_prepare() failed, retrying "
+			    "in 1 second");
+		sane_sleep(inst, 1);
+		goto cleanup;
+	}
+
+	ret = ldap_sync_init(ldap_sync, mode);
+	/* TODO: error handling, set tainted flag & do full reload? */
+	if (ret != LDAP_SUCCESS) {
+		if (ret == LDAP_UNAVAILABLE_CRITICAL_EXTENSION)
+			err_hint = ": is RFC 4533 supported by LDAP server?";
+		else
+			err_hint = "";
+
+		log_ldap_error(ldap_sync->ls_ld, "unable to start SyncRepl "
+				"session%s", err_hint);
+		conn->handle = NULL;
+		CLEANUP_WITH(ISC_R_NOTCONNECTED);
+	}
+
+	while (!inst->exiting && ret == LDAP_SUCCESS
+	       && mode == LDAP_SYNC_REFRESH_AND_PERSIST) {
+		ret = ldap_sync_poll(ldap_sync);
+		if (!inst->exiting && ret != LDAP_SUCCESS) {
+			log_ldap_error(ldap_sync->ls_ld,
+				       "ldap_sync_poll() failed");
+			/* force reconnect in sync_prepare */
+			conn->handle = NULL;
+		}
+	}
+
+cleanup:
+	ldap_sync_cleanup(&ldap_sync);
+	return result;
+}
 
 /*
  * NOTE:
@@ -4373,8 +4432,7 @@ ldap_syncrepl_watcher(isc_threadarg_t arg)
 	int ret;
 	isc_result_t result;
 	sigset_t sigset;
-	ldap_sync_t *ldap_sync = NULL;
-	const char *err_hint = "";
+	isc_uint32_t reconnect_interval;
 
 	log_debug(1, "Entering ldap_syncrepl_watcher");
 
@@ -4396,48 +4454,42 @@ ldap_syncrepl_watcher(isc_threadarg_t arg)
 	CHECK(ldap_pool_getconnection(inst->pool, &conn));
 
 	while (!inst->exiting) {
-		ldap_sync_cleanup(&ldap_sync);
-		result = ldap_sync_prepare(inst, inst->server_ldap_settings,
-					   conn, &ldap_sync);
-		if (result != ISC_R_SUCCESS) {
-			log_error_r("ldap_sync_prepare() failed, retrying "
-				    "in 1 second");
-			sane_sleep(inst, 1);
-			continue;
-		}
 		mldap_cur_generation_bump(inst->mldapdb);
 
 		log_info("LDAP instance '%s' is being synchronized, "
 			 "please ignore message 'all zones loaded'",
 			 inst->db_name);
-		ret = ldap_sync_init(ldap_sync, LDAP_SYNC_REFRESH_AND_PERSIST);
-		/* TODO: error handling, set tainted flag & do full reload? */
-		if (ret != LDAP_SUCCESS) {
-			if (ret == LDAP_UNAVAILABLE_CRITICAL_EXTENSION)
-				err_hint = ": is RFC 4533 supported by LDAP server?";
-			else
-				err_hint = "";
-
-			log_ldap_error(ldap_sync->ls_ld, "unable to start SyncRepl "
-					"session%s", err_hint);
-			conn->handle = NULL;
-			continue;
+		result = ldap_sync_doit(inst, conn,
+				        "(|(objectClass=idnsZone)"
+					"  (objectClass=idnsForwardZone)"
+					"  (objectClass=idnsRecord))",
+					LDAP_SYNC_REFRESH_AND_PERSIST);
+		if (result != ISC_R_SUCCESS) {
+			log_error_r("LDAP data synchronization failed");
+			goto retry;
 		}
 
-		while (!inst->exiting && ret == LDAP_SUCCESS) {
-			ret = ldap_sync_poll(ldap_sync);
-			if (!inst->exiting && ret != LDAP_SUCCESS) {
-				log_ldap_error(ldap_sync->ls_ld,
-					       "ldap_sync_poll() failed");
-				/* force reconnect in sync_prepare */
-				conn->handle = NULL;
-			}
+		CHECK_EXIT;
+
+retry:
+		/* Try to connect. */
+		while (conn->handle == NULL) {
+			CHECK_EXIT;
+			CHECK(setting_get_uint("reconnect_interval",
+					       inst->server_ldap_settings,
+					       &reconnect_interval));
+
+			log_error("ldap_syncrepl will reconnect in %d second%s",
+				  reconnect_interval,
+				  reconnect_interval == 1 ? "": "s");
+			if (!sane_sleep(inst, reconnect_interval))
+				CLEANUP_WITH(ISC_R_SHUTTINGDOWN);
+			handle_connection_error(inst, conn, ISC_TRUE);
 		}
 	}
 
 cleanup:
 	log_debug(1, "Ending ldap_syncrepl_watcher");
-	ldap_sync_cleanup(&ldap_sync);
 	ldap_pool_putconnection(inst->pool, &conn);
 
 	return (isc_threadresult_t)0;
-- 
2.5.5

From 966e162b89f9ae8fab22a1b039a996be0f1e0538 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Fri, 10 Jun 2016 15:44:28 +0200
Subject: [PATCH] Read configuration from LDAP first to guarantee its
 availability.

All configuration need to be read first so its available during data
processing. This makes possible to store fake_mname and similar
variables in LDAP while using them for dynamic entry generation.

New implementation of ldap_syncrepl_watcher() sequentially opens
two SynRepl connections in different modes:
1. configuration is synchronized using LDAP_SYNC_REFRESH_ONLY mode
2. all the data including configuration are read using
   LDAP_SYNC_REFRESH_AND_PERSIST mode

Synchronization state machine (inst->sctx) was extended with new states which
are used to track progress of configuration & data synchronization. The state
machine guarantees that configuration is synchronized first and data are
processed only when all the configuration events were processed.

https://fedorahosted.org/bind-dyndb-ldap/ticket/162
---
 src/ldap_helper.c |  61 ++++++++++++++++++++++----
 src/syncrepl.c    | 128 ++++++++++++++++++++++++++++++++++++++++++++++--------
 src/syncrepl.h    |  21 ++++++---
 3 files changed, 177 insertions(+), 33 deletions(-)

diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index aaaaef810de74094da0d3cbb6db1c52151f5c38f..edf69dff13a53018cb1e2b38d88c899f14f929ee 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -969,7 +969,7 @@ create_zone(ldap_instance_t * const inst, const char * const dn,
 	}
 
 	sync_state_get(inst->sctx, &sync_state);
-	if (sync_state == sync_init) {
+	if (sync_state == sync_datainit) {
 		dns_zone_gettask(raw, &task);
 		CHECK(sync_task_add(inst->sctx, task));
 		isc_task_detach(&task);
@@ -3929,7 +3929,7 @@ syncrepl_update(ldap_instance_t *inst, ldap_entry_t **entryp, int chgtype)
 	    || action == update_serverconfig) {
 		INSIST(task == inst->task); /* For task-exclusive mode */
 		sync_state_get(inst->sctx, &sync_state);
-		if (sync_state == sync_init)
+		if (sync_state == sync_configinit || sync_state == sync_datainit)
 			CHECK(sync_task_add(inst->sctx, task));
 	}
 
@@ -4215,11 +4215,11 @@ int ldap_sync_intermediate (
 		goto cleanup;
 
 	sync_state_get(inst->sctx, &state);
-	if (state == sync_init) {
+	if (state == sync_datainit) {
 		result = sync_barrier_wait(inst->sctx, inst->db_name);
 		if (result != ISC_R_SUCCESS) {
-			log_error_r("sync_barrier_wait() failed for instance "
-				    "'%s'", inst->db_name);
+			log_error_r("%s: sync_barrier_wait() failed for "
+				    "instance '%s'", __func__, inst->db_name);
 			goto cleanup;
 		}
 	}
@@ -4250,12 +4250,36 @@ int ATTR_NONNULLS ATTR_CHECKRESULT ldap_sync_search_result (
 	ldap_sync_t			*ls,
 	LDAPMessage			*msg,
 	int				refreshDeletes ) {
+	isc_result_t	result;
+	ldap_instance_t *inst = ls->ls_private;
+	sync_state_t state;
 
-	UNUSED(ls);
 	UNUSED(msg);
 	UNUSED(refreshDeletes);
 
-	log_error("ldap_sync_search_result is not yet handled");
+	log_debug(1, "ldap_sync_search_result");
+
+	if (inst->exiting)
+		goto cleanup;
+
+	/* This place can be reached only if:
+	 * a) initial config synchronization is done
+	 * b) config is re-synchronized after reconnect to LDAP */
+	sync_state_get(inst->sctx, &state);
+	INSIST(state == sync_configinit || state == sync_finished);
+
+	if (state == sync_configinit) {
+		result = sync_barrier_wait(inst->sctx, inst->db_name);
+		if (result != ISC_R_SUCCESS) {
+			log_error_r("%s: sync_barrier_wait() failed for "
+				    "instance '%s'", __func__, inst->db_name);
+			goto cleanup;
+		}
+	}
+	log_info("LDAP configuration for instance '%s' synchronized",
+		 inst->db_name);
+
+cleanup:
 	return LDAP_SUCCESS;
 }
 
@@ -4433,6 +4457,7 @@ ldap_syncrepl_watcher(isc_threadarg_t arg)
 	isc_result_t result;
 	sigset_t sigset;
 	isc_uint32_t reconnect_interval;
+	sync_state_t state;
 
 	log_debug(1, "Entering ldap_syncrepl_watcher");
 
@@ -4454,9 +4479,26 @@ ldap_syncrepl_watcher(isc_threadarg_t arg)
 	CHECK(ldap_pool_getconnection(inst->pool, &conn));
 
 	while (!inst->exiting) {
+		sync_state_get(inst->sctx, &state);
+		if (state != sync_finished)
+			sync_state_reset(inst->sctx);
+		/* synchronize configuration first so configuration variables
+		 * are already available during data processing */
+		result = ldap_sync_doit(inst, conn, "", LDAP_SYNC_REFRESH_ONLY);
+		if (result != ISC_R_SUCCESS) {
+			log_error_r("LDAP configuration synchronization failed");
+			goto retry;
+		}
+
+		result = ldap_connect(inst, conn, ISC_TRUE);
+		if (result != ISC_R_SUCCESS) {
+			log_error_r("reconnection to LDAP failed");
+			goto retry;
+		}
+
+		/* finally synchronize the data */
 		mldap_cur_generation_bump(inst->mldapdb);
-
-		log_info("LDAP instance '%s' is being synchronized, "
+		log_info("LDAP data for instance '%s' are being synchronized, "
 			 "please ignore message 'all zones loaded'",
 			 inst->db_name);
 		result = ldap_sync_doit(inst, conn,
@@ -4486,6 +4528,7 @@ retry:
 				CLEANUP_WITH(ISC_R_SHUTTINGDOWN);
 			handle_connection_error(inst, conn, ISC_TRUE);
 		}
+
 	}
 
 cleanup:
diff --git a/src/syncrepl.c b/src/syncrepl.c
index 5ee1eb1aeb75ac4dbece9d429dca117465bef782..1117358e9a1ac3de89f8c1504dae87ca1eaaa80a 100644
--- a/src/syncrepl.c
+++ b/src/syncrepl.c
@@ -39,6 +39,7 @@ struct task_element {
 static const isc_interval_t shutdown_timeout = { 3, 0 };
 
 /**
+ * @file syncrepl.c
  * @brief Synchronisation context.
  *
  * This structure provides information necessary for detecting the end
@@ -52,20 +53,31 @@ static const isc_interval_t shutdown_timeout = { 3, 0 };
  * zone. Each task involved in event processing is added to task list in
  * struct sync_ctx by sync_task_add() call.
  *
- * The initial synchronization is done when LDAP intermediate message
- * (with attribute refreshDone = TRUE) was received and all events generated
- * before this message were processed.
+ * The initial synchronization in LDAP_SYNC_REFRESH_ONLY mode is done
+ * when LDAP search result message was
+ * received and all events generated before this message were processed.
+ *
+ * The initial synchronization in LDAP_SYNC_REFRESH_AND_PERSIST mode is done
+ * when LDAP intermediate message (with attribute refreshDone = TRUE) was
+ * received and all events generated before this message were processed.
  *
  * LDAP intermediate message handler ldap_sync_intermediate() calls
  * sync_barrier_wait() and it sends sync_barrierev event to all involved tasks.
  * sync_barrier_wait() returns only if all tasks processed all sync_barrierev
  * events. As a result, all events generated before sync_barrier_wait() call
  * are processed before the call returns.
  *
- * @warning There are two assumptions:
+ * @warning There are three assumptions:
  * 	@li Each task processes events in FIFO order.
  * 	@li The task assigned to a LDAP instance or a DNS zone never changes.
+ * 	@li All code which depends on machine states is executed sequentially.
+ * 	    Asynchronous execution would lead to race conditions.
+ * 	    This currently works because all code depending on machine state
+ * 	    is directly or indirectly executed from ldap_sync_{init,poll}
+ * 	    functions and is synchronous.
  *
+ * @see ldap_sync_search_result()
+ * @see ldap_sync_intermediate()
  * @see ldap_sync_search_entry()
  */
 struct sync_ctx {
@@ -111,18 +123,35 @@ finish(isc_task_t *task, isc_event_t *event) {
 	isc_result_t result = ISC_R_SUCCESS;
 	ldap_instance_t *inst = NULL;
 	sync_barrierev_t *bev = NULL;
+	sync_state_t new_state;
 
 	REQUIRE(ISCAPI_TASK_VALID(task));
 	REQUIRE(event != NULL);
 
 	bev = (sync_barrierev_t *)event;
 	CHECK(manager_get_ldap_instance(bev->dbname, &inst));
 	log_debug(1, "sync_barrier_wait(): finish reached");
 	LOCK(&bev->sctx->mutex);
-	sync_state_change(bev->sctx, sync_finished, ISC_FALSE);
+	switch (bev->sctx->state) {
+		case sync_configbarrier:
+			new_state = sync_datainit;
+			break;
+		case sync_databarrier:
+			new_state = sync_finished;
+			break;
+		case sync_configinit:
+		case sync_datainit:
+		case sync_finished:
+		default:
+			FATAL_ERROR(__FILE__, __LINE__,
+				    "sync_barrier_wait(): invalid state "
+				    "%u", bev->sctx->state);
+	}
+	sync_state_change(bev->sctx, new_state, ISC_FALSE);
 	BROADCAST(&bev->sctx->cond);
 	UNLOCK(&bev->sctx->mutex);
-	activate_zones(task, inst);
+	if (new_state == sync_finished)
+		activate_zones(task, inst);
 
 cleanup:
 	if (result != ISC_R_SUCCESS)
@@ -233,7 +262,7 @@ sync_barrierev_create(sync_ctx_t *sctx, const char *inst_name,
  * @param[in]	inst	LDAP instance associated with this synchronization ctx.
  * @param[out]	sctxp	The new synchronization context.
  *
- * @post state == sync_init
+ * @post state == sync_configinit
  * @post task_cnt == 1
  * @post tasks list contains the task
  */
@@ -264,7 +293,7 @@ sync_ctx_init(isc_mem_t *mctx, ldap_instance_t *inst, sync_ctx_t **sctxp) {
 
 	ISC_LIST_INIT(sctx->tasks);
 
-	sctx->state = sync_init;
+	sctx->state = sync_configinit;
 	CHECK(sync_task_add(sctx, ldap_instance_gettask(sctx->inst)));
 
 	CHECK(semaphore_init(&sctx->concurr_limit, LDAP_CONCURRENCY_LIMIT));
@@ -344,14 +373,25 @@ sync_state_change(sync_ctx_t *sctx, sync_state_t new_state, isc_boolean_t lock)
 		LOCK(&sctx->mutex);
 
 	switch (sctx->state) {
-	case sync_init:
+	case sync_configinit:
+		/* initial synchronization is finished
+		 * and ldap_sync_search_result() was called */
+		INSIST(new_state == sync_configbarrier);
+		break;
+
+	case sync_configbarrier:
+		/* sync_barrier_wait(sync_configinit) finished */
+		INSIST(new_state == sync_datainit);
+		break;
+
+	case sync_datainit:
 		/* refresh phase is finished
 		 * and ldap_sync_intermediate() was called */
-		INSIST(new_state == sync_barrier);
+		INSIST(new_state == sync_databarrier);
 		break;
 
-	case sync_barrier:
-		/* sync_barrier_wait() finished */
+	case sync_databarrier:
+		/* sync_barrier_wait(sync_databarrier) finished */
 		INSIST(new_state == sync_finished);
 		break;
 
@@ -363,11 +403,45 @@ sync_state_change(sync_ctx_t *sctx, sync_state_t new_state, isc_boolean_t lock)
 	}
 
 	sctx->state = new_state;
+	log_debug(1, "sctx state %u reached", new_state);
 	if (lock == ISC_TRUE)
 		UNLOCK(&sctx->mutex);
 }
 
 /**
+ * Reset state of synchronization finite state machine.
+ * Reset can be done only before reaching state finished,
+ * i.e. when one of initial synchronizations in ldap_syncrepl_watcher failed.
+ *
+ * @warning The reset can reliably work only if all state transitions
+ *          are synchronous. This is necessary to prevent race conditions
+ *          between reset and events depending on particular state.
+ */
+void
+sync_state_reset(sync_ctx_t *sctx) {
+	REQUIRE(sctx != NULL);
+
+	LOCK(&sctx->mutex);
+
+	switch (sctx->state) {
+	case sync_configinit:
+	case sync_configbarrier:
+	case sync_datainit:
+	case sync_databarrier:
+		sctx->state = sync_configinit;
+		break;
+
+	case sync_finished:
+		/* state finished cannot be taken back, ever */
+	default:
+		fatal_error("invalid attempt to reset synchronization state");
+	}
+
+	log_debug(1, "sctx state %u reached (reset)", sctx->state);
+	UNLOCK(&sctx->mutex);
+}
+
+/**
  * @brief Add task to task list in synchronization context.
  *
  * As a result, subsequent sync_barrier_wait() call will wait until all events
@@ -389,7 +463,7 @@ sync_task_add(sync_ctx_t *sctx, isc_task_t *task) {
 	isc_task_attach(task, &newel->task);
 
 	LOCK(&sctx->mutex);
-	REQUIRE(sctx->state == sync_init);
+	REQUIRE(sctx->state == sync_configinit || sctx->state == sync_datainit);
 	ISC_LIST_APPEND(sctx->tasks, newel, link);
 	isc_refcount_increment0(&sctx->task_cnt, &cnt);
 	UNLOCK(&sctx->mutex);
@@ -408,23 +482,43 @@ cleanup:
  * @param[in,out]	sctx		Synchronization context
  * @param[in]		inst_name	LDAP instance name for given sctx
  *
- * @pre  sctx->state == sync_init
+ * @pre  sctx->state == sync_configinit || sync_datainit
  * @post sctx->state == sync_finished and all tasks processed all events
  *       enqueued before sync_barrier_wait() call.
  */
 isc_result_t
 sync_barrier_wait(sync_ctx_t *sctx, const char *inst_name) {
 	isc_result_t result;
 	isc_event_t *ev = NULL;
 	sync_barrierev_t *bev = NULL;
+	sync_state_t barrier_state;
+	sync_state_t final_state;
 	task_element_t *taskel = NULL;
 	task_element_t *next_taskel = NULL;
 
 	LOCK(&sctx->mutex);
-	REQUIRE(sctx->state == sync_init);
+	REQUIRE(sctx->state == sync_configinit || sctx->state == sync_datainit);
 	REQUIRE(!EMPTY(sctx->tasks));
 
-	sync_state_change(sctx, sync_barrier, ISC_FALSE);
+	switch (sctx->state) {
+		case sync_configinit:
+			barrier_state = sync_configbarrier;
+			final_state = sync_datainit;
+			break;
+		case sync_datainit:
+			barrier_state = sync_databarrier;
+			final_state = sync_finished;
+			break;
+		case sync_configbarrier:
+		case sync_databarrier:
+		case sync_finished:
+		default:
+			FATAL_ERROR(__FILE__, __LINE__,
+				    "sync_barrier_wait(): invalid state "
+				    "%u", sctx->state);
+	}
+
+	sync_state_change(sctx, barrier_state, ISC_FALSE);
 	for (taskel = next_taskel = HEAD(sctx->tasks);
 	     taskel != NULL;
 	     taskel = next_taskel) {
@@ -438,7 +532,7 @@ sync_barrier_wait(sync_ctx_t *sctx, const char *inst_name) {
 	}
 
 	log_debug(1, "sync_barrier_wait(): wait until all events are processed");
-	while (sctx->state != sync_finished)
+	while (sctx->state != final_state)
 		WAIT(&sctx->cond, &sctx->mutex);
 	log_debug(1, "sync_barrier_wait(): all events were processed");
 
diff --git a/src/syncrepl.h b/src/syncrepl.h
index 10fbbc1fa80d65bdb8bba65a316a4815996985e9..eb6b8d0c9a6a0ab8f7595f4735e333fce9808f26 100644
--- a/src/syncrepl.h
+++ b/src/syncrepl.h
@@ -17,13 +17,17 @@ typedef enum sync_state		sync_state_t;
 typedef struct sync_barrierev	sync_barrierev_t;
 
 enum sync_state {
-	sync_init,	/**< initial synchronisation in progress;
-			     expecting LDAP intermediate message
-			     with refreshDone = TRUE */
-	sync_barrier,	/**< waiting until all tasks process events generated
-			     during initial synchronisation phase*/
-	sync_finished	/**< initial synchronisation done; all events generated
-			     during initial synchronisation were processed */
+	sync_configinit,	/**< initial config synchronization in progress;
+				     expecting LDAP result message */
+	sync_configbarrier,	/**< waiting until all tasks process events
+				     generated during initial synchronization */
+	sync_datainit,		/**< initial data synchronization in progress;
+				     expecting LDAP intermediate message
+				     with refreshDone = TRUE */
+	sync_databarrier,	/**< waiting until all tasks process data events
+				     generated during initial synchronization */
+	sync_finished	/**< initial synchronization done; all events generated
+			     during initial synchronization were processed */
 };
 
 isc_result_t
@@ -38,6 +42,9 @@ sync_state_get(sync_ctx_t *sctx, sync_state_t *statep) ATTR_NONNULLS;
 void
 sync_state_change(sync_ctx_t *sctx, sync_state_t new_state, isc_boolean_t lock) ATTR_NONNULLS;
 
+void
+sync_state_reset(sync_ctx_t *sctx) ATTR_NONNULLS;
+
 isc_result_t
 sync_task_add(sync_ctx_t *sctx, isc_task_t *task) ATTR_NONNULLS ATTR_CHECKRESULT;
 
-- 
2.5.5

From 7970e5fbe78dc9774b26d81b23c51d9fe4fcfb18 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Fri, 10 Jun 2016 17:07:58 +0200
Subject: [PATCH] Support fake_mname option in per-server configuration in
 LDAP.

Run-time changes in idnsSOAmName attribute may not be reflected in
zones which are already loaded.

https://fedorahosted.org/bind-dyndb-ldap/ticket/162
---
 src/ldap_helper.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index edf69dff13a53018cb1e2b38d88c899f14f929ee..64500deccf08bfcc493686c0f54a2dc994a7699e 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -1459,6 +1459,13 @@ ldap_parse_serverconfigentry(ldap_entry_t *entry, ldap_instance_t *inst)
 	} else if (result != ISC_R_IGNORE)
 		goto cleanup;
 
+	result = setting_update_from_ldap_entry("fake_mname",
+						inst->server_ldap_settings,
+						"idnsSOAmName",
+						entry);
+	if (result != ISC_R_SUCCESS && result != ISC_R_IGNORE)
+		goto cleanup;
+
 cleanup:
 	/* Configuration errors are not fatal. */
 	/* TODO: log something? */
@@ -1892,7 +1899,7 @@ zone_sync_apex(const ldap_instance_t * const inst,
 	INIT_LIST(rdatalist);
 	*ldap_writeback = ISC_FALSE; /* GCC */
 
-	CHECK(setting_get_str("fake_mname", inst->local_settings,
+	CHECK(setting_get_str("fake_mname", inst->server_ldap_settings,
 			      &fake_mname));
 	CHECK(ldap_parse_rrentry(inst->mctx, entry, &name, fake_mname,
 				 &rdatalist));
@@ -3668,7 +3675,7 @@ update_restart:
 		/* Parse new data from LDAP. */
 		log_debug(5, "syncrepl_update: updating name in rbtdb, "
 			  "%s", ldap_entry_logname(entry));
-		CHECK(setting_get_str("fake_mname", inst->local_settings,
+		CHECK(setting_get_str("fake_mname", inst->server_ldap_settings,
 				      &fake_mname));
 		CHECK(ldap_parse_rrentry(mctx, entry, &entry->zone_name, fake_mname,
 					 &rdatalist));
-- 
2.5.5

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to