Blame SOURCES/slapi-nis-extmem-0005-slapi-nis-populate-data-trees-asynchronously-after-L.patch

6b9042
From 2df48b57adb666112cab22e62750dd984fc7450a Mon Sep 17 00:00:00 2001
6b9042
From: Alexander Bokovoy <abokovoy@redhat.com>
6b9042
Date: Wed, 23 Dec 2015 14:57:03 +0200
6b9042
Subject: [PATCH 05/12] slapi-nis: populate data trees asynchronously after
6b9042
 LDAP server startup
6b9042
6b9042
Currently slapi-nis design assumes the map cache is populated by
6b9042
scanning the original trees on plugin start up. This has few
6b9042
consequences:
6b9042
   - LDAP server cannot serve LDAP clients until all plugins are
6b9042
     initialized
6b9042
6b9042
   - slapi-nis cannot ask SSSD to resolve external identities at
6b9042
     this point as SSSD will need to talk to the LDAP server which
6b9042
     is at this point not listening for connections. SSSD will put
6b9042
     whole IPA domain into offline and always will respond
6b9042
     with negative result
6b9042
6b9042
To solve these issues, schedule tree scan after LDAP server startup.
6b9042
The problem here is that it is not possible to reliably detect when
6b9042
389-ds starts to listen to the incoming connections. However, it is
6b9042
possible to schedule an event into 389-ds event queue that will run
6b9042
shortly after start of the event loop. Given that the call back function
6b9042
which is registered to be called is called within the event loop thread,
6b9042
one can fire off another thread and wait in the thread function some
6b9042
time until the LDAP server is ready for connections.
6b9042
6b9042
The time interval is something that would depend on a specific
6b9042
deployment profile but experiments show that having 5 seconds delay
6b9042
should be enough as event queue is created just before starting the
6b9042
listeners.
6b9042
---
6b9042
 src/back-shr.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++---------
6b9042
 src/plug-sch.c |   4 +--
6b9042
 2 files changed, 96 insertions(+), 18 deletions(-)
6b9042
6b9042
diff --git a/src/back-shr.c b/src/back-shr.c
6b9042
index c68640a..36ecc0b 100644
6b9042
--- a/src/back-shr.c
6b9042
+++ b/src/back-shr.c
6b9042
@@ -664,40 +664,56 @@ backend_shr_get_vattr_sdnlist(struct plugin_state *state,
6b9042
 	return ret;
6b9042
 }
6b9042
 
6b9042
-/* Scan for the list of configured groups and sets. */
6b9042
-void
6b9042
-backend_shr_startup(struct plugin_state *state,
6b9042
-		    Slapi_PBlock *parent_pb,
6b9042
-		    const char *filter)
6b9042
+struct backend_shr_data_init_cbdata {
6b9042
+	Slapi_PBlock *parent_pb;
6b9042
+	struct plugin_state *state;
6b9042
+	const char *filter;
6b9042
+};
6b9042
+
6b9042
+#define PLUGIN_SCAN_DELAY 5
6b9042
+
6b9042
+static void
6b9042
+backend_shr_data_initialize_thread_cb(void *arg)
6b9042
 {
6b9042
-	Slapi_PBlock *pb;
6b9042
+	struct backend_shr_data_init_cbdata *cbdata = (struct backend_shr_data_init_cbdata *)arg;
6b9042
+	Slapi_PBlock *pb = NULL;
6b9042
 	struct backend_set_config_entry_add_cbdata set_cbdata;
6b9042
+	int result = 0;
6b9042
+	if (cbdata == NULL) {
6b9042
+		return;
6b9042
+	}
6b9042
+
6b9042
+	/* Scan may require consulting SSSD for external identities
6b9042
+	 * therefore, we need to make sure the scan starts after ns-slapd
6b9042
+	 * started to serve LDAP clients. There is no a signal for this,
6b9042
+	 * so we just wait some time. */
6b9042
+	DS_Sleep(PR_SecondsToInterval(PLUGIN_SCAN_DELAY));
6b9042
 
6b9042
-	backend_update_params(parent_pb, state);
6b9042
+	backend_update_params(cbdata->parent_pb, cbdata->state);
6b9042
 
6b9042
 	slapi_log_error(SLAPI_LOG_PLUGIN,
6b9042
-			state->plugin_desc->spd_id,
6b9042
+			cbdata->state->plugin_desc->spd_id,
6b9042
 			"searching under \"%s\" for configuration\n",
6b9042
-			state->plugin_base);
6b9042
-	pb = wrap_pblock_new(parent_pb);
6b9042
+			cbdata->state->plugin_base);
6b9042
+	pb = wrap_pblock_new(cbdata->parent_pb);
6b9042
 	slapi_search_internal_set_pb(pb,
6b9042
-				     state->plugin_base,
6b9042
+				     cbdata->state->plugin_base,
6b9042
 				     LDAP_SCOPE_ONELEVEL,
6b9042
-				     filter,
6b9042
+				     cbdata->filter,
6b9042
 				     NULL, FALSE,
6b9042
 				     NULL,
6b9042
 				     NULL,
6b9042
-				     state->plugin_identity,
6b9042
+				     cbdata->state->plugin_identity,
6b9042
 				     0);
6b9042
 	if (map_wrlock() != 0) {
6b9042
 		slapi_log_error(SLAPI_LOG_PLUGIN,
6b9042
-				state->plugin_desc->spd_id,
6b9042
+				cbdata->state->plugin_desc->spd_id,
6b9042
 				"failed to search under \"%s\" for "
6b9042
 				"configuration: failed to acquire a lock\n",
6b9042
-				state->plugin_base);
6b9042
+				cbdata->state->plugin_base);
6b9042
 		goto done_with_lock;
6b9042
 	}
6b9042
-	set_cbdata.state = state;
6b9042
+	set_cbdata.state = cbdata->state;
6b9042
 	set_cbdata.pb = pb;
6b9042
 	slapi_search_internal_callback_pb(pb, &set_cbdata,
6b9042
 					  NULL,
6b9042
@@ -706,6 +722,68 @@ backend_shr_startup(struct plugin_state *state,
6b9042
 	map_unlock();
6b9042
 done_with_lock:
6b9042
 	slapi_pblock_destroy(pb);
6b9042
+        if (cbdata) {
6b9042
+		slapi_ch_free((void**)&cbdata);
6b9042
+        }
6b9042
+}
6b9042
+
6b9042
+static void
6b9042
+backend_shr_data_initialize_thread(time_t when, void *arg)
6b9042
+{
6b9042
+	struct backend_shr_data_init_cbdata *cbdata = (struct backend_shr_data_init_cbdata *)arg;
6b9042
+	PRThread *thread = NULL;
6b9042
+
6b9042
+	/* start data import as a separate thread */
6b9042
+	thread = PR_CreateThread(PR_USER_THREAD, backend_shr_data_initialize_thread_cb,
6b9042
+			(void *)arg, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
6b9042
+			PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
6b9042
+	if (thread == NULL) {
6b9042
+		slapi_log_error(SLAPI_LOG_FATAL,
6b9042
+				cbdata->state->plugin_desc->spd_id,
6b9042
+				"unable to create compatibility tree scan thread!\n");
6b9042
+	} else {
6b9042
+		slapi_log_error(SLAPI_LOG_FATAL,
6b9042
+				cbdata->state->plugin_desc->spd_id,
6b9042
+				"%s tree scan will start in about %d seconds!\n",
6b9042
+				cbdata->state->plugin_desc->spd_id, PLUGIN_SCAN_DELAY);
6b9042
+	}
6b9042
+
6b9042
+}
6b9042
+
6b9042
+/* Scan for the list of configured groups and sets. */
6b9042
+void
6b9042
+backend_shr_startup(struct plugin_state *state,
6b9042
+		    Slapi_PBlock *parent_pb,
6b9042
+		    const char *filter)
6b9042
+{
6b9042
+	struct backend_shr_data_init_cbdata *cbdata = NULL;
6b9042
+
6b9042
+	cbdata = (struct backend_shr_data_init_cbdata *) 
6b9042
+		 slapi_ch_malloc(sizeof(struct backend_shr_data_init_cbdata));
6b9042
+
6b9042
+	if (cbdata == NULL) {
6b9042
+		slapi_log_error(SLAPI_LOG_FATAL,
6b9042
+				state->plugin_desc->spd_id,
6b9042
+				"failed to create a task for populating "
6b9042
+				"compatibility tree\n");
6b9042
+		return;
6b9042
+	}
6b9042
+
6b9042
+	cbdata->state = state;
6b9042
+	cbdata->parent_pb = parent_pb;
6b9042
+	cbdata->filter = filter;
6b9042
+
6b9042
+	/* Schedule running a callback that will create a thread */
6b9042
+	slapi_eq_once(backend_shr_data_initialize_thread,
6b9042
+		      cbdata, PR_SecondsToInterval(PLUGIN_SCAN_DELAY));
6b9042
+
6b9042
+	slapi_log_error(SLAPI_LOG_FATAL,
6b9042
+			cbdata->state->plugin_desc->spd_id,
6b9042
+			"scheduled %s tree scan in about %d seconds after the server startup!\n",
6b9042
+			state->plugin_desc->spd_id, PLUGIN_SCAN_DELAY);
6b9042
+
6b9042
+	return;
6b9042
+
6b9042
 }
6b9042
 
6b9042
 /* Process a set configuration directory entry.  Pull out the group and set
6b9042
diff --git a/src/plug-sch.c b/src/plug-sch.c
6b9042
index f132e6d..95a4fd8 100644
6b9042
--- a/src/plug-sch.c
6b9042
+++ b/src/plug-sch.c
6b9042
@@ -109,8 +109,6 @@ plugin_startup(Slapi_PBlock *pb)
6b9042
 			state->plugin_base ? "\"" : "",
6b9042
 			state->plugin_base ? state->plugin_base : "NULL",
6b9042
 			state->plugin_base ? "\"" : "");
6b9042
-	/* Populate the tree of fake entries. */
6b9042
-	backend_startup(pb, state);
6b9042
 	state->pam_lock = wrap_new_rwlock();
6b9042
 	backend_nss_init_context((struct nss_ops_ctx**) &state->nss_context);
6b9042
 	if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
6b9042
@@ -123,6 +121,8 @@ plugin_startup(Slapi_PBlock *pb)
6b9042
 	wrap_rwlock_wrlock(state->cached_entries_lock);
6b9042
 	state->cached_entries = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, PL_CompareValues, 0, 0);
6b9042
 	wrap_rwlock_unlock(state->cached_entries_lock);
6b9042
+	/* Populate the tree of fake entries. */
6b9042
+	backend_startup(pb, state);
6b9042
 	/* Note that the plugin is ready to go. */
6b9042
 	slapi_log_error(SLAPI_LOG_PLUGIN, plugin_description.spd_id,
6b9042
 			"plugin startup completed\n");
6b9042
-- 
6b9042
2.5.0
6b9042