URL: https://github.com/freeipa/freeipa/pull/2891
Author: sumit-bose
 Title: #2891: ipa-extdom-exop: add instance counter and limit
Action: opened

PR body:
"""
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.
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/2891/head:pr2891
git checkout pr2891
From 7c137695b23226237d531043f20eed9f5f04ba12 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Fri, 8 Mar 2019 16:07:56 +0100
Subject: [PATCH] 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.
---
 .../ipa-extdom-extop/ipa_extdom.h             |   2 +
 .../ipa-extdom-extop/ipa_extdom_extop.c       | 133 ++++++++++++++++++
 2 files changed, 135 insertions(+)

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 bbc574747e..e01e74ca59 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 83c30e7e6a..3abaa411d2 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:
_______________________________________________
FreeIPA-devel mailing list -- freeipa-devel@lists.fedorahosted.org
To unsubscribe send an email to freeipa-devel-le...@lists.fedorahosted.org
Fedora Code of Conduct: https://getfedora.org/code-of-conduct.html
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedorahosted.org/archives/list/freeipa-devel@lists.fedorahosted.org

Reply via email to