From 0ae19c5c24a3ba51661d3136806d17b8f0f31cef Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Mar 15 2019 15:41:11 +0000 Subject: ipa-extdom-exop: add instance counter and limit The user and group lookups done by the extdom plugin might need some time depending on the state of the service (typically SSSD) handling the requests. To avoid that all worker threads are busy waiting on a connect or a reply from SSSD and no other request can be handled this patch adds an instance counter and an instance limit for the extdom plugin. By default the limit will be around 80% of the number of worker threads. It can be tuned further with the plugin option ipaExtdomMaxInstances which must in set in ipaextdommaxinstances and should have an integer value larger than 0 and lesser than the number of worker threads. If the instance limit is reached the extdom plugin will return LDAP_BUSY for every new request until the number of instance is again below the limit. Reviewed-By: Alexander Bokovoy --- diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h index bbc5747..e01e74c 100644 --- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h +++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h @@ -157,6 +157,8 @@ struct ipa_extdom_ctx { char *base_dn; size_t max_nss_buf_size; struct nss_ops_ctx *nss_ctx; + Slapi_Counter *extdom_instance_counter; + size_t extdom_max_instances; }; struct domain_info { diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c index 83c30e7..3abaa41 100644 --- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c +++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c @@ -62,8 +62,112 @@ static char *ipa_extdom_name_list[] = { NULL }; +#define NSSLAPD_THREADNUMBER "nsslapd-threadnumber" +static int ipa_get_threadnumber(Slapi_ComponentId *plugin_id, size_t *threadnumber) +{ + Slapi_PBlock *search_pb = NULL; + int search_result; + Slapi_Entry **search_entries = NULL; + int ret; + char *attrs[] = { NSSLAPD_THREADNUMBER, NULL }; + + search_pb = slapi_pblock_new(); + if (search_pb == NULL) { + LOG_FATAL("Failed to create new pblock.\n"); + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + + slapi_search_internal_set_pb(search_pb, "cn=config", + LDAP_SCOPE_BASE, "objectclass=*", + attrs, 0, NULL, NULL, plugin_id, 0); + + ret = slapi_search_internal_pb(search_pb); + if (ret != 0) { + LOG_FATAL("Starting internal search failed.\n"); + goto done; + } + + ret = slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, + &search_result); + if (ret != 0 || search_result != LDAP_SUCCESS) { + LOG_FATAL("Internal search failed [%d][%d].\n", ret, search_result); + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + + ret = slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, + &search_entries); + if (ret != 0) { + LOG_FATAL("Failed to read searched entries.\n"); + goto done; + } + + if (search_entries == NULL || search_entries[0] == NULL) { + LOG("No existing entries.\n"); + ret = LDAP_NO_SUCH_OBJECT; + goto done; + } + + if (search_entries[1] != NULL) { + LOG("Too many results found.\n"); + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + + *threadnumber = slapi_entry_attr_get_uint(search_entries[0], + NSSLAPD_THREADNUMBER); + + if (threadnumber <= 0) { + LOG_FATAL("No thread number found.\n"); + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + + LOG("Found thread number [%zu].\n", *threadnumber); + ret = 0; + +done: + slapi_free_search_results_internal(search_pb); + slapi_pblock_destroy(search_pb); + + return ret; +} + static int ipa_extdom_start(Slapi_PBlock *pb) { + int ret; + struct ipa_extdom_ctx *ctx; + size_t threadnumber; + + ret = slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &ctx); + if (ret != 0) { + return LDAP_OPERATIONS_ERROR; + } + + ret = ipa_get_threadnumber(ctx->plugin_id, &threadnumber); + if (ret != 0) { + LOG("Unable to get thread number [%d]!\n", ret); + return ret; + } + + if (ctx->extdom_max_instances >= threadnumber) { + LOG("Option ipaExtdomMaxInstances [%zu] is larger or equal the number " + "of worker threads [%zu], using defaults.\n", + ctx->extdom_max_instances, threadnumber); + ctx->extdom_max_instances = 0; + } + + if (ctx->extdom_max_instances == 0) { + ctx->extdom_max_instances = (size_t)(threadnumber * 0.8); + if (ctx->extdom_max_instances == 0) { + ctx->extdom_max_instances = 1; + } + } + + LOG("Using maximal [%zu] extdom instances for [%zu] threads.\n", + ctx->extdom_max_instances, threadnumber); + return LDAP_SUCCESS; } @@ -78,6 +182,7 @@ static int ipa_extdom_extop(Slapi_PBlock *pb) struct extdom_req *req = NULL; struct ipa_extdom_ctx *ctx; enum extdom_version version; + bool counter_set = false; ret = slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &oid); if (ret != 0) { @@ -109,6 +214,16 @@ static int ipa_extdom_extop(Slapi_PBlock *pb) goto done; } + if (slapi_counter_get_value(ctx->extdom_instance_counter) + > ctx->extdom_max_instances) { + rc = LDAP_BUSY; + err_msg = "Too many extdom instances running.\n"; + goto done; + } + + slapi_counter_increment(ctx->extdom_instance_counter); + counter_set = true; + ret = parse_request_data(req_val, &req); if (ret != LDAP_SUCCESS) { rc = LDAP_UNWILLING_TO_PERFORM; @@ -151,6 +266,14 @@ static int ipa_extdom_extop(Slapi_PBlock *pb) rc = LDAP_SUCCESS; done: + if (counter_set) { + if (slapi_counter_get_value(ctx->extdom_instance_counter) == 0) { + LOG("Instance counter already 0, this is unexpected.\n"); + } else { + slapi_counter_decrement(ctx->extdom_instance_counter); + } + } + if ((req != NULL) && (req->err_msg != NULL)) { err_msg = req->err_msg; } @@ -219,6 +342,16 @@ static int ipa_extdom_init_ctx(Slapi_PBlock *pb, struct ipa_extdom_ctx **_ctx) back_extdom_set_timeout(ctx->nss_ctx, timeout); LOG("Maximal nss timeout (in ms) set to [%u]!\n", timeout); + ctx->extdom_max_instances = slapi_entry_attr_get_uint(e, "ipaExtdomMaxInstances"); + LOG("Maximal instances from config [%zu]!\n", ctx->extdom_max_instances); + + ctx->extdom_instance_counter = slapi_counter_new(); + if (ctx->extdom_instance_counter == NULL) { + LOG("Unable to initialize instance counter!\n"); + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + ret = 0; done: