Skip to content

Commit ccde868

Browse files
committed
refactor(redis): unify command registry to eliminate route/argsLen/table drift
Root-cause fix for the post-merge CI failure on this branch (TestCommand _RouteMatchesTable / TestCommandCount_MatchesTableSize) and for the recurring Codex P2 (HELLO missing from redisCommandTable). Both symptoms shared the same underlying cause: command registration was spread across THREE separate maps (r.route in redis.go, argsLen in redis.go, redisCommandTable in redis_command_info.go) and adding a new command required updating all three by hand. HELLO was added to the first two on main but missed the third — silently breaking COMMAND INFO HELLO and tripping the route-vs-table mirror test. This refactor collapses the three views to a single source of truth. Single-row registration (adapter/redis_command_specs.go): - redisCommandSpecs is the canonical slice. Each row carries Constant / Name / Arity / Flags / FirstKey / LastKey / Step. - argsLen is derived from the slice once at init (function-call package var initializer); same for redisCommandTable. - buildRouteMap binds handlers per RedisServer and panics at server construction if any spec lacks a handler or any handler lacks a spec, so the surviving 2-way sync between specs and handlers is enforced at startup rather than at first request. Why handlers stay separate from the spec slice: - Embedding method values directly in the spec literal triggered a Go init cycle (redisCommandSpecs → method body → argsLen → redisCommandSpecs) because Go's init-order analysis follows function bodies. The buildRouteMap layout sidesteps the cycle while keeping the structural invariant under test. Tests added: - TestRedisCommandSpecs_NoDuplicateConstants pins the "every Constant appears exactly once" invariant — without it a duplicate spec would silently shadow earlier rows in the derived maps. - TestRedisCommandSpecs_HELLOPresent is the explicit regression guard: HELLO must have a redisCommandTable row (the exact gap Codex P2 + TestCommand_RouteMatchesTable both flagged). - The pre-existing TestCommand_RouteMatchesTable and TestCommandCount_MatchesTableSize now pass by construction; they remain as the perimeter check for "anything routed must be tabled". Build / vet / lint clean. CI failures from the previous merge commit (3632cdc) are eliminated by construction.
1 parent 92e7e10 commit ccde868

4 files changed

Lines changed: 323 additions & 275 deletions

File tree

adapter/redis.go

Lines changed: 8 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -165,92 +165,9 @@ var txnApplyHandlers = map[string]txnCommandHandler{
165165
cmdPExpire: (*txnContext).applyExpireMilliseconds,
166166
}
167167

168-
//nolint:mnd
169-
var argsLen = map[string]int{
170-
cmdBZPopMin: -3,
171-
cmdClient: -2,
172-
cmdCommand: -1,
173-
cmdDBSize: 1,
174-
cmdDel: -2,
175-
cmdDiscard: 1,
176-
cmdEval: -3,
177-
cmdEvalSHA: -3,
178-
cmdExec: 1,
179-
cmdExists: -2,
180-
cmdExpire: -3,
181-
cmdFlushAll: 1,
182-
cmdFlushDB: 1,
183-
cmdFlushLegacy: 1,
184-
cmdGet: 2,
185-
cmdGetDel: 2,
186-
cmdHDel: -3,
187-
cmdHExists: 3,
188-
cmdHGet: 3,
189-
cmdHGetAll: 2,
190-
cmdHIncrBy: 4,
191-
cmdHLen: 2,
192-
cmdHMGet: -3,
193-
cmdHMSet: -4,
194-
cmdHSet: -4,
195-
cmdHello: -1,
196-
cmdInfo: -1,
197-
cmdIncr: 2,
198-
cmdKeys: 2,
199-
cmdLIndex: 3,
200-
cmdLLen: 2,
201-
cmdLPop: 2,
202-
cmdLPush: -3,
203-
cmdLPos: -3,
204-
cmdLRange: 4,
205-
cmdLRem: 4,
206-
cmdLSet: 4,
207-
cmdLTrim: 4,
208-
cmdMulti: 1,
209-
cmdPExpire: -3,
210-
cmdPFAdd: -3,
211-
cmdPFCount: -2,
212-
cmdPing: -1,
213-
cmdPTTL: 2,
214-
cmdPublish: 3,
215-
cmdPubSub: -2,
216-
cmdQuit: 1,
217-
cmdRename: 3,
218-
cmdRPop: 2,
219-
cmdRPopLPush: 3,
220-
cmdRPush: -3,
221-
cmdSAdd: -3,
222-
cmdSCard: 2,
223-
cmdScan: -2,
224-
cmdSelect: 2,
225-
cmdSet: -3,
226-
cmdSetEx: 4,
227-
cmdSetNX: 3,
228-
cmdSIsMember: 3,
229-
cmdSMembers: 2,
230-
cmdSRem: -3,
231-
cmdSubscribe: -2,
232-
cmdTTL: 2,
233-
cmdType: 2,
234-
cmdXAdd: -5,
235-
cmdXLen: 2,
236-
cmdXRead: -4,
237-
cmdXRange: -4,
238-
cmdXRevRange: -4,
239-
cmdXTrim: -4,
240-
cmdZAdd: -4,
241-
cmdZCard: 2,
242-
cmdZCount: 4,
243-
cmdZIncrBy: 4,
244-
cmdZRange: -4,
245-
cmdZRangeByScore: -4,
246-
cmdZRem: -3,
247-
cmdZRemRangeByScore: 4,
248-
cmdZRemRangeByRank: 4,
249-
cmdZPopMin: -2,
250-
cmdZRevRange: -4,
251-
cmdZRevRangeByScore: -4,
252-
cmdZScore: 3,
253-
}
168+
// argsLen is derived from redisCommandSpecs in adapter/redis_command_specs.go.
169+
// See that file for the canonical row list and the rationale for the
170+
// single source of truth.
254171

255172
type RedisServer struct {
256173
listen net.Listener
@@ -434,91 +351,11 @@ func NewRedisServer(listen net.Listener, redisAddr string, store store.MVCCStore
434351
}
435352
r.relay.Bind(r.publishLocal)
436353

437-
r.route = map[string]func(conn redcon.Conn, cmd redcon.Command){
438-
cmdBZPopMin: r.bzpopmin,
439-
cmdClient: r.client,
440-
cmdCommand: r.command,
441-
cmdDBSize: r.dbsize,
442-
cmdDel: r.del,
443-
cmdDiscard: r.discard,
444-
cmdEval: r.eval,
445-
cmdEvalSHA: r.evalsha,
446-
cmdExec: r.exec,
447-
cmdExists: r.exists,
448-
cmdExpire: r.expire,
449-
cmdFlushAll: r.flushall,
450-
cmdFlushDB: r.flushdb,
451-
cmdFlushLegacy: r.flushlegacy,
452-
cmdGet: r.get,
453-
cmdGetDel: r.getdel,
454-
cmdHDel: r.hdel,
455-
cmdHExists: r.hexists,
456-
cmdHGet: r.hget,
457-
cmdHGetAll: r.hgetall,
458-
cmdHIncrBy: r.hincrby,
459-
cmdHLen: r.hlen,
460-
cmdHMGet: r.hmget,
461-
cmdHMSet: r.hmset,
462-
cmdHSet: r.hset,
463-
cmdHello: r.hello,
464-
cmdInfo: r.info,
465-
cmdIncr: r.incr,
466-
cmdKeys: r.keys,
467-
cmdLIndex: r.lindex,
468-
cmdLLen: r.llen,
469-
cmdLPop: r.lpop,
470-
cmdLPos: r.lpos,
471-
cmdLPush: r.lpush,
472-
cmdLRange: r.lrange,
473-
cmdLRem: r.lrem,
474-
cmdLSet: r.lset,
475-
cmdLTrim: r.ltrim,
476-
cmdMulti: r.multi,
477-
cmdPExpire: r.pexpire,
478-
cmdPFAdd: r.pfadd,
479-
cmdPFCount: r.pfcount,
480-
cmdPing: r.ping,
481-
cmdPTTL: r.pttl,
482-
cmdPublish: r.publish,
483-
cmdPubSub: r.pubsubCmd,
484-
cmdQuit: r.quit,
485-
cmdRename: r.rename,
486-
cmdRPop: r.rpop,
487-
cmdRPopLPush: r.rpoplpush,
488-
cmdRPush: r.rpush,
489-
cmdSAdd: r.sadd,
490-
cmdSCard: r.scard,
491-
cmdScan: r.scan,
492-
cmdSelect: r.selectDB,
493-
cmdSet: r.set,
494-
cmdSetEx: r.setex,
495-
cmdSetNX: r.setnx,
496-
cmdSIsMember: r.sismember,
497-
cmdSMembers: r.smembers,
498-
cmdSRem: r.srem,
499-
cmdSubscribe: r.subscribe,
500-
cmdTTL: r.ttl,
501-
cmdType: r.typeCmd,
502-
cmdXAdd: r.xadd,
503-
cmdXLen: r.xlen,
504-
cmdXRead: r.xread,
505-
cmdXRange: r.xrange,
506-
cmdXRevRange: r.xrevrange,
507-
cmdXTrim: r.xtrim,
508-
cmdZAdd: r.zadd,
509-
cmdZCard: r.zcard,
510-
cmdZCount: r.zcount,
511-
cmdZIncrBy: r.zincrby,
512-
cmdZRange: r.zrange,
513-
cmdZRangeByScore: r.zrangebyscore,
514-
cmdZRem: r.zrem,
515-
cmdZRemRangeByScore: r.zremrangebyscore,
516-
cmdZRemRangeByRank: r.zremrangebyrank,
517-
cmdZPopMin: r.zpopmin,
518-
cmdZRevRange: r.zrevrange,
519-
cmdZRevRangeByScore: r.zrevrangebyscore,
520-
cmdZScore: r.zscore,
521-
}
354+
// route, argsLen, and redisCommandTable all derive from the single
355+
// redisCommandSpecs slice (adapter/redis_command_specs.go) so adding
356+
// a command is a one-row diff there and the three views can never
357+
// drift. See buildRouteMap for the per-server bind.
358+
r.route = r.buildRouteMap()
522359
for _, opt := range opts {
523360
if opt != nil {
524361
opt(r)

adapter/redis_command_info.go

Lines changed: 7 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
package adapter
22

3-
// redis_command_info.go holds the static metadata table consumed by the
4-
// Redis `COMMAND` handler. It is intentionally a single, grep-able file so
5-
// that adding a new command is a one-liner:
6-
//
7-
// 1) Register the new handler in RedisServer.route (redis.go).
8-
// 2) Add an argsLen entry (redis.go).
9-
// 3) Add a row below. Forgetting step 3 is NOT fatal — the COMMAND
10-
// handler falls back to a zero-metadata entry and emits one warning
11-
// log per command name so the omission is discoverable — but you
12-
// should do step 3 anyway.
13-
//
14-
// The table is the source of truth for `COMMAND`, `COMMAND INFO`,
15-
// `COMMAND COUNT`, `COMMAND LIST`, `COMMAND DOCS`, and `COMMAND GETKEYS`.
3+
// redis_command_info.go holds the COMMAND-family helpers. The metadata
4+
// table itself (redisCommandTable) and the routed-set source of truth
5+
// (argsLen) both live in adapter/redis_command_specs.go and are derived
6+
// from the canonical redisCommandSpecs slice — adding a new command is
7+
// a single row there, with no risk of drifting between r.route /
8+
// argsLen / redisCommandTable the way HELLO did when it was added to
9+
// the route + arity check but missed the metadata table.
1610
//
1711
// Shape notes (Redis reference):
1812
// - arity: exact positive arity, or negative meaning "at least |arity|"
@@ -53,97 +47,6 @@ type redisCommandMeta struct {
5347
Step int
5448
}
5549

56-
// redisCommandTable maps UPPERCASE command name -> metadata. Every entry
57-
// routed by RedisServer.route should appear here. Entries are listed in
58-
// alphabetical order to keep diffs small when adding new commands.
59-
//
60-
//nolint:mnd // magic numbers here are literal Redis metadata (arity, key positions)
61-
var redisCommandTable = map[string]redisCommandMeta{
62-
"BZPOPMIN": {Name: "bzpopmin", Arity: -3, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: -2, Step: 1},
63-
"CLIENT": {Name: "client", Arity: -2, Flags: []string{redisCmdFlagAdmin}, FirstKey: 0, LastKey: 0, Step: 0},
64-
"COMMAND": {Name: "command", Arity: -1, Flags: []string{redisCmdFlagAdmin}, FirstKey: 0, LastKey: 0, Step: 0},
65-
"DBSIZE": {Name: "dbsize", Arity: 1, Flags: []string{redisCmdFlagReadonly}, FirstKey: 0, LastKey: 0, Step: 0},
66-
"DEL": {Name: "del", Arity: -2, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: -1, Step: 1},
67-
"DISCARD": {Name: "discard", Arity: 1, Flags: []string{redisCmdFlagAdmin}, FirstKey: 0, LastKey: 0, Step: 0},
68-
"EVAL": {Name: "eval", Arity: -3, Flags: []string{redisCmdFlagWrite}, FirstKey: 0, LastKey: 0, Step: 0},
69-
"EVALSHA": {Name: "evalsha", Arity: -3, Flags: []string{redisCmdFlagWrite}, FirstKey: 0, LastKey: 0, Step: 0},
70-
"EXEC": {Name: "exec", Arity: 1, Flags: []string{redisCmdFlagAdmin}, FirstKey: 0, LastKey: 0, Step: 0},
71-
"EXISTS": {Name: "exists", Arity: -2, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: -1, Step: 1},
72-
"EXPIRE": {Name: "expire", Arity: -3, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
73-
"FLUSHALL": {Name: "flushall", Arity: 1, Flags: []string{redisCmdFlagWrite}, FirstKey: 0, LastKey: 0, Step: 0},
74-
"FLUSHDB": {Name: "flushdb", Arity: 1, Flags: []string{redisCmdFlagWrite}, FirstKey: 0, LastKey: 0, Step: 0},
75-
// FLUSHLEGACY is an elastickv-internal alias; mirror FLUSHDB metadata.
76-
"FLUSHLEGACY": {Name: "flushlegacy", Arity: 1, Flags: []string{redisCmdFlagWrite}, FirstKey: 0, LastKey: 0, Step: 0},
77-
"GET": {Name: "get", Arity: 2, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
78-
"GETDEL": {Name: "getdel", Arity: 2, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
79-
"HDEL": {Name: "hdel", Arity: -3, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
80-
"HEXISTS": {Name: "hexists", Arity: 3, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
81-
"HGET": {Name: "hget", Arity: 3, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
82-
"HGETALL": {Name: "hgetall", Arity: 2, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
83-
"HINCRBY": {Name: "hincrby", Arity: 4, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
84-
"HLEN": {Name: "hlen", Arity: 2, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
85-
"HMGET": {Name: "hmget", Arity: -3, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
86-
"HMSET": {Name: "hmset", Arity: -4, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
87-
"HSET": {Name: "hset", Arity: -4, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
88-
"INCR": {Name: "incr", Arity: 2, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
89-
"INFO": {Name: "info", Arity: -1, Flags: []string{redisCmdFlagAdmin}, FirstKey: 0, LastKey: 0, Step: 0},
90-
"KEYS": {Name: "keys", Arity: 2, Flags: []string{redisCmdFlagReadonly}, FirstKey: 0, LastKey: 0, Step: 0},
91-
"LINDEX": {Name: "lindex", Arity: 3, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
92-
"LLEN": {Name: "llen", Arity: 2, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
93-
"LPOP": {Name: "lpop", Arity: 2, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
94-
"LPOS": {Name: "lpos", Arity: -3, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
95-
"LPUSH": {Name: "lpush", Arity: -3, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
96-
"LRANGE": {Name: "lrange", Arity: 4, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
97-
"LREM": {Name: "lrem", Arity: 4, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
98-
"LSET": {Name: "lset", Arity: 4, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
99-
"LTRIM": {Name: "ltrim", Arity: 4, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
100-
"MULTI": {Name: "multi", Arity: 1, Flags: []string{redisCmdFlagAdmin}, FirstKey: 0, LastKey: 0, Step: 0},
101-
"PEXPIRE": {Name: "pexpire", Arity: -3, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
102-
"PFADD": {Name: "pfadd", Arity: -3, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
103-
"PFCOUNT": {Name: "pfcount", Arity: -2, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: -1, Step: 1},
104-
"PING": {Name: "ping", Arity: -1, Flags: []string{redisCmdFlagAdmin}, FirstKey: 0, LastKey: 0, Step: 0},
105-
"PTTL": {Name: "pttl", Arity: 2, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
106-
"PUBLISH": {Name: "publish", Arity: 3, Flags: []string{redisCmdFlagAdmin}, FirstKey: 0, LastKey: 0, Step: 0},
107-
"PUBSUB": {Name: "pubsub", Arity: -2, Flags: []string{redisCmdFlagAdmin}, FirstKey: 0, LastKey: 0, Step: 0},
108-
"QUIT": {Name: "quit", Arity: 1, Flags: []string{redisCmdFlagAdmin}, FirstKey: 0, LastKey: 0, Step: 0},
109-
"RENAME": {Name: "rename", Arity: 3, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 2, Step: 1},
110-
"RPOP": {Name: "rpop", Arity: 2, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
111-
"RPOPLPUSH": {Name: "rpoplpush", Arity: 3, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 2, Step: 1},
112-
"RPUSH": {Name: "rpush", Arity: -3, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
113-
"SADD": {Name: "sadd", Arity: -3, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
114-
"SCAN": {Name: "scan", Arity: -2, Flags: []string{redisCmdFlagReadonly}, FirstKey: 0, LastKey: 0, Step: 0},
115-
"SCARD": {Name: "scard", Arity: 2, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
116-
"SELECT": {Name: "select", Arity: 2, Flags: []string{redisCmdFlagAdmin}, FirstKey: 0, LastKey: 0, Step: 0},
117-
"SET": {Name: "set", Arity: -3, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
118-
"SETEX": {Name: "setex", Arity: 4, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
119-
"SETNX": {Name: "setnx", Arity: 3, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
120-
"SISMEMBER": {Name: "sismember", Arity: 3, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
121-
"SMEMBERS": {Name: "smembers", Arity: 2, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
122-
"SREM": {Name: "srem", Arity: -3, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
123-
"SUBSCRIBE": {Name: "subscribe", Arity: -2, Flags: []string{redisCmdFlagAdmin}, FirstKey: 0, LastKey: 0, Step: 0},
124-
"TTL": {Name: "ttl", Arity: 2, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
125-
"TYPE": {Name: "type", Arity: 2, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
126-
"XADD": {Name: "xadd", Arity: -5, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
127-
"XLEN": {Name: "xlen", Arity: 2, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
128-
"XRANGE": {Name: "xrange", Arity: -4, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
129-
"XREAD": {Name: "xread", Arity: -4, Flags: []string{redisCmdFlagReadonly}, FirstKey: 0, LastKey: 0, Step: 0},
130-
"XREVRANGE": {Name: "xrevrange", Arity: -4, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
131-
"XTRIM": {Name: "xtrim", Arity: -4, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
132-
"ZADD": {Name: "zadd", Arity: -4, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
133-
"ZCARD": {Name: "zcard", Arity: 2, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
134-
"ZCOUNT": {Name: "zcount", Arity: 4, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
135-
"ZINCRBY": {Name: "zincrby", Arity: 4, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
136-
"ZPOPMIN": {Name: "zpopmin", Arity: -2, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
137-
"ZRANGE": {Name: "zrange", Arity: -4, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
138-
"ZRANGEBYSCORE": {Name: "zrangebyscore", Arity: -4, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
139-
"ZREM": {Name: "zrem", Arity: -3, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
140-
"ZREMRANGEBYRANK": {Name: "zremrangebyrank", Arity: 4, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
141-
"ZREMRANGEBYSCORE": {Name: "zremrangebyscore", Arity: 4, Flags: []string{redisCmdFlagWrite}, FirstKey: 1, LastKey: 1, Step: 1},
142-
"ZREVRANGE": {Name: "zrevrange", Arity: -4, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
143-
"ZREVRANGEBYSCORE": {Name: "zrevrangebyscore", Arity: -4, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
144-
"ZSCORE": {Name: "zscore", Arity: 3, Flags: []string{redisCmdFlagReadonly}, FirstKey: 1, LastKey: 1, Step: 1},
145-
}
146-
14750
// redisCommandFallbackWarnedOnce deduplicates the "missing metadata" log so
14851
// that a hostile or buggy client probing the same unknown-but-routed name
14952
// cannot generate unbounded log spam. The fallback is a safety net for

0 commit comments

Comments
 (0)