# UNDF: UNDF-2026-000000326 --- a/src/acl.c +++ b/src/acl.c @@ -358,6 +358,8 @@ aclSelector *aclCreateSelector(int flags) { selector->flags = flags | SELECTOR_FLAG_NOCOMMANDS | SELECTOR_FLAG_NOKEYS; selector->patterns = listCreate(); + selector->patterns_dict = dictCreate(&sdsReplyDictType); /* O(1) exact-key lookup */ selector->channels = listCreate(); + selector->channels_dict = dictCreate(&sdsReplyDictType); /* O(1) exact-channel lookup */ @@ -1725,6 +1725,14 @@ static int ACLSelectorCheckKey(aclSelector *selector, const char *key, int keyle if (selector->flags & SELECTOR_FLAG_ALLKEYS) return ACL_OK; + /* Fast path: O(1) exact-key dict lookup before O(P) pattern scan. + * Exact keys (no glob chars) are indexed in patterns_dict at SETUSER time. + * Only glob patterns remain in the linked list — typically zero or very few. */ + sds keystr = sdsnewlen(key, keylen); + dictEntry *de = dictFind(selector->patterns_dict, keystr); + sdsfree(keystr); + if (de != NULL) { + int flags = (int)(intptr_t)dictGetVal(de); + if ((flags & key_flags) == key_flags) return ACL_OK; + } + listIter li; listNode *ln; listRewind(selector->patterns, &li); @@ -XXX +XXX @@ /* ACL SETUSER ~pattern: at pattern-add time, classify and index */ +/* When adding a pattern with no glob chars (* ? [), insert into patterns_dict + * for O(1) key-exact lookup. Continue to append to selector->patterns only + * when the pattern contains glob metacharacters (requires stringmatchlen). + * This converts the common case (exact-key ACLs) from O(S×K×P) to O(S×K). */