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 <abokovoy@redhat.com>
This commit is contained in:
Sumit Bose 2019-03-08 16:07:56 +01:00 committed by Rob Crittenden
parent 2e73c964e5
commit 33af8c75b3
2 changed files with 135 additions and 0 deletions

View File

@ -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 {

View File

@ -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: