redis-0004 + dragonfly-0001: ACL channel O(C×P) + cluster migration O(M²); memcached CLEAN; count 599→601
This commit is contained in:
parent
ff7bd27654
commit
1d6a8b8ccd
8 changed files with 413 additions and 4 deletions
119
defects/redis/unit/RedisAclChannelCheckAlgorithmTest.java
Normal file
119
defects/redis/unit/RedisAclChannelCheckAlgorithmTest.java
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
package unit;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Models Redis ACLCheckChannelAgainstList per-command channel pattern check.
|
||||
*
|
||||
* SLOW: O(C×P) — for each channel arg, scan all P patterns linearly via linked list.
|
||||
* FAST: O(C+P) — pre-build HashSet<exact> + List<glob> from selector; O(1) exact lookup.
|
||||
*
|
||||
* CWE-407: src/acl.c:1652,1694 (ACLCheckChannelAgainstList, ACLSelectorCheckCmd)
|
||||
*/
|
||||
public class RedisAclChannelCheckAlgorithmTest {
|
||||
|
||||
// Simplified match: exact match only (no glob) for benchmark purposes
|
||||
// In production, glob patterns need fnmatch — we model exact-pattern dominance
|
||||
|
||||
static class SlowAclSelector {
|
||||
final List<String> patterns; // linked-list analog
|
||||
long cmpOps = 0;
|
||||
|
||||
SlowAclSelector(List<String> patterns) { this.patterns = patterns; }
|
||||
|
||||
boolean channelAllowed(String channel) {
|
||||
for (String pat : patterns) {
|
||||
cmpOps++;
|
||||
if (pat.equals(channel)) return true; // exact match (simplification)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
long checkCommand(List<String> channels) {
|
||||
cmpOps = 0;
|
||||
for (String ch : channels) channelAllowed(ch);
|
||||
return cmpOps;
|
||||
}
|
||||
}
|
||||
|
||||
static class FastAclSelector {
|
||||
final Set<String> exactPatterns; // hash set for O(1) exact match
|
||||
long cmpOps = 0;
|
||||
|
||||
FastAclSelector(List<String> patterns) {
|
||||
exactPatterns = new HashSet<>(patterns);
|
||||
cmpOps = patterns.size(); // build cost
|
||||
}
|
||||
|
||||
boolean channelAllowed(String channel) {
|
||||
cmpOps++;
|
||||
return exactPatterns.contains(channel);
|
||||
}
|
||||
|
||||
long checkCommand(List<String> channels) {
|
||||
cmpOps = 0;
|
||||
for (String ch : channels) channelAllowed(ch);
|
||||
return cmpOps;
|
||||
}
|
||||
}
|
||||
|
||||
static List<String> makePatterns(int n) {
|
||||
List<String> p = new ArrayList<>();
|
||||
for (int i = 0; i < n; i++) p.add("channel:" + i);
|
||||
return p;
|
||||
}
|
||||
|
||||
static List<String> makeChannels(int c, int offset) {
|
||||
List<String> ch = new ArrayList<>();
|
||||
for (int i = 0; i < c; i++) ch.add("channel:" + (offset + i));
|
||||
return ch;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int passed = 0, total = 0;
|
||||
|
||||
System.out.println("=== redis-0004: ACLCheckChannelAgainstList O(C×P) ===");
|
||||
|
||||
// Test various (P, C) combinations
|
||||
int[][] cases = {{100, 10}, {500, 10}, {1000, 10}, {500, 50}};
|
||||
for (int[] cs : cases) {
|
||||
int p = cs[0], c = cs[1];
|
||||
List<String> patterns = makePatterns(p);
|
||||
// Channels not in patterns (worst case — full scan each time)
|
||||
List<String> channels = makeChannels(c, p + 1000);
|
||||
|
||||
SlowAclSelector slow = new SlowAclSelector(patterns);
|
||||
FastAclSelector fast = new FastAclSelector(patterns);
|
||||
|
||||
long s = slow.checkCommand(channels);
|
||||
long f = fast.checkCommand(channels);
|
||||
double ratio = (double) s / Math.max(f, 1);
|
||||
|
||||
total++;
|
||||
boolean ok = s > f && ratio >= 5.0;
|
||||
System.out.printf("P=%4d C=%3d slow=%8d fast=%5d ratio=%7.1fx %s%n",
|
||||
p, c, s, f, ratio, ok ? "PASS" : "FAIL");
|
||||
if (ok) passed++;
|
||||
}
|
||||
|
||||
// Correctness: both allow/deny same channels
|
||||
List<String> pats = makePatterns(100);
|
||||
SlowAclSelector slow = new SlowAclSelector(pats);
|
||||
FastAclSelector fast = new FastAclSelector(pats);
|
||||
|
||||
// Allowed channel
|
||||
total++;
|
||||
boolean correct1 = slow.channelAllowed("channel:42") == fast.channelAllowed("channel:42");
|
||||
System.out.printf("allow correctness (channel:42): %s%n", correct1 ? "PASS" : "FAIL");
|
||||
if (correct1) passed++;
|
||||
|
||||
// Denied channel
|
||||
total++;
|
||||
boolean correct2 = slow.channelAllowed("channel:9999") == fast.channelAllowed("channel:9999");
|
||||
System.out.printf("deny correctness (channel:9999): %s%n", correct2 ? "PASS" : "FAIL");
|
||||
if (correct2) passed++;
|
||||
|
||||
System.out.printf("%n%d/%d PASS%n", passed, total);
|
||||
if (passed < total) System.exit(1);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue