├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── issue.md ├── release-drafter.yml └── workflows │ ├── ci.yml │ ├── docker-publish.yml │ ├── pages.yml │ └── release.yml ├── .gitignore ├── Dockerfile ├── README.md ├── build.sh ├── cmd └── redis-shake │ └── main.go ├── docs ├── .gitignore ├── .vitepress │ ├── config.ts │ ├── en.ts │ └── zh.ts ├── demo.gif ├── intro.png ├── package-lock.json ├── package.json └── src │ ├── en │ ├── filter │ │ ├── filter.md │ │ └── function.md │ ├── guide │ │ ├── architecture.md │ │ ├── config.md │ │ ├── getting-started.md │ │ ├── introduction.md │ │ └── mode.md │ ├── index.md │ ├── others │ │ ├── consistent.md │ │ ├── modules.md │ │ └── version.md │ ├── reader │ │ ├── aof_reader.md │ │ ├── rdb_reader.md │ │ ├── scan_reader.md │ │ └── sync_reader.md │ └── writer │ │ ├── file_writer.md │ │ └── redis_writer.md │ ├── index.md │ ├── public │ ├── aof_reader.jpg │ ├── architecture-c2c.svg │ ├── architecture-s2s.svg │ ├── favicon.ico │ └── module-supported.jpg │ └── zh │ ├── filter │ ├── filter.md │ └── function.md │ ├── guide │ ├── architecture.md │ ├── config.md │ ├── getting-started.md │ ├── introduction.md │ └── mode.md │ ├── index.md │ ├── others │ ├── consistent.md │ ├── modules.md │ └── version.md │ ├── reader │ ├── aof_reader.md │ ├── rdb_reader.md │ ├── scan_reader.md │ └── sync_reader.md │ └── writer │ ├── file_writer.md │ └── redis_writer.md ├── entrypoint.sh ├── go.mod ├── go.sum ├── internal ├── aof │ └── aof.go ├── client │ ├── func.go │ ├── proto │ │ ├── license.txt │ │ ├── reader.go │ │ ├── strconv.go │ │ └── writer.go │ ├── redis.go │ ├── reply.go │ └── sentinel.go ├── commands │ ├── keys.go │ ├── keys_test.go │ ├── table.go │ └── types.go ├── config │ └── config.go ├── entry │ └── entry.go ├── filter │ ├── filter.go │ ├── filter_keys_pattern.go │ ├── function.go │ └── function_test.go ├── log │ ├── func.go │ └── init.go ├── rdb │ ├── rdb.go │ ├── structure │ │ ├── byte.go │ │ ├── float.go │ │ ├── int.go │ │ ├── intset.go │ │ ├── length.go │ │ ├── listpack.go │ │ ├── module2_struct.go │ │ ├── string.go │ │ └── ziplist.go │ └── types │ │ ├── hash.go │ │ ├── interface.go │ │ ├── list.go │ │ ├── mbbloom.go │ │ ├── module2.go │ │ ├── set.go │ │ ├── set_test.go │ │ ├── stream.go │ │ ├── string.go │ │ ├── tairhash.go │ │ ├── tairstring.go │ │ ├── tairzset.go │ │ └── zset.go ├── reader │ ├── aof_reader.go │ ├── interface.go │ ├── parsing_aof.go │ ├── rdb_reader.go │ ├── scan_cluster_reader.go │ ├── scan_standalone_reader.go │ ├── sync_cluster_reader.go │ ├── sync_standalone_reader.go │ └── sync_standalone_reader_test.go ├── status │ ├── entry_count.go │ ├── handler.go │ └── status.go ├── utils │ ├── UniqueQueue.go │ ├── cluster_nodes.go │ ├── crc16.go │ ├── crc64.go │ ├── crc_test.go │ ├── file.go │ ├── file_rotate │ │ ├── aof_reader.go │ │ └── aof_writer.go │ ├── filelock.go │ ├── ncpu.go │ ├── parse.go │ └── pprof.go └── writer │ ├── file_writer.go │ ├── interface.go │ ├── redis_cluster_writer.go │ └── redis_standalone_writer.go ├── license.txt ├── scripts ├── commands │ ├── acl-cat.json │ ├── acl-deluser.json │ ├── acl-dryrun.json │ ├── acl-genpass.json │ ├── acl-getuser.json │ ├── acl-help.json │ ├── acl-list.json │ ├── acl-load.json │ ├── acl-log.json │ ├── acl-save.json │ ├── acl-setuser.json │ ├── acl-users.json │ ├── acl-whoami.json │ ├── acl.json │ ├── append.json │ ├── asking.json │ ├── auth.json │ ├── bgrewriteaof.json │ ├── bgsave.json │ ├── bitcount.json │ ├── bitfield.json │ ├── bitfield_ro.json │ ├── bitop.json │ ├── bitpos.json │ ├── blmove.json │ ├── blmpop.json │ ├── blpop.json │ ├── brpop.json │ ├── brpoplpush.json │ ├── bzmpop.json │ ├── bzpopmax.json │ ├── bzpopmin.json │ ├── client-caching.json │ ├── client-getname.json │ ├── client-getredir.json │ ├── client-help.json │ ├── client-id.json │ ├── client-info.json │ ├── client-kill.json │ ├── client-list.json │ ├── client-no-evict.json │ ├── client-pause.json │ ├── client-reply.json │ ├── client-setname.json │ ├── client-tracking.json │ ├── client-trackinginfo.json │ ├── client-unblock.json │ ├── client-unpause.json │ ├── client.json │ ├── cluster-addslots.json │ ├── cluster-addslotsrange.json │ ├── cluster-bumpepoch.json │ ├── cluster-count-failure-reports.json │ ├── cluster-countkeysinslot.json │ ├── cluster-delslots.json │ ├── cluster-delslotsrange.json │ ├── cluster-failover.json │ ├── cluster-flushslots.json │ ├── cluster-forget.json │ ├── cluster-getkeysinslot.json │ ├── cluster-help.json │ ├── cluster-info.json │ ├── cluster-keyslot.json │ ├── cluster-links.json │ ├── cluster-meet.json │ ├── cluster-myid.json │ ├── cluster-nodes.json │ ├── cluster-replicas.json │ ├── cluster-replicate.json │ ├── cluster-reset.json │ ├── cluster-saveconfig.json │ ├── cluster-set-config-epoch.json │ ├── cluster-setslot.json │ ├── cluster-shards.json │ ├── cluster-slaves.json │ ├── cluster-slots.json │ ├── cluster.json │ ├── command-count.json │ ├── command-docs.json │ ├── command-getkeys.json │ ├── command-getkeysandflags.json │ ├── command-help.json │ ├── command-info.json │ ├── command-list.json │ ├── command.json │ ├── config-get.json │ ├── config-help.json │ ├── config-resetstat.json │ ├── config-rewrite.json │ ├── config-set.json │ ├── config.json │ ├── copy.json │ ├── dbsize.json │ ├── debug.json │ ├── decr.json │ ├── decrby.json │ ├── del.json │ ├── discard.json │ ├── dump.json │ ├── echo.json │ ├── eval.json │ ├── eval_ro.json │ ├── evalsha.json │ ├── evalsha_ro.json │ ├── exec.json │ ├── exhset.json │ ├── exists.json │ ├── expire.json │ ├── expireat.json │ ├── expiretime.json │ ├── exset.json │ ├── exzadd.json │ ├── failover.json │ ├── fcall.json │ ├── fcall_ro.json │ ├── flushall.json │ ├── flushdb.json │ ├── function-delete.json │ ├── function-dump.json │ ├── function-flush.json │ ├── function-help.json │ ├── function-kill.json │ ├── function-list.json │ ├── function-load.json │ ├── function-restore.json │ ├── function-stats.json │ ├── function.json │ ├── geoadd.json │ ├── geodist.json │ ├── geohash.json │ ├── geopos.json │ ├── georadius.json │ ├── georadius_ro.json │ ├── georadiusbymember.json │ ├── georadiusbymember_ro.json │ ├── geosearch.json │ ├── geosearchstore.json │ ├── get.json │ ├── getbit.json │ ├── getdel.json │ ├── getex.json │ ├── getrange.json │ ├── getset.json │ ├── hdel.json │ ├── hello.json │ ├── hexists.json │ ├── hget.json │ ├── hgetall.json │ ├── hincrby.json │ ├── hincrbyfloat.json │ ├── hkeys.json │ ├── hlen.json │ ├── hmget.json │ ├── hmset.json │ ├── hrandfield.json │ ├── hscan.json │ ├── hset.json │ ├── hsetnx.json │ ├── hstrlen.json │ ├── hvals.json │ ├── incr.json │ ├── incrby.json │ ├── incrbyfloat.json │ ├── info.json │ ├── keys.json │ ├── lastsave.json │ ├── latency-doctor.json │ ├── latency-graph.json │ ├── latency-help.json │ ├── latency-histogram.json │ ├── latency-history.json │ ├── latency-latest.json │ ├── latency-reset.json │ ├── latency.json │ ├── lcs.json │ ├── lindex.json │ ├── linsert.json │ ├── llen.json │ ├── lmove.json │ ├── lmpop.json │ ├── lolwut.json │ ├── lpop.json │ ├── lpos.json │ ├── lpush.json │ ├── lpushx.json │ ├── lrange.json │ ├── lrem.json │ ├── lset.json │ ├── ltrim.json │ ├── memory-doctor.json │ ├── memory-help.json │ ├── memory-malloc-stats.json │ ├── memory-purge.json │ ├── memory-stats.json │ ├── memory-usage.json │ ├── memory.json │ ├── mget.json │ ├── migrate.json │ ├── module-help.json │ ├── module-list.json │ ├── module-load.json │ ├── module-loadex.json │ ├── module-unload.json │ ├── module.json │ ├── monitor.json │ ├── move.json │ ├── mset.json │ ├── msetnx.json │ ├── multi.json │ ├── object-encoding.json │ ├── object-freq.json │ ├── object-help.json │ ├── object-idletime.json │ ├── object-refcount.json │ ├── object.json │ ├── persist.json │ ├── pexpire.json │ ├── pexpireat.json │ ├── pexpiretime.json │ ├── pfadd.json │ ├── pfcount.json │ ├── pfdebug.json │ ├── pfmerge.json │ ├── pfselftest.json │ ├── ping.json │ ├── psetex.json │ ├── psubscribe.json │ ├── psync.json │ ├── pttl.json │ ├── publish.json │ ├── pubsub-channels.json │ ├── pubsub-help.json │ ├── pubsub-numpat.json │ ├── pubsub-numsub.json │ ├── pubsub-shardchannels.json │ ├── pubsub-shardnumsub.json │ ├── pubsub.json │ ├── punsubscribe.json │ ├── quit.json │ ├── randomkey.json │ ├── readonly.json │ ├── readwrite.json │ ├── rename.json │ ├── renamenx.json │ ├── replconf.json │ ├── replicaof.json │ ├── reset.json │ ├── restore-asking.json │ ├── restore.json │ ├── role.json │ ├── rpop.json │ ├── rpoplpush.json │ ├── rpush.json │ ├── rpushx.json │ ├── sadd.json │ ├── save.json │ ├── scan.json │ ├── scard.json │ ├── script-debug.json │ ├── script-exists.json │ ├── script-flush.json │ ├── script-help.json │ ├── script-kill.json │ ├── script-load.json │ ├── script.json │ ├── sdiff.json │ ├── sdiffstore.json │ ├── select.json │ ├── sentinel-ckquorum.json │ ├── sentinel-config.json │ ├── sentinel-debug.json │ ├── sentinel-failover.json │ ├── sentinel-flushconfig.json │ ├── sentinel-get-master-addr-by-name.json │ ├── sentinel-help.json │ ├── sentinel-info-cache.json │ ├── sentinel-is-master-down-by-addr.json │ ├── sentinel-master.json │ ├── sentinel-masters.json │ ├── sentinel-monitor.json │ ├── sentinel-myid.json │ ├── sentinel-pending-scripts.json │ ├── sentinel-remove.json │ ├── sentinel-replicas.json │ ├── sentinel-reset.json │ ├── sentinel-sentinels.json │ ├── sentinel-set.json │ ├── sentinel-simulate-failure.json │ ├── sentinel-slaves.json │ ├── sentinel.json │ ├── set.json │ ├── setbit.json │ ├── setex.json │ ├── setnx.json │ ├── setrange.json │ ├── shutdown.json │ ├── sinter.json │ ├── sintercard.json │ ├── sinterstore.json │ ├── sismember.json │ ├── slaveof.json │ ├── slowlog-get.json │ ├── slowlog-help.json │ ├── slowlog-len.json │ ├── slowlog-reset.json │ ├── slowlog.json │ ├── smembers.json │ ├── smismember.json │ ├── smove.json │ ├── sort.json │ ├── sort_ro.json │ ├── spop.json │ ├── spublish.json │ ├── srandmember.json │ ├── srem.json │ ├── sscan.json │ ├── ssubscribe.json │ ├── strlen.json │ ├── subscribe.json │ ├── substr.json │ ├── sunion.json │ ├── sunionstore.json │ ├── sunsubscribe.json │ ├── swapdb.json │ ├── sync.json │ ├── time.json │ ├── touch.json │ ├── ttl.json │ ├── type.json │ ├── unlink.json │ ├── unsubscribe.json │ ├── unwatch.json │ ├── wait.json │ ├── watch.json │ ├── xack.json │ ├── xadd.json │ ├── xautoclaim.json │ ├── xclaim.json │ ├── xdel.json │ ├── xgroup-create.json │ ├── xgroup-createconsumer.json │ ├── xgroup-delconsumer.json │ ├── xgroup-destroy.json │ ├── xgroup-help.json │ ├── xgroup-setid.json │ ├── xgroup.json │ ├── xinfo-consumers.json │ ├── xinfo-groups.json │ ├── xinfo-help.json │ ├── xinfo-stream.json │ ├── xinfo.json │ ├── xlen.json │ ├── xpending.json │ ├── xrange.json │ ├── xread.json │ ├── xreadgroup.json │ ├── xrevrange.json │ ├── xsetid.json │ ├── xtrim.json │ ├── zadd.json │ ├── zcard.json │ ├── zcount.json │ ├── zdiff.json │ ├── zdiffstore.json │ ├── zincrby.json │ ├── zinter.json │ ├── zintercard.json │ ├── zinterstore.json │ ├── zlexcount.json │ ├── zmpop.json │ ├── zmscore.json │ ├── zpopmax.json │ ├── zpopmin.json │ ├── zrandmember.json │ ├── zrange.json │ ├── zrangebylex.json │ ├── zrangebyscore.json │ ├── zrangestore.json │ ├── zrank.json │ ├── zrem.json │ ├── zremrangebylex.json │ ├── zremrangebyrank.json │ ├── zremrangebyscore.json │ ├── zrevrange.json │ ├── zrevrangebylex.json │ ├── zrevrangebyscore.json │ ├── zrevrank.json │ ├── zscan.json │ ├── zscore.json │ ├── zunion.json │ └── zunionstore.json ├── gen_table_go_from_table_json.py ├── gen_table_json_from_commands.py └── table.json ├── shake.toml ├── shake_scan_env.toml ├── shake_sync_env.toml ├── test.sh └── tests ├── .gitignore ├── README.md ├── cases ├── aof.py ├── auth_acl.py ├── function.py ├── rdb.py ├── scan.py └── sync.py ├── helpers ├── __init__.py ├── cluster.py ├── commands │ ├── __init__.py │ ├── checker.py │ ├── list.py │ ├── select.py │ ├── string.py │ ├── tair_hash.py │ ├── tair_string.py │ └── tair_zset.py ├── constant.py ├── data_inserter.py ├── redis.py ├── shake.py └── utils │ ├── __init__.py │ ├── filesystem.py │ ├── network.py │ ├── rand.py │ └── timer.py └── requirements.txt /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: 功能性建议(Suggest an idea for this project) 4 | title: '' 5 | labels: 'type: feature request' 6 | assignees: suxb201 7 | 8 | --- 9 | 10 | 请描述你的功能性建议。清晰地说明你希望添加或改进的功能,并尽可能提供详细的信息。 11 | 12 | Please describe your feature request. Clearly state the functionality you would like to add or improve and provide as much detail as possible. 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Issue 3 | about: 使用中遇到问题(Encountering problems while using) 4 | title: '' 5 | labels: 'type: question' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### 问题描述(Issue Description) 11 | 12 | 请在这里简要描述你遇到的问题。 13 | 14 | Please provide a brief description of the issue you encountered. 15 | 16 | ### 环境信息(Environment) 17 | 18 | - RedisShake 版本(RedisShake Version): 19 | - Redis 源端版本(Redis Source Version): 20 | - Redis 目的端版本(Redis Destination Version): 21 | - Redis 部署方式(standalone/cluster/sentinel): 22 | - 是否在云服务商实例上部署(Deployed on Cloud Provider): 23 | 24 | ### 日志信息(Logs) 25 | 26 | 如果有错误日志或其他相关日志,请在这里提供。 27 | 28 | If there are any error logs or other relevant logs, please provide them here. 29 | 30 | ### 其他信息(Additional Information) 31 | 32 | 请提供任何其他相关的信息,如配置文件、错误信息或截图等。 33 | 34 | Please provide any additional information, such as configuration files, error messages, or screenshots. 35 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/release-drafter/release-drafter#example 2 | name-template: 'redis-shake-v$RESOLVED_VERSION' 3 | tag-template: 'v$RESOLVED_VERSION' 4 | template: | 5 | ## Changes 6 | 7 | $CHANGES 8 | version-resolver: 9 | major: 10 | labels: 11 | - 'major' 12 | minor: 13 | labels: 14 | - 'minor' 15 | patch: 16 | labels: 17 | - 'patch' 18 | default: patch -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # system 2 | .idea/ 3 | __pycache__/ 4 | .DS_Store 5 | 6 | # compiled output or test output 7 | bin/ 8 | dist/ 9 | tmp/ 10 | data/ 11 | *.log 12 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.21-alpine AS builder 2 | WORKDIR /app 3 | COPY . . 4 | RUN go mod download 5 | RUN go build -o redis-shake ./cmd/redis-shake 6 | 7 | FROM alpine:latest 8 | WORKDIR /app 9 | COPY --from=builder /app/redis-shake . 10 | COPY shake_sync_env.toml . 11 | COPY shake_scan_env.toml . 12 | COPY entrypoint.sh . 13 | 14 | RUN chmod +x entrypoint.sh 15 | 16 | ENTRYPOINT ["/bin/sh", "entrypoint.sh"] -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | cache/ -------------------------------------------------------------------------------- /docs/.vitepress/config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfigWithTheme } from "vitepress" 2 | import { en } from "./en" 3 | import { zh } from "./zh" 4 | 5 | // https://vitepress.dev/reference/site-config 6 | export default defineConfigWithTheme({ 7 | head: [["link", { rel: "icon", href: "/RedisShake/favicon.ico" }]], 8 | base: "/RedisShake/", 9 | title: "RedisShake", 10 | srcDir: "./src", 11 | 12 | locales: { 13 | zh: { label: "简体中文", ...zh }, 14 | en: { label: "English", ...en }, 15 | }, 16 | themeConfig: { 17 | nav: zh.themeConfig?.nav, 18 | socialLinks: [ 19 | { icon: "github", link: "https://github.com/tair-opensource/RedisShake" } 20 | ], 21 | editLink: { 22 | pattern: "https://github.com/tair-opensource/RedisShake/tree/v4/docs/src/:path" 23 | }, 24 | lastUpdated: { 25 | text: "Updated at", 26 | formatOptions: { 27 | dateStyle: "full", 28 | timeStyle: "medium" 29 | } 30 | }, 31 | footer: { 32 | message: "Released under the MIT License.", 33 | copyright: "Copyright © 2019-present Tair" 34 | } 35 | } 36 | }) 37 | -------------------------------------------------------------------------------- /docs/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tair-opensource/RedisShake/bbca45b9de86fa337f5173b8927580a6b92f95a1/docs/demo.gif -------------------------------------------------------------------------------- /docs/intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tair-opensource/RedisShake/bbca45b9de86fa337f5173b8927580a6b92f95a1/docs/intro.png -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "devDependencies": { 4 | "vitepress": "^1.0.0-rc.4" 5 | }, 6 | "scripts": { 7 | "docs:dev": "vitepress dev", 8 | "docs:build": "vitepress build", 9 | "docs:preview": "vitepress preview" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /docs/src/en/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | hero: 6 | name: "RedisShake" 7 | tagline: Data migration and processing for Redis-like databases 8 | actions: 9 | - theme: brand 10 | text: Get Started 11 | link: /en/guide/getting-started 12 | - theme: alt 13 | text: What is RedisShake 14 | link: /en/guide/introduction 15 | features: 16 | - title: Data Migration 17 | details: Supports sync, scan, and restore modes for data migration 18 | - title: Data Processing 19 | details: Supports data filtering and modification using lua scripts 20 | - title: Compatibility 21 | details: Compatible with various Redis deployment forms and mainstream cloud vendor's Redis-like databases 22 | --- 23 | 24 | -------------------------------------------------------------------------------- /docs/src/en/reader/aof_reader.md: -------------------------------------------------------------------------------- 1 | # aof_reader 2 | 3 | ## Introduction 4 | 5 | Can use ` aof_ Reader 'to read data from the AOF file and then write it to the target end. 6 | It is commonly used to recover data from backup files and also supports data flash back. 7 | 8 | ## configuration 9 | 10 | ```toml 11 | [aof_reader] 12 | aoffilepath="/tmp/appendonly.aof.manifest" #or single-aof: /tmp/appendonly.aof" 13 | aoftimestamp="0" 14 | ``` 15 | 16 | *An absolute path should be passed in. 17 | 18 | ##The main process is as follows: 19 | ![aof_reader.jpg](/public/aof_reader.jpg) -------------------------------------------------------------------------------- /docs/src/en/reader/rdb_reader.md: -------------------------------------------------------------------------------- 1 | # RDB Reader 2 | 3 | ## Introduction 4 | 5 | The `rdb_reader` can be used to read data from an RDB file and then write it to the target destination. This is commonly used for recovering data from backup files. 6 | 7 | ## Configuration 8 | 9 | ```toml 10 | [rdb_reader] 11 | filepath = "/tmp/dump.rdb" 12 | ``` 13 | 14 | * An absolute path should be passed in. 15 | 16 | -------------------------------------------------------------------------------- /docs/src/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | hero: 6 | name: "RedisShake" 7 | tagline: 用于 Redis-like 数据库的数据迁移与处理服务 8 | actions: 9 | - theme: brand 10 | text: 快速上手 11 | link: /zh/guide/getting-started 12 | - theme: alt 13 | text: 什么是 RedisShake 14 | link: /zh/guide/introduction 15 | features: 16 | - icon: ☁️ 17 | title: 兼容性 18 | details: 兼容自建 Redis 与主流云厂商的 Redis-like 数据库 19 | - icon: 🔍 20 | title: 数据过滤与修改 21 | details: 提供强大的数据过滤和修改功能 22 | - icon: 🔄 23 | title: 增量同步 24 | details: 支持实时增量数据同步,用于不停机迁移 25 | --- 26 | 27 | -------------------------------------------------------------------------------- /docs/src/public/aof_reader.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tair-opensource/RedisShake/bbca45b9de86fa337f5173b8927580a6b92f95a1/docs/src/public/aof_reader.jpg -------------------------------------------------------------------------------- /docs/src/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tair-opensource/RedisShake/bbca45b9de86fa337f5173b8927580a6b92f95a1/docs/src/public/favicon.ico -------------------------------------------------------------------------------- /docs/src/public/module-supported.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tair-opensource/RedisShake/bbca45b9de86fa337f5173b8927580a6b92f95a1/docs/src/public/module-supported.jpg -------------------------------------------------------------------------------- /docs/src/zh/guide/config.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | 5 | # 配置文件 6 | 7 | RedisShake 使用 [TOML](https://toml.io/cn/) 语言书写,所有的配置参数在 all.toml 中均有说明。 8 | 9 | 配置文件的组成如下: 10 | 11 | ```toml 12 | 13 | [xxx_reader] 14 | ... 15 | 16 | [xxx_writer] 17 | ... 18 | 19 | [filter] 20 | ... 21 | 22 | [advanced] 23 | ... 24 | ``` 25 | 26 | 27 | ## reader 配置 28 | 29 | RedisShake 提供了不同的 Reader 用来对接不同的源端,配置详见 Reader 章节: 30 | 31 | * [Sync Reader](../reader/sync_reader.md) 32 | * [Scan Reader](../reader/scan_reader.md) 33 | * [RDB Reader](../reader/rdb_reader.md) 34 | * [AOF Reader](../reader/aof_reader.md) 35 | 36 | ## writer 配置 37 | 38 | RedisShake 提供了不同的 Writer 用来对接不同的目标端,配置详见 Writer 章节: 39 | 40 | * [Redis Writer](../writer/redis_writer.md) 41 | 42 | ## filter 配置 43 | 44 | 允许通过配置文件设置过滤规则,参考 [过滤与加工](../filter/filter.md) 与 [function](../filter/function.md)。 45 | 46 | ## advanced 配置 47 | 48 | 参考 [shake.toml 配置文件](https://github.com/tair-opensource/RedisShake/blob/v4/shake.toml)。 -------------------------------------------------------------------------------- /docs/src/zh/guide/getting-started.md: -------------------------------------------------------------------------------- 1 | # 快速上手 2 | 3 | ## 安装 4 | 5 | ### 下载二进制包 6 | 7 | 直接从 [Release](https://github.com/tair-opensource/RedisShake/releases) 下载二进制包。 8 | 9 | ### 从源代码编译 10 | 11 | 要从源代码编译,确保您在本地机器上设置了 Golang 环境: 12 | 13 | ```shell 14 | git clone https://github.com/alibaba/RedisShake 15 | cd RedisShake 16 | sh build.sh 17 | ``` 18 | 19 | ## 使用 20 | 21 | 假设你有两个 Redis 实例: 22 | 23 | * 实例 A:127.0.0.1:6379 24 | * 实例 B:127.0.0.1:6380 25 | 26 | 创建一个新的配置文件 `shake.toml`: 27 | 28 | ```toml 29 | [sync_reader] 30 | address = "127.0.0.1:6379" 31 | 32 | [redis_writer] 33 | address = "127.0.0.1:6380" 34 | ``` 35 | 36 | 要启动 RedisShake,运行以下命令: 37 | 38 | ```shell 39 | ./redis-shake shake.toml 40 | ``` 41 | 42 | ## 注意事项 43 | 44 | 1. 不要在同一个目录运行两个 RedisShake 进程,因为运行时产生的临时文件可能会被覆盖,导致异常行为。 45 | 2. 不要降低 Redis 版本,比如从 6.0 降到 5.0,因为 RedisShake 每个大版本都会引入一些新的命令和新的编码方式,如果降低版本,可能会导致不兼容。 46 | -------------------------------------------------------------------------------- /docs/src/zh/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | hero: 6 | name: "RedisShake" 7 | tagline: 用于 Redis-like 数据库的数据迁移与处理服务 8 | actions: 9 | - theme: brand 10 | text: 快速上手 11 | link: /zh/guide/getting-started 12 | - theme: alt 13 | text: 什么是 RedisShake 14 | link: /zh/guide/introduction 15 | features: 16 | - icon: ☁️ 17 | title: 云厂商兼容性 18 | details: 兼容自建 Redis 与主流云厂商的 Redis-like 数据库 19 | - icon: 🔍 20 | title: 数据过滤与修改 21 | details: 提供强大的数据过滤和修改功能 22 | - icon: 🔄 23 | title: 增量同步 24 | details: 支持实时增量数据同步,用于不停机迁移 25 | --- 26 | 27 | -------------------------------------------------------------------------------- /docs/src/zh/others/consistent.md: -------------------------------------------------------------------------------- 1 | # 如何判断数据一致 2 | 3 | 在增量同步阶段经常需要判断源端与目标端数据是否一致,介绍两种经验方法: 4 | 1. 通过日志或者监控,观察到 RedisShake 的同步流量为 0,认为同步结束,两端一致。 5 | 2. 对比源端与目的端 Key 数量是否相等,如果相等,认为一致。 6 | 7 | 如果 Key 带有过期时间,会导致 Key 数量不一致。原因: 8 | 1. 因为过期算法限制,源端中可能存在一些 Key 已经过期但实际上没有被删除,这批 Key 在目的端可能会被删除,导致目的端 Key 数量少于源端。 9 | 2. 源端和目的端独立运行,各自的过期算法独立运行,过期算法具有随机性,会导致源端和目的端删除的 Key 不一致,导致 Key 数量不一致。 10 | 11 | 在实践中,带有过期时间的 Key 一般认为是允许不一致的,不会影响业务,所以可以仅校验不带有过期时间的 Key 数量是否一致。如下所示,应当分别计算源端和目的端的 `$keys-$expires` 的值是否一样。[[795]](https://github.com/tair-opensource/RedisShake/issues/795) [[791]](https://github.com/tair-opensource/RedisShake/issues/791) 12 | ``` 13 | 127.0.0.1:6379> info keyspace 14 | # Keyspace 15 | db0:keys=4463175,expires=2,avg_ttl=333486 16 | ``` -------------------------------------------------------------------------------- /docs/src/zh/others/version.md: -------------------------------------------------------------------------------- 1 | # 跨版本迁移 2 | 3 | 常见 Redis-like 数据库都是向后兼容的,低版本实例迁移至高版本时,不会存在兼容问题。 4 | 但是,高版本实例迁移至低版本时,可能会存在不兼容问题,例如:Redis 7.0 的数据导入至 Redis 4.0。 5 | 建议尽量避免此类场景,因为会存在多种不兼容场景 [[794]](https://github.com/tair-opensource/RedisShake/issues/794) [[699]](https://github.com/tair-opensource/RedisShake/issues/699): 6 | 1. 二进制数据编码不兼容 7 | 2. 命令不支持,见于 SYNC 的增量阶段 8 | 9 | 10 | 如果无法避免迁移至低版本,可以通过以下方式解决: 11 | 1. 对于二进制数据编码不兼容,可以考虑修改 `target_redis_proto_max_bulk_len` 参数,将其设置为 0。 12 | `target_redis_proto_max_bulk_len` 本意是为了处理超大 Key,RedisShake 会在同步过程中将大于 `target_redis_proto_max_bulk_len` 的二进制数据转换为 RESP 命令。比如元素非常多的 list 结构,RedisShake 会将其转换为多个 `RPUSH` 命令。在降低版本场景中,可以将其设置为 0,让 RedisShake 将所有二进制数据转换为 RESP 命令,以此避免二进制数据编码不兼容问题。 13 | 2. 对于命令不支持问题,建议直接过滤掉不支持的命令。 -------------------------------------------------------------------------------- /docs/src/zh/reader/aof_reader.md: -------------------------------------------------------------------------------- 1 | # aof_reader 2 | 3 | ## 介绍 4 | 5 | 可以使用 `aof_reader` 来从 AOF 文件中读取数据,然后写入目标端。常见于从备份文件中恢复数据,还支持数据闪回。 6 | 7 | ## 配置 8 | 9 | ```toml 10 | [aof_reader] 11 | aoffilepath="/tmp/appendonly.aof.manifest" #或者单aof文件 "/tmp/appendonly.aof" 12 | aoftimestamp="0" 13 | ``` 14 | 15 | * 应传入绝对路径。 16 | 17 | ## 主要流程如下: 18 | ![aof_reader.jpg](/public/aof_reader.jpg) -------------------------------------------------------------------------------- /docs/src/zh/reader/rdb_reader.md: -------------------------------------------------------------------------------- 1 | # rdb_reader 2 | 3 | ## 介绍 4 | 5 | 可以使用 `rdb_reader` 来从 RDB 文件中读取数据,然后写入目标端。常见于从备份文件中恢复数据。 6 | 7 | ## 配置 8 | 9 | ```toml 10 | [rdb_reader] 11 | filepath = "/tmp/dump.rdb" 12 | ``` 13 | 14 | * 应传入绝对路径。 15 | -------------------------------------------------------------------------------- /docs/src/zh/writer/redis_writer.md: -------------------------------------------------------------------------------- 1 | # Redis Writer 2 | 3 | ## 介绍 4 | 5 | `redis_writer` 用于将数据写入 Redis-like 数据库。 6 | 7 | ## 配置 8 | 9 | ```toml 10 | [redis_writer] 11 | cluster = false 12 | address = "127.0.0.1:6379" # when cluster is true, address is one of the cluster node 13 | username = "" # keep empty if not using ACL 14 | password = "" # keep empty if no authentication is required 15 | tls = false 16 | ``` 17 | 18 | * `cluster`:是否为集群。 19 | * `address`:连接地址。当目的端为集群时,`address` 填写集群中的任意一个节点即可 20 | * 鉴权: 21 | * 当使用 ACL 账号体系时,配置 `username` 和 `password` 22 | * 当使用传统账号体系时,仅配置 `password` 23 | * 当无鉴权时,不配置 `username` 和 `password` 24 | * `tls`:是否开启 TLS/SSL,不需要配置证书因为 RedisShake 没有校验服务器证书 25 | 26 | 注意事项: 27 | 1. 当目的端为集群时,应保证源端发过来的命令满足 [Key 的哈希值属于同一个 slot](https://redis.io/docs/reference/cluster-spec/#implemented-subset)。 28 | 2. 应尽量保证目的端版本大于等于源端版本,否则可能会出现不支持的命令。如确实需要降低版本,可以设置 `target_redis_proto_max_bulk_len` 为 0,来避免使用 `restore` 命令恢复数据。 29 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [ "$SYNC" = "true" ]; then 3 | ./redis-shake shake_sync_env.toml 4 | elif [ "$SCAN" = "true" ]; then 5 | ./redis-shake shake_scan_env.toml 6 | else 7 | echo "Error: Neither SYNC nor SCAN environment variable is set to true" 8 | exit 1 9 | fi -------------------------------------------------------------------------------- /internal/client/func.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "bytes" 5 | "strings" 6 | 7 | "RedisShake/internal/client/proto" 8 | "RedisShake/internal/log" 9 | ) 10 | 11 | func EncodeArgv(argv []string, buf *bytes.Buffer) { 12 | writer := proto.NewWriter(buf) 13 | argvInterface := make([]interface{}, len(argv)) 14 | 15 | for inx, item := range argv { 16 | argvInterface[inx] = item 17 | } 18 | err := writer.WriteArgs(argvInterface) 19 | if err != nil { 20 | log.Panicf(err.Error()) 21 | } 22 | } 23 | 24 | // IsCluster is for determining whether the server is in cluster mode. 25 | func (r *Redis) IsCluster() bool { 26 | reply := r.DoWithStringReply("INFO", "Cluster") 27 | return strings.Contains(reply, "cluster_enabled:1") 28 | } 29 | -------------------------------------------------------------------------------- /internal/client/proto/license.txt: -------------------------------------------------------------------------------- 1 | port from https://github.com/go-redis/redis/tree/master/internal/proto -------------------------------------------------------------------------------- /internal/client/proto/strconv.go: -------------------------------------------------------------------------------- 1 | package proto 2 | 3 | import "strconv" 4 | 5 | func bytesToString(b []byte) string { 6 | return string(b) 7 | } 8 | 9 | func stringToBytes(s string) []byte { 10 | return []byte(s) 11 | } 12 | 13 | func atoi(b []byte) (int, error) { 14 | return strconv.Atoi(bytesToString(b)) 15 | } 16 | 17 | func parseInt(b []byte, base int, bitSize int) (int64, error) { 18 | return strconv.ParseInt(bytesToString(b), base, bitSize) 19 | } 20 | 21 | func parseUint(b []byte, base int, bitSize int) (uint64, error) { 22 | return strconv.ParseUint(bytesToString(b), base, bitSize) 23 | } 24 | 25 | func parseFloat(b []byte, bitSize int) (float64, error) { 26 | return strconv.ParseFloat(bytesToString(b), bitSize) 27 | } 28 | -------------------------------------------------------------------------------- /internal/client/reply.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import "RedisShake/internal/log" 4 | 5 | func ArrayString(replyInterface interface{}, err error) []string { 6 | if err != nil { 7 | log.Panicf(err.Error()) 8 | } 9 | replyArray := replyInterface.([]interface{}) 10 | replyArrayString := make([]string, len(replyArray)) 11 | for inx, item := range replyArray { 12 | replyArrayString[inx] = item.(string) 13 | } 14 | return replyArrayString 15 | } 16 | 17 | func String(reply interface{}, err error) (string, error) { 18 | if err != nil { 19 | return "", err 20 | } 21 | return reply.(string), err 22 | } 23 | 24 | func Int64(reply interface{}, err error) (int64, error) { 25 | if err != nil { 26 | return 0, err 27 | } 28 | switch v := reply.(type) { 29 | case int64: 30 | return v, nil 31 | case int: 32 | return int64(v), nil 33 | default: 34 | log.Panicf("reply type is not int64 or int, type=%T", v) 35 | } 36 | return 0, err 37 | } 38 | -------------------------------------------------------------------------------- /internal/client/sentinel.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "RedisShake/internal/log" 5 | "context" 6 | "fmt" 7 | ) 8 | 9 | type SentinelOptions struct { 10 | MasterName string `mapstructure:"master_name" default:""` 11 | Address string `mapstructure:"address" default:""` 12 | Username string `mapstructure:"username" default:""` 13 | Password string `mapstructure:"password" default:""` 14 | Tls bool `mapstructure:"tls" default:"false"` 15 | TlsConfig TlsConfig `mapstructure:"tls_config" default:"{}"` 16 | } 17 | 18 | func FetchAddressFromSentinel(opts *SentinelOptions) string { 19 | log.Infof("fetching master address from sentinel. sentinel address: %s, master name: %s", opts.Address, opts.MasterName) 20 | 21 | ctx := context.Background() 22 | c := NewRedisClient(ctx, opts.Address, opts.Username, opts.Password, opts.Tls, opts.TlsConfig, false) 23 | defer c.Close() 24 | c.Send("SENTINEL", "GET-MASTER-ADDR-BY-NAME", opts.MasterName) 25 | hostport := ArrayString(c.Receive()) 26 | address := fmt.Sprintf("%s:%s", hostport[0], hostport[1]) 27 | log.Infof("fetched master address: %s", address) 28 | return address 29 | } 30 | -------------------------------------------------------------------------------- /internal/commands/types.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | type keySpec struct { 4 | // begin_search 5 | beginSearchType string 6 | // @index 7 | beginSearchIndex int 8 | // @keyword 9 | beginSearchKeyword string 10 | beginSearchStartFrom int 11 | 12 | // find_keys 13 | findKeysType string 14 | // @range 15 | findKeysRangeLastKey int 16 | findKeysRangeKeyStep int 17 | findKeysRangeLimit int 18 | // @keynum 19 | findKeysKeynumIndex int 20 | findKeysKeynumFirstKey int 21 | findKeysKeynumKeyStep int 22 | } 23 | 24 | type redisCommand struct { 25 | group string 26 | keySpec []keySpec 27 | } 28 | -------------------------------------------------------------------------------- /internal/entry/entry.go: -------------------------------------------------------------------------------- 1 | package entry 2 | 3 | import ( 4 | "bytes" 5 | "strings" 6 | 7 | "RedisShake/internal/client/proto" 8 | "RedisShake/internal/commands" 9 | "RedisShake/internal/log" 10 | ) 11 | 12 | type Entry struct { 13 | DbId int // required 14 | Argv []string // required 15 | 16 | CmdName string 17 | Group string 18 | Keys []string 19 | KeyIndexes []int 20 | Slots []int 21 | 22 | // for stat 23 | SerializedSize int64 24 | } 25 | 26 | func NewEntry() *Entry { 27 | e := new(Entry) 28 | return e 29 | } 30 | 31 | func (e *Entry) String() string { 32 | str := strings.Join(e.Argv, " ") 33 | if len(str) > 100 { 34 | str = str[:100] + "..." 35 | } 36 | return str 37 | } 38 | 39 | func (e *Entry) Serialize() []byte { 40 | buf := new(bytes.Buffer) 41 | writer := proto.NewWriter(buf) 42 | argvInterface := make([]interface{}, len(e.Argv)) 43 | 44 | for inx, item := range e.Argv { 45 | argvInterface[inx] = item 46 | } 47 | err := writer.WriteArgs(argvInterface) 48 | if err != nil { 49 | log.Panicf(err.Error()) 50 | } 51 | e.SerializedSize = int64(buf.Len()) 52 | return buf.Bytes() 53 | } 54 | 55 | func (e *Entry) Parse() { 56 | e.CmdName, e.Group, e.Keys, e.KeyIndexes = commands.CalcKeys(e.Argv) 57 | e.Slots = commands.CalcSlots(e.Keys) 58 | } 59 | -------------------------------------------------------------------------------- /internal/filter/filter_keys_pattern.go: -------------------------------------------------------------------------------- 1 | package filter 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | "strings" 7 | ) 8 | 9 | // keys pattern 10 | type KeysPattern struct { 11 | regList []*regexp.Regexp 12 | } 13 | 14 | // new keys patterns 15 | func NewKeysPattern(patternList01 []string) (ret *KeysPattern, err error) { 16 | ret = &KeysPattern{ 17 | regList: []*regexp.Regexp{}, 18 | } 19 | for _, k01 := range patternList01 { 20 | k01 = strings.TrimSpace(k01) 21 | if k01 == "" { 22 | continue 23 | } 24 | regItem, err := regexp.Compile(k01) 25 | if err != nil { 26 | err = fmt.Errorf("%s regexp.Compile fail,err:%v", regItem, err) 27 | return nil, err 28 | } 29 | ret.regList = append(ret.regList, regItem) 30 | } 31 | return ret, nil 32 | } 33 | 34 | // match Key 35 | func (f *KeysPattern) MatchKey(k01 string) bool { 36 | if len(f.regList) == 0 { 37 | return false 38 | } 39 | for _, reg01 := range f.regList { 40 | regItem := reg01 41 | if regItem.MatchString(k01) == true { 42 | return true 43 | } 44 | } 45 | return false 46 | } 47 | -------------------------------------------------------------------------------- /internal/log/func.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | 8 | "github.com/go-stack/stack" 9 | ) 10 | 11 | func Debugf(format string, args ...interface{}) { 12 | logger.Debug().Msgf(format, args...) 13 | } 14 | 15 | func Infof(format string, args ...interface{}) { 16 | logger.Info().Msgf(format, args...) 17 | } 18 | 19 | func Warnf(format string, args ...interface{}) { 20 | logger.Warn().Msgf(format, args...) 21 | } 22 | 23 | func Panicf(format string, args ...interface{}) { 24 | frames := stack.Trace() 25 | errMsg := fmt.Sprintf(format, args...) 26 | for _, frame := range frames { 27 | frameStr := fmt.Sprintf("%+v", frame) 28 | if strings.HasPrefix(frameStr, "redis-shake/main.go") { 29 | frameStr = "RedisShake/cmd/" + frameStr 30 | } 31 | if strings.HasPrefix(frameStr, "RedisShake/internal/log/func") { 32 | continue 33 | } 34 | errMsg += fmt.Sprintf("\n\t\t\t%v -> %n()", frameStr, frame) 35 | } 36 | logger.Error().Msg(errMsg) 37 | os.Exit(1) 38 | } 39 | -------------------------------------------------------------------------------- /internal/rdb/structure/byte.go: -------------------------------------------------------------------------------- 1 | package structure 2 | 3 | import ( 4 | "io" 5 | 6 | "RedisShake/internal/log" 7 | ) 8 | 9 | func ReadByte(rd io.Reader) byte { 10 | b := ReadBytes(rd, 1)[0] 11 | return b 12 | } 13 | 14 | func ReadBytes(rd io.Reader, n int) []byte { 15 | buf := make([]byte, n) 16 | _, err := io.ReadFull(rd, buf) 17 | if err != nil { 18 | log.Panicf(err.Error()) 19 | } 20 | return buf 21 | } 22 | -------------------------------------------------------------------------------- /internal/rdb/structure/float.go: -------------------------------------------------------------------------------- 1 | package structure 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | "math" 7 | "strconv" 8 | 9 | "RedisShake/internal/log" 10 | ) 11 | 12 | func ReadFloat(rd io.Reader) float64 { 13 | u := ReadUint8(rd) 14 | 15 | switch u { 16 | case 253: 17 | return math.NaN() 18 | case 254: 19 | return math.Inf(0) 20 | case 255: 21 | return math.Inf(-1) 22 | default: 23 | buf := make([]byte, u) 24 | _, err := io.ReadFull(rd, buf) 25 | if err != nil { 26 | return 0 27 | } 28 | 29 | v, err := strconv.ParseFloat(string(buf), 64) 30 | if err != nil { 31 | log.Panicf(err.Error()) 32 | } 33 | return v 34 | } 35 | } 36 | 37 | func ReadDouble(rd io.Reader) float64 { 38 | var buf = make([]byte, 8) 39 | _, err := io.ReadFull(rd, buf) 40 | if err != nil { 41 | log.Panicf(err.Error()) 42 | } 43 | num := binary.LittleEndian.Uint64(buf) 44 | return math.Float64frombits(num) 45 | } 46 | -------------------------------------------------------------------------------- /internal/rdb/structure/intset.go: -------------------------------------------------------------------------------- 1 | package structure 2 | 3 | import ( 4 | "bufio" 5 | "encoding/binary" 6 | "io" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func ReadIntset(rd io.Reader) []string { 12 | rd = bufio.NewReader(strings.NewReader(ReadString(rd))) 13 | 14 | encodingType := int(ReadUint32(rd)) 15 | size := int(ReadUint32(rd)) 16 | elements := make([]string, size) 17 | 18 | for i := 0; i < size; i++ { 19 | intBytes := ReadBytes(rd, encodingType) 20 | var intString string 21 | switch encodingType { 22 | case 2: 23 | intString = strconv.FormatInt(int64(int16(binary.LittleEndian.Uint16(intBytes))), 10) 24 | case 4: 25 | intString = strconv.FormatInt(int64(int32(binary.LittleEndian.Uint32(intBytes))), 10) 26 | case 8: 27 | intString = strconv.FormatInt(int64(int64(binary.LittleEndian.Uint64(intBytes))), 10) 28 | } 29 | elements[i] = intString 30 | } 31 | return elements 32 | } 33 | -------------------------------------------------------------------------------- /internal/rdb/types/module2.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "io" 5 | 6 | "RedisShake/internal/log" 7 | "RedisShake/internal/rdb/structure" 8 | ) 9 | 10 | type ModuleObject interface { 11 | RedisObject 12 | } 13 | 14 | func PareseModuleType(rd io.Reader, key string, typeByte byte) ModuleObject { 15 | if typeByte == rdbTypeModule { 16 | log.Panicf("module type with version 1 is not supported, key=[%s]", key) 17 | } 18 | moduleId := structure.ReadLength(rd) 19 | moduleName := ModuleTypeNameByID(moduleId) 20 | switch moduleName { 21 | case "exstrtype": 22 | o := new(TairStringObject) 23 | o.LoadFromBuffer(rd, key, typeByte) 24 | return o 25 | case "tairhash-": 26 | o := new(TairHashObject) 27 | o.LoadFromBuffer(rd, key, typeByte) 28 | return o 29 | case "tairzset_": 30 | o := new(TairZsetObject) 31 | o.LoadFromBuffer(rd, key, typeByte) 32 | return o 33 | case "MBbloom--": 34 | o := new(BloomObject) 35 | o.encver = int(moduleId & 1023) 36 | o.LoadFromBuffer(rd, key, typeByte) 37 | return o 38 | default: 39 | log.Panicf("unsupported module type: %s", moduleName) 40 | return nil 41 | 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /internal/rdb/types/string.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "RedisShake/internal/rdb/structure" 5 | "io" 6 | ) 7 | 8 | type StringObject struct { 9 | key string 10 | rd io.Reader 11 | } 12 | 13 | func (o *StringObject) LoadFromBuffer(rd io.Reader, key string, _ byte) { 14 | o.key = key 15 | o.rd = rd 16 | } 17 | 18 | func (o *StringObject) Rewrite() <-chan RedisCmd { 19 | cmdC := make(chan RedisCmd) 20 | go func() { 21 | defer close(cmdC) 22 | value := structure.ReadString(o.rd) 23 | cmdC <- RedisCmd{"set", o.key, value} 24 | }() 25 | return cmdC 26 | } 27 | -------------------------------------------------------------------------------- /internal/rdb/types/tairhash.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "io" 5 | "strconv" 6 | 7 | "RedisShake/internal/rdb/structure" 8 | ) 9 | 10 | type TairHashObject struct { 11 | rd io.Reader 12 | cmdC chan RedisCmd 13 | } 14 | 15 | func (o *TairHashObject) LoadFromBuffer(rd io.Reader, key string, typeByte byte) { 16 | // `key` and `typeByte` are not used 17 | o.rd = rd 18 | o.cmdC = make(chan RedisCmd) 19 | } 20 | 21 | func (o *TairHashObject) Rewrite() <-chan RedisCmd { 22 | rd := o.rd 23 | cmdC := o.cmdC 24 | go func() { 25 | defer close(o.cmdC) 26 | dictSizeStr := structure.ReadModuleUnsigned(rd) 27 | key := structure.ReadModuleString(rd) 28 | size, _ := strconv.Atoi(dictSizeStr) 29 | cmdC <- RedisCmd{"del", key} 30 | for i := 0; i < size; i++ { 31 | skey := structure.ReadModuleString(rd) 32 | version := structure.ReadModuleUnsigned(rd) 33 | expireText := structure.ReadModuleUnsigned(rd) 34 | fieldValue := structure.ReadModuleString(rd) 35 | expire, _ := strconv.Atoi(expireText) 36 | if expire == 0 { 37 | cmdC <- RedisCmd{"EXHSET", key, skey, fieldValue} 38 | } else { 39 | cmdC <- RedisCmd{"EXHSET", key, skey, fieldValue, 40 | "ABS", version, 41 | "PXAT", expireText} 42 | } 43 | } 44 | structure.ReadModuleEof(rd) 45 | }() 46 | return cmdC 47 | } 48 | -------------------------------------------------------------------------------- /internal/rdb/types/tairstring.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "RedisShake/internal/rdb/structure" 5 | "io" 6 | ) 7 | 8 | type TairStringObject struct { 9 | key string 10 | rd io.Reader 11 | cmdC chan RedisCmd 12 | } 13 | 14 | func (o *TairStringObject) LoadFromBuffer(rd io.Reader, key string, typeByte byte) { 15 | o.key = key 16 | o.rd = rd 17 | o.cmdC = make(chan RedisCmd) 18 | } 19 | 20 | func (o *TairStringObject) Rewrite() <-chan RedisCmd { 21 | go func() { 22 | defer close(o.cmdC) 23 | rd := o.rd 24 | version := structure.ReadModuleUnsigned(rd) 25 | flags := structure.ReadModuleUnsigned(rd) 26 | tairValue := structure.ReadModuleString(rd) 27 | structure.ReadModuleEof(rd) 28 | o.cmdC <- RedisCmd{"EXSET", o.key, tairValue, "ABS", version, "FLAGS", flags} 29 | }() 30 | return o.cmdC 31 | } 32 | -------------------------------------------------------------------------------- /internal/rdb/types/tairzset.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "io" 5 | "strconv" 6 | "strings" 7 | 8 | "RedisShake/internal/rdb/structure" 9 | ) 10 | 11 | type TairZsetObject struct { 12 | key string 13 | rd io.Reader 14 | cmdC chan RedisCmd 15 | } 16 | 17 | func (o *TairZsetObject) LoadFromBuffer(rd io.Reader, key string, typeByte byte) { 18 | o.key = key 19 | o.rd = rd 20 | o.cmdC = make(chan RedisCmd) 21 | } 22 | 23 | func (o *TairZsetObject) Rewrite() <-chan RedisCmd { 24 | rd := o.rd 25 | cmdC := o.cmdC 26 | go func() { 27 | defer close(cmdC) 28 | cmdC <- RedisCmd{"del", o.key} 29 | length, _ := strconv.Atoi(structure.ReadModuleUnsigned(rd)) 30 | scoreNum, _ := strconv.Atoi(structure.ReadModuleUnsigned(rd)) 31 | for i := 0; i < length; i++ { 32 | key := structure.ReadModuleString(rd) 33 | var values []string 34 | for j := 0; j < scoreNum; j++ { 35 | values = append(values, structure.ReadModuleDouble(rd)) 36 | } 37 | score := strings.Join(values, "#") 38 | cmdC <- RedisCmd{"EXZADD", o.key, score, key} 39 | } 40 | structure.ReadModuleEof(rd) 41 | }() 42 | return cmdC 43 | } 44 | -------------------------------------------------------------------------------- /internal/reader/interface.go: -------------------------------------------------------------------------------- 1 | package reader 2 | 3 | import ( 4 | "RedisShake/internal/entry" 5 | "RedisShake/internal/status" 6 | "context" 7 | ) 8 | 9 | type Reader interface { 10 | status.Statusable 11 | StartRead(ctx context.Context) []chan *entry.Entry 12 | } 13 | -------------------------------------------------------------------------------- /internal/status/entry_count.go: -------------------------------------------------------------------------------- 1 | package status 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type EntryCount struct { 9 | ReadCount uint64 `json:"read_count"` 10 | ReadOps float64 `json:"read_ops"` 11 | WriteCount uint64 `json:"write_count"` 12 | WriteOps float64 `json:"write_ops"` 13 | 14 | // update ops 15 | lastReadCount uint64 16 | lastWriteCount uint64 17 | lastUpdateTimestampSec float64 18 | } 19 | 20 | // call this function every second 21 | func (e *EntryCount) UpdateOPS() { 22 | nowTimestampSec := float64(time.Now().UnixNano()) / 1e9 23 | if e.lastUpdateTimestampSec != 0 { 24 | timeIntervalSec := nowTimestampSec - e.lastUpdateTimestampSec 25 | e.ReadOps = float64(e.ReadCount-e.lastReadCount) / timeIntervalSec 26 | e.WriteOps = float64(e.WriteCount-e.lastWriteCount) / timeIntervalSec 27 | e.lastReadCount = e.ReadCount 28 | e.lastWriteCount = e.WriteCount 29 | } 30 | e.lastUpdateTimestampSec = nowTimestampSec 31 | } 32 | 33 | func (e *EntryCount) String() string { 34 | return fmt.Sprintf("read_count=[%d], read_ops=[%.2f], write_count=[%d], write_ops=[%.2f]", e.ReadCount, e.ReadOps, e.WriteCount, e.WriteOps) 35 | } 36 | -------------------------------------------------------------------------------- /internal/utils/UniqueQueue.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | type UniqueQueue struct { 8 | innerChannel chan interface{} 9 | set map[interface{}]bool 10 | lock sync.Mutex 11 | closed bool 12 | Ch chan interface{} 13 | } 14 | 15 | func NewUniqueQueue(size int) *UniqueQueue { 16 | mc := new(UniqueQueue) 17 | mc.innerChannel = make(chan interface{}, size) 18 | mc.Ch = make(chan interface{}) 19 | mc.set = make(map[interface{}]bool) 20 | go func() { 21 | for item := range mc.innerChannel { 22 | mc.lock.Lock() 23 | delete(mc.set, item) 24 | mc.lock.Unlock() 25 | mc.Ch <- item 26 | } 27 | close(mc.Ch) 28 | }() 29 | return mc 30 | } 31 | 32 | func (mc *UniqueQueue) Put(item interface{}) { 33 | mc.lock.Lock() 34 | if _, ok := mc.set[item]; ok { 35 | mc.lock.Unlock() 36 | return 37 | } else { 38 | mc.set[item] = true 39 | mc.lock.Unlock() 40 | mc.innerChannel <- item 41 | } 42 | } 43 | 44 | func (mc *UniqueQueue) Len() int { 45 | return len(mc.innerChannel) 46 | } 47 | 48 | func (mc *UniqueQueue) Close() { 49 | close(mc.innerChannel) 50 | } 51 | -------------------------------------------------------------------------------- /internal/utils/crc_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "testing" 4 | 5 | func TestCrc16(t *testing.T) { 6 | ret := Crc16("123456789") 7 | if ret != 0x31c3 { 8 | t.Errorf("Crc16(123456789) = %x", ret) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /internal/utils/file.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | "RedisShake/internal/log" 8 | ) 9 | 10 | func CreateEmptyDir(dir string) { 11 | if IsExist(dir) { 12 | err := os.RemoveAll(dir) 13 | if err != nil { 14 | log.Panicf("remove dir failed. dir=[%s], error=[%v]", dir, err) 15 | } 16 | } 17 | err := os.MkdirAll(dir, 0777) 18 | if err != nil { 19 | log.Panicf("mkdir failed. dir=[%s], error=[%v]", dir, err) 20 | } 21 | log.Debugf("CreateEmptyDir: dir=[%s]", dir) 22 | } 23 | 24 | func IsExist(path string) bool { 25 | _, err := os.Stat(path) 26 | if err != nil { 27 | if os.IsNotExist(err) { 28 | return false 29 | } else { 30 | log.Panicf(err.Error()) 31 | } 32 | } 33 | return true 34 | } 35 | 36 | func GetFileSize(path string) uint64 { 37 | fi, err := os.Stat(path) 38 | if err != nil { 39 | log.Panicf(err.Error()) 40 | } 41 | return uint64(fi.Size()) 42 | } 43 | 44 | func GetAbsPath(path string) string { 45 | absolutePath, err := filepath.Abs(path) 46 | if err != nil { 47 | log.Panicf(err.Error()) 48 | } 49 | return absolutePath 50 | } 51 | -------------------------------------------------------------------------------- /internal/utils/filelock.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | "RedisShake/internal/config" 8 | "RedisShake/internal/log" 9 | 10 | "github.com/gofrs/flock" 11 | ) 12 | 13 | var filelock *flock.Flock 14 | 15 | func ChdirAndAcquireFileLock() { 16 | // dir 17 | dir, _ := filepath.Abs(config.Opt.Advanced.Dir) 18 | file := filepath.Join(dir, "pid.lockfile") 19 | filelock = flock.New(file) 20 | locked, err := filelock.TryLock() 21 | if err != nil { 22 | log.Panicf("failed to lock file, maybe another instance is running. err=[%v], file=[%v]", err, file) 23 | } 24 | if !locked { 25 | log.Panicf("failed to lock pid file, another RedisShake instance is running?") 26 | } 27 | err = os.Chdir(dir) // change dir 28 | if err != nil { 29 | log.Panicf("failed to change dir. dir=[%v], err=[%v]", dir, err) 30 | } 31 | log.Infof("changed work dir. dir=[%s]", dir) 32 | } 33 | 34 | func ReleaseFileLock() { 35 | if filelock != nil { 36 | err := filelock.Unlock() 37 | if err != nil { 38 | log.Warnf("failed to unlock pid file. err=[%v]", err) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /internal/utils/ncpu.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "runtime" 5 | 6 | "RedisShake/internal/config" 7 | "RedisShake/internal/log" 8 | ) 9 | 10 | func SetNcpu() { 11 | if config.Opt.Advanced.Ncpu != 0 { 12 | log.Infof("set ncpu to %d", config.Opt.Advanced.Ncpu) 13 | runtime.GOMAXPROCS(config.Opt.Advanced.Ncpu) 14 | log.Infof("set GOMAXPROCS to %v", config.Opt.Advanced.Ncpu) 15 | } else { 16 | log.Infof("GOMAXPROCS defaults to the value of runtime.NumCPU [%v]", runtime.NumCPU()) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /internal/utils/parse.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "regexp" 5 | "strconv" 6 | ) 7 | 8 | func ParseDBs(s string) []int { 9 | dbsString := regexp.MustCompile(`db(\d+):`).FindAllStringSubmatch(s, -1) 10 | if dbsString == nil { 11 | return []int{} 12 | } 13 | dbs := make([]int, len(dbsString)) 14 | for i, dbString := range dbsString { 15 | db, _ := strconv.Atoi(dbString[1]) 16 | dbs[i] = db 17 | } 18 | return dbs 19 | } 20 | -------------------------------------------------------------------------------- /internal/utils/pprof.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "RedisShake/internal/config" 8 | "RedisShake/internal/log" 9 | ) 10 | 11 | func SetPprofPort() { 12 | // pprof_port 13 | if config.Opt.Advanced.PprofPort != 0 { 14 | go func() { 15 | err := http.ListenAndServe(fmt.Sprintf("localhost:%d", config.Opt.Advanced.PprofPort), nil) 16 | if err != nil { 17 | log.Panicf(err.Error()) 18 | } 19 | }() 20 | log.Infof("pprof information: http://localhost:%d/debug/pprof/", config.Opt.Advanced.PprofPort) 21 | } else { 22 | log.Infof("not set pprof port") 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /internal/writer/interface.go: -------------------------------------------------------------------------------- 1 | package writer 2 | 3 | import ( 4 | "RedisShake/internal/entry" 5 | "RedisShake/internal/status" 6 | "context" 7 | ) 8 | 9 | type Writer interface { 10 | status.Statusable 11 | Write(entry *entry.Entry) 12 | StartWrite(ctx context.Context) (ch chan *entry.Entry) 13 | Close() 14 | } 15 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Alibaba Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /scripts/commands/acl-cat.json: -------------------------------------------------------------------------------- 1 | { 2 | "CAT": { 3 | "summary": "List the ACL categories or the commands inside a category", 4 | "complexity": "O(1) since the categories and commands are a fixed set.", 5 | "group": "server", 6 | "since": "6.0.0", 7 | "arity": -2, 8 | "container": "ACL", 9 | "function": "aclCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "LOADING", 13 | "STALE", 14 | "SENTINEL" 15 | ], 16 | "arguments": [ 17 | { 18 | "name": "categoryname", 19 | "type": "string", 20 | "optional": true 21 | } 22 | ] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /scripts/commands/acl-deluser.json: -------------------------------------------------------------------------------- 1 | { 2 | "DELUSER": { 3 | "summary": "Remove the specified ACL users and the associated rules", 4 | "complexity": "O(1) amortized time considering the typical user.", 5 | "group": "server", 6 | "since": "6.0.0", 7 | "arity": -3, 8 | "container": "ACL", 9 | "function": "aclCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "LOADING", 14 | "STALE", 15 | "SENTINEL" 16 | ], 17 | "arguments": [ 18 | { 19 | "name": "username", 20 | "type": "string", 21 | "multiple": true 22 | } 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /scripts/commands/acl-dryrun.json: -------------------------------------------------------------------------------- 1 | { 2 | "DRYRUN": { 3 | "summary": "Returns whether the user can execute the given command without executing the command.", 4 | "complexity": "O(1).", 5 | "group": "server", 6 | "since": "7.0.0", 7 | "arity": -4, 8 | "container": "ACL", 9 | "function": "aclCommand", 10 | "history": [], 11 | "command_flags": [ 12 | "ADMIN", 13 | "NOSCRIPT", 14 | "LOADING", 15 | "STALE", 16 | "SENTINEL" 17 | ], 18 | "arguments": [ 19 | { 20 | "name": "username", 21 | "type": "string" 22 | }, 23 | { 24 | "name": "command", 25 | "type": "string" 26 | }, 27 | { 28 | "name": "arg", 29 | "type": "string", 30 | "optional": true, 31 | "multiple": true 32 | } 33 | ] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /scripts/commands/acl-genpass.json: -------------------------------------------------------------------------------- 1 | { 2 | "GENPASS": { 3 | "summary": "Generate a pseudorandom secure password to use for ACL users", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "6.0.0", 7 | "arity": -2, 8 | "container": "ACL", 9 | "function": "aclCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "LOADING", 13 | "STALE", 14 | "SENTINEL" 15 | ], 16 | "arguments": [ 17 | { 18 | "name": "bits", 19 | "type": "integer", 20 | "optional": true 21 | } 22 | ] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /scripts/commands/acl-getuser.json: -------------------------------------------------------------------------------- 1 | { 2 | "GETUSER": { 3 | "summary": "Get the rules for a specific ACL user", 4 | "complexity": "O(N). Where N is the number of password, command and pattern rules that the user has.", 5 | "group": "server", 6 | "since": "6.0.0", 7 | "arity": 3, 8 | "container": "ACL", 9 | "function": "aclCommand", 10 | "history": [ 11 | [ 12 | "6.2.0", 13 | "Added Pub/Sub channel patterns." 14 | ], 15 | [ 16 | "7.0.0", 17 | "Added selectors and changed the format of key and channel patterns from a list to their rule representation." 18 | ] 19 | ], 20 | "command_flags": [ 21 | "ADMIN", 22 | "NOSCRIPT", 23 | "LOADING", 24 | "STALE", 25 | "SENTINEL" 26 | ], 27 | "arguments": [ 28 | { 29 | "name": "username", 30 | "type": "string" 31 | } 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /scripts/commands/acl-help.json: -------------------------------------------------------------------------------- 1 | { 2 | "HELP": { 3 | "summary": "Show helpful text about the different subcommands", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "6.0.0", 7 | "arity": 2, 8 | "container": "ACL", 9 | "function": "aclCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE", 13 | "SENTINEL" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scripts/commands/acl-list.json: -------------------------------------------------------------------------------- 1 | { 2 | "LIST": { 3 | "summary": "List the current ACL rules in ACL config file format", 4 | "complexity": "O(N). Where N is the number of configured users.", 5 | "group": "server", 6 | "since": "6.0.0", 7 | "arity": 2, 8 | "container": "ACL", 9 | "function": "aclCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "LOADING", 14 | "STALE", 15 | "SENTINEL" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/acl-load.json: -------------------------------------------------------------------------------- 1 | { 2 | "LOAD": { 3 | "summary": "Reload the ACLs from the configured ACL file", 4 | "complexity": "O(N). Where N is the number of configured users.", 5 | "group": "server", 6 | "since": "6.0.0", 7 | "arity": 2, 8 | "container": "ACL", 9 | "function": "aclCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "LOADING", 14 | "STALE", 15 | "SENTINEL" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/acl-log.json: -------------------------------------------------------------------------------- 1 | { 2 | "LOG": { 3 | "summary": "List latest events denied because of ACLs in place", 4 | "complexity": "O(N) with N being the number of entries shown.", 5 | "group": "server", 6 | "since": "6.0.0", 7 | "arity": -2, 8 | "container": "ACL", 9 | "function": "aclCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "LOADING", 14 | "STALE", 15 | "SENTINEL" 16 | ], 17 | "arguments": [ 18 | { 19 | "name": "operation", 20 | "type": "oneof", 21 | "optional": true, 22 | "arguments": [ 23 | { 24 | "name": "count", 25 | "type": "integer" 26 | }, 27 | { 28 | "name": "reset", 29 | "type": "pure-token", 30 | "token": "RESET" 31 | } 32 | ] 33 | } 34 | ] 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /scripts/commands/acl-save.json: -------------------------------------------------------------------------------- 1 | { 2 | "SAVE": { 3 | "summary": "Save the current ACL rules in the configured ACL file", 4 | "complexity": "O(N). Where N is the number of configured users.", 5 | "group": "server", 6 | "since": "6.0.0", 7 | "arity": 2, 8 | "container": "ACL", 9 | "function": "aclCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "LOADING", 14 | "STALE", 15 | "SENTINEL" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/acl-setuser.json: -------------------------------------------------------------------------------- 1 | { 2 | "SETUSER": { 3 | "summary": "Modify or create the rules for a specific ACL user", 4 | "complexity": "O(N). Where N is the number of rules provided.", 5 | "group": "server", 6 | "since": "6.0.0", 7 | "arity": -3, 8 | "container": "ACL", 9 | "function": "aclCommand", 10 | "history": [ 11 | [ 12 | "6.2.0", 13 | "Added Pub/Sub channel patterns." 14 | ], 15 | [ 16 | "7.0.0", 17 | "Added selectors and key based permissions." 18 | ] 19 | ], 20 | "command_flags": [ 21 | "ADMIN", 22 | "NOSCRIPT", 23 | "LOADING", 24 | "STALE", 25 | "SENTINEL" 26 | ], 27 | "arguments": [ 28 | { 29 | "name": "username", 30 | "type": "string" 31 | }, 32 | { 33 | "name": "rule", 34 | "type": "string", 35 | "optional": true, 36 | "multiple": true 37 | } 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /scripts/commands/acl-users.json: -------------------------------------------------------------------------------- 1 | { 2 | "USERS": { 3 | "summary": "List the username of all the configured ACL rules", 4 | "complexity": "O(N). Where N is the number of configured users.", 5 | "group": "server", 6 | "since": "6.0.0", 7 | "arity": 2, 8 | "container": "ACL", 9 | "function": "aclCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "LOADING", 14 | "STALE", 15 | "SENTINEL" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/acl-whoami.json: -------------------------------------------------------------------------------- 1 | { 2 | "WHOAMI": { 3 | "summary": "Return the name of the user associated to the current connection", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "6.0.0", 7 | "arity": 2, 8 | "container": "ACL", 9 | "function": "aclCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "LOADING", 13 | "STALE", 14 | "SENTINEL" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/commands/acl.json: -------------------------------------------------------------------------------- 1 | { 2 | "ACL": { 3 | "summary": "A container for Access List Control commands ", 4 | "complexity": "Depends on subcommand.", 5 | "group": "server", 6 | "since": "6.0.0", 7 | "arity": -2, 8 | "command_flags": [ 9 | "SENTINEL" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /scripts/commands/asking.json: -------------------------------------------------------------------------------- 1 | { 2 | "ASKING": { 3 | "summary": "Sent by cluster clients after an -ASK redirect", 4 | "complexity": "O(1)", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 1, 8 | "function": "askingCommand", 9 | "command_flags": [ 10 | "FAST" 11 | ], 12 | "acl_categories": [ 13 | "CONNECTION" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scripts/commands/auth.json: -------------------------------------------------------------------------------- 1 | { 2 | "AUTH": { 3 | "summary": "Authenticate to the server", 4 | "complexity": "O(N) where N is the number of passwords defined for the user", 5 | "group": "connection", 6 | "since": "1.0.0", 7 | "arity": -2, 8 | "function": "authCommand", 9 | "history": [ 10 | [ 11 | "6.0.0", 12 | "Added ACL style (username and password)." 13 | ] 14 | ], 15 | "command_flags": [ 16 | "NOSCRIPT", 17 | "LOADING", 18 | "STALE", 19 | "FAST", 20 | "NO_AUTH", 21 | "SENTINEL", 22 | "ALLOW_BUSY" 23 | ], 24 | "acl_categories": [ 25 | "CONNECTION" 26 | ], 27 | "arguments": [ 28 | { 29 | "name": "username", 30 | "type": "string", 31 | "optional": true, 32 | "since": "6.0.0" 33 | }, 34 | { 35 | "name": "password", 36 | "type": "string" 37 | } 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /scripts/commands/bgrewriteaof.json: -------------------------------------------------------------------------------- 1 | { 2 | "BGREWRITEAOF": { 3 | "summary": "Asynchronously rewrite the append-only file", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "1.0.0", 7 | "arity": 1, 8 | "function": "bgrewriteaofCommand", 9 | "command_flags": [ 10 | "NO_ASYNC_LOADING", 11 | "ADMIN", 12 | "NOSCRIPT" 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /scripts/commands/bgsave.json: -------------------------------------------------------------------------------- 1 | { 2 | "BGSAVE": { 3 | "summary": "Asynchronously save the dataset to disk", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "1.0.0", 7 | "arity": -1, 8 | "function": "bgsaveCommand", 9 | "history": [ 10 | [ 11 | "3.2.2", 12 | "Added the `SCHEDULE` option." 13 | ] 14 | ], 15 | "command_flags": [ 16 | "NO_ASYNC_LOADING", 17 | "ADMIN", 18 | "NOSCRIPT" 19 | ], 20 | "arguments": [ 21 | { 22 | "name": "schedule", 23 | "token": "SCHEDULE", 24 | "type": "pure-token", 25 | "optional": true, 26 | "since": "3.2.2" 27 | } 28 | ] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /scripts/commands/client-caching.json: -------------------------------------------------------------------------------- 1 | { 2 | "CACHING": { 3 | "summary": "Instruct the server about tracking or not keys in the next request", 4 | "complexity": "O(1)", 5 | "group": "connection", 6 | "since": "6.0.0", 7 | "arity": 3, 8 | "container": "CLIENT", 9 | "function": "clientCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "LOADING", 13 | "STALE" 14 | ], 15 | "acl_categories": [ 16 | "CONNECTION" 17 | ], 18 | "arguments": [ 19 | { 20 | "name": "mode", 21 | "type": "oneof", 22 | "arguments": [ 23 | { 24 | "name": "yes", 25 | "type": "pure-token", 26 | "token": "YES" 27 | }, 28 | { 29 | "name": "no", 30 | "type": "pure-token", 31 | "token": "NO" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /scripts/commands/client-getname.json: -------------------------------------------------------------------------------- 1 | { 2 | "GETNAME": { 3 | "summary": "Get the current connection name", 4 | "complexity": "O(1)", 5 | "group": "connection", 6 | "since": "2.6.9", 7 | "arity": 2, 8 | "container": "CLIENT", 9 | "function": "clientCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "LOADING", 13 | "STALE" 14 | ], 15 | "acl_categories": [ 16 | "CONNECTION" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /scripts/commands/client-getredir.json: -------------------------------------------------------------------------------- 1 | { 2 | "GETREDIR": { 3 | "summary": "Get tracking notifications redirection client ID if any", 4 | "complexity": "O(1)", 5 | "group": "connection", 6 | "since": "6.0.0", 7 | "arity": 2, 8 | "container": "CLIENT", 9 | "function": "clientCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "LOADING", 13 | "STALE" 14 | ], 15 | "acl_categories": [ 16 | "CONNECTION" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /scripts/commands/client-help.json: -------------------------------------------------------------------------------- 1 | { 2 | "HELP": { 3 | "summary": "Show helpful text about the different subcommands", 4 | "complexity": "O(1)", 5 | "group": "connection", 6 | "since": "5.0.0", 7 | "arity": 2, 8 | "container": "CLIENT", 9 | "function": "clientCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ], 14 | "acl_categories": [ 15 | "CONNECTION" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/client-id.json: -------------------------------------------------------------------------------- 1 | { 2 | "ID": { 3 | "summary": "Returns the client ID for the current connection", 4 | "complexity": "O(1)", 5 | "group": "connection", 6 | "since": "5.0.0", 7 | "arity": 2, 8 | "container": "CLIENT", 9 | "function": "clientCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "LOADING", 13 | "STALE" 14 | ], 15 | "acl_categories": [ 16 | "CONNECTION" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /scripts/commands/client-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "INFO": { 3 | "summary": "Returns information about the current client connection.", 4 | "complexity": "O(1)", 5 | "group": "connection", 6 | "since": "6.2.0", 7 | "arity": 2, 8 | "container": "CLIENT", 9 | "function": "clientCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "LOADING", 13 | "STALE" 14 | ], 15 | "acl_categories": [ 16 | "CONNECTION" 17 | ], 18 | "command_tips": [ 19 | "NONDETERMINISTIC_OUTPUT" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scripts/commands/client-no-evict.json: -------------------------------------------------------------------------------- 1 | { 2 | "NO-EVICT": { 3 | "summary": "Set client eviction mode for the current connection", 4 | "complexity": "O(1)", 5 | "group": "connection", 6 | "since": "7.0.0", 7 | "arity": 3, 8 | "container": "CLIENT", 9 | "function": "clientCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "LOADING", 14 | "STALE" 15 | ], 16 | "acl_categories": [ 17 | "CONNECTION" 18 | ], 19 | "arguments": [ 20 | { 21 | "name": "enabled", 22 | "type": "oneof", 23 | "arguments": [ 24 | { 25 | "name": "on", 26 | "type": "pure-token", 27 | "token": "ON" 28 | }, 29 | { 30 | "name": "off", 31 | "type": "pure-token", 32 | "token": "OFF" 33 | } 34 | ] 35 | } 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /scripts/commands/client-reply.json: -------------------------------------------------------------------------------- 1 | { 2 | "REPLY": { 3 | "summary": "Instruct the server whether to reply to commands", 4 | "complexity": "O(1)", 5 | "group": "connection", 6 | "since": "3.2.0", 7 | "arity": 3, 8 | "container": "CLIENT", 9 | "function": "clientCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "LOADING", 13 | "STALE" 14 | ], 15 | "acl_categories": [ 16 | "CONNECTION" 17 | ], 18 | "arguments": [ 19 | { 20 | "name": "on_off_skip", 21 | "type": "oneof", 22 | "arguments": [ 23 | { 24 | "name": "on", 25 | "type": "pure-token", 26 | "token": "ON" 27 | }, 28 | { 29 | "name": "off", 30 | "type": "pure-token", 31 | "token": "OFF" 32 | }, 33 | { 34 | "name": "skip", 35 | "type": "pure-token", 36 | "token": "SKIP" 37 | } 38 | ] 39 | } 40 | ] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /scripts/commands/client-setname.json: -------------------------------------------------------------------------------- 1 | { 2 | "SETNAME": { 3 | "summary": "Set the current connection name", 4 | "complexity": "O(1)", 5 | "group": "connection", 6 | "since": "2.6.9", 7 | "arity": 3, 8 | "container": "CLIENT", 9 | "function": "clientCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "LOADING", 13 | "STALE" 14 | ], 15 | "acl_categories": [ 16 | "CONNECTION" 17 | ], 18 | "arguments": [ 19 | { 20 | "name": "connection-name", 21 | "type": "string" 22 | } 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /scripts/commands/client-trackinginfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "TRACKINGINFO": { 3 | "summary": "Return information about server assisted client side caching for the current connection", 4 | "complexity": "O(1)", 5 | "group": "connection", 6 | "since": "6.2.0", 7 | "arity": 2, 8 | "container": "CLIENT", 9 | "function": "clientCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "LOADING", 13 | "STALE" 14 | ], 15 | "acl_categories": [ 16 | "CONNECTION" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /scripts/commands/client-unpause.json: -------------------------------------------------------------------------------- 1 | { 2 | "UNPAUSE": { 3 | "summary": "Resume processing of clients that were paused", 4 | "complexity": "O(N) Where N is the number of paused clients", 5 | "group": "connection", 6 | "since": "6.2.0", 7 | "arity": 2, 8 | "container": "CLIENT", 9 | "function": "clientCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "LOADING", 14 | "STALE" 15 | ], 16 | "acl_categories": [ 17 | "CONNECTION" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /scripts/commands/client.json: -------------------------------------------------------------------------------- 1 | { 2 | "CLIENT": { 3 | "summary": "A container for client connection commands", 4 | "complexity": "Depends on subcommand.", 5 | "group": "connection", 6 | "since": "2.4.0", 7 | "arity": -2, 8 | "command_flags": [ 9 | "SENTINEL" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /scripts/commands/cluster-addslots.json: -------------------------------------------------------------------------------- 1 | { 2 | "ADDSLOTS": { 3 | "summary": "Assign new hash slots to receiving node", 4 | "complexity": "O(N) where N is the total number of hash slot arguments", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": -3, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "NO_ASYNC_LOADING", 12 | "ADMIN", 13 | "STALE" 14 | ], 15 | "command_tips": [ 16 | "NONDETERMINISTIC_OUTPUT" 17 | ], 18 | "arguments": [ 19 | { 20 | "name": "slot", 21 | "type": "integer", 22 | "multiple": true 23 | } 24 | ] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /scripts/commands/cluster-addslotsrange.json: -------------------------------------------------------------------------------- 1 | { 2 | "ADDSLOTSRANGE": { 3 | "summary": "Assign new hash slots to receiving node", 4 | "complexity": "O(N) where N is the total number of the slots between the start slot and end slot arguments.", 5 | "group": "cluster", 6 | "since": "7.0.0", 7 | "arity": -4, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "NO_ASYNC_LOADING", 12 | "ADMIN", 13 | "STALE" 14 | ], 15 | "command_tips": [ 16 | "NONDETERMINISTIC_OUTPUT" 17 | ], 18 | "arguments": [ 19 | { 20 | "name": "start-slot_end-slot", 21 | "type": "block", 22 | "multiple": true, 23 | "arguments": [ 24 | { 25 | "name": "start-slot", 26 | "type": "integer" 27 | }, 28 | { 29 | "name": "end-slot", 30 | "type": "integer" 31 | } 32 | ] 33 | } 34 | ] 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /scripts/commands/cluster-bumpepoch.json: -------------------------------------------------------------------------------- 1 | { 2 | "BUMPEPOCH": { 3 | "summary": "Advance the cluster config epoch", 4 | "complexity": "O(1)", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 2, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "NO_ASYNC_LOADING", 12 | "ADMIN", 13 | "STALE" 14 | ], 15 | "command_tips": [ 16 | "NONDETERMINISTIC_OUTPUT" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /scripts/commands/cluster-count-failure-reports.json: -------------------------------------------------------------------------------- 1 | { 2 | "COUNT-FAILURE-REPORTS": { 3 | "summary": "Return the number of failure reports active for a given node", 4 | "complexity": "O(N) where N is the number of failure reports", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 3, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "STALE" 13 | ], 14 | "command_tips": [ 15 | "NONDETERMINISTIC_OUTPUT" 16 | ], 17 | "arguments": [ 18 | { 19 | "name": "node-id", 20 | "type": "string" 21 | } 22 | ] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /scripts/commands/cluster-countkeysinslot.json: -------------------------------------------------------------------------------- 1 | { 2 | "COUNTKEYSINSLOT": { 3 | "summary": "Return the number of local keys in the specified hash slot", 4 | "complexity": "O(1)", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 3, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "STALE" 12 | ], 13 | "command_tips": [ 14 | "NONDETERMINISTIC_OUTPUT" 15 | ], 16 | "arguments": [ 17 | { 18 | "name": "slot", 19 | "type": "integer" 20 | } 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /scripts/commands/cluster-delslots.json: -------------------------------------------------------------------------------- 1 | { 2 | "DELSLOTS": { 3 | "summary": "Set hash slots as unbound in receiving node", 4 | "complexity": "O(N) where N is the total number of hash slot arguments", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": -3, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "NO_ASYNC_LOADING", 12 | "ADMIN", 13 | "STALE" 14 | ], 15 | "command_tips": [ 16 | "NONDETERMINISTIC_OUTPUT" 17 | ], 18 | "arguments": [ 19 | { 20 | "name": "slot", 21 | "type": "integer", 22 | "multiple": true 23 | } 24 | ] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /scripts/commands/cluster-delslotsrange.json: -------------------------------------------------------------------------------- 1 | { 2 | "DELSLOTSRANGE": { 3 | "summary": "Set hash slots as unbound in receiving node", 4 | "complexity": "O(N) where N is the total number of the slots between the start slot and end slot arguments.", 5 | "group": "cluster", 6 | "since": "7.0.0", 7 | "arity": -4, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "NO_ASYNC_LOADING", 12 | "ADMIN", 13 | "STALE" 14 | ], 15 | "command_tips": [ 16 | "NONDETERMINISTIC_OUTPUT" 17 | ], 18 | "arguments": [ 19 | { 20 | "name": "start-slot_end-slot", 21 | "type": "block", 22 | "multiple": true, 23 | "arguments": [ 24 | { 25 | "name": "start-slot", 26 | "type": "integer" 27 | }, 28 | { 29 | "name": "end-slot", 30 | "type": "integer" 31 | } 32 | ] 33 | } 34 | ] 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /scripts/commands/cluster-failover.json: -------------------------------------------------------------------------------- 1 | { 2 | "FAILOVER": { 3 | "summary": "Forces a replica to perform a manual failover of its master.", 4 | "complexity": "O(1)", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": -2, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "NO_ASYNC_LOADING", 12 | "ADMIN", 13 | "STALE" 14 | ], 15 | "command_tips": [ 16 | "NONDETERMINISTIC_OUTPUT" 17 | ], 18 | "arguments": [ 19 | { 20 | "name": "options", 21 | "type": "oneof", 22 | "optional": true, 23 | "arguments": [ 24 | { 25 | "name": "force", 26 | "type": "pure-token", 27 | "token": "FORCE" 28 | }, 29 | { 30 | "name": "takeover", 31 | "type": "pure-token", 32 | "token": "TAKEOVER" 33 | } 34 | ] 35 | } 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /scripts/commands/cluster-flushslots.json: -------------------------------------------------------------------------------- 1 | { 2 | "FLUSHSLOTS": { 3 | "summary": "Delete a node's own slots information", 4 | "complexity": "O(1)", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 2, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "NO_ASYNC_LOADING", 12 | "ADMIN", 13 | "STALE" 14 | ], 15 | "command_tips": [ 16 | "NONDETERMINISTIC_OUTPUT" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /scripts/commands/cluster-forget.json: -------------------------------------------------------------------------------- 1 | { 2 | "FORGET": { 3 | "summary": "Remove a node from the nodes table", 4 | "complexity": "O(1)", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 3, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "NO_ASYNC_LOADING", 12 | "ADMIN", 13 | "STALE" 14 | ], 15 | "command_tips": [ 16 | "NONDETERMINISTIC_OUTPUT" 17 | ], 18 | "arguments": [ 19 | { 20 | "name": "node-id", 21 | "type": "string" 22 | } 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /scripts/commands/cluster-getkeysinslot.json: -------------------------------------------------------------------------------- 1 | { 2 | "GETKEYSINSLOT": { 3 | "summary": "Return local key names in the specified hash slot", 4 | "complexity": "O(log(N)) where N is the number of requested keys", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 4, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "STALE" 12 | ], 13 | "command_tips": [ 14 | "NONDETERMINISTIC_OUTPUT" 15 | ], 16 | "arguments": [ 17 | { 18 | "name": "slot", 19 | "type": "integer" 20 | }, 21 | { 22 | "name": "count", 23 | "type": "integer" 24 | } 25 | ] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /scripts/commands/cluster-help.json: -------------------------------------------------------------------------------- 1 | { 2 | "HELP": { 3 | "summary": "Show helpful text about the different subcommands", 4 | "complexity": "O(1)", 5 | "group": "cluster", 6 | "since": "5.0.0", 7 | "arity": 2, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /scripts/commands/cluster-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "INFO": { 3 | "summary": "Provides info about Redis Cluster node state", 4 | "complexity": "O(1)", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 2, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "STALE" 12 | ], 13 | "command_tips": [ 14 | "NONDETERMINISTIC_OUTPUT" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/commands/cluster-keyslot.json: -------------------------------------------------------------------------------- 1 | { 2 | "KEYSLOT": { 3 | "summary": "Returns the hash slot of the specified key", 4 | "complexity": "O(N) where N is the number of bytes in the key", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 3, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "STALE" 12 | ], 13 | "command_tips": [ 14 | "NONDETERMINISTIC_OUTPUT" 15 | ], 16 | "arguments": [ 17 | { 18 | "name": "key", 19 | "type": "string" 20 | } 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /scripts/commands/cluster-links.json: -------------------------------------------------------------------------------- 1 | { 2 | "LINKS": { 3 | "summary": "Returns a list of all TCP links to and from peer nodes in cluster", 4 | "complexity": "O(N) where N is the total number of Cluster nodes", 5 | "group": "cluster", 6 | "since": "7.0.0", 7 | "arity": 2, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "STALE" 12 | ], 13 | "command_tips": [ 14 | "NONDETERMINISTIC_OUTPUT" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/commands/cluster-meet.json: -------------------------------------------------------------------------------- 1 | { 2 | "MEET": { 3 | "summary": "Force a node cluster to handshake with another node", 4 | "complexity": "O(1)", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": -4, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "NO_ASYNC_LOADING", 12 | "ADMIN", 13 | "STALE" 14 | ], 15 | "command_tips": [ 16 | "NONDETERMINISTIC_OUTPUT" 17 | ], 18 | "arguments": [ 19 | { 20 | "name": "ip", 21 | "type": "string" 22 | }, 23 | { 24 | "name": "port", 25 | "type": "integer" 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /scripts/commands/cluster-myid.json: -------------------------------------------------------------------------------- 1 | { 2 | "MYID": { 3 | "summary": "Return the node id", 4 | "complexity": "O(1)", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 2, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "STALE" 12 | ], 13 | "command_tips": [ 14 | "NONDETERMINISTIC_OUTPUT" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/commands/cluster-nodes.json: -------------------------------------------------------------------------------- 1 | { 2 | "NODES": { 3 | "summary": "Get Cluster config for the node", 4 | "complexity": "O(N) where N is the total number of Cluster nodes", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 2, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "STALE" 12 | ], 13 | "command_tips": [ 14 | "NONDETERMINISTIC_OUTPUT" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/commands/cluster-replicas.json: -------------------------------------------------------------------------------- 1 | { 2 | "REPLICAS": { 3 | "summary": "List replica nodes of the specified master node", 4 | "complexity": "O(1)", 5 | "group": "cluster", 6 | "since": "5.0.0", 7 | "arity": 3, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "STALE" 13 | ], 14 | "command_tips": [ 15 | "NONDETERMINISTIC_OUTPUT" 16 | ], 17 | "arguments": [ 18 | { 19 | "name": "node-id", 20 | "type": "string" 21 | } 22 | ] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /scripts/commands/cluster-replicate.json: -------------------------------------------------------------------------------- 1 | { 2 | "REPLICATE": { 3 | "summary": "Reconfigure a node as a replica of the specified master node", 4 | "complexity": "O(1)", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 3, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "NO_ASYNC_LOADING", 12 | "ADMIN", 13 | "STALE" 14 | ], 15 | "command_tips": [ 16 | "NONDETERMINISTIC_OUTPUT" 17 | ], 18 | "arguments": [ 19 | { 20 | "name": "node-id", 21 | "type": "string" 22 | } 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /scripts/commands/cluster-reset.json: -------------------------------------------------------------------------------- 1 | { 2 | "RESET": { 3 | "summary": "Reset a Redis Cluster node", 4 | "complexity": "O(N) where N is the number of known nodes. The command may execute a FLUSHALL as a side effect.", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 3, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "STALE", 13 | "NOSCRIPT" 14 | ], 15 | "command_tips": [ 16 | "NONDETERMINISTIC_OUTPUT" 17 | ], 18 | "arguments": [ 19 | { 20 | "name": "hard_soft", 21 | "type": "oneof", 22 | "optional": true, 23 | "arguments": [ 24 | { 25 | "name": "hard", 26 | "type": "pure-token", 27 | "token": "HARD" 28 | }, 29 | { 30 | "name": "soft", 31 | "type": "pure-token", 32 | "token": "SOFT" 33 | } 34 | ] 35 | } 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /scripts/commands/cluster-saveconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "SAVECONFIG": { 3 | "summary": "Forces the node to save cluster state on disk", 4 | "complexity": "O(1)", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 2, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "NO_ASYNC_LOADING", 12 | "ADMIN", 13 | "STALE" 14 | ], 15 | "command_tips": [ 16 | "NONDETERMINISTIC_OUTPUT" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /scripts/commands/cluster-set-config-epoch.json: -------------------------------------------------------------------------------- 1 | { 2 | "SET-CONFIG-EPOCH": { 3 | "summary": "Set the configuration epoch in a new node", 4 | "complexity": "O(1)", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 3, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "command_flags": [ 11 | "NO_ASYNC_LOADING", 12 | "ADMIN", 13 | "STALE" 14 | ], 15 | "command_tips": [ 16 | "NONDETERMINISTIC_OUTPUT" 17 | ], 18 | "arguments": [ 19 | { 20 | "name": "config-epoch", 21 | "type": "integer" 22 | } 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /scripts/commands/cluster-shards.json: -------------------------------------------------------------------------------- 1 | { 2 | "SHARDS": { 3 | "summary": "Get array of cluster slots to node mappings", 4 | "complexity": "O(N) where N is the total number of cluster nodes", 5 | "group": "cluster", 6 | "since": "7.0.0", 7 | "arity": 2, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "history": [], 11 | "command_flags": [ 12 | "STALE" 13 | ], 14 | "command_tips": [ 15 | "NONDETERMINISTIC_OUTPUT" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/cluster-slaves.json: -------------------------------------------------------------------------------- 1 | { 2 | "SLAVES": { 3 | "summary": "List replica nodes of the specified master node", 4 | "complexity": "O(1)", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 3, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "deprecated_since": "5.0.0", 11 | "replaced_by": "`CLUSTER REPLICAS`", 12 | "doc_flags": [ 13 | "DEPRECATED" 14 | ], 15 | "command_flags": [ 16 | "ADMIN", 17 | "STALE" 18 | ], 19 | "command_tips": [ 20 | "NONDETERMINISTIC_OUTPUT" 21 | ], 22 | "arguments": [ 23 | { 24 | "name": "node-id", 25 | "type": "string" 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /scripts/commands/cluster-slots.json: -------------------------------------------------------------------------------- 1 | { 2 | "SLOTS": { 3 | "summary": "Get array of Cluster slot to node mappings", 4 | "complexity": "O(N) where N is the total number of Cluster nodes", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 2, 8 | "container": "CLUSTER", 9 | "function": "clusterCommand", 10 | "deprecated_since": "7.0.0", 11 | "replaced_by": "`CLUSTER SHARDS`", 12 | "doc_flags": [ 13 | "DEPRECATED" 14 | ], 15 | "history": [ 16 | [ 17 | "4.0.0", 18 | "Added node IDs." 19 | ], 20 | [ 21 | "7.0.0", 22 | "Added additional networking metadata field." 23 | ] 24 | ], 25 | "command_flags": [ 26 | "STALE" 27 | ], 28 | "command_tips": [ 29 | "NONDETERMINISTIC_OUTPUT" 30 | ] 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /scripts/commands/cluster.json: -------------------------------------------------------------------------------- 1 | { 2 | "CLUSTER": { 3 | "summary": "A container for cluster commands", 4 | "complexity": "Depends on subcommand.", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": -2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scripts/commands/command-count.json: -------------------------------------------------------------------------------- 1 | { 2 | "COUNT": { 3 | "summary": "Get total number of Redis commands", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "2.8.13", 7 | "arity": 2, 8 | "container": "COMMAND", 9 | "function": "commandCountCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ], 14 | "acl_categories": [ 15 | "CONNECTION" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/command-docs.json: -------------------------------------------------------------------------------- 1 | { 2 | "DOCS": { 3 | "summary": "Get array of specific Redis command documentation", 4 | "complexity": "O(N) where N is the number of commands to look up", 5 | "group": "server", 6 | "since": "7.0.0", 7 | "arity": -2, 8 | "container": "COMMAND", 9 | "function": "commandDocsCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ], 14 | "acl_categories": [ 15 | "CONNECTION" 16 | ], 17 | "command_tips": [ 18 | "NONDETERMINISTIC_OUTPUT_ORDER" 19 | ], 20 | "arguments": [ 21 | { 22 | "name": "command-name", 23 | "type": "string", 24 | "optional": true, 25 | "multiple": true 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /scripts/commands/command-getkeys.json: -------------------------------------------------------------------------------- 1 | { 2 | "GETKEYS": { 3 | "summary": "Extract keys given a full Redis command", 4 | "complexity": "O(N) where N is the number of arguments to the command", 5 | "group": "server", 6 | "since": "2.8.13", 7 | "arity": -4, 8 | "container": "COMMAND", 9 | "function": "commandGetKeysCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ], 14 | "acl_categories": [ 15 | "CONNECTION" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/command-getkeysandflags.json: -------------------------------------------------------------------------------- 1 | { 2 | "GETKEYSANDFLAGS": { 3 | "summary": "Extract keys and access flags given a full Redis command", 4 | "complexity": "O(N) where N is the number of arguments to the command", 5 | "group": "server", 6 | "since": "7.0.0", 7 | "arity": -4, 8 | "container": "COMMAND", 9 | "function": "commandGetKeysAndFlagsCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ], 14 | "acl_categories": [ 15 | "CONNECTION" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/command-help.json: -------------------------------------------------------------------------------- 1 | { 2 | "HELP": { 3 | "summary": "Show helpful text about the different subcommands", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "5.0.0", 7 | "arity": 2, 8 | "container": "COMMAND", 9 | "function": "commandHelpCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ], 14 | "acl_categories": [ 15 | "CONNECTION" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/command-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "INFO": { 3 | "summary": "Get array of specific Redis command details, or all when no argument is given.", 4 | "complexity": "O(N) where N is the number of commands to look up", 5 | "group": "server", 6 | "since": "2.8.13", 7 | "arity": -2, 8 | "container": "COMMAND", 9 | "function": "commandInfoCommand", 10 | "history": [ 11 | [ 12 | "7.0.0", 13 | "Allowed to be called with no argument to get info on all commands." 14 | ] 15 | ], 16 | "command_flags": [ 17 | "LOADING", 18 | "STALE" 19 | ], 20 | "acl_categories": [ 21 | "CONNECTION" 22 | ], 23 | "command_tips": [ 24 | "NONDETERMINISTIC_OUTPUT_ORDER" 25 | ], 26 | "arguments": [ 27 | { 28 | "name": "command-name", 29 | "type": "string", 30 | "optional": true, 31 | "multiple": true 32 | } 33 | ] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /scripts/commands/command.json: -------------------------------------------------------------------------------- 1 | { 2 | "COMMAND": { 3 | "summary": "Get array of Redis command details", 4 | "complexity": "O(N) where N is the total number of Redis commands", 5 | "group": "server", 6 | "since": "2.8.13", 7 | "arity": -1, 8 | "function": "commandCommand", 9 | "command_flags": [ 10 | "LOADING", 11 | "STALE", 12 | "SENTINEL" 13 | ], 14 | "acl_categories": [ 15 | "CONNECTION" 16 | ], 17 | "command_tips": [ 18 | "NONDETERMINISTIC_OUTPUT_ORDER" 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scripts/commands/config-get.json: -------------------------------------------------------------------------------- 1 | { 2 | "GET": { 3 | "summary": "Get the values of configuration parameters", 4 | "complexity": "O(N) when N is the number of configuration parameters provided", 5 | "group": "server", 6 | "since": "2.0.0", 7 | "arity": -3, 8 | "container": "CONFIG", 9 | "function": "configGetCommand", 10 | "history": [ 11 | [ 12 | "7.0.0", 13 | "Added the ability to pass multiple pattern parameters in one call" 14 | ] 15 | ], 16 | "command_flags": [ 17 | "ADMIN", 18 | "NOSCRIPT", 19 | "LOADING", 20 | "STALE" 21 | ], 22 | "arguments": [ 23 | { 24 | "name": "parameter", 25 | "type": "block", 26 | "multiple": true, 27 | "arguments": [ 28 | { 29 | "name": "parameter", 30 | "type": "string" 31 | } 32 | ] 33 | } 34 | ] 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /scripts/commands/config-help.json: -------------------------------------------------------------------------------- 1 | { 2 | "HELP": { 3 | "summary": "Show helpful text about the different subcommands", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "5.0.0", 7 | "arity": 2, 8 | "container": "CONFIG", 9 | "function": "configHelpCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /scripts/commands/config-resetstat.json: -------------------------------------------------------------------------------- 1 | { 2 | "RESETSTAT": { 3 | "summary": "Reset the stats returned by INFO", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "2.0.0", 7 | "arity": 2, 8 | "container": "CONFIG", 9 | "function": "configResetStatCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "LOADING", 14 | "STALE" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/commands/config-rewrite.json: -------------------------------------------------------------------------------- 1 | { 2 | "REWRITE": { 3 | "summary": "Rewrite the configuration file with the in memory configuration", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "2.8.0", 7 | "arity": 2, 8 | "container": "CONFIG", 9 | "function": "configRewriteCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "LOADING", 14 | "STALE" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/commands/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "CONFIG": { 3 | "summary": "A container for server configuration commands", 4 | "complexity": "Depends on subcommand.", 5 | "group": "server", 6 | "since": "2.0.0", 7 | "arity": -2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scripts/commands/dbsize.json: -------------------------------------------------------------------------------- 1 | { 2 | "DBSIZE": { 3 | "summary": "Return the number of keys in the selected database", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "1.0.0", 7 | "arity": 1, 8 | "function": "dbsizeCommand", 9 | "command_flags": [ 10 | "READONLY", 11 | "FAST" 12 | ], 13 | "acl_categories": [ 14 | "KEYSPACE" 15 | ], 16 | "command_tips": [ 17 | "REQUEST_POLICY:ALL_SHARDS", 18 | "RESPONSE_POLICY:AGG_SUM" 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scripts/commands/debug.json: -------------------------------------------------------------------------------- 1 | { 2 | "DEBUG": { 3 | "summary": "A container for debugging commands", 4 | "complexity": "Depends on subcommand.", 5 | "group": "server", 6 | "since": "1.0.0", 7 | "arity": -2, 8 | "function": "debugCommand", 9 | "doc_flags": [ 10 | "SYSCMD" 11 | ], 12 | "command_flags": [ 13 | "ADMIN", 14 | "NOSCRIPT", 15 | "LOADING", 16 | "STALE", 17 | "PROTECTED" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /scripts/commands/decr.json: -------------------------------------------------------------------------------- 1 | { 2 | "DECR": { 3 | "summary": "Decrement the integer value of a key by one", 4 | "complexity": "O(1)", 5 | "group": "string", 6 | "since": "1.0.0", 7 | "arity": 2, 8 | "function": "decrCommand", 9 | "command_flags": [ 10 | "WRITE", 11 | "DENYOOM", 12 | "FAST" 13 | ], 14 | "acl_categories": [ 15 | "STRING" 16 | ], 17 | "key_specs": [ 18 | { 19 | "flags": [ 20 | "RW", 21 | "ACCESS", 22 | "UPDATE" 23 | ], 24 | "begin_search": { 25 | "index": { 26 | "pos": 1 27 | } 28 | }, 29 | "find_keys": { 30 | "range": { 31 | "lastkey": 0, 32 | "step": 1, 33 | "limit": 0 34 | } 35 | } 36 | } 37 | ], 38 | "arguments": [ 39 | { 40 | "name": "key", 41 | "type": "key", 42 | "key_spec_index": 0 43 | } 44 | ] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /scripts/commands/discard.json: -------------------------------------------------------------------------------- 1 | { 2 | "DISCARD": { 3 | "summary": "Discard all commands issued after MULTI", 4 | "complexity": "O(N), when N is the number of queued commands", 5 | "group": "transactions", 6 | "since": "2.0.0", 7 | "arity": 1, 8 | "function": "discardCommand", 9 | "command_flags": [ 10 | "NOSCRIPT", 11 | "LOADING", 12 | "STALE", 13 | "FAST", 14 | "ALLOW_BUSY" 15 | ], 16 | "acl_categories": [ 17 | "TRANSACTION" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /scripts/commands/echo.json: -------------------------------------------------------------------------------- 1 | { 2 | "ECHO": { 3 | "summary": "Echo the given string", 4 | "complexity": "O(1)", 5 | "group": "connection", 6 | "since": "1.0.0", 7 | "arity": 2, 8 | "function": "echoCommand", 9 | "command_flags": [ 10 | "LOADING", 11 | "STALE", 12 | "FAST" 13 | ], 14 | "acl_categories": [ 15 | "CONNECTION" 16 | ], 17 | "arguments": [ 18 | { 19 | "name": "message", 20 | "type": "string" 21 | } 22 | ] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /scripts/commands/exec.json: -------------------------------------------------------------------------------- 1 | { 2 | "EXEC": { 3 | "summary": "Execute all commands issued after MULTI", 4 | "complexity": "Depends on commands in the transaction", 5 | "group": "transactions", 6 | "since": "1.2.0", 7 | "arity": 1, 8 | "function": "execCommand", 9 | "command_flags": [ 10 | "NOSCRIPT", 11 | "LOADING", 12 | "STALE", 13 | "SKIP_SLOWLOG" 14 | ], 15 | "acl_categories": [ 16 | "TRANSACTION" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /scripts/commands/exhset.json: -------------------------------------------------------------------------------- 1 | { 2 | "EXHSET": { 3 | "summary": "TairHash, Insert a field into the TairHash specified by the key", 4 | "complexity": "O(1)", 5 | "group": "TairHash", 6 | "function": "exhsetCommand", 7 | "key_specs": [ 8 | { 9 | "flags": [ 10 | "RW", 11 | "UPDATE" 12 | ], 13 | "begin_search": { 14 | "index": { 15 | "pos": 1 16 | } 17 | }, 18 | "find_keys": { 19 | "range": { 20 | "lastkey": 0, 21 | "step": 1, 22 | "limit": 0 23 | } 24 | } 25 | } 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scripts/commands/expiretime.json: -------------------------------------------------------------------------------- 1 | { 2 | "EXPIRETIME": { 3 | "summary": "Get the expiration Unix timestamp for a key", 4 | "complexity": "O(1)", 5 | "group": "generic", 6 | "since": "7.0.0", 7 | "arity": 2, 8 | "function": "expiretimeCommand", 9 | "command_flags": [ 10 | "READONLY", 11 | "FAST" 12 | ], 13 | "acl_categories": [ 14 | "KEYSPACE" 15 | ], 16 | "key_specs": [ 17 | { 18 | "flags": [ 19 | "RO", 20 | "ACCESS" 21 | ], 22 | "begin_search": { 23 | "index": { 24 | "pos": 1 25 | } 26 | }, 27 | "find_keys": { 28 | "range": { 29 | "lastkey": 0, 30 | "step": 1, 31 | "limit": 0 32 | } 33 | } 34 | } 35 | ], 36 | "arguments": [ 37 | { 38 | "name": "key", 39 | "type": "key", 40 | "key_spec_index": 0 41 | } 42 | ] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /scripts/commands/exset.json: -------------------------------------------------------------------------------- 1 | { 2 | "EXSET": { 3 | "summary": "TairString, Set the value of a key", 4 | "complexity": "O(1)", 5 | "group": "TairString", 6 | "function": "exsetCommand", 7 | "key_specs": [ 8 | { 9 | "flags": [ 10 | "RW", 11 | "UPDATE" 12 | ], 13 | "begin_search": { 14 | "index": { 15 | "pos": 1 16 | } 17 | }, 18 | "find_keys": { 19 | "range": { 20 | "lastkey": 0, 21 | "step": 1, 22 | "limit": 0 23 | } 24 | } 25 | } 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scripts/commands/exzadd.json: -------------------------------------------------------------------------------- 1 | { 2 | "EXZADD": { 3 | "summary": "TairZset, Adds all the specified members with the specified (multi)scores to the tairzset stored at key", 4 | "complexity": "O(N)", 5 | "group": "TairZset", 6 | "function": "exzaddCommand", 7 | "key_specs": [ 8 | { 9 | "flags": [ 10 | "RW", 11 | "UPDATE" 12 | ], 13 | "begin_search": { 14 | "index": { 15 | "pos": 1 16 | } 17 | }, 18 | "find_keys": { 19 | "range": { 20 | "lastkey": 0, 21 | "step": 1, 22 | "limit": 0 23 | } 24 | } 25 | } 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scripts/commands/function-delete.json: -------------------------------------------------------------------------------- 1 | { 2 | "DELETE": { 3 | "summary": "Delete a function by name", 4 | "complexity": "O(1)", 5 | "group": "scripting", 6 | "since": "7.0.0", 7 | "arity": 3, 8 | "container": "FUNCTION", 9 | "function": "functionDeleteCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "WRITE" 13 | ], 14 | "acl_categories": [ 15 | "SCRIPTING" 16 | ], 17 | "command_tips": [ 18 | "REQUEST_POLICY:ALL_SHARDS", 19 | "RESPONSE_POLICY:ALL_SUCCEEDED" 20 | ], 21 | "arguments": [ 22 | { 23 | "name": "library-name", 24 | "type": "string" 25 | } 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scripts/commands/function-dump.json: -------------------------------------------------------------------------------- 1 | { 2 | "DUMP": { 3 | "summary": "Dump all functions into a serialized binary payload", 4 | "complexity": "O(N) where N is the number of functions", 5 | "group": "scripting", 6 | "since": "7.0.0", 7 | "arity": 2, 8 | "container": "FUNCTION", 9 | "function": "functionDumpCommand", 10 | "command_flags": [ 11 | "NOSCRIPT" 12 | ], 13 | "acl_categories": [ 14 | "SCRIPTING" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/commands/function-flush.json: -------------------------------------------------------------------------------- 1 | { 2 | "FLUSH": { 3 | "summary": "Deleting all functions", 4 | "complexity": "O(N) where N is the number of functions deleted", 5 | "group": "scripting", 6 | "since": "7.0.0", 7 | "arity": -2, 8 | "container": "FUNCTION", 9 | "function": "functionFlushCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "WRITE" 13 | ], 14 | "acl_categories": [ 15 | "SCRIPTING" 16 | ], 17 | "command_tips": [ 18 | "REQUEST_POLICY:ALL_SHARDS", 19 | "RESPONSE_POLICY:ALL_SUCCEEDED" 20 | ], 21 | "arguments": [ 22 | { 23 | "name": "async", 24 | "type": "oneof", 25 | "optional": true, 26 | "arguments": [ 27 | { 28 | "name": "async", 29 | "type": "pure-token", 30 | "token": "ASYNC" 31 | }, 32 | { 33 | "name": "sync", 34 | "type": "pure-token", 35 | "token": "SYNC" 36 | } 37 | ] 38 | } 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /scripts/commands/function-help.json: -------------------------------------------------------------------------------- 1 | { 2 | "HELP": { 3 | "summary": "Show helpful text about the different subcommands", 4 | "complexity": "O(1)", 5 | "group": "scripting", 6 | "since": "7.0.0", 7 | "arity": 2, 8 | "container": "FUNCTION", 9 | "function": "functionHelpCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ], 14 | "acl_categories": [ 15 | "SCRIPTING" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/function-kill.json: -------------------------------------------------------------------------------- 1 | { 2 | "KILL": { 3 | "summary": "Kill the function currently in execution.", 4 | "complexity": "O(1)", 5 | "group": "scripting", 6 | "since": "7.0.0", 7 | "arity": 2, 8 | "container": "FUNCTION", 9 | "function": "functionKillCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "ALLOW_BUSY" 13 | ], 14 | "acl_categories": [ 15 | "SCRIPTING" 16 | ], 17 | "command_tips": [ 18 | "REQUEST_POLICY:ALL_SHARDS", 19 | "RESPONSE_POLICY:ONE_SUCCEEDED" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scripts/commands/function-list.json: -------------------------------------------------------------------------------- 1 | { 2 | "LIST": { 3 | "summary": "List information about all the functions", 4 | "complexity": "O(N) where N is the number of functions", 5 | "group": "scripting", 6 | "since": "7.0.0", 7 | "arity": -2, 8 | "container": "FUNCTION", 9 | "function": "functionListCommand", 10 | "command_flags": [ 11 | "NOSCRIPT" 12 | ], 13 | "command_tips": [ 14 | "NONDETERMINISTIC_OUTPUT_ORDER" 15 | ], 16 | "acl_categories": [ 17 | "SCRIPTING" 18 | ], 19 | "arguments": [ 20 | { 21 | "name": "library-name-pattern", 22 | "type": "string", 23 | "token": "LIBRARYNAME", 24 | "optional": true 25 | }, 26 | { 27 | "name": "withcode", 28 | "type": "pure-token", 29 | "token": "WITHCODE", 30 | "optional": true 31 | } 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /scripts/commands/function-load.json: -------------------------------------------------------------------------------- 1 | { 2 | "LOAD": { 3 | "summary": "Create a function with the given arguments (name, code, description)", 4 | "complexity": "O(1) (considering compilation time is redundant)", 5 | "group": "scripting", 6 | "since": "7.0.0", 7 | "arity": -3, 8 | "container": "FUNCTION", 9 | "function": "functionLoadCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "WRITE", 13 | "DENYOOM" 14 | ], 15 | "acl_categories": [ 16 | "SCRIPTING" 17 | ], 18 | "command_tips": [ 19 | "REQUEST_POLICY:ALL_SHARDS", 20 | "RESPONSE_POLICY:ALL_SUCCEEDED" 21 | ], 22 | "arguments": [ 23 | { 24 | "name": "replace", 25 | "type": "pure-token", 26 | "token": "REPLACE", 27 | "optional": true 28 | }, 29 | { 30 | "name": "function-code", 31 | "type": "string" 32 | } 33 | ] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /scripts/commands/function-stats.json: -------------------------------------------------------------------------------- 1 | { 2 | "STATS": { 3 | "summary": "Return information about the function currently running (name, description, duration)", 4 | "complexity": "O(1)", 5 | "group": "scripting", 6 | "since": "7.0.0", 7 | "arity": 2, 8 | "container": "FUNCTION", 9 | "function": "functionStatsCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "ALLOW_BUSY" 13 | ], 14 | "acl_categories": [ 15 | "SCRIPTING" 16 | ], 17 | "command_tips": [ 18 | "NONDETERMINISTIC_OUTPUT", 19 | "REQUEST_POLICY:ALL_SHARDS", 20 | "RESPONSE_POLICY:SPECIAL" 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /scripts/commands/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "FUNCTION": { 3 | "summary": "A container for function commands", 4 | "complexity": "Depends on subcommand.", 5 | "group": "scripting", 6 | "since": "7.0.0", 7 | "arity": -2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scripts/commands/get.json: -------------------------------------------------------------------------------- 1 | { 2 | "GET": { 3 | "summary": "Get the value of a key", 4 | "complexity": "O(1)", 5 | "group": "string", 6 | "since": "1.0.0", 7 | "arity": 2, 8 | "function": "getCommand", 9 | "command_flags": [ 10 | "READONLY", 11 | "FAST" 12 | ], 13 | "acl_categories": [ 14 | "STRING" 15 | ], 16 | "key_specs": [ 17 | { 18 | "flags": [ 19 | "RO", 20 | "ACCESS" 21 | ], 22 | "begin_search": { 23 | "index": { 24 | "pos": 1 25 | } 26 | }, 27 | "find_keys": { 28 | "range": { 29 | "lastkey": 0, 30 | "step": 1, 31 | "limit": 0 32 | } 33 | } 34 | } 35 | ], 36 | "arguments": [ 37 | { 38 | "name": "key", 39 | "type": "key", 40 | "key_spec_index": 0 41 | } 42 | ] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /scripts/commands/getdel.json: -------------------------------------------------------------------------------- 1 | { 2 | "GETDEL": { 3 | "summary": "Get the value of a key and delete the key", 4 | "complexity": "O(1)", 5 | "group": "string", 6 | "since": "6.2.0", 7 | "arity": 2, 8 | "function": "getdelCommand", 9 | "command_flags": [ 10 | "WRITE", 11 | "FAST" 12 | ], 13 | "acl_categories": [ 14 | "STRING" 15 | ], 16 | "key_specs": [ 17 | { 18 | "flags": [ 19 | "RW", 20 | "ACCESS", 21 | "DELETE" 22 | ], 23 | "begin_search": { 24 | "index": { 25 | "pos": 1 26 | } 27 | }, 28 | "find_keys": { 29 | "range": { 30 | "lastkey": 0, 31 | "step": 1, 32 | "limit": 0 33 | } 34 | } 35 | } 36 | ], 37 | "arguments": [ 38 | { 39 | "name": "key", 40 | "type": "key", 41 | "key_spec_index": 0 42 | } 43 | ] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /scripts/commands/hexists.json: -------------------------------------------------------------------------------- 1 | { 2 | "HEXISTS": { 3 | "summary": "Determine if a hash field exists", 4 | "complexity": "O(1)", 5 | "group": "hash", 6 | "since": "2.0.0", 7 | "arity": 3, 8 | "function": "hexistsCommand", 9 | "command_flags": [ 10 | "READONLY", 11 | "FAST" 12 | ], 13 | "acl_categories": [ 14 | "HASH" 15 | ], 16 | "key_specs": [ 17 | { 18 | "flags": [ 19 | "RO" 20 | ], 21 | "begin_search": { 22 | "index": { 23 | "pos": 1 24 | } 25 | }, 26 | "find_keys": { 27 | "range": { 28 | "lastkey": 0, 29 | "step": 1, 30 | "limit": 0 31 | } 32 | } 33 | } 34 | ], 35 | "arguments": [ 36 | { 37 | "name": "key", 38 | "type": "key", 39 | "key_spec_index": 0 40 | }, 41 | { 42 | "name": "field", 43 | "type": "string" 44 | } 45 | ] 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /scripts/commands/hkeys.json: -------------------------------------------------------------------------------- 1 | { 2 | "HKEYS": { 3 | "summary": "Get all the fields in a hash", 4 | "complexity": "O(N) where N is the size of the hash.", 5 | "group": "hash", 6 | "since": "2.0.0", 7 | "arity": 2, 8 | "function": "hkeysCommand", 9 | "command_flags": [ 10 | "READONLY" 11 | ], 12 | "acl_categories": [ 13 | "HASH" 14 | ], 15 | "command_tips": [ 16 | "NONDETERMINISTIC_OUTPUT_ORDER" 17 | ], 18 | "key_specs": [ 19 | { 20 | "flags": [ 21 | "RO", 22 | "ACCESS" 23 | ], 24 | "begin_search": { 25 | "index": { 26 | "pos": 1 27 | } 28 | }, 29 | "find_keys": { 30 | "range": { 31 | "lastkey": 0, 32 | "step": 1, 33 | "limit": 0 34 | } 35 | } 36 | } 37 | ], 38 | "arguments": [ 39 | { 40 | "name": "key", 41 | "type": "key", 42 | "key_spec_index": 0 43 | } 44 | ] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /scripts/commands/hlen.json: -------------------------------------------------------------------------------- 1 | { 2 | "HLEN": { 3 | "summary": "Get the number of fields in a hash", 4 | "complexity": "O(1)", 5 | "group": "hash", 6 | "since": "2.0.0", 7 | "arity": 2, 8 | "function": "hlenCommand", 9 | "command_flags": [ 10 | "READONLY", 11 | "FAST" 12 | ], 13 | "acl_categories": [ 14 | "HASH" 15 | ], 16 | "key_specs": [ 17 | { 18 | "flags": [ 19 | "RO" 20 | ], 21 | "begin_search": { 22 | "index": { 23 | "pos": 1 24 | } 25 | }, 26 | "find_keys": { 27 | "range": { 28 | "lastkey": 0, 29 | "step": 1, 30 | "limit": 0 31 | } 32 | } 33 | } 34 | ], 35 | "arguments": [ 36 | { 37 | "name": "key", 38 | "type": "key", 39 | "key_spec_index": 0 40 | } 41 | ] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scripts/commands/hstrlen.json: -------------------------------------------------------------------------------- 1 | { 2 | "HSTRLEN": { 3 | "summary": "Get the length of the value of a hash field", 4 | "complexity": "O(1)", 5 | "group": "hash", 6 | "since": "3.2.0", 7 | "arity": 3, 8 | "function": "hstrlenCommand", 9 | "command_flags": [ 10 | "READONLY", 11 | "FAST" 12 | ], 13 | "acl_categories": [ 14 | "HASH" 15 | ], 16 | "key_specs": [ 17 | { 18 | "flags": [ 19 | "RO" 20 | ], 21 | "begin_search": { 22 | "index": { 23 | "pos": 1 24 | } 25 | }, 26 | "find_keys": { 27 | "range": { 28 | "lastkey": 0, 29 | "step": 1, 30 | "limit": 0 31 | } 32 | } 33 | } 34 | ], 35 | "arguments": [ 36 | { 37 | "name": "key", 38 | "type": "key", 39 | "key_spec_index": 0 40 | }, 41 | { 42 | "name": "field", 43 | "type": "string" 44 | } 45 | ] 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /scripts/commands/hvals.json: -------------------------------------------------------------------------------- 1 | { 2 | "HVALS": { 3 | "summary": "Get all the values in a hash", 4 | "complexity": "O(N) where N is the size of the hash.", 5 | "group": "hash", 6 | "since": "2.0.0", 7 | "arity": 2, 8 | "function": "hvalsCommand", 9 | "command_flags": [ 10 | "READONLY" 11 | ], 12 | "acl_categories": [ 13 | "HASH" 14 | ], 15 | "command_tips": [ 16 | "NONDETERMINISTIC_OUTPUT_ORDER" 17 | ], 18 | "key_specs": [ 19 | { 20 | "flags": [ 21 | "RO", 22 | "ACCESS" 23 | ], 24 | "begin_search": { 25 | "index": { 26 | "pos": 1 27 | } 28 | }, 29 | "find_keys": { 30 | "range": { 31 | "lastkey": 0, 32 | "step": 1, 33 | "limit": 0 34 | } 35 | } 36 | } 37 | ], 38 | "arguments": [ 39 | { 40 | "name": "key", 41 | "type": "key", 42 | "key_spec_index": 0 43 | } 44 | ] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /scripts/commands/incr.json: -------------------------------------------------------------------------------- 1 | { 2 | "INCR": { 3 | "summary": "Increment the integer value of a key by one", 4 | "complexity": "O(1)", 5 | "group": "string", 6 | "since": "1.0.0", 7 | "arity": 2, 8 | "function": "incrCommand", 9 | "command_flags": [ 10 | "WRITE", 11 | "DENYOOM", 12 | "FAST" 13 | ], 14 | "acl_categories": [ 15 | "STRING" 16 | ], 17 | "key_specs": [ 18 | { 19 | "flags": [ 20 | "RW", 21 | "ACCESS", 22 | "UPDATE" 23 | ], 24 | "begin_search": { 25 | "index": { 26 | "pos": 1 27 | } 28 | }, 29 | "find_keys": { 30 | "range": { 31 | "lastkey": 0, 32 | "step": 1, 33 | "limit": 0 34 | } 35 | } 36 | } 37 | ], 38 | "arguments": [ 39 | { 40 | "name": "key", 41 | "type": "key", 42 | "key_spec_index": 0 43 | } 44 | ] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /scripts/commands/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "INFO": { 3 | "summary": "Get information and statistics about the server", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "1.0.0", 7 | "arity": -1, 8 | "function": "infoCommand", 9 | "history": [ 10 | [ 11 | "7.0.0", 12 | "Added support for taking multiple section arguments." 13 | ] 14 | ], 15 | "command_flags": [ 16 | "LOADING", 17 | "STALE", 18 | "SENTINEL" 19 | ], 20 | "acl_categories": [ 21 | "DANGEROUS" 22 | ], 23 | "command_tips": [ 24 | "NONDETERMINISTIC_OUTPUT", 25 | "REQUEST_POLICY:ALL_SHARDS", 26 | "RESPONSE_POLICY:SPECIAL" 27 | ], 28 | "arguments": [ 29 | { 30 | "name": "section", 31 | "type": "string", 32 | "multiple": true, 33 | "optional": true 34 | } 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /scripts/commands/keys.json: -------------------------------------------------------------------------------- 1 | { 2 | "KEYS": { 3 | "summary": "Find all keys matching the given pattern", 4 | "complexity": "O(N) with N being the number of keys in the database, under the assumption that the key names in the database and the given pattern have limited length.", 5 | "group": "generic", 6 | "since": "1.0.0", 7 | "arity": 2, 8 | "function": "keysCommand", 9 | "command_flags": [ 10 | "READONLY" 11 | ], 12 | "acl_categories": [ 13 | "KEYSPACE", 14 | "DANGEROUS" 15 | ], 16 | "command_tips": [ 17 | "REQUEST_POLICY:ALL_SHARDS", 18 | "NONDETERMINISTIC_OUTPUT_ORDER" 19 | ], 20 | "arguments": [ 21 | { 22 | "name": "pattern", 23 | "type": "pattern" 24 | } 25 | ] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /scripts/commands/lastsave.json: -------------------------------------------------------------------------------- 1 | { 2 | "LASTSAVE": { 3 | "summary": "Get the UNIX time stamp of the last successful save to disk", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "1.0.0", 7 | "arity": 1, 8 | "function": "lastsaveCommand", 9 | "command_flags": [ 10 | "LOADING", 11 | "STALE", 12 | "FAST" 13 | ], 14 | "command_tips": [ 15 | "NONDETERMINISTIC_OUTPUT" 16 | ], 17 | "acl_categories": [ 18 | "ADMIN", 19 | "DANGEROUS" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scripts/commands/latency-doctor.json: -------------------------------------------------------------------------------- 1 | { 2 | "DOCTOR": { 3 | "summary": "Return a human readable latency analysis report.", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "2.8.13", 7 | "arity": 2, 8 | "container": "LATENCY", 9 | "function": "latencyCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "LOADING", 14 | "STALE" 15 | ], 16 | "command_tips": [ 17 | "NONDETERMINISTIC_OUTPUT", 18 | "REQUEST_POLICY:ALL_NODES", 19 | "RESPONSE_POLICY:SPECIAL" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scripts/commands/latency-graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "GRAPH": { 3 | "summary": "Return a latency graph for the event.", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "2.8.13", 7 | "arity": 3, 8 | "container": "LATENCY", 9 | "function": "latencyCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "LOADING", 14 | "STALE" 15 | ], 16 | "command_tips": [ 17 | "NONDETERMINISTIC_OUTPUT", 18 | "REQUEST_POLICY:ALL_NODES", 19 | "RESPONSE_POLICY:SPECIAL" 20 | ], 21 | "arguments": [ 22 | { 23 | "name": "event", 24 | "type": "string" 25 | } 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scripts/commands/latency-help.json: -------------------------------------------------------------------------------- 1 | { 2 | "HELP": { 3 | "summary": "Show helpful text about the different subcommands.", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "2.8.13", 7 | "arity": 2, 8 | "container": "LATENCY", 9 | "function": "latencyCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /scripts/commands/latency-histogram.json: -------------------------------------------------------------------------------- 1 | { 2 | "HISTOGRAM": { 3 | "summary": "Return the cumulative distribution of latencies of a subset of commands or all.", 4 | "complexity": "O(N) where N is the number of commands with latency information being retrieved.", 5 | "group": "server", 6 | "since": "7.0.0", 7 | "arity": -2, 8 | "container": "LATENCY", 9 | "function": "latencyCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "LOADING", 14 | "STALE" 15 | ], 16 | "command_tips": [ 17 | "NONDETERMINISTIC_OUTPUT", 18 | "REQUEST_POLICY:ALL_NODES", 19 | "RESPONSE_POLICY:SPECIAL" 20 | ], 21 | "arguments": [ 22 | { 23 | "name": "COMMAND", 24 | "type": "string", 25 | "optional": true, 26 | "multiple": true 27 | } 28 | ] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /scripts/commands/latency-history.json: -------------------------------------------------------------------------------- 1 | { 2 | "HISTORY": { 3 | "summary": "Return timestamp-latency samples for the event.", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "2.8.13", 7 | "arity": 3, 8 | "container": "LATENCY", 9 | "function": "latencyCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "LOADING", 14 | "STALE" 15 | ], 16 | "command_tips": [ 17 | "NONDETERMINISTIC_OUTPUT", 18 | "REQUEST_POLICY:ALL_NODES", 19 | "RESPONSE_POLICY:SPECIAL" 20 | ], 21 | "arguments": [ 22 | { 23 | "name": "event", 24 | "type": "string" 25 | } 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scripts/commands/latency-latest.json: -------------------------------------------------------------------------------- 1 | { 2 | "LATEST": { 3 | "summary": "Return the latest latency samples for all events.", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "2.8.13", 7 | "arity": 2, 8 | "container": "LATENCY", 9 | "function": "latencyCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "LOADING", 14 | "STALE" 15 | ], 16 | "command_tips": [ 17 | "NONDETERMINISTIC_OUTPUT", 18 | "REQUEST_POLICY:ALL_NODES", 19 | "RESPONSE_POLICY:SPECIAL" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scripts/commands/latency-reset.json: -------------------------------------------------------------------------------- 1 | { 2 | "RESET": { 3 | "summary": "Reset latency data for one or more events.", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "2.8.13", 7 | "arity": -2, 8 | "container": "LATENCY", 9 | "function": "latencyCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "LOADING", 14 | "STALE" 15 | ], 16 | "command_tips": [ 17 | "REQUEST_POLICY:ALL_NODES", 18 | "RESPONSE_POLICY:ALL_SUCCEEDED" 19 | ], 20 | "arguments": [ 21 | { 22 | "name": "event", 23 | "type": "string", 24 | "optional": true, 25 | "multiple": true 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /scripts/commands/latency.json: -------------------------------------------------------------------------------- 1 | { 2 | "LATENCY": { 3 | "summary": "A container for latency diagnostics commands", 4 | "complexity": "Depends on subcommand.", 5 | "group": "server", 6 | "since": "2.8.13", 7 | "arity": -2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scripts/commands/llen.json: -------------------------------------------------------------------------------- 1 | { 2 | "LLEN": { 3 | "summary": "Get the length of a list", 4 | "complexity": "O(1)", 5 | "group": "list", 6 | "since": "1.0.0", 7 | "arity": 2, 8 | "function": "llenCommand", 9 | "command_flags": [ 10 | "READONLY", 11 | "FAST" 12 | ], 13 | "acl_categories": [ 14 | "LIST" 15 | ], 16 | "key_specs": [ 17 | { 18 | "flags": [ 19 | "RO" 20 | ], 21 | "begin_search": { 22 | "index": { 23 | "pos": 1 24 | } 25 | }, 26 | "find_keys": { 27 | "range": { 28 | "lastkey": 0, 29 | "step": 1, 30 | "limit": 0 31 | } 32 | } 33 | } 34 | ], 35 | "arguments": [ 36 | { 37 | "name": "key", 38 | "type": "key", 39 | "key_spec_index": 0 40 | } 41 | ] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scripts/commands/lolwut.json: -------------------------------------------------------------------------------- 1 | { 2 | "LOLWUT": { 3 | "summary": "Display some computer art and the Redis version", 4 | "group": "server", 5 | "since": "5.0.0", 6 | "arity": -1, 7 | "function": "lolwutCommand", 8 | "command_flags": [ 9 | "READONLY", 10 | "FAST" 11 | ], 12 | "arguments": [ 13 | { 14 | "token": "VERSION", 15 | "name": "version", 16 | "type": "integer", 17 | "optional": true 18 | } 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scripts/commands/memory-doctor.json: -------------------------------------------------------------------------------- 1 | { 2 | "DOCTOR": { 3 | "summary": "Outputs memory problems report", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "4.0.0", 7 | "arity": 2, 8 | "container": "MEMORY", 9 | "function": "memoryCommand", 10 | "command_tips": [ 11 | "NONDETERMINISTIC_OUTPUT", 12 | "REQUEST_POLICY:ALL_SHARDS", 13 | "RESPONSE_POLICY:SPECIAL" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scripts/commands/memory-help.json: -------------------------------------------------------------------------------- 1 | { 2 | "HELP": { 3 | "summary": "Show helpful text about the different subcommands", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "4.0.0", 7 | "arity": 2, 8 | "container": "MEMORY", 9 | "function": "memoryCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /scripts/commands/memory-malloc-stats.json: -------------------------------------------------------------------------------- 1 | { 2 | "MALLOC-STATS": { 3 | "summary": "Show allocator internal stats", 4 | "complexity": "Depends on how much memory is allocated, could be slow", 5 | "group": "server", 6 | "since": "4.0.0", 7 | "arity": 2, 8 | "container": "MEMORY", 9 | "function": "memoryCommand", 10 | "command_tips": [ 11 | "NONDETERMINISTIC_OUTPUT", 12 | "REQUEST_POLICY:ALL_SHARDS", 13 | "RESPONSE_POLICY:SPECIAL" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scripts/commands/memory-purge.json: -------------------------------------------------------------------------------- 1 | { 2 | "PURGE": { 3 | "summary": "Ask the allocator to release memory", 4 | "complexity": "Depends on how much memory is allocated, could be slow", 5 | "group": "server", 6 | "since": "4.0.0", 7 | "arity": 2, 8 | "container": "MEMORY", 9 | "function": "memoryCommand", 10 | "command_tips": [ 11 | "REQUEST_POLICY:ALL_SHARDS", 12 | "RESPONSE_POLICY:ALL_SUCCEEDED" 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /scripts/commands/memory-stats.json: -------------------------------------------------------------------------------- 1 | { 2 | "STATS": { 3 | "summary": "Show memory usage details", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "4.0.0", 7 | "arity": 2, 8 | "container": "MEMORY", 9 | "function": "memoryCommand", 10 | "command_tips": [ 11 | "NONDETERMINISTIC_OUTPUT", 12 | "REQUEST_POLICY:ALL_SHARDS", 13 | "RESPONSE_POLICY:SPECIAL" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scripts/commands/memory.json: -------------------------------------------------------------------------------- 1 | { 2 | "MEMORY": { 3 | "summary": "A container for memory diagnostics commands", 4 | "complexity": "Depends on subcommand.", 5 | "group": "server", 6 | "since": "4.0.0", 7 | "arity": -2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scripts/commands/module-help.json: -------------------------------------------------------------------------------- 1 | { 2 | "HELP": { 3 | "summary": "Show helpful text about the different subcommands", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "5.0.0", 7 | "arity": 2, 8 | "container": "MODULE", 9 | "function": "moduleCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /scripts/commands/module-list.json: -------------------------------------------------------------------------------- 1 | { 2 | "LIST": { 3 | "summary": "List all modules loaded by the server", 4 | "complexity": "O(N) where N is the number of loaded modules.", 5 | "group": "server", 6 | "since": "4.0.0", 7 | "arity": 2, 8 | "container": "MODULE", 9 | "function": "moduleCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "NOSCRIPT" 13 | ], 14 | "command_tips": [ 15 | "NONDETERMINISTIC_OUTPUT_ORDER" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/module-load.json: -------------------------------------------------------------------------------- 1 | { 2 | "LOAD": { 3 | "summary": "Load a module", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "4.0.0", 7 | "arity": -3, 8 | "container": "MODULE", 9 | "function": "moduleCommand", 10 | "command_flags": [ 11 | "NO_ASYNC_LOADING", 12 | "ADMIN", 13 | "NOSCRIPT", 14 | "PROTECTED" 15 | ], 16 | "arguments": [ 17 | { 18 | "name": "path", 19 | "type": "string" 20 | }, 21 | { 22 | "name": "arg", 23 | "type": "string", 24 | "optional": true, 25 | "multiple": true 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /scripts/commands/module-unload.json: -------------------------------------------------------------------------------- 1 | { 2 | "UNLOAD": { 3 | "summary": "Unload a module", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "4.0.0", 7 | "arity": 3, 8 | "container": "MODULE", 9 | "function": "moduleCommand", 10 | "command_flags": [ 11 | "NO_ASYNC_LOADING", 12 | "ADMIN", 13 | "NOSCRIPT", 14 | "PROTECTED" 15 | ], 16 | "arguments": [ 17 | { 18 | "name": "name", 19 | "type": "string" 20 | } 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /scripts/commands/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "MODULE": { 3 | "summary": "A container for module commands", 4 | "complexity": "Depends on subcommand.", 5 | "group": "server", 6 | "since": "4.0.0", 7 | "arity": -2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scripts/commands/monitor.json: -------------------------------------------------------------------------------- 1 | { 2 | "MONITOR": { 3 | "summary": "Listen for all requests received by the server in real time", 4 | "group": "server", 5 | "since": "1.0.0", 6 | "arity": 1, 7 | "function": "monitorCommand", 8 | "history": [], 9 | "command_flags": [ 10 | "ADMIN", 11 | "NOSCRIPT", 12 | "LOADING", 13 | "STALE" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scripts/commands/multi.json: -------------------------------------------------------------------------------- 1 | { 2 | "MULTI": { 3 | "summary": "Mark the start of a transaction block", 4 | "complexity": "O(1)", 5 | "group": "transactions", 6 | "since": "1.2.0", 7 | "arity": 1, 8 | "function": "multiCommand", 9 | "command_flags": [ 10 | "NOSCRIPT", 11 | "LOADING", 12 | "STALE", 13 | "FAST", 14 | "ALLOW_BUSY" 15 | ], 16 | "acl_categories": [ 17 | "TRANSACTION" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /scripts/commands/object-encoding.json: -------------------------------------------------------------------------------- 1 | { 2 | "ENCODING": { 3 | "summary": "Inspect the internal encoding of a Redis object", 4 | "complexity": "O(1)", 5 | "group": "generic", 6 | "since": "2.2.3", 7 | "arity": 3, 8 | "container": "OBJECT", 9 | "function": "objectCommand", 10 | "command_flags": [ 11 | "READONLY" 12 | ], 13 | "acl_categories": [ 14 | "KEYSPACE" 15 | ], 16 | "command_tips": [ 17 | "NONDETERMINISTIC_OUTPUT" 18 | ], 19 | "key_specs": [ 20 | { 21 | "flags": [ 22 | "RO" 23 | ], 24 | "begin_search": { 25 | "index": { 26 | "pos": 2 27 | } 28 | }, 29 | "find_keys": { 30 | "range": { 31 | "lastkey": 0, 32 | "step": 1, 33 | "limit": 0 34 | } 35 | } 36 | } 37 | ], 38 | "arguments": [ 39 | { 40 | "name": "key", 41 | "type": "key", 42 | "key_spec_index": 0 43 | } 44 | ] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /scripts/commands/object-help.json: -------------------------------------------------------------------------------- 1 | { 2 | "HELP": { 3 | "summary": "Show helpful text about the different subcommands", 4 | "complexity": "O(1)", 5 | "group": "generic", 6 | "since": "6.2.0", 7 | "arity": 2, 8 | "container": "OBJECT", 9 | "function": "objectCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ], 14 | "acl_categories": [ 15 | "KEYSPACE" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/object.json: -------------------------------------------------------------------------------- 1 | { 2 | "OBJECT": { 3 | "summary": "A container for object introspection commands", 4 | "complexity": "Depends on subcommand.", 5 | "group": "generic", 6 | "since": "2.2.3", 7 | "arity": -2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scripts/commands/persist.json: -------------------------------------------------------------------------------- 1 | { 2 | "PERSIST": { 3 | "summary": "Remove the expiration from a key", 4 | "complexity": "O(1)", 5 | "group": "generic", 6 | "since": "2.2.0", 7 | "arity": 2, 8 | "function": "persistCommand", 9 | "command_flags": [ 10 | "WRITE", 11 | "FAST" 12 | ], 13 | "acl_categories": [ 14 | "KEYSPACE" 15 | ], 16 | "key_specs": [ 17 | { 18 | "flags": [ 19 | "RW", 20 | "UPDATE" 21 | ], 22 | "begin_search": { 23 | "index": { 24 | "pos": 1 25 | } 26 | }, 27 | "find_keys": { 28 | "range": { 29 | "lastkey": 0, 30 | "step": 1, 31 | "limit": 0 32 | } 33 | } 34 | } 35 | ], 36 | "arguments": [ 37 | { 38 | "name": "key", 39 | "type": "key", 40 | "key_spec_index": 0 41 | } 42 | ] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /scripts/commands/pexpiretime.json: -------------------------------------------------------------------------------- 1 | { 2 | "PEXPIRETIME": { 3 | "summary": "Get the expiration Unix timestamp for a key in milliseconds", 4 | "complexity": "O(1)", 5 | "group": "generic", 6 | "since": "7.0.0", 7 | "arity": 2, 8 | "function": "pexpiretimeCommand", 9 | "command_flags": [ 10 | "READONLY", 11 | "FAST" 12 | ], 13 | "acl_categories": [ 14 | "KEYSPACE" 15 | ], 16 | "key_specs": [ 17 | { 18 | "flags": [ 19 | "RO", 20 | "ACCESS" 21 | ], 22 | "begin_search": { 23 | "index": { 24 | "pos": 1 25 | } 26 | }, 27 | "find_keys": { 28 | "range": { 29 | "lastkey": 0, 30 | "step": 1, 31 | "limit": 0 32 | } 33 | } 34 | } 35 | ], 36 | "arguments": [ 37 | { 38 | "name": "key", 39 | "type": "key", 40 | "key_spec_index": 0 41 | } 42 | ] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /scripts/commands/pfselftest.json: -------------------------------------------------------------------------------- 1 | { 2 | "PFSELFTEST": { 3 | "summary": "An internal command for testing HyperLogLog values", 4 | "complexity": "N/A", 5 | "group": "hyperloglog", 6 | "since": "2.8.9", 7 | "arity": 1, 8 | "function": "pfselftestCommand", 9 | "doc_flags": [ 10 | "SYSCMD" 11 | ], 12 | "command_flags": [ 13 | "ADMIN" 14 | ], 15 | "acl_categories": [ 16 | "HYPERLOGLOG" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /scripts/commands/ping.json: -------------------------------------------------------------------------------- 1 | { 2 | "PING": { 3 | "summary": "Ping the server", 4 | "complexity": "O(1)", 5 | "group": "connection", 6 | "since": "1.0.0", 7 | "arity": -1, 8 | "function": "pingCommand", 9 | "command_flags": [ 10 | "FAST", 11 | "SENTINEL" 12 | ], 13 | "acl_categories": [ 14 | "CONNECTION" 15 | ], 16 | "command_tips": [ 17 | "REQUEST_POLICY:ALL_SHARDS", 18 | "RESPONSE_POLICY:ALL_SUCCEEDED" 19 | ], 20 | "arguments": [ 21 | { 22 | "name": "message", 23 | "type": "string", 24 | "optional": true 25 | } 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scripts/commands/psubscribe.json: -------------------------------------------------------------------------------- 1 | { 2 | "PSUBSCRIBE": { 3 | "summary": "Listen for messages published to channels matching the given patterns", 4 | "complexity": "O(N) where N is the number of patterns the client is already subscribed to.", 5 | "group": "pubsub", 6 | "since": "2.0.0", 7 | "arity": -2, 8 | "function": "psubscribeCommand", 9 | "command_flags": [ 10 | "PUBSUB", 11 | "NOSCRIPT", 12 | "LOADING", 13 | "STALE", 14 | "SENTINEL" 15 | ], 16 | "arguments": [ 17 | { 18 | "name": "pattern", 19 | "type": "block", 20 | "multiple": true, 21 | "arguments": [ 22 | { 23 | "name": "pattern", 24 | "type": "pattern" 25 | } 26 | ] 27 | } 28 | ] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /scripts/commands/psync.json: -------------------------------------------------------------------------------- 1 | { 2 | "PSYNC": { 3 | "summary": "Internal command used for replication", 4 | "group": "server", 5 | "since": "2.8.0", 6 | "arity": -3, 7 | "function": "syncCommand", 8 | "command_flags": [ 9 | "NO_ASYNC_LOADING", 10 | "ADMIN", 11 | "NO_MULTI", 12 | "NOSCRIPT" 13 | ], 14 | "arguments": [ 15 | { 16 | "name": "replicationid", 17 | "type": "string" 18 | }, 19 | { 20 | "name": "offset", 21 | "type": "integer" 22 | } 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /scripts/commands/publish.json: -------------------------------------------------------------------------------- 1 | { 2 | "PUBLISH": { 3 | "summary": "Post a message to a channel", 4 | "complexity": "O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client).", 5 | "group": "pubsub", 6 | "since": "2.0.0", 7 | "arity": 3, 8 | "function": "publishCommand", 9 | "command_flags": [ 10 | "PUBSUB", 11 | "LOADING", 12 | "STALE", 13 | "FAST", 14 | "MAY_REPLICATE", 15 | "SENTINEL" 16 | ], 17 | "arguments": [ 18 | { 19 | "name": "channel", 20 | "type": "string" 21 | }, 22 | { 23 | "name": "message", 24 | "type": "string" 25 | } 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scripts/commands/pubsub-channels.json: -------------------------------------------------------------------------------- 1 | { 2 | "CHANNELS": { 3 | "summary": "List active channels", 4 | "complexity": "O(N) where N is the number of active channels, and assuming constant time pattern matching (relatively short channels and patterns)", 5 | "group": "pubsub", 6 | "since": "2.8.0", 7 | "arity": -2, 8 | "container": "PUBSUB", 9 | "function": "pubsubCommand", 10 | "command_flags": [ 11 | "PUBSUB", 12 | "LOADING", 13 | "STALE" 14 | ], 15 | "arguments": [ 16 | { 17 | "name": "pattern", 18 | "type": "pattern", 19 | "optional": true 20 | } 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /scripts/commands/pubsub-help.json: -------------------------------------------------------------------------------- 1 | { 2 | "HELP": { 3 | "summary": "Show helpful text about the different subcommands", 4 | "complexity": "O(1)", 5 | "group": "pubsub", 6 | "since": "6.2.0", 7 | "arity": 2, 8 | "container": "PUBSUB", 9 | "function": "pubsubCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /scripts/commands/pubsub-numpat.json: -------------------------------------------------------------------------------- 1 | { 2 | "NUMPAT": { 3 | "summary": "Get the count of unique patterns pattern subscriptions", 4 | "complexity": "O(1)", 5 | "group": "pubsub", 6 | "since": "2.8.0", 7 | "arity": 2, 8 | "container": "PUBSUB", 9 | "function": "pubsubCommand", 10 | "command_flags": [ 11 | "PUBSUB", 12 | "LOADING", 13 | "STALE" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scripts/commands/pubsub-numsub.json: -------------------------------------------------------------------------------- 1 | { 2 | "NUMSUB": { 3 | "summary": "Get the count of subscribers for channels", 4 | "complexity": "O(N) for the NUMSUB subcommand, where N is the number of requested channels", 5 | "group": "pubsub", 6 | "since": "2.8.0", 7 | "arity": -2, 8 | "container": "PUBSUB", 9 | "function": "pubsubCommand", 10 | "command_flags": [ 11 | "PUBSUB", 12 | "LOADING", 13 | "STALE" 14 | ], 15 | "arguments": [ 16 | { 17 | "name": "channel", 18 | "type": "string", 19 | "optional": true, 20 | "multiple": true 21 | } 22 | ] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /scripts/commands/pubsub-shardchannels.json: -------------------------------------------------------------------------------- 1 | { 2 | "SHARDCHANNELS": { 3 | "summary": "List active shard channels", 4 | "complexity": "O(N) where N is the number of active shard channels, and assuming constant time pattern matching (relatively short shard channels).", 5 | "group": "pubsub", 6 | "since": "7.0.0", 7 | "arity": -2, 8 | "container": "PUBSUB", 9 | "function": "pubsubCommand", 10 | "command_flags": [ 11 | "PUBSUB", 12 | "LOADING", 13 | "STALE" 14 | ], 15 | "arguments": [ 16 | { 17 | "name": "pattern", 18 | "type": "pattern", 19 | "optional": true 20 | } 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /scripts/commands/pubsub-shardnumsub.json: -------------------------------------------------------------------------------- 1 | { 2 | "SHARDNUMSUB": { 3 | "summary": "Get the count of subscribers for shard channels", 4 | "complexity": "O(N) for the SHARDNUMSUB subcommand, where N is the number of requested shard channels", 5 | "group": "pubsub", 6 | "since": "7.0.0", 7 | "arity": -2, 8 | "container": "PUBSUB", 9 | "function": "pubsubCommand", 10 | "command_flags": [ 11 | "PUBSUB", 12 | "LOADING", 13 | "STALE" 14 | ], 15 | "arguments": [ 16 | { 17 | "name": "shardchannel", 18 | "type": "string", 19 | "optional": true, 20 | "multiple": true 21 | } 22 | ] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /scripts/commands/pubsub.json: -------------------------------------------------------------------------------- 1 | { 2 | "PUBSUB": { 3 | "summary": "A container for Pub/Sub commands", 4 | "complexity": "Depends on subcommand.", 5 | "group": "pubsub", 6 | "since": "2.8.0", 7 | "arity": -2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scripts/commands/punsubscribe.json: -------------------------------------------------------------------------------- 1 | { 2 | "PUNSUBSCRIBE": { 3 | "summary": "Stop listening for messages posted to channels matching the given patterns", 4 | "complexity": "O(N+M) where N is the number of patterns the client is already subscribed and M is the number of total patterns subscribed in the system (by any client).", 5 | "group": "pubsub", 6 | "since": "2.0.0", 7 | "arity": -1, 8 | "function": "punsubscribeCommand", 9 | "command_flags": [ 10 | "PUBSUB", 11 | "NOSCRIPT", 12 | "LOADING", 13 | "STALE", 14 | "SENTINEL" 15 | ], 16 | "arguments": [ 17 | { 18 | "name": "pattern", 19 | "type": "pattern", 20 | "optional": true, 21 | "multiple": true 22 | } 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /scripts/commands/quit.json: -------------------------------------------------------------------------------- 1 | { 2 | "QUIT": { 3 | "summary": "Close the connection", 4 | "complexity": "O(1)", 5 | "group": "connection", 6 | "since": "1.0.0", 7 | "arity": -1, 8 | "function": "quitCommand", 9 | "command_flags": [ 10 | "ALLOW_BUSY", 11 | "NOSCRIPT", 12 | "LOADING", 13 | "STALE", 14 | "FAST", 15 | "NO_AUTH" 16 | ], 17 | "acl_categories": [ 18 | "CONNECTION" 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scripts/commands/randomkey.json: -------------------------------------------------------------------------------- 1 | { 2 | "RANDOMKEY": { 3 | "summary": "Return a random key from the keyspace", 4 | "complexity": "O(1)", 5 | "group": "generic", 6 | "since": "1.0.0", 7 | "arity": 1, 8 | "function": "randomkeyCommand", 9 | "command_flags": [ 10 | "READONLY" 11 | ], 12 | "acl_categories": [ 13 | "KEYSPACE" 14 | ], 15 | "command_tips": [ 16 | "REQUEST_POLICY:ALL_SHARDS", 17 | "NONDETERMINISTIC_OUTPUT" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /scripts/commands/readonly.json: -------------------------------------------------------------------------------- 1 | { 2 | "READONLY": { 3 | "summary": "Enables read queries for a connection to a cluster replica node", 4 | "complexity": "O(1)", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 1, 8 | "function": "readonlyCommand", 9 | "command_flags": [ 10 | "FAST", 11 | "LOADING", 12 | "STALE" 13 | ], 14 | "acl_categories": [ 15 | "CONNECTION" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/readwrite.json: -------------------------------------------------------------------------------- 1 | { 2 | "READWRITE": { 3 | "summary": "Disables read queries for a connection to a cluster replica node", 4 | "complexity": "O(1)", 5 | "group": "cluster", 6 | "since": "3.0.0", 7 | "arity": 1, 8 | "function": "readwriteCommand", 9 | "command_flags": [ 10 | "FAST", 11 | "LOADING", 12 | "STALE" 13 | ], 14 | "acl_categories": [ 15 | "CONNECTION" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/replconf.json: -------------------------------------------------------------------------------- 1 | { 2 | "REPLCONF": { 3 | "summary": "An internal command for configuring the replication stream", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "3.0.0", 7 | "arity": -1, 8 | "function": "replconfCommand", 9 | "doc_flags": [ 10 | "SYSCMD" 11 | ], 12 | "command_flags": [ 13 | "ADMIN", 14 | "NOSCRIPT", 15 | "LOADING", 16 | "STALE", 17 | "ALLOW_BUSY" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /scripts/commands/replicaof.json: -------------------------------------------------------------------------------- 1 | { 2 | "REPLICAOF": { 3 | "summary": "Make the server a replica of another instance, or promote it as master.", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "5.0.0", 7 | "arity": 3, 8 | "function": "replicaofCommand", 9 | "command_flags": [ 10 | "NO_ASYNC_LOADING", 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "STALE" 14 | ], 15 | "arguments": [ 16 | { 17 | "name": "host", 18 | "type": "string" 19 | }, 20 | { 21 | "name": "port", 22 | "type": "integer" 23 | } 24 | ] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /scripts/commands/reset.json: -------------------------------------------------------------------------------- 1 | { 2 | "RESET": { 3 | "summary": "Reset the connection", 4 | "complexity": "O(1)", 5 | "group": "connection", 6 | "since": "6.2.0", 7 | "arity": 1, 8 | "function": "resetCommand", 9 | "command_flags": [ 10 | "NOSCRIPT", 11 | "LOADING", 12 | "STALE", 13 | "FAST", 14 | "NO_AUTH", 15 | "ALLOW_BUSY" 16 | ], 17 | "acl_categories": [ 18 | "CONNECTION" 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scripts/commands/role.json: -------------------------------------------------------------------------------- 1 | { 2 | "ROLE": { 3 | "summary": "Return the role of the instance in the context of replication", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "2.8.12", 7 | "arity": 1, 8 | "function": "roleCommand", 9 | "command_flags": [ 10 | "NOSCRIPT", 11 | "LOADING", 12 | "STALE", 13 | "FAST", 14 | "SENTINEL" 15 | ], 16 | "acl_categories": [ 17 | "ADMIN", 18 | "DANGEROUS" 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scripts/commands/save.json: -------------------------------------------------------------------------------- 1 | { 2 | "SAVE": { 3 | "summary": "Synchronously save the dataset to disk", 4 | "complexity": "O(N) where N is the total number of keys in all databases", 5 | "group": "server", 6 | "since": "1.0.0", 7 | "arity": 1, 8 | "function": "saveCommand", 9 | "command_flags": [ 10 | "NO_ASYNC_LOADING", 11 | "ADMIN", 12 | "NOSCRIPT", 13 | "NO_MULTI" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scripts/commands/scard.json: -------------------------------------------------------------------------------- 1 | { 2 | "SCARD": { 3 | "summary": "Get the number of members in a set", 4 | "complexity": "O(1)", 5 | "group": "set", 6 | "since": "1.0.0", 7 | "arity": 2, 8 | "function": "scardCommand", 9 | "command_flags": [ 10 | "READONLY", 11 | "FAST" 12 | ], 13 | "acl_categories": [ 14 | "SET" 15 | ], 16 | "key_specs": [ 17 | { 18 | "flags": [ 19 | "RO" 20 | ], 21 | "begin_search": { 22 | "index": { 23 | "pos": 1 24 | } 25 | }, 26 | "find_keys": { 27 | "range": { 28 | "lastkey": 0, 29 | "step": 1, 30 | "limit": 0 31 | } 32 | } 33 | } 34 | ], 35 | "arguments": [ 36 | { 37 | "name": "key", 38 | "type": "key", 39 | "key_spec_index": 0 40 | } 41 | ] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scripts/commands/script-debug.json: -------------------------------------------------------------------------------- 1 | { 2 | "DEBUG": { 3 | "summary": "Set the debug mode for executed scripts.", 4 | "complexity": "O(1)", 5 | "group": "scripting", 6 | "since": "3.2.0", 7 | "arity": 3, 8 | "container": "SCRIPT", 9 | "function": "scriptCommand", 10 | "command_flags": [ 11 | "NOSCRIPT" 12 | ], 13 | "acl_categories": [ 14 | "SCRIPTING" 15 | ], 16 | "arguments": [ 17 | { 18 | "name": "mode", 19 | "type": "oneof", 20 | "arguments": [ 21 | { 22 | "name": "yes", 23 | "type": "pure-token", 24 | "token": "YES" 25 | }, 26 | { 27 | "name": "sync", 28 | "type": "pure-token", 29 | "token": "SYNC" 30 | }, 31 | { 32 | "name": "no", 33 | "type": "pure-token", 34 | "token": "NO" 35 | } 36 | ] 37 | } 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /scripts/commands/script-exists.json: -------------------------------------------------------------------------------- 1 | { 2 | "EXISTS": { 3 | "summary": "Check existence of scripts in the script cache.", 4 | "complexity": "O(N) with N being the number of scripts to check (so checking a single script is an O(1) operation).", 5 | "group": "scripting", 6 | "since": "2.6.0", 7 | "arity": -3, 8 | "container": "SCRIPT", 9 | "function": "scriptCommand", 10 | "command_flags": [ 11 | "NOSCRIPT" 12 | ], 13 | "acl_categories": [ 14 | "SCRIPTING" 15 | ], 16 | "command_tips": [ 17 | "REQUEST_POLICY:ALL_SHARDS", 18 | "RESPONSE_POLICY:AGG_LOGICAL_AND" 19 | ], 20 | "arguments": [ 21 | { 22 | "name": "sha1", 23 | "type": "string", 24 | "multiple": true 25 | } 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scripts/commands/script-help.json: -------------------------------------------------------------------------------- 1 | { 2 | "HELP": { 3 | "summary": "Show helpful text about the different subcommands", 4 | "complexity": "O(1)", 5 | "group": "scripting", 6 | "since": "5.0.0", 7 | "arity": 2, 8 | "container": "SCRIPT", 9 | "function": "scriptCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ], 14 | "acl_categories": [ 15 | "SCRIPTING" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/script-kill.json: -------------------------------------------------------------------------------- 1 | { 2 | "KILL": { 3 | "summary": "Kill the script currently in execution.", 4 | "complexity": "O(1)", 5 | "group": "scripting", 6 | "since": "2.6.0", 7 | "arity": 2, 8 | "container": "SCRIPT", 9 | "function": "scriptCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "ALLOW_BUSY" 13 | ], 14 | "acl_categories": [ 15 | "SCRIPTING" 16 | ], 17 | "command_tips": [ 18 | "REQUEST_POLICY:ALL_SHARDS", 19 | "RESPONSE_POLICY:ONE_SUCCEEDED" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scripts/commands/script-load.json: -------------------------------------------------------------------------------- 1 | { 2 | "LOAD": { 3 | "summary": "Load the specified Lua script into the script cache.", 4 | "complexity": "O(N) with N being the length in bytes of the script body.", 5 | "group": "scripting", 6 | "since": "2.6.0", 7 | "arity": 3, 8 | "container": "SCRIPT", 9 | "function": "scriptCommand", 10 | "command_flags": [ 11 | "NOSCRIPT", 12 | "STALE" 13 | ], 14 | "acl_categories": [ 15 | "SCRIPTING" 16 | ], 17 | "command_tips": [ 18 | "REQUEST_POLICY:ALL_NODES", 19 | "RESPONSE_POLICY:ALL_SUCCEEDED" 20 | ], 21 | "arguments": [ 22 | { 23 | "name": "script", 24 | "type": "string" 25 | } 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scripts/commands/script.json: -------------------------------------------------------------------------------- 1 | { 2 | "SCRIPT": { 3 | "summary": "A container for Lua scripts management commands", 4 | "complexity": "Depends on subcommand.", 5 | "group": "scripting", 6 | "since": "2.6.0", 7 | "arity": -2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scripts/commands/select.json: -------------------------------------------------------------------------------- 1 | { 2 | "SELECT": { 3 | "summary": "Change the selected database for the current connection", 4 | "complexity": "O(1)", 5 | "group": "connection", 6 | "since": "1.0.0", 7 | "arity": 2, 8 | "function": "selectCommand", 9 | "command_flags": [ 10 | "LOADING", 11 | "STALE", 12 | "FAST" 13 | ], 14 | "acl_categories": [ 15 | "CONNECTION" 16 | ], 17 | "arguments": [ 18 | { 19 | "name": "index", 20 | "type": "integer" 21 | } 22 | ] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-ckquorum.json: -------------------------------------------------------------------------------- 1 | { 2 | "CKQUORUM": { 3 | "summary": "Check for a Sentinel quorum", 4 | "group": "sentinel", 5 | "since": "2.8.4", 6 | "arity": 3, 7 | "container": "SENTINEL", 8 | "function": "sentinelCommand", 9 | "command_flags": [ 10 | "ADMIN", 11 | "SENTINEL", 12 | "ONLY_SENTINEL" 13 | ], 14 | "arguments": [ 15 | { 16 | "name": "master-name", 17 | "type": "string" 18 | } 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-debug.json: -------------------------------------------------------------------------------- 1 | { 2 | "DEBUG": { 3 | "summary": "List or update the current configurable parameters", 4 | "complexity": "O(N) where N is the number of configurable parameters", 5 | "group": "sentinel", 6 | "since": "7.0.0", 7 | "arity": -2, 8 | "container": "SENTINEL", 9 | "function": "sentinelCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "SENTINEL", 13 | "ONLY_SENTINEL" 14 | ], 15 | "arguments": [ 16 | { 17 | "name": "parameter_value", 18 | "type": "block", 19 | "multiple": true, 20 | "arguments": [ 21 | { 22 | "name": "parameter", 23 | "type": "string" 24 | }, 25 | { 26 | "name": "value", 27 | "type": "string" 28 | } 29 | ] 30 | } 31 | ] 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-failover.json: -------------------------------------------------------------------------------- 1 | { 2 | "FAILOVER": { 3 | "summary": "Force a failover", 4 | "group": "sentinel", 5 | "since": "2.8.4", 6 | "arity": 3, 7 | "container": "SENTINEL", 8 | "function": "sentinelCommand", 9 | "command_flags": [ 10 | "ADMIN", 11 | "SENTINEL", 12 | "ONLY_SENTINEL" 13 | ], 14 | "arguments": [ 15 | { 16 | "name": "master-name", 17 | "type": "string" 18 | } 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-flushconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "FLUSHCONFIG": { 3 | "summary": "Rewrite configuration file", 4 | "complexity": "O(1)", 5 | "group": "sentinel", 6 | "since": "2.8.4", 7 | "arity": 2, 8 | "container": "SENTINEL", 9 | "function": "sentinelCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "SENTINEL", 13 | "ONLY_SENTINEL" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-get-master-addr-by-name.json: -------------------------------------------------------------------------------- 1 | { 2 | "GET-MASTER-ADDR-BY-NAME": { 3 | "summary": "Get port and address of a master", 4 | "complexity": "O(1)", 5 | "group": "sentinel", 6 | "since": "2.8.4", 7 | "arity": 3, 8 | "container": "SENTINEL", 9 | "function": "sentinelCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "SENTINEL", 13 | "ONLY_SENTINEL" 14 | ], 15 | "arguments": [ 16 | { 17 | "name": "master-name", 18 | "type": "string" 19 | } 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-help.json: -------------------------------------------------------------------------------- 1 | { 2 | "HELP": { 3 | "summary": "Show helpful text about the different subcommands", 4 | "complexity": "O(1)", 5 | "group": "sentinel", 6 | "since": "6.2.0", 7 | "arity": 2, 8 | "container": "SENTINEL", 9 | "function": "sentinelCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE", 13 | "SENTINEL", 14 | "ONLY_SENTINEL" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-info-cache.json: -------------------------------------------------------------------------------- 1 | { 2 | "INFO-CACHE": { 3 | "summary": "Get cached INFO from the instances in the deployment", 4 | "complexity": "O(N) where N is the number of instances", 5 | "group": "sentinel", 6 | "since": "3.2.0", 7 | "arity": -3, 8 | "container": "SENTINEL", 9 | "function": "sentinelCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "SENTINEL", 13 | "ONLY_SENTINEL" 14 | ], 15 | "arguments": [ 16 | { 17 | "name": "nodename", 18 | "type": "string", 19 | "multiple": true 20 | } 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-is-master-down-by-addr.json: -------------------------------------------------------------------------------- 1 | { 2 | "IS-MASTER-DOWN-BY-ADDR": { 3 | "summary": "Check if a master is down", 4 | "complexity": "O(1)", 5 | "group": "sentinel", 6 | "since": "2.8.4", 7 | "arity": 6, 8 | "container": "SENTINEL", 9 | "function": "sentinelCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "SENTINEL", 13 | "ONLY_SENTINEL" 14 | ], 15 | "arguments": [ 16 | { 17 | "name": "ip", 18 | "type": "string" 19 | }, 20 | { 21 | "name": "port", 22 | "type": "integer" 23 | }, 24 | { 25 | "name": "current-epoch", 26 | "type": "integer" 27 | }, 28 | { 29 | "name": "runid", 30 | "type": "string" 31 | } 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-master.json: -------------------------------------------------------------------------------- 1 | { 2 | "MASTER": { 3 | "summary": "Shows the state of a master", 4 | "complexity": "O(1)", 5 | "group": "sentinel", 6 | "since": "2.8.4", 7 | "arity": 3, 8 | "container": "SENTINEL", 9 | "function": "sentinelCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "SENTINEL", 13 | "ONLY_SENTINEL" 14 | ], 15 | "arguments": [ 16 | { 17 | "name": "master-name", 18 | "type": "string" 19 | } 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-masters.json: -------------------------------------------------------------------------------- 1 | { 2 | "MASTERS": { 3 | "summary": "List the monitored masters", 4 | "complexity": "O(N) where N is the number of masters", 5 | "group": "sentinel", 6 | "since": "2.8.4", 7 | "arity": 2, 8 | "container": "SENTINEL", 9 | "function": "sentinelCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "SENTINEL", 13 | "ONLY_SENTINEL" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-monitor.json: -------------------------------------------------------------------------------- 1 | { 2 | "MONITOR": { 3 | "summary": "Start monitoring", 4 | "complexity": "O(1)", 5 | "group": "sentinel", 6 | "since": "2.8.4", 7 | "arity": 6, 8 | "container": "SENTINEL", 9 | "function": "sentinelCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "SENTINEL", 13 | "ONLY_SENTINEL" 14 | ], 15 | "arguments": [ 16 | { 17 | "name": "name", 18 | "type": "string" 19 | }, 20 | { 21 | "name": "ip", 22 | "type": "string" 23 | }, 24 | { 25 | "name": "port", 26 | "type": "integer" 27 | }, 28 | { 29 | "name": "quorum", 30 | "type": "integer" 31 | } 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-myid.json: -------------------------------------------------------------------------------- 1 | { 2 | "MYID": { 3 | "summary": "Get the Sentinel instance ID", 4 | "complexity": "O(1)", 5 | "group": "sentinel", 6 | "since": "6.2.0", 7 | "arity": 2, 8 | "container": "SENTINEL", 9 | "function": "sentinelCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "SENTINEL", 13 | "ONLY_SENTINEL" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-pending-scripts.json: -------------------------------------------------------------------------------- 1 | { 2 | "PENDING-SCRIPTS": { 3 | "summary": "Get information about pending scripts", 4 | "group": "sentinel", 5 | "since": "2.8.4", 6 | "arity": 2, 7 | "container": "SENTINEL", 8 | "function": "sentinelCommand", 9 | "command_flags": [ 10 | "ADMIN", 11 | "SENTINEL", 12 | "ONLY_SENTINEL" 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-remove.json: -------------------------------------------------------------------------------- 1 | { 2 | "REMOVE": { 3 | "summary": "Stop monitoring", 4 | "complexity": "O(1)", 5 | "group": "sentinel", 6 | "since": "2.8.4", 7 | "arity": 3, 8 | "container": "SENTINEL", 9 | "function": "sentinelCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "SENTINEL", 13 | "ONLY_SENTINEL" 14 | ], 15 | "arguments": [ 16 | { 17 | "name": "master-name", 18 | "type": "string" 19 | } 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-replicas.json: -------------------------------------------------------------------------------- 1 | { 2 | "REPLICAS": { 3 | "summary": "List the monitored replicas", 4 | "complexity": "O(N) where N is the number of replicas", 5 | "group": "sentinel", 6 | "since": "5.0.0", 7 | "arity": 3, 8 | "container": "SENTINEL", 9 | "function": "sentinelCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "SENTINEL", 13 | "ONLY_SENTINEL" 14 | ], 15 | "arguments": [ 16 | { 17 | "name": "master-name", 18 | "type": "string" 19 | } 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-reset.json: -------------------------------------------------------------------------------- 1 | { 2 | "RESET": { 3 | "summary": "Reset masters by name pattern", 4 | "complexity": "O(N) where N is the number of monitored masters", 5 | "group": "sentinel", 6 | "since": "2.8.4", 7 | "arity": 3, 8 | "container": "SENTINEL", 9 | "function": "sentinelCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "SENTINEL", 13 | "ONLY_SENTINEL" 14 | ], 15 | "arguments": [ 16 | { 17 | "name": "pattern", 18 | "type": "pattern" 19 | } 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-sentinels.json: -------------------------------------------------------------------------------- 1 | { 2 | "SENTINELS": { 3 | "summary": "List the Sentinel instances", 4 | "complexity": "O(N) where N is the number of Sentinels", 5 | "group": "sentinel", 6 | "since": "2.8.4", 7 | "arity": 3, 8 | "container": "SENTINEL", 9 | "function": "sentinelCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "SENTINEL", 13 | "ONLY_SENTINEL" 14 | ], 15 | "arguments": [ 16 | { 17 | "name": "master-name", 18 | "type": "string" 19 | } 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-set.json: -------------------------------------------------------------------------------- 1 | { 2 | "SET": { 3 | "summary": "Change the configuration of a monitored master", 4 | "complexity": "O(1)", 5 | "group": "sentinel", 6 | "since": "2.8.4", 7 | "arity": -5, 8 | "container": "SENTINEL", 9 | "function": "sentinelCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "SENTINEL", 13 | "ONLY_SENTINEL" 14 | ], 15 | "arguments": [ 16 | { 17 | "name": "master-name", 18 | "type": "string" 19 | }, 20 | { 21 | "name": "option_value", 22 | "type": "block", 23 | "multiple": true, 24 | "arguments": [ 25 | { 26 | "name": "option", 27 | "type": "string" 28 | }, 29 | { 30 | "name": "value", 31 | "type": "string" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-simulate-failure.json: -------------------------------------------------------------------------------- 1 | { 2 | "SIMULATE-FAILURE": { 3 | "summary": "Simulate failover scenarios", 4 | "group": "sentinel", 5 | "since": "3.2.0", 6 | "arity": -3, 7 | "container": "SENTINEL", 8 | "function": "sentinelCommand", 9 | "command_flags": [ 10 | "ADMIN", 11 | "SENTINEL", 12 | "ONLY_SENTINEL" 13 | ], 14 | "arguments": [ 15 | { 16 | "name": "mode", 17 | "type": "oneof", 18 | "optional":true, 19 | "multiple":true, 20 | "arguments": [ 21 | { 22 | "name": "crash-after-election", 23 | "type": "pure-token" 24 | }, 25 | { 26 | "name": "crash-after-promotion", 27 | "type": "pure-token" 28 | }, 29 | { 30 | "name": "help", 31 | "type": "pure-token" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /scripts/commands/sentinel-slaves.json: -------------------------------------------------------------------------------- 1 | { 2 | "SLAVES": { 3 | "summary": "List the monitored slaves", 4 | "complexity": "O(N) where N is the number of slaves", 5 | "group": "sentinel", 6 | "since": "2.8.0", 7 | "arity": 3, 8 | "container": "SENTINEL", 9 | "function": "sentinelCommand", 10 | "deprecated_since": "5.0.0", 11 | "replaced_by": "`SENTINEL REPLICAS`", 12 | "doc_flags": [ 13 | "DEPRECATED" 14 | ], 15 | "command_flags": [ 16 | "ADMIN", 17 | "SENTINEL", 18 | "ONLY_SENTINEL" 19 | ], 20 | "arguments": [ 21 | { 22 | "name": "master-name", 23 | "type": "string" 24 | } 25 | ] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /scripts/commands/sentinel.json: -------------------------------------------------------------------------------- 1 | { 2 | "SENTINEL": { 3 | "summary": "A container for Sentinel commands", 4 | "complexity": "Depends on subcommand.", 5 | "group": "sentinel", 6 | "since": "2.8.4", 7 | "arity": -2, 8 | "command_flags": [ 9 | "ADMIN", 10 | "SENTINEL", 11 | "ONLY_SENTINEL" 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /scripts/commands/slaveof.json: -------------------------------------------------------------------------------- 1 | { 2 | "SLAVEOF": { 3 | "summary": "Make the server a replica of another instance, or promote it as master.", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "1.0.0", 7 | "arity": 3, 8 | "function": "replicaofCommand", 9 | "deprecated_since": "5.0.0", 10 | "replaced_by": "`REPLICAOF`", 11 | "doc_flags": [ 12 | "DEPRECATED" 13 | ], 14 | "command_flags": [ 15 | "NO_ASYNC_LOADING", 16 | "ADMIN", 17 | "NOSCRIPT", 18 | "STALE" 19 | ], 20 | "arguments": [ 21 | { 22 | "name": "host", 23 | "type": "string" 24 | }, 25 | { 26 | "name": "port", 27 | "type": "integer" 28 | } 29 | ] 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /scripts/commands/slowlog-get.json: -------------------------------------------------------------------------------- 1 | { 2 | "GET": { 3 | "summary": "Get the slow log's entries", 4 | "complexity": "O(N) where N is the number of entries returned", 5 | "group": "server", 6 | "since": "2.2.12", 7 | "arity": -2, 8 | "container": "SLOWLOG", 9 | "function": "slowlogCommand", 10 | "history": [ 11 | [ 12 | "4.0.0", 13 | "Added client IP address, port and name to the reply." 14 | ] 15 | ], 16 | "command_flags": [ 17 | "ADMIN", 18 | "LOADING", 19 | "STALE" 20 | ], 21 | "command_tips": [ 22 | "REQUEST_POLICY:ALL_NODES", 23 | "NONDETERMINISTIC_OUTPUT" 24 | ], 25 | "arguments": [ 26 | { 27 | "name": "count", 28 | "type": "integer", 29 | "optional": true 30 | } 31 | ] 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /scripts/commands/slowlog-help.json: -------------------------------------------------------------------------------- 1 | { 2 | "HELP": { 3 | "summary": "Show helpful text about the different subcommands", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "6.2.0", 7 | "arity": 2, 8 | "container": "SLOWLOG", 9 | "function": "slowlogCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /scripts/commands/slowlog-len.json: -------------------------------------------------------------------------------- 1 | { 2 | "LEN": { 3 | "summary": "Get the slow log's length", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "2.2.12", 7 | "arity": 2, 8 | "container": "SLOWLOG", 9 | "function": "slowlogCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "LOADING", 13 | "STALE" 14 | ], 15 | "command_tips": [ 16 | "REQUEST_POLICY:ALL_NODES", 17 | "RESPONSE_POLICY:AGG_SUM", 18 | "NONDETERMINISTIC_OUTPUT" 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scripts/commands/slowlog-reset.json: -------------------------------------------------------------------------------- 1 | { 2 | "RESET": { 3 | "summary": "Clear all entries from the slow log", 4 | "complexity": "O(N) where N is the number of entries in the slowlog", 5 | "group": "server", 6 | "since": "2.2.12", 7 | "arity": 2, 8 | "container": "SLOWLOG", 9 | "function": "slowlogCommand", 10 | "command_flags": [ 11 | "ADMIN", 12 | "LOADING", 13 | "STALE" 14 | ], 15 | "command_tips": [ 16 | "REQUEST_POLICY:ALL_NODES", 17 | "RESPONSE_POLICY:ALL_SUCCEEDED" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /scripts/commands/slowlog.json: -------------------------------------------------------------------------------- 1 | { 2 | "SLOWLOG": { 3 | "summary": "A container for slow log commands", 4 | "complexity": "Depends on subcommand.", 5 | "group": "server", 6 | "since": "2.2.12", 7 | "arity": -2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scripts/commands/ssubscribe.json: -------------------------------------------------------------------------------- 1 | { 2 | "SSUBSCRIBE": { 3 | "summary": "Listen for messages published to the given shard channels", 4 | "complexity": "O(N) where N is the number of shard channels to subscribe to.", 5 | "group": "pubsub", 6 | "since": "7.0.0", 7 | "arity": -2, 8 | "function": "ssubscribeCommand", 9 | "command_flags": [ 10 | "PUBSUB", 11 | "NOSCRIPT", 12 | "LOADING", 13 | "STALE" 14 | ], 15 | "arguments": [ 16 | { 17 | "name": "shardchannel", 18 | "type": "string", 19 | "multiple": true 20 | } 21 | ], 22 | "key_specs": [ 23 | { 24 | "flags": [ 25 | "NOT_KEY" 26 | ], 27 | "begin_search": { 28 | "index": { 29 | "pos": 1 30 | } 31 | }, 32 | "find_keys": { 33 | "range": { 34 | "lastkey": -1, 35 | "step": 1, 36 | "limit": 0 37 | } 38 | } 39 | } 40 | ] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /scripts/commands/strlen.json: -------------------------------------------------------------------------------- 1 | { 2 | "STRLEN": { 3 | "summary": "Get the length of the value stored in a key", 4 | "complexity": "O(1)", 5 | "group": "string", 6 | "since": "2.2.0", 7 | "arity": 2, 8 | "function": "strlenCommand", 9 | "command_flags": [ 10 | "READONLY", 11 | "FAST" 12 | ], 13 | "acl_categories": [ 14 | "STRING" 15 | ], 16 | "key_specs": [ 17 | { 18 | "flags": [ 19 | "RO" 20 | ], 21 | "begin_search": { 22 | "index": { 23 | "pos": 1 24 | } 25 | }, 26 | "find_keys": { 27 | "range": { 28 | "lastkey": 0, 29 | "step": 1, 30 | "limit": 0 31 | } 32 | } 33 | } 34 | ], 35 | "arguments": [ 36 | { 37 | "name": "key", 38 | "type": "key", 39 | "key_spec_index": 0 40 | } 41 | ] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scripts/commands/subscribe.json: -------------------------------------------------------------------------------- 1 | { 2 | "SUBSCRIBE": { 3 | "summary": "Listen for messages published to the given channels", 4 | "complexity": "O(N) where N is the number of channels to subscribe to.", 5 | "group": "pubsub", 6 | "since": "2.0.0", 7 | "arity": -2, 8 | "function": "subscribeCommand", 9 | "history": [], 10 | "command_flags": [ 11 | "PUBSUB", 12 | "NOSCRIPT", 13 | "LOADING", 14 | "STALE", 15 | "SENTINEL" 16 | ], 17 | "arguments": [ 18 | { 19 | "name": "channel", 20 | "type": "string", 21 | "multiple": true 22 | } 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /scripts/commands/swapdb.json: -------------------------------------------------------------------------------- 1 | { 2 | "SWAPDB": { 3 | "summary": "Swaps two Redis databases", 4 | "complexity": "O(N) where N is the count of clients watching or blocking on keys from both databases.", 5 | "group": "server", 6 | "since": "4.0.0", 7 | "arity": 3, 8 | "function": "swapdbCommand", 9 | "command_flags": [ 10 | "WRITE", 11 | "FAST" 12 | ], 13 | "acl_categories": [ 14 | "KEYSPACE", 15 | "DANGEROUS" 16 | ], 17 | "arguments": [ 18 | { 19 | "name": "index1", 20 | "type": "integer" 21 | }, 22 | { 23 | "name": "index2", 24 | "type": "integer" 25 | } 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scripts/commands/sync.json: -------------------------------------------------------------------------------- 1 | { 2 | "SYNC": { 3 | "summary": "Internal command used for replication", 4 | "group": "server", 5 | "since": "1.0.0", 6 | "arity": 1, 7 | "function": "syncCommand", 8 | "command_flags": [ 9 | "NO_ASYNC_LOADING", 10 | "ADMIN", 11 | "NO_MULTI", 12 | "NOSCRIPT" 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /scripts/commands/time.json: -------------------------------------------------------------------------------- 1 | { 2 | "TIME": { 3 | "summary": "Return the current server time", 4 | "complexity": "O(1)", 5 | "group": "server", 6 | "since": "2.6.0", 7 | "arity": 1, 8 | "function": "timeCommand", 9 | "command_flags": [ 10 | "LOADING", 11 | "STALE", 12 | "FAST" 13 | ], 14 | "command_tips": [ 15 | "NONDETERMINISTIC_OUTPUT" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/type.json: -------------------------------------------------------------------------------- 1 | { 2 | "TYPE": { 3 | "summary": "Determine the type stored at key", 4 | "complexity": "O(1)", 5 | "group": "generic", 6 | "since": "1.0.0", 7 | "arity": 2, 8 | "function": "typeCommand", 9 | "command_flags": [ 10 | "READONLY", 11 | "FAST" 12 | ], 13 | "acl_categories": [ 14 | "KEYSPACE" 15 | ], 16 | "key_specs": [ 17 | { 18 | "flags": [ 19 | "RO" 20 | ], 21 | "begin_search": { 22 | "index": { 23 | "pos": 1 24 | } 25 | }, 26 | "find_keys": { 27 | "range": { 28 | "lastkey": 0, 29 | "step": 1, 30 | "limit": 0 31 | } 32 | } 33 | } 34 | ], 35 | "arguments": [ 36 | { 37 | "name": "key", 38 | "type": "key", 39 | "key_spec_index": 0 40 | } 41 | ] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scripts/commands/unsubscribe.json: -------------------------------------------------------------------------------- 1 | { 2 | "UNSUBSCRIBE": { 3 | "summary": "Stop listening for messages posted to the given channels", 4 | "complexity": "O(N) where N is the number of clients already subscribed to a channel.", 5 | "group": "pubsub", 6 | "since": "2.0.0", 7 | "arity": -1, 8 | "function": "unsubscribeCommand", 9 | "command_flags": [ 10 | "PUBSUB", 11 | "NOSCRIPT", 12 | "LOADING", 13 | "STALE", 14 | "SENTINEL" 15 | ], 16 | "arguments": [ 17 | { 18 | "name": "channel", 19 | "type": "string", 20 | "optional": true, 21 | "multiple": true 22 | } 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /scripts/commands/unwatch.json: -------------------------------------------------------------------------------- 1 | { 2 | "UNWATCH": { 3 | "summary": "Forget about all watched keys", 4 | "complexity": "O(1)", 5 | "group": "transactions", 6 | "since": "2.2.0", 7 | "arity": 1, 8 | "function": "unwatchCommand", 9 | "command_flags": [ 10 | "NOSCRIPT", 11 | "LOADING", 12 | "STALE", 13 | "FAST", 14 | "ALLOW_BUSY" 15 | ], 16 | "acl_categories": [ 17 | "TRANSACTION" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /scripts/commands/wait.json: -------------------------------------------------------------------------------- 1 | { 2 | "WAIT": { 3 | "summary": "Wait for the synchronous replication of all the write commands sent in the context of the current connection", 4 | "complexity": "O(1)", 5 | "group": "generic", 6 | "since": "3.0.0", 7 | "arity": 3, 8 | "function": "waitCommand", 9 | "command_flags": [ 10 | "NOSCRIPT" 11 | ], 12 | "acl_categories": [ 13 | "CONNECTION" 14 | ], 15 | "command_tips": [ 16 | "REQUEST_POLICY:ALL_SHARDS", 17 | "RESPONSE_POLICY:AGG_MIN" 18 | ], 19 | "arguments": [ 20 | { 21 | "name": "numreplicas", 22 | "type": "integer" 23 | }, 24 | { 25 | "name": "timeout", 26 | "type": "integer" 27 | } 28 | ] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /scripts/commands/xgroup-help.json: -------------------------------------------------------------------------------- 1 | { 2 | "HELP": { 3 | "summary": "Show helpful text about the different subcommands", 4 | "complexity": "O(1)", 5 | "group": "stream", 6 | "since": "5.0.0", 7 | "arity": 2, 8 | "container": "XGROUP", 9 | "function": "xgroupCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ], 14 | "acl_categories": [ 15 | "STREAM" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/xgroup.json: -------------------------------------------------------------------------------- 1 | { 2 | "XGROUP": { 3 | "summary": "A container for consumer groups commands", 4 | "complexity": "Depends on subcommand.", 5 | "group": "stream", 6 | "since": "5.0.0", 7 | "arity": -2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scripts/commands/xinfo-help.json: -------------------------------------------------------------------------------- 1 | { 2 | "HELP": { 3 | "summary": "Show helpful text about the different subcommands", 4 | "complexity": "O(1)", 5 | "group": "stream", 6 | "since": "5.0.0", 7 | "arity": 2, 8 | "container": "XINFO", 9 | "function": "xinfoCommand", 10 | "command_flags": [ 11 | "LOADING", 12 | "STALE" 13 | ], 14 | "acl_categories": [ 15 | "STREAM" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/commands/xinfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "XINFO": { 3 | "summary": "A container for stream introspection commands", 4 | "complexity": "Depends on subcommand.", 5 | "group": "stream", 6 | "since": "5.0.0", 7 | "arity": -2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scripts/commands/xlen.json: -------------------------------------------------------------------------------- 1 | { 2 | "XLEN": { 3 | "summary": "Return the number of entries in a stream", 4 | "complexity": "O(1)", 5 | "group": "stream", 6 | "since": "5.0.0", 7 | "arity": 2, 8 | "function": "xlenCommand", 9 | "command_flags": [ 10 | "READONLY", 11 | "FAST" 12 | ], 13 | "acl_categories": [ 14 | "STREAM" 15 | ], 16 | "key_specs": [ 17 | { 18 | "flags": [ 19 | "RO" 20 | ], 21 | "begin_search": { 22 | "index": { 23 | "pos": 1 24 | } 25 | }, 26 | "find_keys": { 27 | "range": { 28 | "lastkey": 0, 29 | "step": 1, 30 | "limit": 0 31 | } 32 | } 33 | } 34 | ], 35 | "arguments": [ 36 | { 37 | "name": "key", 38 | "type": "key", 39 | "key_spec_index": 0 40 | } 41 | ] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scripts/commands/zcard.json: -------------------------------------------------------------------------------- 1 | { 2 | "ZCARD": { 3 | "summary": "Get the number of members in a sorted set", 4 | "complexity": "O(1)", 5 | "group": "sorted_set", 6 | "since": "1.2.0", 7 | "arity": 2, 8 | "function": "zcardCommand", 9 | "command_flags": [ 10 | "READONLY", 11 | "FAST" 12 | ], 13 | "acl_categories": [ 14 | "SORTEDSET" 15 | ], 16 | "key_specs": [ 17 | { 18 | "flags": [ 19 | "RO" 20 | ], 21 | "begin_search": { 22 | "index": { 23 | "pos": 1 24 | } 25 | }, 26 | "find_keys": { 27 | "range": { 28 | "lastkey": 0, 29 | "step": 1, 30 | "limit": 0 31 | } 32 | } 33 | } 34 | ], 35 | "arguments": [ 36 | { 37 | "name": "key", 38 | "type": "key", 39 | "key_spec_index": 0 40 | } 41 | ] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scripts/gen_table_json_from_commands.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | 4 | commands_dir = "./commands" 5 | files = os.listdir(commands_dir) 6 | table = {} 7 | container = set() 8 | files = sorted(files) 9 | for file in files: 10 | content = json.load(open(f"{commands_dir}/{file}")) 11 | for cmd_name, j in content.items(): 12 | print(cmd_name) 13 | if cmd_name in ("SORT", "SORT_RO", "MIGRATE"): 14 | continue 15 | 16 | group = j["group"] 17 | key_specs = [] 18 | if "key_specs" in j: 19 | for key_spec in j["key_specs"]: 20 | begin_search = key_spec["begin_search"] 21 | find_keys = key_spec["find_keys"] 22 | key_specs.append({ 23 | "begin_search": begin_search, 24 | "find_keys": find_keys 25 | }) 26 | if "container" in j: 27 | cmd_name = j["container"] + "-" + cmd_name 28 | container.add(j["container"]) 29 | 30 | if group not in table: 31 | table[group] = {} 32 | table[group][cmd_name] = key_specs 33 | 34 | container = sorted(container) 35 | with open("table.json", "w") as f: 36 | json.dump({ 37 | "table": table, 38 | "container": list(container) 39 | }, f, indent=4) 40 | -------------------------------------------------------------------------------- /shake_scan_env.toml: -------------------------------------------------------------------------------- 1 | [scan_reader] 2 | address = "${SHAKE_SRC_ADDRESS}" # export SHAKE_SRC_ADDRESS=127.0.0.1:6379 3 | 4 | [redis_writer] 5 | address = "${SHAKE_DST_ADDRESS}" # export SHAKE_DST_ADDRESS=127.0.0.1:6380 6 | -------------------------------------------------------------------------------- /shake_sync_env.toml: -------------------------------------------------------------------------------- 1 | [sync_reader] 2 | address = "${SHAKE_SRC_ADDRESS}" # export SHAKE_SRC_ADDRESS=127.0.0.1:6379 3 | 4 | [redis_writer] 5 | address = "${SHAKE_DST_ADDRESS}" # export SHAKE_DST_ADDRESS=127.0.0.1:6380 6 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # unit test 5 | go test ./... -v 6 | 7 | # black box test 8 | cd tests/ 9 | pybbt cases --verbose --flags modules -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | .pytest_cache 2 | __pycache__ 3 | tmp 4 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | 本项目使用 pybbt 工具进行黑盒测试。pybbt 是一个基于 Python 的工具,简化了软件的黑盒测试过程。要运行测试用例,请执行以下命令: 2 | 3 | ```bash 4 | pybbt cases --verbose --flags modules 5 | ``` 6 | 该命令将以详细日志记录的方式运行 cases 目录中的测试用例,并向测试用例传递 modules 标志。 7 | 8 | 如果本地没有安装 modules,可以不起用 modules 标志,这样就会跳过需要 modules 的测试用例: 9 | ```bash 10 | pybbt cases --verbose 11 | ``` 12 | 13 | 更多关于 pybbt 的信息、安装说明和用法示例,请参阅完整的文档: https://pypi.org/project/pybbt/ -------------------------------------------------------------------------------- /tests/cases/rdb.py: -------------------------------------------------------------------------------- 1 | import pybbt as p 2 | 3 | import helpers as h 4 | 5 | 6 | def test(src, dst): 7 | cross_slots_cmd = not (src.is_cluster() or dst.is_cluster()) 8 | inserter = h.DataInserter() 9 | inserter.add_data(src, cross_slots_cmd=cross_slots_cmd) 10 | p.ASSERT_TRUE(src.do("save")) 11 | 12 | opts = h.ShakeOpts.create_rdb_opts(f"{src.dir}/dump.rdb", dst) 13 | p.log(f"opts: {opts}") 14 | h.Shake.run_once(opts) 15 | 16 | # check data 17 | inserter.check_data(src, cross_slots_cmd=cross_slots_cmd) 18 | inserter.check_data(dst, cross_slots_cmd=cross_slots_cmd) 19 | p.ASSERT_EQ(src.dbsize(), dst.dbsize()) 20 | 21 | 22 | @p.subcase() 23 | def rdb_to_standalone(): 24 | src = h.Redis() 25 | dst = h.Redis() 26 | test(src, dst) 27 | 28 | 29 | @p.subcase() 30 | def rdb_to_cluster(): 31 | if h.REDIS_SERVER_VERSION < 3.0: 32 | return 33 | src = h.Redis() 34 | dst = h.Cluster() 35 | test(src, dst) 36 | 37 | 38 | @p.case(tags=["sync"]) 39 | def main(): 40 | rdb_to_standalone() 41 | rdb_to_cluster() 42 | 43 | 44 | if __name__ == '__main__': 45 | main() 46 | -------------------------------------------------------------------------------- /tests/helpers/__init__.py: -------------------------------------------------------------------------------- 1 | from .cluster import Cluster 2 | from .constant import REDIS_SERVER_VERSION 3 | from .data_inserter import DataInserter 4 | from .redis import Redis 5 | from .shake import Shake, ShakeOpts 6 | -------------------------------------------------------------------------------- /tests/helpers/commands/__init__.py: -------------------------------------------------------------------------------- 1 | from .select import SelectChecker 2 | from .string import StringChecker 3 | from .tair_string import TairStringChecker 4 | from .tair_hash import TairHashChecker 5 | from .tair_zset import TairZsetChecker -------------------------------------------------------------------------------- /tests/helpers/commands/checker.py: -------------------------------------------------------------------------------- 1 | from helpers.redis import Redis 2 | 3 | 4 | class Checker: 5 | def add_data(self, r: Redis, cross_slots_cmd: bool): 6 | ... 7 | 8 | def check_data(self, r: Redis, cross_slots_cmd: bool): 9 | ... 10 | -------------------------------------------------------------------------------- /tests/helpers/commands/list.py: -------------------------------------------------------------------------------- 1 | import pybbt 2 | 3 | from helpers.commands.checker import Checker 4 | from helpers.redis import Redis 5 | 6 | 7 | class ListChecker(Checker): 8 | PREFIX = "list" 9 | 10 | def __init__(self): 11 | self.cnt = 0 12 | 13 | def add_data(self, r: Redis, cross_slots_cmd: bool): 14 | p = r.pipeline() 15 | p.lpush(f"{self.PREFIX}_{self.cnt}_list", 0) 16 | p.lpush(f"{self.PREFIX}_{self.cnt}_list", 1) 17 | p.lpush(f"{self.PREFIX}_{self.cnt}_list", 2) 18 | p.lpush(f"{self.PREFIX}_{self.cnt}_list_str", "string0") 19 | p.lpush(f"{self.PREFIX}_{self.cnt}_list_str", "string1") 20 | p.lpush(f"{self.PREFIX}_{self.cnt}_list_str", "string2") 21 | ret = p.execute() 22 | pybbt.ASSERT_EQ(ret, [1, 2, 3, 1, 2, 3]) 23 | self.cnt += 1 24 | 25 | def check_data(self, r: Redis, cross_slots_cmd: bool): 26 | for i in range(self.cnt): 27 | p = r.pipeline() 28 | p.lrange(f"{self.PREFIX}_{i}_list", 0, -1) 29 | p.lrange(f"{self.PREFIX}_{i}_list_str", 0, -1) 30 | ret = p.execute() 31 | pybbt.ASSERT_EQ(ret, [[b"2", b"1", b"0"], [b"string2", b"string1", b"string0"]]) 32 | -------------------------------------------------------------------------------- /tests/helpers/commands/string.py: -------------------------------------------------------------------------------- 1 | import pybbt 2 | 3 | from helpers.commands.checker import Checker 4 | from helpers.redis import Redis 5 | 6 | 7 | class StringChecker(Checker): 8 | PREFIX = "string" 9 | 10 | def __init__(self): 11 | self.cnt = 0 12 | 13 | def add_data(self, r: Redis, cross_slots_cmd: bool): 14 | p = r.pipeline() 15 | p.set(f"{self.PREFIX}_{self.cnt}_str", "string") 16 | p.set(f"{self.PREFIX}_{self.cnt}_int", 0) 17 | p.set(f"{self.PREFIX}_{self.cnt}_int0", -1) 18 | p.set(f"{self.PREFIX}_{self.cnt}_int1", 123456789) 19 | ret = p.execute() 20 | pybbt.ASSERT_EQ(ret, [True, True, True, True]) 21 | self.cnt += 1 22 | 23 | def check_data(self, r: Redis, cross_slots_cmd: bool): 24 | for i in range(self.cnt): 25 | p = r.pipeline() 26 | p.get(f"{self.PREFIX}_{i}_str") 27 | p.get(f"{self.PREFIX}_{i}_int") 28 | p.get(f"{self.PREFIX}_{i}_int0") 29 | p.get(f"{self.PREFIX}_{i}_int1") 30 | ret = p.execute() 31 | pybbt.ASSERT_EQ(ret, [b"string", b"0", b"-1", b"123456789"]) 32 | -------------------------------------------------------------------------------- /tests/helpers/constant.py: -------------------------------------------------------------------------------- 1 | import shutil 2 | import subprocess 3 | from pathlib import Path 4 | 5 | import pybbt 6 | 7 | BASE_PATH = f"{Path(__file__).parent.parent.parent.absolute()}" # project path 8 | PATH_REDIS_SHAKE = f"{BASE_PATH}/bin/redis-shake" 9 | PATH_REDIS_SERVER = shutil.which('redis-server') 10 | output = subprocess.check_output(f"{PATH_REDIS_SERVER} --version", shell=True) 11 | output_str = output.decode("utf-8") 12 | REDIS_SERVER_VERSION = float(output_str.split("=")[1].split(" ")[0][:3]) 13 | 14 | # REDIS_SERVER_MODULES_ENABLED 15 | REDIS_SERVER_MODULES_ENABLED = REDIS_SERVER_VERSION >= 5.0 and "modules" in pybbt.get_global_flags() 16 | 17 | if __name__ == '__main__': 18 | print(BASE_PATH) 19 | print(PATH_REDIS_SHAKE) 20 | print(PATH_REDIS_SERVER) 21 | print(REDIS_SERVER_VERSION) 22 | -------------------------------------------------------------------------------- /tests/helpers/data_inserter.py: -------------------------------------------------------------------------------- 1 | from helpers.commands import SelectChecker, StringChecker, TairHashChecker, TairStringChecker, TairZsetChecker 2 | from helpers.redis import Redis 3 | 4 | 5 | class DataInserter: 6 | def __init__(self, ): 7 | self.checkers = [ 8 | StringChecker(), 9 | SelectChecker(), 10 | TairStringChecker(), 11 | TairHashChecker(), 12 | TairZsetChecker(), 13 | ] 14 | 15 | def add_data(self, r: Redis, cross_slots_cmd: bool): 16 | for checker in self.checkers: 17 | checker.add_data(r, cross_slots_cmd) 18 | 19 | def check_data(self, r: Redis, cross_slots_cmd: bool): 20 | for checker in self.checkers: 21 | checker.check_data(r, cross_slots_cmd) 22 | -------------------------------------------------------------------------------- /tests/helpers/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tair-opensource/RedisShake/bbca45b9de86fa337f5173b8927580a6b92f95a1/tests/helpers/utils/__init__.py -------------------------------------------------------------------------------- /tests/helpers/utils/filesystem.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | 4 | 5 | def file_size(file): 6 | return os.stat(file).st_size 7 | 8 | 9 | def file_truncate(file, size): 10 | with open(file, "rb+") as f: 11 | content = f.read() 12 | f.truncate(size) 13 | return content[size:] 14 | 15 | 16 | def file_append(file, content): 17 | with open(file, "ab") as f: 18 | f.write(content) 19 | 20 | 21 | def create_empty_dir(path): 22 | if os.path.exists(path): 23 | shutil.rmtree(path) 24 | os.makedirs(path) 25 | 26 | -------------------------------------------------------------------------------- /tests/helpers/utils/network.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import threading 3 | 4 | 5 | def is_port_available(port: int) -> bool: 6 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 7 | try: 8 | s.bind(('0.0.0.0', port)) 9 | return True 10 | except OSError: 11 | return False 12 | 13 | 14 | MIN_PORT = 1000 15 | MAX_PORT = 40000 16 | 17 | port_cursor = MIN_PORT 18 | 19 | g_lock = threading.Lock() 20 | 21 | 22 | def get_free_port(): 23 | global port_cursor 24 | global g_lock 25 | with g_lock: 26 | while True: 27 | port_cursor += 1 28 | if port_cursor == MAX_PORT: 29 | port_cursor = MIN_PORT 30 | 31 | if is_port_available(port_cursor): 32 | return port_cursor 33 | 34 | 35 | __all__ = [ 36 | "is_port_available", 37 | "get_free_port", 38 | ] 39 | 40 | if __name__ == '__main__': 41 | # test 42 | for i in range(10): 43 | print(get_free_port()) 44 | -------------------------------------------------------------------------------- /tests/helpers/utils/rand.py: -------------------------------------------------------------------------------- 1 | import random 2 | import string 3 | 4 | 5 | def random_string(length=8) -> str: 6 | chars = string.ascii_letters + string.digits 7 | random_str = ''.join(random.choices(chars, k=length)) 8 | return random_str 9 | -------------------------------------------------------------------------------- /tests/helpers/utils/timer.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | 4 | class Timer: 5 | def __init__(self): 6 | self.start_time = time.perf_counter() 7 | 8 | def elapsed(self): 9 | return time.perf_counter() - self.start_time 10 | -------------------------------------------------------------------------------- /tests/requirements.txt: -------------------------------------------------------------------------------- 1 | requests>=2.31.0 2 | toml>=0.10.2 3 | pybbt>=1.0.1 4 | redis>=4.5.4 5 | --------------------------------------------------------------------------------