Blame SOURCES/0030-Issue-4925-Performance-ACI-targetfilter-evaluation-r.patch

fcc543
From 4503d03aa3aa5b5f35f3db4cf1de838273e051a7 Mon Sep 17 00:00:00 2001
fcc543
From: tbordaz <tbordaz@redhat.com>
fcc543
Date: Thu, 23 Sep 2021 10:48:50 +0200
fcc543
Subject: [PATCH 1/2] Issue 4925 - Performance ACI: targetfilter evaluation
fcc543
 result can be reused (#4926)
fcc543
fcc543
Bug description:
fcc543
	An ACI may contain targetfilter. For a given returned entry, of a
fcc543
        SRCH request, the same targetfilter is evaluated for each of the
fcc543
        returned attributes.
fcc543
        Once the filter has been evaluated, it is useless to reevaluate
fcc543
        it for a next attribute.
fcc543
fcc543
Fix description:
fcc543
	The fix implements a very simple cache (linked list) that keeps
fcc543
        the results of the previously evaluated 'targetfilter'.
fcc543
        This cache is per-entry. For an operation, a aclpb is allocated
fcc543
        that is used to evaluate ACIs against each successive entry.
fcc543
        Each time a candidate entry is added in the aclpb
fcc543
        (acl_access_allowed), the cache (aclpb_curr_entry_targetfilters)
fcc543
        is freed. Then for each 'targetfilter', the original targetfilter
fcc543
        is lookup from the cache. If this is the first evaluation of it
fcc543
        then the result of the evaluation is stored into the cache using
fcc543
        the original targetfilter as the key in the cache
fcc543
fcc543
	The key to lookup/store the cache is the string representation
fcc543
        of the targetfilter. The string contains a redzone to detect
fcc543
        that the filter exceeds the maximum size (2K). If it exceeds
fcc543
        then the key is invalid and the lookup/store is noop.
fcc543
fcc543
relates: #4925
fcc543
fcc543
Reviewed by: Mark Reynolds, William Brown (Thanks)
fcc543
fcc543
Platforms tested: F34
fcc543
---
fcc543
 ldap/servers/plugins/acl/acl.c     | 138 +++++++++++++++++++++++++++--
fcc543
 ldap/servers/plugins/acl/acl.h     |  14 +++
fcc543
 ldap/servers/plugins/acl/acl_ext.c |  12 +++
fcc543
 ldap/servers/slapd/libglobs.c      |  29 ++++++
fcc543
 ldap/servers/slapd/proto-slap.h    |   2 +
fcc543
 ldap/servers/slapd/slap.h          |   2 +
fcc543
 6 files changed, 191 insertions(+), 6 deletions(-)
fcc543
fcc543
diff --git a/ldap/servers/plugins/acl/acl.c b/ldap/servers/plugins/acl/acl.c
fcc543
index ecd23aa88..646a369db 100644
fcc543
--- a/ldap/servers/plugins/acl/acl.c
fcc543
+++ b/ldap/servers/plugins/acl/acl.c
fcc543
@@ -66,6 +66,9 @@ static void print_access_control_summary(char *source,
fcc543
                                          const char *edn,
fcc543
                                          aclResultReason_t *acl_reason);
fcc543
 static int check_rdn_access(Slapi_PBlock *pb, Slapi_Entry *e, const char *newrdn, int access);
fcc543
+static struct targetfilter_cached_result *targetfilter_cache_lookup(struct acl_pblock *aclpb, char *filter, PRBool filter_valid);
fcc543
+static void targetfilter_cache_add(struct acl_pblock *aclpb, char *filter, int result, PRBool filter_valid);
fcc543
+
fcc543
 
fcc543
 
fcc543
 /*
fcc543
@@ -175,6 +178,70 @@ check_rdn_access(Slapi_PBlock *pb, Slapi_Entry *e, const char *dn, int access)
fcc543
     return (retCode);
fcc543
 }
fcc543
 
fcc543
+/* Retrieves, in the targetfilter cache (list), this
fcc543
+ * filter in case it was already evaluated
fcc543
+ *
fcc543
+ * filter: key to retrieve the evaluation in the cache
fcc543
+ * filter_valid: PR_FALSE means that the filter key is truncated, PR_TRUE else
fcc543
+ */
fcc543
+static struct targetfilter_cached_result *
fcc543
+targetfilter_cache_lookup(struct acl_pblock *aclpb, char *filter, PRBool filter_valid)
fcc543
+{
fcc543
+    struct targetfilter_cached_result *results;
fcc543
+    if (! aclpb->targetfilter_cache_enabled) {
fcc543
+        /* targetfilter cache is disabled */
fcc543
+        return NULL;
fcc543
+    }
fcc543
+    if (filter == NULL) {
fcc543
+        return NULL;
fcc543
+    }
fcc543
+    for(results = aclpb->aclpb_curr_entry_targetfilters; results; results = results->next) {
fcc543
+        if (strcmp(results->filter, filter) == 0) {
fcc543
+            return results;
fcc543
+        }
fcc543
+    }
fcc543
+
fcc543
+    return NULL;
fcc543
+}
fcc543
+
fcc543
+/* Free all evaluations cached for this current entry */
fcc543
+void
fcc543
+targetfilter_cache_free(struct acl_pblock *aclpb)
fcc543
+{
fcc543
+    struct targetfilter_cached_result *results, *next;
fcc543
+    if (aclpb == NULL) {
fcc543
+        return;
fcc543
+    }
fcc543
+    for(results = aclpb->aclpb_curr_entry_targetfilters; results;) {
fcc543
+        next = results->next;
fcc543
+        slapi_ch_free_string(&results->filter);
fcc543
+        slapi_ch_free((void **) &results);
fcc543
+        results = next;
fcc543
+    }
fcc543
+    aclpb->aclpb_curr_entry_targetfilters = NULL;
fcc543
+}
fcc543
+
fcc543
+/* add a new targetfilter evaluation into the cache (per entry)
fcc543
+ * ATM just use a linked list of evaluation
fcc543
+ *
fcc543
+ * filter: key to retrieve the evaluation in the cache
fcc543
+ * result: result of the evaluation
fcc543
+ * filter_valid: PR_FALSE means that the filter key is truncated, PR_TRUE else
fcc543
+ */
fcc543
+static void
fcc543
+targetfilter_cache_add(struct acl_pblock *aclpb, char *filter, int result, PRBool filter_valid)
fcc543
+{
fcc543
+    struct targetfilter_cached_result *results;
fcc543
+    if (! filter_valid || ! aclpb->targetfilter_cache_enabled) {
fcc543
+        /* targetfilter cache is disabled or filter is truncated */
fcc543
+        return;
fcc543
+    }
fcc543
+    results = (struct targetfilter_cached_result *) slapi_ch_calloc(1, (sizeof(struct targetfilter_cached_result)));
fcc543
+    results->filter = slapi_ch_strdup(filter);
fcc543
+    results->next = aclpb->aclpb_curr_entry_targetfilters;
fcc543
+    results->matching_result = result;
fcc543
+    aclpb->aclpb_curr_entry_targetfilters = results;
fcc543
+}
fcc543
 /***************************************************************************
fcc543
 *
fcc543
 * acl_access_allowed
fcc543
@@ -495,6 +562,7 @@ acl_access_allowed(
fcc543
 
fcc543
         /* Keep the ptr to the current entry */
fcc543
         aclpb->aclpb_curr_entry = (Slapi_Entry *)e;
fcc543
+        targetfilter_cache_free(aclpb);
fcc543
 
fcc543
         /* Get the attr info */
fcc543
         deallocate_attrEval = acl__get_attrEval(aclpb, attr);
fcc543
@@ -1922,7 +1990,7 @@ acl_modified(Slapi_PBlock *pb, int optype, Slapi_DN *e_sdn, void *change)
fcc543
 *    None.
fcc543
 *
fcc543
 **************************************************************************/
fcc543
-static int
fcc543
+int
fcc543
 acl__scan_for_acis(Acl_PBlock *aclpb, int *err)
fcc543
 {
fcc543
     aci_t *aci;
fcc543
@@ -2403,10 +2471,68 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
fcc543
                                                     ACL_EVAL_TARGET_FILTER);
fcc543
             slapi_ch_free((void **)&lasinfo);
fcc543
         } else {
fcc543
-            if (slapi_vattr_filter_test(NULL, aclpb->aclpb_curr_entry,
fcc543
-                                        aci->targetFilter,
fcc543
-                                        0 /*don't do access check*/) != 0) {
fcc543
-                filter_matched = ACL_FALSE;
fcc543
+            Slapi_DN *sdn;
fcc543
+            char* attr_evaluated = "None";
fcc543
+            char logbuf[2048] = {0};
fcc543
+            char *redzone = "the redzone";
fcc543
+            int32_t redzone_idx;
fcc543
+            char *filterstr; /* key to retrieve/add targetfilter value in the cache */
fcc543
+            PRBool valid_filter;
fcc543
+            struct targetfilter_cached_result *previous_filter_test;
fcc543
+
fcc543
+            /* only usefull for debug purpose */
fcc543
+            if (aclpb->aclpb_curr_attrEval && aclpb->aclpb_curr_attrEval->attrEval_name) {
fcc543
+                attr_evaluated = aclpb->aclpb_curr_attrEval->attrEval_name;
fcc543
+            }
fcc543
+            sdn = slapi_entry_get_sdn(aclpb->aclpb_curr_entry);
fcc543
+
fcc543
+            /* The key for the cache is the string representation of the original filter
fcc543
+             * If the string can not fit into the provided buffer (overwrite redzone)
fcc543
+             * then the filter is said invalid (for the cache) and it will be evaluated
fcc543
+             */
fcc543
+            redzone_idx = sizeof(logbuf) - 1 - strlen(redzone);
fcc543
+            strcpy(&logbuf[redzone_idx], redzone);
fcc543
+            filterstr = slapi_filter_to_string(aci->targetFilter, logbuf, sizeof(logbuf));
fcc543
+
fcc543
+            /* if the redzone was overwritten that means filterstr is truncated and not valid */
fcc543
+            valid_filter = (strcmp(&logbuf[redzone_idx], redzone) == 0);
fcc543
+            if (!valid_filter) {
fcc543
+                strcpy(&logbuf[50], "...");
fcc543
+                slapi_log_err(SLAPI_LOG_ACL, "acl__ressource_match_aci", "targetfilter too large (can not be cache) %s\n", logbuf);
fcc543
+            }
fcc543
+
fcc543
+            previous_filter_test = targetfilter_cache_lookup(aclpb, filterstr, valid_filter);
fcc543
+            if (previous_filter_test) {
fcc543
+                /* The filter was already evaluated against that same entry */
fcc543
+                if (previous_filter_test->matching_result == 0) {
fcc543
+                    slapi_log_err(SLAPI_LOG_ACL, "acl__ressource_match_aci", "cached result for entry %s did NOT match %s (%s)\n",
fcc543
+                            slapi_sdn_get_ndn(sdn),
fcc543
+                            filterstr,
fcc543
+                            attr_evaluated);
fcc543
+                    filter_matched = ACL_FALSE;
fcc543
+                } else {
fcc543
+                    slapi_log_err(SLAPI_LOG_ACL, "acl__ressource_match_aci", "cached result for entry %s did match %s (%s)\n",
fcc543
+                            slapi_sdn_get_ndn(sdn),
fcc543
+                            filterstr,
fcc543
+                            attr_evaluated);
fcc543
+                }
fcc543
+            } else {
fcc543
+                /* The filter has not already been evaluated against that entry
fcc543
+                 * evaluate it and cache the result
fcc543
+                 */
fcc543
+                if (slapi_vattr_filter_test(NULL, aclpb->aclpb_curr_entry,
fcc543
+                        aci->targetFilter,
fcc543
+                        0 /*don't do access check*/) != 0) {
fcc543
+                    filter_matched = ACL_FALSE;
fcc543
+                    targetfilter_cache_add(aclpb, filterstr, 0, valid_filter); /* does not match */
fcc543
+                } else {
fcc543
+                    targetfilter_cache_add(aclpb, filterstr, 1, valid_filter); /* does match */
fcc543
+                }
fcc543
+                slapi_log_err(SLAPI_LOG_ACL, "acl__ressource_match_aci", "entry %s %s match %s (%s)\n",
fcc543
+                        slapi_sdn_get_ndn(sdn),
fcc543
+                        filter_matched == ACL_FALSE ? "does not" : "does",
fcc543
+                        filterstr,
fcc543
+                        attr_evaluated);
fcc543
             }
fcc543
         }
fcc543
 
fcc543
@@ -2862,7 +2988,7 @@ acl__resource_match_aci_EXIT:
fcc543
 *    None.
fcc543
 *
fcc543
 **************************************************************************/
fcc543
-static int
fcc543
+int
fcc543
 acl__TestRights(Acl_PBlock *aclpb, int access, const char **right, const char **map_generic, aclResultReason_t *result_reason)
fcc543
 {
fcc543
     ACLEvalHandle_t *acleval;
fcc543
diff --git a/ldap/servers/plugins/acl/acl.h b/ldap/servers/plugins/acl/acl.h
fcc543
index 5d453d825..cf74510e7 100644
fcc543
--- a/ldap/servers/plugins/acl/acl.h
fcc543
+++ b/ldap/servers/plugins/acl/acl.h
fcc543
@@ -407,6 +407,17 @@ struct aci_container
fcc543
 };
fcc543
 typedef struct aci_container AciContainer;
fcc543
 
fcc543
+/* This structure is stored in the aclpb.
fcc543
+ * It is a linked list containing the result of
fcc543
+ * the filter matching against a specific entry.
fcc543
+ *
fcc543
+ * This list is free for each new entry in the aclpb*/
fcc543
+struct targetfilter_cached_result {
fcc543
+    char *filter;                            /* strdup of string representation of aci->targetFilter */
fcc543
+    int matching_result;                     /* 0 does not match / 1 does match */
fcc543
+    struct targetfilter_cached_result *next; /* next targetfilter already evaluated */
fcc543
+};
fcc543
+
fcc543
 struct acl_pblock
fcc543
 {
fcc543
     int aclpb_state;
fcc543
@@ -476,6 +487,8 @@ struct acl_pblock
fcc543
 
fcc543
     /* Current entry/dn/attr evaluation info */
fcc543
     Slapi_Entry *aclpb_curr_entry; /* current Entry being processed */
fcc543
+    int32_t targetfilter_cache_enabled;
fcc543
+    struct targetfilter_cached_result *aclpb_curr_entry_targetfilters;
fcc543
     int aclpb_num_entries;
fcc543
     Slapi_DN *aclpb_curr_entry_sdn;    /* Entry's SDN */
fcc543
     Slapi_DN *aclpb_authorization_sdn; /* dn used for authorization */
fcc543
@@ -723,6 +736,7 @@ void acl_modified(Slapi_PBlock *pb, int optype, Slapi_DN *e_sdn, void *change);
fcc543
 
fcc543
 int acl_access_allowed_disjoint_resource(Slapi_PBlock *pb, Slapi_Entry *e, char *attr, struct berval *val, int access);
fcc543
 int acl_access_allowed_main(Slapi_PBlock *pb, Slapi_Entry *e, char **attrs, struct berval *val, int access, int flags, char **errbuf);
fcc543
+void targetfilter_cache_free(struct acl_pblock *aclpb);
fcc543
 int acl_access_allowed(Slapi_PBlock *pb, Slapi_Entry *e, char *attr, struct berval *val, int access);
fcc543
 aclUserGroup *acl_get_usersGroup(struct acl_pblock *aclpb, char *n_dn);
fcc543
 void acl_print_acllib_err(NSErr_t *errp, char *str);
fcc543
diff --git a/ldap/servers/plugins/acl/acl_ext.c b/ldap/servers/plugins/acl/acl_ext.c
fcc543
index 31c61c2f4..73dd6c39d 100644
fcc543
--- a/ldap/servers/plugins/acl/acl_ext.c
fcc543
+++ b/ldap/servers/plugins/acl/acl_ext.c
fcc543
@@ -187,6 +187,11 @@ acl_operation_ext_constructor(void *object __attribute__((unused)), void *parent
fcc543
         slapi_log_err(SLAPI_LOG_ERR, plugin_name,
fcc543
                       "acl_operation_ext_constructor - Operation extension allocation Failed\n");
fcc543
     }
fcc543
+    /* targetfilter_cache toggle set during aclpb allocation
fcc543
+     * to avoid accessing configuration during the evaluation
fcc543
+     * of each aci
fcc543
+     */
fcc543
+    aclpb->targetfilter_cache_enabled = config_get_targetfilter_cache();
fcc543
 
fcc543
     TNF_PROBE_0_DEBUG(acl_operation_ext_constructor_end, "ACL", "");
fcc543
 
fcc543
@@ -711,6 +716,7 @@ acl__free_aclpb(Acl_PBlock **aclpb_ptr)
fcc543
     slapi_ch_free((void **)&(aclpb->aclpb_curr_entryEval_context.acle_handles_matched_target));
fcc543
     slapi_ch_free((void **)&(aclpb->aclpb_prev_entryEval_context.acle_handles_matched_target));
fcc543
     slapi_ch_free((void **)&(aclpb->aclpb_prev_opEval_context.acle_handles_matched_target));
fcc543
+    targetfilter_cache_free(aclpb);
fcc543
     slapi_sdn_free(&aclpb->aclpb_authorization_sdn);
fcc543
     slapi_sdn_free(&aclpb->aclpb_curr_entry_sdn);
fcc543
     if (aclpb->aclpb_macro_ht) {
fcc543
@@ -919,6 +925,12 @@ acl__done_aclpb(struct acl_pblock *aclpb)
fcc543
                       aclpb->aclpb_acleval ? (char *)aclpb->aclpb_acleval : "NULL");
fcc543
     }
fcc543
 
fcc543
+    /* This aclpb return to the aclpb pool, make sure
fcc543
+     * the cached evaluations are freed and that
fcc543
+     * aclpb_curr_entry_targetfilters is NULL
fcc543
+     */
fcc543
+    targetfilter_cache_free(aclpb);
fcc543
+
fcc543
     /* Now Free the contents or clean it */
fcc543
     slapi_sdn_done(aclpb->aclpb_curr_entry_sdn);
fcc543
     if (aclpb->aclpb_Evalattr)
fcc543
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
fcc543
index 91c3a4a89..89f7e5344 100644
fcc543
--- a/ldap/servers/slapd/libglobs.c
fcc543
+++ b/ldap/servers/slapd/libglobs.c
fcc543
@@ -211,6 +211,7 @@ slapi_onoff_t init_return_exact_case;
fcc543
 slapi_onoff_t init_result_tweak;
fcc543
 slapi_onoff_t init_plugin_track;
fcc543
 slapi_onoff_t init_moddn_aci;
fcc543
+slapi_onoff_t init_targetfilter_cache;
fcc543
 slapi_onoff_t init_lastmod;
fcc543
 slapi_onoff_t init_readonly;
fcc543
 slapi_onoff_t init_accesscontrol;
fcc543
@@ -822,6 +823,11 @@ static struct config_get_and_set
fcc543
      (void **)&global_slapdFrontendConfig.moddn_aci,
fcc543
      CONFIG_ON_OFF, (ConfigGetFunc)config_get_moddn_aci,
fcc543
      &init_moddn_aci},
fcc543
+    {CONFIG_TARGETFILTER_CACHE_ATTRIBUTE, config_set_targetfilter_cache,
fcc543
+     NULL, 0,
fcc543
+     (void **)&global_slapdFrontendConfig.targetfilter_cache,
fcc543
+     CONFIG_ON_OFF, (ConfigGetFunc)config_get_targetfilter_cache,
fcc543
+     &init_targetfilter_cache},
fcc543
     {CONFIG_ATTRIBUTE_NAME_EXCEPTION_ATTRIBUTE, config_set_attrname_exceptions,
fcc543
      NULL, 0,
fcc543
      (void **)&global_slapdFrontendConfig.attrname_exceptions,
fcc543
@@ -1567,6 +1573,7 @@ FrontendConfig_init(void)
fcc543
     init_syntaxcheck = cfg->syntaxcheck = LDAP_ON;
fcc543
     init_plugin_track = cfg->plugin_track = LDAP_OFF;
fcc543
     init_moddn_aci = cfg->moddn_aci = LDAP_ON;
fcc543
+    init_targetfilter_cache = cfg->targetfilter_cache = LDAP_ON;
fcc543
     init_syntaxlogging = cfg->syntaxlogging = LDAP_OFF;
fcc543
     init_dn_validate_strict = cfg->dn_validate_strict = LDAP_OFF;
fcc543
     init_ds4_compatible_schema = cfg->ds4_compatible_schema = LDAP_OFF;
fcc543
@@ -3525,6 +3532,21 @@ config_set_moddn_aci(const char *attrname, char *value, char *errorbuf, int appl
fcc543
     return retVal;
fcc543
 }
fcc543
 
fcc543
+int32_t
fcc543
+config_set_targetfilter_cache(const char *attrname, char *value, char *errorbuf, int apply)
fcc543
+{
fcc543
+    int32_t retVal = LDAP_SUCCESS;
fcc543
+    slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
fcc543
+
fcc543
+    retVal = config_set_onoff(attrname,
fcc543
+                              value,
fcc543
+                              &(slapdFrontendConfig->targetfilter_cache),
fcc543
+                              errorbuf,
fcc543
+                              apply);
fcc543
+
fcc543
+    return retVal;
fcc543
+}
fcc543
+
fcc543
 int32_t
fcc543
 config_set_dynamic_plugins(const char *attrname, char *value, char *errorbuf, int apply)
fcc543
 {
fcc543
@@ -5334,6 +5356,13 @@ config_get_moddn_aci(void)
fcc543
     return slapi_atomic_load_32(&(slapdFrontendConfig->moddn_aci), __ATOMIC_ACQUIRE);
fcc543
 }
fcc543
 
fcc543
+int32_t
fcc543
+config_get_targetfilter_cache(void)
fcc543
+{
fcc543
+    slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
fcc543
+    return slapi_atomic_load_32(&(slapdFrontendConfig->targetfilter_cache), __ATOMIC_ACQUIRE);
fcc543
+}
fcc543
+
fcc543
 int32_t
fcc543
 config_get_security(void)
fcc543
 {
fcc543
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
fcc543
index d9fb8fd08..13b41ffa4 100644
fcc543
--- a/ldap/servers/slapd/proto-slap.h
fcc543
+++ b/ldap/servers/slapd/proto-slap.h
fcc543
@@ -262,6 +262,7 @@ int config_set_lastmod(const char *attrname, char *value, char *errorbuf, int ap
fcc543
 int config_set_nagle(const char *attrname, char *value, char *errorbuf, int apply);
fcc543
 int config_set_accesscontrol(const char *attrname, char *value, char *errorbuf, int apply);
fcc543
 int config_set_moddn_aci(const char *attrname, char *value, char *errorbuf, int apply);
fcc543
+int32_t config_set_targetfilter_cache(const char *attrname, char *value, char *errorbuf, int apply);
fcc543
 int config_set_security(const char *attrname, char *value, char *errorbuf, int apply);
fcc543
 int config_set_readonly(const char *attrname, char *value, char *errorbuf, int apply);
fcc543
 int config_set_schemacheck(const char *attrname, char *value, char *errorbuf, int apply);
fcc543
@@ -450,6 +451,7 @@ int config_get_accesscontrol(void);
fcc543
 int config_get_return_exact_case(void);
fcc543
 int config_get_result_tweak(void);
fcc543
 int config_get_moddn_aci(void);
fcc543
+int32_t config_get_targetfilter_cache(void);
fcc543
 int config_get_security(void);
fcc543
 int config_get_schemacheck(void);
fcc543
 int config_get_syntaxcheck(void);
fcc543
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
fcc543
index 007c50b86..b2de66754 100644
fcc543
--- a/ldap/servers/slapd/slap.h
fcc543
+++ b/ldap/servers/slapd/slap.h
fcc543
@@ -2157,6 +2157,7 @@ typedef struct _slapdEntryPoints
fcc543
 #define CONFIG_REWRITE_RFC1274_ATTRIBUTE "nsslapd-rewrite-rfc1274"
fcc543
 #define CONFIG_PLUGIN_BINDDN_TRACKING_ATTRIBUTE "nsslapd-plugin-binddn-tracking"
fcc543
 #define CONFIG_MODDN_ACI_ATTRIBUTE "nsslapd-moddn-aci"
fcc543
+#define CONFIG_TARGETFILTER_CACHE_ATTRIBUTE "nsslapd-targetfilter-cache"
fcc543
 #define CONFIG_GLOBAL_BACKEND_LOCK "nsslapd-global-backend-lock"
fcc543
 #define CONFIG_ENABLE_NUNC_STANS "nsslapd-enable-nunc-stans"
fcc543
 #define CONFIG_CONFIG_ATTRIBUTE "nsslapd-config"
fcc543
@@ -2315,6 +2316,7 @@ typedef struct _slapdFrontendConfig
fcc543
     char **plugin;
fcc543
     slapi_onoff_t plugin_track;
fcc543
     slapi_onoff_t moddn_aci;
fcc543
+    slapi_onoff_t targetfilter_cache;
fcc543
     struct pw_scheme *pw_storagescheme;
fcc543
     slapi_onoff_t pwpolicy_local;
fcc543
     slapi_onoff_t pw_is_global_policy;
fcc543
-- 
fcc543
2.31.1
fcc543