From 7fa685ef79873fe362df7d6618664e37099023ca Mon Sep 17 00:00:00 2001 From: Ian Webster Date: Wed, 13 Jul 2022 11:13:41 -0700 Subject: [PATCH 001/377] Fix link to eviction policy docs (#2040) --- docs/getting-started/faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/faq.md b/docs/getting-started/faq.md index c9183b14c8..9ee1d55c83 100644 --- a/docs/getting-started/faq.md +++ b/docs/getting-started/faq.md @@ -77,7 +77,7 @@ with an error to write commands (but will continue to accept read-only commands). You can also configure Redis to evict keys when the max memory limit -is reached. See the [eviction policy docs] for more information on this. +is reached. See the [eviction policy docs](/docs/manual/eviction/) for more information on this. ## Background saving fails with a fork() error on Linux? From 8861b78ebe30a2a5bf8010810e90d13540a1d32a Mon Sep 17 00:00:00 2001 From: Huang Zhw Date: Sat, 23 Jul 2022 22:26:48 +0800 Subject: [PATCH 002/377] fix typo and url of Code of Conduct. (#2053) --- community/index.md | 2 +- docs/reference/optimization/latency-monitor.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/community/index.md b/community/index.md index 659e24b9c3..f496a29bd4 100644 --- a/community/index.md +++ b/community/index.md @@ -7,7 +7,7 @@ Since 2009, the Redis open source project has inspired an enthusiastic and activ ## Code of Conduct -Redis has adopted the [Contributor Covenant Code of Conduct](https://github.com/redis/redis/blob/unstable/CONDUCT). +Redis has adopted the [Contributor Covenant Code of Conduct](https://github.com/redis/redis/blob/unstable/CODE_OF_CONDUCT.md). ## Getting help diff --git a/docs/reference/optimization/latency-monitor.md b/docs/reference/optimization/latency-monitor.md index 204b695e11..6426abd617 100644 --- a/docs/reference/optimization/latency-monitor.md +++ b/docs/reference/optimization/latency-monitor.md @@ -55,7 +55,7 @@ event. This is how the time series work: * Every time a latency spike happens, it is logged in the appropriate time series. * Every time series is composed of 160 elements. * Each element is a pair made of a Unix timestamp of the time the latency spike was measured and the number of milliseconds the event took to execute. -* Latency spikes for the same event that occur in the same second are merged by taking the maximum latency. Even if continuous latency spikes are measured for a given event, which could happen with a low threshold, at least 180 seconds of history are available. +* Latency spikes for the same event that occur in the same second are merged by taking the maximum latency. Even if continuous latency spikes are measured for a given event, which could happen with a low threshold, at least 160 seconds of history are available. * Records the all-time maximum latency for every element. The framework monitors and logs latency spikes in the execution time of these events: From 43bcaa4ca8b5050206aa0df3db2b82e324bc5606 Mon Sep 17 00:00:00 2001 From: Luca Cillario Date: Wed, 3 Aug 2022 17:27:33 +0200 Subject: [PATCH 003/377] Update indexes.md (#2063) Fixed multi dimensional indexes miscalculation. --- docs/reference/patterns/indexes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/patterns/indexes.md b/docs/reference/patterns/indexes.md index cffd413220..be0363002c 100644 --- a/docs/reference/patterns/indexes.md +++ b/docs/reference/patterns/indexes.md @@ -625,7 +625,7 @@ So by interleaving digits, our representation in the index would be: Let's see what are our ranges as we substitute the last 2, 4, 6, 8, ... bits with 0s ad 1s in the interleaved representation: - 2 bits: x between 70 and 75, y between 200 and 201 (range=2) + 2 bits: x between 74 and 75, y between 200 and 201 (range=2) 4 bits: x between 72 and 75, y between 200 and 203 (range=4) 6 bits: x between 72 and 79, y between 200 and 207 (range=8) 8 bits: x between 64 and 79, y between 192 and 207 (range=16) From 434ff78d76127aae3d1508dd8b2852b83c5635af Mon Sep 17 00:00:00 2001 From: Joe Date: Wed, 3 Aug 2022 23:43:22 +0800 Subject: [PATCH 004/377] Fix `ssubscribe` examples (#2064) --- commands/ssubscribe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/ssubscribe.md b/commands/ssubscribe.md index c628b8e2d4..bf7d30e859 100644 --- a/commands/ssubscribe.md +++ b/commands/ssubscribe.md @@ -15,7 +15,7 @@ Reading messages... (press Ctrl-C to quit) 1) "ssubscribe" 2) "orders" 3) (integer) 1 -1) "message" +1) "smessage" 2) "orders" 3) "hello" ``` From 21b838f2a77f49e3856cde439375f21cddd12e6b Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Thu, 4 Aug 2022 19:36:09 +0300 Subject: [PATCH 005/377] Documents dangling PEL entries in XREADGROUP (#2067) --- commands/xreadgroup.md | 27 +++++++++++++++++++++++++++ wordlist | 1 + 2 files changed, 28 insertions(+) diff --git a/commands/xreadgroup.md b/commands/xreadgroup.md index c597b68bb5..4b516e532a 100644 --- a/commands/xreadgroup.md +++ b/commands/xreadgroup.md @@ -102,6 +102,33 @@ consumers that are processing new things. To see how the command actually replies, please check the `XREAD` command page. +## What happens when a pending message is deleted? + +Entries may be deleted from the stream due to trimming or explicit calls to `XDEL` at any time. +By design, Redis doesn't prevent the deletion of entries that are present in the stream's PELs. +When this happens, the PELs retain the deleted entries' IDs, but the actual entry payload is no longer available. +Therefore, when reading such PEL entries, Redis will return a null value in place of their respective data. + +Example: + +``` +> XADD mystream 1 myfield mydata +"1-0" +> XGROUP CREATE mystream mygroup 0 +OK +> XREADGROUP GROUP mygroup myconsumer STREAMS STREAMS mystream > +1) 1) "mystream" + 2) 1) 1) "1-0" + 2) 1) "myfield" + 2) "mydata" +> XDEL mystream 1-0 +(integer) 1 +> XREADGROUP GROUP mygroup myconsumer STREAMS STREAMS mystream 0 +1) 1) "mystream" + 2) 1) 1) "1-0" + 2) (nil) +``` + @return @array-reply, specifically: diff --git a/wordlist b/wordlist index a9aabaea5a..3a9c4a7874 100644 --- a/wordlist +++ b/wordlist @@ -235,6 +235,7 @@ OpenBSD OpenSSL Opteron PEL +PELs PEM PFAIL PHPRedisMutex From d84077ef3a8ac58c5b9d08b3e00efdaac058ee24 Mon Sep 17 00:00:00 2001 From: Kyle Banker Date: Fri, 5 Aug 2022 12:08:03 -0600 Subject: [PATCH 006/377] New data types pages (#2046) Co-authored-by: Nermina Miller <102551568+nermiller@users.noreply.github.com> Co-authored-by: Itamar Haber --- docs/about/_index.md | 8 +- docs/data-types/_index.md | 109 ++++++++++++ docs/data-types/bitfields.md | 54 ++++++ docs/data-types/bitmaps.md | 57 +++++++ docs/data-types/geospatial.md | 47 ++++++ docs/data-types/hashes.md | 73 +++++++++ docs/data-types/hyperloglogs.md | 51 ++++++ docs/data-types/lists.md | 111 +++++++++++++ docs/data-types/sets.md | 83 ++++++++++ docs/data-types/sorted-sets.md | 77 +++++++++ .../streams-tutorial.md} | 21 +-- docs/data-types/streams.md | 81 +++++++++ docs/data-types/strings.md | 76 +++++++++ .../tutorial.md} | 37 +---- docs/manual/data-types/_index.md | 155 ------------------ wordlist | 23 ++- 16 files changed, 858 insertions(+), 205 deletions(-) create mode 100644 docs/data-types/_index.md create mode 100644 docs/data-types/bitfields.md create mode 100644 docs/data-types/bitmaps.md create mode 100644 docs/data-types/geospatial.md create mode 100644 docs/data-types/hashes.md create mode 100644 docs/data-types/hyperloglogs.md create mode 100644 docs/data-types/lists.md create mode 100644 docs/data-types/sets.md create mode 100644 docs/data-types/sorted-sets.md rename docs/{manual/data-types/streams.md => data-types/streams-tutorial.md} (95%) create mode 100644 docs/data-types/streams.md create mode 100644 docs/data-types/strings.md rename docs/{manual/data-types/data-types-tutorial.md => data-types/tutorial.md} (94%) delete mode 100644 docs/manual/data-types/_index.md diff --git a/docs/about/_index.md b/docs/about/_index.md index fa840d2b6e..2b0bbf590a 100644 --- a/docs/about/_index.md +++ b/docs/about/_index.md @@ -8,15 +8,15 @@ aliases: - /buzz --- -Redis is an open source (BSD licensed), in-memory **data structure store** used as a database, cache, message broker, and streaming engine. Redis provides data structures such as -[strings](/topics/data-types-intro#strings), [hashes](/topics/data-types-intro#hashes), [lists](/topics/data-types-intro#lists), [sets](/topics/data-types-intro#sets), [sorted sets](/topics/data-types-intro#sorted-sets) with range queries, [bitmaps](/topics/data-types-intro#bitmaps), [hyperloglogs](/topics/data-types-intro#hyperloglogs), [geospatial indexes](/commands/geoadd), and [streams](/topics/streams-intro). Redis has built-in [replication](/topics/replication), [Lua scripting](/commands/eval), [LRU eviction](/topics/lru-cache), [transactions](/topics/transactions), and different levels of [on-disk persistence](/topics/persistence), and provides high availability via [Redis Sentinel](/topics/sentinel) and automatic partitioning with [Redis Cluster](/topics/cluster-tutorial). +Redis is an open source (BSD licensed), in-memory __data structure store__ used as a database, cache, message broker, and streaming engine. Redis provides [data structures](/docs/data-types/) such as +[strings](/docs/data-types/strings/), [hashes](/docs/data-types/hashes/), [lists](/docs/data-types/lists/), [sets](/docs/data-types/lists/), [sorted sets](/docs/data-types/sorted-sets/) with range queries, [bitmaps](/docs/data-types/bitmaps/), [hyperloglogs](/docs/data-types/hyperloglogs/), [geospatial indexes](/docs/data-types/geospatial/), and [streams](/docs/data-types/streams/). Redis has built-in [replication](/topics/replication), [Lua scripting](/commands/eval), [LRU eviction](/topics/lru-cache), [transactions](/topics/transactions), and different levels of [on-disk persistence](/topics/persistence), and provides high availability via [Redis Sentinel](/topics/sentinel) and automatic partitioning with [Redis Cluster](/topics/cluster-tutorial). -You can run **atomic operations** +You can run __atomic operations__ on these types, like [appending to a string](/commands/append); [incrementing the value in a hash](/commands/hincrby); [pushing an element to a list](/commands/lpush); [computing set intersection](/commands/sinter), [union](/commands/sunion) and [difference](/commands/sdiff); -or [getting the member with highest ranking in a sorted set](/commands/zrangebyscore). +or [getting the member with highest ranking in a sorted set](/commands/zrange). To achieve top performance, Redis works with an **in-memory dataset**. Depending on your use case, Redis can persist your data either diff --git a/docs/data-types/_index.md b/docs/data-types/_index.md new file mode 100644 index 0000000000..8f30ad0842 --- /dev/null +++ b/docs/data-types/_index.md @@ -0,0 +1,109 @@ +--- +title: "Redis data types" +linkTitle: "Data types" +description: Overview of data types supported by Redis +weight: 2 +aliases: + - /docs/manual/data-types + - /topics/data-types +--- + +Redis is a data structure server. +At its core, Redis provides a collection of native data types that help you solve a wide variety of problems, from [caching](/docs/manual/client-side-caching/) to [queuing](/docs/data-types/lists/) to [event processing](/docs/data-types/streams/). +Below is a short description of each data type, with links to broader overviews and command references. + +If you'd like to try a comprehensive tutorial, see the [Redis data types tutorial](/docs/data-types/tutorial/). + +## Core + +### Strings + +[Redis strings](/docs/data-types/strings) are the most basic Redis data type, representing a sequence of bytes. +For more information, see: + +* [Overview of Redis strings](/docs/data-types/strings/) +* [Redis string command reference](/commands/?group=string) + +### Lists + +[Redis lists](/docs/data-types/lists) are lists of strings sorted by insertion order. +For more information, see: + +* [Overview of Redis lists](/docs/data-types/lists/) +* [Redis list command reference](/commands/?group=list) + +### Sets + +[Redis sets](/docs/data-types/sets) are unordered collections of unique strings that act like the sets from your favorite programming language (for example, [Java HashSets](https://docs.oracle.com/javase/7/docs/api/java/util/HashSet.html), [Python sets](https://docs.python.org/3.10/library/stdtypes.html#set-types-set-frozenset), and so on). +With a Redis set, you can add, remove, and test for existence O(1) time (in other words, regardless of the number of set elements). +For more information, see: + +* [Overview of Redis sets](/docs/data-types/sets/) +* [Redis set command reference](/commands/?group=set) + +### Hashes + +[Redis hashes](/docs/data-types/hashes) are record types modeled as collections of field-value pairs. +As such, Redis hashes resemble [Python dictionaries](https://docs.python.org/3/tutorial/datastructures.html#dictionaries), [Java HashMaps](https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html), and [Ruby hashes](https://ruby-doc.org/core-3.1.2/Hash.html). +For more information, see: + +* [Overview of Redis hashes](/docs/data-types/hashes/) +* [Redis hashes command reference](/commands/?group=hash) + +### Sorted sets + +[Redis sorted sets](/docs/data-types/sorted-sets) are collections of unique strings that maintain order by each string's associated score. +For more information, see: + +* [Overview of Redis sorted sets](/docs/data-types/sorted-sets) +* [Redis sorted set command reference](/commands/?group=sorted-set) + +### Streams + +A [Redis stream](/docs/data-types/streams) is a data structure that acts like an append-only log. +Streams help record events in the order they occur and then syndicate them for processing. +For more information, see: + +* [Overview of Redis Streams](/docs/data-types/streams) +* [Redis Streams command reference](/commands/?group=streams) +* [Redis Streams tutorial](/docs/data-types/streams-tutorial) + +### Geospatial indexes + +[Redis geospatial indexes](/docs/data-types/geospatial) are useful for finding locations within a given geographic radius or bounding box. +For more information, see: + +* [Overview of Redis geospatial indexes](/docs/data-types/geospatial/) +* [Redis geospatial indexes command reference](/commands/?group=geo) + +### Bitmaps + +[Redis bitmaps](/docs/data-types/bitmaps/) let you perform bitwise operations on strings. +For more information, see: + +* [Overview of Redis bitmaps](/docs/data-types/bitmaps/) +* [Redis bitmap command reference](/commands/?group=bitmap) + +### Bitfields + +[Redis bitfields](/docs/data-types/bitfields/) efficiently encode multiple counters in a string value. +Bitfields provide atomic get, set, and increment operations and support different overflow policies. +For more information, see: + +* [Overview of Redis bitfields](/docs/data-types/bitfields/) +* The `BITFIELD` command. + +### HyperLogLog + +The [Redis HyperLogLog](/docs/data-types/hyperloglogs) data structures provide probabilistic estimates of the cardinality (i.e., number of elements) of large sets. For more information, see: + +* [Overview of Redis HyperLogLog](/docs/data-types/hyperloglogs) +* [Redis HyperLogLog command reference](/commands/?group=hyperloglog) + +## Extensions + +To extend the features provided by the included data types, use one of these options: + +1. Write your own custom [server-side functions in Lua](/docs/manual/programmability/). +1. Write your own Redis module using the [modules API](/docs/reference/modules/) or check out the [community-supported modules](/docs/modules/). +1. Use [JSON](/docs/stack/json/), [querying](/docs/stack/search/), [time series](/docs/stack/timeseries/), and other capabilities provided by [Redis Stack](/docs/stack/). diff --git a/docs/data-types/bitfields.md b/docs/data-types/bitfields.md new file mode 100644 index 0000000000..89f9b75319 --- /dev/null +++ b/docs/data-types/bitfields.md @@ -0,0 +1,54 @@ +--- +title: "Redis bitfields" +linkTitle: "Bitfields" +weight: 130 +description: > + Introduction to Redis bitmaps +--- + +Redis bitfields let you perform bitwise arithmetic on integer field of arbitrary bit length. For example, you an operate on anything from unsigned, 32-bit integers to signed 5-bit integers. + +These values are stored using binary-encoded Redis strings. +Bitfields support atomic read, write and increment operations, making them a good choice for managing counters and similar numerical values. + +## Examples + +Suppose you're keeping track of activity in an online game. +You want to maintain two crucial metrics for each player: the total amount of gold and the number of monsters slain. +Because your game is highly addictive, these counters should be at least 32 bits wide. + +You can represent these counters with one bitfield per player. + +* New players start the tutorial with 1000 gold (counter in offset 0). +``` +> BITFIELD player:1:stats SET u32 #0 1000 +1) (integer) 0 +``` + +* After killing the goblin holding the prince captive, add the 50 gold earned and increment the "slain" counter (offset 1). +``` +> BITFIELD player:1:stats INCRBY u32 #0 50 INCRBY u32 #1 1 +1) (integer) 1050 +2) (integer) 1 +``` + +* Pay the blacksmith 999 gold to buy a legendary rusty dagger. +``` +> BITFIELD player:1:stats INCRBY u32 #0 -999 +1) (integer) 51 +``` + +* Read the player's stats: +``` +> BITFIELD player:1:stats GET u32 #0 GET u32 #1 +1) (integer) 51 +2) (integer) 1 + +## Basic commands + +* `BITFIELD` atomically sets, increments and reads one or more values. +* `BITFIELD_RO` is a read-only variant of `BITFIELD`. + +## Performance + +`BITFIELD` is O(n), where _n_ is the number of counters accessed. diff --git a/docs/data-types/bitmaps.md b/docs/data-types/bitmaps.md new file mode 100644 index 0000000000..d1d4440644 --- /dev/null +++ b/docs/data-types/bitmaps.md @@ -0,0 +1,57 @@ +--- +title: "Redis bitmaps" +linkTitle: "Bitmaps" +weight: 120 +description: > + Introduction to Redis bitmaps +--- + +Redis bitmaps are an extension of the string data type that lets you treat a string like a bit vector. +You can also perform bitwise operations on one or more strings. +Some examples of bitmap use cases include: + +* Efficient set representations for cases where the members of a set correspond to the integers 0-N. +* Object permissions, where each bit represents a particular permission, similar to the way that file systems store permissions. + +## Examples + +Suppose you have 1000 sensors deployed in the field, labeled 0-999. +You want to quickly determine whether a given sensor has pinged the server within the hour. + +You can represent this scenario using a bitmap whose key references the current hour. + +* Sensor 123 pings the server on January 1, 2024 within the 00:00 hour. +``` +> SETBIT pings:2024-01-01-00:00 123 1 +(integer) 0 +``` + +* Did sensor 123 ping the server on January 1, 2024 within the 00:00 hour? +``` +> GETBIT pings:2024-01-01-00:00 123 +1 +``` + +* What about server 456? +``` +> GETBIT pings:2024-01-01-00:00 456 +0 +``` + +## Basic commands + +* `SETBIT` sets a bit at the provided offset to 0 or 1. +* `GETBIT` returns the value of a bit at a given offset. +* `BITOP` lets you perform bitwise operations against one or more strings. + +See the [complete list of bitmap commands](https://redis.io/commands/?group=bitmap). + +## Performance + +`SETBIT` and `GETBIT` are O(1). +`BITOP` is O(n), where _n_ is the length of the longest string in the comparison. + +## Learn more + +* [Redis Bitmaps Explained](https://www.youtube.com/watch?v=oj8LdJQjhJo) teaches you how to use bitmaps for map exploration in an online game. +* [Redis University's RU101](https://university.redis.com/courses/ru101/) covers Redis bitmaps in detail. \ No newline at end of file diff --git a/docs/data-types/geospatial.md b/docs/data-types/geospatial.md new file mode 100644 index 0000000000..8c070fdc8e --- /dev/null +++ b/docs/data-types/geospatial.md @@ -0,0 +1,47 @@ +--- +title: "Redis geospatial" +linkTitle: "Geospatial" +weight: 80 +description: > + Introduction to the Redis Geospatial data type +--- + +Redis geospatial indexes let you store coordinates and search for them. +This data structure is useful for finding nearby points within a given radius or bounding box. + +## Examples + +Suppose you're building a mobile app that lets you find all of the electric car charging stations closest to your current location. + +Add several locations to a geospatial index: +``` +> GEOADD locations:ca -122.27652 37.805186 station:1 +(integer) 1 +> GEOADD locations:ca -122.2674626 37.8062344 station:2 +(integer) 1 +> GEOADD locations:ca -122.2469854 37.8104049 station:3 +(integer) 1 +``` + +Find all locations within a 1 kilometer radius of a given location, and return the distance to each location: +``` +> GEOSEARCH locations:ca FROMLONLAT -122.2612767 37.7936847 BYRADIUS 5 km WITHDIST +1) 1) "station:1" + 2) "1.8523" +2) 1) "station:2" + 2) "1.4979" +3) 1) "station:3" + 2) "2.2441" +``` + +## Basic commands + +* `GEOADD` adds a location to a given geospatial index (note that longitude comes before latitude with this command). +* `GEOSEARCH` returns locations with a given radius or a bounding box. + +See the [complete list of geospatial index commands](https://redis.io/commands/?group=geo). + +## Learn more + +* [Redis Geospatial Explained](https://www.youtube.com/watch?v=qftiVQraxmI) introduces geospatial indexes by showing you how to build a map of local park attractions. +* [Redis University's RU101](https://university.redis.com/courses/ru101/) covers Redis geospatial indexes in detail. diff --git a/docs/data-types/hashes.md b/docs/data-types/hashes.md new file mode 100644 index 0000000000..2bafb4ab61 --- /dev/null +++ b/docs/data-types/hashes.md @@ -0,0 +1,73 @@ +--- +title: "Redis hashes" +linkTitle: "Hashes" +weight: 40 +description: > + Introduction to Redis hashes +--- + +Redis hashes are record types structured as collections of field-value pairs. +You can use hashes to represent basic objects and to store groupings of counters, among other things. + +## Examples + +* Represent a basic user profile as a hash: +``` +> HSET user:123 username martina firstName Martina lastName Elisa country GB +(integer) 4 +> HGET user:123 username +"martina" +> HGETALL user:123 +1) "username" +2) "martina" +3) "firstName" +4) "Martina" +5) "lastName" +6) "Elisa" +7) "country" +8) "GB" +``` + +* Store counters for the number of times device 777 had pinged the server, issued a request, or sent an error: +``` +> HINCRBY device:777:stats pings 1 +(integer) 1 +> HINCRBY device:777:stats pings 1 +(integer) 2 +> HINCRBY device:777:stats pings 1 +(integer) 3 +> HINCRBY device:777:stats errors 1 +(integer) 1 +> HINCRBY device:777:stats requests 1 +(integer) 1 +> HGET device:777:stats pings +"3" +> HMGET device:777:stats requests errors +1) "1" +2) "1" +``` + +## Basic commands + +* `HSET` sets the value of one or more fields on a hash. +* `HGET` returns the value at a given field. +* `HMGET` returns the values at one or more given fields. +* `HINCRBY` increments the value at a given field by the integer provided. + +See the [complete list of hash commands](https://redis.io/commands/?group=hash). + +## Performance + +Most Redis hash commands are O(1). + +A few commands - such as `HKEYS`, `HVALS`, and `HGETALL` - are O(n), where _n_ is the number of field-value pairs. + +## Limits + +Every hash can store up to 4,294,967,295 (2^32 - 1) field-value pairs. +In practice, your hashes are limited only by the overall memory on the VMs hosting your Redis deployment. + +## Learn more + +* [Redis Hashes Explained](https://www.youtube.com/watch?v=-KdITaRkQ-U) is a short, comprehensive video explainer covering Redis hashes. +* [Redis University's RU101](https://university.redis.com/courses/ru101/) covers Redis hashes in detail. diff --git a/docs/data-types/hyperloglogs.md b/docs/data-types/hyperloglogs.md new file mode 100644 index 0000000000..0730d5ef17 --- /dev/null +++ b/docs/data-types/hyperloglogs.md @@ -0,0 +1,51 @@ +--- +title: "Redis HyperLogLog" +linkTitle: "HyperLogLog" +weight: 90 +description: > + Introduction to the Redis HyperLogLog data type +--- + +HyperLogLog is a data structure that estimates the cardinality of a set. As a probabilistic data structure, HyperLogLog trades perfect accuracy for efficient space utilization. + +The Redis HyperLogLog implementation uses up to 12 KB and provides a standard error of 0.81%. + +## Examples + +* Add some items to the HyperLogLog: +``` +> PFADD members 123 +(integer) 1 +> PFADD members 500 +(integer) 1 +> PFADD members 12 +(integer) 1 +``` + +* Estimate the number of members in the set: +``` +> PFCOUNT members +(integer) 3 +``` + +## Basic commands + +* `PFADD` adds an item to a HyperLogLog. +* `PFCOUNT` returns an estimate of the number of items in the set. +* `PFMERGE` combines two or more HyperLogLogs into one. + +See the [complete list of HyperLogLog commands](https://redis.io/commands/?group=hyperloglog). + +## Performance + +Writing (`PFADD`) to and reading from (`PFCOUNT`) the HyperLogLog is done in constant time and space. +Merging HLLs is O(n), where _n_ is the number of sketches. + +## Limits + +The HyperLogLog can estimate the cardinality of sets with up to 18,446,744,073,709,551,616 (2^64) members. + +## Learn more + +* [Redis new data structure: the HyperLogLog](https://antirez.com/news/75) has a lot of details about the data structure and its implementation in Redis. +* [Redis HyperLogLog Explained](https://www.youtube.com/watch?v=MunL8nnwscQ) shows you how to use Redis HyperLogLog data structures to build a traffic heat map. diff --git a/docs/data-types/lists.md b/docs/data-types/lists.md new file mode 100644 index 0000000000..c9753db790 --- /dev/null +++ b/docs/data-types/lists.md @@ -0,0 +1,111 @@ +--- +title: "Redis lists" +linkTitle: "Lists" +weight: 20 +description: > + Introduction to Redis lists +--- + +Redis lists are linked lists of string values. +Redis lists are frequently used to: + +* Implement stacks and queues. +* Build queue management for background worker systems. + +## Examples + +* Treat a list like a queue (first in, first out): +``` +> LPUSH work:queue:ids 101 +(integer) 1 +> LPUSH work:queue:ids 237 +(integer) 2 +> RPOP work:queue:ids +"101" +> RPOP work:queue:ids +"237" +``` + +* Treat a list like a stack (first in, last out): +``` +> LPUSH work:queue:ids 101 +(integer) 1 +> LPUSH work:queue:ids 237 +(integer) 2 +> LPOP work:queue:ids +"237" +> LPOP work:queue:ids +"101" +``` + +* Check the length of a list: +``` +> LLEN work:queue:ids +(integer) 0 +``` + +* Atomically pop an element from one list and push to another: +``` +> LPUSH board:todo:ids 101 +(integer) 1 +> LPUSH board:todo:ids 273 +(integer) 2 +> LMOVE board:todo:ids board:in-progress:ids LEFT LEFT +"273" +> LRANGE board:todo:ids 0 -1 +1) "101" +> LRANGE board:in-progress:ids 0 -1 +1) "273" +``` + +* To create a capped list that never grows beyond 100 elements, you can call `LTRIM` after each call to `LPUSH`: +``` +> LPUSH notifications:user:1 "You've got mail!" +(integer) 1 +> LTRIM notifications:user:1 0 99 +OK +> LPUSH notifications:user:1 "Your package will be delivered at 12:01 today." +(integer) 2 +> LTRIM notifications:user:1 0 99 +OK +``` + +## Limits + +The max length of a Redis list is 2^32 - 1 (4,294,967,295) elements. + +## Basic commands + +* `LPUSH` adds a new element to the head of a list; `RPUSH` adds to the tail. +* `LPOP` removes and returns an element from the head of a list; `RPOP`does the same but from the tails of a list. +* `LLEN` returns the length of a list. +* `LMOVE` atomically moves elements from one list to another. +* `LTRIM` reduces a list to the specified range of elements. + +### Blocking commands + +Lists support several blocking commands. +For example: + +* `BLPOP` removes and returns an element from the head of a list. + If the list is empty, the command blocks until an element becomes available or until the specified timeout is reached. +* `BLMOVE` atomically moves elements from a source list to a target list. + If the source list is empty, the command will block until a new element becomes available. + +See the [complete series of list commands](https://redis.io/commands/?group=list). + +## Performance + +List operations that access its head or tail are O(1), which means they're highly efficient. +However, commands that manipulate elements within a list are usually O(n). +Examples of these include `LINDEX`, `LINSERT`, and `LSET`. +Exercise caution when running these commands, mainly when operating on large lists. + +## Alternatives + +Consider [Redis streams](/docs/data-types/streams) as an alternative to lists when you need to store and process an indeterminate series of events. + +## Learn more + +* [Redis Lists Explained](https://www.youtube.com/watch?v=PB5SeOkkxQc) is a short, comprehensive video explainer on Redis lists. +* [Redis University's RU101](https://university.redis.com/courses/ru101/) covers Redis lists in detail. diff --git a/docs/data-types/sets.md b/docs/data-types/sets.md new file mode 100644 index 0000000000..f358568fa6 --- /dev/null +++ b/docs/data-types/sets.md @@ -0,0 +1,83 @@ +--- +title: "Redis sets" +linkTitle: "Sets" +weight: 30 +description: > + Introduction to Redis sets +--- + +A Redis set is an unordered collection of unique strings (members). +You can use Redis sets to efficiently: + +* Track unique items (e.g., track all unique IP addresses accessing a given blog post). +* Represent relations (e.g., the set of all users with a given role). +* Perform common set operations such as intersection, unions, and differences. + +## Examples + +* Store the set of favorited book IDs for users 123 and 456: +``` +> SADD user:123:favorites 347 +(integer) 1 +> SADD user:123:favorites 561 +(integer) 1 +> SADD user:123:favorites 742 +(integer) 1 +> SADD user:456:favorites 561 +(integer) 1 +``` + +* Check whether user 123 likes books 742 and 299 +``` +> SISMEMBER user:123:favorites 742 +(integer) 1 +> SISMEMBER user:123:favorites 299 +(integer) 0 +``` + +* Do user 123 and 456 have any favorite books in common? +``` +> SINTER user:123:favorites user:456:favorites +1) "561" +``` + +* How many books has user 123 favorited? +``` +> SCARD user:123:favorites +(integer) 3 +``` + +## Limits + +The max size of a Redis set is 2^32 - 1 (4,294,967,295) members. + +## Basic commands + +* `SADD` adds a new member to a set. +* `SREM` removes the specified member from the set. +* `SISMEMBER` tests a string for set membership. +* `SINTER` returns the set of members that two or more sets have in common (i.e., the intersection). +* `SCARD` returns the size (a.k.a. cardinality) of a set. + +See the [complete list of set commands](https://redis.io/commands/?group=set). + +## Performance + +Most set operations, including adding, removing, and checking whether an item is a set member, are O(1). +This means that they're highly efficient. +However, for large sets with hundreds of thousands of members or more, you should exercise caution when running the `SMEMBERS` command. +This command is O(n) and returns the entire set in a single response. +As an alternative, consider the `SSCAN`, which lets you retrieve all members of a set iteratively. + +## Alternatives + +Sets membership checks on large datasets (or on streaming data) can use a lot of memory. +If you're concerned about memory usage and don't need perfect precision, consider a [Bloom filter or Cuckoo filter](/docs/stack/bloom) as an alternative to a set. + +Redis sets are frequently used as a kind of index. +If you need to index and query your data, consider [RediSearch](/docs/stack/search)](/docs/stack/search) and [RedisJSON](/docs/stack/json). + +## Learn more + +* [Redis Sets Explained](https://www.youtube.com/watch?v=PB5SeOkkxQc) and [Redis Sets Elaborated](https://www.youtube.com/watch?v=aRw5ME_5kMY) are two short but thorough video explainers covering Redis sets. +* [Redis University's RU101](https://university.redis.com/courses/ru101/) explores Redis sets in detail. diff --git a/docs/data-types/sorted-sets.md b/docs/data-types/sorted-sets.md new file mode 100644 index 0000000000..71e0d8457e --- /dev/null +++ b/docs/data-types/sorted-sets.md @@ -0,0 +1,77 @@ +--- +title: "Redis sorted sets" +linkTitle: "Sorted sets" +weight: 50 +description: > + Introduction to Redis sorted sets +--- + +A Redis sorted set is a collection of unique strings (members) ordered by an associated score. +When more than one string has the same score, the strings are ordered lexicographically. +Some use cases for sorted sets include: + +* Leaderboards. For example, you can use sorted sets to easily maintain ordered lists of the highest scores in a massive online game. +* Rate limiters. In particular, you can use a sorted set to build a sliding-window rate limiter to prevent excessive API requests. + +## Examples + +* Update a real-time leaderboard as players' scores change: +``` +> ZADD leaderboard:455 100 user:1 +(integer) 1 +> ZADD leaderboard:455 75 user:2 +(integer) 1 +> ZADD leaderboard:455 101 user:3 +(integer) 1 +> ZADD leaderboard:455 15 user:4 +(integer) 1 +> ZADD leaderboard:455 275 user:2 +(integer) 0 +``` + +Notice that `user:2`'s score is updated in the final `ZADD` call. + +* Get the top 3 players' scores: +``` +> ZRANGE leaderboard:455 0 4 REV WITHSCORES +1) "user:2" +2) "275" +3) "user:3" +4) "101" +5) "user:1" +6) "100" +7) "user:4" +8) "15" +``` + +* What's the rank of user 2? +``` +> ZREVRANK leaderboard:455 user:2 +(integer) 0 +``` + +## Basic commands + +* `ZADD` adds a new member and associated score to a sorted set. If the member already exists, the score is updated. +* `ZRANGE` returns members of a sorted set, sorted within a given range. +* `ZRANK` returns the rank the provided member, assuming the sorted is in ascending order. +* `ZREVRANK` returns the rank the provided member, assuming the sorted set is in descending order. + +See the [complete list of sorted set commands](https://redis.io/commands/?group=sorted-set). + +## Performance + +Most sorted set operations are O(log(n)), where _n_ is the number of members. + +Exercise some caution when running the `ZRANGE` command with large returns values (e.g., in the tens of thousands or more). +This command's time complexity is O(log(n) + m), where _m_ is the number of results returned. + +## Alternatives + +Redis sorted sets are sometimes used for indexing other Redis data structures. +If you need to index and query your data, consider [RediSearch](/docs/stack/search) and [RedisJSON](/docs/stack/json). + +## Learn more + +* [Redis Sorted Sets Explained](https://www.youtube.com/watch?v=MUKlxdBQZ7g) is an entertaining introduction to sorted sets in Redis. +* [Redis University's RU101](https://university.redis.com/courses/ru101/) explores Redis sorted sets in detail. diff --git a/docs/manual/data-types/streams.md b/docs/data-types/streams-tutorial.md similarity index 95% rename from docs/manual/data-types/streams.md rename to docs/data-types/streams-tutorial.md index 7388f10fde..35e9241adb 100644 --- a/docs/manual/data-types/streams.md +++ b/docs/data-types/streams-tutorial.md @@ -1,24 +1,25 @@ --- -title: "Redis streams" -linkTitle: "Streams" -weight: 2 +title: "Redis Streams tutorial" +linkTitle: "Streams tutorial" +weight: 61 description: > - An introduction to the Redis stream data type + A comprehensive tutorial on Redis streams aliases: - /topics/streams-intro + - /docs/manual/data-types/streams --- -The Stream is a new data type introduced with Redis 5.0, which models a *log data structure* in a more abstract way. However the essence of a log is still intact: like a log file, often implemented as a file open in append-only mode, Redis Streams are primarily an append-only data structure. At least conceptually, because being an abstract data type represented in memory, Redis Streams implement powerful operations to overcome the limitations of a log file. +If you're new to streams, see the [Redis Streams introduction](/docs/data-types/streams/). For a more comprehensive tutorial, read on. -What makes Redis streams the most complex type of Redis, despite the data structure itself being quite simple, is the fact that it implements additional, non-mandatory features: a set of blocking operations allowing consumers to wait for new data added to a stream by producers, and in addition to that a concept called **Consumer Groups**. +## Introduction -Consumer groups were initially introduced by the popular messaging system Kafka (TM). Redis reimplements a similar idea in completely different terms, but the goal is the same: to allow a group of clients to cooperate in consuming a different portion of the same stream of messages. +The Redis stream data type was introduced in Redis 5.0. Streams model a log data structure but also implement several operations to overcome some of the limits of a typical append-only log. These include random access in O(1) time and complex consumption strategies, such as consumer groups. ## Streams basics -For the goal of understanding what Redis Streams are and how to use them, we will ignore all the advanced features, and instead focus on the data structure itself, in terms of commands used to manipulate and access it. This is, basically, the part which is common to most of the other Redis data types, like Lists, Sets, Sorted Sets and so forth. However, note that Lists also have an optional more complex blocking API, exported by commands like `BLPOP` and similar. So Streams are not much different than Lists in this regard, it's just that the additional API is more complex and more powerful. +Streams are an append-only data structure. The fundamental write command, called [XADD](/commands/xadd), appends a new entry to the specified stream. -Because Streams are an append only data structure, the fundamental write command, called `XADD`, appends a new entry into the specified stream. A stream entry is not just a string, but is instead composed of one or more field-value pairs. This way, each entry of a stream is already structured, like an append only file written in CSV format where multiple separated fields are present in each line. +Each stream entry consists of one or more field-value pairs, somewhat like a record or a Redis hash: ``` > XADD mystream * sensor-id 1234 temperature 19.8 @@ -62,7 +63,7 @@ Note that in this case, the minimum ID is 0-1 and that the command will not acce (error) ERR The ID specified in XADD is equal or smaller than the target stream top item ``` -It is also possible to use an explicit ID that only consists of the milliseconds part, and have the sequence part be automatically generated for the entry: +If you're running Redis 7 or later, you can also provide an explicit ID consisting of the milliseconds part only. In this case, the sequence portion of the ID will be automatically generated. To do this, use the syntax below: ``` > XADD somestream 0-* baz qux diff --git a/docs/data-types/streams.md b/docs/data-types/streams.md new file mode 100644 index 0000000000..d74220b319 --- /dev/null +++ b/docs/data-types/streams.md @@ -0,0 +1,81 @@ +--- +title: "Redis Streams" +linkTitle: "Streams" +weight: 60 +description: > + Introduction to Redis streams +--- + +A Redis stream is a data structure that acts like an append-only log. +You can use streams to record and simultaneously syndicate events in real time. +Examples of Redis stream use cases include: + +* Event sourcing (e.g., tracking user actions, clicks, etc.) +* Sensor monitoring (e.g., readings from devices in the field) +* Notifications (e.g., storing a record of each user's notifications in a separate stream) + +Redis generates a unique ID for each stream entry. +You can use these IDs to retrieve their associated entries later or to read and process all subsequent entries in the stream. + +Redis streams support several trimming strategies (to prevent streams from growing unbounded) and more than one consumption strategy (see `XREAD`, `XREADGROUP`, and `XRANGE`). + +## Examples + +* Add several temperature readings to a stream +``` +> XADD temperatures:us-ny:10007 * temp_f 87.2 pressure 29.69 humidity 46 +"1658354918398-0" +> XADD temperatures:us-ny:10007 * temp_f 83.1 pressure 29.21 humidity 46.5 +"1658354934941-0" +> XADD temperatures:us-ny:10007 * temp_f 81.9 pressure 28.37 humidity 43.7 +"1658354957524-0" +``` + +* Read the first two stream entries starting at ID `1658354934941-0`: +``` +> XRANGE temperatures:us-ny:10007 1658354934941-0 + COUNT 2 +1) 1) "1658354934941-0" + 2) 1) "temp_f" + 2) "83.1" + 3) "pressure" + 4) "29.21" + 5) "humidity" + 6) "46.5" +2) 1) "1658354957524-0" + 2) 1) "temp_f" + 2) "81.9" + 3) "pressure" + 4) "28.37" + 5) "humidity" + 6) "43.7" +``` + +* Read up to 100 new stream entries, starting at the end of the stream, and block for up to 300 ms if no entries are being written: +``` +> XREAD COUNT 100 BLOCK 300 STREAMS tempertures:us-ny:10007 $ +(nil) +``` + +## Basic commands +* `XADD` adds a new entry to a stream. +* `XREAD` reads one or more entries, starting at a given position and moving forward in time. +* `XRANGE` returns a range of entries between two supplied entry IDs. +* `XLEN` returns the length of a stream. + +See the [complete list of stream commands](https://redis.io/commands/?group=stream). + +## Performance + +Adding an entry to a stream is O(1). +Accessing any single entry is O(n), where _n_ is the length of the ID. +Since stream IDs are typically short and of a fixed length, this effectively reduces to a constant time lookup. +For details on why, note that streams are implemented as [radix trees](https://en.wikipedia.org/wiki/Radix_tree). + +Simply put, Redis streams provide highly efficient inserts and reads. +See each command's time complexity for the details. + +## Learn more + +* The [Redis Streams Tutorial](/docs/data-types/streams-tutorial.md) explains Redis streams with many examples. +* [Redis Streams Explained](https://www.youtube.com/watch?v=Z8qcpXyMAiA) is an entertaining introduction to streams in Redis. +* [Redis University's RU102](https://university.redis.com/courses/ru102/) is a free, online course dedicated to Redis Streams. diff --git a/docs/data-types/strings.md b/docs/data-types/strings.md new file mode 100644 index 0000000000..77dbe16d73 --- /dev/null +++ b/docs/data-types/strings.md @@ -0,0 +1,76 @@ +--- +title: "Redis Strings" +linkTitle: "Strings" +weight: 10 +description: > + Introduction to Redis strings +--- + +Redis strings store sequences of bytes, including text, serialized objects, and binary arrays. +As such, strings are the most basic Redis data type. +They're often used for caching, but they support additional functionality that lets you implement counters and perform bitwise operations, too. + +## Examples + +* Store and then retrieve a string in Redis: + +``` +> SET user:1 salvatore +OK +> GET user:1 +"salvatore" +``` + +* Store a serialized JSON string and set it to expire 100 seconds from now: + +``` +> SET ticket:27 "\"{'username': 'priya', 'ticket_id': 321}\"" EX 100 +``` + +* Increment a counter: + +``` +> INCR views:page:2 +(integer) 1 +> INCRBY views:page:2 10 +(integer) 11 +``` + +## Limits + +By default, a single Redis string can be a maximum of 512 MB. + +## Basic commands + +### Getting and setting Strings + +* `SET` stores a string value. +* `SETNX` stores a string value only if the key doesn't already exist. Useful for implementing locks. +* `GET` retrieves a string value. +* `MGET` retrieves multiple string values in a single operation. + +### Managing counters + +* `INCRBY` atomically increments (and decrements when passing a negative number) counters stored at a given key. +* Another command exists for floating point counters: [INCRBYFLOAT](/commands/incrbyfloat). + +### Bitwise operations + +To perform bitwise operations on a string, see the [bitmaps data type](/docs/data-types/bitmaps) docs. + +See the [complete list of string commands](/commands/?group=string). + +## Performance + +Most string operations are O(1), which means they're highly efficient. +However, be careful with the `SUBSTR`, `GETRANGE`, and `SETRANGE` commands, which can be O(n). +These random-access string commands may cause performance issues when dealing with large strings. + +## Alternatives + +If you're storing structured data as a serialized string, you may also want to consider [Redis hashes](/docs/data-types/hashes) or [RedisJSON](/docs/stack/json). + +## Learn more + +* [Redis Strings Explained](https://www.youtube.com/watch?v=7CUt4yWeRQE) is a short, comprehensive video explainer on Redis strings. +* [Redis University's RU101](https://university.redis.com/courses/ru101/) covers Redis strings in detail. diff --git a/docs/manual/data-types/data-types-tutorial.md b/docs/data-types/tutorial.md similarity index 94% rename from docs/manual/data-types/data-types-tutorial.md rename to docs/data-types/tutorial.md index 87bc00c915..f414c7ba8c 100644 --- a/docs/manual/data-types/data-types-tutorial.md +++ b/docs/data-types/tutorial.md @@ -1,45 +1,14 @@ --- -title: "Data types tutorial" +title: "Redis data types tutorial" linkTitle: "Tutorial" description: Learning the basic Redis data types and how to use them weight: 1 aliases: - /topics/data-types-intro + - /docs/manual/data-types/data-types-tutorial --- -Redis is not a *plain* key-value store, it is actually a *data structures server*, supporting different kinds of values. What this means is that, while in -traditional key-value stores you associate string keys to string values, in -Redis the value is not limited to a simple string, but can also hold more complex -data structures. The following is the list of all the data structures supported -by Redis, which will be covered separately in this tutorial: - -* Binary-safe strings. -* Lists: collections of string elements sorted according to the order of insertion. They are basically *linked lists*. -* Sets: collections of unique, unsorted string elements. -* Sorted sets, similar to Sets but where every string element is associated to a - floating number value, called *score*. The elements are always taken sorted - by their score, so unlike Sets it is possible to retrieve a range of elements - (for example you may ask: give me the top 10, or the bottom 10). -* Hashes, which are maps composed of fields associated with values. Both the - field and the value are strings. This is very similar to Ruby or Python - hashes. -* Bit arrays (or simply bitmaps): it is possible, using special commands, to - handle String values like an array of bits: you can set and clear individual - bits, count all the bits set to 1, find the first set or unset bit, and so - forth. -* HyperLogLogs: this is a probabilistic data structure which is used in order - to estimate the cardinality of a set. Don't be scared, it is simpler than - it seems... See later in the HyperLogLog section of this tutorial. -* Streams: append-only collections of map-like entries that provide an abstract - log data type. They are covered in depth in the - [Introduction to Redis Streams](/topics/streams-intro). - -It's not always trivial to grasp how these data types work and what to use in -order to solve a given problem from the [command reference](/commands), so this -document is a crash course in Redis data types and their most common patterns. - -For all the examples we'll use the `redis-cli` utility, a simple but -handy command-line utility, to issue commands against the Redis server. +The following is a hands-on tutorial that teaches the core Redis data types using the Redis CLI. For a general overview of the data types, see the [data types introduction](/docs/data-types/). ## Keys diff --git a/docs/manual/data-types/_index.md b/docs/manual/data-types/_index.md deleted file mode 100644 index ff39872d27..0000000000 --- a/docs/manual/data-types/_index.md +++ /dev/null @@ -1,155 +0,0 @@ ---- -title: "Redis data types" -linkTitle: "Data types" -description: Overview of the many data types supported by Redis -weight: 1 -aliases: - - /topics/data-types ---- - -## Strings - -Strings are the most basic kind of Redis value. Redis Strings are binary safe, this means that a Redis string can contain any kind of data, for instance a -JPEG image or a serialized Ruby object. - -A String value can be at max 512 Megabytes in length. - -You can do a number of interesting things using strings in Redis, for instance you can: - -* Use Strings as atomic counters using commands in the INCR family: [INCR](/commands/incr), [DECR](/commands/decr), [INCRBY](/commands/incrby). -* Append to strings with the [APPEND](/commands/append) command. -* Use Strings as a random access vectors with [GETRANGE](/commands/getrange) and [SETRANGE](/commands/setrange). -* Encode a lot of data in little space, or create a Redis backed Bloom Filter using [GETBIT](/commands/getbit) and [SETBIT](/commands/setbit). - -Check all the [available string commands](/commands/#string) for more information, or read the [introduction to Redis data types](/topics/data-types-intro). - -## Lists - -Redis Lists are simply lists of strings, sorted by insertion order. -It is possible to add elements to a Redis List pushing new elements on the head (on the left) or on the tail (on the right) of the list. - -The [LPUSH](/commands/lpush) command inserts a new element on the head, while -[RPUSH](/commands/rpush) inserts a new element on the tail. A new list is created -when one of this operations is performed against an empty key. -Similarly the key is removed from the key space if a list operation will -empty the list. These are very handy semantics since all the list commands will -behave exactly like they were called with an empty list if called with a -non-existing key as argument. - -Some example of list operations and resulting lists: - - LPUSH mylist a # now the list is "a" - LPUSH mylist b # now the list is "b","a" - RPUSH mylist c # now the list is "b","a","c" (RPUSH was used this time) - -The max length of a list is 2^32 - 1 elements (4294967295, more than 4 billion of elements per list). - -The main features of Redis Lists from the point of view of time complexity are -the support for constant time insertion and deletion of elements near the -head and tail, even with many millions of inserted items. -Accessing elements is very fast near the extremes of the list but -is slow if you try accessing the middle of a very big list, as it is -an O(N) operation. - -You can do many interesting things with Redis Lists, for instance you can: - -* Model a timeline in a social network, using [LPUSH](/commands/lpush) in order to add new elements in the user time line, and using [LRANGE](/commands/lrange) in order to retrieve a few of recently inserted items. -* You can use [LPUSH](/commands/lpush) together with [LTRIM](/commands/ltrim) to create a list that never exceeds a given number of elements, but just remembers the latest N elements. -* Lists can be used as a message passing primitive, See for instance the well known [Resque](https://github.com/resque/resque) Ruby library for creating background jobs. -* You can do a lot more with lists, this data type supports a number of commands, including blocking commands like [BLPOP](/commands/blpop). - -Please check all the [available commands operating on lists](/commands#list) for more information, or read the [introduction to Redis data types](/topics/data-types-intro). - -## Sets ---- - -Redis Sets are an unordered collection of Strings. It is possible to add, -remove, and test for existence of members in O(1) (constant time regardless -of the number of elements contained inside the Set). - -Redis Sets have the desirable property of not allowing repeated members. Adding the same element multiple times will result in a set having a single copy of this element. Practically speaking this means that adding a member does not require a *check if exists then add* operation. - -A very interesting thing about Redis Sets is that they support a number of -server side commands to compute sets starting from existing sets, so you -can do unions, intersections, differences of sets in very short time. - -The max number of members in a set is 2^32 - 1 (4294967295, more than 4 billion of members per set). - -You can do many interesting things using Redis Sets, for instance you can: - -* You can track unique things using Redis Sets. Want to know all the unique IP addresses visiting a given blog post? Simply use [SADD](/commands/sadd) every time you process a page view. You are sure repeated IPs will not be inserted. -* Redis Sets are good to represent relations. You can create a tagging system with Redis using a Set to represent every tag. Then you can add all the IDs of all the objects having a given tag into a Set representing this particular tag, using the [SADD](/commands/sadd) command. Do you want all the IDs of all the Objects having three different tags at the same time? Just use [SINTER](/commands/sinter). -* You can use Sets to extract elements at random using the [SPOP](/commands/spop) or [SRANDMEMBER](/commands/srandmember) commands. - - -As usual, check the [full list of Set commands](/commands#set) for more information, or read the [introduction to Redis data types](/topics/data-types-intro). - -## Hashes - -Redis Hashes are maps between string fields and string values, so they are the perfect data type to represent objects (e.g. A User with a number of fields like name, surname, age, and so forth): - - HMSET user:1000 username antirez password P1pp0 age 34 - HGETALL user:1000 - HSET user:1000 password 12345 - HGETALL user:1000 - -A hash with a few fields (where few means up to one hundred or so) is stored in a way -that takes very little space, so you can store millions of objects in a small -Redis instance. - -While Hashes are used mainly to represent objects, they are capable of storing many elements, so you can use Hashes for many other tasks as well. - -Every hash can store up to 2^32 - 1 field-value pairs (more than 4 billion). - -Check the [full list of Hash commands](/commands#hash) for more information, or read the [introduction to Redis data types](/topics/data-types-intro). - -## Sorted Sets - -Redis Sorted Sets are, similarly to Redis Sets, non repeating collections of -Strings. The difference is that every member of a Sorted Set is associated -with a score, that is used to keep the Sorted Set in order, from the -smallest to the greatest score. While members are unique, scores may be -repeated. - -With Sorted Sets you can add, remove, or update elements in a very fast way -(in a time proportional to the logarithm of the number of elements). Since -elements are *stored in order* and not ordered afterwards, you can also get -ranges by score or by rank (position) in a very fast way. -Accessing the middle of a Sorted Set is also very fast, so you can use -Sorted Sets as a smart list of non repeating elements where you can quickly access -everything you need: elements in order, fast existence test, fast access -to elements in the middle! - -In short with Sorted Sets you can do a lot of tasks with great performance -that are really hard to model in other kind of databases. - -With Sorted Sets you can: - -* Build a leaderboard in a massive online game, where every time a new score -is submitted you update it using [ZADD](/commands/zadd). You can easily -retrieve the top users using [ZRANGE](/commands/zrange), you can also, given a -user name, return its rank in the listing using [ZRANK](/commands/zrank). -Using ZRANK and ZRANGE together you can show users with a score similar to -a given user. All very *quickly*. -* Sorted Sets are often used in order to index data that is stored inside Redis. -For instance if you have many hashes representing users, you can use a Sorted Set with members having the age of the user as the score and the ID of the user as the value. So using [ZRANGEBYSCORE](/commands/zrangebyscore) it will be trivial and fast to retrieve all the users with a given age range. - - -Sorted Sets are one of the more advanced Redis data types, so take some time to check the [full list of Sorted Set commands](/commands#sorted_set) to discover what you can do with Redis! Also you may want to read the [Introduction to Redis Data Types](/topics/data-types-intro). - -## Bitmaps and HyperLogLogs - -Redis also supports Bitmaps and HyperLogLogs which are actually data types -based on the String base type, but having their own semantics. - -Please refer to the [data types tutorial](/docs/manual/data-types/data-types-tutorial) for information about those types. - -## Streams - -A Redis stream is a data structure that acts like an append-only log. Streams are useful for recording events in the order they occur. See the [Redis streams docs](/docs/manual/data-types/streams) for details and usage. - -## Geospatial indexes - -Redis provides geospatial indexes, which are useful for finding locations within a given geographic radius. You can add locations to a geospatial index using the [GEOADD](/commands/geoadd) command. You then search for locations within a given radius using the [GEORADIUS](/commands/georadius) command. - -See the [complete geospatial index command reference](/commands/?group=geo) for all of the details. diff --git a/wordlist b/wordlist index 3a9c4a7874..daff9b3159 100644 --- a/wordlist +++ b/wordlist @@ -1,3 +1,4 @@ + .rdb 0s 0x00060007 @@ -67,6 +68,7 @@ Benchmarking BigNumber BitOp Bitfields +Bitwise C1 C2 C3 @@ -157,13 +159,17 @@ HMAC-SHA256 HVM HW Hardcoded +HashMaps +HashSets Haversine Hexastore Hitmeister Homebrew Hotspot HyperLogLog +HyperLogLog. HyperLogLogs +Hyperloglogs IOPs IPC IPs @@ -191,6 +197,7 @@ LRU LRU's LRU. LUA +Leaderboards Leau Lehmann Levelgraph @@ -222,7 +229,6 @@ NaN Nehalem NoSQL NodeJS -nonprintable Noordhuis NullArray ODOWN @@ -279,16 +285,20 @@ RM_.* RPC RSS RTT +RU101 +RU102 RW Rebranding Reconfiguring Reddit's +RediSearch Redimension Redis-rb Redis-to-Lua RedisCallReply RedisConf RedisHost. +RedisJSON RedisModule.* Redisson Redistributions @@ -432,8 +442,11 @@ benchmarked benchmarking big-endian bitfield +bitfield +bitfields bitop bitwise +bitwise bool breakpoint broadcasted @@ -513,6 +526,7 @@ endianness enum enum_val enum_vals +enums epel-release epoll errno @@ -525,6 +539,8 @@ eval-intro everysec executables expiries +explainer +explainers facto factorializing failover @@ -538,6 +554,7 @@ failover. failovers fanout faq +favorited fdatasync filesystem firewalled @@ -592,6 +609,7 @@ iostat ip ip:port iterable +iteratively jemalloc jpeg kB @@ -618,6 +636,7 @@ launchd lazyfree-lazy-user-flush ldb leaderboard +leaderboards len lenptr lexicographically @@ -676,6 +695,7 @@ non-TCP non-TLS non-reachability non-virtualized +nonprintable nopass notify-keyspace-events notifyKeyspaceEvent @@ -913,4 +933,3 @@ zeroed-ACLs ziplists zset ˈrɛd-ɪs -enums From d19e3603e93eb78c122a8db53904c9e8681197cb Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Sat, 6 Aug 2022 16:58:54 +0300 Subject: [PATCH 007/377] Fixes command links (#2069) --- docs/manual/config.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/manual/config.md b/docs/manual/config.md index 89b8aacd75..f80d29f462 100644 --- a/docs/manual/config.md +++ b/docs/manual/config.md @@ -63,7 +63,7 @@ as the one used in the redis.conf file, with the exception that the keyword is prefixed with `--`. Note that internally this generates an in-memory temporary config file -(possibly concatenating the config file passed by the user if any) where +(possibly concatenating the config file passed by the user, if any) where arguments are translated into the format of redis.conf. Changing Redis configuration while the server is running @@ -71,20 +71,21 @@ Changing Redis configuration while the server is running It is possible to reconfigure Redis on the fly without stopping and restarting the service, or querying the current configuration programmatically using the -special commands [`CONFIG SET`](/commands/config-set) and -[`CONFIG GET`](/commands/config-get) +special commands `CONFIG SET` and `CONFIG GET`. Not all of the configuration directives are supported in this way, but most -are supported as expected. Please refer to the -[`CONFIG SET`](/commands/config-set) and [`CONFIG GET`](/commands/config-get) -pages for more information. +are supported as expected. +Please refer to the `CONFIG SET` and `CONFIG GET` pages for more information. Note that modifying the configuration on the fly **has no effects on the redis.conf file** so at the next restart of Redis the old configuration will be used instead. Make sure to also modify the `redis.conf` file accordingly to the configuration -you set using [`CONFIG SET`](/commands/config-set). You can do it manually or you can use [`CONFIG REWRITE`](/commands/config-rewrite), which will automatically scan your `redis.conf` file and update the fields which don't match the current configuration value. Fields non existing but set to the default value are not added. Comments inside your configuration file are retained. +you set using `CONFIG SET`. +You can do it manually, or you can use `CONFIG REWRITE`, which will automatically scan your `redis.conf` file and update the fields which don't match the current configuration value. +Fields non existing but set to the default value are not added. +Comments inside your configuration file are retained. Configuring Redis as a cache --- @@ -101,5 +102,5 @@ time to live for keys using the `EXPIRE` command (or equivalent) since all the keys will be evicted using an approximated LRU algorithm as long as we hit the 2 megabyte memory limit. -Basically in this configuration Redis acts in a similar way to memcached. +Basically, in this configuration Redis acts in a similar way to memcached. We have more extensive documentation about using Redis as an LRU cache [here](/topics/lru-cache). From 366d0436791d2092a651250c0a2284407d6aa6a5 Mon Sep 17 00:00:00 2001 From: wanglun Date: Sun, 7 Aug 2022 19:45:38 +0800 Subject: [PATCH 008/377] Fix typo (#2072) --- docs/data-types/bitfields.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/bitfields.md b/docs/data-types/bitfields.md index 89f9b75319..87762d8e43 100644 --- a/docs/data-types/bitfields.md +++ b/docs/data-types/bitfields.md @@ -3,7 +3,7 @@ title: "Redis bitfields" linkTitle: "Bitfields" weight: 130 description: > - Introduction to Redis bitmaps + Introduction to Redis bitfields --- Redis bitfields let you perform bitwise arithmetic on integer field of arbitrary bit length. For example, you an operate on anything from unsigned, 32-bit integers to signed 5-bit integers. From 6cbfaadf0986ca06fb707ef6b1d09aded7a86f9e Mon Sep 17 00:00:00 2001 From: Binbin Date: Mon, 15 Aug 2022 02:45:25 +0800 Subject: [PATCH 009/377] Fix outdated lfu-decay-time doc in eviction.md (#2084) Now we won't do anything on counter if lfu-decay-time is 0. --- docs/manual/eviction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/eviction.md b/docs/manual/eviction.md index cbf1372200..7887042f30 100644 --- a/docs/manual/eviction.md +++ b/docs/manual/eviction.md @@ -169,7 +169,7 @@ lfu-log-factor 10 lfu-decay-time 1 ``` -The decay time is the obvious one, it is the amount of minutes a counter should be decayed, when sampled and found to be older than that value. A special value of `0` means: always decay the counter every time is scanned, and is rarely useful. +The decay time is the obvious one, it is the amount of minutes a counter should be decayed, when sampled and found to be older than that value. A special value of `0` means: we will never decay the counter. The counter *logarithm factor* changes how many hits are needed to saturate the frequency counter, which is just in the range 0-255. The higher the factor, the more accesses are needed to reach the maximum. The lower the factor, the better is the resolution of the counter for low accesses, according to the following table: From a43dc2b146acc04e820bd5b26f7fc0a86ac320b9 Mon Sep 17 00:00:00 2001 From: Callis Ezenwaka Date: Tue, 16 Aug 2022 21:19:17 +0100 Subject: [PATCH 010/377] Fix typo in Introduction to Redis bitfields (#2083) Co-authored-by: Itamar Haber --- docs/data-types/bitfields.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/data-types/bitfields.md b/docs/data-types/bitfields.md index 87762d8e43..79cb6853a0 100644 --- a/docs/data-types/bitfields.md +++ b/docs/data-types/bitfields.md @@ -6,7 +6,8 @@ description: > Introduction to Redis bitfields --- -Redis bitfields let you perform bitwise arithmetic on integer field of arbitrary bit length. For example, you an operate on anything from unsigned, 32-bit integers to signed 5-bit integers. +Redis bitfields let you set, increment, and get integer values of arbitrary bit length. +For example, you can operate on anything from unsigned 1-bit integers to signed 63-bit integers. These values are stored using binary-encoded Redis strings. Bitfields support atomic read, write and increment operations, making them a good choice for managing counters and similar numerical values. From a06cd523d8effa54614282f7782a9b79d14fc4a8 Mon Sep 17 00:00:00 2001 From: Tempo481 <65311849+Tempo481@users.noreply.github.com> Date: Tue, 16 Aug 2022 22:20:06 +0200 Subject: [PATCH 011/377] Fixed typo (#2082) "the" shouldn't be in that sentence --- docs/getting-started/installation/install-redis-on-windows.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/installation/install-redis-on-windows.md b/docs/getting-started/installation/install-redis-on-windows.md index ef8495cfa3..b774febb22 100644 --- a/docs/getting-started/installation/install-redis-on-windows.md +++ b/docs/getting-started/installation/install-redis-on-windows.md @@ -5,7 +5,7 @@ weight: 1 description: Use Redis on Windows for development --- -Redis is not officially supported on Windows. However, you can install Redis on Windows for development by the following the instructions below. +Redis is not officially supported on Windows. However, you can install Redis on Windows for development by following the instructions below. To install Redis on Windows, you'll first need to enable [WSL2](https://docs.microsoft.com/en-us/windows/wsl/install) (Windows Subsystem for Linux). WSL2 lets you run Linux binaries natively on Windows. For this method to work, you'll need to be running Windows 10 version 2004 and higher or Windows 11. From c227910fe4daba717694598c30d192562edb9f70 Mon Sep 17 00:00:00 2001 From: chris-janidlo Date: Tue, 16 Aug 2022 15:20:46 -0500 Subject: [PATCH 012/377] Redis bitfields doc page - close out code block (#2078) --- docs/data-types/bitfields.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/data-types/bitfields.md b/docs/data-types/bitfields.md index 79cb6853a0..0643aeea71 100644 --- a/docs/data-types/bitfields.md +++ b/docs/data-types/bitfields.md @@ -44,6 +44,7 @@ You can represent these counters with one bitfield per player. > BITFIELD player:1:stats GET u32 #0 GET u32 #1 1) (integer) 51 2) (integer) 1 +``` ## Basic commands From 855640149f0fc44c64b3c3ba22ffcb344c2cead6 Mon Sep 17 00:00:00 2001 From: Roman Niukhalov Date: Wed, 17 Aug 2022 06:22:02 +1000 Subject: [PATCH 013/377] Fix incorrect link to Redis Sets Explained video (#2073) The former link points to the Redis Lists Explained video. --- docs/data-types/sets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/sets.md b/docs/data-types/sets.md index f358568fa6..81c93ca1c0 100644 --- a/docs/data-types/sets.md +++ b/docs/data-types/sets.md @@ -79,5 +79,5 @@ If you need to index and query your data, consider [RediSearch](/docs/stack/sear ## Learn more -* [Redis Sets Explained](https://www.youtube.com/watch?v=PB5SeOkkxQc) and [Redis Sets Elaborated](https://www.youtube.com/watch?v=aRw5ME_5kMY) are two short but thorough video explainers covering Redis sets. +* [Redis Sets Explained](https://www.youtube.com/watch?v=PKdCppSNTGQ) and [Redis Sets Elaborated](https://www.youtube.com/watch?v=aRw5ME_5kMY) are two short but thorough video explainers covering Redis sets. * [Redis University's RU101](https://university.redis.com/courses/ru101/) explores Redis sets in detail. From fe8335b9c48367aa5d4f79ba1df1adbd3c2eb555 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Tue, 16 Aug 2022 23:43:16 +0300 Subject: [PATCH 014/377] Adds note about lsb-release (#2051) * Adds note about lsb-release * Whitelists lsb-release * Whitelists lsb_release Co-authored-by: Yossi Gottlieb --- .../installation/install-redis-on-linux.md | 9 +++++++++ wordlist | 1 + 2 files changed, 10 insertions(+) diff --git a/docs/getting-started/installation/install-redis-on-linux.md b/docs/getting-started/installation/install-redis-on-linux.md index 95f1c07e7b..8ed07b87d8 100644 --- a/docs/getting-started/installation/install-redis-on-linux.md +++ b/docs/getting-started/installation/install-redis-on-linux.md @@ -11,6 +11,15 @@ Most major Linux distributions provide packages for Redis. ## Install on Ubuntu/Debian You can install recent stable versions of Redis from the official `packages.redis.io` APT repository. + +{{% alert title="Prerequisites" color="warning" %}} +If you're running a very minimal distribution (such as a Docker container) you may need to install `lsb-release` first: + +{{< highlight bash >}} +sudo apt install lsb-release" +{{< / highlight >}} +{{% /alert %}} + Add the repository to the apt index, update it, and then install: {{< highlight bash >}} diff --git a/wordlist b/wordlist index daff9b3159..70eaf4572c 100644 --- a/wordlist +++ b/wordlist @@ -657,6 +657,7 @@ loopback lpush lru_cache lsb_release +lsb-release lua-api lua-replicate-commands lubs From 468845e2b188265f7f7d023d2f3727522001d08d Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Thu, 18 Aug 2022 04:07:45 -0400 Subject: [PATCH 015/377] [BUG FIX] Replace HMSET with HSET in data types tutorial (#2086) --- docs/data-types/tutorial.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/data-types/tutorial.md b/docs/data-types/tutorial.md index f414c7ba8c..715ee7c6d5 100644 --- a/docs/data-types/tutorial.md +++ b/docs/data-types/tutorial.md @@ -474,8 +474,8 @@ Example of rule 3: Redis hashes look exactly how one might expect a "hash" to look, with field-value pairs: - > hmset user:1000 username antirez birthyear 1977 verified 1 - OK + > hset user:1000 username antirez birthyear 1977 verified 1 + (integer) 3 > hget user:1000 username "antirez" > hget user:1000 birthyear @@ -492,7 +492,7 @@ While hashes are handy to represent *objects*, actually the number of fields you put inside a hash has no practical limits (other than available memory), so you can use hashes in many different ways inside your application. -The command `HMSET` sets multiple fields of the hash, while `HGET` retrieves +The command `HSET` sets multiple fields of the hash, while `HGET` retrieves a single field. `HMGET` is similar to `HGET` but returns an array of values: > hmget user:1000 username birthyear no-such-field From 309f033f9cac1e795a06e69bb465721c19587b37 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Thu, 18 Aug 2022 19:04:00 +0300 Subject: [PATCH 016/377] Fixes link to stream intro (#2088) Fix #2087 --- docs/data-types/streams.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/streams.md b/docs/data-types/streams.md index d74220b319..78c3d1017d 100644 --- a/docs/data-types/streams.md +++ b/docs/data-types/streams.md @@ -76,6 +76,6 @@ See each command's time complexity for the details. ## Learn more -* The [Redis Streams Tutorial](/docs/data-types/streams-tutorial.md) explains Redis streams with many examples. +* The [Redis Streams Tutorial](/docs/data-types/streams-tutorial) explains Redis streams with many examples. * [Redis Streams Explained](https://www.youtube.com/watch?v=Z8qcpXyMAiA) is an entertaining introduction to streams in Redis. * [Redis University's RU102](https://university.redis.com/courses/ru102/) is a free, online course dedicated to Redis Streams. From e9c0a31d15a5c998f259a79513f1ee6151f4c7d3 Mon Sep 17 00:00:00 2001 From: Uzlopak Date: Sun, 21 Aug 2022 13:31:37 +0200 Subject: [PATCH 017/377] remove doublequote typo (#2089) --- docs/getting-started/installation/install-redis-on-linux.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/installation/install-redis-on-linux.md b/docs/getting-started/installation/install-redis-on-linux.md index 8ed07b87d8..d8fa005fbc 100644 --- a/docs/getting-started/installation/install-redis-on-linux.md +++ b/docs/getting-started/installation/install-redis-on-linux.md @@ -16,7 +16,7 @@ You can install recent stable versions of Redis from the official `packages.redi If you're running a very minimal distribution (such as a Docker container) you may need to install `lsb-release` first: {{< highlight bash >}} -sudo apt install lsb-release" +sudo apt install lsb-release {{< / highlight >}} {{% /alert %}} From a68e5b2d2f28e9cec9e6dcc7999d800054769a23 Mon Sep 17 00:00:00 2001 From: Aaron Roh Date: Sun, 21 Aug 2022 23:00:43 +0900 Subject: [PATCH 018/377] Modify deprecated command in reference/patterns (#2045) --- docs/reference/patterns/indexes.md | 40 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/reference/patterns/indexes.md b/docs/reference/patterns/indexes.md index be0363002c..09011bac24 100644 --- a/docs/reference/patterns/indexes.md +++ b/docs/reference/patterns/indexes.md @@ -35,7 +35,7 @@ vanilla sorted sets are limited to things where the indexing field is a number within a given range. The two commands to build these kind of indexes are `ZADD` and -`ZRANGEBYSCORE` to respectively add items and retrieve items within a +`ZRANGE` with the `BYSCORE` argument to respectively add items and retrieve items within a specified range. For instance, it is possible to index a set of person names by their @@ -50,11 +50,11 @@ person and the score will be the age. In order to retrieve all persons with an age between 20 and 40, the following command can be used: - ZRANGEBYSCORE myindex 20 40 + ZRANGE myindex 20 40 BYSCORE 1) "Manuel" 2) "Jon" -By using the **WITHSCORES** option of `ZRANGEBYSCORE` it is also possible +By using the **WITHSCORES** option of `ZRANGE` it is also possible to obtain the scores associated with the returned elements. The `ZCOUNT` command can be used in order to retrieve the number of elements @@ -62,10 +62,10 @@ within a given range, without actually fetching the elements, which is also useful, especially given the fact the operation is executed in logarithmic time regardless of the size of the range. -Ranges can be inclusive or exclusive, please refer to the `ZRANGEBYSCORE` +Ranges can be inclusive or exclusive, please refer to the `ZRANGE` command documentation for more information. -**Note**: Using the `ZREVRANGEBYSCORE` it is possible to query a range in +**Note**: Using the `ZRANGE` with the `BYSCORE` and `REV` arguments, it is possible to query a range in reversed order, which is often useful when data is indexed in a given direction (ascending or descending) but we want to retrieve information the other way around. @@ -93,7 +93,7 @@ could do: ZADD user.age.index 33 3 This time the value associated with the score in the sorted set is the -ID of the object. So once I query the index with `ZRANGEBYSCORE` I'll +ID of the object. So once I query the index with `ZRANGE` with the `BYSCORE` argument, I'll also have to retrieve the information I need with `HGETALL` or similar commands. The obvious advantage is that objects can change without touching the index, as long as we don't change the indexed field. @@ -170,7 +170,7 @@ the second is checked and so forth. If the common prefix of two strings is the same then the longer string is considered the greater of the two, so "foobar" is greater than "foo". -There are commands such as `ZRANGEBYLEX` and `ZLEXCOUNT` that +There are commands such as `ZRANGE` and `ZLEXCOUNT` that are able to query and count ranges in a lexicographically fashion, assuming they are used with sorted sets where all the elements have the same score. @@ -198,9 +198,9 @@ are ordered lexicographically. 3) "baaa" 4) "bbbb" -Now we can use `ZRANGEBYLEX` in order to perform range queries. +Now we can use `ZRANGE` with the `BYLEX` argument in order to perform range queries. - ZRANGEBYLEX myindex [a (b + ZRANGE myindex [a (b BYLEX 1) "aaaa" 2) "abbb" @@ -214,7 +214,7 @@ which are all the elements starting with `a`. There are also two more special characters indicating the infinitely negative string and the infinitely positive string, which are `-` and `+`. - ZRANGEBYLEX myindex [b + + ZRANGE myindex [b + BYLEX 1) "baaa" 2) "bbbb" @@ -235,12 +235,12 @@ we'll just do: ZADD myindex 0 banana And so forth for each search query ever encountered. Then when we want to -complete the user input, we execute a range query using `ZRANGEBYLEX`. +complete the user input, we execute a range query using `ZRANGE` with the `BYLEX` argument. Imagine the user is typing "bit" inside the search form, and we want to offer possible search keywords starting for "bit". We send Redis a command like that: - ZRANGEBYLEX myindex "[bit" "[bit\xff" + ZRANGE myindex "[bit" "[bit\xff" BYLEX Basically we create a range using the string the user is typing right now as start, and the same string plus a trailing byte set to 255, which is `\xff` in the example, as the end of the range. This way we get all the strings that start for the string the user is typing. @@ -269,7 +269,7 @@ We also need logic in order to increment the index if the search term already exists in the index, so what we'll actually do is something like that: - ZRANGEBYLEX myindex "[banana:" + LIMIT 0 1 + ZRANGE myindex "[banana:" + BYLEX LIMIT 0 1 1) "banana:1" This will return the single entry of `banana` if it exists. Then we @@ -291,7 +291,7 @@ There is more: our goal is to just have items searched very frequently. So we need some form of purging. When we actually query the index in order to complete the user input, we may see something like that: - ZRANGEBYLEX myindex "[banana:" + LIMIT 0 10 + ZRANGE myindex "[banana:" + BYLEX LIMIT 0 10 1) "banana:123" 2) "banaooo:1" 3) "banned user:49" @@ -355,7 +355,7 @@ we just store the entry as `key:value`: And search for the key with: - ZRANGEBYLEX myindex [mykey: + LIMIT 0 1 + ZRANGE myindex [mykey: + BYLEX LIMIT 0 1 1) "mykey:myvalue" Then we extract the part after the colon to retrieve the value. @@ -436,7 +436,7 @@ With an index like that, to get all the products in room 56 having a price between 10 and 30 dollars is very easy. We can just run the following command: - ZRANGEBYLEX myindex [0056:0010.00 [0056:0030.00 + ZRANGE myindex [0056:0010.00 [0056:0030.00 BYLEX The above is called a composed index. Its effectiveness depends on the order of the fields and the queries I want to run. For example the above @@ -505,7 +505,7 @@ Now things start to be interesting, and I can query the graph in many different ways. For example, who are all the people `antirez` *is friend of*? - ZRANGEBYLEX myindex "[spo:antirez:is-friend-of:" "[spo:antirez:is-friend-of:\xff" + ZRANGE myindex "[spo:antirez:is-friend-of:" "[spo:antirez:is-friend-of:\xff" BYLEX 1) "spo:antirez:is-friend-of:matteocollina" 2) "spo:antirez:is-friend-of:wonderwoman" 3) "spo:antirez:is-friend-of:spiderman" @@ -513,7 +513,7 @@ different ways. For example, who are all the people `antirez` Or, what are all the relationships `antirez` and `matteocollina` have where the first is the subject and the second is the object? - ZRANGEBYLEX myindex "[sop:antirez:matteocollina:" "[sop:antirez:matteocollina:\xff" + ZRANGE myindex "[sop:antirez:matteocollina:" "[sop:antirez:matteocollina:\xff" BYLEX 1) "sop:antirez:matteocollina:is-friend-of" 2) "sop:antirez:matteocollina:was-at-conference-with" 3) "sop:antirez:matteocollina:talked-with" @@ -672,7 +672,7 @@ Turning this into code is simple. Here is a Ruby example: y_range_end = y_range_start | ((2**exp)-1) puts "#{x},#{y} x from #{x_range_start} to #{x_range_end}, y from #{y_range_start} to #{y_range_end}" - # Turn it into interleaved form for ZRANGEBYLEX query. + # Turn it into interleaved form for ZRANGE query. # We assume we need 9 bits for each integer, so the final # interleaved representation will be 18 bits. xbin = x_range_start.to_s(2).rjust(9,'0') @@ -681,7 +681,7 @@ Turning this into code is simple. Here is a Ruby example: # Now that we have the start of the range, calculate the end # by replacing the specified number of bits from 0 to 1. e = s[0..-(bits+1)]+("1"*bits) - puts "ZRANGEBYLEX myindex [#{s} [#{e}" + puts "ZRANGE myindex [#{s} [#{e} BYLEX" } } end From 2a73d5e6a9f789248abb540155962e5f21485665 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Mon, 22 Aug 2022 19:44:31 +0300 Subject: [PATCH 019/377] Fixes link to install on linux (#2097) Fixes #2096 --- docs/getting-started/installation/install-redis-on-windows.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/installation/install-redis-on-windows.md b/docs/getting-started/installation/install-redis-on-windows.md index b774febb22..3ce2d367d0 100644 --- a/docs/getting-started/installation/install-redis-on-windows.md +++ b/docs/getting-started/installation/install-redis-on-windows.md @@ -15,7 +15,7 @@ Microsoft provides [detailed instructions for installing WSL](https://docs.micro ## Install Redis -Once you're running Ubuntu on Windows, you can follow the steps detailed at [Install on Ubuntu/Debian](install-redis-on-linux#install-on-ubuntu-debian) to install recent stable versions of Redis from the official `packages.redis.io` APT repository. +Once you're running Ubuntu on Windows, you can follow the steps detailed at [Install on Ubuntu/Debian](../install-redis-on-linux#install-on-ubuntu-debian) to install recent stable versions of Redis from the official `packages.redis.io` APT repository. Add the repository to the apt index, update it, and then install: {{< highlight bash >}} From c242cd94626cb87249294882333b7d75eab3bf1d Mon Sep 17 00:00:00 2001 From: Khonko Alex <33666699+dozer111@users.noreply.github.com> Date: Wed, 24 Aug 2022 19:00:42 +0300 Subject: [PATCH 020/377] fix link (#2099) --- docs/data-types/hyperloglogs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/hyperloglogs.md b/docs/data-types/hyperloglogs.md index 0730d5ef17..3c60947af6 100644 --- a/docs/data-types/hyperloglogs.md +++ b/docs/data-types/hyperloglogs.md @@ -47,5 +47,5 @@ The HyperLogLog can estimate the cardinality of sets with up to 18,446,744,073,7 ## Learn more -* [Redis new data structure: the HyperLogLog](https://antirez.com/news/75) has a lot of details about the data structure and its implementation in Redis. +* [Redis new data structure: the HyperLogLog](http://antirez.com/news/75) has a lot of details about the data structure and its implementation in Redis. * [Redis HyperLogLog Explained](https://www.youtube.com/watch?v=MunL8nnwscQ) shows you how to use Redis HyperLogLog data structures to build a traffic heat map. From dd658e3ad8ca34f64d4914a1ef82245878714fb0 Mon Sep 17 00:00:00 2001 From: zjybjtu Date: Sun, 28 Aug 2022 20:05:26 +0800 Subject: [PATCH 021/377] Update sorted-sets.md (#2102) modify the ` Get the top 3 players' scores ` 's code to the correct answer. --- docs/data-types/sorted-sets.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/data-types/sorted-sets.md b/docs/data-types/sorted-sets.md index 71e0d8457e..a0d017b5c7 100644 --- a/docs/data-types/sorted-sets.md +++ b/docs/data-types/sorted-sets.md @@ -33,15 +33,13 @@ Notice that `user:2`'s score is updated in the final `ZADD` call. * Get the top 3 players' scores: ``` -> ZRANGE leaderboard:455 0 4 REV WITHSCORES +> ZRANGE leaderboard:455 0 2 REV WITHSCORES 1) "user:2" 2) "275" 3) "user:3" 4) "101" 5) "user:1" 6) "100" -7) "user:4" -8) "15" ``` * What's the rank of user 2? From 377e2d7a20bb6d4ce3a20fdc2a8824b378d0fd24 Mon Sep 17 00:00:00 2001 From: Tian Date: Mon, 29 Aug 2022 14:12:08 +0800 Subject: [PATCH 022/377] fix the description about aof-write in latency monitor (#2101) summary of changes: these 4 events are measuring the same thing, in different states, they all measure `write` (not `fsync` which was stated). and the `pending-fsync` one is while there's a pending `fsync` (not `write` which was stated). in essence, fsync and write were swapped. --- docs/reference/optimization/latency-monitor.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/reference/optimization/latency-monitor.md b/docs/reference/optimization/latency-monitor.md index 6426abd617..bbb96c707d 100644 --- a/docs/reference/optimization/latency-monitor.md +++ b/docs/reference/optimization/latency-monitor.md @@ -64,11 +64,11 @@ The framework monitors and logs latency spikes in the execution time of these ev * `fast-command`: O(1) and O(log N) commands. * `fork`: the `fork(2)` system call. * `rdb-unlink-temp-file`: the `unlink(2)` system call. -* `aof-write`: writing to the AOF - a catchall event for `fsync(2)` system calls. * `aof-fsync-always`: the `fsync(2)` system call when invoked by the `appendfsync allways` policy. -* `aof-write-pending-fsync`: the `fsync(2)` system call when there are pending writes. -* `aof-write-active-child`: the `fsync(2)` system call when performed by a child process. -* `aof-write-alone`: the `fsync(2)` system call when performed by the main process. +* `aof-write`: writing to the AOF - a catchall event for `write(2)` system calls. +* `aof-write-pending-fsync`: the `write(2)` system call when there is a pending fsync. +* `aof-write-active-child`: the `write(2)` system call when there are active child processes. +* `aof-write-alone`: the `write(2)` system call when no pending fsync and no active child process. * `aof-fstat`: the `fstat(2)` system call. * `aof-rename`: the `rename(2)` system call for renaming the temporary file after completing `BGREWRITEAOF`. * `aof-rewrite-diff-write`: writing the differences accumulated while performing `BGREWRITEAOF`. From 1a847fe2247ca90dee02d933d637c543eec66503 Mon Sep 17 00:00:00 2001 From: guybe7 Date: Thu, 1 Sep 2022 14:51:47 +0300 Subject: [PATCH 023/377] Add display_text to COMMAND DOCS (#2091) --- docs/reference/command-arguments.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/reference/command-arguments.md b/docs/reference/command-arguments.md index 2c6d6d62e7..8984a23785 100644 --- a/docs/reference/command-arguments.md +++ b/docs/reference/command-arguments.md @@ -16,6 +16,10 @@ Every element in the _arguments_ array is a map with the following fields: * **name:** the argument's name, always present. The name of an argument is given for identification purposes alone. It isn't displayed during the command's syntax rendering. + The same name can appear more than once in the entire argument tree, but it is unique compared to other sibling arguments' names. + This allows obtaining a unique identifier for each argument (the concatenation of all names in the path from the root to any argument). +* **display_text:** the argument's display string, present in arguments that have a displayable representation (all arguments that aren't oneof/block). + This is the string used in the command's syntax rendering. * **type:** the argument's type, always present. An argument must have one of the following types: - **string:** a string argument. From 93c3d737f8fb10f1a6591bd9cc10080ac6ec0362 Mon Sep 17 00:00:00 2001 From: Adam Tuttle Date: Thu, 1 Sep 2022 11:07:26 -0400 Subject: [PATCH 024/377] fix a markdown link syntax issue (#2107) --- docs/data-types/sets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/sets.md b/docs/data-types/sets.md index 81c93ca1c0..76ce907a3a 100644 --- a/docs/data-types/sets.md +++ b/docs/data-types/sets.md @@ -75,7 +75,7 @@ Sets membership checks on large datasets (or on streaming data) can use a lot of If you're concerned about memory usage and don't need perfect precision, consider a [Bloom filter or Cuckoo filter](/docs/stack/bloom) as an alternative to a set. Redis sets are frequently used as a kind of index. -If you need to index and query your data, consider [RediSearch](/docs/stack/search)](/docs/stack/search) and [RedisJSON](/docs/stack/json). +If you need to index and query your data, consider [RediSearch](/docs/stack/search) and [RedisJSON](/docs/stack/json). ## Learn more From c5ae50668a563cff44c43020e1244a37b80f999e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20H=2E=20Mil=C3=A1n?= Date: Sun, 4 Sep 2022 13:39:19 +0200 Subject: [PATCH 025/377] =?UTF-8?q?Adding=20disclaimer=20about=20consisten?= =?UTF-8?q?cy=20(fencing=20tokens=20and=20ttls=20expirati=E2=80=A6=20(#210?= =?UTF-8?q?6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Itamar Haber Co-authored-by: Oran Agra --- docs/reference/patterns/distributed-locks.md | 13 +++++++++++++ wordlist | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/docs/reference/patterns/distributed-locks.md b/docs/reference/patterns/distributed-locks.md index 634f1d6065..cc8f6864b0 100644 --- a/docs/reference/patterns/distributed-locks.md +++ b/docs/reference/patterns/distributed-locks.md @@ -206,6 +206,19 @@ However this does not technically change the algorithm, so the maximum number of lock reacquisition attempts should be limited, otherwise one of the liveness properties is violated. +### Disclaimer about consistency + +Please consider thoroughly reviewing the [Analysis of Redlock](#analysis-of-redlock) section at the end of this page. +Martin Kleppman's article and antirez's answer to it are very relevant. +If you are concerned about consistency and correctness, you should pay attention to the following topics: + +1. You should implement fencing tokens. + This is especially important for processes that can take significant time and applies to any distributed locking system. + Extending locks' lifetime is also an option, but don´t assume that a lock is retained as long as the process that had acquired it is alive. +2. Redis is not using monotonic clock for TTL expiration mechanism. + That means that a wall-clock shift may result in a lock being acquired by more than one process. + Even though the problem can be mitigated by preventing admins from manually setting the server's time and setting up NTP properly, there's still a chance of this issue occurring in real life and compromising consistency. + ## Want to help? If you are into distributed systems, it would be great to have your opinion / analysis. Also reference implementations in other languages could be great. diff --git a/wordlist b/wordlist index 70eaf4572c..b72ecc84c6 100644 --- a/wordlist +++ b/wordlist @@ -934,3 +934,8 @@ zeroed-ACLs ziplists zset ˈrɛd-ɪs +NX +TTL +Kleppman's +antirez's +NTP \ No newline at end of file From 262722346075f4a0a648ab2facd8351a8f214dbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Colin=20de=20Verdi=C3=A8re?= Date: Thu, 15 Sep 2022 02:21:32 +0200 Subject: [PATCH 026/377] Fix typo on streams (#2126) A 'u' was missing --- docs/data-types/streams.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/streams.md b/docs/data-types/streams.md index 78c3d1017d..1949c832cf 100644 --- a/docs/data-types/streams.md +++ b/docs/data-types/streams.md @@ -52,7 +52,7 @@ Redis streams support several trimming strategies (to prevent streams from growi * Read up to 100 new stream entries, starting at the end of the stream, and block for up to 300 ms if no entries are being written: ``` -> XREAD COUNT 100 BLOCK 300 STREAMS tempertures:us-ny:10007 $ +> XREAD COUNT 100 BLOCK 300 STREAMS temperatures:us-ny:10007 $ (nil) ``` From 2e2ea5f10e5790dace668a88cbed87ccade478d8 Mon Sep 17 00:00:00 2001 From: HullQin Date: Thu, 15 Sep 2022 08:24:16 +0800 Subject: [PATCH 027/377] Fix unused variable warnings of example code (#2118) --- docs/manual/programmability/functions-intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/programmability/functions-intro.md b/docs/manual/programmability/functions-intro.md index 13db8877c9..5686d12852 100644 --- a/docs/manual/programmability/functions-intro.md +++ b/docs/manual/programmability/functions-intro.md @@ -228,7 +228,7 @@ end local function my_hlastmodified(keys, args) local hash = keys[1] - return redis.call('HGET', keys[1], '_last_modified_') + return redis.call('HGET', hash, '_last_modified_') end redis.register_function('my_hset', my_hset) From 8a20699c0ad072ca6d1e94ddfd22a0a001d970a9 Mon Sep 17 00:00:00 2001 From: "Victor \"Vito\" Gama" Date: Wed, 14 Sep 2022 21:25:30 -0300 Subject: [PATCH 028/377] Fix inconsistent tyPING -> typing (#2117) --- docs/manual/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/cli.md b/docs/manual/cli.md index af1b6d10df..903e411c5d 100644 --- a/docs/manual/cli.md +++ b/docs/manual/cli.md @@ -10,7 +10,7 @@ aliases: The Redis command line interface (`redis-cli`) is a terminal program used to send commands to and read replies from the Redis server. It has two main modes: an interactive Read Eval Print Loop (REPL) mode where the user types Redis commands and receives replies, and a command mode where `redis-cli` is executed with additional arguments and the reply is printed to the standard output. -In interactive mode, `redis-cli` has basic line editing capabilities to provide a familiar tyPING experience. +In interactive mode, `redis-cli` has basic line editing capabilities to provide a familiar typing experience. To launch the program in special modes, you can use several options, including: From d770e2fdec51756d45a8089c8134545f4950ed82 Mon Sep 17 00:00:00 2001 From: Shogo Hayashi Date: Sun, 18 Sep 2022 21:38:54 +0900 Subject: [PATCH 029/377] Remove duplicated explanation about backing up AOF persistence (#2129) --- docs/manual/persistence.md | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/docs/manual/persistence.md b/docs/manual/persistence.md index 54c3f29490..71c3b4d3c6 100644 --- a/docs/manual/persistence.md +++ b/docs/manual/persistence.md @@ -354,29 +354,6 @@ Prior to version 7.0.0 backing up the AOF file can be done simply by copying the but Redis will still be able to load it (see the previous sections about [truncated AOF files](#what-should-i-do-if-my-aof-gets-truncated)). -1. Turn off automatic rewrites with
- `CONFIG SET` `auto-aof-rewrite-percentage 0`
- Make sure you don't manually start a rewrite (using `BGREWRITEAOF`) during this time. -2. Check there's no current rewrite in progress using
- `INFO` `persistence`
- and verifying `aof_rewrite_in_progress` is 0. If it's 1, then you'll need to wait for the rewrite to complete. -3. Now you can safely copy the files in the `appenddirname` directory. -4. Re-enable rewrites when done:
- `CONFIG SET` `auto-aof-rewrite-percentage ` - -**Note:** If you want to minimize the time AOF rewrites are disabled you may create hard links to the files in `appenddirname` (in step 3 above) and then re-enable rewrites (step 4) after the hard links are created. -Now you can copy/tar the hardlinks and delete them when done. This works because Redis guarantees that it -only appends to files in this directory, or completely replaces them if necessary, so the content should be -consistent at any given point in time. - - -**Note:** If you want to handle the case of the server being restarted during the backup and make sure no rewrite will automatically start after the restart you can change step 1 above to also persist the updated configuration via `CONFIG REWRITE`. -Just make sure to re-enable automatic rewrites when done (step 4) and persist it with another `CONFIG REWRITE`. - -Prior to version 7.0.0 backing up the AOF file can be done simply by copying the aof file (like backing up the RDB snapshot). The file may lack the final part -but Redis will still be able to load it (see the previous sections about [truncated AOF files](#what-should-i-do-if-my-aof-gets-truncated)). - - ## Disaster recovery Disaster recovery in the context of Redis is basically the same story as From 8ed5787422b77745add940bb3b18de4402a057fb Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Sun, 18 Sep 2022 09:46:32 -0400 Subject: [PATCH 030/377] [BUG FIX] Correct default benchmark datasize (#2115) * Fixes #2105 --- docs/reference/optimization/benchmarks.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/reference/optimization/benchmarks.md b/docs/reference/optimization/benchmarks.md index 93663f249e..a4f9c28d7b 100644 --- a/docs/reference/optimization/benchmarks.md +++ b/docs/reference/optimization/benchmarks.md @@ -9,8 +9,8 @@ aliases: --- Redis includes the `redis-benchmark` utility that simulates running commands done -by N clients at the same time sending M total queries. The utility provides -a default set of tests, or a custom set of tests can be supplied. +by N clients while at the same time sending M total queries. The utility provides +a default set of tests, or you can supply a custom set of tests. The following options are supported: @@ -22,7 +22,7 @@ The following options are supported: -a Password for Redis Auth -c Number of parallel connections (default 50) -n Total number of requests (default 100000) - -d Data size of SET/GET value in bytes (default 2) + -d Data size of SET/GET value in bytes (default 3) --dbnum SELECT the specified db number (default 0) -k 1=keep alive 0=reconnect (default 1) -r Use random keys for SET/GET/INCR, random values for SADD @@ -103,7 +103,7 @@ multiple commands at once, a feature often exploited by real world applications. Redis pipelining is able to dramatically improve the number of operations per second a server is able do deliver. -This is an example of running the benchmark in a MacBook Air 11" using a +Consider this example of running the benchmark using a pipelining of 16 commands: $ redis-benchmark -n 1000000 -t set,get -P 16 -q @@ -115,8 +115,7 @@ Using pipelining results in a significant increase in performance. ### Pitfalls and misconceptions The first point is obvious: the golden rule of a useful benchmark is to -only compare apples and apples. Different versions of Redis can be compared -on the same workload for instance. Or the same version of Redis, but with +only compare apples and apples. You can compare different versions of Redis on the same workload or the same version of Redis, but with different options. If you plan to compare Redis to something else, then it is important to evaluate the functional and technical differences, and take them in account. From e0587875f8bc936e9f8815bbd26859efeba24236 Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Mon, 19 Sep 2022 16:13:00 -0400 Subject: [PATCH 031/377] Fixes #1907, updates the topic description (#2113) --- docs/reference/command-tips.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/reference/command-tips.md b/docs/reference/command-tips.md index d7ffd83e37..090c1e7e0b 100644 --- a/docs/reference/command-tips.md +++ b/docs/reference/command-tips.md @@ -2,7 +2,7 @@ title: "Redis command tips" linkTitle: "Command tips" weight: 1 -description: Programm +description: Get additional information about a command aliases: - /topics/command-tips --- @@ -20,21 +20,21 @@ However, the following sections describe proposed tips and demonstrate the conve This tip indicates that the command's output isn't deterministic. That means that calls to the command may yield different results with the same arguments and data. -That difference could be the result of the command's random nature (e.g., `RANDOMKEY` and `SPOP`); the call's timing (e.g. `TTL`); or generic differences that relate to the server's state (e.g. `INFO` and `CLIENT LIST`). +That difference could be the result of the command's random nature (e.g., `RANDOMKEY` and `SPOP`); the call's timing (e.g., `TTL`); or generic differences that relate to the server's state (e.g., `INFO` and `CLIENT LIST`). **Note:** -prior to Redis 7.0, this tip was the _random_ command flag. +Prior to Redis 7.0, this tip was the _random_ command flag. ## nondeterministic_output_order -The existence of this tip indicates that the command's output is deterministic, but its ordering is random (e.g. `HGETALL` and `SMEMBERS`). +The existence of this tip indicates that the command's output is deterministic, but its ordering is random (e.g., `HGETALL` and `SMEMBERS`). **Note:** -prior to Redis 7.0, this tip was the _sort_\__for_\__script_ flag. +Prior to Redis 7.0, this tip was the _sort_\__for_\__script_ flag. ## request_policy -This tip can help clients determine the shard(s) to send the command in clustering mode. +This tip can help clients determine the shards to send the command in clustering mode. The default behavior a client should implement for commands without the _request_policy_ tip is as follows: 1. The command doesn't accept key name arguments: the client can execute the command on an arbitrary shard. From 1e091469aa81d0eb5484a3bcff698affcf14ac32 Mon Sep 17 00:00:00 2001 From: Ning Xie Date: Tue, 20 Sep 2022 04:16:19 +0800 Subject: [PATCH 032/377] remove stale info about config get requirepass (#2111) --- docs/manual/security/acl.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/manual/security/acl.md b/docs/manual/security/acl.md index 46f3c89d0e..e341b2e87c 100644 --- a/docs/manual/security/acl.md +++ b/docs/manual/security/acl.md @@ -491,9 +491,6 @@ examples, for the sake of brevity, the long hex string was trimmed: 11) "selectors" 12) (empty array) -Also, starting with Redis 6, the old command `CONFIG GET requirepass` will -no longer return the clear text password, but instead the hashed password. - Using SHA256 provides the ability to avoid storing the password in clear text while still allowing for a very fast `AUTH` command, which is a very important feature of Redis and is coherent with what clients expect from Redis. From d9dffd8efa821a86bdb8f7e85f602b1ba2a739c3 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Mon, 19 Sep 2022 23:17:29 +0300 Subject: [PATCH 033/377] Adds a note about ping errors (#2104) --- commands/ping.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/commands/ping.md b/commands/ping.md index c16f760e2f..1667e1eab5 100644 --- a/commands/ping.md +++ b/commands/ping.md @@ -1,7 +1,9 @@ Returns `PONG` if no argument is provided, otherwise return a copy of the argument as a bulk. -This command is often used to test if a connection is still alive, or to measure -latency. +This command is useful for: +1. Testing whether a connection is still alive. +1. Verifying the server's ability to serve data - an error is returned when this isn't the case (e.g., during load from persistence or accessing a stale replica). +1. Measuring latency. If the client is subscribed to a channel or a pattern, it will instead return a multi-bulk with a "pong" in the first position and an empty bulk in the second From b8943b2959cf2e7669cd8d8a97e2dbead9786aff Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Mon, 19 Sep 2022 16:32:09 -0400 Subject: [PATCH 034/377] [BUG FIX] Update XGROUP CREATECONSUMER about stream data presence (#2094) --- commands/xgroup-createconsumer.md | 1 + 1 file changed, 1 insertion(+) diff --git a/commands/xgroup-createconsumer.md b/commands/xgroup-createconsumer.md index 17274a5eab..3b27b1d123 100644 --- a/commands/xgroup-createconsumer.md +++ b/commands/xgroup-createconsumer.md @@ -1,6 +1,7 @@ Create a consumer named `` in the consumer group `` of the stream that's stored at ``. Consumers are also created automatically whenever an operation, such as `XREADGROUP`, references a consumer that doesn't exist. +This is valid for `XREADGROUP` only when there is data in the stream. @return From 906833551c5631f9ad1d3ed145d313905cbc7d36 Mon Sep 17 00:00:00 2001 From: slurpsmcgoo <39334972+slurpsmcgoo@users.noreply.github.com> Date: Mon, 19 Sep 2022 16:34:48 -0400 Subject: [PATCH 035/377] Fix broken link to Redis Streams Tutorial (#2074) removed .md in link path From e50ea1872e4efaf2a7174700050b7ce1c47dc2a8 Mon Sep 17 00:00:00 2001 From: Oran Agra Date: Thu, 22 Sep 2022 08:09:50 +0300 Subject: [PATCH 036/377] updated for commands.json from redis 7.0.5 (#2132) corresponding to: Remove the NONDETERMINISTIC_OUTPUT flag from most CLUSTER sub-commands. redis#11157 Replaces "capital-case" with "uppercase" in GEO commands history notes redis#11169 Adds historical note about lower-case geo units support redis#11162 Fix wrong commands json docs for CLIENT KILL redis#10970 fixed complexity of bzmpop and zmpop commands redis#11026 Adds LASTID to XCLAIM docs redis#11017 Fix EVALSHA_RO and EVAL_RO command json file redis#11015 Add optional for FCALL and FCALL_RO command json file redis#10988 --- commands.json | 229 +++++++++++++++++++++++++------------------------- 1 file changed, 115 insertions(+), 114 deletions(-) diff --git a/commands.json b/commands.json index 978e128f5b..7f73e43599 100644 --- a/commands.json +++ b/commands.json @@ -1302,7 +1302,7 @@ "summary": "Remove and return members with scores in a sorted set or block until one is available", "since": "7.0.0", "group": "sorted-set", - "complexity": "O(K) + O(N*log(M)) where K is the number of provided keys, N being the number of elements in the sorted set, and M being the number of elements popped.", + "complexity": "O(K) + O(M*log(N)) where K is the number of provided keys, N being the number of elements in the sorted set, and M being the number of elements popped.", "acl_categories": [ "@write", "@sortedset", @@ -1653,77 +1653,90 @@ "arity": -3, "arguments": [ { - "name": "ip:port", - "type": "string", - "optional": true - }, - { - "name": "client-id", - "type": "integer", - "token": "ID", - "since": "2.8.12", - "optional": true - }, - { - "name": "normal_master_slave_pubsub", + "name": "filter", "type": "oneof", - "token": "TYPE", - "since": "2.8.12", - "optional": true, "arguments": [ { - "name": "normal", - "type": "pure-token", - "token": "NORMAL" - }, - { - "name": "master", - "type": "pure-token", - "token": "MASTER", - "since": "3.2.0" - }, - { - "name": "slave", - "type": "pure-token", - "token": "SLAVE" - }, - { - "name": "replica", - "type": "pure-token", - "token": "REPLICA", - "since": "5.0.0" + "name": "ip:port", + "type": "string", + "deprecated_since": "2.8.12" }, { - "name": "pubsub", - "type": "pure-token", - "token": "PUBSUB" + "name": "new-format", + "type": "oneof", + "multiple": true, + "arguments": [ + { + "name": "client-id", + "type": "integer", + "token": "ID", + "since": "2.8.12", + "optional": true + }, + { + "name": "normal_master_slave_pubsub", + "type": "oneof", + "token": "TYPE", + "since": "2.8.12", + "optional": true, + "arguments": [ + { + "name": "normal", + "type": "pure-token", + "token": "NORMAL" + }, + { + "name": "master", + "type": "pure-token", + "token": "MASTER", + "since": "3.2.0" + }, + { + "name": "slave", + "type": "pure-token", + "token": "SLAVE" + }, + { + "name": "replica", + "type": "pure-token", + "token": "REPLICA", + "since": "5.0.0" + }, + { + "name": "pubsub", + "type": "pure-token", + "token": "PUBSUB" + } + ] + }, + { + "name": "username", + "type": "string", + "token": "USER", + "optional": true + }, + { + "name": "ip:port", + "type": "string", + "token": "ADDR", + "optional": true + }, + { + "name": "ip:port", + "type": "string", + "token": "LADDR", + "since": "6.2.0", + "optional": true + }, + { + "name": "yes/no", + "type": "string", + "token": "SKIPME", + "optional": true + } + ] } ] - }, - { - "name": "username", - "type": "string", - "token": "USER", - "optional": true - }, - { - "name": "ip:port", - "type": "string", - "token": "ADDR", - "optional": true - }, - { - "name": "ip:port", - "type": "string", - "token": "LADDR", - "since": "6.2.0", - "optional": true - }, - { - "name": "yes/no", - "type": "string", - "token": "SKIPME", - "optional": true } ], "command_flags": [ @@ -2142,9 +2155,6 @@ "admin", "stale", "no_async_loading" - ], - "hints": [ - "nondeterministic_output" ] }, "CLUSTER ADDSLOTSRANGE": { @@ -2179,9 +2189,6 @@ "admin", "stale", "no_async_loading" - ], - "hints": [ - "nondeterministic_output" ] }, "CLUSTER BUMPEPOCH": { @@ -2246,9 +2253,6 @@ ], "command_flags": [ "stale" - ], - "hints": [ - "nondeterministic_output" ] }, "CLUSTER DELSLOTS": { @@ -2273,9 +2277,6 @@ "admin", "stale", "no_async_loading" - ], - "hints": [ - "nondeterministic_output" ] }, "CLUSTER DELSLOTSRANGE": { @@ -2310,9 +2311,6 @@ "admin", "stale", "no_async_loading" - ], - "hints": [ - "nondeterministic_output" ] }, "CLUSTER FAILOVER": { @@ -2349,9 +2347,6 @@ "admin", "stale", "no_async_loading" - ], - "hints": [ - "nondeterministic_output" ] }, "CLUSTER FLUSHSLOTS": { @@ -2369,9 +2364,6 @@ "admin", "stale", "no_async_loading" - ], - "hints": [ - "nondeterministic_output" ] }, "CLUSTER FORGET": { @@ -2395,9 +2387,6 @@ "admin", "stale", "no_async_loading" - ], - "hints": [ - "nondeterministic_output" ] }, "CLUSTER GETKEYSINSLOT": { @@ -2473,9 +2462,6 @@ ], "command_flags": [ "stale" - ], - "hints": [ - "nondeterministic_output" ] }, "CLUSTER LINKS": { @@ -2531,9 +2517,6 @@ "admin", "stale", "no_async_loading" - ], - "hints": [ - "nondeterministic_output" ] }, "CLUSTER MYID": { @@ -2547,9 +2530,6 @@ "arity": 2, "command_flags": [ "stale" - ], - "hints": [ - "nondeterministic_output" ] }, "CLUSTER NODES": { @@ -2614,9 +2594,6 @@ "admin", "stale", "no_async_loading" - ], - "hints": [ - "nondeterministic_output" ] }, "CLUSTER RESET": { @@ -2653,9 +2630,6 @@ "admin", "noscript", "stale" - ], - "hints": [ - "nondeterministic_output" ] }, "CLUSTER SAVECONFIG": { @@ -2673,9 +2647,6 @@ "admin", "stale", "no_async_loading" - ], - "hints": [ - "nondeterministic_output" ] }, "CLUSTER SET-CONFIG-EPOCH": { @@ -2699,9 +2670,6 @@ "admin", "stale", "no_async_loading" - ], - "hints": [ - "nondeterministic_output" ] }, "CLUSTER SETSLOT": { @@ -2751,9 +2719,6 @@ "admin", "stale", "no_async_loading" - ], - "hints": [ - "nondeterministic_output" ] }, "CLUSTER SHARDS": { @@ -3667,11 +3632,13 @@ "name": "key", "type": "key", "key_spec_index": 0, + "optional": true, "multiple": true }, { "name": "arg", "type": "string", + "optional": true, "multiple": true } ], @@ -3728,11 +3695,13 @@ "name": "key", "type": "key", "key_spec_index": 0, + "optional": true, "multiple": true }, { "name": "arg", "type": "string", + "optional": true, "multiple": true } ], @@ -4118,11 +4087,13 @@ "name": "key", "type": "key", "key_spec_index": 0, + "optional": true, "multiple": true }, { "name": "arg", "type": "string", + "optional": true, "multiple": true } ], @@ -4178,11 +4149,13 @@ "name": "key", "type": "key", "key_spec_index": 0, + "optional": true, "multiple": true }, { "name": "arg", "type": "string", + "optional": true, "multiple": true } ], @@ -4828,6 +4801,10 @@ [ "6.2.0", "Added the `ANY` option for `COUNT`." + ], + [ + "7.0.0", + "Added support for uppercase unit names." ] ], "acl_categories": [ @@ -5023,6 +5000,12 @@ "complexity": "O(N+log(M)) where N is the number of elements inside the bounding box of the circular area delimited by center and radius and M is the number of items inside the index.", "deprecated_since": "6.2.0", "replaced_by": "`GEOSEARCH` and `GEOSEARCHSTORE` with the `BYRADIUS` and `FROMMEMBER` arguments", + "history": [ + [ + "7.0.0", + "Added support for uppercase unit names." + ] + ], "acl_categories": [ "@write", "@geo", @@ -5488,6 +5471,12 @@ "since": "6.2.0", "group": "geo", "complexity": "O(N+log(M)) where N is the number of elements in the grid-aligned bounding box area around the shape provided as the filter and M is the number of items inside the shape", + "history": [ + [ + "7.0.0", + "Added support for uppercase unit names." + ] + ], "acl_categories": [ "@read", "@geo", @@ -5693,6 +5682,12 @@ "since": "6.2.0", "group": "geo", "complexity": "O(N+log(M)) where N is the number of elements in the grid-aligned bounding box area around the shape provided as the filter and M is the number of items inside the shape", + "history": [ + [ + "7.0.0", + "Added support for uppercase unit names." + ] + ], "acl_categories": [ "@write", "@geo", @@ -13801,6 +13796,12 @@ "type": "pure-token", "token": "JUSTID", "optional": true + }, + { + "name": "id", + "type": "string", + "token": "LASTID", + "optional": true } ], "command_flags": [ @@ -15645,7 +15646,7 @@ "summary": "Remove and return members with scores in a sorted set", "since": "7.0.0", "group": "sorted-set", - "complexity": "O(K) + O(N*log(M)) where K is the number of provided keys, N being the number of elements in the sorted set, and M being the number of elements popped.", + "complexity": "O(K) + O(M*log(N)) where K is the number of provided keys, N being the number of elements in the sorted set, and M being the number of elements popped.", "acl_categories": [ "@write", "@sortedset", From 55cff0176c97d6f89731662b7852f9ba457702df Mon Sep 17 00:00:00 2001 From: Binbin Date: Thu, 22 Sep 2022 20:35:46 +0800 Subject: [PATCH 037/377] Fix CLUSTER SHARDS output example (#2131) Replace output example with the latest output of the current CLUSTER SHARDS. The cluster is created with redis utils/create-cluster --- commands/cluster-shards.md | 146 ++++++++++++++++++++----------------- 1 file changed, 79 insertions(+), 67 deletions(-) diff --git a/commands/cluster-shards.md b/commands/cluster-shards.md index bca6d1c13f..bcafe027fd 100644 --- a/commands/cluster-shards.md +++ b/commands/cluster-shards.md @@ -14,7 +14,7 @@ The command returns an array of shards, with each shard containing two fields, ' The 'slots' field is a list of slot ranges served by this shard, stored as pair of integers representing the inclusive start and end slots of the ranges. For example, if a node owns the slots 1, 2, 3, 5, 7, 8 and 9, the slots ranges would be stored as [1-3], [5-5], [7-9]. -The slots field would therefor be represented by the following list of integers. +The slots field would therefore be represented by the following list of integers. ``` 1) 1) "slots" @@ -55,99 +55,111 @@ Which endpoint is set is determined by the `cluster-preferred-endpoint-type` con ``` > CLUSTER SHARDS 1) 1) "slots" - 2) 1) (integer) 10923 - 2) (integer) 11110 - 3) (integer) 11113 - 4) (integer) 16111 - 5) (integer) 16113 - 6) (integer) 16383 + 2) 1) (integer) 0 + 2) (integer) 5460 3) "nodes" 4) 1) 1) "id" - 2) "71f058078c142a73b94767a4e78e9033d195dfb4" + 2) "e10b7051d6bf2d5febd39a2be297bbaea6084111" 3) "port" - 4) (integer) 6381 + 4) (integer) 30001 5) "ip" 6) "127.0.0.1" - 7) "role" - 8) "primary" - 9) "replication-offset" - 10) (integer) 1500 - 11) "health" - 12) "online" + 7) "endpoint" + 8) "127.0.0.1" + 9) "hostname" + 10) "" + 11) "role" + 12) "master" + 13) "replication-offset" + 14) (integer) 72156 + 15) "health" + 16) "online" 2) 1) "id" - 2) "1461967c62eab0e821ed54f2c98e594fccfd8736" + 2) "1901f5962d865341e81c85f9f596b1e7160c35ce" 3) "port" - 4) (integer) 7381 + 4) (integer) 30006 5) "ip" 6) "127.0.0.1" - 7) "role" - 8) "replica" - 9) "replication-offset" - 10) (integer) 700 - 11) "health" - 12) "fail" + 7) "endpoint" + 8) "127.0.0.1" + 9) "hostname" + 10) "" + 11) "role" + 12) "replica" + 13) "replication-offset" + 14) (integer) 72156 + 15) "health" + 16) "online" 2) 1) "slots" - 2) 1) (integer) 5461 - 2) (integer) 10922 + 2) 1) (integer) 10923 + 2) (integer) 16383 3) "nodes" 4) 1) 1) "id" - 2) "9215e30cd4a71070088778080565de6ef75fd459" + 2) "fd20502fe1b32fc32c15b69b0a9537551f162f1f" 3) "port" - 4) (integer) 6380 + 4) (integer) 30003 5) "ip" 6) "127.0.0.1" - 7) "role" - 8) "primary" - 9) "replication-offset" - 10) (integer) 1200 - 11) "health" - 12) "online" + 7) "endpoint" + 8) "127.0.0.1" + 9) "hostname" + 10) "" + 11) "role" + 12) "master" + 13) "replication-offset" + 14) (integer) 72156 + 15) "health" + 16) "online" 2) 1) "id" - 2) "877fa59da72cb902d0563d3d8def3437fc3a0196" + 2) "6daa25c08025a0c7e4cc0d1ab255949ce6cee902" 3) "port" - 4) (integer) 7380 + 4) (integer) 30005 5) "ip" 6) "127.0.0.1" - 7) "role" - 8) "replica" - 9) "replication-offset" - 10) (integer) 1100 - 11) "health" - 12) "loading" + 7) "endpoint" + 8) "127.0.0.1" + 9) "hostname" + 10) "" + 11) "role" + 12) "replica" + 13) "replication-offset" + 14) (integer) 72156 + 15) "health" + 16) "online" 3) 1) "slots" - 2) 1) (integer) 0 - 2) (integer) 5460 - 3) (integer) 11111 - 4) (integer) 11112 - 3) (integer) 16112 - 4) (integer) 16112 + 2) 1) (integer) 5461 + 2) (integer) 10922 3) "nodes" 4) 1) 1) "id" - 2) "b7e9acc0def782aabe6b596f67f06c73c2ffff93" + 2) "a4a3f445ead085eb3eb9ee7d8c644ec4481ec9be" 3) "port" - 4) (integer) 7379 + 4) (integer) 30002 5) "ip" 6) "127.0.0.1" - 7) "hostname" - 8) "example.com" - 9) "role" - 10) "replica" - 11) "replication-offset" - 12) "primary" - 13) "health" - 14) "online" + 7) "endpoint" + 8) "127.0.0.1" + 9) "hostname" + 10) "" + 11) "role" + 12) "master" + 13) "replication-offset" + 14) (integer) 72156 + 15) "health" + 16) "online" 2) 1) "id" - 2) "e2acf1a97c055fd09dcc2c0dcc62b19a6905dbc8" + 2) "da6d5847aa019e9b9d2a8aa24a75f856fd3456cc" 3) "port" - 4) (integer) 6379 + 4) (integer) 30004 5) "ip" 6) "127.0.0.1" - 7) "hostname" - 8) "example.com" - 9) "role" - 10) "replica" - 11) "replication-offset" - 12) (integer) 0 - 13) "health" - 14) "loading" + 7) "endpoint" + 8) "127.0.0.1" + 9) "hostname" + 10) "" + 11) "role" + 12) "replica" + 13) "replication-offset" + 14) (integer) 72156 + 15) "health" + 16) "online" ``` \ No newline at end of file From da47abe30d8c15bd24a7a0d72246e565082a65dd Mon Sep 17 00:00:00 2001 From: Manoj Chandrashekar Date: Thu, 22 Sep 2022 16:16:55 +0200 Subject: [PATCH 038/377] Correct docs (#2071) * Update redis-om-node.json Incorrect name for the library. (Python --> Node.js) * Update libraries/typescript/github.com/redis/redis-om-node.json Co-authored-by: Binbin --- libraries/typescript/github.com/redis/redis-om-node.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/typescript/github.com/redis/redis-om-node.json b/libraries/typescript/github.com/redis/redis-om-node.json index 538cd8b23f..544fae76a0 100644 --- a/libraries/typescript/github.com/redis/redis-om-node.json +++ b/libraries/typescript/github.com/redis/redis-om-node.json @@ -1,5 +1,5 @@ { - "name": "Redis OM for Python", - "description": "Object mapping, and more, for Redis and Node.js.", + "name": "Redis OM for Node.js", + "description": "Object mapping, and more, for Redis and Node.js. Written in TypeScript.", "recommended": true -} \ No newline at end of file +} From 26613ac0282e5ceebda2dacaa0a0247b6d1e117e Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Fri, 23 Sep 2022 00:29:25 +1000 Subject: [PATCH 039/377] Add Deno language, redis module and r2d2 module (#2062) --- clients/deno/github.com/denodrivers/redis.json | 4 ++++ clients/deno/github.com/iuioiua/r2d2.json | 4 ++++ languages.json | 1 + 3 files changed, 9 insertions(+) create mode 100644 clients/deno/github.com/denodrivers/redis.json create mode 100644 clients/deno/github.com/iuioiua/r2d2.json diff --git a/clients/deno/github.com/denodrivers/redis.json b/clients/deno/github.com/denodrivers/redis.json new file mode 100644 index 0000000000..36ee3007f2 --- /dev/null +++ b/clients/deno/github.com/denodrivers/redis.json @@ -0,0 +1,4 @@ +{ + "name": "redis", + "description": "🦕 Redis client for Deno 🍕" +} diff --git a/clients/deno/github.com/iuioiua/r2d2.json b/clients/deno/github.com/iuioiua/r2d2.json new file mode 100644 index 0000000000..636cd2f05e --- /dev/null +++ b/clients/deno/github.com/iuioiua/r2d2.json @@ -0,0 +1,4 @@ +{ + "name": "r2d2", + "description": "Fast, lightweight Redis client library for Deno." +} \ No newline at end of file diff --git a/languages.json b/languages.json index d7a8b26be0..b201a3bbca 100644 --- a/languages.json +++ b/languages.json @@ -12,6 +12,7 @@ "D": "d", "Dart": "dart", "Delphi": "delphi", + "Deno": "deno", "Elixir": "elixir", "emacs lisp": "emacs-lisp", "Erlang": "erlang", From 72a4944bb94168350655eb37093ea1cb20bae4e5 Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Thu, 22 Sep 2022 10:32:25 -0400 Subject: [PATCH 040/377] Add redis-rope to the community modules list (#2058) --- modules/community/github.com/ekzhang/redis-rope.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 modules/community/github.com/ekzhang/redis-rope.json diff --git a/modules/community/github.com/ekzhang/redis-rope.json b/modules/community/github.com/ekzhang/redis-rope.json new file mode 100644 index 0000000000..ef387bfc47 --- /dev/null +++ b/modules/community/github.com/ekzhang/redis-rope.json @@ -0,0 +1,8 @@ +{ + "name": "redis-rope", + "license": "MIT", + "description": "A native data type for manipulating large strings up to exponentially faster, based on splay trees.", + "github": [ + "ekzhang" + ] +} \ No newline at end of file From cd4a1dcc045a7fb13f82bcb6d4fb3e6c8f8d8a9f Mon Sep 17 00:00:00 2001 From: Taishi Kasuga Date: Thu, 22 Sep 2022 14:36:03 +0000 Subject: [PATCH 041/377] Add redis-client and redis-cluster-client to Ruby clients (#2041) --- clients/ruby/github.com/redis-rb/redis-client.json | 4 ++++ clients/ruby/github.com/redis-rb/redis-cluster-client.json | 4 ++++ clients/ruby/github.com/redis/redis-clustering.json | 4 ++++ 3 files changed, 12 insertions(+) create mode 100644 clients/ruby/github.com/redis-rb/redis-client.json create mode 100644 clients/ruby/github.com/redis-rb/redis-cluster-client.json create mode 100644 clients/ruby/github.com/redis/redis-clustering.json diff --git a/clients/ruby/github.com/redis-rb/redis-client.json b/clients/ruby/github.com/redis-rb/redis-client.json new file mode 100644 index 0000000000..06eb81aca8 --- /dev/null +++ b/clients/ruby/github.com/redis-rb/redis-client.json @@ -0,0 +1,4 @@ +{ + "name": "redis-client", + "description": "Simple low level client for Redis 6+" +} diff --git a/clients/ruby/github.com/redis-rb/redis-cluster-client.json b/clients/ruby/github.com/redis-rb/redis-cluster-client.json new file mode 100644 index 0000000000..bed2139126 --- /dev/null +++ b/clients/ruby/github.com/redis-rb/redis-cluster-client.json @@ -0,0 +1,4 @@ +{ + "name": "redis-cluster-client", + "description": "A simple client for Redis 6+ cluster" +} diff --git a/clients/ruby/github.com/redis/redis-clustering.json b/clients/ruby/github.com/redis/redis-clustering.json new file mode 100644 index 0000000000..0857ad5c33 --- /dev/null +++ b/clients/ruby/github.com/redis/redis-clustering.json @@ -0,0 +1,4 @@ +{ + "name": "redis-clustering", + "description": "A Ruby client that tries to match Redis' Cluster API one-to-one, while still providing an idiomatic interface." +} From cd350e122fe210dbaaacad26b3bb1822f7331989 Mon Sep 17 00:00:00 2001 From: tzongw Date: Thu, 22 Sep 2022 22:38:30 +0800 Subject: [PATCH 042/377] redis-timer module (#2026) --- modules/community/github.com/tzongw/redis-timer.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 modules/community/github.com/tzongw/redis-timer.json diff --git a/modules/community/github.com/tzongw/redis-timer.json b/modules/community/github.com/tzongw/redis-timer.json new file mode 100644 index 0000000000..da65c77f17 --- /dev/null +++ b/modules/community/github.com/tzongw/redis-timer.json @@ -0,0 +1,8 @@ +{ + "name": "redis-timer", + "license": "MIT", + "description": "A module allows the delayed execution of LUA scripts, both periodic and one-time, supports replication and cluster.", + "github": [ + "tzongw" + ] +} From f341d112e6ca00103b356b27d4f7519fcbc3ebaa Mon Sep 17 00:00:00 2001 From: Ryo Nakamura Date: Fri, 23 Sep 2022 22:56:28 +0900 Subject: [PATCH 043/377] Update cli.md for typo fix (#2134) --- docs/manual/cli.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/manual/cli.md b/docs/manual/cli.md index 903e411c5d..760c1f9160 100644 --- a/docs/manual/cli.md +++ b/docs/manual/cli.md @@ -29,7 +29,7 @@ To run a Redis command and return a standard output at the terminal, include the The reply of the command is "7". Since Redis replies are typed (strings, arrays, integers, nil, errors, etc.), you see the type of the reply between parentheses. This additional information may not be ideal when the output of `redis-cli` must be used as input of another command or redirected into a file. -`redis-cli` only shows additional information for human readibility when it detects the standard output is a tty, or terminal. For all other outputs it will auto-enable the *raw output mode*, as in the following example: +`redis-cli` only shows additional information for human readability when it detects the standard output is a tty, or terminal. For all other outputs it will auto-enable the *raw output mode*, as in the following example: $ redis-cli INCR mycounter > /tmp/output.txt $ cat /tmp/output.txt @@ -261,7 +261,7 @@ In interactive mode the user types Redis commands at the prompt. The command is sent to the server, processed, and the reply is parsed back and rendered into a simpler form to read. -Nothing special is needed for running the `redis-cli`in interactive mode - +Nothing special is needed for running the `redis-cli` in interactive mode - just execute it without any arguments $ redis-cli From c34d7ede7f4362735b114a2c4f6d087d36d8af3e Mon Sep 17 00:00:00 2001 From: Kyle Banker Date: Tue, 27 Sep 2022 10:46:50 -0600 Subject: [PATCH 044/377] Fix section 7 'notification' (#2136) --- docs/about/trademark.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/about/trademark.md b/docs/about/trademark.md index e57d6832ed..5fa1fce213 100644 --- a/docs/about/trademark.md +++ b/docs/about/trademark.md @@ -49,6 +49,6 @@ or Logo other than as expressly described as permitted herein is not permitted b * b. Capitalization. Always distinguish the Mark from surrounding text with at least initial capital letters or in all capital letters, (e.g., as Redis or REDIS). * c. Adjective. Always use the Mark as an adjective modifying a noun, such as “the Redis software.” * d. Do not make any changes to the Logo. This means you may not add decorative elements, change the colors, change the proportions, distort it, add elements or combine it with other logos. -7. **NOTIFY US OF ABUSE.** Do not make any changes to the Logo. This means you may not add decorative elements, change the colors, change the proportions, distort it, add elements or combine it with other logos. +7. **NOTIFY US OF ABUSE.** Please notify Redis at [legal@redis.com](mailto:legal@redis.com) if you discover any violations of these guidelines. 8. **MORE QUESTIONS?** If you have questions about this policy, or wish to request a license for any uses that are not specifically authorized in this policy, please contact us at legal@redis.com. From be2c2c26ea4fe56f6f84ed753272a064416714e4 Mon Sep 17 00:00:00 2001 From: SK <78915702+sskserk@users.noreply.github.com> Date: Wed, 28 Sep 2022 11:47:37 +0200 Subject: [PATCH 045/377] Update gopher.md (#2137) --- docs/reference/gopher.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/gopher.md b/docs/reference/gopher.md index 211d65b767..92a25e2136 100644 --- a/docs/reference/gopher.md +++ b/docs/reference/gopher.md @@ -7,7 +7,7 @@ aliases: - /topics/gopher --- -** Note: Support for Gopher was removed is Redis 7.0 ** +** Note: Support for Gopher was removed in Redis 7.0 ** Redis contains an implementation of the Gopher protocol, as specified in the [RFC 1436](https://www.ietf.org/rfc/rfc1436.txt). From 65efcb9ceb5149c332f749490e759aa7f613a768 Mon Sep 17 00:00:00 2001 From: aradz44 <112960166+aradz44@users.noreply.github.com> Date: Sun, 2 Oct 2022 11:11:39 +0300 Subject: [PATCH 046/377] Update info.md Adding 4 new fields to the STATS section : acl_access_denied_auth acl_access_denied_cmd acl_access_denied_key acl_access_denied_channel to get stats of ACL failuers. --- commands/info.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/commands/info.md b/commands/info.md index be9b318593..d507f41d20 100644 --- a/commands/info.md +++ b/commands/info.md @@ -305,6 +305,10 @@ Here is the meaning of all fields in the **stats** section: * `total_writes_processed`: Total number of write events processed * `io_threaded_reads_processed`: Number of read events processed by the main and I/O threads * `io_threaded_writes_processed`: Number of write events processed by the main and I/O threads +* `acl_access_denied_auth`: Number of AUTH authentication failures +* `acl_access_denied_cmd`: Number of ACL denied accesses to run a command +* `acl_access_denied_key`: Number of ACL denied accesses to a key +* `acl_access_denied_channel`: Number of ACL denied accesses to a channel Here is the meaning of all fields in the **replication** section: From a9ccc6eb2c04f78fe0c0d553c03816b29c2622e2 Mon Sep 17 00:00:00 2001 From: aradz44 <112960166+aradz44@users.noreply.github.com> Date: Sun, 2 Oct 2022 22:24:34 +0300 Subject: [PATCH 047/377] Update info.md --- commands/info.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/info.md b/commands/info.md index d507f41d20..36292d49c8 100644 --- a/commands/info.md +++ b/commands/info.md @@ -305,7 +305,7 @@ Here is the meaning of all fields in the **stats** section: * `total_writes_processed`: Total number of write events processed * `io_threaded_reads_processed`: Number of read events processed by the main and I/O threads * `io_threaded_writes_processed`: Number of write events processed by the main and I/O threads -* `acl_access_denied_auth`: Number of AUTH authentication failures +* `acl_access_denied_auth`: Number of authentication failures * `acl_access_denied_cmd`: Number of ACL denied accesses to run a command * `acl_access_denied_key`: Number of ACL denied accesses to a key * `acl_access_denied_channel`: Number of ACL denied accesses to a channel From 532b74a9b6ddaa6a06a611c8147d2e8b0fa9488c Mon Sep 17 00:00:00 2001 From: Kyle Banker Date: Sun, 2 Oct 2022 21:57:17 -0600 Subject: [PATCH 048/377] Fix community page (naming issue with hugo) (#2145) * Update community page so that we can support additional pages under /community --- community/{index.md => _index.md} | 4 ++++ wordlist | 14 ++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) rename community/{index.md => _index.md} (97%) diff --git a/community/index.md b/community/_index.md similarity index 97% rename from community/index.md rename to community/_index.md index f496a29bd4..19f09a3865 100644 --- a/community/index.md +++ b/community/_index.md @@ -64,3 +64,7 @@ For larger doc changes, we ask that you first create an issue describing your pr ### Client libraries The Redis client libraries are nearly always open source and accepting of contributions. Consult the contribution guidelines for the library you're interested in. + +### Hacktoberfest + +Redis is participating in [Hacktoberfest 2022](/community/hacktoberfest/). diff --git a/wordlist b/wordlist index b72ecc84c6..e9c351c4af 100644 --- a/wordlist +++ b/wordlist @@ -158,6 +158,7 @@ HLLs HMAC-SHA256 HVM HW +Hacktoberfest Hardcoded HashMaps HashSets @@ -186,6 +187,7 @@ Jemalloc KEYSPACE Keyspace KeyspaceNotification +Kleppman's Kleppmann L3 LDB @@ -224,7 +226,9 @@ NFS NIC NICs NOOP +NTP NUMA +NX NaN Nehalem NoSQL @@ -361,6 +365,7 @@ T2 TCL TCP TLS +TTL TTLs Tthe Twemproxy @@ -408,6 +413,7 @@ allocator's allocators analytics antirez +antirez's aof aof-1 aof-2 @@ -580,6 +586,7 @@ getkeys-api github globals gpg +hacktoberfest handleClientsWithPendingWrites hardcoded hardlinks @@ -656,8 +663,8 @@ lookups loopback lpush lru_cache -lsb_release lsb-release +lsb_release lua-api lua-replicate-commands lubs @@ -934,8 +941,3 @@ zeroed-ACLs ziplists zset ˈrɛd-ɪs -NX -TTL -Kleppman's -antirez's -NTP \ No newline at end of file From e2673dd6f9b458280f0df5956321a57c5dd984f8 Mon Sep 17 00:00:00 2001 From: Brian Evans <53117772+mrbrianevans@users.noreply.github.com> Date: Tue, 4 Oct 2022 15:09:47 +0100 Subject: [PATCH 049/377] Doc: fix grammer error (#2123) --- docs/data-types/sorted-sets.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data-types/sorted-sets.md b/docs/data-types/sorted-sets.md index a0d017b5c7..d7049f94b9 100644 --- a/docs/data-types/sorted-sets.md +++ b/docs/data-types/sorted-sets.md @@ -52,8 +52,8 @@ Notice that `user:2`'s score is updated in the final `ZADD` call. * `ZADD` adds a new member and associated score to a sorted set. If the member already exists, the score is updated. * `ZRANGE` returns members of a sorted set, sorted within a given range. -* `ZRANK` returns the rank the provided member, assuming the sorted is in ascending order. -* `ZREVRANK` returns the rank the provided member, assuming the sorted set is in descending order. +* `ZRANK` returns the rank of the provided member, assuming the sorted is in ascending order. +* `ZREVRANK` returns the rank of the provided member, assuming the sorted set is in descending order. See the [complete list of sorted set commands](https://redis.io/commands/?group=sorted-set). From 28fbee28e9c3d392639b6db4daf4736058aafecd Mon Sep 17 00:00:00 2001 From: Zvi Rosenfeld <50112103+ZviRosenfeld@users.noreply.github.com> Date: Tue, 4 Oct 2022 19:52:22 +0300 Subject: [PATCH 050/377] Fixed a small mistake in keyspace-notifications.md (#2141) --- docs/manual/keyspace-notifications.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/keyspace-notifications.md b/docs/manual/keyspace-notifications.md index bd0dce4680..6f4d1cbbf0 100644 --- a/docs/manual/keyspace-notifications.md +++ b/docs/manual/keyspace-notifications.md @@ -74,7 +74,7 @@ following table: e Evicted events (events generated when a key is evicted for maxmemory) m Key miss events (events generated when a key that doesn't exist is accessed) n New key events (Note: not included in the 'A' class) - A Alias for "g$lshztxed", so that the "AKE" string means all the events except "m". + A Alias for "g$lshztxed", so that the "AKE" string means all the events except "m" and "n". At least `K` or `E` should be present in the string, otherwise no event will be delivered regardless of the rest of the string. From 84b12f1b259ab9af2d6383bb3b39f9cd3c4be206 Mon Sep 17 00:00:00 2001 From: Ning Xie Date: Thu, 6 Oct 2022 00:02:38 +0800 Subject: [PATCH 051/377] keep description in update with latest option in bitop command (#2148) --- commands/bitop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/bitop.md b/commands/bitop.md index d35c756302..fd5aca9b17 100644 --- a/commands/bitop.md +++ b/commands/bitop.md @@ -58,5 +58,5 @@ bitmaps][hbgc212fermurb]" for an interesting use cases. Care should be taken when running it against long input strings. For real-time metrics and statistics involving large inputs a good approach is -to use a replica (with read-only option disabled) where the bit-wise +to use a replica (with replica-read-only option enabled) where the bit-wise operations are performed to avoid blocking the master instance. From bda27fa9a017b2f6e977ed837240a98a6b9e32bc Mon Sep 17 00:00:00 2001 From: Madelyn Olson <34459052+madolson@users.noreply.github.com> Date: Fri, 7 Oct 2022 10:13:28 -0700 Subject: [PATCH 052/377] Update commands/info.md --- commands/info.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/commands/info.md b/commands/info.md index 36292d49c8..a07ec67c49 100644 --- a/commands/info.md +++ b/commands/info.md @@ -306,9 +306,9 @@ Here is the meaning of all fields in the **stats** section: * `io_threaded_reads_processed`: Number of read events processed by the main and I/O threads * `io_threaded_writes_processed`: Number of write events processed by the main and I/O threads * `acl_access_denied_auth`: Number of authentication failures -* `acl_access_denied_cmd`: Number of ACL denied accesses to run a command -* `acl_access_denied_key`: Number of ACL denied accesses to a key -* `acl_access_denied_channel`: Number of ACL denied accesses to a channel +* `acl_access_denied_cmd`: Number of commands rejected because of access denied to the command +* `acl_access_denied_key`: Number of commands rejected because of access denied to a key +* `acl_access_denied_channel`: Number of commands rejected because of access denied to a channel Here is the meaning of all fields in the **replication** section: From 31450f1dbf374655e72a07d2b464702d559ddb38 Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Fri, 7 Oct 2022 18:21:15 -0400 Subject: [PATCH 053/377] [UPDATE] Add a link to linear scaling on redis.com (#2151) * Adds a link to enterprise content in Scaling * Copy edit for docs/manual/scaling.md Co-authored-by: Kyle Banker --- docs/manual/scaling.md | 230 +++++++++++++++++++++-------------------- 1 file changed, 120 insertions(+), 110 deletions(-) diff --git a/docs/manual/scaling.md b/docs/manual/scaling.md index c5c444477e..ad8d5ae273 100644 --- a/docs/manual/scaling.md +++ b/docs/manual/scaling.md @@ -8,73 +8,53 @@ aliases: - /topics/partitioning --- -Redis scales horizontally with a deployment topology called Redis Cluster. +Redis scales horizontally with a deployment topology called Redis Cluster. +This topic will teach you how to set up, test, and operate Redis Cluster in production. +You will learn about the availability and consistency characteristics of Redis Cluster from the end user's point of view. -This document is a gentle introduction to Redis Cluster, teaching you -how to set up, test, and operate Redis Cluster in production. - -This tutorial also described the availability -and consistency characteristics of Redis Cluster from the point of view -of the end user, stated in a simple-to-understand way. - -If you plan to run a production Redis Cluster deployment, or want to better understand how Redis Cluster works internally, consult the [Redis Cluster specification](/topics/cluster-spec). +If you plan to run a production Redis Cluster deployment or want to understand better how Redis Cluster works internally, consult the [Redis Cluster specification](/topics/cluster-spec). To learn how Redis Enterprise handles scaling, see [Linear Scaling with Redis Enterprise](https://redis.com/redis-enterprise/technology/linear-scaling-redis-enterprise/). ## Redis Cluster 101 -Redis Cluster provides a way to run a Redis installation where data is -**automatically sharded across multiple Redis nodes**. - -Redis Cluster also provides **some degree of availability during partitions**, -that is in practical terms the ability to continue the operations when -some nodes fail or are not able to communicate. However the cluster stops -to operate in the event of larger failures (for example when the majority of -masters are unavailable). +Redis Cluster provides a way to run a Redis installation where data is automatically sharded across multiple Redis nodes. +Redis Cluster also provides some degree of availability during partitions—in practical terms, the ability to continue operations when some nodes fail or are unable to communicate. +However, the cluster will become unavailable in the event of larger failures (for example, when the majority of masters are unavailable). -So in practical terms, what do you get with Redis Cluster? +So, with Redis Cluster, you get the ability to: -* The ability to **automatically split your dataset among multiple nodes**. -* The ability to **continue operations when a subset of the nodes are experiencing failures** or are unable to communicate with the rest of the cluster. +* Automatically split your dataset among multiple nodes. +* Continue operations when a subset of the nodes are experiencing failures or are unable to communicate with the rest of the cluster. -### Redis Cluster TCP ports +#### Redis Cluster TCP ports -Every Redis Cluster node requires two open TCP connections: a Redis -TCP port used to serve clients, e.g., 6379, and second port known as the -cluster bus port. By default, the cluster bus port is set by adding 10000 to the data port (e.g., 16379); however, you can override this in the `cluster-port` config. +Every Redis Cluster node requires two open TCP connections: a Redis TCP port used to serve clients, e.g., 6379, and second port known as the _cluster bus port_. +By default, the cluster bus port is set by adding 10000 to the data port (e.g., 16379); however, you can override this in the `cluster-port` configuration. -This second port is used for the cluster bus, which is a node-to-node -communication channel using a binary protocol. The cluster bus is used by -nodes for failure detection, configuration update, failover authorization, -and so forth. Clients should never try to communicate with the cluster bus -port, but always with the normal Redis command port, however make sure you -open both ports in your firewall, otherwise Redis cluster nodes will be -unable to communicate. +Cluster bus is a node-to-node communication channel that uses a binary protocol, which is more suited to exchanging information between nodes due to +little bandwidth and processing time. +Nodes use the cluster bus for failure detection, configuration updates, failover authorization, and so forth. +Clients should never try to communicate with the cluster bus port, but rather use the Redis command port. +However, make sure you open both ports in your firewall, otherwise Redis cluster nodes won't be unable to communicate. -Note that for a Redis Cluster to work properly you need, for each node: +For a Redis Cluster to work properly you need, for each node: -1. The normal client communication port (usually 6379) used to communicate with clients to be open to all the clients that need to reach the cluster, plus all the other cluster nodes (that use the client port for keys migrations). +1. The client communication port (usually 6379) used to communicate with clients and be open to all the clients that need to reach the cluster, plus all the other cluster nodes that use the client port for key migrations. 2. The cluster bus port must be reachable from all the other cluster nodes. If you don't open both TCP ports, your cluster will not work as expected. -The cluster bus uses a different, binary protocol, for node to node data -exchange, which is more suited to exchange information between nodes using -little bandwidth and processing time. - -### Redis Cluster and Docker +#### Redis Cluster and Docker Currently, Redis Cluster does not support NATted environments and in general environments where IP addresses or TCP ports are remapped. -Docker uses a technique called *port mapping*: programs running inside Docker -containers may be exposed with a different port compared to the one the -program believes to be using. This is useful for running multiple -containers using the same ports, at the same time, in the same server. +Docker uses a technique called _port mapping_: programs running inside Docker containers may be exposed with a different port compared to the one the program believes to be using. +This is useful for running multiple containers using the same ports, at the same time, in the same server. -To make Docker compatible with Redis Cluster, you need to use -Docker's **host networking mode**. Please see the `--net=host` option -in the [Docker documentation](https://docs.docker.com/engine/userguide/networking/dockernetworks/) for more information. +To make Docker compatible with Redis Cluster, you need to use Docker's _host networking mode_. +Please see the `--net=host` option in the [Docker documentation](https://docs.docker.com/engine/userguide/networking/dockernetworks/) for more information. -### Redis Cluster data sharding +#### Redis Cluster data sharding Redis Cluster does not use consistent hashing, but a different form of sharding where every key is conceptually part of what we call a **hash slot**. @@ -107,7 +87,7 @@ Hash tags are documented in the Redis Cluster specification, but the gist is that if there is a substring between {} brackets in a key, only what is inside the string is hashed. For example, the keys `user:{123}:profile` and `user:{123}:account` are guaranteed to be in the same hash slot because they share the same hash tag. As a result, you can operate on these two keys in the same multi-key operation. -### Redis Cluster master-replica model +#### Redis Cluster master-replica model To remain available when a subset of master nodes are failing or are not able to communicate with the majority of nodes, Redis Cluster uses a @@ -128,7 +108,7 @@ master and will continue to operate correctly. However, note that if nodes B and B1 fail at the same time, Redis Cluster will not be able to continue to operate. -### Redis Cluster consistency guarantees +#### Redis Cluster consistency guarantees Redis Cluster does not guarantee **strong consistency**. In practical terms this means that under certain conditions it is possible that Redis @@ -149,7 +129,7 @@ but crashes before being able to send the write to its replicas, one of the replicas (that did not receive the write) can be promoted to master, losing the write forever. -This is **very similar to what happens** with most databases that are +This is very similar to what happens with most databases that are configured to flush data to disk every second, so it is a scenario you are already able to reason about because of past experiences with traditional database systems not involving distributed systems. Similarly you can @@ -183,10 +163,12 @@ However, if the partition lasts enough time for B1 to be promoted to master on the majority side of the partition, the writes that Z1 has sent to B in the meantime will be lost. -Note that there is a **maximum window** to the amount of writes Z1 will be able +{{% alert title="Note" color="info" %}} +There is a **maximum window** to the amount of writes Z1 will be able to send to B: if enough time has elapsed for the majority side of the partition to elect a replica as master, every master node in the minority side will have stopped accepting writes. +{{% /alert %}} This amount of time is a very important configuration directive of Redis Cluster, and is called the **node timeout**. @@ -199,8 +181,8 @@ and stops accepting writes. ## Redis Cluster configuration parameters -We are about to create an example cluster deployment. Before we continue, -let's introduce the configuration parameters that Redis Cluster introduces +We are about to create an example cluster deployment. +Before we continue, let's introduce the configuration parameters that Redis Cluster introduces in the `redis.conf` file. * **cluster-enabled ``**: If yes, enables Redis Cluster support in a specific Redis instance. Otherwise the instance starts as a standalone instance as usual. @@ -211,13 +193,30 @@ in the `redis.conf` file. * **cluster-require-full-coverage ``**: If this is set to yes, as it is by default, the cluster stops accepting writes if some percentage of the key space is not covered by any node. If the option is set to no, the cluster will still serve queries even if only requests about a subset of keys can be processed. * **cluster-allow-reads-when-down ``**: If this is set to no, as it is by default, a node in a Redis Cluster will stop serving all traffic when the cluster is marked as failed, either when a node can't reach a quorum of masters or when full coverage is not met. This prevents reading potentially inconsistent data from a node that is unaware of changes in the cluster. This option can be set to yes to allow reads from a node during the fail state, which is useful for applications that want to prioritize read availability but still want to prevent inconsistent writes. It can also be used for when using Redis Cluster with only one or two shards, as it allows the nodes to continue serving writes when a master fails but automatic failover is impossible. +## Create and use a Redis Cluster + +To create and use a Redis Cluster, follow these steps: + +* [Create a Redis Cluster](#create-a-redis-cluster) +* [Interact with the cluster](#interact-with-the-cluster) +* [Write an example app with redis-rb-cluster](#write-an-example-app-with-redis-rb-cluster) +* [Reshard the cluster](#reshard-the-cluster) +* [A more interesting example application](#a-more-interesting-example-application) +* [Test the failover](#test-the-failover) +* [Manual failover](#manual-failover) +* [Add a new node](#add-a-new-node) +* [Remove a node](#remove-a-node) +* [Replica migration](#replica-migration) +* [Upgrade nodes in a Redis Cluster](#upgrade-nodes-in-a-redis-cluster) +* [Migrate to Redis Cluster](#migrate-to-redis-cluster) -## Creating and using a Redis Cluster +But, first, familiarize yourself with the requirements for creating a cluster. -To create a cluster, the first thing we need is to have a few empty -Redis instances running in **cluster mode**. +#### Requirements to create a Redis Cluster -At minimum, you'll see to set the following directives in the `redis.conf` file: +To create a cluster, the first thing you need is to have a few empty Redis instances running in _cluster mode_. + +At minimum, set the following directives in the `redis.conf` file: ``` port 7000 @@ -227,7 +226,7 @@ cluster-node-timeout 5000 appendonly yes ``` -Setting the `cluster-enabled` directive to `yes` enables cluster mode. +To enable cluster mode, set the `cluster-enabled` directive to `yes`. Every instance also contains the path of a file where the configuration for this node is stored, which by default is `nodes.conf`. This file is never touched by humans; it is simply generated at startup @@ -270,10 +269,12 @@ remembers every other node using this IDs, and not by IP or port. IP addresses and ports may change, but the unique node identifier will never change for all the life of the node. We call this identifier simply **Node ID**. -### Initializing the cluster +#### Create a Redis Cluster + +Now that we have a number of instances running, you need to create your cluster by writing some meaningful configuration to the nodes. -Now that we have a number of instances running, we need to create our -cluster by writing some meaningful configuration to the nodes. +You can configure and execute individual instances manually or use the create-cluster script. +Let's go over how you do it manually. To create the cluster, run: @@ -296,8 +297,6 @@ bootstrapped into talking with each other. Finally, if everything has gone well, This means that there is at least one master instance serving each of the 16384 available slots. -### Creating a Redis Cluster using the create-cluster script - If you don't want to create a Redis Cluster by configuring and executing individual instances manually as explained above, there is a much simpler system (but you'll not learn the same amount of operational details). @@ -322,10 +321,10 @@ by default. When you are done, stop the cluster with: Please read the `README` inside this directory for more information on how to run the script. -### Interacting with the cluster ---- +#### Interact with the cluster -To connect to Redis Cluster, you'll need a cluster-aware Redis client. See the documentation for your client of choice to determine its cluster support. +To connect to Redis Cluster, you'll need a cluster-aware Redis client. +See the [documentation](/docs/clients) for your client of choice to determine its cluster support. You can also test your Redis Cluster using the `redis-cli` command line utility: @@ -345,8 +344,10 @@ redis 127.0.0.1:7002> get hello "world" ``` -**Note:** if you created the cluster using the script, your nodes may listen +{{% alert title="Note" color="info" %}} +If you created the cluster using the script, your nodes may listen on different ports, starting from 30001 by default. +{{% /alert %}} The `redis-cli` cluster support is very basic, so it always uses the fact that Redis Cluster nodes are able to redirect a client to the right node. @@ -356,7 +357,7 @@ right node. The map is refreshed only when something changed in the cluster configuration, for example after a failover or after the system administrator changed the cluster layout by adding or removing nodes. -### Writing an example app with redis-rb-cluster +#### Write an example app with redis-rb-cluster Before going forward showing how to operate the Redis Cluster, doing things like a failover, or a resharding, we need to create some example application @@ -370,7 +371,8 @@ is writing to the cluster. This section explains some basic usage of [redis-rb-cluster](https://github.com/antirez/redis-rb-cluster) showing two -examples. The first is the following, and is the +examples. +The first is the following, and is the [`example.rb`](https://github.com/antirez/redis-rb-cluster/blob/master/example.rb) file inside the redis-rb-cluster distribution: @@ -479,18 +481,18 @@ This is not a very interesting program and we'll use a better one in a moment but we can already see what happens during a resharding when the program is running. -### Resharding the cluster +#### Reshard the cluster -Now we are ready to try a cluster resharding. To do this please +Now we are ready to try a cluster resharding. To do this, please keep the example.rb program running, so that you can see if there is some -impact on the program running. Also you may want to comment the `sleep` -call in order to have some more serious write load during resharding. +impact on the program running. Also, you may want to comment the `sleep` +call to have some more serious write load during resharding. Resharding basically means to move hash slots from a set of nodes to another -set of nodes, and like cluster creation it is accomplished using the -redis-cli utility. +set of nodes. +Like cluster creation, it is accomplished using the redis-cli utility. -To start a resharding just type: +To start a resharding, just type: redis-cli --cluster reshard 127.0.0.1:7000 @@ -542,8 +544,6 @@ the following command: All the slots will be covered as usual, but this time the master at 127.0.0.1:7000 will have more hash slots, something around 6461. -### Scripting a resharding operation - Resharding can be performed automatically without the need to manually enter the parameters in an interactive way. This is possible using a command line like the following: @@ -561,7 +561,7 @@ The `--cluster-yes` option instructs the cluster manager to automatically answer Note that this option can also be activated by setting the `REDISCLI_CLUSTER_YES` environment variable. -### A more interesting example application +#### A more interesting example application The example application we wrote early is not very good. It writes to the cluster in a simple way without even checking if what was @@ -625,16 +625,17 @@ When I set the counter to 0 the real value was 114, so the program reports This program is much more interesting as a test case, so we'll use it to test the Redis Cluster failover. -Testing the failover ---- +#### Test the failover -Note: during this test, you should take a tab open with the consistency test -application running. - -In order to trigger the failover, the simplest thing we can do (that is also +To trigger the failover, the simplest thing we can do (that is also the semantically simplest failure that can occur in a distributed system) is to crash a single process, in our case a single master. +{{% alert title="Note" color="info" %}} +During this test, you should take a tab open with the consistency test +application running. +{{% /alert %}} + We can identify a master and crash it with the following command: ``` @@ -707,19 +708,19 @@ The output of the `CLUSTER NODES` command may look intimidating, but it is actua * Status of the link to this node. * Slots served... -### Manual failover +#### Manual failover Sometimes it is useful to force a failover without actually causing any problem -on a master. For example in order to upgrade the Redis process of one of the -master nodes it is a good idea to failover it in order to turn it into a replica +on a master. For example, to upgrade the Redis process of one of the +master nodes it is a good idea to failover it to turn it into a replica with minimal impact on availability. Manual failovers are supported by Redis Cluster using the `CLUSTER FAILOVER` -command, that must be executed in one of the **replicas** of the master you want +command, that must be executed in one of the replicas of the master you want to failover. Manual failovers are special and are safer compared to failovers resulting from -actual master failures, since they occur in a way that avoid data loss in the +actual master failures. They occur in a way that avoids data loss in the process, by switching clients from the original master to the new master only when the system is sure that the new master processed all the replication stream from the old one. @@ -740,13 +741,13 @@ the failover starts, and the old master is informed about the configuration switch. When the clients are unblocked on the old master, they are redirected to the new master. -Note: - -* To promote a replica to master, it must first be known as a replica by a majority of the masters in the cluster. +{{% alert title="Note" color="info" %}} +To promote a replica to master, it must first be known as a replica by a majority of the masters in the cluster. Otherwise, it cannot win the failover election. - If the replica has just been added to the cluster (see [Adding a new node as a replica](#adding-a-new-node-as-a-replica) below), you may need to wait a while before sending the `CLUSTER FAILOVER` command, to make sure the masters in cluster are aware of the new replica. + If the replica has just been added to the cluster (see [Add a new node as a replica](#add-a-new-node-as-a-replica)), you may need to wait a while before sending the `CLUSTER FAILOVER` command, to make sure the masters in cluster are aware of the new replica. +{{% /alert %}} -### Adding a new node +#### Add a new node Adding a new node is basically the process of adding an empty node and then moving some data into it, in case it is a new master, or telling it to @@ -805,20 +806,21 @@ the cluster. However it has two peculiarities compared to the other masters: * Because it is a master without assigned slots, it does not participate in the election process when a replica wants to become a master. Now it is possible to assign hash slots to this node using the resharding -feature of `redis-cli`. It is basically useless to show this as we already +feature of `redis-cli`. +It is basically useless to show this as we already did in a previous section, there is no difference, it is just a resharding having as a target the empty node. -### Adding a new node as a replica +##### Add a new node as a replica -Adding a new Replica can be performed in two ways. The obvious one is to +Adding a new replica can be performed in two ways. The obvious one is to use redis-cli again, but with the --cluster-slave option, like this: redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 --cluster-slave Note that the command line here is exactly like the one we used to add a new master, so we are not specifying to which master we want to add -the replica. In this case what happens is that redis-cli will add the new +the replica. In this case, what happens is that redis-cli will add the new node as replica of a random master among the masters with fewer replicas. However you can specify exactly what master you want to target with your @@ -852,8 +854,7 @@ f093c80dde814da99c5cf72a7dd01590792b783b 127.0.0.1:7006 slave 3c3a0c74aae0b56170 The node 3c3a0c... now has two replicas, running on ports 7002 (the existing one) and 7006 (the new one). -Removing a node ---- +#### Remove a node To remove a replica node just use the `del-node` command of redis-cli: @@ -871,10 +872,10 @@ over one of its replicas and remove the node after it turned into a replica of t new master. Obviously this does not help when you want to reduce the actual number of masters in your cluster, in that case, a resharding is needed. -### Replica migration +#### Replica migration -In Redis Cluster it is possible to reconfigure a replica to replicate with a -different master at any time just using the following command: +In Redis Cluster, you can reconfigure a replica to replicate with a +different master at any time just using this command: CLUSTER REPLICATE @@ -883,8 +884,10 @@ master to another one automatically, without the help of the system administrato The automatic reconfiguration of replicas is called *replicas migration* and is able to improve the reliability of a Redis Cluster. -Note: you can read the details of replicas migration in the [Redis Cluster Specification](/topics/cluster-spec), here we'll only provide some information about the +{{% alert title="Note" color="info" %}} +You can read the details of replicas migration in the [Redis Cluster Specification](/topics/cluster-spec), here we'll only provide some information about the general idea and what you should do in order to benefit from it. +{{% /alert %}} The reason why you may want to let your cluster replicas to move from one master to another under certain condition, is that usually the Redis Cluster is as @@ -920,8 +923,7 @@ So what you should know about replicas migration in short? * To benefit from replica migration you have just to add a few more replicas to a single master in your cluster, it does not matter what master. * There is a configuration parameter that controls the replica migration feature that is called `cluster-migration-barrier`: you can read more about it in the example `redis.conf` file provided with Redis Cluster. -Upgrading nodes in a Redis Cluster ---- +#### Upgrade nodes in a Redis Cluster Upgrading replica nodes is easy since you just need to stop the node and restart it with an updated version of Redis. If there are clients scaling reads using @@ -931,7 +933,7 @@ one is not available. Upgrading masters is a bit more complex, and the suggested procedure is: 1. Use `CLUSTER FAILOVER` to trigger a manual failover of the master to one of its replicas. - (See the [Manual failover](#manual-failover) section in this document.) + (See the [Manual failover](#manual-failover) in this topic.) 2. Wait for the master to turn into a replica. 3. Finally upgrade the node as you do for replicas. 4. If you want the master to be the node you just upgraded, trigger a new manual failover in order to turn back the upgraded node into a master. @@ -939,8 +941,7 @@ Upgrading masters is a bit more complex, and the suggested procedure is: Following this procedure you should upgrade one node after the other until all the nodes are upgraded. -Migrating to Redis Cluster ---- +#### Migrate to Redis Cluster Users willing to migrate to Redis Cluster may have just a single master, or may already using a preexisting sharding setup, where keys @@ -986,4 +987,13 @@ may be slow since 2.8 does not implement migrate connection caching, so you may want to restart your source instance with a Redis 3.x version before to perform such operation. -**A note about the word slave used in this page**: Starting with Redis 5, if not for backward compatibility, the Redis project no longer uses the word slave. Unfortunately in this command the word slave is part of the protocol, so we'll be able to remove such occurrences only when this API will be naturally deprecated. +{{% alert title="Note" color="info" %}} +Starting with Redis 5, if not for backward compatibility, the Redis project no longer uses the word slave. Unfortunately in this command the word slave is part of the protocol, so we'll be able to remove such occurrences only when this API will be naturally deprecated. +{{% /alert %}} + +## Learn more + +* [Redis Cluster specification](/topics/cluster-spec) +* [Linear Scaling with Redis Enterprise](https://redis.com/redis-enterprise/technology/linear-scaling-redis-enterprise/) +* [Docker documentation](https://docs.docker.com/engine/userguide/networking/dockernetworks/) + From 0937349676e6b388dc03d51f6394ea6b58496fc7 Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Sun, 9 Oct 2022 11:11:16 -0400 Subject: [PATCH 054/377] Fixes #2125 plus other copyedits (#2149) --- commands/xgroup-create.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/commands/xgroup-create.md b/commands/xgroup-create.md index f0f1606bf0..4fdc149f61 100644 --- a/commands/xgroup-create.md +++ b/commands/xgroup-create.md @@ -1,22 +1,24 @@ -This command creates a new consumer group uniquely identified by `` for the stream stored at ``. +Create a new consumer group uniquely identified by `` for the stream stored at `` -Every group has a unique name in a given stream. When a consumer group with the same name already exists, the command returns a `-BUSYGROUP` error. +Every group has a unique name in a given stream. +When a consumer group with the same name already exists, the command returns a `-BUSYGROUP` error. The command's `` argument specifies the last delivered entry in the stream from the new group's perspective. -The special ID `$` means the ID of the last entry in the stream, but you can provide any valid ID instead. +The special ID `$` is the ID of the last entry in the stream, but you can substitute it with any valid ID. + For example, if you want the group's consumers to fetch the entire stream from the beginning, use zero as the starting ID for the consumer group: XGROUP CREATE mystream mygroup 0 -By default, the `XGROUP CREATE` command insists that the target stream exists and returns an error when it doesn't. -However, you can use the optional `MKSTREAM` subcommand as the last argument after the `` to automatically create the stream (with length of 0) if it doesn't exist: +By default, the `XGROUP CREATE` command expects that the target stream exists, and returns an error when it doesn't. +If a stream does not exist, you can create it automatically with length of 0 by using the optional `MKSTREAM` subcommand as the last argument after the ``: XGROUP CREATE mystream mygroup $ MKSTREAM -The optional `entries_read` named argument can be specified to enable consumer group lag tracking for an arbitrary ID. -An arbitrary ID is any ID that isn't the ID of the stream's first entry, its last entry or the zero ("0-0") ID. -This can be useful you know exactly how many entries are between the arbitrary ID (excluding it) and the stream's last entry. -In such cases, the `entries_read` can be set to the stream's `entries_added` subtracted with the number of entries. +To enable consumer group lag tracking, specify the optional `entries_read` named argument with an arbitrary ID. +An arbitrary ID is any ID that isn't the ID of the stream's first entry, last entry, or zero ("0-0") ID. +Use it to find out how many entries are between the arbitrary ID (excluding it) and the stream's last entry. +Set the `entries_read` the stream's `entries_added` subtracted by the number of entries. @return From 87f911c70bdac919d360a7cfe27aae80772ebc96 Mon Sep 17 00:00:00 2001 From: Benjamin Pill Date: Wed, 12 Oct 2022 14:56:31 +0200 Subject: [PATCH 055/377] FIx radius in GEOSEARCH example (#2157) The example shows how to get all locations within a radius of 5 km, but the text says within 1 kilometer. --- docs/data-types/geospatial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/geospatial.md b/docs/data-types/geospatial.md index 8c070fdc8e..0f1e7ccdcb 100644 --- a/docs/data-types/geospatial.md +++ b/docs/data-types/geospatial.md @@ -23,7 +23,7 @@ Add several locations to a geospatial index: (integer) 1 ``` -Find all locations within a 1 kilometer radius of a given location, and return the distance to each location: +Find all locations within a 5 kilometer radius of a given location, and return the distance to each location: ``` > GEOSEARCH locations:ca FROMLONLAT -122.2612767 37.7936847 BYRADIUS 5 km WITHDIST 1) 1) "station:1" From 000b78f7ef7e0f228cb33b30575e9bbc4fdcc5df Mon Sep 17 00:00:00 2001 From: Lenin Fernandes <49443133+Lchris22@users.noreply.github.com> Date: Wed, 12 Oct 2022 18:34:33 +0530 Subject: [PATCH 056/377] Update eviction.md (#2158) Fixed pronoun mistakes. --- docs/manual/eviction.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/manual/eviction.md b/docs/manual/eviction.md index 7887042f30..7f46cc436d 100644 --- a/docs/manual/eviction.md +++ b/docs/manual/eviction.md @@ -16,8 +16,7 @@ evict old data as you add new data. This behavior is well known in the developer community, since it is the default behavior for the popular *memcached* system. -This page covers the more general topic of the Redis `maxmemory` directive used to limit the memory usage to a fixed amount. This page it also covers in -depth the LRU eviction algorithm used by Redis, that is actually an approximation of +This page covers the more general topic of the Redis `maxmemory` directive used to limit the memory usage to a fixed amount. It also extensively covers the LRU eviction algorithm used by Redis, which is actually an approximation of the exact LRU. ## `Maxmemory` configuration directive From 41af9e51dde21c07a4bad0e88f7a14a2434bebd2 Mon Sep 17 00:00:00 2001 From: Simon Prickett Date: Fri, 14 Oct 2022 18:05:11 +0400 Subject: [PATCH 057/377] Corrected case of Access Control List in title. (#2161) --- docs/manual/security/acl.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/security/acl.md b/docs/manual/security/acl.md index e341b2e87c..b983a02a3c 100644 --- a/docs/manual/security/acl.md +++ b/docs/manual/security/acl.md @@ -2,7 +2,7 @@ title: "ACL" linkTitle: "ACL" weight: 1 -description: Redis access control list +description: Redis Access Control List aliases: - /topics/acl --- From e2da907db759a919ce01a7e0f48362807db1fd1a Mon Sep 17 00:00:00 2001 From: Ryo Nakamura Date: Tue, 18 Oct 2022 00:11:28 +0900 Subject: [PATCH 058/377] Update transactions.md (#2162) Typo fix --- docs/manual/transactions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/transactions.md b/docs/manual/transactions.md index ae230a944d..02e06b7e12 100644 --- a/docs/manual/transactions.md +++ b/docs/manual/transactions.md @@ -221,7 +221,7 @@ instead. **NOTE** * In Redis versions before 6.0.9, an expired key would not cause a transaction to be aborted. [More on this](https://github.com/redis/redis/pull/7920) -* Commands within a transaction wont trigger the `WATCH` condition since they +* Commands within a transaction won't trigger the `WATCH` condition since they are only queued until the `EXEC` is sent. `WATCH` can be called multiple times. Simply all the `WATCH` calls will From b5eef55c18ad104fed97e12bcade5c38add321c3 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Wed, 19 Oct 2022 18:36:45 +0300 Subject: [PATCH 059/377] Adds the redis.conf template file (#2169) --- docs/manual/config-file.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs/manual/config-file.md diff --git a/docs/manual/config-file.md b/docs/manual/config-file.md new file mode 100644 index 0000000000..da824b55d4 --- /dev/null +++ b/docs/manual/config-file.md @@ -0,0 +1,9 @@ +--- +title: "Redis configuration file example" +linkTitle: "Configuration example" +weight: 1 +description: > + The self-documented `redis.conf` file that's shipped with every version. +--- + +Note: this file is generated from the unstable redis.conf during the website's build. From f1e157314a5c9bd5f530eb197e26293be60e35ec Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Fri, 21 Oct 2022 01:23:11 -0400 Subject: [PATCH 060/377] [UPDATE] Add a link to RU330 from the security topic (#2172) * Adds a link to the security course Co-authored-by: Kyle Banker --- docs/manual/security/_index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/manual/security/_index.md b/docs/manual/security/_index.md index cf87c69b2f..f7b295d1ae 100644 --- a/docs/manual/security/_index.md +++ b/docs/manual/security/_index.md @@ -10,7 +10,8 @@ aliases: This document provides an introduction to the topic of security from the point of view of Redis. It covers the access control provided by Redis, code security concerns, attacks that can be triggered from the outside by selecting malicious inputs, and -other similar topics. +other similar topics. +You can learn more about access control, data protection and encryption, secure Redis architectures, and secure deployment techniques by taking the [Redis University security course](https://university.redis.com/courses/ru330/). For security-related contacts, open an issue on GitHub, or when you feel it is really important to preserve the security of the communication, use the From 0f97319e31adac967bdfb221029b2198c84bff11 Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Fri, 21 Oct 2022 17:27:14 -0400 Subject: [PATCH 061/377] [UPDATE] Add Redis Stack install to Redis get started (#2154) * Add Redis Stack install link --- docs/getting-started/_index.md | 11 ++++++----- wordlist | 2 ++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/getting-started/_index.md b/docs/getting-started/_index.md index b3c38f3481..68df45241d 100644 --- a/docs/getting-started/_index.md +++ b/docs/getting-started/_index.md @@ -12,12 +12,13 @@ This is a guide to getting started with Redis. You'll learn how to install, run, ## Install Redis -How you install Redis depends on your operating system. See the guide below that best fits your needs: +How you install Redis depends on your operating system and whether you'd like to install it bundled with Redis Stack and Redis UI. See the guide below that best fits your needs: -* [Install Redis from Source]({{< ref "/docs/getting-started/installation/install-redis-from-source.md" >}}) -* [Install Redis on Linux]({{< ref "/docs/getting-started/installation/install-redis-on-linux.md" >}}) -* [Install Redis on macOS]({{< ref "/docs/getting-started/installation/install-redis-on-mac-os.md" >}}) -* [Install Redis on Windows]({{< ref "/docs/getting-started/installation/install-redis-on-windows.md" >}}) +* [Install Redis from Source](/docs/getting-started/installation/install-redis-from-source) +* [Install Redis on Linux](/docs/getting-started/installation/install-redis-on-linux) +* [Install Redis on macOS](/docs/getting-started/installation/install-redis-on-mac-os) +* [Install Redis on Windows](/docs/getting-started/installation/install-redis-on-windows) +* [Install Redis with Redis Stack and RedisInsight](/docs/stack/get-started/install) Once you have Redis up and running, and can connect using `redis-cli`, you can continue with the steps below. diff --git a/wordlist b/wordlist index e9c351c4af..12848a643f 100644 --- a/wordlist +++ b/wordlist @@ -275,6 +275,7 @@ RC3 RC4 RDB RDB-saving +RedisInsight REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD REDISPORT REPL @@ -369,6 +370,7 @@ TTL TTLs Tthe Twemproxy +UI URI USD UTF-8 From f9f20422301bb992942b3d03dc6221de9813e6e5 Mon Sep 17 00:00:00 2001 From: Nikos Paschos Date: Mon, 31 Oct 2022 13:15:03 +0200 Subject: [PATCH 062/377] Fix invalid markdown link (#2181) Fixes invalid markdown syntax of a link on `docs/reference/internals/internals-rediseventlib.md` --- docs/reference/internals/internals-rediseventlib.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/internals/internals-rediseventlib.md b/docs/reference/internals/internals-rediseventlib.md index 134817536f..d644e72cee 100644 --- a/docs/reference/internals/internals-rediseventlib.md +++ b/docs/reference/internals/internals-rediseventlib.md @@ -17,7 +17,7 @@ Let us figure it out through a series of Q&As. Q: What do you expect a network server to be doing all the time?
A: Watch for inbound connections on the port its listening and accept them. -Q: Calling [accept](http://man.cx/accept%282%29 accept) yields a descriptor. What do I do with it?
+Q: Calling [accept](http://man.cx/accept%282%29) yields a descriptor. What do I do with it?
A: Save the descriptor and do a non-blocking read/write operation on it. Q: Why does the read/write have to be non-blocking?
From 60264ab1356d05214e77a0abb422e4f84c5a6ceb Mon Sep 17 00:00:00 2001 From: sewenew Date: Mon, 31 Oct 2022 19:20:39 +0800 Subject: [PATCH 063/377] Add C++ Redlock implementation (#2173) --- docs/reference/patterns/distributed-locks.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/reference/patterns/distributed-locks.md b/docs/reference/patterns/distributed-locks.md index cc8f6864b0..58a4a6761d 100644 --- a/docs/reference/patterns/distributed-locks.md +++ b/docs/reference/patterns/distributed-locks.md @@ -40,6 +40,7 @@ already available that can be used for reference. * [Redisson](https://github.com/mrniko/redisson) (Java implementation). * [Redis::DistLock](https://github.com/sbertrang/redis-distlock) (Perl implementation). * [Redlock-cpp](https://github.com/jacket-code/redlock-cpp) (C++ implementation). +* [Redis-plus-plus](https://github.com/sewenew/redis-plus-plus/#redlock) (C++ implementation). * [Redlock-cs](https://github.com/kidfashion/redlock-cs) (C#/.NET implementation). * [RedLock.net](https://github.com/samcook/RedLock.net) (C#/.NET implementation). Includes async and lock extension support. * [ScarletLock](https://github.com/psibernetic/scarletlock) (C# .NET implementation with configurable datastore). From 187b751fcf69ebe8953e860e57d370d4589743b4 Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Mon, 31 Oct 2022 07:27:08 -0400 Subject: [PATCH 064/377] [UPDATE] Link from persistence topic to enterprise persistence options/configuration (#2170) --- docs/manual/persistence.md | 15 ++++++++------- wordlist | 1 + 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/manual/persistence.md b/docs/manual/persistence.md index 71c3b4d3c6..8c3b432909 100644 --- a/docs/manual/persistence.md +++ b/docs/manual/persistence.md @@ -11,15 +11,16 @@ aliases: [ ] --- -Persistence refers to the writing of data to durable storage, such as a solid-state disk (SSD). Redis itself provides a range of persistence options: +Persistence refers to the writing of data to durable storage, such as a solid-state disk (SSD). Redis provides a range of persistence options. These include: -* **RDB** (Redis Database): The RDB persistence performs point-in-time snapshots of your dataset at specified intervals. -* **AOF** (Append Only File): The AOF persistence logs every write operation received by the server, that will be played again at server startup, reconstructing the original dataset. Commands are logged using the same format as the Redis protocol itself, in an append-only fashion. Redis is able to [rewrite](#log-rewriting) the log in the background when it gets too big. -* **No persistence**: If you wish, you can disable persistence completely, if you want your data to just exist as long as the server is running. -* **RDB + AOF**: It is possible to combine both AOF and RDB in the same instance. Notice that, in this case, when Redis restarts the AOF file will be used to reconstruct the original dataset since it is guaranteed to be the most complete. +* **RDB** (Redis Database): RDB persistence performs point-in-time snapshots of your dataset at specified intervals. +* **AOF** (Append Only File): AOF persistence logs every write operation received by the server. These operations can then be replayed again at server startup, reconstructing the original dataset. Commands are logged using the same format as the Redis protocol itself. +* **No persistence**: You can disable persistence completely. This is sometimes used when caching. +* **RDB + AOF**: You can also combine both AOF and RDB in the same instance. -The most important thing to understand is the different trade-offs between the -RDB and AOF persistence. +If you'd rather not think about the tradeoffs between these different persistence strategies, you may want to consider [Redis Enterprise's persistence options](https://docs.redis.com/latest/rs/databases/configure/database-persistence/), which can be pre-configured using a UI. + +To learn more about how to evaluate your Redis persistence strategy, read on. ## RDB advantages diff --git a/wordlist b/wordlist index 12848a643f..211ec9bdc9 100644 --- a/wordlist +++ b/wordlist @@ -740,6 +740,7 @@ pmessage ppa:redislabs pratical pre-conditions +pre-configured pre-existing pre-imported pre-loaded From 8a502ec293572ccb622746bb8fe41003a045021d Mon Sep 17 00:00:00 2001 From: Jacky Date: Mon, 31 Oct 2022 19:41:40 +0800 Subject: [PATCH 065/377] Create Redis Client Links (#2168) --- clients/csharp/github.com/XiaoFeng/XiaoFeng.Redis.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 clients/csharp/github.com/XiaoFeng/XiaoFeng.Redis.json diff --git a/clients/csharp/github.com/XiaoFeng/XiaoFeng.Redis.json b/clients/csharp/github.com/XiaoFeng/XiaoFeng.Redis.json new file mode 100644 index 0000000000..79f1266166 --- /dev/null +++ b/clients/csharp/github.com/XiaoFeng/XiaoFeng.Redis.json @@ -0,0 +1,5 @@ +{ + "name": "XiaoFeng.Redis", + "description": "A useful Redis client that supports the .NET FRAMEWORK,.NET CORE,.NET STANDARD. A client tool that is quite convenient to operate.", + "homepage": "https://github.com/zhuovi/XiaoFeng" +} \ No newline at end of file From a8d0167115f90344b8ebf3b476f12966bcb6f399 Mon Sep 17 00:00:00 2001 From: Ein Verne Date: Mon, 31 Oct 2022 20:41:26 +0800 Subject: [PATCH 066/377] Fix typo in benchmarks (#2159) * Fix typo in benchmarks * Remove typo in wordlist --- docs/reference/optimization/benchmarks.md | 2 +- wordlist | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/reference/optimization/benchmarks.md b/docs/reference/optimization/benchmarks.md index a4f9c28d7b..476951fffc 100644 --- a/docs/reference/optimization/benchmarks.md +++ b/docs/reference/optimization/benchmarks.md @@ -56,7 +56,7 @@ as in the following example: This example runs the tests for the `SET` and `LPUSH` commands and uses quiet mode (see the `-q` switch). -You can even benchmark a specfic command: +You can even benchmark a specific command: $ redis-benchmark -n 100000 -q script load "redis.call('set','foo','bar')" script load redis.call('set','foo','bar'): 69881.20 requests per second diff --git a/wordlist b/wordlist index 211ec9bdc9..e72679d721 100644 --- a/wordlist +++ b/wordlist @@ -852,7 +852,6 @@ smaps snapd snapshotting somekey -specfic spectrogram spellchecker-cli spiped From fef28f9fdc8be77ccc617709ef322045de310afd Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Mon, 31 Oct 2022 18:46:39 +0200 Subject: [PATCH 067/377] Remove dysfunctional meetup (#2188) --- community/_index.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/community/_index.md b/community/_index.md index 19f09a3865..09e6949d5c 100644 --- a/community/_index.md +++ b/community/_index.md @@ -45,8 +45,6 @@ Redis regularly sponsors conferences and meetups. Recent conferences include: * [RedisConf 2020](https://www.youtube.com/c/Redisinc/playlists?view=50&sort=dd&shelf_id=4) -If you're looking for a Redis meetup, check out [Redis Live](https://meetups.redis.com/redis-live/). This virtual, online meetup gets together each month to highlight members of the Redis community. - ## Contributing to Redis There are many ways to contribute to Redis, starting with documentation all the way to changes to the open source Redis server. Here are a few ways you can get involved. From df33ee82cb8d4e5b5c6a34cadf80324ecaa51db5 Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Tue, 1 Nov 2022 15:36:40 -0400 Subject: [PATCH 068/377] [UPDATE] Create new Using and Managing sections from Manual and Reference (#2177) * Restructures manual and reference into using, managing, and reference * Adds redirects * Updates redirects * Updates wordlist * Updates wordlist * updates aliases * Update benchmarks.md * updates aliases * updates aliases * Updates descriptions * Updates descriptions --- docs/clients/index.md | 2 +- docs/libraries/index.md | 2 +- docs/management/_index.md | 6 ++++++ docs/{manual => management}/admin.md | 2 +- docs/{manual => management}/config-file.md | 5 ++++- docs/{manual => management}/config.md | 8 +++++--- docs/{reference => management}/debugging.md | 9 ++++++--- docs/{reference => management}/optimization/_index.md | 5 ++++- .../optimization/benchmarks.md | 11 +++++++---- .../optimization/cpu-profiling.md | 6 ++++-- .../optimization/latency-monitor.md | 6 ++++-- .../{reference => management}/optimization/latency.md | 6 ++++-- .../optimization/memory-optimization.md | 6 ++++-- docs/{manual => management}/persistence.md | 8 ++++---- docs/{manual => management}/replication.md | 6 +++--- docs/{manual => management}/scaling.md | 11 +++++++---- docs/{manual => management}/security/_index.md | 7 +++++-- docs/{manual => management}/security/acl.md | 7 +++++-- docs/{manual => management}/security/encryption.md | 7 +++++-- docs/{manual => management}/sentinel.md | 9 ++++++--- docs/{manual => management}/troubleshooting.md | 9 ++++++--- docs/manual/_index.md | 6 +++--- docs/manual/keyspace-notifications.md | 2 +- docs/{reference => manual}/patterns/_index.md | 5 ++++- docs/{reference => manual}/patterns/bulk-loading.md | 6 ++++-- .../patterns/distributed-locks.md | 9 ++++++--- docs/{reference => manual}/patterns/indexes.md | 6 ++++-- docs/{reference => manual}/patterns/twitter-clone.md | 3 +++ docs/manual/pipelining.md | 2 +- docs/manual/programmability/_index.md | 2 +- docs/manual/pubsub.md | 2 +- docs/manual/transactions.md | 2 +- docs/modules/index.md | 2 +- docs/reference/_index.md | 4 ++-- docs/reference/arm.md | 2 +- docs/reference/clients.md | 2 +- docs/reference/cluster-spec.md | 2 +- docs/reference/command-arguments.md | 2 +- docs/{manual => reference}/eviction.md | 2 +- docs/reference/gopher.md | 2 +- docs/reference/internals/_index.md | 2 +- docs/reference/key-specs.md | 2 +- docs/reference/modules/_index.md | 2 +- docs/reference/protocol-spec.md | 2 +- docs/reference/signals.md | 2 +- docs/tools/index.md | 2 +- wordlist | 2 ++ 47 files changed, 138 insertions(+), 77 deletions(-) create mode 100644 docs/management/_index.md rename docs/{manual => management}/admin.md (99%) rename docs/{manual => management}/config-file.md (81%) rename docs/{manual => management}/config.md (98%) rename docs/{reference => management}/debugging.md (98%) rename docs/{reference => management}/optimization/_index.md (71%) rename docs/{reference => management}/optimization/benchmarks.md (98%) rename docs/{reference => management}/optimization/cpu-profiling.md (99%) rename docs/{reference => management}/optimization/latency-monitor.md (98%) rename docs/{reference => management}/optimization/latency.md (99%) rename docs/{reference => management}/optimization/memory-optimization.md (99%) rename docs/{manual => management}/persistence.md (99%) rename docs/{manual => management}/replication.md (99%) rename docs/{manual => management}/scaling.md (99%) rename docs/{manual => management}/security/_index.md (99%) rename docs/{manual => management}/security/acl.md (99%) rename docs/{manual => management}/security/encryption.md (97%) rename docs/{manual => management}/sentinel.md (99%) rename docs/{manual => management}/troubleshooting.md (95%) rename docs/{reference => manual}/patterns/_index.md (81%) rename docs/{reference => manual}/patterns/bulk-loading.md (98%) rename docs/{reference => manual}/patterns/distributed-locks.md (99%) rename docs/{reference => manual}/patterns/indexes.md (99%) rename docs/{reference => manual}/patterns/twitter-clone.md (99%) rename docs/{manual => reference}/eviction.md (99%) diff --git a/docs/clients/index.md b/docs/clients/index.md index e13277cf0b..795a03cbea 100644 --- a/docs/clients/index.md +++ b/docs/clients/index.md @@ -1,7 +1,7 @@ --- title: "Clients" linkTitle: "Clients" -weight: 10 +weight: 4 description: Redis clients layout: bazzar bazzar: clients diff --git a/docs/libraries/index.md b/docs/libraries/index.md index 09b4a4cede..cf636bcd06 100644 --- a/docs/libraries/index.md +++ b/docs/libraries/index.md @@ -1,7 +1,7 @@ --- title: "Libraries" linkTitle: "Libraries" -weight: 11 +weight: 8 description: Libraries that use Redis layout: bazzar bazzar: libraries diff --git a/docs/management/_index.md b/docs/management/_index.md new file mode 100644 index 0000000000..da6175de7d --- /dev/null +++ b/docs/management/_index.md @@ -0,0 +1,6 @@ +--- +title: "Managing Redis" +linkTitle: "Managing Redis" +description: An administrator's guide to Redis +weight: 6 +--- diff --git a/docs/manual/admin.md b/docs/management/admin.md similarity index 99% rename from docs/manual/admin.md rename to docs/management/admin.md index fdf76ec3d4..ce666c46c4 100644 --- a/docs/manual/admin.md +++ b/docs/management/admin.md @@ -7,7 +7,7 @@ aliases: [ /topics/admin, /topics/admin.md, /manual/admin, - /manual/admin.md, + /manual/admin.md ] --- diff --git a/docs/manual/config-file.md b/docs/management/config-file.md similarity index 81% rename from docs/manual/config-file.md rename to docs/management/config-file.md index da824b55d4..cbd1f4c4d8 100644 --- a/docs/manual/config-file.md +++ b/docs/management/config-file.md @@ -1,9 +1,12 @@ --- title: "Redis configuration file example" linkTitle: "Configuration example" -weight: 1 +weight: 3 description: > The self-documented `redis.conf` file that's shipped with every version. +aliases: [ + /docs/management/config-file + ] --- Note: this file is generated from the unstable redis.conf during the website's build. diff --git a/docs/manual/config.md b/docs/management/config.md similarity index 98% rename from docs/manual/config.md rename to docs/management/config.md index f80d29f462..db09e0fb1f 100644 --- a/docs/manual/config.md +++ b/docs/management/config.md @@ -1,11 +1,13 @@ --- title: "Redis configuration" linkTitle: "Configuration" -weight: 1 +weight: 2 description: > Overview of redis.conf, the Redis configuration file -aliases: - - /docs/manual/config +aliases: [ + /docs/management/config + ] + --- Redis is able to start without a configuration file using a built-in default diff --git a/docs/reference/debugging.md b/docs/management/debugging.md similarity index 98% rename from docs/reference/debugging.md rename to docs/management/debugging.md index 95b0c719d0..60dbc70898 100644 --- a/docs/reference/debugging.md +++ b/docs/management/debugging.md @@ -1,11 +1,14 @@ --- title: "Debugging" linkTitle: "Debugging" -weight: 1 +weight: 10 description: > A guide to debugging Redis server processes -aliases: - - /topics/debugging +aliases: [ + /topics/debugging, + /docs/reference/debugging, + /docs/reference/debugging.md +] --- Redis is developed with an emphasis on stability. We do our best with diff --git a/docs/reference/optimization/_index.md b/docs/management/optimization/_index.md similarity index 71% rename from docs/reference/optimization/_index.md rename to docs/management/optimization/_index.md index 393ac7f37b..d444e489ad 100644 --- a/docs/reference/optimization/_index.md +++ b/docs/management/optimization/_index.md @@ -1,6 +1,9 @@ --- title: "Optimizing Redis" linkTitle: "Optimization" -weight: 1 +weight: 8 description: Benchmarking, profiling, and optimizations for memory and latency +aliases: [ + /docs/reference/optimization +] --- diff --git a/docs/reference/optimization/benchmarks.md b/docs/management/optimization/benchmarks.md similarity index 98% rename from docs/reference/optimization/benchmarks.md rename to docs/management/optimization/benchmarks.md index 476951fffc..d15254a3f0 100644 --- a/docs/reference/optimization/benchmarks.md +++ b/docs/management/optimization/benchmarks.md @@ -3,9 +3,12 @@ title: "Redis benchmark" linkTitle: "Benchmarking" weight: 1 description: > - Using the redis-benchmark utility to benchmark a Redis server -aliases: - - /topics/benchmarks + Using the redis-benchmark utility on a Redis server +aliases: [ + /topics/benchmarks, + /docs/reference/optimization/benchmarks, + /docs/reference/optimization/benchmarks.md +] --- Redis includes the `redis-benchmark` utility that simulates running commands done @@ -287,4 +290,4 @@ documentation for more information about its goals and capabilities. * [memtier_benchmark](https://github.com/redislabs/memtier_benchmark) from [Redis Ltd.](https://twitter.com/RedisInc) is a NoSQL Redis and Memcache traffic generation and benchmarking tool. * [rpc-perf](https://github.com/twitter/rpc-perf) from [Twitter](https://twitter.com/twitter) is a tool for benchmarking RPC services that supports Redis and Memcache. -* [YCSB](https://github.com/brianfrankcooper/YCSB) from [Yahoo @Yahoo](https://twitter.com/Yahoo) is a benchmarking framework with clients to many databases, including Redis. +* [YCSB](https://github.com/brianfrankcooper/YCSB) from [Yahoo @Yahoo](https://twitter.com/Yahoo) is a benchmarking framework with clients to many databases, including Redis. diff --git a/docs/reference/optimization/cpu-profiling.md b/docs/management/optimization/cpu-profiling.md similarity index 99% rename from docs/reference/optimization/cpu-profiling.md rename to docs/management/optimization/cpu-profiling.md index 53371e43e1..9852b12693 100644 --- a/docs/reference/optimization/cpu-profiling.md +++ b/docs/management/optimization/cpu-profiling.md @@ -4,8 +4,10 @@ linkTitle: "CPU profiling" weight: 1 description: > Performance engineering guide for on-CPU profiling and tracing -aliases: - - /topics/performance-on-cpu +aliases: [ + /topics/performance-on-cpu, + /docs/reference/optimization/cpu-profiling +] --- ## Filling the performance checklist diff --git a/docs/reference/optimization/latency-monitor.md b/docs/management/optimization/latency-monitor.md similarity index 98% rename from docs/reference/optimization/latency-monitor.md rename to docs/management/optimization/latency-monitor.md index bbb96c707d..07809edb28 100644 --- a/docs/reference/optimization/latency-monitor.md +++ b/docs/management/optimization/latency-monitor.md @@ -3,8 +3,10 @@ title: "Redis latency monitoring" linkTitle: "Latency monitoring" weight: 1 description: Discovering slow server events in Redis -aliases: - - /topics/latency-monitor +aliases: [ + /topics/latency-monitor, + /docs/reference/optimization/latency-monitor +] --- Redis is often used for demanding use cases, where it diff --git a/docs/reference/optimization/latency.md b/docs/management/optimization/latency.md similarity index 99% rename from docs/reference/optimization/latency.md rename to docs/management/optimization/latency.md index ce214915a0..1419fa8fc6 100644 --- a/docs/reference/optimization/latency.md +++ b/docs/management/optimization/latency.md @@ -3,8 +3,10 @@ title: "Diagnosing latency issues" linkTitle: "Latency diagnosis" weight: 1 description: Finding the causes of slow responses -aliases: - - /topics/latency +aliases: [ + /topics/latency, + /docs/reference/optimization/latency +] --- This document will help you understand what the problem could be if you diff --git a/docs/reference/optimization/memory-optimization.md b/docs/management/optimization/memory-optimization.md similarity index 99% rename from docs/reference/optimization/memory-optimization.md rename to docs/management/optimization/memory-optimization.md index 0b3b822f38..0d77bc7f84 100644 --- a/docs/reference/optimization/memory-optimization.md +++ b/docs/management/optimization/memory-optimization.md @@ -3,8 +3,10 @@ title: Memory optimization linkTitle: Memory optimization description: Strategies for optimizing memory usage in Redis weight: 1 -aliases: - - /topics/memory-optimization +aliases: [ + /topics/memory-optimization, + /docs/reference/optimization/memory-optimization +] --- ## Special encoding of small aggregate data types diff --git a/docs/manual/persistence.md b/docs/management/persistence.md similarity index 99% rename from docs/manual/persistence.md rename to docs/management/persistence.md index 8c3b432909..e2e4be102b 100644 --- a/docs/manual/persistence.md +++ b/docs/management/persistence.md @@ -1,13 +1,13 @@ --- title: Redis persistence linkTitle: Persistence -weight: 1 -description: How Redis writes data to disk (append-only files, snapshots, etc.) +weight: 7 +description: How Redis writes data to disk aliases: [ /topics/persistence, /topics/persistence.md, - /manual/persistence, - /manual/persistence.md, + /docs/manual/persistence, + /docs/manual/persistence.md ] --- diff --git a/docs/manual/replication.md b/docs/management/replication.md similarity index 99% rename from docs/manual/replication.md rename to docs/management/replication.md index bac6b83a4c..145fc394b6 100644 --- a/docs/manual/replication.md +++ b/docs/management/replication.md @@ -1,13 +1,13 @@ --- title: Redis replication linkTitle: Replication -weight: 1 +weight: 5 description: How Redis supports high availability and failover with replication aliases: [ /topics/replication, /topics/replication.md, - /manual/replication, - /manual/replication.md, + /docs/manual/replication, + /docs/manual/replication.md ] --- diff --git a/docs/manual/scaling.md b/docs/management/scaling.md similarity index 99% rename from docs/manual/scaling.md rename to docs/management/scaling.md index ad8d5ae273..2863fac665 100644 --- a/docs/manual/scaling.md +++ b/docs/management/scaling.md @@ -1,11 +1,14 @@ --- title: Scaling with Redis Cluster linkTitle: Scaling -weight: 1 +weight: 6 description: Horizontal scaling with Redis Cluster -aliases: - - /topics/cluster-tutorial - - /topics/partitioning +aliases: [ + /topics/cluster-tutorial, + /topics/partitioning, + /docs/manual/scaling, + /docs/manual/scaling.md +] --- Redis scales horizontally with a deployment topology called Redis Cluster. diff --git a/docs/manual/security/_index.md b/docs/management/security/_index.md similarity index 99% rename from docs/manual/security/_index.md rename to docs/management/security/_index.md index f7b295d1ae..fa2d71390c 100644 --- a/docs/manual/security/_index.md +++ b/docs/management/security/_index.md @@ -3,8 +3,11 @@ title: "Redis security" linkTitle: "Security" weight: 1 description: Security model and features in Redis -aliases: - - /topics/security +aliases: [ + /topics/security, + /docs/manual/security, + /docs/manual/security.md +] --- This document provides an introduction to the topic of security from the point of diff --git a/docs/manual/security/acl.md b/docs/management/security/acl.md similarity index 99% rename from docs/manual/security/acl.md rename to docs/management/security/acl.md index b983a02a3c..f68d09304b 100644 --- a/docs/manual/security/acl.md +++ b/docs/management/security/acl.md @@ -3,8 +3,11 @@ title: "ACL" linkTitle: "ACL" weight: 1 description: Redis Access Control List -aliases: - - /topics/acl +aliases: [ + /topics/acl, + /docs/manual/security/acl, + /docs/manual/security/acl.md +] --- The Redis ACL, short for Access Control List, is the feature that allows certain diff --git a/docs/manual/security/encryption.md b/docs/management/security/encryption.md similarity index 97% rename from docs/manual/security/encryption.md rename to docs/management/security/encryption.md index 33407aeb05..28f3db69f7 100644 --- a/docs/manual/security/encryption.md +++ b/docs/management/security/encryption.md @@ -3,8 +3,11 @@ title: "TLS" linkTitle: "TLS" weight: 1 description: Redis TLS support -aliases: - - /topics/encryption +aliases: [ + /topics/encryption, + /docs/manual/security/encryption, + /docs/manual/security/encryption.md +] --- SSL/TLS is supported by Redis starting with version 6 as an optional feature diff --git a/docs/manual/sentinel.md b/docs/management/sentinel.md similarity index 99% rename from docs/manual/sentinel.md rename to docs/management/sentinel.md index 03e84d72d1..63cc24c11e 100644 --- a/docs/manual/sentinel.md +++ b/docs/management/sentinel.md @@ -1,10 +1,13 @@ --- title: "High availability with Redis Sentinel" linkTitle: "High availability with Sentinel" -weight: 1 +weight: 4 description: High availability for non-clustered Redis -aliases: - - /topics/sentinel +aliases: [ + /topics/sentinel, + /docs/manual/sentinel, + /docs/manual/sentinel.md +] --- Redis Sentinel provides high availability for Redis when not using [Redis Cluster](/docs/manual/scaling). diff --git a/docs/manual/troubleshooting.md b/docs/management/troubleshooting.md similarity index 95% rename from docs/manual/troubleshooting.md rename to docs/management/troubleshooting.md index 5264c8b701..8c19c906c8 100644 --- a/docs/manual/troubleshooting.md +++ b/docs/management/troubleshooting.md @@ -1,10 +1,13 @@ --- title: "Troubleshooting Redis" linkTitle: "Troubleshooting" -weight: 1 +weight: 9 description: Problems with Redis? Start here. -aliases: - - /topics/problems +aliases: [ + /topics/problems, + /docs/manual/troubleshooting, + /docs/manual/troubleshooting.md +] --- This page tries to help you with what to do if you have issues with Redis. Part of the Redis project is helping people that are experiencing problems because we don't like to leave people alone with their issues. diff --git a/docs/manual/_index.md b/docs/manual/_index.md index 760810a813..ec7112aa66 100644 --- a/docs/manual/_index.md +++ b/docs/manual/_index.md @@ -1,6 +1,6 @@ --- -title: "The Redis manual" -linkTitle: "Manual" +title: "Using Redis" +linkTitle: "Using Redis" description: A developer's guide to Redis -weight: 20 +weight: 5 --- diff --git a/docs/manual/keyspace-notifications.md b/docs/manual/keyspace-notifications.md index 6f4d1cbbf0..380180a771 100644 --- a/docs/manual/keyspace-notifications.md +++ b/docs/manual/keyspace-notifications.md @@ -1,7 +1,7 @@ --- title: "Redis keyspace notifications" linkTitle: "Keyspace notifications" -weight: 1 +weight: 3 description: > Monitor changes to Redis keys and values in real time aliases: diff --git a/docs/reference/patterns/_index.md b/docs/manual/patterns/_index.md similarity index 81% rename from docs/reference/patterns/_index.md rename to docs/manual/patterns/_index.md index 0802b5e6f2..3a3246f713 100644 --- a/docs/reference/patterns/_index.md +++ b/docs/manual/patterns/_index.md @@ -2,7 +2,10 @@ title: "Redis programming patterns" linkTitle: "Patterns" description: Novel patterns for working with Redis data structures -weight: 1 +weight: 6 +aliases: [ + /docs/reference/patterns +] --- The following documents describe some novel development patterns you can use with Redis. diff --git a/docs/reference/patterns/bulk-loading.md b/docs/manual/patterns/bulk-loading.md similarity index 98% rename from docs/reference/patterns/bulk-loading.md rename to docs/manual/patterns/bulk-loading.md index f09cef74fe..8676291f2e 100644 --- a/docs/reference/patterns/bulk-loading.md +++ b/docs/manual/patterns/bulk-loading.md @@ -4,8 +4,10 @@ linkTitle: "Bulk loading" weight: 1 description: > Writing data in bulk using the Redis protocol -aliases: - - /topics/mass-insertion +aliases: [ + /topics/mass-insertion, + /docs/reference/patterns/bulk-loading +] --- Bulk loading is the process of loading Redis with a large amount of pre-existing data. Ideally, you want to perform this operation quickly and efficiently. This document describes some strategies for bulk loading data in Redis. diff --git a/docs/reference/patterns/distributed-locks.md b/docs/manual/patterns/distributed-locks.md similarity index 99% rename from docs/reference/patterns/distributed-locks.md rename to docs/manual/patterns/distributed-locks.md index 58a4a6761d..01aa057b91 100644 --- a/docs/reference/patterns/distributed-locks.md +++ b/docs/manual/patterns/distributed-locks.md @@ -3,9 +3,12 @@ title: "Distributed Locks with Redis" linkTitle: "Distributed locks" weight: 1 description: > - A Distributed Lock Pattern with Redis -aliases: - - /topics/distlock + A distributed lock pattern with Redis +aliases: [ + /topics/distlock, + /docs/reference/patterns/distributed-locks, + /docs/reference/patterns/distributed-locks.md +] --- Distributed locks are a very useful primitive in many environments where different processes must operate with shared resources in a mutually diff --git a/docs/reference/patterns/indexes.md b/docs/manual/patterns/indexes.md similarity index 99% rename from docs/reference/patterns/indexes.md rename to docs/manual/patterns/indexes.md index 09011bac24..8164864fd9 100644 --- a/docs/reference/patterns/indexes.md +++ b/docs/manual/patterns/indexes.md @@ -4,8 +4,10 @@ linkTitle: Secondary indexing weight: 1 description: > Building secondary indexes in Redis -aliases: - - /topics/indexing +aliases: [ + /topics/indexing, + /docs/reference/patterns/indexes +] --- Redis is not exactly a key-value store, since values can be complex data structures. However it has an external key-value shell: at API level data is addressed by the key name. It is fair to say that, natively, Redis only offers *primary key access*. However since Redis is a data structures server, its capabilities can be used for indexing, in order to create secondary indexes of different kinds, including composite (multi-column) indexes. diff --git a/docs/reference/patterns/twitter-clone.md b/docs/manual/patterns/twitter-clone.md similarity index 99% rename from docs/reference/patterns/twitter-clone.md rename to docs/manual/patterns/twitter-clone.md index 38a01059cd..f8d39d134e 100644 --- a/docs/reference/patterns/twitter-clone.md +++ b/docs/manual/patterns/twitter-clone.md @@ -3,6 +3,9 @@ title: "Redis patterns example" linkTitle: "Patterns example" description: Learn several Redis patterns by building a Twitter clone weight: 20 +aliases: [ + /docs/reference/patterns/twitter-clone +] --- This article describes the design and implementation of a [very simple Twitter clone](https://github.com/antirez/retwis) written using PHP with Redis as the only database. The programming community has traditionally considered key-value stores as a special purpose database that couldn't be used as a drop-in replacement for a relational database for the development of web applications. This article will try to show that Redis data structures on top of a key-value layer are an effective data model to implement many kinds of applications. diff --git a/docs/manual/pipelining.md b/docs/manual/pipelining.md index e1653925b7..605074f434 100644 --- a/docs/manual/pipelining.md +++ b/docs/manual/pipelining.md @@ -1,7 +1,7 @@ --- title: "Redis pipelining" linkTitle: "Pipelining" -weight: 1 +weight: 2 description: How to optimize round-trip times by batching Redis commands aliases: - /topics/pipelining diff --git a/docs/manual/programmability/_index.md b/docs/manual/programmability/_index.md index 48b2ca1c91..9508d17e04 100644 --- a/docs/manual/programmability/_index.md +++ b/docs/manual/programmability/_index.md @@ -1,7 +1,7 @@ --- title: "Redis programmability" linkTitle: "Programmability" -weight: 1 +weight: 7 description: > Extending Redis with Lua and Redis Functions aliases: diff --git a/docs/manual/pubsub.md b/docs/manual/pubsub.md index fac9e917a4..eb18120a11 100644 --- a/docs/manual/pubsub.md +++ b/docs/manual/pubsub.md @@ -1,7 +1,7 @@ --- title: Redis Pub/Sub linkTitle: "Pub/sub" -weight: 1 +weight: 4 description: How to use pub/sub channels in Redis aliases: - /topics/pubsub diff --git a/docs/manual/transactions.md b/docs/manual/transactions.md index 02e06b7e12..b75a41d838 100644 --- a/docs/manual/transactions.md +++ b/docs/manual/transactions.md @@ -1,7 +1,7 @@ --- title: Transactions linkTitle: Transactions -weight: 1 +weight: 5 description: How transactions work in Redis aliases: - /topics/transactions diff --git a/docs/modules/index.md b/docs/modules/index.md index 9911c06691..45201fde59 100644 --- a/docs/modules/index.md +++ b/docs/modules/index.md @@ -1,7 +1,7 @@ --- title: "Modules" linkTitle: "Modules" -weight: 13 +weight: 10 description: List of Redis modules layout: bazzar bazzar: modules diff --git a/docs/reference/_index.md b/docs/reference/_index.md index eeed48e834..fb85a77771 100644 --- a/docs/reference/_index.md +++ b/docs/reference/_index.md @@ -1,6 +1,6 @@ --- title: "Redis reference" linkTitle: "Reference" -description: Specifications, patterns, internals, and optimization -weight: 20 +description: Specifications and protocols +weight: 7 --- diff --git a/docs/reference/arm.md b/docs/reference/arm.md index 2eec312367..e0323160f3 100644 --- a/docs/reference/arm.md +++ b/docs/reference/arm.md @@ -1,7 +1,7 @@ --- title: "ARM support" linkTitle: "ARM support" -weight: 1 +weight: 11 description: > Exploring Redis on the ARM CPU Architecture aliases: diff --git a/docs/reference/clients.md b/docs/reference/clients.md index b5da8d83e9..25068b5ec1 100644 --- a/docs/reference/clients.md +++ b/docs/reference/clients.md @@ -1,7 +1,7 @@ --- title: "Redis client handling" linkTitle: "Client handling" -weight: 1 +weight: 5 description: > How the Redis server manages client connections aliases: diff --git a/docs/reference/cluster-spec.md b/docs/reference/cluster-spec.md index 4261662338..64c8016980 100644 --- a/docs/reference/cluster-spec.md +++ b/docs/reference/cluster-spec.md @@ -1,7 +1,7 @@ --- title: Redis cluster specification linkTitle: Cluster spec -weight: 1 +weight: 9 description: > Detailed specification for Redis cluster aliases: diff --git a/docs/reference/command-arguments.md b/docs/reference/command-arguments.md index 8984a23785..a6ff30189e 100644 --- a/docs/reference/command-arguments.md +++ b/docs/reference/command-arguments.md @@ -1,7 +1,7 @@ --- title: "Redis command arguments" linkTitle: "Command arguments" -weight: 1 +weight: 7 description: How Redis commands expose their documentation programmatically aliases: - /topics/command-arguments diff --git a/docs/manual/eviction.md b/docs/reference/eviction.md similarity index 99% rename from docs/manual/eviction.md rename to docs/reference/eviction.md index 7f46cc436d..a50ca1070c 100644 --- a/docs/manual/eviction.md +++ b/docs/reference/eviction.md @@ -1,7 +1,7 @@ --- title: Key eviction linkTitle: Eviction -weight: 1 +weight: 6 description: Overview of Redis key eviction policies (LRU, LFU, etc.) aliases: [ /topics/lru_cache, diff --git a/docs/reference/gopher.md b/docs/reference/gopher.md index 92a25e2136..f34812323c 100644 --- a/docs/reference/gopher.md +++ b/docs/reference/gopher.md @@ -1,7 +1,7 @@ --- title: "Redis and the Gopher protocol" linkTitle: "Gopher protocol" -weight: 1 +weight: 10 description: The Redis Gopher protocol implementation aliases: - /topics/gopher diff --git a/docs/reference/internals/_index.md b/docs/reference/internals/_index.md index 3aea94d563..43f6409921 100644 --- a/docs/reference/internals/_index.md +++ b/docs/reference/internals/_index.md @@ -1,7 +1,7 @@ --- title: "Redis internals" linkTitle: "Internals" -weight: 1 +weight: 12 description: Documents describing internals in early Redis implementations aliases: - /topics/internals diff --git a/docs/reference/key-specs.md b/docs/reference/key-specs.md index 95e874f145..8bbc215f76 100644 --- a/docs/reference/key-specs.md +++ b/docs/reference/key-specs.md @@ -1,7 +1,7 @@ --- title: "Command key specifications" linkTitle: "Command key specifications" - weight: 1 + weight: 3 description: What are command key specification and how to use them in your client aliases: - /topics/key-specs diff --git a/docs/reference/modules/_index.md b/docs/reference/modules/_index.md index 64e3b1d9aa..1823e4b485 100644 --- a/docs/reference/modules/_index.md +++ b/docs/reference/modules/_index.md @@ -1,7 +1,7 @@ --- title: "Redis modules API" linkTitle: "Modules API" -weight: 1 +weight: 2 description: > Introduction to writing Redis modules aliases: diff --git a/docs/reference/protocol-spec.md b/docs/reference/protocol-spec.md index 9ae6cc3129..732e81b01a 100644 --- a/docs/reference/protocol-spec.md +++ b/docs/reference/protocol-spec.md @@ -1,7 +1,7 @@ --- title: "RESP protocol spec" linkTitle: "Protocol spec" -weight: 1 +weight: 4 description: Redis serialization protocol (RESP) specification aliases: - /topics/protocol diff --git a/docs/reference/signals.md b/docs/reference/signals.md index 4a63ce3c0b..1aae7d5116 100644 --- a/docs/reference/signals.md +++ b/docs/reference/signals.md @@ -1,7 +1,7 @@ --- title: "Redis signal handling" linkTitle: "Signal handling" -weight: 1 +weight: 8 description: How Redis handles common Unix signals aliases: - /topics/signals diff --git a/docs/tools/index.md b/docs/tools/index.md index 8d8c31424c..eabf562dec 100644 --- a/docs/tools/index.md +++ b/docs/tools/index.md @@ -1,7 +1,7 @@ --- title: "Tools" linkTitle: "Tools" -weight: 12 +weight: 9 description: A list of tools for Redis layout: bazzar bazzar: tools diff --git a/wordlist b/wordlist index e72679d721..abb56f2617 100644 --- a/wordlist +++ b/wordlist @@ -478,10 +478,12 @@ codenamed commandstats commnad config +config-file configEpoch configs const cpu +cpu-profiling cron cryptographic ctx From 7e10889b4138e0dde5f8dbcaf86107df18d55bf7 Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Wed, 2 Nov 2022 18:44:55 -0400 Subject: [PATCH 069/377] Fixes broken links (#2193) --- docs/data-types/streams.md | 2 +- docs/management/optimization/memory-optimization.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data-types/streams.md b/docs/data-types/streams.md index 1949c832cf..f55469df06 100644 --- a/docs/data-types/streams.md +++ b/docs/data-types/streams.md @@ -78,4 +78,4 @@ See each command's time complexity for the details. * The [Redis Streams Tutorial](/docs/data-types/streams-tutorial) explains Redis streams with many examples. * [Redis Streams Explained](https://www.youtube.com/watch?v=Z8qcpXyMAiA) is an entertaining introduction to streams in Redis. -* [Redis University's RU102](https://university.redis.com/courses/ru102/) is a free, online course dedicated to Redis Streams. +* [Redis University's RU202](https://university.redis.com/courses/ru202/) is a free, online course dedicated to Redis Streams. diff --git a/docs/management/optimization/memory-optimization.md b/docs/management/optimization/memory-optimization.md index 0d77bc7f84..bfee9912ae 100644 --- a/docs/management/optimization/memory-optimization.md +++ b/docs/management/optimization/memory-optimization.md @@ -223,7 +223,7 @@ To store user keys, Redis allocates at most as much memory as the `maxmemory` setting enables (however there are small extra allocations possible). The exact value can be set in the configuration file or set later via -`CONFIG SET` (see [Using memory as an LRU cache for more info](https://redis.io/topics/lru-cache)). +`CONFIG SET` (for more info, see [Using memory as an LRU cache](/docs/reference/eviction)). There are a few things that should be noted about how Redis manages memory: * Redis will not always free up (return) memory to the OS when keys are removed. From 954171f3100e2d331fe94cf01842b42f05456989 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Thu, 3 Nov 2022 21:43:43 +0200 Subject: [PATCH 070/377] Moves community projects to resources (#2187) --- .spellcheck.yml | 8 ++++---- docs/libraries/index.md | 9 --------- docs/tools/index.md | 9 --------- resources/_index.md | 8 ++++++++ {docs => resources}/clients/index.md | 5 +++-- resources/libraries/index.md | 11 +++++++++++ {docs => resources}/modules/index.md | 5 +++-- resources/tools/index.md | 11 +++++++++++ wordlist | 1 + 9 files changed, 41 insertions(+), 26 deletions(-) delete mode 100644 docs/libraries/index.md delete mode 100644 docs/tools/index.md create mode 100644 resources/_index.md rename {docs => resources}/clients/index.md (50%) create mode 100644 resources/libraries/index.md rename {docs => resources}/modules/index.md (51%) create mode 100644 resources/tools/index.md diff --git a/.spellcheck.yml b/.spellcheck.yml index c411a380e8..b63649b810 100644 --- a/.spellcheck.yml +++ b/.spellcheck.yml @@ -1,9 +1,9 @@ files: - '**/*.md' - - '!docs/clients/index.md' - - '!docs/libraries/index.md' - - '!docs/modules/index.md' - - '!docs/tools/index.md' + - '!resources/clients/index.md' + - '!resources/libraries/index.md' + - '!resources/modules/index.md' + - '!resources/tools/index.md' - '!docs/reference/modules/modules-api-ref.md' dictionaries: - wordlist diff --git a/docs/libraries/index.md b/docs/libraries/index.md deleted file mode 100644 index cf636bcd06..0000000000 --- a/docs/libraries/index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Libraries" -linkTitle: "Libraries" -weight: 8 -description: Libraries that use Redis -layout: bazzar -bazzar: libraries ---- - diff --git a/docs/tools/index.md b/docs/tools/index.md deleted file mode 100644 index eabf562dec..0000000000 --- a/docs/tools/index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Tools" -linkTitle: "Tools" -weight: 9 -description: A list of tools for Redis -layout: bazzar -bazzar: tools ---- - diff --git a/resources/_index.md b/resources/_index.md new file mode 100644 index 0000000000..ba4bf01a2b --- /dev/null +++ b/resources/_index.md @@ -0,0 +1,8 @@ +--- +title: Resources +linkTitle: Resources +description: Open-source and source-available projects for connecting, using, managing, and extending Redis. +type: docs +--- + +The following sections are lists of open-source and source-available projects. diff --git a/docs/clients/index.md b/resources/clients/index.md similarity index 50% rename from docs/clients/index.md rename to resources/clients/index.md index 795a03cbea..288ab72292 100644 --- a/docs/clients/index.md +++ b/resources/clients/index.md @@ -1,12 +1,13 @@ --- title: "Clients" linkTitle: "Clients" -weight: 4 -description: Redis clients +weight: 10 +description: Implementations of the Redis' protocol in different programming languages layout: bazzar bazzar: clients aliases: - /clients - /clients/ + - /docs/clients --- diff --git a/resources/libraries/index.md b/resources/libraries/index.md new file mode 100644 index 0000000000..711891a988 --- /dev/null +++ b/resources/libraries/index.md @@ -0,0 +1,11 @@ +--- +title: "Libraries" +linkTitle: "Libraries" +weight: 11 +description: Libraries that use Redis and can be used by applications +layout: bazzar +bazzar: libraries +aliases: + - /docs/libraries/ +--- + diff --git a/docs/modules/index.md b/resources/modules/index.md similarity index 51% rename from docs/modules/index.md rename to resources/modules/index.md index 45201fde59..adebb01500 100644 --- a/docs/modules/index.md +++ b/resources/modules/index.md @@ -1,12 +1,13 @@ --- title: "Modules" linkTitle: "Modules" -weight: 10 -description: List of Redis modules +weight: 13 +description: Redis modules extend the server's functionality in various ways layout: bazzar bazzar: modules aliases: - /modules - /modules/ + - /docs/modules/ --- diff --git a/resources/tools/index.md b/resources/tools/index.md new file mode 100644 index 0000000000..edb4575bd9 --- /dev/null +++ b/resources/tools/index.md @@ -0,0 +1,11 @@ +--- +title: "Tools" +linkTitle: "Tools" +weight: 12 +description: Tools for managing and deploying Redis +layout: bazzar +bazzar: tools +aliases: + - /docs/tools/ +--- + diff --git a/wordlist b/wordlist index abb56f2617..fdbc4a4c29 100644 --- a/wordlist +++ b/wordlist @@ -292,6 +292,7 @@ RSS RTT RU101 RU102 +RU202 RW Rebranding Reconfiguring From 3d4b7f985cdd0de4d2f7ab55c0f8c549083d80f2 Mon Sep 17 00:00:00 2001 From: Kyle Banker Date: Fri, 4 Nov 2022 11:31:58 -0600 Subject: [PATCH 071/377] Fix aliases --- docs/management/config.md | 2 +- docs/reference/eviction.md | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/management/config.md b/docs/management/config.md index db09e0fb1f..a971ae0bdc 100644 --- a/docs/management/config.md +++ b/docs/management/config.md @@ -5,7 +5,7 @@ weight: 2 description: > Overview of redis.conf, the Redis configuration file aliases: [ - /docs/management/config + /docs/manual/config ] --- diff --git a/docs/reference/eviction.md b/docs/reference/eviction.md index a50ca1070c..a0d87ebd8a 100644 --- a/docs/reference/eviction.md +++ b/docs/reference/eviction.md @@ -6,8 +6,7 @@ description: Overview of Redis key eviction policies (LRU, LFU, etc.) aliases: [ /topics/lru_cache, /topics/lru_cache.md, - /manual/eviction, - /manual/eviction.md, + /docs/manual/eviction ] --- From 2218ed526692e0077194092b429fb9cc7a20cb0a Mon Sep 17 00:00:00 2001 From: Noah Abe Date: Tue, 8 Nov 2022 13:26:53 +0300 Subject: [PATCH 072/377] tense change of the word "execute" (#2202) --- docs/data-types/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/tutorial.md b/docs/data-types/tutorial.md index 715ee7c6d5..8986ddce9a 100644 --- a/docs/data-types/tutorial.md +++ b/docs/data-types/tutorial.md @@ -303,7 +303,7 @@ Lists are useful for a number of tasks, two very representative use cases are the following: * Remember the latest updates posted by users into a social network. -* Communication between processes, using a consumer-producer pattern where the producer pushes items into a list, and a consumer (usually a *worker*) consumes those items and executed actions. Redis has special list commands to make this use case both more reliable and efficient. +* Communication between processes, using a consumer-producer pattern where the producer pushes items into a list, and a consumer (usually a *worker*) consumes those items and executes actions. Redis has special list commands to make this use case both more reliable and efficient. For example both the popular Ruby libraries [resque](https://github.com/resque/resque) and [sidekiq](https://github.com/mperham/sidekiq) use Redis lists under the hood in order to From 75539fd789118d7a7b07772b6cd3f8055e89a912 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Tue, 8 Nov 2022 17:23:25 +0200 Subject: [PATCH 073/377] Removed recommendation (#2204) --- clients/java/github.com/mrniko/redisson.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clients/java/github.com/mrniko/redisson.json b/clients/java/github.com/mrniko/redisson.json index e6c235317e..b2c4ed4d13 100644 --- a/clients/java/github.com/mrniko/redisson.json +++ b/clients/java/github.com/mrniko/redisson.json @@ -1,8 +1,7 @@ { "name": "Redisson", "description": "distributed and scalable Java data structures on top of Redis server", - "recommended": true, "twitter": [ "mrniko" ] -} \ No newline at end of file +} From 3b594d31029b738b70aee51ff68fae19d437f642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20S=C3=B6derqvist?= Date: Wed, 9 Nov 2022 15:00:53 +0100 Subject: [PATCH 074/377] Add note to QUIT that clients should not use it (#2205) --- commands/quit.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/commands/quit.md b/commands/quit.md index 6be9b55dd8..b4cf337338 100644 --- a/commands/quit.md +++ b/commands/quit.md @@ -2,6 +2,10 @@ Ask the server to close the connection. The connection is closed as soon as all pending replies have been written to the client. +**Note:** Clients should not use this command. +Instead, clients should simply close the connection when they're not used anymore. +Terminating a connection on the client side is preferable, as it eliminates `TIME_WAIT` lingering sockets on the server side. + @return @simple-string-reply: always OK. From 2b711c0c74375e373c53a897b81005f64692dbdc Mon Sep 17 00:00:00 2001 From: Antonin De Jesus <30664047+YngProgrammer@users.noreply.github.com> Date: Thu, 10 Nov 2022 19:44:48 +0100 Subject: [PATCH 075/377] Replace dead link for key eviction (#2201) --- docs/about/_index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/about/_index.md b/docs/about/_index.md index 2b0bbf590a..629974adc3 100644 --- a/docs/about/_index.md +++ b/docs/about/_index.md @@ -9,7 +9,7 @@ aliases: --- Redis is an open source (BSD licensed), in-memory __data structure store__ used as a database, cache, message broker, and streaming engine. Redis provides [data structures](/docs/data-types/) such as -[strings](/docs/data-types/strings/), [hashes](/docs/data-types/hashes/), [lists](/docs/data-types/lists/), [sets](/docs/data-types/lists/), [sorted sets](/docs/data-types/sorted-sets/) with range queries, [bitmaps](/docs/data-types/bitmaps/), [hyperloglogs](/docs/data-types/hyperloglogs/), [geospatial indexes](/docs/data-types/geospatial/), and [streams](/docs/data-types/streams/). Redis has built-in [replication](/topics/replication), [Lua scripting](/commands/eval), [LRU eviction](/topics/lru-cache), [transactions](/topics/transactions), and different levels of [on-disk persistence](/topics/persistence), and provides high availability via [Redis Sentinel](/topics/sentinel) and automatic partitioning with [Redis Cluster](/topics/cluster-tutorial). +[strings](/docs/data-types/strings/), [hashes](/docs/data-types/hashes/), [lists](/docs/data-types/lists/), [sets](/docs/data-types/lists/), [sorted sets](/docs/data-types/sorted-sets/) with range queries, [bitmaps](/docs/data-types/bitmaps/), [hyperloglogs](/docs/data-types/hyperloglogs/), [geospatial indexes](/docs/data-types/geospatial/), and [streams](/docs/data-types/streams/). Redis has built-in [replication](/topics/replication), [Lua scripting](/commands/eval), [LRU eviction](/docs/reference/eviction/), [transactions](/topics/transactions), and different levels of [on-disk persistence](/topics/persistence), and provides high availability via [Redis Sentinel](/topics/sentinel) and automatic partitioning with [Redis Cluster](/topics/cluster-tutorial). You can run __atomic operations__ on these types, like [appending to a string](/commands/append); @@ -31,7 +31,7 @@ Redis also includes: * [Pub/Sub](/topics/pubsub) * [Lua scripting](/commands/eval) * [Keys with a limited time-to-live](/commands/expire) -* [LRU eviction of keys](/topics/lru-cache) +* [LRU eviction of keys](/docs/reference/eviction) * [Automatic failover](/topics/sentinel) You can use Redis from [most programming languages](/clients). From 09a6b41cdd612d5cb36442c4590707da6498b397 Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Thu, 10 Nov 2022 13:49:36 -0500 Subject: [PATCH 076/377] [BUG FIX] Remove a typo and copyedit content (#2114) * Fixes #2108 plus copyedits * Update commands/acl-setuser.md * Update commands/acl-setuser.md * Update commands/acl-setuser.md Co-authored-by: Itamar Haber * Update commands/acl-setuser.md Co-authored-by: Itamar Haber * Update commands/acl-setuser.md Co-authored-by: Itamar Haber Co-authored-by: Itamar Haber --- commands/acl-setuser.md | 75 ++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/commands/acl-setuser.md b/commands/acl-setuser.md index a6ae4a8e03..7cda6e8b49 100644 --- a/commands/acl-setuser.md +++ b/commands/acl-setuser.md @@ -1,32 +1,31 @@ Create an ACL user with the specified rules or modify the rules of an -existing user. This is the main interface in order to manipulate Redis ACL -users interactively: if the username does not exist, the command creates -the username without any privilege, then reads from left to right all the -rules provided as successive arguments, setting the user ACL rules as specified. +existing user. +Manipulate Redis ACL users interactively. +If the username does not exist, the command creates the username without any privilege. +It then reads from left to right all the [rules](#acl-rules) provided as successive arguments, setting the user ACL rules as specified. If the user already exists, the provided ACL rules are simply applied *in addition* to the rules already set. For example: ACL SETUSER virginia on allkeys +set -The above command will create a user called `virginia` that is active -(the on rule), can access any key (allkeys rule), and can call the -set command (+set rule). Then another SETUSER call can modify the user rules: +The above command creates a user called `virginia` who is active(the _on_ rule), can access any key (_allkeys_ rule), and can call the set command (_+set_ rule). +Then, you can use another `ACL SETUSER` call to modify the user rules: ACL SETUSER virginia +get -The above rule will not apply the new rule to the user virginia, so other than `SET`, the user virginia will now be able to also use the `GET` command. +The above rule applies the new rule to the user `virginia`, so other than `SET`, the user `virginia` can now also use the `GET` command. -Starting from Redis 7.0, ACL rules can also be grouped into multiple distinct sets of rules, called selectors. +Starting from Redis 7.0, ACL rules can also be grouped into multiple distinct sets of rules, called _selectors_. Selectors are added by wrapping the rules in parentheses and providing them just like any other rule. In order to execute a command, either the root permissions (rules defined outside of parenthesis) or any of the selectors (rules defined inside parenthesis) must match the given command. For example: ACL SETUSER virginia on +GET allkeys (+SET ~app1*) -This sets a user with two sets of permission, one defined on the user and one defined with a selector. -The root user permissions only allows executing the get command, but can be executed on any keys. -The selector then grants a secondary set of permissions: access to the `SET` command to be executed on any key that starts with "app1". +This sets a user with two sets of permissions, one defined on the user and one defined with a selector. +The root user permissions only allow executing the get command, but can be executed on any keys. +The selector then grants a secondary set of permissions: access to the `SET` command to be executed on any key that starts with `app1`. Using multiple selectors allows you to grant permissions that are different depending on what keys are being accessed. When we want to be sure to define a user from scratch, without caring if @@ -35,9 +34,7 @@ it had previously defined rules associated, we can use the special rule ACL SETUSER antirez reset [... other rules ...] -After resetting a user, it returns back to the status it has when it -was just created: non active (off rule), can't execute any command, can't -access any key: +After resetting a user, its ACL rules revert to the default: inactive, passwordless, can't execute any command nor access any key or channel: > ACL SETUSER antirez reset +OK @@ -50,42 +47,42 @@ another string (without any space in between), like "+SET". The following documentation is a reference manual about the capabilities of this command, however our [ACL tutorial](/topics/acl) may be a more gentle introduction to how the ACL system works in general. -## List of rules +## ACL rules -Redis ACL rules are split into two categories: rules that define command permissions, "Command rules", and rules that define user state, "User management rules". +Redis ACL rules are split into two categories: rules that define command permissions or _command rules_, and rules that define the user state or _user management rules_. This is a list of all the supported Redis ACL rules: ### Command rules -* `~`: add the specified key pattern (glob style pattern, like in the `KEYS` command), to the list of key patterns accessible by the user. This grants both read and write permissions to keys that match the pattern. You can add multiple key patterns to the same user. Example: `~objects:*` -* `%R~`: (Available in Redis 7.0 and later) Add the specified read key pattern. This behaves similar to the regular key pattern but only grants permission to read from keys that match the given pattern. See [key permissions](/topics/acl#key-permissions) for more information. -* `%W~`: (Available in Redis 7.0 and later) Add the specified write key pattern. This behaves similar to the regular key pattern but only grants permission to write to keys that match the given pattern. See [key permissions](/topics/acl#key-permissions) for more information. +* `~`: Adds the specified key pattern (glob style pattern, like in the `KEYS` command), to the list of key patterns accessible by the user. This grants both read and write permissions to keys that match the pattern. You can add multiple key patterns to the same user. Example: `~objects:*` +* `%R~`: (Available in Redis 7.0 and later) Adds the specified read key pattern. This behaves similar to the regular key pattern but only grants permission to read from keys that match the given pattern. See [key permissions](/topics/acl#key-permissions) for more information. +* `%W~`: (Available in Redis 7.0 and later) Adds the specified write key pattern. This behaves similar to the regular key pattern but only grants permission to write to keys that match the given pattern. See [key permissions](/topics/acl#key-permissions) for more information. * `%RW~`: (Available in Redis 7.0 and later) Alias for `~`. -* `allkeys`: alias for `~*`, it allows the user to access all the keys. -* `resetkeys`: removes all the key patterns from the list of key patterns the user can access. -* `&`: (Available in Redis 6.2 and later) add the specified glob style pattern to the list of Pub/Sub channel patterns accessible by the user. You can add multiple channel patterns to the same user. Example: `&chatroom:*` -* `allchannels`: alias for `&*`, it allows the user to access all Pub/Sub channels. -* `resetchannels`: removes all channel patterns from the list of Pub/Sub channel patterns the user can access. -* `+`: Add the command to the list of commands the user can call. Can be used with `|` for allowing subcommands (e.g "+config|get"). -* `+@`: add all the commands in the specified category to the list of commands the user is able to execute. Example: `+@string` (adds all the string commands). For a list of categories check the `ACL CAT` command. -* `+|first-arg`: Allow a specific first argument of an otherwise disabled command. It is only supported on commands with no sub-commands, and is not allowed as negative form like -SELECT|1, only additive starting with "+". This feature is deprecated and may be removed in the future. -* `allcommands`: alias of `+@all`. Adds all the commands there are in the server, including *future commands* loaded via module, to be executed by this user. -* `-`: Remove the command to the list of commands the user can call. Starting Redis 7.0, it can be used with `|` for blocking subcommands (e.g "-config|set"). +* `allkeys`: Alias for `~*`, it allows the user to access all the keys. +* `resetkeys`: Removes all the key patterns from the list of key patterns the user can access. +* `&`: (Available in Redis 6.2 and later) Adds the specified glob style pattern to the list of Pub/Sub channel patterns accessible by the user. You can add multiple channel patterns to the same user. Example: `&chatroom:*` +* `allchannels`: Alias for `&*`, it allows the user to access all Pub/Sub channels. +* `resetchannels`: Removes all channel patterns from the list of Pub/Sub channel patterns the user can access. +* `+`: Adds the command to the list of commands the user can call. Can be used with `|` for allowing subcommands (e.g "+config|get"). +* `+@`: Adds all the commands in the specified category to the list of commands the user is able to execute. Example: `+@string` (adds all the string commands). For a list of categories, check the `ACL CAT` command. +* `+|first-arg`: Allows a specific first argument of an otherwise disabled command. It is only supported on commands with no sub-commands, and is not allowed as negative form like -SELECT|1, only additive starting with "+". This feature is deprecated and may be removed in the future. +* `allcommands`: Alias of `+@all`. Adds all the commands there are in the server, including *future commands* loaded via module, to be executed by this user. +* `-`: Remove the command to the list of commands the user can call. Starting Redis 7.0, it can be used with `|` for blocking subcommands (e.g., "-config|set"). * `-@`: Like `+@` but removes all the commands in the category instead of adding them. -* `nocommands`: alias for `-@all`. Removes all the commands, the user will no longer be able to execute anything. +* `nocommands`: Alias for `-@all`. Removes all the commands, and the user is no longer able to execute anything. ### User management rules -* `on`: set the user as active, it will be possible to authenticate as this user using `AUTH `. -* `off`: set user as not active, it will be impossible to log as this user. Please note that if a user gets disabled (set to off) after there are connections already authenticated with such a user, the connections will continue to work as expected. To also kill the old connections you can use `CLIENT KILL` with the user option. An alternative is to delete the user with `ACL DELUSER`, that will result in all the connections authenticated as the deleted user to be disconnected. -* `nopass`: the user is set as a "no password" user. It means that it will be possible to authenticate as such user with any password. By default, the `default` special user is set as "nopass". The `nopass` rule will also reset all the configured passwords for the user. -* `>password`: Add the specified clear text password as a hashed password in the list of the users passwords. Every user can have many active passwords, so that password rotation will be simpler. The specified password is not stored as clear text inside the server. Example: `>mypassword`. -* `#`: Add the specified hashed password to the list of user passwords. A Redis hashed password is hashed with SHA256 and translated into a hexadecimal string. Example: `#c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2`. +* `on`: Set the user as active, it will be possible to authenticate as this user using `AUTH `. +* `off`: Set user as not active, it will be impossible to log as this user. Please note that if a user gets disabled (set to off) after there are connections already authenticated with such a user, the connections will continue to work as expected. To also kill the old connections you can use `CLIENT KILL` with the user option. An alternative is to delete the user with `ACL DELUSER`, that will result in all the connections authenticated as the deleted user to be disconnected. +* `nopass`: The user is set as a _no password_ user. It means that it will be possible to authenticate as such user with any password. By default, the `default` special user is set as "nopass". The `nopass` rule will also reset all the configured passwords for the user. +* `>password`: Adds the specified clear text password as a hashed password in the list of the users passwords. Every user can have many active passwords, so that password rotation will be simpler. The specified password is not stored as clear text inside the server. Example: `>mypassword`. +* `#`: Adds the specified hashed password to the list of user passwords. A Redis hashed password is hashed with SHA256 and translated into a hexadecimal string. Example: `#c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2`. * `password` but removes the password instead of adding it. * `!`: Like `#` but removes the password instead of adding it. -* `()`: (Available in Redis 7.0 and later) Create a new selector to match rules against. Selectors are evaluated after the user permissions, and are evaluated according to the order they are defined. If a command matches either the user permissions or any selector, it is allowed. See [selectors](/topics/acl#selectors) for more information. -* `clearselectors`: (Available in Redis 7.0 and later) Delete all of the selectors attached to the user. -* `reset`: Remove any capability from the user. It is set to off, without passwords, unable to execute any command, unable to access any key. +* `()`: (Available in Redis 7.0 and later) Creates a new selector to match rules against. Selectors are evaluated after the user permissions, and are evaluated according to the order they are defined. If a command matches either the user permissions or any selector, it is allowed. See [selectors](/topics/acl#selectors) for more information. +* `clearselectors`: (Available in Redis 7.0 and later) Deletes all of the selectors attached to the user. +* `reset`: Removes any capability from the user. They are set to off, without passwords, unable to execute any command, unable to access any key. @return From 1145eabaaa12a77b017818e0485d98fb6d7f4b84 Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Thu, 10 Nov 2022 13:51:51 -0500 Subject: [PATCH 077/377] [BUG FIX] Correct DUMP command example (#2093) * Fixes #2076, corrects example output * Fixes error * Fix error * Fix error * Fix error --- commands/dump.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/commands/dump.md b/commands/dump.md index d74003314e..0446386cc1 100644 --- a/commands/dump.md +++ b/commands/dump.md @@ -27,7 +27,9 @@ If `key` does not exist a nil bulk reply is returned. @examples -```cli -SET mykey 10 -DUMP mykey +``` +> SET mykey 10 +OK +> DUMP mykey +"\x00\xc0\n\n\x00n\x9fWE\x0e\xaec\xbb" ``` From 6ee220b5477ff04be46af52a095d6a992e58bd8b Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Thu, 10 Nov 2022 13:52:42 -0500 Subject: [PATCH 078/377] Add RHEL and CentOS install steps (#1999) * Updates install instructions to include RHEL and CentOS * Error fixes plus wordlist update * code fix * code fix 2 * Fix 3 * Fix 4 * Fix 5 * Fix 6 * Fix 7 * Revert changes but keep minor copyedits and word list updates --- .../installation/install-redis-on-linux.md | 5 +++-- wordlist | 9 +++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/getting-started/installation/install-redis-on-linux.md b/docs/getting-started/installation/install-redis-on-linux.md index d8fa005fbc..ac2464f587 100644 --- a/docs/getting-started/installation/install-redis-on-linux.md +++ b/docs/getting-started/installation/install-redis-on-linux.md @@ -3,7 +3,7 @@ title: "Install Redis on Linux" linkTitle: "Install on Linux" weight: 1 description: > - How to install Redis on Ubuntu, RHEL, and CentOS + How to install Redis on Linux --- Most major Linux distributions provide packages for Redis. @@ -34,6 +34,7 @@ sudo apt-get install redis ## Install from Snapcraft The [Snapcraft store](https://snapcraft.io/store) provides [Redis packages](https://snapcraft.io/redis) that can be installed on platforms that support snap. +Snap is supported and available on most major Linux distributions. To install via snap, run: @@ -41,4 +42,4 @@ To install via snap, run: sudo snap install redis {{< / highlight >}} -If your Linux does not currently have snap installed, you may install it by following the instructions described in [Installing snapd](https://snapcraft.io/docs/installing-snapd). +If your Linux does not currently have snap installed, install it using the instructions described in [Installing snapd](https://snapcraft.io/docs/installing-snapd). diff --git a/wordlist b/wordlist index fdbc4a4c29..2856089416 100644 --- a/wordlist +++ b/wordlist @@ -107,6 +107,8 @@ DBs DEL'ition DLM DMA +dnf +DNF DNS DSL Deauthenticate @@ -127,6 +129,7 @@ ENOENT ENOTSUP EOF EP +EPEL EPSG:3785 EPSG:900913 ERANGE @@ -286,6 +289,12 @@ RESP3's RESP3-typed RESP3. REdis +RHEL +RM_CreateCommand +RM_CreateStringFromString +RM_IsKeysPositionRequest +RM_KeyAtPosWithFlags +RM_SetCommandInfo RM_.* RPC RSS From 559dfaa26bc72d227e0e31282b9de1e3ebf7e104 Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Thu, 10 Nov 2022 14:54:59 -0500 Subject: [PATCH 079/377] Fixes #2065 (#2116) --- commands/setex.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/commands/setex.md b/commands/setex.md index 8d8b6b3f22..7bebf45fda 100644 --- a/commands/setex.md +++ b/commands/setex.md @@ -25,3 +25,6 @@ SETEX mykey 10 "Hello" TTL mykey GET mykey ``` +## See also + +`TTL` \ No newline at end of file From ec472248452cdb5ae747f71d7e688c70d03b53d8 Mon Sep 17 00:00:00 2001 From: Ping Xie Date: Sat, 12 Nov 2022 22:43:35 -0800 Subject: [PATCH 080/377] Added cluster-myshardid.md. Updated cluster-nodes.md to include the new auxiliary fields that are available on Redis 7.2.0. --- commands/cluster-myshardid.md | 7 +++++ commands/cluster-nodes.md | 49 +++++++++++++++++++++++++++-------- 2 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 commands/cluster-myshardid.md diff --git a/commands/cluster-myshardid.md b/commands/cluster-myshardid.md new file mode 100644 index 0000000000..4334b150a0 --- /dev/null +++ b/commands/cluster-myshardid.md @@ -0,0 +1,7 @@ +Returns the node's shard id. + +The `CLUSTER MYSHARDID` command returns the unique, auto-generated identifier that is associated with the shard to which the connected cluster node belongs. + +@return + +@bulk-string-reply: The node's shard id. diff --git a/commands/cluster-nodes.md b/commands/cluster-nodes.md index 2ec706c580..4b4df054fa 100644 --- a/commands/cluster-nodes.md +++ b/commands/cluster-nodes.md @@ -18,7 +18,7 @@ It is also used by `redis-cli` in order to manage a cluster. The output of the command is just a space-separated CSV string, where each line represents a node in the cluster. The following is an example -of output: +of output on Redis versions prior to 7.2.0: ``` 07c37dfeb235213a872192d90877d0cd55635b91 127.0.0.1:30004@31004 slave e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca 0 1426238317239 4 connected @@ -28,26 +28,53 @@ of output: 824fe116063bc5fcf9f4ffd895bc17aee7731ac3 127.0.0.1:30006@31006 slave 292f8b365bb7edb5e285caf0b7e6ddc7265d2f4f 0 1426238317741 6 connected e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca 127.0.0.1:30001@31001 myself,master - 0 0 1 connected 0-5460 ``` +Starting from 7.2.0, the output of the command always contains a new auxiliary +field called shard-id. The following is an example of output on Redis 7.2.0. + +``` +07c37dfeb235213a872192d90877d0cd55635b91 127.0.0.1:30004@31004,,shard-id=69bc080733d1355567173199cff4a6a039a2f024 slave e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca 0 1426238317239 4 connected +67ed2db8d677e59ec4a4cefb06858cf2a1a89fa1 127.0.0.1:30002@31002,,shard-id=114f6674a35b84949fe567f5dfd41415ee776261 master - 0 1426238316232 2 connected 5461-10922 +292f8b365bb7edb5e285caf0b7e6ddc7265d2f4f 127.0.0.1:30003@31003,,shard-id=fdb36c73e72dd027bc19811b7c219ef6e55c550e master - 0 1426238318243 3 connected 10923-16383 +6ec23923021cf3ffec47632106199cb7f496ce01 127.0.0.1:30005@31005,,shard-id=114f6674a35b84949fe567f5dfd41415ee776261 slave 67ed2db8d677e59ec4a4cefb06858cf2a1a89fa1 0 1426238316232 5 connected +824fe116063bc5fcf9f4ffd895bc17aee7731ac3 127.0.0.1:30006@31006,,shard-id=fdb36c73e72dd027bc19811b7c219ef6e55c550e slave 292f8b365bb7edb5e285caf0b7e6ddc7265d2f4f 0 1426238317741 6 connected +e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca 127.0.0.1:30001@31001,,shard-id=69bc080733d1355567173199cff4a6a039a2f024 myself,master - 0 0 1 connected 0-5460 +``` Each line is composed of the following fields: ``` - ... + ... ``` The meaning of each filed is the following: 1. `id`: The node ID, a 40 characters random string generated when a node is created and never changed again (unless `CLUSTER RESET HARD` is used). 2. `ip:port@cport`: The node address where clients should contact the node to run queries. -3. `flags`: A list of comma separated flags: `myself`, `master`, `slave`, `fail?`, `fail`, `handshake`, `noaddr`, `nofailover`, `noflags`. Flags are explained in detail in the next section. -4. `master`: If the node is a replica, and the master is known, the master node ID, otherwise the "-" character. -5. `ping-sent`: Milliseconds unix time at which the currently active ping was sent, or zero if there are no pending pings. -6. `pong-recv`: Milliseconds unix time the last pong was received. -7. `config-epoch`: The configuration epoch (or version) of the current node (or of the current master if the node is a replica). Each time there is a failover, a new, unique, monotonically increasing configuration epoch is created. If multiple nodes claim to serve the same hash slots, the one with higher configuration epoch wins. -8. `link-state`: The state of the link used for the node-to-node cluster bus. We use this link to communicate with the node. Can be `connected` or `disconnected`. -9. `slot`: A hash slot number or range. Starting from argument number 9, but there may be up to 16384 entries in total (limit never reached). This is the list of hash slots served by this node. If the entry is just a number, is parsed as such. If it is a range, it is in the form `start-end`, and means that the node is responsible for all the hash slots from `start` to `end` including the start and end values. - -Meaning of the flags (field number 3): +3. `hostname`: A human readable string that can be configured via the + `cluster-annouce-hostname` setting. The max length of the string is 256 + characters, excluding the null terminator. The name can contain ASCII alphanumeric characters, + '-', and '.' only. +4. `[,auxiliary_field=value]*`: A list of comma-separated key-value pairs that + represent various node properties, such as `shard-id`. There is no intrinsic + order among auxiliary fields. The auxiliary fields can appear at + different position in the list from release to release. Both the key name and + value can contain alphanumeric characters and the characters in + `!#$%&()*+-.:;<>?@[]^_{|}~` only. Auxiliary fields are explaned in detail in + the section below. +5. `flags`: A list of comma separated flags: `myself`, `master`, `slave`, `fail?`, `fail`, `handshake`, `noaddr`, `nofailover`, `noflags`. Flags are explained in detail in the next section. +6. `master`: If the node is a replica, and the master is known, the master node ID, otherwise the "-" character. +7. `ping-sent`: Milliseconds unix time at which the currently active ping was sent, or zero if there are no pending pings. +8. `pong-recv`: Milliseconds unix time the last pong was received. +9. `config-epoch`: The configuration epoch (or version) of the current node (or of the current master if the node is a replica). Each time there is a failover, a new, unique, monotonically increasing configuration epoch is created. If multiple nodes claim to serve the same hash slots, the one with higher configuration epoch wins. +10. `link-state`: The state of the link used for the node-to-node cluster bus. We use this link to communicate with the node. Can be `connected` or `disconnected`. +11. `slot`: A hash slot number or range. Starting from argument number 9, but there may be up to 16384 entries in total (limit never reached). This is the list of hash slots served by this node. If the entry is just a number, is parsed as such. If it is a range, it is in the form `start-end`, and means that the node is responsible for all the hash slots from `start` to `end` including the start and end values. + +Auxiliary fields (filed number 4): +* `shard-id`: a 40 characters random string generated when a node is created. A + node's shard id changes only when the node joins a different shard via + `cluster replicate` and there the node's shard id is updated to its primary's. + +Meaning of the flags (field number 5): * `myself`: The node you are contacting. * `master`: Node is a master. From 6c5eed60f03a9ef2e3cafc7e6ffe42fe27a8b456 Mon Sep 17 00:00:00 2001 From: Michael Hoffmann Date: Mon, 14 Nov 2022 17:28:39 +0100 Subject: [PATCH 081/377] Add note about LASTSAVE without previous BGSAVE (#2100) --- commands/lastsave.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/lastsave.md b/commands/lastsave.md index cfec6253ab..eec80e5b67 100644 --- a/commands/lastsave.md +++ b/commands/lastsave.md @@ -1,7 +1,7 @@ Return the UNIX TIME of the last DB save executed with success. A client may check if a `BGSAVE` command succeeded reading the `LASTSAVE` value, then issuing a `BGSAVE` command and checking at regular intervals every N -seconds if `LASTSAVE` changed. +seconds if `LASTSAVE` changed. Redis considers the database saved successfully at startup. @return From e3c9321f1c536f7da73ffd1adb5331e6bb99d052 Mon Sep 17 00:00:00 2001 From: Simon Prickett Date: Thu, 17 Nov 2022 18:43:20 +0000 Subject: [PATCH 082/377] Minor phrasing improvement. (#2215) --- commands/geosearchstore.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/geosearchstore.md b/commands/geosearchstore.md index 2a4fc38d15..53e5ebe603 100644 --- a/commands/geosearchstore.md +++ b/commands/geosearchstore.md @@ -1,6 +1,6 @@ This command is like `GEOSEARCH`, but stores the result in destination key. -This command comes in place of the now deprecated `GEORADIUS` and `GEORADIUSBYMEMBER`. +This command replaces the now deprecated `GEORADIUS` and `GEORADIUSBYMEMBER`. By default, it stores the results in the `destination` sorted set with their geospatial information. @@ -19,4 +19,4 @@ GEOSEARCHSTORE key1 Sicily FROMLONLAT 15 37 BYBOX 400 400 km ASC COUNT 3 GEOSEARCH key1 FROMLONLAT 15 37 BYBOX 400 400 km ASC WITHCOORD WITHDIST WITHHASH GEOSEARCHSTORE key2 Sicily FROMLONLAT 15 37 BYBOX 400 400 km ASC COUNT 3 STOREDIST ZRANGE key2 0 -1 WITHSCORES -``` \ No newline at end of file +``` From 8933527c8bc7b14411582858d785925cc27de0c6 Mon Sep 17 00:00:00 2001 From: Ping Xie Date: Sat, 19 Nov 2022 01:58:23 -0800 Subject: [PATCH 083/377] Incorporated review feedback --- commands/cluster-nodes.md | 74 +++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/commands/cluster-nodes.md b/commands/cluster-nodes.md index 4b4df054fa..039f2febe7 100644 --- a/commands/cluster-nodes.md +++ b/commands/cluster-nodes.md @@ -17,19 +17,9 @@ It is also used by `redis-cli` in order to manage a cluster. ## Serialization format The output of the command is just a space-separated CSV string, where -each line represents a node in the cluster. The following is an example -of output on Redis versions prior to 7.2.0: - -``` -07c37dfeb235213a872192d90877d0cd55635b91 127.0.0.1:30004@31004 slave e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca 0 1426238317239 4 connected -67ed2db8d677e59ec4a4cefb06858cf2a1a89fa1 127.0.0.1:30002@31002 master - 0 1426238316232 2 connected 5461-10922 -292f8b365bb7edb5e285caf0b7e6ddc7265d2f4f 127.0.0.1:30003@31003 master - 0 1426238318243 3 connected 10923-16383 -6ec23923021cf3ffec47632106199cb7f496ce01 127.0.0.1:30005@31005 slave 67ed2db8d677e59ec4a4cefb06858cf2a1a89fa1 0 1426238316232 5 connected -824fe116063bc5fcf9f4ffd895bc17aee7731ac3 127.0.0.1:30006@31006 slave 292f8b365bb7edb5e285caf0b7e6ddc7265d2f4f 0 1426238317741 6 connected -e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca 127.0.0.1:30001@31001 myself,master - 0 0 1 connected 0-5460 -``` -Starting from 7.2.0, the output of the command always contains a new auxiliary -field called shard-id. The following is an example of output on Redis 7.2.0. +each line represents a node in the cluster. Starting from 7.2.0, the +output of the command always contains a new auxiliary field called +shard-id. The following is an example of output on Redis 7.2.0. ``` 07c37dfeb235213a872192d90877d0cd55635b91 127.0.0.1:30004@31004,,shard-id=69bc080733d1355567173199cff4a6a039a2f024 slave e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca 0 1426238317239 4 connected @@ -48,39 +38,55 @@ Each line is composed of the following fields: The meaning of each filed is the following: -1. `id`: The node ID, a 40 characters random string generated when a node is created and never changed again (unless `CLUSTER RESET HARD` is used). -2. `ip:port@cport`: The node address where clients should contact the node to run queries. +1. `id`: The node ID, a 40-character globally unique string generated when a node + is created and never changed again (unless `CLUSTER RESET HARD` is used). +2. `ip:port@cport`: The node address that clients should contact to run queries. 3. `hostname`: A human readable string that can be configured via the `cluster-annouce-hostname` setting. The max length of the string is 256 - characters, excluding the null terminator. The name can contain ASCII alphanumeric characters, - '-', and '.' only. + characters, excluding the null terminator. The name can contain ASCII + alphanumeric characters, '-', and '.' only. 4. `[,auxiliary_field=value]*`: A list of comma-separated key-value pairs that represent various node properties, such as `shard-id`. There is no intrinsic order among auxiliary fields. The auxiliary fields can appear at different position in the list from release to release. Both the key name and - value can contain alphanumeric characters and the characters in + value can contain ASCII alphanumeric characters and the characters in `!#$%&()*+-.:;<>?@[]^_{|}~` only. Auxiliary fields are explaned in detail in the section below. -5. `flags`: A list of comma separated flags: `myself`, `master`, `slave`, `fail?`, `fail`, `handshake`, `noaddr`, `nofailover`, `noflags`. Flags are explained in detail in the next section. -6. `master`: If the node is a replica, and the master is known, the master node ID, otherwise the "-" character. -7. `ping-sent`: Milliseconds unix time at which the currently active ping was sent, or zero if there are no pending pings. -8. `pong-recv`: Milliseconds unix time the last pong was received. -9. `config-epoch`: The configuration epoch (or version) of the current node (or of the current master if the node is a replica). Each time there is a failover, a new, unique, monotonically increasing configuration epoch is created. If multiple nodes claim to serve the same hash slots, the one with higher configuration epoch wins. -10. `link-state`: The state of the link used for the node-to-node cluster bus. We use this link to communicate with the node. Can be `connected` or `disconnected`. -11. `slot`: A hash slot number or range. Starting from argument number 9, but there may be up to 16384 entries in total (limit never reached). This is the list of hash slots served by this node. If the entry is just a number, is parsed as such. If it is a range, it is in the form `start-end`, and means that the node is responsible for all the hash slots from `start` to `end` including the start and end values. - -Auxiliary fields (filed number 4): -* `shard-id`: a 40 characters random string generated when a node is created. A +5. `flags`: A list of comma separated flags: `myself`, `master`, `slave`, `fail?`, + `fail`, `handshake`, `noaddr`, `nofailover`, `noflags`. Flags are explained + below. +6. `master`: If the node is a replica, and the primary is known, the primary node ID, + otherwise the "-" character. +7. `ping-sent`: Unix time at which the currently active ping was sent, or zero if there + are no pending pings, in milliseconds. +8. `pong-recv`: Unix time the last pong was received, in milliseconds. +9. `config-epoch`: The configuration epoch (or version) of the current node (or of the + current primary if the node is a replica). Each time there is a failover, a new, unique, + monotonically increasing configuration epoch is created. If multiple nodes claim to + serve the same hash slots, the one with the higher configuration epoch wins. +10. `link-state`: The state of the link used for the node-to-node cluster bus. Use + this link to communicate with the node. Can be `connected` or `disconnected`. +11. `slot`: A hash slot number or range. Starting from argument number 9, but there + may be up to 16384 entries in total (limit never reached). This is the list of hash + slots served by this node. If the entry is just a number, it is parsed as such. + If it is a range, it is in the form `start-end`, and means that the node is + responsible for all the hash slots from `start` to `end` including the start and + end values. + +Auxiliary fields are: +* `shard-id`: a 40s-character globally unique string generated when a node is created. A node's shard id changes only when the node joins a different shard via `cluster replicate` and there the node's shard id is updated to its primary's. -Meaning of the flags (field number 5): +Flags are: * `myself`: The node you are contacting. -* `master`: Node is a master. +* `master`: Node is a primary. * `slave`: Node is a replica. -* `fail?`: Node is in `PFAIL` state. Not reachable for the node you are contacting, but still logically reachable (not in `FAIL` state). -* `fail`: Node is in `FAIL` state. It was not reachable for multiple nodes that promoted the `PFAIL` state to `FAIL`. +* `fail?`: Node is in `PFAIL` state. Not reachable for the node you are contacting, + but still logically reachable (not in `FAIL` state). +* `fail`: Node is in `FAIL` state. It was not reachable for multiple nodes that + promoted the `PFAIL` state to `FAIL`. * `handshake`: Untrusted node, we are handshaking. * `noaddr`: No address known for this node. * `nofailover`: Replica will not try to failover. @@ -88,13 +94,13 @@ Meaning of the flags (field number 5): ## Notes on published config epochs -Replicas broadcast their master's config epochs (in order to get an `UPDATE` +Replicas broadcast their primary's config epochs (in order to get an `UPDATE` message if they are found to be stale), so the real config epoch of the replica (which is meaningless more or less, since they don't serve hash slots) can be only obtained checking the node flagged as `myself`, which is the entry of the node we are asking to generate `CLUSTER NODES` output. The other replicas epochs reflect what they publish in heartbeat packets, which is, the -configuration epoch of the masters they are currently replicating. +configuration epoch of the primaries they are currently replicating. ## Special slot entries From 71d255c24fe7eaf84cd62dd88dccc03b05a55d00 Mon Sep 17 00:00:00 2001 From: Ping Xie Date: Tue, 22 Nov 2022 17:57:16 -0800 Subject: [PATCH 084/377] Fixed a typo --- commands/cluster-nodes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/cluster-nodes.md b/commands/cluster-nodes.md index 039f2febe7..2a53d7297b 100644 --- a/commands/cluster-nodes.md +++ b/commands/cluster-nodes.md @@ -50,7 +50,7 @@ The meaning of each filed is the following: order among auxiliary fields. The auxiliary fields can appear at different position in the list from release to release. Both the key name and value can contain ASCII alphanumeric characters and the characters in - `!#$%&()*+-.:;<>?@[]^_{|}~` only. Auxiliary fields are explaned in detail in + `!#$%&()*+-.:;<>?@[]^_{|}~` only. Auxiliary fields are explained in detail in the section below. 5. `flags`: A list of comma separated flags: `myself`, `master`, `slave`, `fail?`, `fail`, `handshake`, `noaddr`, `nofailover`, `noflags`. Flags are explained From 3dee96e1daaed92bc4a8cbfb141d739c61076e5e Mon Sep 17 00:00:00 2001 From: Ping Xie Date: Wed, 23 Nov 2022 10:54:26 -0800 Subject: [PATCH 085/377] Fixed a typo --- commands/cluster-nodes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/cluster-nodes.md b/commands/cluster-nodes.md index 2a53d7297b..4ec406a6cb 100644 --- a/commands/cluster-nodes.md +++ b/commands/cluster-nodes.md @@ -74,7 +74,7 @@ The meaning of each filed is the following: end values. Auxiliary fields are: -* `shard-id`: a 40s-character globally unique string generated when a node is created. A +* `shard-id`: a 40-character globally unique string generated when a node is created. A node's shard id changes only when the node joins a different shard via `cluster replicate` and there the node's shard id is updated to its primary's. From 744f0b3d6a0e5f836cd79e8074829fd75da91af8 Mon Sep 17 00:00:00 2001 From: kmiku7 Date: Fri, 25 Nov 2022 23:23:55 +0800 Subject: [PATCH 086/377] Fix the URL to streams' command list page. (#2224) --- docs/data-types/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/_index.md b/docs/data-types/_index.md index 8f30ad0842..784a7eb9e4 100644 --- a/docs/data-types/_index.md +++ b/docs/data-types/_index.md @@ -65,7 +65,7 @@ Streams help record events in the order they occur and then syndicate them for p For more information, see: * [Overview of Redis Streams](/docs/data-types/streams) -* [Redis Streams command reference](/commands/?group=streams) +* [Redis Streams command reference](/commands/?group=stream) * [Redis Streams tutorial](/docs/data-types/streams-tutorial) ### Geospatial indexes From 66c6e42b854c845eb98b2ac58c480fb2dd4c3cae Mon Sep 17 00:00:00 2001 From: Ping Xie Date: Sun, 27 Nov 2022 14:01:51 -0800 Subject: [PATCH 087/377] Reverted formatting changes --- commands/cluster-nodes.md | 52 +++++++++------------------------------ 1 file changed, 12 insertions(+), 40 deletions(-) diff --git a/commands/cluster-nodes.md b/commands/cluster-nodes.md index 4ec406a6cb..afee4b895b 100644 --- a/commands/cluster-nodes.md +++ b/commands/cluster-nodes.md @@ -38,55 +38,27 @@ Each line is composed of the following fields: The meaning of each filed is the following: -1. `id`: The node ID, a 40-character globally unique string generated when a node - is created and never changed again (unless `CLUSTER RESET HARD` is used). +1. `id`: The node ID, a 40-character globally unique string generated when a node is created and never changed again (unless `CLUSTER RESET HARD` is used). 2. `ip:port@cport`: The node address that clients should contact to run queries. -3. `hostname`: A human readable string that can be configured via the - `cluster-annouce-hostname` setting. The max length of the string is 256 - characters, excluding the null terminator. The name can contain ASCII - alphanumeric characters, '-', and '.' only. -4. `[,auxiliary_field=value]*`: A list of comma-separated key-value pairs that - represent various node properties, such as `shard-id`. There is no intrinsic - order among auxiliary fields. The auxiliary fields can appear at - different position in the list from release to release. Both the key name and - value can contain ASCII alphanumeric characters and the characters in - `!#$%&()*+-.:;<>?@[]^_{|}~` only. Auxiliary fields are explained in detail in - the section below. -5. `flags`: A list of comma separated flags: `myself`, `master`, `slave`, `fail?`, - `fail`, `handshake`, `noaddr`, `nofailover`, `noflags`. Flags are explained - below. -6. `master`: If the node is a replica, and the primary is known, the primary node ID, - otherwise the "-" character. -7. `ping-sent`: Unix time at which the currently active ping was sent, or zero if there - are no pending pings, in milliseconds. -8. `pong-recv`: Unix time the last pong was received, in milliseconds. -9. `config-epoch`: The configuration epoch (or version) of the current node (or of the - current primary if the node is a replica). Each time there is a failover, a new, unique, - monotonically increasing configuration epoch is created. If multiple nodes claim to - serve the same hash slots, the one with the higher configuration epoch wins. -10. `link-state`: The state of the link used for the node-to-node cluster bus. Use - this link to communicate with the node. Can be `connected` or `disconnected`. -11. `slot`: A hash slot number or range. Starting from argument number 9, but there - may be up to 16384 entries in total (limit never reached). This is the list of hash - slots served by this node. If the entry is just a number, it is parsed as such. - If it is a range, it is in the form `start-end`, and means that the node is - responsible for all the hash slots from `start` to `end` including the start and - end values. +3. `hostname`: A human readable string that can be configured via the `cluster-annouce-hostname` setting. The max length of the string is 256 characters, excluding the null terminator. The name can contain ASCII alphanumeric characters, '-', and '.' only. +4. `[,auxiliary_field=value]*`: A list of comma-separated key-value pairs that represent various node properties, such as `shard-id`. There is no intrinsic order among auxiliary fields. The auxiliary fields can appear at different position in the list from release to release. Both the key name and value can contain ASCII alphanumeric characters and the characters in `!#$%&()*+-.:;<>?@[]^_{|}~` only. Auxiliary fields are explained in detail in the section below. +5. `flags`: A list of comma separated flags: `myself`, `master`, `slave`, `fail?`, `fail`, `handshake`, `noaddr`, `nofailover`, `noflags`. Flags are explained below. +6. `master`: If the node is a replica, and the primary is known, the primary node ID, otherwise the "-" character. +7. `ping-sent`: Unix time at which the currently active ping was sent, or zero if there are no pending pings, in milliseconds. +8. `pong-recv`: Unix time the last pong was received, in milliseconds. 9. `config-epoch`: The configuration epoch (or version) of the current node (or of the current primary if the node is a replica). Each time there is a failover, a new, unique, monotonically increasing configuration epoch is created. If multiple nodes claim to serve the same hash slots, the one with the higher configuration epoch wins. +10. `link-state`: The state of the link used for the node-to-node cluster bus. Use this link to communicate with the node. Can be `connected` or `disconnected`. +11. `slot`: A hash slot number or range. Starting from argument number 9, but there may be up to 16384 entries in total (limit never reached). This is the list of hash slots served by this node. If the entry is just a number, it is parsed as such. If it is a range, it is in the form `start-end`, and means that the node is responsible for all the hash slots from `start` to `end` including the start and end values. Auxiliary fields are: -* `shard-id`: a 40-character globally unique string generated when a node is created. A - node's shard id changes only when the node joins a different shard via - `cluster replicate` and there the node's shard id is updated to its primary's. +* `shard-id`: a 40-character globally unique string generated when a node is created. A node's shard id changes only when the node joins a different shard via `cluster replicate` and there the node's shard id is updated to its primary's. Flags are: * `myself`: The node you are contacting. * `master`: Node is a primary. * `slave`: Node is a replica. -* `fail?`: Node is in `PFAIL` state. Not reachable for the node you are contacting, - but still logically reachable (not in `FAIL` state). -* `fail`: Node is in `FAIL` state. It was not reachable for multiple nodes that - promoted the `PFAIL` state to `FAIL`. +* `fail?`: Node is in `PFAIL` state. Not reachable for the node you are contacting, but still logically reachable (not in `FAIL` state). +* `fail`: Node is in `FAIL` state. It was not reachable for multiple nodes that promoted the `PFAIL` state to `FAIL`. * `handshake`: Untrusted node, we are handshaking. * `noaddr`: No address known for this node. * `nofailover`: Replica will not try to failover. From 006787d8cb39ebd71700998895c2ba2a2ed25fd5 Mon Sep 17 00:00:00 2001 From: Andrew <44983823+andrewvasilchuk@users.noreply.github.com> Date: Fri, 2 Dec 2022 23:31:49 +0100 Subject: [PATCH 088/377] Typo (#2221) --- docs/data-types/lists.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/lists.md b/docs/data-types/lists.md index c9753db790..b4769f5bfc 100644 --- a/docs/data-types/lists.md +++ b/docs/data-types/lists.md @@ -77,7 +77,7 @@ The max length of a Redis list is 2^32 - 1 (4,294,967,295) elements. ## Basic commands * `LPUSH` adds a new element to the head of a list; `RPUSH` adds to the tail. -* `LPOP` removes and returns an element from the head of a list; `RPOP`does the same but from the tails of a list. +* `LPOP` removes and returns an element from the head of a list; `RPOP` does the same but from the tails of a list. * `LLEN` returns the length of a list. * `LMOVE` atomically moves elements from one list to another. * `LTRIM` reduces a list to the specified range of elements. From efc870b8d996e7f3982a873db637e17443b6f0ec Mon Sep 17 00:00:00 2001 From: Binbin Date: Sat, 3 Dec 2022 06:33:03 +0800 Subject: [PATCH 089/377] ACL related link fixes (#2231) --- commands/acl-setuser.md | 2 +- commands/acl.md | 2 +- commands/command-list.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/commands/acl-setuser.md b/commands/acl-setuser.md index 7cda6e8b49..15e872c124 100644 --- a/commands/acl-setuser.md +++ b/commands/acl-setuser.md @@ -80,7 +80,7 @@ This is a list of all the supported Redis ACL rules: * `#`: Adds the specified hashed password to the list of user passwords. A Redis hashed password is hashed with SHA256 and translated into a hexadecimal string. Example: `#c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2`. * `password` but removes the password instead of adding it. * `!`: Like `#` but removes the password instead of adding it. -* `()`: (Available in Redis 7.0 and later) Creates a new selector to match rules against. Selectors are evaluated after the user permissions, and are evaluated according to the order they are defined. If a command matches either the user permissions or any selector, it is allowed. See [selectors](/topics/acl#selectors) for more information. +* `()`: (Available in Redis 7.0 and later) Creates a new selector to match rules against. Selectors are evaluated after the user permissions, and are evaluated according to the order they are defined. If a command matches either the user permissions or any selector, it is allowed. See [selectors](/docs/management/security/acl#selectors) for more information. * `clearselectors`: (Available in Redis 7.0 and later) Deletes all of the selectors attached to the user. * `reset`: Removes any capability from the user. They are set to off, without passwords, unable to execute any command, unable to access any key. diff --git a/commands/acl.md b/commands/acl.md index eb9277cb40..7e60f2e6b0 100644 --- a/commands/acl.md +++ b/commands/acl.md @@ -1,3 +1,3 @@ -This is a container command for [Access Control List](/docs/manual/security/acl/) commands. +This is a container command for [Access Control List](/docs/management/security/acl/) commands. To see the list of available commands you can call `ACL HELP`. diff --git a/commands/command-list.md b/commands/command-list.md index 5c0a4a772c..85cc453afb 100644 --- a/commands/command-list.md +++ b/commands/command-list.md @@ -3,7 +3,7 @@ Return an array of the server's command names. You can use the optional _FILTERBY_ modifier to apply one of the following filters: - **MODULE module-name**: get the commands that belong to the module specified by _module-name_. - - **ACLCAT category**: get the commands in the [ACL category](/docs/manual/security/acl/#command-categories) specified by _category_. + - **ACLCAT category**: get the commands in the [ACL category](/docs/management/security/acl/#command-categories) specified by _category_. - **PATTERN pattern**: get the commands that match the given glob-like _pattern_. @return From c72c823b8e20231129444e94ffeab1607aa05810 Mon Sep 17 00:00:00 2001 From: Mahmud Ridwan Date: Mon, 5 Dec 2022 01:58:10 +0600 Subject: [PATCH 090/377] Create redsync.json (#2226) --- libraries/go/github.com/go-redsync/redsync.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 libraries/go/github.com/go-redsync/redsync.json diff --git a/libraries/go/github.com/go-redsync/redsync.json b/libraries/go/github.com/go-redsync/redsync.json new file mode 100644 index 0000000000..f743258688 --- /dev/null +++ b/libraries/go/github.com/go-redsync/redsync.json @@ -0,0 +1,8 @@ +{ + "name": "Redsync", + "description": "Distributed mutual exclusion lock using Redis for Go; Redsync implements the Redlock algorithm.", + "homepage": "https://github.com/go-redsync/redsync", + "github": [ + "hjr265" + ] +} From a4c7ded5685fb469b370f7b69c4d6e2e4d1fec6a Mon Sep 17 00:00:00 2001 From: Virusuk Date: Wed, 7 Dec 2022 00:34:28 +0900 Subject: [PATCH 091/377] Update encryption.md (#2236) * Update encryption.md When installing Redis TLS, Run `make BUILD_TLS=yes` <--- Need to install it with the corresponding command to install it correctly. However, Run `make BUILD_TLS=yes`. <--- Due to the '.'dot, a TLS testing error occurred due to a misunderstanding, so we request a correction. * Formatting Co-authored-by: Itamar Haber --- docs/management/security/encryption.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/management/security/encryption.md b/docs/management/security/encryption.md index 28f3db69f7..33aa813a44 100644 --- a/docs/management/security/encryption.md +++ b/docs/management/security/encryption.md @@ -18,9 +18,13 @@ that needs to be enabled at compile time. ### Building To build with TLS support you'll need OpenSSL development libraries (e.g. -libssl-dev on Debian/Ubuntu). +`libssl-dev` on Debian/Ubuntu). -Run `make BUILD_TLS=yes`. +Build Redis with the following command: + +```sh +make BUILD_TLS=yes +``` ### Tests From 1813bfd0088fbba8ccaddf8691882d620b40ea66 Mon Sep 17 00:00:00 2001 From: Andrew <44983823+andrewvasilchuk@users.noreply.github.com> Date: Sat, 10 Dec 2022 19:08:22 +0200 Subject: [PATCH 092/377] docs: correct minimum possible id (#2233) --- commands/xrange.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/commands/xrange.md b/commands/xrange.md index fc6d11dd3c..fa81b316a5 100644 --- a/commands/xrange.md +++ b/commands/xrange.md @@ -41,9 +41,8 @@ will just return every entry in the stream: ... other entries here ... ``` -The `-` ID is effectively just exactly as specifying `0-0`, while -`+` is equivalent to `18446744073709551615-18446744073709551615`, however -they are nicer to type. +The `-` and `+` special IDs mean, respectively, the minimal and maximal range IDs, +however they are nicer to type. ## Incomplete IDs From ae9a0a6cce1ae4720ab52c778bab878869f14642 Mon Sep 17 00:00:00 2001 From: Simon Prickett Date: Sun, 11 Dec 2022 13:40:23 +0000 Subject: [PATCH 093/377] Rewrite the security page a bit to mention ACLs as another option since Redis 6. (#2243) Co-authored-by: Itamar Haber --- docs/management/security/_index.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/management/security/_index.md b/docs/management/security/_index.md index fa2d71390c..8fdde186cd 100644 --- a/docs/management/security/_index.md +++ b/docs/management/security/_index.md @@ -76,11 +76,14 @@ disable protected mode or manually bind all the interfaces. ## Authentication -While Redis does not try to implement Access Control, it provides -a tiny layer of optional authentication that is turned on by editing the -**redis.conf** file. +Redis provides two ways to authenticate clients. +The recommended authentication method, introduced in Redis 6, is via Access Control Lists, allowing named users to be created and assigned fine-grained permissions. +Read more about Access Control Lists [here](/docs/management/security/acl/). -When the authorization layer is enabled, Redis will refuse any query by +The legacy authentication method is enabled by editing the **redis.conf** file, and providing a database password using the `requirepass` setting. +This password is then used by all clients. + +When the `reuirepass` setting is enabled, Redis will refuse any query by unauthenticated clients. A client can authenticate itself by sending the **AUTH** command followed by the password. @@ -96,7 +99,7 @@ redundancy. If firewalling or any other system implemented to protect Redis from external attackers fail, an external client will still not be able to access the Redis instance without knowledge of the authentication password. -Since the AUTH command, like every other Redis command, is sent unencrypted, it +Since the `AUTH` command, like every other Redis command, is sent unencrypted, it does not protect against an attacker that has enough access to the network to perform eavesdropping. From bc8218eb481cc5d095ee7c274388a44dc09942e9 Mon Sep 17 00:00:00 2001 From: Oran Agra Date: Mon, 12 Dec 2022 18:44:39 +0200 Subject: [PATCH 094/377] module api ref update for 7.0.6 (#2248) --- docs/reference/modules/modules-api-ref.md | 56 ++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/docs/reference/modules/modules-api-ref.md b/docs/reference/modules/modules-api-ref.md index 91cf5167af..00ae846fde 100644 --- a/docs/reference/modules/modules-api-ref.md +++ b/docs/reference/modules/modules-api-ref.md @@ -3461,6 +3461,17 @@ Return the pointer and length of a string or error reply. Return a new string object from a call reply of type string, error or integer. Otherwise (wrong reply type) return NULL. + + +### `RedisModule_SetContextUser` + + void RedisModule_SetContextUser(RedisModuleCtx *ctx, + const RedisModuleUser *user); + +**Available since:** 7.0.6 + +Modifies the user that [`RedisModule_Call`](#RedisModule_Call) will use (e.g. for ACL checks) + ### `RedisModule_Call` @@ -3494,7 +3505,17 @@ Exported API to call any Redis command from modules. * `0` -- Return the reply in auto mode, i.e. the reply format will be the same as the client attached to the given RedisModuleCtx. This will probably used when you want to pass the reply directly to the client. - * `C` -- Check if command can be executed according to ACL rules. + * `C` -- Run a command as the user attached to the context. + User is either attached automatically via the client that directly + issued the command and created the context or via RedisModule_SetContextUser. + If the context is not directly created by an issued command (such as a + background context and no user was set on it via RedisModule_SetContextUser, + RedisModule_Call will fail. + Checks if the command can be executed according to ACL rules and causes + the command to run as the determined user, so that any future user + dependent activity, such as ACL checks within scripts will proceed as + expected. + Otherwise, the command will run as the Redis unrestricted user. * `S` -- Run the command in a script mode, this means that it will raise an error if a command which are not allowed inside a script (flagged with the `deny-script` flag) is invoked (like SHUTDOWN). @@ -5051,6 +5072,36 @@ for detailed usage. Returns `REDISMODULE_OK` on success and `REDISMODULE_ERR` on failure and will set an errno describing why the operation failed. + + +### `RedisModule_SetModuleUserACLString` + + int RedisModule_SetModuleUserACLString(RedisModuleCtx *ctx, + RedisModuleUser *user, + const char *acl, + RedisModuleString **error); + +**Available since:** 7.0.6 + +Sets the permission of a user with a complete ACL string, such as one +would use on the redis ACL SETUSER command line API. This differs from +[`RedisModule_SetModuleUserACL`](#RedisModule_SetModuleUserACL), which only takes single ACL operations at a time. + +Returns `REDISMODULE_OK` on success and `REDISMODULE_ERR` on failure +if a `RedisModuleString` is provided in error, a string describing the error +will be returned + + + +### `RedisModule_GetModuleUserACLString` + + RedisModuleString *RedisModule_GetModuleUserACLString(RedisModuleUser *user); + +**Available since:** 7.0.6 + +Get the ACL string for a given user +Returns a `RedisModuleString` + ### `RedisModule_GetCurrentUserName` @@ -7351,6 +7402,7 @@ There is no guarantee that this info is always available, so this may return -1. * [`RedisModule_GetKeyspaceNotificationFlagsAll`](#RedisModule_GetKeyspaceNotificationFlagsAll) * [`RedisModule_GetLFU`](#RedisModule_GetLFU) * [`RedisModule_GetLRU`](#RedisModule_GetLRU) +* [`RedisModule_GetModuleUserACLString`](#RedisModule_GetModuleUserACLString) * [`RedisModule_GetModuleUserFromUserName`](#RedisModule_GetModuleUserFromUserName) * [`RedisModule_GetMyClusterID`](#RedisModule_GetMyClusterID) * [`RedisModule_GetNotifyKeyspaceEvents`](#RedisModule_GetNotifyKeyspaceEvents) @@ -7488,12 +7540,14 @@ There is no guarantee that this info is always available, so this may return -1. * [`RedisModule_SetClientNameById`](#RedisModule_SetClientNameById) * [`RedisModule_SetClusterFlags`](#RedisModule_SetClusterFlags) * [`RedisModule_SetCommandInfo`](#RedisModule_SetCommandInfo) +* [`RedisModule_SetContextUser`](#RedisModule_SetContextUser) * [`RedisModule_SetDisconnectCallback`](#RedisModule_SetDisconnectCallback) * [`RedisModule_SetExpire`](#RedisModule_SetExpire) * [`RedisModule_SetLFU`](#RedisModule_SetLFU) * [`RedisModule_SetLRU`](#RedisModule_SetLRU) * [`RedisModule_SetModuleOptions`](#RedisModule_SetModuleOptions) * [`RedisModule_SetModuleUserACL`](#RedisModule_SetModuleUserACL) +* [`RedisModule_SetModuleUserACLString`](#RedisModule_SetModuleUserACLString) * [`RedisModule_SignalKeyAsReady`](#RedisModule_SignalKeyAsReady) * [`RedisModule_SignalModifiedKey`](#RedisModule_SignalModifiedKey) * [`RedisModule_StopTimer`](#RedisModule_StopTimer) From 677173ea789cecb7f9dcc586ae6b8f0c065f3d45 Mon Sep 17 00:00:00 2001 From: Binbin Date: Tue, 13 Dec 2022 23:21:31 +0800 Subject: [PATCH 095/377] Fix outdated ACL SETUSER reset actions (#2252) * Fix outdated ACL SETUSER reset actions * spell check --- docs/management/security/acl.md | 2 +- wordlist | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/management/security/acl.md b/docs/management/security/acl.md index f68d09304b..7db447cfbd 100644 --- a/docs/management/security/acl.md +++ b/docs/management/security/acl.md @@ -142,7 +142,7 @@ Configure selectors for the user: Reset the user: -* `reset` Performs the following actions: resetpass, resetkeys, resetchannels, off, -@all. The user returns to the same state it had immediately after its creation. +* `reset` Performs the following actions: resetpass, resetkeys, resetchannels, allchannels (if acl-pubsub-default is set), off, clearselectors, -@all. The user returns to the same state it had immediately after its creation. ## Create and edit user ACLs with the ACL SETUSER command diff --git a/wordlist b/wordlist index 2856089416..f0181afaf7 100644 --- a/wordlist +++ b/wordlist @@ -415,8 +415,10 @@ ZeroBrane Zhao acknowledgement acl +acl-pubsub-default ad-hoc alice +allchannels allkeys allkeys-lru allkeys-random From cd405345fd08ebe5d15131c10542418b349fd799 Mon Sep 17 00:00:00 2001 From: Binbin Date: Wed, 14 Dec 2022 23:49:16 +0800 Subject: [PATCH 096/377] Minor fixes in outdated acl doc (#2255) All output is based on the current 7.0.6 version. --- docs/management/security/acl.md | 56 ++++++++++++++------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/docs/management/security/acl.md b/docs/management/security/acl.md index 7db447cfbd..508e781887 100644 --- a/docs/management/security/acl.md +++ b/docs/management/security/acl.md @@ -169,8 +169,8 @@ users. If the user already exists, the command above will do nothing at all. Check the default user status: > ACL LIST - 1) "user alice off &* -@all" - 2) "user default on nopass ~* ~& +@all" + 1) "user alice off resetchannels -@all" + 2) "user default on nopass ~* &* +@all" The new user "alice" is: @@ -178,7 +178,7 @@ The new user "alice" is: * The user also has no passwords set. * Cannot access any command. Note that the user is created by default without the ability to access any command, so the `-@all` in the output above could be omitted; however, `ACL LIST` attempts to be explicit rather than implicit. * There are no key patterns that the user can access. -* The user can access all Pub/Sub channels. +* There are no Pub/Sub channels that the user can access. New users are created with restrictive permissions by default. Starting with Redis 6.2, ACL provides Pub/Sub channels access management as well. To ensure backward compatibility with version 6.0 when upgrading to Redis 6.2, new users are granted the 'allchannels' permission by default. The default can be set to `resetchannels` via the `acl-pubsub-default` configuration directive. @@ -211,7 +211,6 @@ computers to read, while `ACL GETUSER` is more human readable. > ACL GETUSER alice 1) "flags" 2) 1) "on" - 2) "allchannels" 3) "passwords" 4) 1) "2d9c75..." 5) "commands" @@ -219,27 +218,19 @@ computers to read, while `ACL GETUSER` is more human readable. 7) "keys" 8) "~cached:*" 9) "channels" - 10) "&*" + 10) "" 11) "selectors" - 12) 1) 1) "commands" - 2) "-@all +set" - 3) "keys" - 4) "~*" - 5) "channels" - 6) "&*" + 12) (empty array) The `ACL GETUSER` returns a field-value array that describes the user in more parsable terms. The output includes the set of flags, a list of key patterns, passwords, and so forth. The output is probably more readable if we use RESP3, so that it is returned as a map reply: > ACL GETUSER alice 1# "flags" => 1~ "on" - 2~ "allchannels" 2# "passwords" => 1) "2d9c75273d72b32df726fb545c8a4edc719f0a95a6fd993950b10c474ad9c927" 3# "commands" => "-@all +get" 4# "keys" => "~cached:*" - 5# "channels" => "&*" - 6# "selectors" => 1) 1# "commands" => "-@all +set" - 2# "keys" => "~*" - 3# "channels" => "&*" + 5# "channels" => "" + 6# "selectors" => (empty array) *Note: from now on, we'll continue using the Redis default protocol, version 2* @@ -248,7 +239,7 @@ Using another `ACL SETUSER` command (from a different user, because alice cannot > ACL SETUSER alice ~objects:* ~items:* ~public:* OK > ACL LIST - 1) "user alice on >2d9c75... ~cached:* ~objects:* ~items:* ~public:* &* -@all +get" + 1) "user alice on #2d9c75... ~cached:* ~objects:* ~items:* ~public:* resetchannels -@all +get" 2) "user default on nopass ~* &* +@all" The user representation in memory is now as we expect it to be. @@ -274,7 +265,7 @@ Will result in myuser being able to call both `GET` and `SET`: > ACL LIST 1) "user default on nopass ~* &* +@all" - 2) "user myuser off &* -@all +set +get" + 2) "user myuser off resetchannels -@all +get +set" ## Command categories @@ -330,7 +321,7 @@ The following is a list of command categories and their meanings: * **transaction** - `WATCH` / `MULTI` / `EXEC` related commands. * **write** - Writing to keys (values or metadata). -Redis can also show you a list of all categories and the exact commands each category includes using the Redis `ACL` command's `CAT` subcommand. It can be used in two forms: +Redis can also show you a list of all categories and the exact commands each category includes using the Redis `ACL CAT` command. It can be used in two forms: ACL CAT -- Will just list all the categories available ACL CAT -- Will list all the commands inside the category @@ -363,15 +354,17 @@ Examples: As you can see, so far there are 21 distinct categories. Now let's check what command is part of the *geo* category: - > ACL CAT geo - 1) "geohash" - 2) "georadius_ro" - 3) "georadiusbymember" - 4) "geopos" - 5) "geoadd" - 6) "georadiusbymember_ro" - 7) "geodist" - 8) "georadius" + > ACL CAT geo + 1) "geohash" + 2) "georadius_ro" + 3) "georadiusbymember" + 4) "geopos" + 5) "geoadd" + 6) "georadiusbymember_ro" + 7) "geodist" + 8) "georadius" + 9) "geosearch" + 10) "geosearchstore" Note that commands may be part of multiple categories. For example, an ACL rule like `+@geo -@read` will result in certain geo commands to be @@ -451,7 +444,7 @@ For a concrete example, consider a user with ACL rules `+@all ~app1:* (+@readonl This user has full access on `app1:*` and readonly access on `app2:*`. However, some commands support reading data from one key, doing some transformation, and storing it into another key. One such command is the `COPY` command, which copies the data from the source key into the destination key. -The example set of ACL rules is unable to handle a request copying data from `app2:user` into `app1:user`, since neither the root permission or the selector fully matches the command. +The example set of ACL rules is unable to handle a request copying data from `app2:user` into `app1:user`, since neither the root permission nor the selector fully matches the command. However, using key selectors you can define a set of ACL rules that can handle this request `+@all ~app1:* %R~app2:*`. The first pattern is able to match `app1:user` and the second pattern is able to match `app2:user`. @@ -462,7 +455,7 @@ The access flag maps to the read key permission. If the key has no logical operation flags, such as `EXISTS`, the user still needs either key read or key write permissions to execute the command. Note: Side channels to accessing user data are ignored when it comes to evaluating whether read permissions are required to execute a command. -This means that some write commands that return metadata about the modified key only require write permission on the key to execute: +This means that some write commands that return metadata about the modified key only require write permission on the key to execute. For example, consider the following two commands: * `LPUSH key1 data`: modifies "key1" but only returns metadata about it, the size of the list after the push, so the command only requires write permission on "key1" to execute. @@ -480,9 +473,6 @@ examples, for the sake of brevity, the long hex string was trimmed: > ACL GETUSER default 1) "flags" 2) 1) "on" - 2) "allkeys" - 3) "allcommands" - 4) "allchannels" 3) "passwords" 4) 1) "2d9c75273d72b32df726fb545c8a4edc719f0a95a6fd993950b10c474ad9c927" 5) "commands" From 5921ba4cdef2761bfed34b982368f1fe077d03e9 Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Thu, 15 Dec 2022 11:50:31 -0500 Subject: [PATCH 097/377] Removes trademark section and points License content to redis.com trademark guidelines (#2257) --- docs/about/license.md | 2 +- docs/about/trademark.md | 54 ----------------------------------------- 2 files changed, 1 insertion(+), 55 deletions(-) delete mode 100644 docs/about/trademark.md diff --git a/docs/about/license.md b/docs/about/license.md index 7d5e4ea8a5..5bcada4c4f 100644 --- a/docs/about/license.md +++ b/docs/about/license.md @@ -11,7 +11,7 @@ aliases: Redis is **open source software** released under the terms of the **three clause BSD license**. Most of the Redis source code was written and is copyrighted by Salvatore Sanfilippo and Pieter Noordhuis. A list of other contributors can be found in the git history. The Redis trademark and logo are owned by Redis Ltd. and can be -used in accordance with the [Redis Trademark Guidelines](/docs/about/trademark). +used in accordance with the [Redis Trademark Guidelines](https://redis.com/legal/trademark-guidelines/). ## Three clause BSD license diff --git a/docs/about/trademark.md b/docs/about/trademark.md deleted file mode 100644 index 5fa1fce213..0000000000 --- a/docs/about/trademark.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: "Redis trademark guidelines" -linkTitle: "Trademark" -weight: 6 -description: How can the Redis trademarks be used? -aliases: - - /topics/trademark ---- - -1. **OPEN SOURCE LICENSE VS. TRADEMARKS.** The three-clause BSD license gives you the right to redistribute and use the software in source and binary forms, with or without modification, under certain conditions. However, open source licenses like the three-clause BSD license do not address trademarks. Redis trademarks and brands need to be used in a way consistent with trademark law, and that is why we have prepared this policy – to help you understand what branding is allowed or required when using our software. - -2. **PURPOSE**. To outline the policy and guidelines for using the Redis trademark (“Mark”) and logo (“Logo”). - -3. **WHY IS THIS IMPORTANT?** The Mark and Logo are symbols of the quality and community support associated with the open source Redis. Trademarks protect not only its owners, but its users and the entire open source community. Our community members need to know that they can rely on the quality represented by the brand. No one should use the Mark or Logo in any way that misleads anyone, either directly or by omission, or in any way that is likely to confuse or take advantage of the community, or constitutes unfair competition. For example, you cannot say you are distributing Redis software when you are distributing a modified version of Redis open source, because people will be confused when they are not getting the same features and functionality they would get if they downloaded the software directly from Redis, or will think that the modified software is endorsed or sponsored by us or the community. You also cannot use the Mark or Logo on your website or in connection with any services in a way that suggests that your website is an official Redis website or service, or that suggests that we endorse your website or services. - -4. **PROPER USE OF THE REDIS TRADEMARKS AND LOGO.** You may do any of the following: - * a. When you use an unaltered, unmodified copy of open source Redis downloaded from https://redis.io (the “Software”) as a data source for your application, you may use the Mark and Logo to identify your use. The open source Redis software combined with, or integrated into, any other software program, including but not limited to automation software for offering Redis as a cloud service or orchestration software for offering Redis in containers is considered “modified” Redis software and does not entitle you to use the Mark or the Logo, except in a case of nominative use, as described below. Integrating the Software with other software or service can introduce performance or quality control problems that can devalue the goodwill in the Redis brand and we want to be sure that such problems do not confuse users as to the quality of the product. - * b. The Software is developed by and for the Redis community. If you are engaged in community advocacy, you can use the Mark but not the Logo in the context of showing support for the open source Redis project, provided that: - * i. The Mark is used in a manner consistent with this policy; - * ii. There is no commercial purpose behind the use and you are not offering Redis commercially under the same domain name; - * iii. There is no suggestion that you are the creator or source of Redis, or that your project is approved, sponsored, or affiliated with us or the community; and - * iv. You must include attribution according to section 6.a. below. - * c. __Nominative Use__: Trademark law permits third parties the use of a mark to identify the trademark holder’s product or service so long as such use is not likely to cause unnecessary consumer or public confusion. This is referred to as a nominative or fair use. When you distribute, or offer an altered, modified or combined copy of the Software, such as in the case of a cloud service or a container service, you may engage in “nominative use” of the Mark, but this does not allow you to use the Logo. - * d. Examples of Nominative Use: - * i. Offering an XYZ software, which is an altered, modified or combined copy of the open source Redis software, including but not limited to offering Redis as a cloud service or as a container service, and while fully complying with the open source Redis API - you may only name it **"XYZ for Redis®"** or state that **"XYZ software is compatible with the Redis® API"**. No other term or description of your software is allowed. - * ii. Offering an ABC application, which uses an altered, modified or combined copy of the open source Redis software as a data source, including but not limited to using Redis as a cloud service or a container service, and while the modified Redis fully complies with the open source Redis API - you may only state that **"ABC application is using XYZ for Redis®"**, or **"ABC application is using a software which is compatible with the Redis® API"**. No other term or description of your application is allowed. - * iii. If, however, the offered XYZ software, or service based thereof, or application ABC uses an altered, modified or combined copy of the open source Redis software that does not fully comply with the open source Redis API - you may not use the Mark and Logo at all. - * e. In any use (or nominative use) of the Mark or the Logo as per the above, you should comply with all the provisions of Section 6 (General Use). -5. **IMPROPER USE OF THE REDIS TRADEMARKS AND LOGOS**. Any use of the Mark -or Logo other than as expressly described as permitted herein is not permitted because we believe that it would likely cause impermissible public confusion. Use of the Mark that we will likely consider infringing without permission for use include: - * a. Entity Names. You may not form a company, use a company name, or create a software product or service name that includes the Mark or implies any that such company is the source or sponsor of Redis. If you wish to form an entity for a user or developer group, please contact us and we will be glad to discuss a license for a suitable name; - * b. Class or Quality. You may not imply that you are providing a class or quality of Redis (e.g., "enterprise-class" or "commercial quality" or “fully managed”) in a way that implies Redis is not of that class, grade or quality, nor that other parties are not of that class, grade, or quality; - * c. False or Misleading Statements. You may not make false or misleading statements regarding your use of Redis (e.g., "we wrote the majority of the code" or "we are major contributors" or "we are committers"); - * d. Domain Names and Subdomains. You must not use Redis or any confusingly similar phrase in a domain name or subdomain. For instance “www.Redishost.com” is not allowed. If you wish to use such a domain name for a user or developer group, please contact us and we will be glad to discuss a license for a suitable domain name. Because of the many persons who, unfortunately, seek to spoof, swindle or deceive the community by using confusing domain names, we must be very strict about this rule; - * e. Websites. You must not use our Mark or Logo on your website in a way that suggests that your website is an official website or that we endorse your website; - * f. Merchandise. You must not manufacture, sell or give away merchandise items, such as T-shirts and mugs, bearing the Mark or Logo, or create any mascot for Redis. If you wish to use the Mark or Logo for a user or developer group, please contact us and we will be glad to discuss a license to do this; - * g. Variations, takeoffs or abbreviations. You may not use a variation of the Mark for any purpose. For example, the following are not acceptable: - * i. Red; - * ii. MyRedis; and - * iii. RedisHost. - * h. Rebranding. You may not change the Mark or Logo on a redistributed (unmodified) Software to your own brand or logo. You may not hold yourself out as the source of the Redis software, except to the extent you have modified it as allowed under the three-clause BSD license, and you make it clear that you are the source only of the modification; - * i. Combination Marks. Do not use our Mark or Logo in combination with any other marks or logos. For example Foobar Redis, or the name of your company or product typeset to look like the Redis logo; and - * j. Web Tags. Do not use the Mark in a title or metatag of a web page to influence search engine rankings or result listings, rather than for discussion or advocacy of the Redis project. -6. **GENERAL USE INFORMATION.** - * a. Attribution. Any permitted use of the Mark or Logo, as indicated above, should comply with the following provisions: - * i. You should add the R mark (®) and an asterisk (`*`) to the first mention of the word "Redis" as part of or in connection with a product name; - * ii. Whenever "Redis®`*`" is shown - add the following legend (with an asterisk) in a noticeable and readable format: "`*` Redis is a registered trademark of Redis Ltd. Any rights therein are reserved to Redis Ltd. Any use by `<`company XYZ`>` is for referential purposes only and does not indicate any sponsorship, endorsement or affiliation between Redis and `<`company XYZ`>`"; and - * iii. Sections i. and ii. above apply to any appearance of the word "Redis" in: (a) any web page, gated or un-gated; (b) any marketing collateral, white paper, or other promotional material, whether printed or electronic; and (c) any advertisement, in any format. - * b. Capitalization. Always distinguish the Mark from surrounding text with at least initial capital letters or in all capital letters, (e.g., as Redis or REDIS). - * c. Adjective. Always use the Mark as an adjective modifying a noun, such as “the Redis software.” - * d. Do not make any changes to the Logo. This means you may not add decorative elements, change the colors, change the proportions, distort it, add elements or combine it with other logos. -7. **NOTIFY US OF ABUSE.** Please notify Redis at [legal@redis.com](mailto:legal@redis.com) if you discover any violations of these guidelines. -8. **MORE QUESTIONS?** If you have questions about this policy, or wish to request a license for any uses that are not specifically authorized in this policy, please contact us at legal@redis.com. - From 44a6d479e8ba65477beb1530a4cf83208728d4bf Mon Sep 17 00:00:00 2001 From: Cosme Zamudio Date: Wed, 21 Dec 2022 22:47:02 -0600 Subject: [PATCH 098/377] Update _index.md (#2261) --- docs/management/security/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/management/security/_index.md b/docs/management/security/_index.md index 8fdde186cd..20537b6879 100644 --- a/docs/management/security/_index.md +++ b/docs/management/security/_index.md @@ -83,7 +83,7 @@ Read more about Access Control Lists [here](/docs/management/security/acl/). The legacy authentication method is enabled by editing the **redis.conf** file, and providing a database password using the `requirepass` setting. This password is then used by all clients. -When the `reuirepass` setting is enabled, Redis will refuse any query by +When the `requirepass` setting is enabled, Redis will refuse any query by unauthenticated clients. A client can authenticate itself by sending the **AUTH** command followed by the password. From a08e6851dc240008cf7fd82eb2ae605bc4c79192 Mon Sep 17 00:00:00 2001 From: Michael Silverman Date: Wed, 21 Dec 2022 23:47:36 -0500 Subject: [PATCH 099/377] Update scan.md (#2263) --- commands/scan.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/scan.md b/commands/scan.md index fd5924ff98..dcc94de9cb 100644 --- a/commands/scan.md +++ b/commands/scan.md @@ -82,7 +82,7 @@ Important: **there is no need to use the same COUNT value** for every iteration. ## The MATCH option -It is possible to only iterate elements matching a given glob-style pattern, similarly to the behavior of the `KEYS` command that takes a pattern as only argument. +It is possible to only iterate elements matching a given glob-style pattern, similarly to the behavior of the `KEYS` command that takes a pattern as its only argument. To do so, just append the `MATCH ` arguments at the end of the `SCAN` command (it works with all the SCAN family commands). @@ -173,7 +173,7 @@ Since there is no state server side, but the full state is captured by the curso ## Calling SCAN with a corrupted cursor -Calling `SCAN` with a broken, negative, out of range, or otherwise invalid cursor, will result into undefined behavior but never into a crash. What will be undefined is that the guarantees about the returned elements can no longer be ensured by the `SCAN` implementation. +Calling `SCAN` with a broken, negative, out of range, or otherwise invalid cursor, will result in undefined behavior but never in a crash. What will be undefined is that the guarantees about the returned elements can no longer be ensured by the `SCAN` implementation. The only valid cursors to use are: From 57007fcbf887e86b6def8b0aa7e953ab503e1442 Mon Sep 17 00:00:00 2001 From: Andrew <44983823+andrewvasilchuk@users.noreply.github.com> Date: Thu, 22 Dec 2022 06:48:33 +0200 Subject: [PATCH 100/377] CONFIG SET without a restart (#2220) --- docs/management/admin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/management/admin.md b/docs/management/admin.md index ce666c46c4..3c1992877b 100644 --- a/docs/management/admin.md +++ b/docs/management/admin.md @@ -58,7 +58,7 @@ aliases: [ ## Upgrading or restarting a Redis instance without downtime -Redis is designed to be a long-running process in your server. You can modify many configuration options restart using the [CONFIG SET command](/commands/config-set). You can also switch from AOF to RDB snapshots persistence, or the other way around, without restarting Redis. Check the output of the `CONFIG GET *` command for more information. +Redis is designed to be a long-running process in your server. You can modify many configuration options without a restart using the [CONFIG SET command](/commands/config-set). You can also switch from AOF to RDB snapshots persistence, or the other way around, without restarting Redis. Check the output of the `CONFIG GET *` command for more information. From time to time, a restart is required, for example, to upgrade the Redis process to a newer version, or when you need to modify a configuration parameter that is currently not supported by the `CONFIG` command. From 07950cefe165158f380a9618b6753db96ef056f0 Mon Sep 17 00:00:00 2001 From: Cassiano Aquino Date: Tue, 27 Dec 2022 15:42:44 +0000 Subject: [PATCH 101/377] add redis-bash to list of clients. (#2266) --- clients/bash/github.com/caquino/redis-bash.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 clients/bash/github.com/caquino/redis-bash.json diff --git a/clients/bash/github.com/caquino/redis-bash.json b/clients/bash/github.com/caquino/redis-bash.json new file mode 100644 index 0000000000..319f6fed0c --- /dev/null +++ b/clients/bash/github.com/caquino/redis-bash.json @@ -0,0 +1,7 @@ +{ + "name": "redis-bash", + "description": "Bash library and example client to access Redis Databases", + "twitter": [ + "syshero" + ] +} From 71e60c2afb932277aba561cf59fe177633606dc3 Mon Sep 17 00:00:00 2001 From: Irfan Butt Date: Wed, 28 Dec 2022 13:12:45 +0000 Subject: [PATCH 102/377] Spelling mistake corrected s/preform/perform (#2269) --- docs/manual/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/cli.md b/docs/manual/cli.md index 760c1f9160..38d35ebb81 100644 --- a/docs/manual/cli.md +++ b/docs/manual/cli.md @@ -96,7 +96,7 @@ You can change the port using several command line options. To specify a differe PONG If your instance is password protected, the `-a ` option will -preform authentication saving the need of explicitly using the `AUTH` command: +perform authentication saving the need of explicitly using the `AUTH` command: $ redis-cli -a myUnguessablePazzzzzword123 PING PONG From af2a573ae3369a67b560e2c0dfa17d70da542f2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alihan=20SARA=C3=87=28Brick=29?= <56413673+saracalihan@users.noreply.github.com> Date: Wed, 28 Dec 2022 19:22:47 +0300 Subject: [PATCH 103/377] metronom added to Node clients (#2042) --- clients/nodejs/github.com/anchovycation/metronom.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 clients/nodejs/github.com/anchovycation/metronom.json diff --git a/clients/nodejs/github.com/anchovycation/metronom.json b/clients/nodejs/github.com/anchovycation/metronom.json new file mode 100644 index 0000000000..af473fdda0 --- /dev/null +++ b/clients/nodejs/github.com/anchovycation/metronom.json @@ -0,0 +1,8 @@ +{ + "name": "metronom", + "description": "User friendly Redis ORM for Node.js with asynchronous and TypeScript support.", + "homepage": "https://anchovycation.github.io/metronom/", + "twitter": [ + "saracaIihan" + ] +} From c0a7125d575e0766390c9f667d94950ac1f4df52 Mon Sep 17 00:00:00 2001 From: Leibale Eidelman Date: Wed, 28 Dec 2022 13:19:34 -0500 Subject: [PATCH 104/377] Fix SPUBLISH reply description (#2259) * Fix SPUBLISH reply description * Update commands/spublish.md Co-authored-by: Itamar Haber --- commands/spublish.md | 1 + 1 file changed, 1 insertion(+) diff --git a/commands/spublish.md b/commands/spublish.md index e8b6925c1c..762ff8ed75 100644 --- a/commands/spublish.md +++ b/commands/spublish.md @@ -9,6 +9,7 @@ For more information about sharded pubsub, see [Sharded Pubsub](/topics/pubsub#s @return @integer-reply: the number of clients that received the message. +Note that in a Redis Cluster, only clients that are connected to the same node as the publishing client are included in the count. @examples From 5ac38ea48248a6fb5d22d7e2822a2baa439ca554 Mon Sep 17 00:00:00 2001 From: Massoud Maboudi Date: Thu, 29 Dec 2022 04:14:41 +0800 Subject: [PATCH 105/377] Update hset.md (#2234) Update the description to match by adding multiple keys description with respective examples Co-authored-by: Itamar Haber --- commands/hset.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/commands/hset.md b/commands/hset.md index 42e15c127d..0572b01cf5 100644 --- a/commands/hset.md +++ b/commands/hset.md @@ -1,6 +1,7 @@ -Sets `field` in the hash stored at `key` to `value`. -If `key` does not exist, a new key holding a hash is created. -If `field` already exists in the hash, it is overwritten. +Sets the specified fields to their respective values in the hash stored at `key`. + +This command overwrites the values of specified fields that exist in the hash. +If `key` doesn't exist, a new key holding a hash is created. @return @@ -11,4 +12,8 @@ If `field` already exists in the hash, it is overwritten. ```cli HSET myhash field1 "Hello" HGET myhash field1 +HSET myhash field2 "Hi" field3 "World" +HGET myhash field2 +HGET myhash field3 +HGETALL myhash ``` From d52033ba9c72bdc39167223d63470562fb9c191a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E4=BB=A4=E7=AB=A5=E9=9E=8B?= Date: Thu, 29 Dec 2022 04:32:30 +0800 Subject: [PATCH 106/377] Fix XREADGROUP command error (#2219) --- commands/xreadgroup.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/xreadgroup.md b/commands/xreadgroup.md index 4b516e532a..2e20d415f2 100644 --- a/commands/xreadgroup.md +++ b/commands/xreadgroup.md @@ -116,14 +116,14 @@ Example: "1-0" > XGROUP CREATE mystream mygroup 0 OK -> XREADGROUP GROUP mygroup myconsumer STREAMS STREAMS mystream > +> XREADGROUP GROUP mygroup myconsumer STREAMS mystream > 1) 1) "mystream" 2) 1) 1) "1-0" 2) 1) "myfield" 2) "mydata" > XDEL mystream 1-0 (integer) 1 -> XREADGROUP GROUP mygroup myconsumer STREAMS STREAMS mystream 0 +> XREADGROUP GROUP mygroup myconsumer STREAMS mystream 0 1) 1) "mystream" 2) 1) 1) "1-0" 2) (nil) From 057f5fb6b471f5ae2b212f4b5fc999fdcfa28053 Mon Sep 17 00:00:00 2001 From: Irfan Butt Date: Thu, 29 Dec 2022 15:11:45 +0000 Subject: [PATCH 107/377] Correct the English a little bit (#2270) Co-authored-by: Itamar Haber --- docs/manual/client-side-caching.md | 2 +- docs/manual/programmability/lua-api.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/manual/client-side-caching.md b/docs/manual/client-side-caching.md index 60e94fff89..61da7dd6c6 100644 --- a/docs/manual/client-side-caching.md +++ b/docs/manual/client-side-caching.md @@ -93,7 +93,7 @@ The Redis client-side caching support is called _Tracking_, and has two modes: * In the _broadcasting_ mode, the server does not attempt to remember what keys a given client accessed, so this mode costs no memory at all in the server side. Instead clients subscribe to key prefixes such as `object:` or `user:`, and receive a notification message every time a key matching a subscribed prefix is touched. To recap, for now let's forget for a moment about the broadcasting mode, to -focus on the first mode. We'll describe broadcasting later more in details. +focus on the first mode. We'll describe broadcasting in more detail later. 1. Clients can enable tracking if they want. Connections start without tracking enabled. 2. When tracking is enabled, the server remembers what keys each client requested during the connection lifetime (by sending read commands about such keys). diff --git a/docs/manual/programmability/lua-api.md b/docs/manual/programmability/lua-api.md index da048f76a8..d63ee5cc0f 100644 --- a/docs/manual/programmability/lua-api.md +++ b/docs/manual/programmability/lua-api.md @@ -36,7 +36,7 @@ my_global_variable = 'some value' And similarly for the following global function declaration: ```lua -function my_global_funcion() +function my_global_function() -- Do something amazing end ``` From 0c2ae0cedf2ef193599f97be9a0659a3ad91debc Mon Sep 17 00:00:00 2001 From: Stephan Schneider Date: Mon, 2 Jan 2023 12:58:56 +0100 Subject: [PATCH 108/377] Formatting and spelling fixes in Lua API (#2274) * Fix formatting in Lua API pcall section * Fix spelling in Lua API error_reply section * Fix spelling in Lua API status_reply section --- docs/manual/programmability/lua-api.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/manual/programmability/lua-api.md b/docs/manual/programmability/lua-api.md index d63ee5cc0f..39ca8b0c0b 100644 --- a/docs/manual/programmability/lua-api.md +++ b/docs/manual/programmability/lua-api.md @@ -201,7 +201,7 @@ redis> EVAL "return redis.error_reply('My very special reply error')" 0 (error) My very special reply error ``` -For returing Redis status replies refer to [`redis.status_reply()`](#redis.status_reply). +For returning Redis status replies refer to [`redis.status_reply()`](#redis.status_reply). Refer to the [Data type conversion](#data-type-conversion) for returning other response types. ### `redis.status_reply(x)` @@ -231,7 +231,7 @@ redis> EVAL "return redis.status_reply('TOCK')" 0 TOCK ``` -For returing Redis error replies refer to [`redis.error_reply()`](#redis.error_reply). +For returning Redis error replies refer to [`redis.error_reply()`](#redis.error_reply). Refer to the [Data type conversion](#data-type-conversion) for returning other response types. ### `redis.sha1hex(x)` @@ -287,7 +287,7 @@ will produce a line similar to the following in your server's log: * Available in scripts: yes * Available in functions: yes -This function allows the executing script to switch between [Redis Serialization Protocol (RESP)](/topics/protocol) versions for the replies returned by [`redis.call()](#redis.call) and [`redis.pall()](#redis.pcall). +This function allows the executing script to switch between [Redis Serialization Protocol (RESP)](/topics/protocol) versions for the replies returned by [`redis.call()`](#redis.call) and [`redis.pcall()`](#redis.pcall). It expects a single numerical argument as the protocol's version. The default protocol version is _2_, but it can be switched to version _3_. From c7043b031503aba9bfdc83dd0a15d06e8b66a065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Catanzariti?= Date: Tue, 3 Jan 2023 15:20:17 +0100 Subject: [PATCH 109/377] Added rustis client library (#2271) --- clients/rust/github.com/dahomey-technologies/rustis.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 clients/rust/github.com/dahomey-technologies/rustis.json diff --git a/clients/rust/github.com/dahomey-technologies/rustis.json b/clients/rust/github.com/dahomey-technologies/rustis.json new file mode 100644 index 0000000000..782b2201ec --- /dev/null +++ b/clients/rust/github.com/dahomey-technologies/rustis.json @@ -0,0 +1,4 @@ +{ + "name": "rustis", + "description": "An asynchronous Redis client for Rust.", +} From 7b1bbc7fef46056f7004ab00fd462cd61456ac09 Mon Sep 17 00:00:00 2001 From: liuwenzhuang Date: Wed, 4 Jan 2023 21:42:39 +0800 Subject: [PATCH 110/377] fix: setbit should return 0 on an empty instance (#2237) --- docs/data-types/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/tutorial.md b/docs/data-types/tutorial.md index 8986ddce9a..02647ad4df 100644 --- a/docs/data-types/tutorial.md +++ b/docs/data-types/tutorial.md @@ -880,7 +880,7 @@ a user wants to receive a newsletter) of 4 billion of users using just 512 MB of Bits are set and retrieved using the `SETBIT` and `GETBIT` commands: > setbit key 10 1 - (integer) 1 + (integer) 0 > getbit key 10 (integer) 1 > getbit key 11 From fb026cd3b11ce18387f68a2cc86b9cd81a963926 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Thu, 5 Jan 2023 16:20:40 +0200 Subject: [PATCH 111/377] Removes a comma (#2278) --- clients/rust/github.com/dahomey-technologies/rustis.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/rust/github.com/dahomey-technologies/rustis.json b/clients/rust/github.com/dahomey-technologies/rustis.json index 782b2201ec..df88e4ecf2 100644 --- a/clients/rust/github.com/dahomey-technologies/rustis.json +++ b/clients/rust/github.com/dahomey-technologies/rustis.json @@ -1,4 +1,4 @@ { "name": "rustis", - "description": "An asynchronous Redis client for Rust.", + "description": "An asynchronous Redis client for Rust." } From b5b9f4c6515ac3a668def0a193f94a866894be64 Mon Sep 17 00:00:00 2001 From: Michael <50352631+michaelvanstraten@users.noreply.github.com> Date: Thu, 5 Jan 2023 15:46:28 +0100 Subject: [PATCH 112/377] Added SwiftyRedis as a swift client (#2277) --- clients/swift/github.com/michaelvanstraten/Swifty-Redis.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 clients/swift/github.com/michaelvanstraten/Swifty-Redis.json diff --git a/clients/swift/github.com/michaelvanstraten/Swifty-Redis.json b/clients/swift/github.com/michaelvanstraten/Swifty-Redis.json new file mode 100644 index 0000000000..ddf86c957f --- /dev/null +++ b/clients/swift/github.com/michaelvanstraten/Swifty-Redis.json @@ -0,0 +1,5 @@ +{ + "name": "SwiftyRedis", + "description": "SwiftyRedis is a high level async redis library for Swift. ", + "homepage": "https://michaelvanstraten.github.io/swifty-redis/documentation/swiftyredis/" +} From 1f1071f82884407b35ce44c04ae704ae08e3d7ca Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Thu, 5 Jan 2023 19:03:13 +0200 Subject: [PATCH 113/377] Fixes wrong alias (#2279) --- docs/management/config-file.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/management/config-file.md b/docs/management/config-file.md index cbd1f4c4d8..05074ec832 100644 --- a/docs/management/config-file.md +++ b/docs/management/config-file.md @@ -5,7 +5,7 @@ weight: 3 description: > The self-documented `redis.conf` file that's shipped with every version. aliases: [ - /docs/management/config-file + /docs/manual/config-file ] --- From 837bfb291d949264cfd56bb24b5150baa7023738 Mon Sep 17 00:00:00 2001 From: Alex Yeo Date: Sat, 7 Jan 2023 13:52:21 -0800 Subject: [PATCH 114/377] Fix small typo in tutorial.md (#2281) Should either read "elements in a sorted set" or "elements in sorted sets". --- docs/data-types/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/tutorial.md b/docs/data-types/tutorial.md index 02647ad4df..8681607964 100644 --- a/docs/data-types/tutorial.md +++ b/docs/data-types/tutorial.md @@ -659,7 +659,7 @@ a sorted set is associated with a floating point value, called *the score* (this is why the type is also similar to a hash, since every element is mapped to a value). -Moreover, elements in a sorted sets are *taken in order* (so they are not +Moreover, elements in a sorted set are *taken in order* (so they are not ordered on request, order is a peculiarity of the data structure used to represent sorted sets). They are ordered according to the following rule: From 98b7f06a43f1dca3a0dd8434df4236e77a840b65 Mon Sep 17 00:00:00 2001 From: Shivam Date: Mon, 9 Jan 2023 17:10:38 +0530 Subject: [PATCH 115/377] Fix typo in scaling.md (#2282) --- docs/management/scaling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/management/scaling.md b/docs/management/scaling.md index 2863fac665..519242ac7d 100644 --- a/docs/management/scaling.md +++ b/docs/management/scaling.md @@ -37,7 +37,7 @@ Cluster bus is a node-to-node communication channel that uses a binary protocol, little bandwidth and processing time. Nodes use the cluster bus for failure detection, configuration updates, failover authorization, and so forth. Clients should never try to communicate with the cluster bus port, but rather use the Redis command port. -However, make sure you open both ports in your firewall, otherwise Redis cluster nodes won't be unable to communicate. +However, make sure you open both ports in your firewall, otherwise Redis cluster nodes won't be able to communicate. For a Redis Cluster to work properly you need, for each node: From 281af38767956c125d237ff4015485516bcfaf23 Mon Sep 17 00:00:00 2001 From: nachoalonsoportillo <41644064+nachoalonsoportillo@users.noreply.github.com> Date: Tue, 10 Jan 2023 19:17:13 +0100 Subject: [PATCH 116/377] Correct minor typo (#2284) --- commands/xclaim.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/xclaim.md b/commands/xclaim.md index d3a17dc32a..bc7b7be3a6 100644 --- a/commands/xclaim.md +++ b/commands/xclaim.md @@ -10,7 +10,7 @@ command argument. Normally this is what happens: This dynamic is clearly explained in the [Stream intro documentation](/topics/streams-intro). -Note that the message is claimed only if its idle time is greater the minimum idle time we specify when calling `XCLAIM`. Because as a side effect `XCLAIM` will also reset the idle time (since this is a new attempt at processing the message), two consumers trying to claim a message at the same time will never both succeed: only one will successfully claim the message. This avoids that we process a given message multiple times in a trivial way (yet multiple processing is possible and unavoidable in the general case). +Note that the message is claimed only if its idle time is greater than the minimum idle time we specify when calling `XCLAIM`. Because as a side effect `XCLAIM` will also reset the idle time (since this is a new attempt at processing the message), two consumers trying to claim a message at the same time will never both succeed: only one will successfully claim the message. This avoids that we process a given message multiple times in a trivial way (yet multiple processing is possible and unavoidable in the general case). Moreover, as a side effect, `XCLAIM` will increment the count of attempted deliveries of the message unless the `JUSTID` option has been specified (which only delivers the message ID, not the message itself). In this way messages that cannot be processed for some reason, for instance because the consumers crash attempting to process them, will start to have a larger counter and can be detected inside the system. From 82691cefab5f42aedb351cdcffd5435cd953d19f Mon Sep 17 00:00:00 2001 From: Seer Date: Wed, 18 Jan 2023 20:33:38 +0800 Subject: [PATCH 117/377] Fixes nodes.conf fields doc format error (#2291) * fixed nodes.conf fields explanation format error Co-authored-by: Binbin --- commands/cluster-nodes.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/commands/cluster-nodes.md b/commands/cluster-nodes.md index afee4b895b..2152c94c78 100644 --- a/commands/cluster-nodes.md +++ b/commands/cluster-nodes.md @@ -45,7 +45,8 @@ The meaning of each filed is the following: 5. `flags`: A list of comma separated flags: `myself`, `master`, `slave`, `fail?`, `fail`, `handshake`, `noaddr`, `nofailover`, `noflags`. Flags are explained below. 6. `master`: If the node is a replica, and the primary is known, the primary node ID, otherwise the "-" character. 7. `ping-sent`: Unix time at which the currently active ping was sent, or zero if there are no pending pings, in milliseconds. -8. `pong-recv`: Unix time the last pong was received, in milliseconds. 9. `config-epoch`: The configuration epoch (or version) of the current node (or of the current primary if the node is a replica). Each time there is a failover, a new, unique, monotonically increasing configuration epoch is created. If multiple nodes claim to serve the same hash slots, the one with the higher configuration epoch wins. +8. `pong-recv`: Unix time the last pong was received, in milliseconds. +9. `config-epoch`: The configuration epoch (or version) of the current node (or of the current primary if the node is a replica). Each time there is a failover, a new, unique, monotonically increasing configuration epoch is created. If multiple nodes claim to serve the same hash slots, the one with the higher configuration epoch wins. 10. `link-state`: The state of the link used for the node-to-node cluster bus. Use this link to communicate with the node. Can be `connected` or `disconnected`. 11. `slot`: A hash slot number or range. Starting from argument number 9, but there may be up to 16384 entries in total (limit never reached). This is the list of hash slots served by this node. If the entry is just a number, it is parsed as such. If it is a range, it is in the form `start-end`, and means that the node is responsible for all the hash slots from `start` to `end` including the start and end values. From 690be1deddc9c800fc54c71dd437deb7cff05119 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Wed, 18 Jan 2023 15:18:24 +0200 Subject: [PATCH 118/377] Fixes a typo (#2292) --- commands/info.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/info.md b/commands/info.md index a07ec67c49..27b6ce22a4 100644 --- a/commands/info.md +++ b/commands/info.md @@ -194,7 +194,7 @@ Here is the meaning of all fields in the **persistence** section: if any * `rdb_last_cow_size`: The size in bytes of copy-on-write memory during the last RDB save operation -* `rdb_last_load_keys_expired`: Number volatile keys deleted during the last RDB loading. Added in Redis 7.0. +* `rdb_last_load_keys_expired`: Number of volatile keys deleted during the last RDB loading. Added in Redis 7.0. * `rdb_last_load_keys_loaded`: Number of keys loaded during the last RDB loading. Added in Redis 7.0. * `aof_enabled`: Flag indicating AOF logging is activated * `aof_rewrite_in_progress`: Flag indicating a AOF rewrite operation is From c000094b572b469f221647c7ea7c4b03d1457dc6 Mon Sep 17 00:00:00 2001 From: Jacky Date: Wed, 18 Jan 2023 21:35:05 +0800 Subject: [PATCH 119/377] =?UTF-8?q?=E6=9B=B4=E6=96=B0Redis=E5=BA=93=20(#22?= =?UTF-8?q?75)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clients/csharp/github.com/XiaoFeng/XiaoFeng.Redis.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/csharp/github.com/XiaoFeng/XiaoFeng.Redis.json b/clients/csharp/github.com/XiaoFeng/XiaoFeng.Redis.json index 79f1266166..a105772e78 100644 --- a/clients/csharp/github.com/XiaoFeng/XiaoFeng.Redis.json +++ b/clients/csharp/github.com/XiaoFeng/XiaoFeng.Redis.json @@ -1,5 +1,5 @@ { "name": "XiaoFeng.Redis", "description": "A useful Redis client that supports the .NET FRAMEWORK,.NET CORE,.NET STANDARD. A client tool that is quite convenient to operate.", - "homepage": "https://github.com/zhuovi/XiaoFeng" + "homepage": "https://github.com/zhuovi/XiaoFeng.Redis" } \ No newline at end of file From 936de39da1098a1053febdb3defa88338b16c25a Mon Sep 17 00:00:00 2001 From: Binbin Date: Thu, 19 Jan 2023 19:46:10 +0800 Subject: [PATCH 120/377] Clarified that LINSERT will return 0 if the key does not exist (#2289) --- commands/linsert.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/commands/linsert.md b/commands/linsert.md index 9fe8f6131b..df80725136 100644 --- a/commands/linsert.md +++ b/commands/linsert.md @@ -8,8 +8,7 @@ An error is returned when `key` exists but does not hold a list value. @return -@integer-reply: the length of the list after the insert operation, or `-1` when -the value `pivot` was not found. +@integer-reply: the list length after a successful insert operation, `0` if the `key` doesn't exist, and `-1` when the `pivot` wasn't found. @examples From f640a2bfeae214168f26ad8e1b7f7742a2937538 Mon Sep 17 00:00:00 2001 From: Chayim Date: Sat, 21 Jan 2023 17:41:18 +0200 Subject: [PATCH 121/377] Adding nredisstack, fixing python description (#2293) --- clients/csharp/github.com/NRedisStack/Redis.NRedisStack.json | 5 +++++ clients/python/github.com/redis/redis-py.json | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 clients/csharp/github.com/NRedisStack/Redis.NRedisStack.json diff --git a/clients/csharp/github.com/NRedisStack/Redis.NRedisStack.json b/clients/csharp/github.com/NRedisStack/Redis.NRedisStack.json new file mode 100644 index 0000000000..5108698fbd --- /dev/null +++ b/clients/csharp/github.com/NRedisStack/Redis.NRedisStack.json @@ -0,0 +1,5 @@ +{ + "name": "NRedisStack", + "description": "This client is developed by Redis to bring RedisStack support to CSharp.", + "recommended": true +} diff --git a/clients/python/github.com/redis/redis-py.json b/clients/python/github.com/redis/redis-py.json index e36a228c5c..4ad33550f8 100644 --- a/clients/python/github.com/redis/redis-py.json +++ b/clients/python/github.com/redis/redis-py.json @@ -1,5 +1,5 @@ { "name": "redis-py", - "description": "Mature and supported. Currently the way to go for Python.", + "description": "Mature and supported. The way to go for Python.", "recommended": true -} \ No newline at end of file +} From fbeda35047090914128e791e5cf768459e5baca5 Mon Sep 17 00:00:00 2001 From: Abdullah Saquib <48850765+AbdullahSaquib@users.noreply.github.com> Date: Sun, 22 Jan 2023 18:41:50 +0530 Subject: [PATCH 122/377] Correction in eviction.md (#2294) --- docs/reference/eviction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/eviction.md b/docs/reference/eviction.md index a0d87ebd8a..8fcbda98ae 100644 --- a/docs/reference/eviction.md +++ b/docs/reference/eviction.md @@ -89,7 +89,7 @@ If a command results in a lot of memory being used (like a big set intersection ## Approximated LRU algorithm Redis LRU algorithm is not an exact implementation. This means that Redis is -not able to pick the *best candidate* for eviction, that is, the access that +not able to pick the *best candidate* for eviction, that is, the key that was accessed the furthest in the past. Instead it will try to run an approximation of the LRU algorithm, by sampling a small number of keys, and evicting the one that is the best (with the oldest access time) among the sampled keys. From 00af5211f039f44c3b35d7511ce201ff2c6bba7c Mon Sep 17 00:00:00 2001 From: Chen Tianjie Date: Wed, 25 Jan 2023 00:45:20 +0800 Subject: [PATCH 123/377] Add description of WITHSCORE argument to ZRANK and ZREVRANK (#2227) For PR redis/redis#11235, which adds the WITHSCORE option to command ZRANK and ZREVRANK. --- commands/zrank.md | 15 ++++++++++++--- commands/zrevrank.md | 15 ++++++++++++--- wordlist | 1 + 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/commands/zrank.md b/commands/zrank.md index 1419adf82a..f458f298da 100644 --- a/commands/zrank.md +++ b/commands/zrank.md @@ -3,14 +3,21 @@ ordered from low to high. The rank (or index) is 0-based, which means that the member with the lowest score has rank `0`. +The optional `WITHSCORE` argument supplements the command's reply with the score of the element returned. + Use `ZREVRANK` to get the rank of an element with the scores ordered from high to low. @return -* If `member` exists in the sorted set, @integer-reply: the rank of `member`. -* If `member` does not exist in the sorted set or `key` does not exist, - @bulk-string-reply: `nil`. +* If `member` exists in the sorted set: + * using `WITHSCORE`, @array-reply: an array containing the rank and score of `member`. + * without using `WITHSCORE`, @integer-reply: the rank of `member`. +* If `member` does not exist in the sorted set or `key` does not exist: + * using `WITHSCORE`, @array-reply: `nil`. + * without using `WITHSCORE`, @bulk-string-reply: `nil`. + +Note that in RESP3 null and nullarray are the same, but in RESP2 they are not. @examples @@ -20,4 +27,6 @@ ZADD myzset 2 "two" ZADD myzset 3 "three" ZRANK myzset "three" ZRANK myzset "four" +ZRANK myzset "three" WITHSCORE +ZRANK myzset "four" WITHSCORE ``` diff --git a/commands/zrevrank.md b/commands/zrevrank.md index 6c64d98734..11aad62bbe 100644 --- a/commands/zrevrank.md +++ b/commands/zrevrank.md @@ -3,14 +3,21 @@ ordered from high to low. The rank (or index) is 0-based, which means that the member with the highest score has rank `0`. +The optional `WITHSCORE` argument supplements the command's reply with the score of the element returned. + Use `ZRANK` to get the rank of an element with the scores ordered from low to high. @return -* If `member` exists in the sorted set, @integer-reply: the rank of `member`. -* If `member` does not exist in the sorted set or `key` does not exist, - @bulk-string-reply: `nil`. +* If `member` exists in the sorted set: + * using `WITHSCORE`, @array-reply: an array containing the rank and score of `member`. + * without using `WITHSCORE`, @integer-reply: the rank of `member`. +* If `member` does not exist in the sorted set or `key` does not exist: + * using `WITHSCORE`, @array-reply: `nil`. + * without using `WITHSCORE`, @bulk-string-reply: `nil`. + +Note that in RESP3 null and nullarray are the same, but in RESP2 they are not. @examples @@ -20,4 +27,6 @@ ZADD myzset 2 "two" ZADD myzset 3 "three" ZREVRANK myzset "one" ZREVRANK myzset "four" +ZREVRANK myzset "three" WITHSCORE +ZREVRANK myzset "four" WITHSCORE ``` diff --git a/wordlist b/wordlist index f0181afaf7..3d99006a91 100644 --- a/wordlist +++ b/wordlist @@ -726,6 +726,7 @@ notifyKeyspaceEvent num-items numactl numkeys +nullarray observability odown ok From 0a0d8c42a163747663be1642e86dd13316bd7da9 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Tue, 24 Jan 2023 21:52:43 +0200 Subject: [PATCH 124/377] Removes/fixes a bunch of external repos links (#2296) --- .../wusongwei/soce/{tree/master => }/soce-redis.json | 3 +-- .../Redis.NRedisStack.json => redis/NRedisStack.json} | 0 .../github.com/{XiaoFeng => zhuovi}/XiaoFeng.Redis.json | 3 +-- clients/fancy/github.com/bakkdoor/redis.fy.json | 7 ------- clients/php/github.com/jdp/redisent.json | 7 ------- .../tree/develop/finagle-redis.json => finagle.json} | 2 +- .../github.com/{RediStick => mumez}/RediStick.json | 0 .../{SimpleRedisClient => svenvc}/SimpleRedisClient.json | 0 .../{Pharo-Redis => tblanchard}/Pharo-Redis.json | 1 - .../labview/decibel.ni.com/content/docs/DOC-36322.json | 7 ------- libraries/python/github.com/lsbardel/python-stdnet.json | 7 ------- libraries/ruby/github.com/carlhoerberg/meerkat.json | 1 - 12 files changed, 3 insertions(+), 35 deletions(-) rename clients/cpp/github.com/wusongwei/soce/{tree/master => }/soce-redis.json (61%) rename clients/csharp/github.com/{NRedisStack/Redis.NRedisStack.json => redis/NRedisStack.json} (100%) rename clients/csharp/github.com/{XiaoFeng => zhuovi}/XiaoFeng.Redis.json (65%) delete mode 100644 clients/fancy/github.com/bakkdoor/redis.fy.json delete mode 100644 clients/php/github.com/jdp/redisent.json rename clients/scala/github.com/twitter/{finagle/tree/develop/finagle-redis.json => finagle.json} (65%) rename clients/smalltalk/github.com/{RediStick => mumez}/RediStick.json (100%) rename clients/smalltalk/github.com/{SimpleRedisClient => svenvc}/SimpleRedisClient.json (100%) rename clients/smalltalk/github.com/{Pharo-Redis => tblanchard}/Pharo-Redis.json (80%) delete mode 100644 libraries/labview/decibel.ni.com/content/docs/DOC-36322.json delete mode 100644 libraries/python/github.com/lsbardel/python-stdnet.json diff --git a/clients/cpp/github.com/wusongwei/soce/tree/master/soce-redis.json b/clients/cpp/github.com/wusongwei/soce/soce-redis.json similarity index 61% rename from clients/cpp/github.com/wusongwei/soce/tree/master/soce-redis.json rename to clients/cpp/github.com/wusongwei/soce/soce-redis.json index b230eb134e..26f6972f1f 100644 --- a/clients/cpp/github.com/wusongwei/soce/tree/master/soce-redis.json +++ b/clients/cpp/github.com/wusongwei/soce/soce-redis.json @@ -1,5 +1,4 @@ { "name": "soce-redis", - "description": "Based on hiredis, accesses the sever(single, sentinel, cluster) with the same interface, supports pipeline and async(by coroutine)", - "homepage": "https://github.com/wusongwei/soce/tree/master/soce-redis" + "description": "Based on hiredis, accesses the sever(single, sentinel, cluster) with the same interface, supports pipeline and async(by coroutine)" } \ No newline at end of file diff --git a/clients/csharp/github.com/NRedisStack/Redis.NRedisStack.json b/clients/csharp/github.com/redis/NRedisStack.json similarity index 100% rename from clients/csharp/github.com/NRedisStack/Redis.NRedisStack.json rename to clients/csharp/github.com/redis/NRedisStack.json diff --git a/clients/csharp/github.com/XiaoFeng/XiaoFeng.Redis.json b/clients/csharp/github.com/zhuovi/XiaoFeng.Redis.json similarity index 65% rename from clients/csharp/github.com/XiaoFeng/XiaoFeng.Redis.json rename to clients/csharp/github.com/zhuovi/XiaoFeng.Redis.json index a105772e78..8f73792fef 100644 --- a/clients/csharp/github.com/XiaoFeng/XiaoFeng.Redis.json +++ b/clients/csharp/github.com/zhuovi/XiaoFeng.Redis.json @@ -1,5 +1,4 @@ { "name": "XiaoFeng.Redis", - "description": "A useful Redis client that supports the .NET FRAMEWORK,.NET CORE,.NET STANDARD. A client tool that is quite convenient to operate.", - "homepage": "https://github.com/zhuovi/XiaoFeng.Redis" + "description": "A useful Redis client that supports the .NET FRAMEWORK,.NET CORE,.NET STANDARD. A client tool that is quite convenient to operate." } \ No newline at end of file diff --git a/clients/fancy/github.com/bakkdoor/redis.fy.json b/clients/fancy/github.com/bakkdoor/redis.fy.json deleted file mode 100644 index 99a5c75559..0000000000 --- a/clients/fancy/github.com/bakkdoor/redis.fy.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "redis.fy", - "description": "A Fancy Redis client library", - "twitter": [ - "bakkdoor" - ] -} \ No newline at end of file diff --git a/clients/php/github.com/jdp/redisent.json b/clients/php/github.com/jdp/redisent.json deleted file mode 100644 index 05614fbee7..0000000000 --- a/clients/php/github.com/jdp/redisent.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Redisent", - "description": "A Redis client.", - "twitter": [ - "justinpoliey" - ] -} diff --git a/clients/scala/github.com/twitter/finagle/tree/develop/finagle-redis.json b/clients/scala/github.com/twitter/finagle.json similarity index 65% rename from clients/scala/github.com/twitter/finagle/tree/develop/finagle-redis.json rename to clients/scala/github.com/twitter/finagle.json index 031dc0d80e..d85604ce4c 100644 --- a/clients/scala/github.com/twitter/finagle/tree/develop/finagle-redis.json +++ b/clients/scala/github.com/twitter/finagle.json @@ -1,4 +1,4 @@ { - "name": "finagle-redis", + "name": "finagle", "description": "Redis client based on Finagle" } \ No newline at end of file diff --git a/clients/smalltalk/github.com/RediStick/RediStick.json b/clients/smalltalk/github.com/mumez/RediStick.json similarity index 100% rename from clients/smalltalk/github.com/RediStick/RediStick.json rename to clients/smalltalk/github.com/mumez/RediStick.json diff --git a/clients/smalltalk/github.com/SimpleRedisClient/SimpleRedisClient.json b/clients/smalltalk/github.com/svenvc/SimpleRedisClient.json similarity index 100% rename from clients/smalltalk/github.com/SimpleRedisClient/SimpleRedisClient.json rename to clients/smalltalk/github.com/svenvc/SimpleRedisClient.json diff --git a/clients/smalltalk/github.com/Pharo-Redis/Pharo-Redis.json b/clients/smalltalk/github.com/tblanchard/Pharo-Redis.json similarity index 80% rename from clients/smalltalk/github.com/Pharo-Redis/Pharo-Redis.json rename to clients/smalltalk/github.com/tblanchard/Pharo-Redis.json index e8d53bac52..cbd1afb89a 100644 --- a/clients/smalltalk/github.com/Pharo-Redis/Pharo-Redis.json +++ b/clients/smalltalk/github.com/tblanchard/Pharo-Redis.json @@ -1,7 +1,6 @@ { "name": "Pharo-Redis", "language": "Smalltalk", - "repository": "https://github.com/tblanchard/Pharo-Redis", "description": "A full featured Redis client for Pharo. This was forked from svenvc/SimpleRedisClient and that simple client is still at the center of this.", "authors": [ "ToddBlanchard10" diff --git a/libraries/labview/decibel.ni.com/content/docs/DOC-36322.json b/libraries/labview/decibel.ni.com/content/docs/DOC-36322.json deleted file mode 100644 index 75c8802b74..0000000000 --- a/libraries/labview/decibel.ni.com/content/docs/DOC-36322.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "redis-in-labview", - "description": "LabVIEW toolkit for Redis", - "twitter": [ - "iwac" - ] -} \ No newline at end of file diff --git a/libraries/python/github.com/lsbardel/python-stdnet.json b/libraries/python/github.com/lsbardel/python-stdnet.json deleted file mode 100644 index 6d8007d161..0000000000 --- a/libraries/python/github.com/lsbardel/python-stdnet.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Stdnet", - "description": "Redis data manager with advanced query and search API.", - "twitter": [ - "lsbardel" - ] -} \ No newline at end of file diff --git a/libraries/ruby/github.com/carlhoerberg/meerkat.json b/libraries/ruby/github.com/carlhoerberg/meerkat.json index f114d9d99d..d4bc7069ce 100644 --- a/libraries/ruby/github.com/carlhoerberg/meerkat.json +++ b/libraries/ruby/github.com/carlhoerberg/meerkat.json @@ -1,7 +1,6 @@ { "name": "Meerkat", "description": "Rack middleware for Server Sent Events with multiple backends.", - "homepage": "https://carlhoerberg.github.io/meerkat/", "twitter": [ "carlhoerberg" ] From 84083d0644613027408b5a66b546659842f40c44 Mon Sep 17 00:00:00 2001 From: Binbin Date: Wed, 25 Jan 2023 04:19:58 +0800 Subject: [PATCH 125/377] Document Sentinel fields in INFO command (#2290) Fixes #2283 Co-authored-by: Itamar Haber --- commands/info.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/commands/info.md b/commands/info.md index 27b6ce22a4..9f7b7226db 100644 --- a/commands/info.md +++ b/commands/info.md @@ -12,6 +12,7 @@ The optional parameter can be used to select a specific section of information: * `cpu`: CPU consumption statistics * `commandstats`: Redis command statistics * `latencystats`: Redis command latency percentile distribution statistics +* `sentinel`: Redis Sentinel section (only applicable to Sentinel instances) * `cluster`: Redis Cluster section * `modules`: Modules section * `keyspace`: Database related statistics @@ -409,6 +410,15 @@ For each error type, the following line is added: * `errorstat_XXX`: `count=XXX` +The **sentinel** section is only available in Redis Sentinel instances. It consists of the following fields: + +* `sentinel_masters`: Number of Redis masters monitored by this Sentinel instance +* `sentinel_tilt`: A value of 1 means this sentinel is in TILT mode +* `sentinel_tilt_since_seconds`: Duration in seconds of current TILT, or -1 if not TILTed. Added in Redis 7.0.0 +* `sentinel_running_scripts`: The number of scripts this Sentinel is currently executing +* `sentinel_scripts_queue_length`: The length of the queue of user scripts that are pending execution +* `sentinel_simulate_failure_flags`: Flags for the `SENTINEL SIMULATE-FAILURE` command + The **cluster** section currently only contains a unique field: * `cluster_enabled`: Indicate Redis cluster is enabled From 007bf3e7633dc1b7f06aab1cf025a25a9e901526 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Tue, 24 Jan 2023 22:23:17 +0200 Subject: [PATCH 126/377] More dead ones (#2297) --- .../wusongwei/{soce/soce-redis.json => soce.json} | 0 clients/ruby/github.com/redis/redis-clustering.json | 4 ---- clients/smalltalk/squeaksource.com/Redis/Redis.json | 6 ------ .../RedisBinaryClient/RedisBinaryClient.json | 6 ------ .../unstable/tests/support/redis.tcl.json => redis.json} | 0 5 files changed, 16 deletions(-) rename clients/cpp/github.com/wusongwei/{soce/soce-redis.json => soce.json} (100%) delete mode 100644 clients/ruby/github.com/redis/redis-clustering.json delete mode 100644 clients/smalltalk/squeaksource.com/Redis/Redis.json delete mode 100644 clients/smalltalk/squeaksource.com/RedisBinaryClient/RedisBinaryClient.json rename clients/tcl/github.com/redis/{redis/blob/unstable/tests/support/redis.tcl.json => redis.json} (100%) diff --git a/clients/cpp/github.com/wusongwei/soce/soce-redis.json b/clients/cpp/github.com/wusongwei/soce.json similarity index 100% rename from clients/cpp/github.com/wusongwei/soce/soce-redis.json rename to clients/cpp/github.com/wusongwei/soce.json diff --git a/clients/ruby/github.com/redis/redis-clustering.json b/clients/ruby/github.com/redis/redis-clustering.json deleted file mode 100644 index 0857ad5c33..0000000000 --- a/clients/ruby/github.com/redis/redis-clustering.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "redis-clustering", - "description": "A Ruby client that tries to match Redis' Cluster API one-to-one, while still providing an idiomatic interface." -} diff --git a/clients/smalltalk/squeaksource.com/Redis/Redis.json b/clients/smalltalk/squeaksource.com/Redis/Redis.json deleted file mode 100644 index 8868bdfa4d..0000000000 --- a/clients/smalltalk/squeaksource.com/Redis/Redis.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "Redis", - "language": "Smalltalk", - "repository": "http://www.squeaksource.com/Redis", - "description": "Smalltalk Redis client." -} \ No newline at end of file diff --git a/clients/smalltalk/squeaksource.com/RedisBinaryClient/RedisBinaryClient.json b/clients/smalltalk/squeaksource.com/RedisBinaryClient/RedisBinaryClient.json deleted file mode 100644 index c78a59da11..0000000000 --- a/clients/smalltalk/squeaksource.com/RedisBinaryClient/RedisBinaryClient.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "RedisBinaryClient", - "language": "Smalltalk", - "repository": "http://www.squeaksource.com/RedisBinaryClient/", - "description": "A fork of the RedisConnection from Redis Client." -} \ No newline at end of file diff --git a/clients/tcl/github.com/redis/redis/blob/unstable/tests/support/redis.tcl.json b/clients/tcl/github.com/redis/redis.json similarity index 100% rename from clients/tcl/github.com/redis/redis/blob/unstable/tests/support/redis.tcl.json rename to clients/tcl/github.com/redis/redis.json From 4d81f91eff7f615d810aeaf8f42e4d08afbbd2d5 Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Tue, 24 Jan 2023 17:32:18 -0500 Subject: [PATCH 127/377] Fixes links and typos (#2298) --- docs/getting-started/_index.md | 18 ++++++--------- docs/reference/modules/modules-api-ref.md | 28 ++++++++--------------- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/docs/getting-started/_index.md b/docs/getting-started/_index.md index 68df45241d..e6af889adf 100644 --- a/docs/getting-started/_index.md +++ b/docs/getting-started/_index.md @@ -22,7 +22,7 @@ How you install Redis depends on your operating system and whether you'd like to Once you have Redis up and running, and can connect using `redis-cli`, you can continue with the steps below. -## Exploring Redis with the CLI +## Explore Redis using the CLI External programs talk to Redis using a TCP socket and a Redis specific protocol. This protocol is implemented in the Redis client libraries for the different programming languages. However to make hacking with Redis simpler Redis provides a command line utility that can be used to send commands to Redis. This program is called **redis-cli**. @@ -45,8 +45,7 @@ Another interesting way to run `redis-cli` is without arguments: the program wil At this point you are able to talk with Redis. It is the right time to pause a bit with this tutorial and start the [fifteen minutes introduction to Redis data types](https://redis.io/topics/data-types-intro) in order to learn a few Redis commands. Otherwise if you already know a few basic Redis commands you can keep reading. -Securing Redis -=== +## Securing Redis By default Redis binds to **all the interfaces** and has no authentication at all. If you use Redis in a very controlled environment, separated from the @@ -60,8 +59,7 @@ is exposed to the internet, it is a big security concern. If you are not 100% su Note that a Redis instance exposed to the internet without any security [is very simple to exploit](http://antirez.com/news/96), so make sure you understand the above and apply **at least** a firewall layer. After the firewall is in place, try to connect with `redis-cli` from an external host in order to prove yourself the instance is actually not reachable. -Using Redis from your application -=== +## Use Redis from your application Of course using Redis just from the command line interface is not enough as the goal is to use it from your application. In order to do so you need to @@ -89,8 +87,7 @@ commands calling methods. A short interactive example using Ruby: >> r.get('foo') => "bar" -Redis persistence -================= +## Redis persistence You can learn [how Redis persistence works on this page](https://redis.io/topics/persistence), however what is important to understand for a quick start is that by default, if you start Redis with the default configuration, Redis will spontaneously save the dataset only from time to time (for instance after at least five minutes if you have at least 100 changes in your data), so if you want your database to persist and be reloaded after a restart make sure to call the **SAVE** command manually every time you want to force a data set snapshot. Otherwise make sure to shutdown the database using the **SHUTDOWN** command: @@ -99,8 +96,7 @@ You can learn [how Redis persistence works on this page](https://redis.io/topics This way Redis will make sure to save the data on disk before quitting. Reading the [persistence page](https://redis.io/topics/persistence) is strongly suggested in order to better understand how Redis persistence works. -Installing Redis more properly -============================== +## Install Redis more properly Running Redis from the command line is fine just to hack a bit or for development. However, at some point you'll have some actual application to run on a real server. For this kind of usage you have two different choices: @@ -158,5 +154,5 @@ Make sure that everything is working as expected: * Check that your Redis instance is correctly logging in the log file. * If it's a new machine where you can try it without problems make sure that after a reboot everything is still working. -Note: In the above instructions we skipped many Redis configuration parameters that you would like to change, for instance in order to use AOF persistence instead of RDB persistence, or to setup replication, and so forth. -Make sure to read the example [`redis.conf`](https://github.com/redis/redis/blob/6.2/redis.conf) file (that is heavily commented) and the other documentation you can find in this web site for more information. +Note: The above instructions don't include all of the Redis configuration parameters that you could change, for instance, to use AOF persistence instead of RDB persistence, or to set up replication, and so forth. +Make sure to read the example [`redis.conf`](https://github.com/redis/redis/blob/6.2/redis.conf) file (that is heavily commented). diff --git a/docs/reference/modules/modules-api-ref.md b/docs/reference/modules/modules-api-ref.md index 00ae846fde..10cc445b99 100644 --- a/docs/reference/modules/modules-api-ref.md +++ b/docs/reference/modules/modules-api-ref.md @@ -4235,7 +4235,7 @@ latency-monitor-threshold. ## Blocking clients from modules For a guide about blocking commands in modules, see -[https://redis.io/topics/modules-blocking-ops](https://redis.io/topics/modules-blocking-ops). +[Redis modules and blocking commands](https://redis.io/topics/modules-blocking-ops). @@ -4249,25 +4249,20 @@ For a guide about blocking commands in modules, see **Available since:** 4.0.0 -Block a client in the context of a blocking command, returning a handle -which will be used, later, in order to unblock the client with a call to +Block a client in the context of a blocking command, returning a handle that will be used later to unblock the client with a call to [`RedisModule_UnblockClient()`](#RedisModule_UnblockClient). The arguments specify callback functions and a timeout after which the client is unblocked. The callbacks are called in the following contexts: - reply_callback: called after a successful RedisModule_UnblockClient() - call in order to reply to the client and unblock it. +* `reply_callback`: called after a successful `RedisModule_UnblockClient()` call to reply to the client and unblock it. - timeout_callback: called when the timeout is reached or if `CLIENT UNBLOCK` - is invoked, in order to send an error to the client. +* `timeout_callback`: called to send an error to the client when the timeout is reached or if `CLIENT UNBLOCK` is invoked. - free_privdata: called in order to free the private data that is passed - by RedisModule_UnblockClient() call. +* `free_privdata`: called to free the private data that is passed by `RedisModule_UnblockClient()` call. -Note: [`RedisModule_UnblockClient`](#RedisModule_UnblockClient) should be called for every blocked client, - even if client was killed, timed-out or disconnected. Failing to do so - will result in memory leaks. +Note: [`RedisModule_UnblockClient`](#RedisModule_UnblockClient) should be called for every blocked client, even if client was killed, timed-out or disconnected. +Failing to do so results in memory leaks. There are some cases where [`RedisModule_BlockClient()`](#RedisModule_BlockClient) cannot be used: @@ -4395,12 +4390,9 @@ to compute reply or some reply obtained via networking. Note 1: this function can be called from threads spawned by the module. -Note 2: when we unblock a client that is blocked for keys using the API -[`RedisModule_BlockClientOnKeys()`](#RedisModule_BlockClientOnKeys), the privdata argument here is not used. -Unblocking a client that was blocked for keys using this API will still -require the client to get some reply, so the function will use the -"timeout" handler in order to do so (The privdata provided in -[`RedisModule_BlockClientOnKeys()`](#RedisModule_BlockClientOnKeys) is accessible from the timeout +Note 2: when we unblock a client that is blocked for keys using the API [`RedisModule_BlockClientOnKeys()`](#RedisModule_BlockClientOnKeys), the `privdata` argument here is not used. +Unblocking a client that was blocked for keys using this API will still require the client to get some reply, so the function will use the "timeout" handler in order to do so. +The `privdata` provided in [`RedisModule_BlockClientOnKeys()`](#RedisModule_BlockClientOnKeys) is accessible from the timeout callback via [`RedisModule_GetBlockedClientPrivateData`](#RedisModule_GetBlockedClientPrivateData)). From 70c2262735deffc404f7b875771eee10ab856666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3bert=20Kel=C4=8D=C3=A1k?= Date: Thu, 26 Jan 2023 12:59:40 +0100 Subject: [PATCH 128/377] Create phpCacheAdmin.json (#2299) --- libraries/php/github.com/RobiNN1/phpCacheAdmin.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 libraries/php/github.com/RobiNN1/phpCacheAdmin.json diff --git a/libraries/php/github.com/RobiNN1/phpCacheAdmin.json b/libraries/php/github.com/RobiNN1/phpCacheAdmin.json new file mode 100644 index 0000000000..67ec634b1b --- /dev/null +++ b/libraries/php/github.com/RobiNN1/phpCacheAdmin.json @@ -0,0 +1,4 @@ +{ + "name": "phpCacheAdmin", + "description": "A web dashboard for your favorite caching system." +} From f85ac1207bfc536eb413f1d023ee270c6115f85a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20S=C3=B6derqvist?= Date: Thu, 26 Jan 2023 23:57:03 +0100 Subject: [PATCH 129/377] Add tools category 'Other' with K8s related tools (#2300) Add tools: * IBM/operator-for-redis-cluster * spotahome/redis-operator * oliver006/redis_exporter. Co-authored-by: Bjorn Svensson Co-authored-by: Itamar Haber --- tool_types.json | 3 ++- tools/other/github.com/IBM/operator-for-redis-cluster.json | 5 +++++ tools/other/github.com/oliver006/redis_exporter.json | 4 ++++ tools/other/github.com/spotahome/redis-operator.json | 4 ++++ 4 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 tools/other/github.com/IBM/operator-for-redis-cluster.json create mode 100644 tools/other/github.com/oliver006/redis_exporter.json create mode 100644 tools/other/github.com/spotahome/redis-operator.json diff --git a/tool_types.json b/tool_types.json index 98657bac17..d56d04c4cc 100644 --- a/tool_types.json +++ b/tool_types.json @@ -1,5 +1,6 @@ { "cli": "CLI", "gui": "GUI", - "proxy": "Proxy" + "proxy": "Proxy", + "other": "Other" } diff --git a/tools/other/github.com/IBM/operator-for-redis-cluster.json b/tools/other/github.com/IBM/operator-for-redis-cluster.json new file mode 100644 index 0000000000..dc93eb7c56 --- /dev/null +++ b/tools/other/github.com/IBM/operator-for-redis-cluster.json @@ -0,0 +1,5 @@ +{ + "name": "IBM Operator for Redis Cluster", + "description": "The goal of this project is to simplify the deployment and management of a Redis cluster in a Kubernetes environment. It started internally at Amadeus in 2016, where it was initially designed to run on Openshift. This is the third version of the Redis operator, which leverages the Operator SDK framework for operators.", + "homepage": "https://ibm.github.io/operator-for-redis-cluster" +} diff --git a/tools/other/github.com/oliver006/redis_exporter.json b/tools/other/github.com/oliver006/redis_exporter.json new file mode 100644 index 0000000000..78c3e4b0bc --- /dev/null +++ b/tools/other/github.com/oliver006/redis_exporter.json @@ -0,0 +1,4 @@ +{ + "name": "Prometheus Redis Metrics Exporter", + "description": "Prometheus exporter for Redis metrics." +} diff --git a/tools/other/github.com/spotahome/redis-operator.json b/tools/other/github.com/spotahome/redis-operator.json new file mode 100644 index 0000000000..f488e778f1 --- /dev/null +++ b/tools/other/github.com/spotahome/redis-operator.json @@ -0,0 +1,4 @@ +{ + "name": "Redis Operator", + "description": "Redis Operator creates/configures/manages high availability Redis with Sentinel automatic failover atop Kubernetes." +} From f8d47f79a77a7750a5acc2080872672030b522c5 Mon Sep 17 00:00:00 2001 From: impocode <109408819+impocode@users.noreply.github.com> Date: Sat, 28 Jan 2023 18:50:03 +0500 Subject: [PATCH 130/377] Fix link (#2302) --- docs/about/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/about/_index.md b/docs/about/_index.md index 629974adc3..5a208ec21c 100644 --- a/docs/about/_index.md +++ b/docs/about/_index.md @@ -9,7 +9,7 @@ aliases: --- Redis is an open source (BSD licensed), in-memory __data structure store__ used as a database, cache, message broker, and streaming engine. Redis provides [data structures](/docs/data-types/) such as -[strings](/docs/data-types/strings/), [hashes](/docs/data-types/hashes/), [lists](/docs/data-types/lists/), [sets](/docs/data-types/lists/), [sorted sets](/docs/data-types/sorted-sets/) with range queries, [bitmaps](/docs/data-types/bitmaps/), [hyperloglogs](/docs/data-types/hyperloglogs/), [geospatial indexes](/docs/data-types/geospatial/), and [streams](/docs/data-types/streams/). Redis has built-in [replication](/topics/replication), [Lua scripting](/commands/eval), [LRU eviction](/docs/reference/eviction/), [transactions](/topics/transactions), and different levels of [on-disk persistence](/topics/persistence), and provides high availability via [Redis Sentinel](/topics/sentinel) and automatic partitioning with [Redis Cluster](/topics/cluster-tutorial). +[strings](/docs/data-types/strings/), [hashes](/docs/data-types/hashes/), [lists](/docs/data-types/lists/), [sets](/docs/data-types/sets/), [sorted sets](/docs/data-types/sorted-sets/) with range queries, [bitmaps](/docs/data-types/bitmaps/), [hyperloglogs](/docs/data-types/hyperloglogs/), [geospatial indexes](/docs/data-types/geospatial/), and [streams](/docs/data-types/streams/). Redis has built-in [replication](/topics/replication), [Lua scripting](/commands/eval), [LRU eviction](/docs/reference/eviction/), [transactions](/topics/transactions), and different levels of [on-disk persistence](/topics/persistence), and provides high availability via [Redis Sentinel](/topics/sentinel) and automatic partitioning with [Redis Cluster](/topics/cluster-tutorial). You can run __atomic operations__ on these types, like [appending to a string](/commands/append); From 25ee9ea12b39f5af2152f8a33347d7ee36b294a9 Mon Sep 17 00:00:00 2001 From: Jonathon Belotti Date: Sat, 28 Jan 2023 17:32:23 -0500 Subject: [PATCH 131/377] Update MEMORY USAGE doc to be more specific about SAMPLES (#2305) --- commands/memory-usage.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/memory-usage.md b/commands/memory-usage.md index ae5a4bccc1..4d68dcd6fe 100644 --- a/commands/memory-usage.md +++ b/commands/memory-usage.md @@ -5,8 +5,8 @@ The reported usage is the total of memory allocations for data and administrative overheads that a key its value require. For nested data types, the optional `SAMPLES` option can be provided, where -`count` is the number of sampled nested values. By default, this option is set -to `5`. To sample the all of the nested values, use `SAMPLES 0`. +`count` is the number of sampled nested values. The samples are averaged to estimate the total size. +By default, this option is set to `5`. To sample the all of the nested values, use `SAMPLES 0`. @examples From 5367180588d44fe949a0a898e7d6658975e4076b Mon Sep 17 00:00:00 2001 From: Lavanya <62395240+LAVANYARAMYA@users.noreply.github.com> Date: Mon, 30 Jan 2023 21:46:15 +0530 Subject: [PATCH 132/377] Update cli.md (#2308) --- docs/manual/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/cli.md b/docs/manual/cli.md index 38d35ebb81..b640d2fca9 100644 --- a/docs/manual/cli.md +++ b/docs/manual/cli.md @@ -538,7 +538,7 @@ iteration. Because of the command that it uses this option is called `--scan`. key-446 key-371 -Note that `head -10` is used in order to print only the first lines of the +Note that `head -10` is used in order to print only the first ten lines of the output. Scanning is able to use the underlying pattern matching capability of From e227831de37fa203b461494621f9686ca26240e7 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Tue, 31 Jan 2023 20:43:49 +0200 Subject: [PATCH 133/377] Moves cli to ui (#2301) * Moves cli to ui Co-authored-by: Nermina Miller <102551568+nermiller@users.noreply.github.com> --- docs/about/_index.md | 2 +- docs/data-types/_index.md | 2 +- docs/getting-started/_index.md | 2 +- docs/management/_index.md | 2 +- docs/manual/_index.md | 2 +- docs/reference/_index.md | 2 +- docs/ui/_index.md | 9 +++++++++ docs/{manual => ui}/cli.md | 3 +-- 8 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 docs/ui/_index.md rename docs/{manual => ui}/cli.md (98%) diff --git a/docs/about/_index.md b/docs/about/_index.md index 5a208ec21c..ce2fb7769a 100644 --- a/docs/about/_index.md +++ b/docs/about/_index.md @@ -1,7 +1,7 @@ --- title: Introduction to Redis linkTitle: "About" -weight: 1 +weight: 10 description: Learn about the Redis open source project aliases: - /topics/introduction diff --git a/docs/data-types/_index.md b/docs/data-types/_index.md index 784a7eb9e4..8deccd2271 100644 --- a/docs/data-types/_index.md +++ b/docs/data-types/_index.md @@ -2,7 +2,7 @@ title: "Redis data types" linkTitle: "Data types" description: Overview of data types supported by Redis -weight: 2 +weight: 40 aliases: - /docs/manual/data-types - /topics/data-types diff --git a/docs/getting-started/_index.md b/docs/getting-started/_index.md index e6af889adf..b5366bfc36 100644 --- a/docs/getting-started/_index.md +++ b/docs/getting-started/_index.md @@ -1,7 +1,7 @@ --- title: "Getting started with Redis" linkTitle: "Getting started" -weight: 1 +weight: 20 description: > How to get up and running with Redis aliases: diff --git a/docs/management/_index.md b/docs/management/_index.md index da6175de7d..df79a1b191 100644 --- a/docs/management/_index.md +++ b/docs/management/_index.md @@ -2,5 +2,5 @@ title: "Managing Redis" linkTitle: "Managing Redis" description: An administrator's guide to Redis -weight: 6 +weight: 60 --- diff --git a/docs/manual/_index.md b/docs/manual/_index.md index ec7112aa66..0b0eccb8e7 100644 --- a/docs/manual/_index.md +++ b/docs/manual/_index.md @@ -2,5 +2,5 @@ title: "Using Redis" linkTitle: "Using Redis" description: A developer's guide to Redis -weight: 5 +weight: 50 --- diff --git a/docs/reference/_index.md b/docs/reference/_index.md index fb85a77771..f4c0481b16 100644 --- a/docs/reference/_index.md +++ b/docs/reference/_index.md @@ -2,5 +2,5 @@ title: "Redis reference" linkTitle: "Reference" description: Specifications and protocols -weight: 7 +weight: 70 --- diff --git a/docs/ui/_index.md b/docs/ui/_index.md new file mode 100644 index 0000000000..a7e27b13f5 --- /dev/null +++ b/docs/ui/_index.md @@ -0,0 +1,9 @@ +--- +title: User interfaces +linkTitle: User interfaces +description: Learn how to use Redis interfaces +weight: 30 +--- +The Redis command line interface (redis-cli) is a terminal program used to send commands to and read replies from the Redis server. It has two main modes: an interactive Read Eval Print Loop (REPL) mode where the user types Redis commands and receives replies, and a command mode where redis-cli is executed with additional arguments and the reply is printed to the standard output. + +RedisInsight combines a graphical user interface with Redis CLI to let you work with any Redis deployment. You can visually browse and interact with data, take advantage of diagnostic tools, learn by example, and much more. Best of all, RedisInsight is free. diff --git a/docs/manual/cli.md b/docs/ui/cli.md similarity index 98% rename from docs/manual/cli.md rename to docs/ui/cli.md index b640d2fca9..936c0ec2e5 100644 --- a/docs/manual/cli.md +++ b/docs/ui/cli.md @@ -6,10 +6,9 @@ description: > Overview of redis-cli, the Redis command line interface aliases: - /docs/manual/cli + - /docs/management/cli --- -The Redis command line interface (`redis-cli`) is a terminal program used to send commands to and read replies from the Redis server. It has two main modes: an interactive Read Eval Print Loop (REPL) mode where the user types Redis commands and receives replies, and a command mode where `redis-cli` is executed with additional arguments and the reply is printed to the standard output. - In interactive mode, `redis-cli` has basic line editing capabilities to provide a familiar typing experience. To launch the program in special modes, you can use several options, including: From c8271cb390f39b67a749c68ac51d693e1f78aab8 Mon Sep 17 00:00:00 2001 From: Jervis Date: Wed, 1 Feb 2023 22:53:22 +0800 Subject: [PATCH 134/377] Update benchmarks.md (#2311) * Update benchmarks.md * Refactor benchmarking + images Co-authored-by: Itamar Haber --- .../optimization/benchmarks}/Connections_chart.png | Bin .../optimization/benchmarks}/Data_size.png | Bin .../optimization/benchmarks}/NUMA_chart.gif | Bin .../{benchmarks.md => benchmarks/index.md} | 6 +++--- 4 files changed, 3 insertions(+), 3 deletions(-) rename docs/{images => management/optimization/benchmarks}/Connections_chart.png (100%) rename docs/{images => management/optimization/benchmarks}/Data_size.png (100%) rename docs/{images => management/optimization/benchmarks}/NUMA_chart.gif (100%) rename docs/management/optimization/{benchmarks.md => benchmarks/index.md} (98%) diff --git a/docs/images/Connections_chart.png b/docs/management/optimization/benchmarks/Connections_chart.png similarity index 100% rename from docs/images/Connections_chart.png rename to docs/management/optimization/benchmarks/Connections_chart.png diff --git a/docs/images/Data_size.png b/docs/management/optimization/benchmarks/Data_size.png similarity index 100% rename from docs/images/Data_size.png rename to docs/management/optimization/benchmarks/Data_size.png diff --git a/docs/images/NUMA_chart.gif b/docs/management/optimization/benchmarks/NUMA_chart.gif similarity index 100% rename from docs/images/NUMA_chart.gif rename to docs/management/optimization/benchmarks/NUMA_chart.gif diff --git a/docs/management/optimization/benchmarks.md b/docs/management/optimization/benchmarks/index.md similarity index 98% rename from docs/management/optimization/benchmarks.md rename to docs/management/optimization/benchmarks/index.md index d15254a3f0..cca6d8ac52 100644 --- a/docs/management/optimization/benchmarks.md +++ b/docs/management/optimization/benchmarks/index.md @@ -215,7 +215,7 @@ the ethernet packet size (about 1500 bytes). Actually, processing 10 bytes, 100 bytes, or 1000 bytes queries almost result in the same throughput. See the graph below. -![Data size impact](https://github.com/dspezia/redis-doc/raw/client_command/topics/Data_size.png) + ![Data size impact](Data_size.png) + On multi CPU sockets servers, Redis performance becomes dependent on the NUMA configuration and process location. The most visible effect is that @@ -229,7 +229,7 @@ Intel Nehalem EX, and Intel Westmere) with different relative placements. Please note this benchmark is not meant to compare CPU models between themselves (CPUs exact model and frequency are therefore not disclosed). -![NUMA chart](https://github.com/dspezia/redis-doc/raw/6374a07f93e867353e5e946c1e39a573dfc83f6c/topics/NUMA_chart.gif) + ![NUMA chart](NUMA_chart.gif) + With high-end configurations, the number of client connections is also an important factor. Being based on epoll/kqueue, the Redis event loop is quite @@ -239,7 +239,7 @@ an instance with 30000 connections can only process half the throughput achievable with 100 connections. Here is an example showing the throughput of a Redis instance per number of connections: -![connections chart](https://github.com/dspezia/redis-doc/raw/system_info/topics/Connections_chart.png) + ![connections chart](Connections_chart.png) + With high-end configurations, it is possible to achieve higher throughput by tuning the NIC(s) configuration and associated interruptions. Best throughput From 647e6e7198172c1b0ebd6bc0af9d607251b6ae9d Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Wed, 1 Feb 2023 17:04:37 +0200 Subject: [PATCH 135/377] Refactors pages images (#2312) --- docs/{images => manual/patterns/indexes}/2idx_0.png | Bin docs/{images => manual/patterns/indexes}/2idx_1.png | Bin docs/{images => manual/patterns/indexes}/2idx_2.png | Bin .../patterns/{indexes.md => indexes/index.md} | 6 +++--- docs/manual/{pipelining.md => pipelining/index.md} | 2 +- .../{images => manual/pipelining}/pipeline_iops.png | Bin docs/reference/{eviction.md => eviction/index.md} | 2 +- .../eviction}/lru_comparison.png | Bin 8 files changed, 5 insertions(+), 5 deletions(-) rename docs/{images => manual/patterns/indexes}/2idx_0.png (100%) rename docs/{images => manual/patterns/indexes}/2idx_1.png (100%) rename docs/{images => manual/patterns/indexes}/2idx_2.png (100%) rename docs/manual/patterns/{indexes.md => indexes/index.md} (99%) rename docs/manual/{pipelining.md => pipelining/index.md} (99%) rename docs/{images => manual/pipelining}/pipeline_iops.png (100%) rename docs/reference/{eviction.md => eviction/index.md} (99%) rename docs/{images => reference/eviction}/lru_comparison.png (100%) diff --git a/docs/images/2idx_0.png b/docs/manual/patterns/indexes/2idx_0.png similarity index 100% rename from docs/images/2idx_0.png rename to docs/manual/patterns/indexes/2idx_0.png diff --git a/docs/images/2idx_1.png b/docs/manual/patterns/indexes/2idx_1.png similarity index 100% rename from docs/images/2idx_1.png rename to docs/manual/patterns/indexes/2idx_1.png diff --git a/docs/images/2idx_2.png b/docs/manual/patterns/indexes/2idx_2.png similarity index 100% rename from docs/images/2idx_2.png rename to docs/manual/patterns/indexes/2idx_2.png diff --git a/docs/manual/patterns/indexes.md b/docs/manual/patterns/indexes/index.md similarity index 99% rename from docs/manual/patterns/indexes.md rename to docs/manual/patterns/indexes/index.md index 8164864fd9..c7aa7ee1b2 100644 --- a/docs/manual/patterns/indexes.md +++ b/docs/manual/patterns/indexes/index.md @@ -553,7 +553,7 @@ Let's say we have points in the space, which represent our data samples, where ` In the next figure, the blue box represents our query. We want all the points where `x` is between 50 and 100, and where `y` is between 100 and 300. -![Points in the space](../../../images/2idx_0.png) +![Points in the space](2idx_0.png) In order to represent data that makes these kinds of queries fast to perform, we start by padding our numbers with 0. So for example imagine we want to @@ -591,7 +591,7 @@ What this maps to is to a square representing all values where the `x` variable is between 70 and 79, and the `y` variable is between 200 and 209. To identify this specific area, we can write random points in that interval. -![Small area](../../../images/2idx_1.png) +![Small area](2idx_1.png) So the above lexicographic query allows us to easily query for points in a specific square in the picture. However the square may be too small for @@ -606,7 +606,7 @@ This time the range represents all the points where `x` is between 0 and 99 and `y` is between 200 and 299. Drawing random points in this interval shows us this larger area. -![Large area](../../../images/2idx_2.png) +![Large area](2idx_2.png) So now our area is too big for our query, and still our search box is not completely included. We need more granularity, but we can easily obtain diff --git a/docs/manual/pipelining.md b/docs/manual/pipelining/index.md similarity index 99% rename from docs/manual/pipelining.md rename to docs/manual/pipelining/index.md index 605074f434..177681afb8 100644 --- a/docs/manual/pipelining.md +++ b/docs/manual/pipelining/index.md @@ -92,7 +92,7 @@ call. Consequently, the number of total queries performed per second initially increases almost linearly with longer pipelines, and eventually reaches 10 times the baseline obtained without pipelining, as shown in this figure. -![Pipeline size and IOPs](../../images/pipeline_iops.png) +![Pipeline size and IOPs](pipeline_iops.png) ## A real world code example diff --git a/docs/images/pipeline_iops.png b/docs/manual/pipelining/pipeline_iops.png similarity index 100% rename from docs/images/pipeline_iops.png rename to docs/manual/pipelining/pipeline_iops.png diff --git a/docs/reference/eviction.md b/docs/reference/eviction/index.md similarity index 99% rename from docs/reference/eviction.md rename to docs/reference/eviction/index.md index 8fcbda98ae..4874a82bb2 100644 --- a/docs/reference/eviction.md +++ b/docs/reference/eviction/index.md @@ -107,7 +107,7 @@ costs more memory. However, the approximation is virtually equivalent for an application using Redis. This figure compares the LRU approximation used by Redis with true LRU. -![LRU comparison](../../images/lru_comparison.png) +![LRU comparison](lru_comparison.png) The test to generate the above graphs filled a Redis server with a given number of keys. The keys were accessed from the first to the last. The first keys are the best candidates for eviction using an LRU algorithm. Later more 50% of keys are added, in order to force half of the old keys to be evicted. diff --git a/docs/images/lru_comparison.png b/docs/reference/eviction/lru_comparison.png similarity index 100% rename from docs/images/lru_comparison.png rename to docs/reference/eviction/lru_comparison.png From c87a096b89c084bd1e40371adfd29a9e03126cdf Mon Sep 17 00:00:00 2001 From: wuyuansushen <43259764+wuyuansushen@users.noreply.github.com> Date: Thu, 2 Feb 2023 20:37:06 +0800 Subject: [PATCH 136/377] Update placeholders (#2306) All '' has been changed to '' --- docs/management/sentinel.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/management/sentinel.md b/docs/management/sentinel.md index 63cc24c11e..35718e3692 100644 --- a/docs/management/sentinel.md +++ b/docs/management/sentinel.md @@ -117,7 +117,7 @@ One set of instances is called `mymaster`, and the other `resque`. The meaning of the arguments of `sentinel monitor` statements is the following: - sentinel monitor + sentinel monitor For the sake of clarity, let's check line by line what the configuration options mean: @@ -809,8 +809,8 @@ In order for Sentinels to connect to Redis server instances when they are configured with ACL, the Sentinel configuration must include the following directives: - sentinel auth-user - sentinel auth-pass + sentinel auth-user + sentinel auth-pass Where `` and `` are the username and password for accessing the group's instances. These credentials should be provisioned on all of the group's Redis instances with the minimal control permissions. For example: @@ -842,7 +842,7 @@ In order for Sentinels to connect to Redis server instances when they are configured with `requirepass`, the Sentinel configuration must include the `sentinel auth-pass` directive, in the format: - sentinel auth-pass + sentinel auth-pass Configuring Sentinel instances with authentication --- From c54909ff9941b30918c3e4cddbbe9bdf41652de6 Mon Sep 17 00:00:00 2001 From: Roshan Khatri Date: Thu, 2 Feb 2023 11:17:28 -0800 Subject: [PATCH 137/377] Updating the ACL LOG doc. --- commands/acl-log.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/commands/acl-log.md b/commands/acl-log.md index adeaf8d540..e6a23cf488 100644 --- a/commands/acl-log.md +++ b/commands/acl-log.md @@ -35,7 +35,26 @@ When called with `RESET`: 9) "username" 10) "someuser" 11) "age-seconds" - 12) "4.0960000000000001" + 12) "8.038" 13) "client-info" - 14) "id=6 addr=127.0.0.1:63026 fd=8 name= age=9 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=48 qbuf-free=32720 obl=0 oll=0 omem=0 events=r cmd=auth user=default" + 14) "id=3 addr=127.0.0.1:57275 laddr=127.0.0.1:6379 fd=8 name= age=16 idle=0 flags=N db=0 sub=0 psub=0 ssub=0 multi=-1 qbuf=48 qbuf-free=16842 argv-mem=25 multi-mem=0 rbs=1024 rbp=0 obl=0 oll=0 omem=0 tot-mem=18737 events=r cmd=auth user=default redir=-1 resp=2" + 15) "entry-id" + 16) (integer) 0 + 17) "timestamp-created" + 18) (integer) 1675361492408 + 19) "timestamp-last-updated" + 20) (integer) 1675361492408 ``` + +Each LOG is composed of the following fields of the corresponding acl log and their values: + +1. `count`: The number of security events detected within a 60 second periods that are represented by this entry. +2. `reason`: The reason for which the ACL security events were logged. Either `command`, `key`, `channel`, or `auth`. +3. `context`: The context that the security events were detected in. Either `toplevel`, `multi`, `lua`, or `module`. +4. `object`: The resource that the user had insufficient permissions to access. `auth` when the reason is `auth`. +5. `username`: The username that executed the command that caused the security events or the username that had a failed authentication attempt. +6. `age-seconds`: Age of the log entry in seconds. +7. `client-info`: Displays the client info of a client which caused one of the security events. +8. `entry-id`: The sequence number of the entry (starting at 0) since the server process started. Can also be used to check if items were “lost”, if they fell between periods. +9. `timestamp-created`: This timestamp is the unix-time in `milliseconds` at the time the entry was first created. +10. `timestamp-last-updated`: A unix-time in `milliseconds` at the time the entry was last updated. \ No newline at end of file From afe280c7be1f549c45fc3ce00c5dcc2c96128f47 Mon Sep 17 00:00:00 2001 From: Roshan Khatri Date: Thu, 2 Feb 2023 11:59:29 -0800 Subject: [PATCH 138/377] Suggestions and spellcheck corrections --- commands/acl-log.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/commands/acl-log.md b/commands/acl-log.md index e6a23cf488..0b31cc4fd7 100644 --- a/commands/acl-log.md +++ b/commands/acl-log.md @@ -46,7 +46,7 @@ When called with `RESET`: 20) (integer) 1675361492408 ``` -Each LOG is composed of the following fields of the corresponding acl log and their values: +Each log entry is composed of the following fields: 1. `count`: The number of security events detected within a 60 second periods that are represented by this entry. 2. `reason`: The reason for which the ACL security events were logged. Either `command`, `key`, `channel`, or `auth`. @@ -56,5 +56,5 @@ Each LOG is composed of the following fields of the corresponding acl log and th 6. `age-seconds`: Age of the log entry in seconds. 7. `client-info`: Displays the client info of a client which caused one of the security events. 8. `entry-id`: The sequence number of the entry (starting at 0) since the server process started. Can also be used to check if items were “lost”, if they fell between periods. -9. `timestamp-created`: This timestamp is the unix-time in `milliseconds` at the time the entry was first created. -10. `timestamp-last-updated`: A unix-time in `milliseconds` at the time the entry was last updated. \ No newline at end of file +9. `timestamp-created`: A UNIX timestamp in `milliseconds` at the time the entry was first created. +10. `timestamp-last-updated`: A UNIX timestamp in `milliseconds` at the time the entry was last updated. \ No newline at end of file From 7290695970000600d0733ad1cf905f7111c22a95 Mon Sep 17 00:00:00 2001 From: Madelyn Olson <34459052+madolson@users.noreply.github.com> Date: Thu, 2 Feb 2023 12:06:26 -0800 Subject: [PATCH 139/377] Apply suggestions from code review --- commands/acl-log.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/acl-log.md b/commands/acl-log.md index 0b31cc4fd7..c29ce2877d 100644 --- a/commands/acl-log.md +++ b/commands/acl-log.md @@ -48,8 +48,8 @@ When called with `RESET`: Each log entry is composed of the following fields: -1. `count`: The number of security events detected within a 60 second periods that are represented by this entry. -2. `reason`: The reason for which the ACL security events were logged. Either `command`, `key`, `channel`, or `auth`. +1. `count`: The number of security events detected within a 60 second period that are represented by this entry. +2. `reason`: The reason that the security events were logged. Either `command`, `key`, `channel`, or `auth`. 3. `context`: The context that the security events were detected in. Either `toplevel`, `multi`, `lua`, or `module`. 4. `object`: The resource that the user had insufficient permissions to access. `auth` when the reason is `auth`. 5. `username`: The username that executed the command that caused the security events or the username that had a failed authentication attempt. From 7b57619ca4ae815e89bf789abbe9826cc8581da5 Mon Sep 17 00:00:00 2001 From: Bruno Date: Sat, 4 Feb 2023 10:54:52 -0300 Subject: [PATCH 140/377] docs(replication): typo (#2316) --- docs/management/replication.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/management/replication.md b/docs/management/replication.md index 145fc394b6..801638a563 100644 --- a/docs/management/replication.md +++ b/docs/management/replication.md @@ -273,7 +273,7 @@ replicate keys with expires, even when such keys are altered using Lua scripts. To implement such a feature Redis cannot rely on the ability of the master and -replica to have syncd clocks, since this is a problem that cannot be solved +replica to have synced clocks, since this is a problem that cannot be solved and would result in race conditions and diverging data sets, so Redis uses three main techniques to make the replication of expired keys able to work: From 91519c001990fcbb3fe757823df797b56f5a5368 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Sun, 5 Feb 2023 17:52:30 +0200 Subject: [PATCH 141/377] Moves go-redis (#2318) --- .../go/github.com/{go-redis/redis.json => redis/go-redis.json} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename clients/go/github.com/{go-redis/redis.json => redis/go-redis.json} (81%) diff --git a/clients/go/github.com/go-redis/redis.json b/clients/go/github.com/redis/go-redis.json similarity index 81% rename from clients/go/github.com/go-redis/redis.json rename to clients/go/github.com/redis/go-redis.json index c91aa86578..ad7e3e6f1a 100644 --- a/clients/go/github.com/go-redis/redis.json +++ b/clients/go/github.com/redis/go-redis.json @@ -1,5 +1,5 @@ { - "name": "go-redis/redis", + "name": "go-redis", "description": "Redis client for Golang supporting Redis Sentinel and Redis Cluster out of the box.", "recommended": true } \ No newline at end of file From 5f2d4304f01a09ca928a6e9ef91ba3fa88fdd867 Mon Sep 17 00:00:00 2001 From: Binbin Date: Sun, 12 Feb 2023 18:51:21 +0800 Subject: [PATCH 142/377] Use `` to generate the hyperlinks for commands (#2320) --- docs/management/optimization/memory-optimization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/management/optimization/memory-optimization.md b/docs/management/optimization/memory-optimization.md index bfee9912ae..97e503381f 100644 --- a/docs/management/optimization/memory-optimization.md +++ b/docs/management/optimization/memory-optimization.md @@ -80,7 +80,7 @@ with a constant time complexity in the average case, like a hash table. But many times hashes contain just a few fields. When hashes are small we can instead just encode them in an O(N) data structure, like a linear array with length-prefixed key value pairs. Since we do this only when N -is small, the amortized time for HGET and HSET commands is still O(1): the +is small, the amortized time for `HGET` and `HSET` commands is still O(1): the hash will be converted into a real hash table as soon as the number of elements it contains grows too large (you can configure the limit in redis.conf). From 5d02590854bea15e7d953c4e33de68237d763740 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Sun, 12 Feb 2023 21:53:06 +0200 Subject: [PATCH 143/377] Generate commands.json from redis#7dae142a2 (#2321) --- commands.json | 1869 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 1447 insertions(+), 422 deletions(-) diff --git a/commands.json b/commands.json index 7f73e43599..e5cdb2939c 100644 --- a/commands.json +++ b/commands.json @@ -22,6 +22,7 @@ { "name": "categoryname", "type": "string", + "display_text": "categoryname", "optional": true } ], @@ -46,6 +47,7 @@ { "name": "username", "type": "string", + "display_text": "username", "multiple": true } ], @@ -70,15 +72,18 @@ "arguments": [ { "name": "username", - "type": "string" + "type": "string", + "display_text": "username" }, { "name": "command", - "type": "string" + "type": "string", + "display_text": "command" }, { "name": "arg", "type": "string", + "display_text": "arg", "optional": true, "multiple": true } @@ -103,6 +108,7 @@ { "name": "bits", "type": "integer", + "display_text": "bits", "optional": true } ], @@ -136,7 +142,8 @@ "arguments": [ { "name": "username", - "type": "string" + "type": "string", + "display_text": "username" } ], "command_flags": [ @@ -201,6 +208,12 @@ "since": "6.0.0", "group": "server", "complexity": "O(N) with N being the number of entries shown.", + "history": [ + [ + "7.2.0", + "Added entry ID, timestamp created, and timestamp last updated." + ] + ], "acl_categories": [ "@admin", "@slow", @@ -215,11 +228,13 @@ "arguments": [ { "name": "count", - "type": "integer" + "type": "integer", + "display_text": "count" }, { "name": "reset", "type": "pure-token", + "display_text": "reset", "token": "RESET" } ] @@ -274,11 +289,13 @@ "arguments": [ { "name": "username", - "type": "string" + "type": "string", + "display_text": "username" }, { "name": "rule", "type": "string", + "display_text": "rule", "optional": true, "multiple": true } @@ -358,11 +375,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "value", - "type": "string" + "type": "string", + "display_text": "value" } ], "command_flags": [ @@ -405,12 +424,14 @@ { "name": "username", "type": "string", + "display_text": "username", "since": "6.0.0", "optional": true }, { "name": "password", - "type": "string" + "type": "string", + "display_text": "password" } ], "command_flags": [ @@ -460,6 +481,7 @@ { "name": "schedule", "type": "pure-token", + "display_text": "schedule", "token": "SCHEDULE", "since": "3.2.2", "optional": true @@ -512,23 +534,26 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { - "name": "index", + "name": "range", "type": "block", "optional": true, "arguments": [ { "name": "start", - "type": "integer" + "type": "integer", + "display_text": "start" }, { "name": "end", - "type": "integer" + "type": "integer", + "display_text": "end" }, { - "name": "index_unit", + "name": "unit", "type": "oneof", "since": "7.0.0", "optional": true, @@ -536,11 +561,13 @@ { "name": "byte", "type": "pure-token", + "display_text": "byte", "token": "BYTE" }, { "name": "bit", "type": "pure-token", + "display_text": "bit", "token": "BIT" } ] @@ -590,25 +617,29 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "operation", "type": "oneof", + "optional": true, "multiple": true, "arguments": [ { - "name": "encoding_offset", + "name": "get-block", "type": "block", "token": "GET", "arguments": [ { "name": "encoding", - "type": "string" + "type": "string", + "display_text": "encoding" }, { "name": "offset", - "type": "integer" + "type": "integer", + "display_text": "offset" } ] }, @@ -617,7 +648,7 @@ "type": "block", "arguments": [ { - "name": "wrap_sat_fail", + "name": "overflow-block", "type": "oneof", "token": "OVERFLOW", "optional": true, @@ -625,59 +656,68 @@ { "name": "wrap", "type": "pure-token", + "display_text": "wrap", "token": "WRAP" }, { "name": "sat", "type": "pure-token", + "display_text": "sat", "token": "SAT" }, { "name": "fail", "type": "pure-token", + "display_text": "fail", "token": "FAIL" } ] }, { - "name": "write_operation", + "name": "write-operation", "type": "oneof", "arguments": [ { - "name": "encoding_offset_value", + "name": "set-block", "type": "block", "token": "SET", "arguments": [ { "name": "encoding", - "type": "string" + "type": "string", + "display_text": "encoding" }, { "name": "offset", - "type": "integer" + "type": "integer", + "display_text": "offset" }, { "name": "value", - "type": "integer" + "type": "integer", + "display_text": "value" } ] }, { - "name": "encoding_offset_increment", + "name": "incrby-block", "type": "block", "token": "INCRBY", "arguments": [ { "name": "encoding", - "type": "string" + "type": "string", + "display_text": "encoding" }, { "name": "offset", - "type": "integer" + "type": "integer", + "display_text": "offset" }, { "name": "increment", - "type": "integer" + "type": "integer", + "display_text": "increment" } ] } @@ -728,22 +768,26 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { - "name": "encoding_offset", + "name": "get-block", "type": "block", "token": "GET", + "optional": true, "multiple": true, "multiple_token": true, "arguments": [ { "name": "encoding", - "type": "string" + "type": "string", + "display_text": "encoding" }, { "name": "offset", - "type": "integer" + "type": "integer", + "display_text": "offset" } ] } @@ -805,16 +849,44 @@ "arguments": [ { "name": "operation", - "type": "string" + "type": "oneof", + "arguments": [ + { + "name": "and", + "type": "pure-token", + "display_text": "and", + "token": "AND" + }, + { + "name": "or", + "type": "pure-token", + "display_text": "or", + "token": "OR" + }, + { + "name": "xor", + "type": "pure-token", + "display_text": "xor", + "token": "XOR" + }, + { + "name": "not", + "type": "pure-token", + "display_text": "not", + "token": "NOT" + } + ] }, { "name": "destkey", "type": "key", + "display_text": "destkey", "key_spec_index": 0 }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 1, "multiple": true } @@ -865,32 +937,36 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "bit", - "type": "integer" + "type": "integer", + "display_text": "bit" }, { - "name": "index", + "name": "range", "type": "block", "optional": true, "arguments": [ { "name": "start", - "type": "integer" + "type": "integer", + "display_text": "start" }, { - "name": "end_index", + "name": "end-unit-block", "type": "block", "optional": true, "arguments": [ { "name": "end", - "type": "integer" + "type": "integer", + "display_text": "end" }, { - "name": "index_unit", + "name": "unit", "type": "oneof", "since": "7.0.0", "optional": true, @@ -898,11 +974,13 @@ { "name": "byte", "type": "pure-token", + "display_text": "byte", "token": "BYTE" }, { "name": "bit", "type": "pure-token", + "display_text": "bit", "token": "BIT" } ] @@ -971,11 +1049,13 @@ { "name": "source", "type": "key", + "display_text": "source", "key_spec_index": 0 }, { "name": "destination", "type": "key", + "display_text": "destination", "key_spec_index": 1 }, { @@ -985,11 +1065,13 @@ { "name": "left", "type": "pure-token", + "display_text": "left", "token": "LEFT" }, { "name": "right", "type": "pure-token", + "display_text": "right", "token": "RIGHT" } ] @@ -1001,18 +1083,21 @@ { "name": "left", "type": "pure-token", + "display_text": "left", "token": "LEFT" }, { "name": "right", "type": "pure-token", + "display_text": "right", "token": "RIGHT" } ] }, { "name": "timeout", - "type": "double" + "type": "double", + "display_text": "timeout" } ], "command_flags": [ @@ -1058,15 +1143,18 @@ "arguments": [ { "name": "timeout", - "type": "double" + "type": "double", + "display_text": "timeout" }, { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true }, @@ -1077,11 +1165,13 @@ { "name": "left", "type": "pure-token", + "display_text": "left", "token": "LEFT" }, { "name": "right", "type": "pure-token", + "display_text": "right", "token": "RIGHT" } ] @@ -1089,6 +1179,7 @@ { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT", "optional": true } @@ -1142,12 +1233,14 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true }, { "name": "timeout", - "type": "double" + "type": "double", + "display_text": "timeout" } ], "command_flags": [ @@ -1199,12 +1292,14 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true }, { "name": "timeout", - "type": "double" + "type": "double", + "display_text": "timeout" } ], "command_flags": [ @@ -1276,16 +1371,19 @@ { "name": "source", "type": "key", + "display_text": "source", "key_spec_index": 0 }, { "name": "destination", "type": "key", + "display_text": "destination", "key_spec_index": 1 }, { "name": "timeout", - "type": "double" + "type": "double", + "display_text": "timeout" } ], "command_flags": [ @@ -1334,15 +1432,18 @@ "arguments": [ { "name": "timeout", - "type": "double" + "type": "double", + "display_text": "timeout" }, { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true }, @@ -1353,11 +1454,13 @@ { "name": "min", "type": "pure-token", + "display_text": "min", "token": "MIN" }, { "name": "max", "type": "pure-token", + "display_text": "max", "token": "MAX" } ] @@ -1365,6 +1468,7 @@ { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT", "optional": true } @@ -1418,12 +1522,14 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true }, { "name": "timeout", - "type": "double" + "type": "double", + "display_text": "timeout" } ], "command_flags": [ @@ -1476,12 +1582,14 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true }, { "name": "timeout", - "type": "double" + "type": "double", + "display_text": "timeout" } ], "command_flags": [ @@ -1519,11 +1627,13 @@ { "name": "yes", "type": "pure-token", + "display_text": "yes", "token": "YES" }, { "name": "no", "type": "pure-token", + "display_text": "no", "token": "NO" } ] @@ -1657,8 +1767,9 @@ "type": "oneof", "arguments": [ { - "name": "ip:port", + "name": "old-format", "type": "string", + "display_text": "ip:port", "deprecated_since": "2.8.12" }, { @@ -1669,12 +1780,13 @@ { "name": "client-id", "type": "integer", + "display_text": "client-id", "token": "ID", "since": "2.8.12", "optional": true }, { - "name": "normal_master_slave_pubsub", + "name": "client-type", "type": "oneof", "token": "TYPE", "since": "2.8.12", @@ -1683,28 +1795,33 @@ { "name": "normal", "type": "pure-token", + "display_text": "normal", "token": "NORMAL" }, { "name": "master", "type": "pure-token", + "display_text": "master", "token": "MASTER", "since": "3.2.0" }, { "name": "slave", "type": "pure-token", + "display_text": "slave", "token": "SLAVE" }, { "name": "replica", "type": "pure-token", + "display_text": "replica", "token": "REPLICA", "since": "5.0.0" }, { "name": "pubsub", "type": "pure-token", + "display_text": "pubsub", "token": "PUBSUB" } ] @@ -1712,27 +1829,44 @@ { "name": "username", "type": "string", + "display_text": "username", "token": "USER", "optional": true }, { - "name": "ip:port", + "name": "addr", "type": "string", + "display_text": "ip:port", "token": "ADDR", "optional": true }, { - "name": "ip:port", + "name": "laddr", "type": "string", + "display_text": "ip:port", "token": "LADDR", "since": "6.2.0", "optional": true }, { - "name": "yes/no", - "type": "string", + "name": "skipme", + "type": "oneof", "token": "SKIPME", - "optional": true + "optional": true, + "arguments": [ + { + "name": "yes", + "type": "pure-token", + "display_text": "yes", + "token": "YES" + }, + { + "name": "no", + "type": "pure-token", + "display_text": "no", + "token": "NO" + } + ] } ] } @@ -1760,9 +1894,21 @@ "5.0.0", "Added optional `TYPE` filter." ], + [ + "6.0.0", + "Added `user` field." + ], [ "6.2.0", - "Added `laddr` field and the optional `ID` filter." + "Added `argv-mem`, `tot-mem`, `laddr` and `redir` fields and the optional `ID` filter." + ], + [ + "7.0.0", + "Added `resp`, `multi-mem`, `rbs` and `rbp` fields." + ], + [ + "7.0.3", + "Added `ssub` field." ] ], "acl_categories": [ @@ -1774,7 +1920,7 @@ "arity": -2, "arguments": [ { - "name": "normal_master_replica_pubsub", + "name": "client-type", "type": "oneof", "token": "TYPE", "since": "5.0.0", @@ -1783,38 +1929,37 @@ { "name": "normal", "type": "pure-token", + "display_text": "normal", "token": "NORMAL" }, { "name": "master", "type": "pure-token", + "display_text": "master", "token": "MASTER" }, { "name": "replica", "type": "pure-token", + "display_text": "replica", "token": "REPLICA" }, { "name": "pubsub", "type": "pure-token", + "display_text": "pubsub", "token": "PUBSUB" } ] }, { - "name": "id", - "type": "block", + "name": "client-id", + "type": "integer", + "display_text": "client-id", "token": "ID", "since": "6.2.0", "optional": true, - "arguments": [ - { - "name": "client-id", - "type": "integer", - "multiple": true - } - ] + "multiple": true } ], "command_flags": [ @@ -1847,11 +1992,13 @@ { "name": "on", "type": "pure-token", + "display_text": "on", "token": "ON" }, { "name": "off", "type": "pure-token", + "display_text": "off", "token": "OFF" } ] @@ -1866,7 +2013,7 @@ }, "CLIENT PAUSE": { "summary": "Stop processing commands from clients for some time", - "since": "2.9.50", + "since": "3.0.0", "group": "connection", "complexity": "O(1)", "history": [ @@ -1885,7 +2032,8 @@ "arguments": [ { "name": "timeout", - "type": "integer" + "type": "integer", + "display_text": "timeout" }, { "name": "mode", @@ -1896,11 +2044,13 @@ { "name": "write", "type": "pure-token", + "display_text": "write", "token": "WRITE" }, { "name": "all", "type": "pure-token", + "display_text": "all", "token": "ALL" } ] @@ -1925,22 +2075,25 @@ "arity": 3, "arguments": [ { - "name": "on_off_skip", + "name": "action", "type": "oneof", "arguments": [ { "name": "on", "type": "pure-token", + "display_text": "on", "token": "ON" }, { "name": "off", "type": "pure-token", + "display_text": "off", "token": "OFF" }, { "name": "skip", "type": "pure-token", + "display_text": "skip", "token": "SKIP" } ] @@ -1965,7 +2118,8 @@ "arguments": [ { "name": "connection-name", - "type": "string" + "type": "string", + "display_text": "connection-name" } ], "command_flags": [ @@ -1992,11 +2146,13 @@ { "name": "on", "type": "pure-token", + "display_text": "on", "token": "ON" }, { "name": "off", "type": "pure-token", + "display_text": "off", "token": "OFF" } ] @@ -2004,12 +2160,14 @@ { "name": "client-id", "type": "integer", + "display_text": "client-id", "token": "REDIRECT", "optional": true }, { "name": "prefix", "type": "string", + "display_text": "prefix", "token": "PREFIX", "optional": true, "multiple": true, @@ -2018,24 +2176,28 @@ { "name": "bcast", "type": "pure-token", + "display_text": "bcast", "token": "BCAST", "optional": true }, { "name": "optin", "type": "pure-token", + "display_text": "optin", "token": "OPTIN", "optional": true }, { "name": "optout", "type": "pure-token", + "display_text": "optout", "token": "OPTOUT", "optional": true }, { "name": "noloop", "type": "pure-token", + "display_text": "noloop", "token": "NOLOOP", "optional": true } @@ -2077,21 +2239,24 @@ "arguments": [ { "name": "client-id", - "type": "integer" + "type": "integer", + "display_text": "client-id" }, { - "name": "timeout_error", + "name": "unblock-type", "type": "oneof", "optional": true, "arguments": [ { "name": "timeout", "type": "pure-token", + "display_text": "timeout", "token": "TIMEOUT" }, { "name": "error", "type": "pure-token", + "display_text": "error", "token": "ERROR" } ] @@ -2148,6 +2313,7 @@ { "name": "slot", "type": "integer", + "display_text": "slot", "multiple": true } ], @@ -2170,17 +2336,19 @@ "arity": -4, "arguments": [ { - "name": "start-slot_end-slot", + "name": "range", "type": "block", "multiple": true, "arguments": [ { "name": "start-slot", - "type": "integer" + "type": "integer", + "display_text": "start-slot" }, { "name": "end-slot", - "type": "integer" + "type": "integer", + "display_text": "end-slot" } ] } @@ -2225,7 +2393,8 @@ "arguments": [ { "name": "node-id", - "type": "string" + "type": "string", + "display_text": "node-id" } ], "command_flags": [ @@ -2248,7 +2417,8 @@ "arguments": [ { "name": "slot", - "type": "integer" + "type": "integer", + "display_text": "slot" } ], "command_flags": [ @@ -2270,6 +2440,7 @@ { "name": "slot", "type": "integer", + "display_text": "slot", "multiple": true } ], @@ -2292,17 +2463,19 @@ "arity": -4, "arguments": [ { - "name": "start-slot_end-slot", + "name": "range", "type": "block", "multiple": true, "arguments": [ { "name": "start-slot", - "type": "integer" + "type": "integer", + "display_text": "start-slot" }, { "name": "end-slot", - "type": "integer" + "type": "integer", + "display_text": "end-slot" } ] } @@ -2333,11 +2506,13 @@ { "name": "force", "type": "pure-token", + "display_text": "force", "token": "FORCE" }, { "name": "takeover", "type": "pure-token", + "display_text": "takeover", "token": "TAKEOVER" } ] @@ -2380,7 +2555,8 @@ "arguments": [ { "name": "node-id", - "type": "string" + "type": "string", + "display_text": "node-id" } ], "command_flags": [ @@ -2393,7 +2569,7 @@ "summary": "Return local key names in the specified hash slot", "since": "3.0.0", "group": "cluster", - "complexity": "O(log(N)) where N is the number of requested keys", + "complexity": "O(N) where N is the number of requested keys", "acl_categories": [ "@slow" ], @@ -2401,11 +2577,13 @@ "arguments": [ { "name": "slot", - "type": "integer" + "type": "integer", + "display_text": "slot" }, { "name": "count", - "type": "integer" + "type": "integer", + "display_text": "count" } ], "command_flags": [ @@ -2457,7 +2635,8 @@ "arguments": [ { "name": "key", - "type": "string" + "type": "string", + "display_text": "key" } ], "command_flags": [ @@ -2500,15 +2679,18 @@ "arguments": [ { "name": "ip", - "type": "string" + "type": "string", + "display_text": "ip" }, { "name": "port", - "type": "integer" + "type": "integer", + "display_text": "port" }, { - "name": "cluster_bus_port", + "name": "cluster-bus-port", "type": "integer", + "display_text": "cluster-bus-port", "since": "4.0.0", "optional": true } @@ -2532,6 +2714,22 @@ "stale" ] }, + "CLUSTER MYSHARDID": { + "summary": "Return the node shard id", + "since": "7.2.0", + "group": "cluster", + "complexity": "O(1)", + "acl_categories": [ + "@slow" + ], + "arity": 2, + "command_flags": [ + "stale" + ], + "hints": [ + "nondeterministic_output" + ] + }, "CLUSTER NODES": { "summary": "Get Cluster config for the node", "since": "3.0.0", @@ -2562,7 +2760,8 @@ "arguments": [ { "name": "node-id", - "type": "string" + "type": "string", + "display_text": "node-id" } ], "command_flags": [ @@ -2587,7 +2786,8 @@ "arguments": [ { "name": "node-id", - "type": "string" + "type": "string", + "display_text": "node-id" } ], "command_flags": [ @@ -2609,18 +2809,20 @@ "arity": -2, "arguments": [ { - "name": "hard_soft", + "name": "reset-type", "type": "oneof", "optional": true, "arguments": [ { "name": "hard", "type": "pure-token", + "display_text": "hard", "token": "HARD" }, { "name": "soft", "type": "pure-token", + "display_text": "soft", "token": "SOFT" } ] @@ -2663,7 +2865,8 @@ "arguments": [ { "name": "config-epoch", - "type": "integer" + "type": "integer", + "display_text": "config-epoch" } ], "command_flags": [ @@ -2686,30 +2889,35 @@ "arguments": [ { "name": "slot", - "type": "integer" + "type": "integer", + "display_text": "slot" }, { "name": "subcommand", "type": "oneof", "arguments": [ { - "name": "node-id", + "name": "importing", "type": "string", + "display_text": "node-id", "token": "IMPORTING" }, { - "name": "node-id", + "name": "migrating", "type": "string", + "display_text": "node-id", "token": "MIGRATING" }, { - "name": "node-id", + "name": "node", "type": "string", + "display_text": "node-id", "token": "NODE" }, { "name": "stable", "type": "pure-token", + "display_text": "stable", "token": "STABLE" } ] @@ -2753,7 +2961,8 @@ "arguments": [ { "name": "node-id", - "type": "string" + "type": "string", + "display_text": "node-id" } ], "command_flags": [ @@ -2845,6 +3054,7 @@ { "name": "command-name", "type": "string", + "display_text": "command-name", "optional": true, "multiple": true } @@ -2866,7 +3076,21 @@ "@slow", "@connection" ], - "arity": -4, + "arity": -3, + "arguments": [ + { + "name": "command", + "type": "string", + "display_text": "command" + }, + { + "name": "arg", + "type": "string", + "display_text": "arg", + "optional": true, + "multiple": true + } + ], "command_flags": [ "loading", "stale" @@ -2881,7 +3105,21 @@ "@slow", "@connection" ], - "arity": -4, + "arity": -3, + "arguments": [ + { + "name": "command", + "type": "string", + "display_text": "command" + }, + { + "name": "arg", + "type": "string", + "display_text": "arg", + "optional": true, + "multiple": true + } + ], "command_flags": [ "loading", "stale" @@ -2922,6 +3160,7 @@ { "name": "command-name", "type": "string", + "display_text": "command-name", "optional": true, "multiple": true } @@ -2954,16 +3193,19 @@ { "name": "module-name", "type": "string", + "display_text": "module-name", "token": "MODULE" }, { "name": "category", "type": "string", + "display_text": "category", "token": "ACLCAT" }, { "name": "pattern", "type": "pattern", + "display_text": "pattern", "token": "PATTERN" } ] @@ -3007,14 +3249,9 @@ "arguments": [ { "name": "parameter", - "type": "block", - "multiple": true, - "arguments": [ - { - "name": "parameter", - "type": "string" - } - ] + "type": "string", + "display_text": "parameter", + "multiple": true } ], "command_flags": [ @@ -3093,17 +3330,19 @@ "arity": -4, "arguments": [ { - "name": "parameter_value", + "name": "data", "type": "block", "multiple": true, "arguments": [ { "name": "parameter", - "type": "string" + "type": "string", + "display_text": "parameter" }, { "name": "value", - "type": "string" + "type": "string", + "display_text": "value" } ] } @@ -3172,22 +3411,26 @@ { "name": "source", "type": "key", + "display_text": "source", "key_spec_index": 0 }, { "name": "destination", "type": "key", + "display_text": "destination", "key_spec_index": 1 }, { "name": "destination-db", "type": "integer", + "display_text": "destination-db", "token": "DB", "optional": true }, { "name": "replace", "type": "pure-token", + "display_text": "replace", "token": "REPLACE", "optional": true } @@ -3274,6 +3517,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -3319,11 +3563,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "decrement", - "type": "integer" + "type": "integer", + "display_text": "decrement" } ], "command_flags": [ @@ -3367,6 +3613,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true } @@ -3432,6 +3679,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -3455,7 +3703,8 @@ "arguments": [ { "name": "message", - "type": "string" + "type": "string", + "display_text": "message" } ], "command_flags": [ @@ -3499,15 +3748,18 @@ "arguments": [ { "name": "script", - "type": "string" + "type": "string", + "display_text": "script" }, { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "optional": true, "multiple": true @@ -3515,6 +3767,7 @@ { "name": "arg", "type": "string", + "display_text": "arg", "optional": true, "multiple": true } @@ -3561,15 +3814,18 @@ "arguments": [ { "name": "sha1", - "type": "string" + "type": "string", + "display_text": "sha1" }, { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "optional": true, "multiple": true @@ -3577,6 +3833,7 @@ { "name": "arg", "type": "string", + "display_text": "arg", "optional": true, "multiple": true } @@ -3622,15 +3879,18 @@ "arguments": [ { "name": "sha1", - "type": "string" + "type": "string", + "display_text": "sha1" }, { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "optional": true, "multiple": true @@ -3638,6 +3898,7 @@ { "name": "arg", "type": "string", + "display_text": "arg", "optional": true, "multiple": true } @@ -3685,15 +3946,18 @@ "arguments": [ { "name": "script", - "type": "string" + "type": "string", + "display_text": "script" }, { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "optional": true, "multiple": true @@ -3701,6 +3965,7 @@ { "name": "arg", "type": "string", + "display_text": "arg", "optional": true, "multiple": true } @@ -3771,6 +4036,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true } @@ -3825,11 +4091,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "seconds", - "type": "integer" + "type": "integer", + "display_text": "seconds" }, { "name": "condition", @@ -3840,21 +4108,25 @@ { "name": "nx", "type": "pure-token", + "display_text": "nx", "token": "NX" }, { "name": "xx", "type": "pure-token", + "display_text": "xx", "token": "XX" }, { "name": "gt", "type": "pure-token", + "display_text": "gt", "token": "GT" }, { "name": "lt", "type": "pure-token", + "display_text": "lt", "token": "LT" } ] @@ -3906,11 +4178,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "unix-time-seconds", - "type": "unix-time" + "type": "unix-time", + "display_text": "unix-time-seconds" }, { "name": "condition", @@ -3921,21 +4195,25 @@ { "name": "nx", "type": "pure-token", + "display_text": "nx", "token": "NX" }, { "name": "xx", "type": "pure-token", + "display_text": "xx", "token": "XX" }, { "name": "gt", "type": "pure-token", + "display_text": "gt", "token": "GT" }, { "name": "lt", "type": "pure-token", + "display_text": "lt", "token": "LT" } ] @@ -3981,6 +4259,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -4009,15 +4288,18 @@ "arguments": [ { "name": "host", - "type": "string" + "type": "string", + "display_text": "host" }, { "name": "port", - "type": "integer" + "type": "integer", + "display_text": "port" }, { "name": "force", "type": "pure-token", + "display_text": "force", "token": "FORCE", "optional": true } @@ -4026,12 +4308,14 @@ { "name": "abort", "type": "pure-token", + "display_text": "abort", "token": "ABORT", "optional": true }, { "name": "milliseconds", "type": "integer", + "display_text": "milliseconds", "token": "TIMEOUT", "optional": true } @@ -4077,15 +4361,18 @@ "arguments": [ { "name": "function", - "type": "string" + "type": "string", + "display_text": "function" }, { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "optional": true, "multiple": true @@ -4093,6 +4380,7 @@ { "name": "arg", "type": "string", + "display_text": "arg", "optional": true, "multiple": true } @@ -4139,15 +4427,18 @@ "arguments": [ { "name": "function", - "type": "string" + "type": "string", + "display_text": "function" }, { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "optional": true, "multiple": true @@ -4155,6 +4446,7 @@ { "name": "arg", "type": "string", + "display_text": "arg", "optional": true, "multiple": true } @@ -4192,19 +4484,21 @@ "arity": -1, "arguments": [ { - "name": "async", + "name": "flush-type", "type": "oneof", "optional": true, "arguments": [ { "name": "async", "type": "pure-token", + "display_text": "async", "token": "ASYNC", "since": "4.0.0" }, { "name": "sync", "type": "pure-token", + "display_text": "sync", "token": "SYNC", "since": "6.2.0" } @@ -4243,19 +4537,21 @@ "arity": -1, "arguments": [ { - "name": "async", + "name": "flush-type", "type": "oneof", "optional": true, "arguments": [ { "name": "async", "type": "pure-token", + "display_text": "async", "token": "ASYNC", "since": "4.0.0" }, { "name": "sync", "type": "pure-token", + "display_text": "sync", "token": "SYNC", "since": "6.2.0" } @@ -4294,7 +4590,8 @@ "arguments": [ { "name": "library-name", - "type": "string" + "type": "string", + "display_text": "library-name" } ], "command_flags": [ @@ -4333,18 +4630,20 @@ "arity": -2, "arguments": [ { - "name": "async", + "name": "flush-type", "type": "oneof", "optional": true, "arguments": [ { "name": "async", "type": "pure-token", + "display_text": "async", "token": "ASYNC" }, { "name": "sync", "type": "pure-token", + "display_text": "sync", "token": "SYNC" } ] @@ -4407,12 +4706,14 @@ { "name": "library-name-pattern", "type": "string", + "display_text": "library-name-pattern", "token": "LIBRARYNAME", "optional": true }, { "name": "withcode", "type": "pure-token", + "display_text": "withcode", "token": "WITHCODE", "optional": true } @@ -4439,12 +4740,14 @@ { "name": "replace", "type": "pure-token", + "display_text": "replace", "token": "REPLACE", "optional": true }, { "name": "function-code", - "type": "string" + "type": "string", + "display_text": "function-code" } ], "command_flags": [ @@ -4471,7 +4774,8 @@ "arguments": [ { "name": "serialized-value", - "type": "string" + "type": "string", + "display_text": "serialized-value" }, { "name": "policy", @@ -4481,16 +4785,19 @@ { "name": "flush", "type": "pure-token", + "display_text": "flush", "token": "FLUSH" }, { "name": "append", "type": "pure-token", + "display_text": "append", "token": "APPEND" }, { "name": "replace", "type": "pure-token", + "display_text": "replace", "token": "REPLACE" } ] @@ -4567,6 +4874,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { @@ -4578,11 +4886,13 @@ { "name": "nx", "type": "pure-token", + "display_text": "nx", "token": "NX" }, { "name": "xx", "type": "pure-token", + "display_text": "xx", "token": "XX" } ] @@ -4590,26 +4900,30 @@ { "name": "change", "type": "pure-token", + "display_text": "change", "token": "CH", "since": "6.2.0", "optional": true }, { - "name": "longitude_latitude_member", + "name": "data", "type": "block", "multiple": true, "arguments": [ { "name": "longitude", - "type": "double" + "type": "double", + "display_text": "longitude" }, { "name": "latitude", - "type": "double" + "type": "double", + "display_text": "latitude" }, { "name": "member", - "type": "string" + "type": "string", + "display_text": "member" } ] } @@ -4654,15 +4968,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "member1", - "type": "string" + "type": "string", + "display_text": "member1" }, { "name": "member2", - "type": "string" + "type": "string", + "display_text": "member2" }, { "name": "unit", @@ -4672,21 +4989,25 @@ { "name": "m", "type": "pure-token", + "display_text": "m", "token": "M" }, { "name": "km", "type": "pure-token", + "display_text": "km", "token": "KM" }, { "name": "ft", "type": "pure-token", + "display_text": "ft", "token": "FT" }, { "name": "mi", "type": "pure-token", + "display_text": "mi", "token": "MI" } ] @@ -4731,11 +5052,14 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "member", "type": "string", + "display_text": "member", + "optional": true, "multiple": true } ], @@ -4778,11 +5102,14 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "member", "type": "string", + "display_text": "member", + "optional": true, "multiple": true } ], @@ -4875,19 +5202,23 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "longitude", - "type": "double" + "type": "double", + "display_text": "longitude" }, { "name": "latitude", - "type": "double" + "type": "double", + "display_text": "latitude" }, { "name": "radius", - "type": "double" + "type": "double", + "display_text": "radius" }, { "name": "unit", @@ -4896,21 +5227,25 @@ { "name": "m", "type": "pure-token", + "display_text": "m", "token": "M" }, { "name": "km", "type": "pure-token", + "display_text": "km", "token": "KM" }, { "name": "ft", "type": "pure-token", + "display_text": "ft", "token": "FT" }, { "name": "mi", "type": "pure-token", + "display_text": "mi", "token": "MI" } ] @@ -4918,34 +5253,39 @@ { "name": "withcoord", "type": "pure-token", + "display_text": "withcoord", "token": "WITHCOORD", "optional": true }, { "name": "withdist", "type": "pure-token", + "display_text": "withdist", "token": "WITHDIST", "optional": true }, { "name": "withhash", "type": "pure-token", + "display_text": "withhash", "token": "WITHHASH", "optional": true }, { - "name": "count", + "name": "count-block", "type": "block", "optional": true, "arguments": [ { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT" }, { "name": "any", "type": "pure-token", + "display_text": "any", "token": "ANY", "since": "6.2.0", "optional": true @@ -4960,25 +5300,29 @@ { "name": "asc", "type": "pure-token", + "display_text": "asc", "token": "ASC" }, { "name": "desc", "type": "pure-token", + "display_text": "desc", "token": "DESC" } ] }, { - "name": "key", + "name": "storekey", "type": "key", + "display_text": "key", "key_spec_index": 1, "token": "STORE", "optional": true }, { - "name": "key", + "name": "storedistkey", "type": "key", + "display_text": "key", "key_spec_index": 2, "token": "STOREDIST", "optional": true @@ -5074,15 +5418,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "member", - "type": "string" + "type": "string", + "display_text": "member" }, { "name": "radius", - "type": "double" + "type": "double", + "display_text": "radius" }, { "name": "unit", @@ -5091,21 +5438,25 @@ { "name": "m", "type": "pure-token", + "display_text": "m", "token": "M" }, { "name": "km", "type": "pure-token", + "display_text": "km", "token": "KM" }, { "name": "ft", "type": "pure-token", + "display_text": "ft", "token": "FT" }, { "name": "mi", "type": "pure-token", + "display_text": "mi", "token": "MI" } ] @@ -5113,34 +5464,39 @@ { "name": "withcoord", "type": "pure-token", + "display_text": "withcoord", "token": "WITHCOORD", "optional": true }, { "name": "withdist", "type": "pure-token", + "display_text": "withdist", "token": "WITHDIST", "optional": true }, { "name": "withhash", "type": "pure-token", + "display_text": "withhash", "token": "WITHHASH", "optional": true }, { - "name": "count", + "name": "count-block", "type": "block", "optional": true, "arguments": [ { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT" }, { "name": "any", "type": "pure-token", + "display_text": "any", "token": "ANY", "optional": true } @@ -5154,25 +5510,29 @@ { "name": "asc", "type": "pure-token", + "display_text": "asc", "token": "ASC" }, { "name": "desc", "type": "pure-token", + "display_text": "desc", "token": "DESC" } ] }, { - "name": "key", + "name": "storekey", "type": "key", + "display_text": "key", "key_spec_index": 1, "token": "STORE", "optional": true }, { - "name": "key", + "name": "storedistkey", "type": "key", + "display_text": "key", "key_spec_index": 2, "token": "STOREDIST", "optional": true @@ -5224,15 +5584,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "member", - "type": "string" + "type": "string", + "display_text": "member" }, { "name": "radius", - "type": "double" + "type": "double", + "display_text": "radius" }, { "name": "unit", @@ -5241,21 +5604,25 @@ { "name": "m", "type": "pure-token", + "display_text": "m", "token": "M" }, { "name": "km", "type": "pure-token", + "display_text": "km", "token": "KM" }, { "name": "ft", "type": "pure-token", + "display_text": "ft", "token": "FT" }, { "name": "mi", "type": "pure-token", + "display_text": "mi", "token": "MI" } ] @@ -5263,34 +5630,39 @@ { "name": "withcoord", "type": "pure-token", + "display_text": "withcoord", "token": "WITHCOORD", "optional": true }, { "name": "withdist", "type": "pure-token", + "display_text": "withdist", "token": "WITHDIST", "optional": true }, { "name": "withhash", "type": "pure-token", + "display_text": "withhash", "token": "WITHHASH", "optional": true }, { - "name": "count", + "name": "count-block", "type": "block", "optional": true, "arguments": [ { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT" }, { "name": "any", "type": "pure-token", + "display_text": "any", "token": "ANY", "optional": true } @@ -5304,11 +5676,13 @@ { "name": "asc", "type": "pure-token", + "display_text": "asc", "token": "ASC" }, { "name": "desc", "type": "pure-token", + "display_text": "desc", "token": "DESC" } ] @@ -5364,19 +5738,23 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "longitude", - "type": "double" + "type": "double", + "display_text": "longitude" }, { "name": "latitude", - "type": "double" + "type": "double", + "display_text": "latitude" }, { "name": "radius", - "type": "double" + "type": "double", + "display_text": "radius" }, { "name": "unit", @@ -5385,21 +5763,25 @@ { "name": "m", "type": "pure-token", + "display_text": "m", "token": "M" }, { "name": "km", "type": "pure-token", + "display_text": "km", "token": "KM" }, { "name": "ft", "type": "pure-token", + "display_text": "ft", "token": "FT" }, { "name": "mi", "type": "pure-token", + "display_text": "mi", "token": "MI" } ] @@ -5407,34 +5789,39 @@ { "name": "withcoord", "type": "pure-token", + "display_text": "withcoord", "token": "WITHCOORD", "optional": true }, { "name": "withdist", "type": "pure-token", + "display_text": "withdist", "token": "WITHDIST", "optional": true }, { "name": "withhash", "type": "pure-token", + "display_text": "withhash", "token": "WITHHASH", "optional": true }, { - "name": "count", + "name": "count-block", "type": "block", "optional": true, "arguments": [ { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT" }, { "name": "any", "type": "pure-token", + "display_text": "any", "token": "ANY", "since": "6.2.0", "optional": true @@ -5449,11 +5836,13 @@ { "name": "asc", "type": "pure-token", + "display_text": "asc", "token": "ASC" }, { "name": "desc", "type": "pure-token", + "display_text": "desc", "token": "DESC" } ] @@ -5507,6 +5896,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { @@ -5516,20 +5906,23 @@ { "name": "member", "type": "string", + "display_text": "member", "token": "FROMMEMBER" }, { - "name": "longitude_latitude", + "name": "fromlonlat", "type": "block", "token": "FROMLONLAT", "arguments": [ { "name": "longitude", - "type": "double" + "type": "double", + "display_text": "longitude" }, { "name": "latitude", - "type": "double" + "type": "double", + "display_text": "latitude" } ] } @@ -5546,6 +5939,7 @@ { "name": "radius", "type": "double", + "display_text": "radius", "token": "BYRADIUS" }, { @@ -5555,21 +5949,25 @@ { "name": "m", "type": "pure-token", + "display_text": "m", "token": "M" }, { "name": "km", "type": "pure-token", + "display_text": "km", "token": "KM" }, { "name": "ft", "type": "pure-token", + "display_text": "ft", "token": "FT" }, { "name": "mi", "type": "pure-token", + "display_text": "mi", "token": "MI" } ] @@ -5583,11 +5981,13 @@ { "name": "width", "type": "double", + "display_text": "width", "token": "BYBOX" }, { "name": "height", - "type": "double" + "type": "double", + "display_text": "height" }, { "name": "unit", @@ -5596,21 +5996,25 @@ { "name": "m", "type": "pure-token", + "display_text": "m", "token": "M" }, { "name": "km", "type": "pure-token", + "display_text": "km", "token": "KM" }, { "name": "ft", "type": "pure-token", + "display_text": "ft", "token": "FT" }, { "name": "mi", "type": "pure-token", + "display_text": "mi", "token": "MI" } ] @@ -5627,28 +6031,32 @@ { "name": "asc", "type": "pure-token", + "display_text": "asc", "token": "ASC" }, { "name": "desc", "type": "pure-token", + "display_text": "desc", "token": "DESC" } ] }, { - "name": "count", + "name": "count-block", "type": "block", "optional": true, "arguments": [ { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT" }, { "name": "any", "type": "pure-token", + "display_text": "any", "token": "ANY", "optional": true } @@ -5657,18 +6065,21 @@ { "name": "withcoord", "type": "pure-token", + "display_text": "withcoord", "token": "WITHCOORD", "optional": true }, { "name": "withdist", "type": "pure-token", + "display_text": "withdist", "token": "WITHDIST", "optional": true }, { "name": "withhash", "type": "pure-token", + "display_text": "withhash", "token": "WITHHASH", "optional": true } @@ -5736,11 +6147,13 @@ { "name": "destination", "type": "key", + "display_text": "destination", "key_spec_index": 0 }, { "name": "source", "type": "key", + "display_text": "source", "key_spec_index": 1 }, { @@ -5750,20 +6163,23 @@ { "name": "member", "type": "string", + "display_text": "member", "token": "FROMMEMBER" }, { - "name": "longitude_latitude", + "name": "fromlonlat", "type": "block", "token": "FROMLONLAT", "arguments": [ { "name": "longitude", - "type": "double" + "type": "double", + "display_text": "longitude" }, { "name": "latitude", - "type": "double" + "type": "double", + "display_text": "latitude" } ] } @@ -5780,6 +6196,7 @@ { "name": "radius", "type": "double", + "display_text": "radius", "token": "BYRADIUS" }, { @@ -5789,21 +6206,25 @@ { "name": "m", "type": "pure-token", + "display_text": "m", "token": "M" }, { "name": "km", "type": "pure-token", + "display_text": "km", "token": "KM" }, { "name": "ft", "type": "pure-token", + "display_text": "ft", "token": "FT" }, { "name": "mi", "type": "pure-token", + "display_text": "mi", "token": "MI" } ] @@ -5817,11 +6238,13 @@ { "name": "width", "type": "double", + "display_text": "width", "token": "BYBOX" }, { "name": "height", - "type": "double" + "type": "double", + "display_text": "height" }, { "name": "unit", @@ -5830,21 +6253,25 @@ { "name": "m", "type": "pure-token", + "display_text": "m", "token": "M" }, { "name": "km", "type": "pure-token", + "display_text": "km", "token": "KM" }, { "name": "ft", "type": "pure-token", + "display_text": "ft", "token": "FT" }, { "name": "mi", "type": "pure-token", + "display_text": "mi", "token": "MI" } ] @@ -5861,28 +6288,32 @@ { "name": "asc", "type": "pure-token", + "display_text": "asc", "token": "ASC" }, { "name": "desc", "type": "pure-token", + "display_text": "desc", "token": "DESC" } ] }, { - "name": "count", + "name": "count-block", "type": "block", "optional": true, "arguments": [ { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT" }, { "name": "any", "type": "pure-token", + "display_text": "any", "token": "ANY", "optional": true } @@ -5891,6 +6322,7 @@ { "name": "storedist", "type": "pure-token", + "display_text": "storedist", "token": "STOREDIST", "optional": true } @@ -5935,6 +6367,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -5978,11 +6411,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "offset", - "type": "integer" + "type": "integer", + "display_text": "offset" } ], "command_flags": [ @@ -6026,6 +6461,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -6071,6 +6507,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { @@ -6081,26 +6518,31 @@ { "name": "seconds", "type": "integer", + "display_text": "seconds", "token": "EX" }, { "name": "milliseconds", "type": "integer", + "display_text": "milliseconds", "token": "PX" }, { "name": "unix-time-seconds", "type": "unix-time", + "display_text": "unix-time-seconds", "token": "EXAT" }, { "name": "unix-time-milliseconds", "type": "unix-time", + "display_text": "unix-time-milliseconds", "token": "PXAT" }, { "name": "persist", "type": "pure-token", + "display_text": "persist", "token": "PERSIST" } ] @@ -6146,15 +6588,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "start", - "type": "integer" + "type": "integer", + "display_text": "start" }, { "name": "end", - "type": "integer" + "type": "integer", + "display_text": "end" } ], "command_flags": [ @@ -6199,11 +6644,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "value", - "type": "string" + "type": "string", + "display_text": "value" } ], "command_flags": [ @@ -6256,11 +6703,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "field", "type": "string", + "display_text": "field", "multiple": true } ], @@ -6293,27 +6742,31 @@ "arguments": [ { "name": "protover", - "type": "integer" + "type": "integer", + "display_text": "protover" }, { - "name": "username_password", + "name": "auth", "type": "block", "token": "AUTH", "optional": true, "arguments": [ { "name": "username", - "type": "string" + "type": "string", + "display_text": "username" }, { "name": "password", - "type": "string" + "type": "string", + "display_text": "password" } ] }, { "name": "clientname", "type": "string", + "display_text": "clientname", "token": "SETNAME", "optional": true } @@ -6363,11 +6816,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "field", - "type": "string" + "type": "string", + "display_text": "field" } ], "command_flags": [ @@ -6410,11 +6865,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "field", - "type": "string" + "type": "string", + "display_text": "field" } ], "command_flags": [ @@ -6457,6 +6914,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -6503,15 +6961,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "field", - "type": "string" + "type": "string", + "display_text": "field" }, { "name": "increment", - "type": "integer" + "type": "integer", + "display_text": "increment" } ], "command_flags": [ @@ -6556,15 +7017,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "field", - "type": "string" + "type": "string", + "display_text": "field" }, { "name": "increment", - "type": "double" + "type": "double", + "display_text": "increment" } ], "command_flags": [ @@ -6608,6 +7072,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -6652,6 +7117,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -6695,11 +7161,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "field", "type": "string", + "display_text": "field", "multiple": true } ], @@ -6745,20 +7213,23 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { - "name": "field_value", + "name": "data", "type": "block", "multiple": true, "arguments": [ { "name": "field", - "type": "string" + "type": "string", + "display_text": "field" }, { "name": "value", - "type": "string" + "type": "string", + "display_text": "value" } ] } @@ -6807,6 +7278,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { @@ -6816,11 +7288,13 @@ "arguments": [ { "name": "count", - "type": "integer" + "type": "integer", + "display_text": "count" }, { "name": "withvalues", "type": "pure-token", + "display_text": "withvalues", "token": "WITHVALUES", "optional": true } @@ -6838,7 +7312,7 @@ "summary": "Incrementally iterate hash fields and associated values", "since": "2.8.0", "group": "hash", - "complexity": "O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..", + "complexity": "O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection.", "acl_categories": [ "@read", "@hash", @@ -6869,21 +7343,25 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "cursor", - "type": "integer" + "type": "integer", + "display_text": "cursor" }, { "name": "pattern", "type": "pattern", + "display_text": "pattern", "token": "MATCH", "optional": true }, { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT", "optional": true } @@ -6936,20 +7414,23 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { - "name": "field_value", + "name": "data", "type": "block", "multiple": true, "arguments": [ { "name": "field", - "type": "string" + "type": "string", + "display_text": "field" }, { "name": "value", - "type": "string" + "type": "string", + "display_text": "value" } ] } @@ -6995,15 +7476,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "field", - "type": "string" + "type": "string", + "display_text": "field" }, { "name": "value", - "type": "string" + "type": "string", + "display_text": "value" } ], "command_flags": [ @@ -7046,11 +7530,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "field", - "type": "string" + "type": "string", + "display_text": "field" } ], "command_flags": [ @@ -7093,6 +7579,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -7139,6 +7626,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -7184,11 +7672,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "increment", - "type": "integer" + "type": "integer", + "display_text": "increment" } ], "command_flags": [ @@ -7233,11 +7723,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "increment", - "type": "double" + "type": "double", + "display_text": "increment" } ], "command_flags": [ @@ -7266,6 +7758,7 @@ { "name": "section", "type": "string", + "display_text": "section", "optional": true, "multiple": true } @@ -7295,7 +7788,8 @@ "arguments": [ { "name": "pattern", - "type": "pattern" + "type": "pattern", + "display_text": "pattern" } ], "command_flags": [ @@ -7373,7 +7867,8 @@ "arguments": [ { "name": "event", - "type": "string" + "type": "string", + "display_text": "event" } ], "command_flags": [ @@ -7417,6 +7912,7 @@ { "name": "command", "type": "string", + "display_text": "command", "optional": true, "multiple": true } @@ -7447,7 +7943,8 @@ "arguments": [ { "name": "event", - "type": "string" + "type": "string", + "display_text": "event" } ], "command_flags": [ @@ -7500,6 +7997,7 @@ { "name": "event", "type": "string", + "display_text": "event", "optional": true, "multiple": true } @@ -7550,34 +8048,40 @@ { "name": "key1", "type": "key", + "display_text": "key1", "key_spec_index": 0 }, { "name": "key2", "type": "key", + "display_text": "key2", "key_spec_index": 0 }, { "name": "len", "type": "pure-token", + "display_text": "len", "token": "LEN", "optional": true }, { "name": "idx", "type": "pure-token", + "display_text": "idx", "token": "IDX", "optional": true }, { - "name": "len", + "name": "min-match-len", "type": "integer", + "display_text": "min-match-len", "token": "MINMATCHLEN", "optional": true }, { "name": "withmatchlen", "type": "pure-token", + "display_text": "withmatchlen", "token": "WITHMATCHLEN", "optional": true } @@ -7621,11 +8125,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "index", - "type": "integer" + "type": "integer", + "display_text": "index" } ], "command_flags": [ @@ -7667,6 +8173,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { @@ -7676,22 +8183,26 @@ { "name": "before", "type": "pure-token", + "display_text": "before", "token": "BEFORE" }, { "name": "after", "type": "pure-token", + "display_text": "after", "token": "AFTER" } ] }, { "name": "pivot", - "type": "string" + "type": "string", + "display_text": "pivot" }, { "name": "element", - "type": "string" + "type": "string", + "display_text": "element" } ], "command_flags": [ @@ -7733,6 +8244,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -7795,11 +8307,13 @@ { "name": "source", "type": "key", + "display_text": "source", "key_spec_index": 0 }, { "name": "destination", "type": "key", + "display_text": "destination", "key_spec_index": 1 }, { @@ -7809,11 +8323,13 @@ { "name": "left", "type": "pure-token", + "display_text": "left", "token": "LEFT" }, { "name": "right", "type": "pure-token", + "display_text": "right", "token": "RIGHT" } ] @@ -7825,11 +8341,13 @@ { "name": "left", "type": "pure-token", + "display_text": "left", "token": "LEFT" }, { "name": "right", "type": "pure-token", + "display_text": "right", "token": "RIGHT" } ] @@ -7875,11 +8393,13 @@ "arguments": [ { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true }, @@ -7890,11 +8410,13 @@ { "name": "left", "type": "pure-token", + "display_text": "left", "token": "LEFT" }, { "name": "right", "type": "pure-token", + "display_text": "right", "token": "RIGHT" } ] @@ -7902,6 +8424,7 @@ { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT", "optional": true } @@ -7924,6 +8447,7 @@ { "name": "version", "type": "integer", + "display_text": "version", "token": "VERSION", "optional": true } @@ -7975,11 +8499,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "count", "type": "integer", + "display_text": "count", "since": "6.2.0", "optional": true } @@ -8024,27 +8550,32 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "element", - "type": "string" + "type": "string", + "display_text": "element" }, { "name": "rank", "type": "integer", + "display_text": "rank", "token": "RANK", "optional": true }, { "name": "num-matches", "type": "integer", + "display_text": "num-matches", "token": "COUNT", "optional": true }, { "name": "len", "type": "integer", + "display_text": "len", "token": "MAXLEN", "optional": true } @@ -8094,11 +8625,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "element", "type": "string", + "display_text": "element", "multiple": true } ], @@ -8149,11 +8682,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "element", "type": "string", + "display_text": "element", "multiple": true } ], @@ -8198,15 +8733,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "start", - "type": "integer" + "type": "integer", + "display_text": "start" }, { "name": "stop", - "type": "integer" + "type": "integer", + "display_text": "stop" } ], "command_flags": [ @@ -8248,15 +8786,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "count", - "type": "integer" + "type": "integer", + "display_text": "count" }, { "name": "element", - "type": "string" + "type": "string", + "display_text": "element" } ], "command_flags": [ @@ -8298,15 +8839,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "index", - "type": "integer" + "type": "integer", + "display_text": "index" }, { "name": "element", - "type": "string" + "type": "string", + "display_text": "element" } ], "command_flags": [ @@ -8349,15 +8893,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "start", - "type": "integer" + "type": "integer", + "display_text": "start" }, { "name": "stop", - "type": "integer" + "type": "integer", + "display_text": "stop" } ], "command_flags": [ @@ -8480,11 +9027,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "count", "type": "integer", + "display_text": "count", "token": "SAMPLES", "optional": true } @@ -8528,6 +9077,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true } @@ -8615,39 +9165,46 @@ "arguments": [ { "name": "host", - "type": "string" + "type": "string", + "display_text": "host" }, { "name": "port", - "type": "integer" + "type": "integer", + "display_text": "port" }, { - "name": "key_or_empty_string", + "name": "key-selector", "type": "oneof", "arguments": [ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { - "name": "empty_string", + "name": "empty-string", "type": "pure-token", + "display_text": "empty-string", "token": "" } ] }, { "name": "destination-db", - "type": "integer" + "type": "integer", + "display_text": "destination-db" }, { "name": "timeout", - "type": "integer" + "type": "integer", + "display_text": "timeout" }, { "name": "copy", "type": "pure-token", + "display_text": "copy", "token": "COPY", "since": "3.0.0", "optional": true @@ -8655,6 +9212,7 @@ { "name": "replace", "type": "pure-token", + "display_text": "replace", "token": "REPLACE", "since": "3.0.0", "optional": true @@ -8665,34 +9223,36 @@ "optional": true, "arguments": [ { - "name": "password", + "name": "auth", "type": "string", + "display_text": "password", "token": "AUTH", - "since": "4.0.7", - "optional": true + "since": "4.0.7" }, { - "name": "username_password", + "name": "auth2", "type": "block", "token": "AUTH2", "since": "6.0.0", - "optional": true, "arguments": [ { "name": "username", - "type": "string" + "type": "string", + "display_text": "username" }, { "name": "password", - "type": "string" + "type": "string", + "display_text": "password" } ] } ] }, { - "name": "key", + "name": "keys", "type": "key", + "display_text": "key", "key_spec_index": 1, "token": "KEYS", "since": "3.0.6", @@ -8765,11 +9325,13 @@ "arguments": [ { "name": "path", - "type": "string" + "type": "string", + "display_text": "path" }, { "name": "arg", "type": "string", + "display_text": "arg", "optional": true, "multiple": true } @@ -8794,7 +9356,8 @@ "arguments": [ { "name": "path", - "type": "string" + "type": "string", + "display_text": "path" }, { "name": "configs", @@ -8806,26 +9369,23 @@ "arguments": [ { "name": "name", - "type": "string" + "type": "string", + "display_text": "name" }, { "name": "value", - "type": "string" + "type": "string", + "display_text": "value" } ] }, { "name": "args", - "type": "block", + "type": "string", + "display_text": "args", "token": "ARGS", "optional": true, - "multiple": true, - "arguments": [ - { - "name": "arg", - "type": "string" - } - ] + "multiple": true } ], "command_flags": [ @@ -8848,7 +9408,8 @@ "arguments": [ { "name": "name", - "type": "string" + "type": "string", + "display_text": "name" } ], "command_flags": [ @@ -8910,11 +9471,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "db", - "type": "integer" + "type": "integer", + "display_text": "db" } ], "command_flags": [ @@ -8955,18 +9518,20 @@ ], "arguments": [ { - "name": "key_value", + "name": "data", "type": "block", "multiple": true, "arguments": [ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "value", - "type": "string" + "type": "string", + "display_text": "value" } ] } @@ -9013,18 +9578,20 @@ ], "arguments": [ { - "name": "key_value", + "name": "data", "type": "block", "multiple": true, "arguments": [ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "value", - "type": "string" + "type": "string", + "display_text": "value" } ] } @@ -9100,6 +9667,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -9144,6 +9712,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -9203,6 +9772,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -9247,6 +9817,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -9292,6 +9863,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -9341,11 +9913,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "milliseconds", - "type": "integer" + "type": "integer", + "display_text": "milliseconds" }, { "name": "condition", @@ -9356,21 +9930,25 @@ { "name": "nx", "type": "pure-token", + "display_text": "nx", "token": "NX" }, { "name": "xx", "type": "pure-token", + "display_text": "xx", "token": "XX" }, { "name": "gt", "type": "pure-token", + "display_text": "gt", "token": "GT" }, { "name": "lt", "type": "pure-token", + "display_text": "lt", "token": "LT" } ] @@ -9422,11 +10000,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "unix-time-milliseconds", - "type": "unix-time" + "type": "unix-time", + "display_text": "unix-time-milliseconds" }, { "name": "condition", @@ -9437,21 +10017,25 @@ { "name": "nx", "type": "pure-token", + "display_text": "nx", "token": "NX" }, { "name": "xx", "type": "pure-token", + "display_text": "xx", "token": "XX" }, { "name": "gt", "type": "pure-token", + "display_text": "gt", "token": "GT" }, { "name": "lt", "type": "pure-token", + "display_text": "lt", "token": "LT" } ] @@ -9497,6 +10081,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -9540,11 +10125,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "element", "type": "string", + "display_text": "element", "optional": true, "multiple": true } @@ -9591,6 +10178,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true } @@ -9635,11 +10223,13 @@ "arguments": [ { "name": "subcommand", - "type": "string" + "type": "string", + "display_text": "subcommand" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -9706,12 +10296,15 @@ { "name": "destkey", "type": "key", + "display_text": "destkey", "key_spec_index": 0 }, { "name": "sourcekey", "type": "key", + "display_text": "sourcekey", "key_spec_index": 1, + "optional": true, "multiple": true } ], @@ -9753,6 +10346,7 @@ { "name": "message", "type": "string", + "display_text": "message", "optional": true } ], @@ -9769,6 +10363,8 @@ "since": "2.6.0", "group": "string", "complexity": "O(1)", + "deprecated_since": "2.6.12", + "replaced_by": "`SET` with the `PX` argument", "acl_categories": [ "@write", "@string", @@ -9799,20 +10395,26 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "milliseconds", - "type": "integer" + "type": "integer", + "display_text": "milliseconds" }, { "name": "value", - "type": "string" + "type": "string", + "display_text": "value" } ], "command_flags": [ "write", "denyoom" + ], + "doc_flags": [ + "deprecated" ] }, "PSUBSCRIBE": { @@ -9828,14 +10430,9 @@ "arguments": [ { "name": "pattern", - "type": "block", - "multiple": true, - "arguments": [ - { - "name": "pattern", - "type": "pattern" - } - ] + "type": "pattern", + "display_text": "pattern", + "multiple": true } ], "command_flags": [ @@ -9858,11 +10455,13 @@ "arguments": [ { "name": "replicationid", - "type": "string" + "type": "string", + "display_text": "replicationid" }, { "name": "offset", - "type": "integer" + "type": "integer", + "display_text": "offset" } ], "command_flags": [ @@ -9913,6 +10512,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -9937,11 +10537,13 @@ "arguments": [ { "name": "channel", - "type": "string" + "type": "string", + "display_text": "channel" }, { "name": "message", - "type": "string" + "type": "string", + "display_text": "message" } ], "command_flags": [ @@ -9975,6 +10577,7 @@ { "name": "pattern", "type": "pattern", + "display_text": "pattern", "optional": true } ], @@ -10028,6 +10631,7 @@ { "name": "channel", "type": "string", + "display_text": "channel", "optional": true, "multiple": true } @@ -10052,6 +10656,7 @@ { "name": "pattern", "type": "pattern", + "display_text": "pattern", "optional": true } ], @@ -10075,6 +10680,7 @@ { "name": "shardchannel", "type": "string", + "display_text": "shardchannel", "optional": true, "multiple": true } @@ -10099,6 +10705,7 @@ { "name": "pattern", "type": "pattern", + "display_text": "pattern", "optional": true, "multiple": true } @@ -10115,6 +10722,8 @@ "since": "1.0.0", "group": "connection", "complexity": "O(1)", + "deprecated_since": "7.2.0", + "replaced_by": "just closing the connection", "acl_categories": [ "@fast", "@connection" @@ -10127,6 +10736,9 @@ "fast", "no_auth", "allow_busy" + ], + "doc_flags": [ + "deprecated" ] }, "RANDOMKEY": { @@ -10234,11 +10846,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "newkey", "type": "key", + "display_text": "newkey", "key_spec_index": 1 } ], @@ -10306,11 +10920,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "newkey", "type": "key", + "display_text": "newkey", "key_spec_index": 1 } ], @@ -10355,11 +10971,13 @@ "arguments": [ { "name": "host", - "type": "string" + "type": "string", + "display_text": "host" }, { "name": "port", - "type": "integer" + "type": "integer", + "display_text": "port" } ], "command_flags": [ @@ -10438,19 +11056,23 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "ttl", - "type": "integer" + "type": "integer", + "display_text": "ttl" }, { "name": "serialized-value", - "type": "string" + "type": "string", + "display_text": "serialized-value" }, { "name": "replace", "type": "pure-token", + "display_text": "replace", "token": "REPLACE", "since": "3.0.0", "optional": true @@ -10458,6 +11080,7 @@ { "name": "absttl", "type": "pure-token", + "display_text": "absttl", "token": "ABSTTL", "since": "5.0.0", "optional": true @@ -10465,6 +11088,7 @@ { "name": "seconds", "type": "integer", + "display_text": "seconds", "token": "IDLETIME", "since": "5.0.0", "optional": true @@ -10472,6 +11096,7 @@ { "name": "frequency", "type": "integer", + "display_text": "frequency", "token": "FREQ", "since": "5.0.0", "optional": true @@ -10532,19 +11157,23 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "ttl", - "type": "integer" + "type": "integer", + "display_text": "ttl" }, { "name": "serialized-value", - "type": "string" + "type": "string", + "display_text": "serialized-value" }, { "name": "replace", "type": "pure-token", + "display_text": "replace", "token": "REPLACE", "since": "3.0.0", "optional": true @@ -10552,6 +11181,7 @@ { "name": "absttl", "type": "pure-token", + "display_text": "absttl", "token": "ABSTTL", "since": "5.0.0", "optional": true @@ -10559,6 +11189,7 @@ { "name": "seconds", "type": "integer", + "display_text": "seconds", "token": "IDLETIME", "since": "5.0.0", "optional": true @@ -10566,6 +11197,7 @@ { "name": "frequency", "type": "integer", + "display_text": "frequency", "token": "FREQ", "since": "5.0.0", "optional": true @@ -10640,11 +11272,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "count", "type": "integer", + "display_text": "count", "since": "6.2.0", "optional": true } @@ -10710,11 +11344,13 @@ { "name": "source", "type": "key", + "display_text": "source", "key_spec_index": 0 }, { "name": "destination", "type": "key", + "display_text": "destination", "key_spec_index": 1 } ], @@ -10767,11 +11403,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "element", "type": "string", + "display_text": "element", "multiple": true } ], @@ -10822,11 +11460,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "element", "type": "string", + "display_text": "element", "multiple": true } ], @@ -10877,11 +11517,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "member", "type": "string", + "display_text": "member", "multiple": true } ], @@ -10929,23 +11571,27 @@ "arguments": [ { "name": "cursor", - "type": "integer" + "type": "integer", + "display_text": "cursor" }, { "name": "pattern", "type": "pattern", + "display_text": "pattern", "token": "MATCH", "optional": true }, { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT", "optional": true }, { "name": "type", "type": "string", + "display_text": "type", "token": "TYPE", "since": "6.0.0", "optional": true @@ -10993,6 +11639,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -11029,16 +11676,19 @@ { "name": "yes", "type": "pure-token", + "display_text": "yes", "token": "YES" }, { "name": "sync", "type": "pure-token", + "display_text": "sync", "token": "SYNC" }, { "name": "no", "type": "pure-token", + "display_text": "no", "token": "NO" } ] @@ -11062,6 +11712,7 @@ { "name": "sha1", "type": "string", + "display_text": "sha1", "multiple": true } ], @@ -11091,7 +11742,7 @@ "arity": -2, "arguments": [ { - "name": "async", + "name": "flush-type", "type": "oneof", "since": "6.2.0", "optional": true, @@ -11099,11 +11750,13 @@ { "name": "async", "type": "pure-token", + "display_text": "async", "token": "ASYNC" }, { "name": "sync", "type": "pure-token", + "display_text": "sync", "token": "SYNC" } ] @@ -11164,7 +11817,8 @@ "arguments": [ { "name": "script", - "type": "string" + "type": "string", + "display_text": "script" } ], "command_flags": [ @@ -11211,6 +11865,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true } @@ -11275,11 +11930,13 @@ { "name": "destination", "type": "key", + "display_text": "destination", "key_spec_index": 0 }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 1, "multiple": true } @@ -11302,7 +11959,8 @@ "arguments": [ { "name": "index", - "type": "integer" + "type": "integer", + "display_text": "index" } ], "command_flags": [ @@ -11367,11 +12025,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "value", - "type": "string" + "type": "string", + "display_text": "value" }, { "name": "condition", @@ -11382,11 +12042,13 @@ { "name": "nx", "type": "pure-token", + "display_text": "nx", "token": "NX" }, { "name": "xx", "type": "pure-token", + "display_text": "xx", "token": "XX" } ] @@ -11394,6 +12056,7 @@ { "name": "get", "type": "pure-token", + "display_text": "get", "token": "GET", "since": "6.2.0", "optional": true @@ -11406,30 +12069,35 @@ { "name": "seconds", "type": "integer", + "display_text": "seconds", "token": "EX", "since": "2.6.12" }, { "name": "milliseconds", "type": "integer", + "display_text": "milliseconds", "token": "PX", "since": "2.6.12" }, { "name": "unix-time-seconds", "type": "unix-time", + "display_text": "unix-time-seconds", "token": "EXAT", "since": "6.2.0" }, { "name": "unix-time-milliseconds", "type": "unix-time", + "display_text": "unix-time-milliseconds", "token": "PXAT", "since": "6.2.0" }, { "name": "keepttl", "type": "pure-token", + "display_text": "keepttl", "token": "KEEPTTL", "since": "6.0.0" } @@ -11477,15 +12145,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "offset", - "type": "integer" + "type": "integer", + "display_text": "offset" }, { "name": "value", - "type": "integer" + "type": "integer", + "display_text": "value" } ], "command_flags": [ @@ -11498,6 +12169,8 @@ "since": "2.0.0", "group": "string", "complexity": "O(1)", + "deprecated_since": "2.6.12", + "replaced_by": "`SET` with the `EX` argument", "acl_categories": [ "@write", "@string", @@ -11528,20 +12201,26 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "seconds", - "type": "integer" + "type": "integer", + "display_text": "seconds" }, { "name": "value", - "type": "string" + "type": "string", + "display_text": "value" } ], "command_flags": [ "write", "denyoom" + ], + "doc_flags": [ + "deprecated" ] }, "SETNX": { @@ -11549,6 +12228,8 @@ "since": "1.0.0", "group": "string", "complexity": "O(1)", + "deprecated_since": "2.6.12", + "replaced_by": "`SET` with the `NX` argument", "acl_categories": [ "@write", "@string", @@ -11579,17 +12260,22 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "value", - "type": "string" + "type": "string", + "display_text": "value" } ], "command_flags": [ "write", "denyoom", "fast" + ], + "doc_flags": [ + "deprecated" ] }, "SETRANGE": { @@ -11627,15 +12313,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "offset", - "type": "integer" + "type": "integer", + "display_text": "offset" }, { "name": "value", - "type": "string" + "type": "string", + "display_text": "value" } ], "command_flags": [ @@ -11662,18 +12351,20 @@ "arity": -1, "arguments": [ { - "name": "nosave_save", + "name": "save-selector", "type": "oneof", "optional": true, "arguments": [ { "name": "nosave", "type": "pure-token", + "display_text": "nosave", "token": "NOSAVE" }, { "name": "save", "type": "pure-token", + "display_text": "save", "token": "SAVE" } ] @@ -11681,6 +12372,7 @@ { "name": "now", "type": "pure-token", + "display_text": "now", "token": "NOW", "since": "7.0.0", "optional": true @@ -11688,6 +12380,7 @@ { "name": "force", "type": "pure-token", + "display_text": "force", "token": "FORCE", "since": "7.0.0", "optional": true @@ -11695,6 +12388,7 @@ { "name": "abort", "type": "pure-token", + "display_text": "abort", "token": "ABORT", "since": "7.0.0", "optional": true @@ -11744,6 +12438,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true } @@ -11789,17 +12484,20 @@ "arguments": [ { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true }, { "name": "limit", "type": "integer", + "display_text": "limit", "token": "LIMIT", "optional": true } @@ -11862,11 +12560,13 @@ { "name": "destination", "type": "key", + "display_text": "destination", "key_spec_index": 0 }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 1, "multiple": true } @@ -11910,11 +12610,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "member", - "type": "string" + "type": "string", + "display_text": "member" } ], "command_flags": [ @@ -11938,11 +12640,13 @@ "arguments": [ { "name": "host", - "type": "string" + "type": "string", + "display_text": "host" }, { "name": "port", - "type": "integer" + "type": "integer", + "display_text": "port" } ], "command_flags": [ @@ -11986,6 +12690,7 @@ { "name": "count", "type": "integer", + "display_text": "count", "optional": true } ], @@ -12091,6 +12796,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -12136,11 +12842,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "member", "type": "string", + "display_text": "member", "multiple": true } ], @@ -12203,16 +12911,19 @@ { "name": "source", "type": "key", + "display_text": "source", "key_spec_index": 0 }, { "name": "destination", "type": "key", + "display_text": "destination", "key_spec_index": 1 }, { "name": "member", - "type": "string" + "type": "string", + "display_text": "member" } ], "command_flags": [ @@ -12284,34 +12995,39 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { - "name": "pattern", + "name": "by-pattern", "type": "pattern", + "display_text": "pattern", "key_spec_index": 1, "token": "BY", "optional": true }, { - "name": "offset_count", + "name": "limit", "type": "block", "token": "LIMIT", "optional": true, "arguments": [ { "name": "offset", - "type": "integer" + "type": "integer", + "display_text": "offset" }, { "name": "count", - "type": "integer" + "type": "integer", + "display_text": "count" } ] }, { - "name": "pattern", + "name": "get-pattern", "type": "pattern", + "display_text": "pattern", "key_spec_index": 1, "token": "GET", "optional": true, @@ -12326,11 +13042,13 @@ { "name": "asc", "type": "pure-token", + "display_text": "asc", "token": "ASC" }, { "name": "desc", "type": "pure-token", + "display_text": "desc", "token": "DESC" } ] @@ -12338,12 +13056,14 @@ { "name": "sorting", "type": "pure-token", + "display_text": "sorting", "token": "ALPHA", "optional": true }, { "name": "destination", "type": "key", + "display_text": "destination", "key_spec_index": 2, "token": "STORE", "optional": true @@ -12406,34 +13126,39 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { - "name": "pattern", + "name": "by-pattern", "type": "pattern", + "display_text": "pattern", "key_spec_index": 1, "token": "BY", "optional": true }, { - "name": "offset_count", + "name": "limit", "type": "block", "token": "LIMIT", "optional": true, "arguments": [ { "name": "offset", - "type": "integer" + "type": "integer", + "display_text": "offset" }, { "name": "count", - "type": "integer" + "type": "integer", + "display_text": "count" } ] }, { - "name": "pattern", + "name": "get-pattern", "type": "pattern", + "display_text": "pattern", "key_spec_index": 1, "token": "GET", "optional": true, @@ -12448,11 +13173,13 @@ { "name": "asc", "type": "pure-token", + "display_text": "asc", "token": "ASC" }, { "name": "desc", "type": "pure-token", + "display_text": "desc", "token": "DESC" } ] @@ -12460,6 +13187,7 @@ { "name": "sorting", "type": "pure-token", + "display_text": "sorting", "token": "ALPHA", "optional": true } @@ -12511,11 +13239,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "count", "type": "integer", + "display_text": "count", "since": "3.2.0", "optional": true } @@ -12560,11 +13290,13 @@ "arguments": [ { "name": "shardchannel", - "type": "string" + "type": "string", + "display_text": "shardchannel" }, { "name": "message", - "type": "string" + "type": "string", + "display_text": "message" } ], "command_flags": [ @@ -12615,11 +13347,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "count", "type": "integer", + "display_text": "count", "since": "2.6.0", "optional": true } @@ -12672,11 +13406,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "member", "type": "string", + "display_text": "member", "multiple": true } ], @@ -12689,7 +13425,7 @@ "summary": "Incrementally iterate Set elements", "since": "2.8.0", "group": "set", - "complexity": "O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..", + "complexity": "O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection.", "acl_categories": [ "@read", "@set", @@ -12720,21 +13456,25 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "cursor", - "type": "integer" + "type": "integer", + "display_text": "cursor" }, { "name": "pattern", "type": "pattern", + "display_text": "pattern", "token": "MATCH", "optional": true }, { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT", "optional": true } @@ -12779,6 +13519,7 @@ { "name": "shardchannel", "type": "string", + "display_text": "shardchannel", "multiple": true } ], @@ -12823,6 +13564,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -12845,6 +13587,7 @@ { "name": "channel", "type": "string", + "display_text": "channel", "multiple": true } ], @@ -12892,15 +13635,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "start", - "type": "integer" + "type": "integer", + "display_text": "start" }, { "name": "end", - "type": "integer" + "type": "integer", + "display_text": "end" } ], "command_flags": [ @@ -12945,6 +13691,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true } @@ -13009,11 +13756,13 @@ { "name": "destination", "type": "key", + "display_text": "destination", "key_spec_index": 0 }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 1, "multiple": true } @@ -13056,6 +13805,7 @@ { "name": "shardchannel", "type": "string", + "display_text": "shardchannel", "optional": true, "multiple": true } @@ -13082,11 +13832,13 @@ "arguments": [ { "name": "index1", - "type": "integer" + "type": "integer", + "display_text": "index1" }, { "name": "index2", - "type": "integer" + "type": "integer", + "display_text": "index2" } ], "command_flags": [ @@ -13163,6 +13915,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true } @@ -13217,6 +13970,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -13262,6 +14016,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -13305,6 +14060,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true } @@ -13332,6 +14088,7 @@ { "name": "channel", "type": "string", + "display_text": "channel", "optional": true, "multiple": true } @@ -13374,11 +14131,13 @@ "arguments": [ { "name": "numreplicas", - "type": "integer" + "type": "integer", + "display_text": "numreplicas" }, { "name": "timeout", - "type": "integer" + "type": "integer", + "display_text": "timeout" } ], "command_flags": [ @@ -13422,6 +14181,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true } @@ -13469,15 +14229,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "group", - "type": "string" + "type": "string", + "display_text": "group" }, { "name": "id", "type": "string", + "display_text": "id", "multiple": true } ], @@ -13532,11 +14295,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "nomkstream", "type": "pure-token", + "display_text": "nomkstream", "token": "NOMKSTREAM", "since": "6.2.0", "optional": true @@ -13553,11 +14318,13 @@ { "name": "maxlen", "type": "pure-token", + "display_text": "maxlen", "token": "MAXLEN" }, { "name": "minid", "type": "pure-token", + "display_text": "minid", "token": "MINID", "since": "6.2.0" } @@ -13571,22 +14338,26 @@ { "name": "equal", "type": "pure-token", + "display_text": "equal", "token": "=" }, { "name": "approximately", "type": "pure-token", + "display_text": "approximately", "token": "~" } ] }, { "name": "threshold", - "type": "string" + "type": "string", + "display_text": "threshold" }, { "name": "count", "type": "integer", + "display_text": "count", "token": "LIMIT", "since": "6.2.0", "optional": true @@ -13594,32 +14365,36 @@ ] }, { - "name": "id_or_auto", + "name": "id-selector", "type": "oneof", "arguments": [ { - "name": "auto_id", + "name": "auto-id", "type": "pure-token", + "display_text": "auto-id", "token": "*" }, { "name": "id", - "type": "string" + "type": "string", + "display_text": "id" } ] }, { - "name": "field_value", + "name": "data", "type": "block", "multiple": true, "arguments": [ { "name": "field", - "type": "string" + "type": "string", + "display_text": "field" }, { "name": "value", - "type": "string" + "type": "string", + "display_text": "value" } ] } @@ -13674,33 +14449,40 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "group", - "type": "string" + "type": "string", + "display_text": "group" }, { "name": "consumer", - "type": "string" + "type": "string", + "display_text": "consumer" }, { "name": "min-idle-time", - "type": "string" + "type": "string", + "display_text": "min-idle-time" }, { "name": "start", - "type": "string" + "type": "string", + "display_text": "start" }, { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT", "optional": true }, { "name": "justid", "type": "pure-token", + "display_text": "justid", "token": "JUSTID", "optional": true } @@ -13748,58 +14530,69 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "group", - "type": "string" + "type": "string", + "display_text": "group" }, { "name": "consumer", - "type": "string" + "type": "string", + "display_text": "consumer" }, { "name": "min-idle-time", - "type": "string" + "type": "string", + "display_text": "min-idle-time" }, { "name": "id", "type": "string", + "display_text": "id", "multiple": true }, { "name": "ms", "type": "integer", + "display_text": "ms", "token": "IDLE", "optional": true }, { "name": "unix-time-milliseconds", "type": "unix-time", + "display_text": "unix-time-milliseconds", "token": "TIME", "optional": true }, { "name": "count", "type": "integer", + "display_text": "count", "token": "RETRYCOUNT", "optional": true }, { "name": "force", "type": "pure-token", + "display_text": "force", "token": "FORCE", "optional": true }, { "name": "justid", "type": "pure-token", + "display_text": "justid", "token": "JUSTID", "optional": true }, { - "name": "id", + "name": "lastid", "type": "string", + "display_text": "lastid", "token": "LASTID", "optional": true } @@ -13847,11 +14640,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "id", "type": "string", + "display_text": "id", "multiple": true } ], @@ -13911,23 +14706,27 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { - "name": "groupname", - "type": "string" + "name": "group", + "type": "string", + "display_text": "group" }, { - "name": "id", + "name": "id-selector", "type": "oneof", "arguments": [ { "name": "id", - "type": "string" + "type": "string", + "display_text": "id" }, { - "name": "new_id", + "name": "new-id", "type": "pure-token", + "display_text": "new-id", "token": "$" } ] @@ -13935,12 +14734,14 @@ { "name": "mkstream", "type": "pure-token", + "display_text": "mkstream", "token": "MKSTREAM", "optional": true }, { - "name": "entries_read", + "name": "entries-read", "type": "integer", + "display_text": "entries-read", "token": "ENTRIESREAD", "optional": true } @@ -13985,15 +14786,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { - "name": "groupname", - "type": "string" + "name": "group", + "type": "string", + "display_text": "group" }, { - "name": "consumername", - "type": "string" + "name": "consumer", + "type": "string", + "display_text": "consumer" } ], "command_flags": [ @@ -14036,15 +14840,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { - "name": "groupname", - "type": "string" + "name": "group", + "type": "string", + "display_text": "group" }, { - "name": "consumername", - "type": "string" + "name": "consumer", + "type": "string", + "display_text": "consumer" } ], "command_flags": [ @@ -14086,11 +14893,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { - "name": "groupname", - "type": "string" + "name": "group", + "type": "string", + "display_text": "group" } ], "command_flags": [ @@ -14153,30 +14962,35 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { - "name": "groupname", - "type": "string" + "name": "group", + "type": "string", + "display_text": "group" }, { - "name": "id", + "name": "id-selector", "type": "oneof", "arguments": [ { "name": "id", - "type": "string" + "type": "string", + "display_text": "id" }, { - "name": "new_id", + "name": "new-id", "type": "pure-token", + "display_text": "new-id", "token": "$" } ] }, { - "name": "entries_read", + "name": "entriesread", "type": "integer", + "display_text": "entries-read", "token": "ENTRIESREAD", "optional": true } @@ -14230,11 +15044,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { - "name": "groupname", - "type": "string" + "name": "group", + "type": "string", + "display_text": "group" } ], "command_flags": [ @@ -14285,6 +15101,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -14352,17 +15169,24 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { - "name": "full", + "name": "full-block", "type": "block", - "token": "FULL", "optional": true, "arguments": [ + { + "name": "full", + "type": "pure-token", + "display_text": "full", + "token": "FULL" + }, { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT", "optional": true } @@ -14407,6 +15231,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -14456,11 +15281,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "group", - "type": "string" + "type": "string", + "display_text": "group" }, { "name": "filters", @@ -14470,25 +15297,30 @@ { "name": "min-idle-time", "type": "integer", + "display_text": "min-idle-time", "token": "IDLE", "since": "6.2.0", "optional": true }, { "name": "start", - "type": "string" + "type": "string", + "display_text": "start" }, { "name": "end", - "type": "string" + "type": "string", + "display_text": "end" }, { "name": "count", - "type": "integer" + "type": "integer", + "display_text": "count" }, { "name": "consumer", "type": "string", + "display_text": "consumer", "optional": true } ] @@ -14542,19 +15374,23 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "start", - "type": "string" + "type": "string", + "display_text": "start" }, { "name": "end", - "type": "string" + "type": "string", + "display_text": "end" }, { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT", "optional": true } @@ -14600,12 +15436,14 @@ { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT", "optional": true }, { "name": "milliseconds", "type": "integer", + "display_text": "milliseconds", "token": "BLOCK", "optional": true }, @@ -14617,12 +15455,14 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true }, { "name": "id", "type": "string", + "display_text": "id", "multiple": true } ] @@ -14669,35 +15509,40 @@ ], "arguments": [ { - "name": "group_consumer", + "name": "group-block", "type": "block", "token": "GROUP", "arguments": [ { "name": "group", - "type": "string" + "type": "string", + "display_text": "group" }, { "name": "consumer", - "type": "string" + "type": "string", + "display_text": "consumer" } ] }, { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT", "optional": true }, { "name": "milliseconds", "type": "integer", + "display_text": "milliseconds", "token": "BLOCK", "optional": true }, { "name": "noack", "type": "pure-token", + "display_text": "noack", "token": "NOACK", "optional": true }, @@ -14709,12 +15554,14 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true }, { "name": "id", "type": "string", + "display_text": "id", "multiple": true } ] @@ -14767,19 +15614,23 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "end", - "type": "string" + "type": "string", + "display_text": "end" }, { "name": "start", - "type": "string" + "type": "string", + "display_text": "start" }, { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT", "optional": true } @@ -14829,22 +15680,28 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "last-id", - "type": "string" + "type": "string", + "display_text": "last-id" }, { - "name": "entries_added", + "name": "entries-added", "type": "integer", + "display_text": "entries-added", "token": "ENTRIESADDED", + "since": "7.0.0", "optional": true }, { - "name": "max_deleted_entry_id", + "name": "max-deleted-id", "type": "string", + "display_text": "max-deleted-id", "token": "MAXDELETEDID", + "since": "7.0.0", "optional": true } ], @@ -14895,6 +15752,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { @@ -14908,11 +15766,13 @@ { "name": "maxlen", "type": "pure-token", + "display_text": "maxlen", "token": "MAXLEN" }, { "name": "minid", "type": "pure-token", + "display_text": "minid", "token": "MINID", "since": "6.2.0" } @@ -14926,22 +15786,26 @@ { "name": "equal", "type": "pure-token", + "display_text": "equal", "token": "=" }, { "name": "approximately", "type": "pure-token", + "display_text": "approximately", "token": "~" } ] }, { "name": "threshold", - "type": "string" + "type": "string", + "display_text": "threshold" }, { "name": "count", "type": "integer", + "display_text": "count", "token": "LIMIT", "since": "6.2.0", "optional": true @@ -15005,6 +15869,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { @@ -15016,11 +15881,13 @@ { "name": "nx", "type": "pure-token", + "display_text": "nx", "token": "NX" }, { "name": "xx", "type": "pure-token", + "display_text": "xx", "token": "XX" } ] @@ -15034,11 +15901,13 @@ { "name": "gt", "type": "pure-token", + "display_text": "gt", "token": "GT" }, { "name": "lt", "type": "pure-token", + "display_text": "lt", "token": "LT" } ] @@ -15046,6 +15915,7 @@ { "name": "change", "type": "pure-token", + "display_text": "change", "token": "CH", "since": "3.0.2", "optional": true @@ -15053,22 +15923,25 @@ { "name": "increment", "type": "pure-token", + "display_text": "increment", "token": "INCR", "since": "3.0.2", "optional": true }, { - "name": "score_member", + "name": "data", "type": "block", "multiple": true, "arguments": [ { "name": "score", - "type": "double" + "type": "double", + "display_text": "score" }, { "name": "member", - "type": "string" + "type": "string", + "display_text": "member" } ] } @@ -15113,6 +15986,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 } ], @@ -15156,15 +16030,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "min", - "type": "double" + "type": "double", + "display_text": "min" }, { "name": "max", - "type": "double" + "type": "double", + "display_text": "max" } ], "command_flags": [ @@ -15206,17 +16083,20 @@ "arguments": [ { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true }, { "name": "withscores", "type": "pure-token", + "display_text": "withscores", "token": "WITHSCORES", "optional": true } @@ -15279,15 +16159,18 @@ { "name": "destination", "type": "key", + "display_text": "destination", "key_spec_index": 0 }, { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 1, "multiple": true } @@ -15334,15 +16217,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "increment", - "type": "integer" + "type": "integer", + "display_text": "increment" }, { "name": "member", - "type": "string" + "type": "string", + "display_text": "member" } ], "command_flags": [ @@ -15385,17 +16271,20 @@ "arguments": [ { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true }, { "name": "weight", "type": "integer", + "display_text": "weight", "token": "WEIGHTS", "optional": true, "multiple": true @@ -15409,16 +16298,19 @@ { "name": "sum", "type": "pure-token", + "display_text": "sum", "token": "SUM" }, { "name": "min", "type": "pure-token", + "display_text": "min", "token": "MIN" }, { "name": "max", "type": "pure-token", + "display_text": "max", "token": "MAX" } ] @@ -15426,6 +16318,7 @@ { "name": "withscores", "type": "pure-token", + "display_text": "withscores", "token": "WITHSCORES", "optional": true } @@ -15469,17 +16362,20 @@ "arguments": [ { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true }, { "name": "limit", "type": "integer", + "display_text": "limit", "token": "LIMIT", "optional": true } @@ -15542,21 +16438,25 @@ { "name": "destination", "type": "key", + "display_text": "destination", "key_spec_index": 0 }, { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 1, "multiple": true }, { "name": "weight", "type": "integer", + "display_text": "weight", "token": "WEIGHTS", "optional": true, "multiple": true @@ -15570,16 +16470,19 @@ { "name": "sum", "type": "pure-token", + "display_text": "sum", "token": "SUM" }, { "name": "min", "type": "pure-token", + "display_text": "min", "token": "MIN" }, { "name": "max", "type": "pure-token", + "display_text": "max", "token": "MAX" } ] @@ -15626,15 +16529,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "min", - "type": "string" + "type": "string", + "display_text": "min" }, { "name": "max", - "type": "string" + "type": "string", + "display_text": "max" } ], "command_flags": [ @@ -15677,11 +16583,13 @@ "arguments": [ { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true }, @@ -15692,11 +16600,13 @@ { "name": "min", "type": "pure-token", + "display_text": "min", "token": "MIN" }, { "name": "max", "type": "pure-token", + "display_text": "max", "token": "MAX" } ] @@ -15704,6 +16614,7 @@ { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT", "optional": true } @@ -15748,11 +16659,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "member", "type": "string", + "display_text": "member", "multiple": true } ], @@ -15797,11 +16710,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "count", "type": "integer", + "display_text": "count", "optional": true } ], @@ -15846,11 +16761,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "count", "type": "integer", + "display_text": "count", "optional": true } ], @@ -15894,6 +16811,7 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { @@ -15903,11 +16821,13 @@ "arguments": [ { "name": "count", - "type": "integer" + "type": "integer", + "display_text": "count" }, { "name": "withscores", "type": "pure-token", + "display_text": "withscores", "token": "WITHSCORES", "optional": true } @@ -15962,15 +16882,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "start", - "type": "string" + "type": "string", + "display_text": "start" }, { "name": "stop", - "type": "string" + "type": "string", + "display_text": "stop" }, { "name": "sortby", @@ -15981,11 +16904,13 @@ { "name": "byscore", "type": "pure-token", + "display_text": "byscore", "token": "BYSCORE" }, { "name": "bylex", "type": "pure-token", + "display_text": "bylex", "token": "BYLEX" } ] @@ -15993,12 +16918,13 @@ { "name": "rev", "type": "pure-token", + "display_text": "rev", "token": "REV", "since": "6.2.0", "optional": true }, { - "name": "offset_count", + "name": "limit", "type": "block", "token": "LIMIT", "since": "6.2.0", @@ -16006,17 +16932,20 @@ "arguments": [ { "name": "offset", - "type": "integer" + "type": "integer", + "display_text": "offset" }, { "name": "count", - "type": "integer" + "type": "integer", + "display_text": "count" } ] }, { "name": "withscores", "type": "pure-token", + "display_text": "withscores", "token": "WITHSCORES", "optional": true } @@ -16062,29 +16991,34 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "min", - "type": "string" + "type": "string", + "display_text": "min" }, { "name": "max", - "type": "string" + "type": "string", + "display_text": "max" }, { - "name": "offset_count", + "name": "limit", "type": "block", "token": "LIMIT", "optional": true, "arguments": [ { "name": "offset", - "type": "integer" + "type": "integer", + "display_text": "offset" }, { "name": "count", - "type": "integer" + "type": "integer", + "display_text": "count" } ] } @@ -16139,36 +17073,42 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "min", - "type": "double" + "type": "double", + "display_text": "min" }, { "name": "max", - "type": "double" + "type": "double", + "display_text": "max" }, { "name": "withscores", "type": "pure-token", + "display_text": "withscores", "token": "WITHSCORES", "since": "2.0.0", "optional": true }, { - "name": "offset_count", + "name": "limit", "type": "block", "token": "LIMIT", "optional": true, "arguments": [ { "name": "offset", - "type": "integer" + "type": "integer", + "display_text": "offset" }, { "name": "count", - "type": "integer" + "type": "integer", + "display_text": "count" } ] } @@ -16233,20 +17173,24 @@ { "name": "dst", "type": "key", + "display_text": "dst", "key_spec_index": 0 }, { "name": "src", "type": "key", + "display_text": "src", "key_spec_index": 1 }, { "name": "min", - "type": "string" + "type": "string", + "display_text": "min" }, { "name": "max", - "type": "string" + "type": "string", + "display_text": "max" }, { "name": "sortby", @@ -16256,11 +17200,13 @@ { "name": "byscore", "type": "pure-token", + "display_text": "byscore", "token": "BYSCORE" }, { "name": "bylex", "type": "pure-token", + "display_text": "bylex", "token": "BYLEX" } ] @@ -16268,22 +17214,25 @@ { "name": "rev", "type": "pure-token", + "display_text": "rev", "token": "REV", "optional": true }, { - "name": "offset_count", + "name": "limit", "type": "block", "token": "LIMIT", "optional": true, "arguments": [ { "name": "offset", - "type": "integer" + "type": "integer", + "display_text": "offset" }, { "name": "count", - "type": "integer" + "type": "integer", + "display_text": "count" } ] } @@ -16298,12 +17247,18 @@ "since": "2.0.0", "group": "sorted-set", "complexity": "O(log(N))", + "history": [ + [ + "7.2.0", + "Added the optional `WITHSCORE` argument." + ] + ], "acl_categories": [ "@read", "@sortedset", "@fast" ], - "arity": 3, + "arity": -3, "key_specs": [ { "begin_search": { @@ -16328,11 +17283,20 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "member", - "type": "string" + "type": "string", + "display_text": "member" + }, + { + "name": "withscore", + "type": "pure-token", + "display_text": "withscore", + "token": "WITHSCORE", + "optional": true } ], "command_flags": [ @@ -16381,11 +17345,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "member", "type": "string", + "display_text": "member", "multiple": true } ], @@ -16429,15 +17395,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "min", - "type": "string" + "type": "string", + "display_text": "min" }, { "name": "max", - "type": "string" + "type": "string", + "display_text": "max" } ], "command_flags": [ @@ -16479,15 +17448,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "start", - "type": "integer" + "type": "integer", + "display_text": "start" }, { "name": "stop", - "type": "integer" + "type": "integer", + "display_text": "stop" } ], "command_flags": [ @@ -16529,15 +17501,18 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "min", - "type": "double" + "type": "double", + "display_text": "min" }, { "name": "max", - "type": "double" + "type": "double", + "display_text": "max" } ], "command_flags": [ @@ -16581,19 +17556,23 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "start", - "type": "integer" + "type": "integer", + "display_text": "start" }, { "name": "stop", - "type": "integer" + "type": "integer", + "display_text": "stop" }, { "name": "withscores", "type": "pure-token", + "display_text": "withscores", "token": "WITHSCORES", "optional": true } @@ -16642,29 +17621,34 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "max", - "type": "string" + "type": "string", + "display_text": "max" }, { "name": "min", - "type": "string" + "type": "string", + "display_text": "min" }, { - "name": "offset_count", + "name": "limit", "type": "block", "token": "LIMIT", "optional": true, "arguments": [ { "name": "offset", - "type": "integer" + "type": "integer", + "display_text": "offset" }, { "name": "count", - "type": "integer" + "type": "integer", + "display_text": "count" } ] } @@ -16719,35 +17703,41 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "max", - "type": "double" + "type": "double", + "display_text": "max" }, { "name": "min", - "type": "double" + "type": "double", + "display_text": "min" }, { "name": "withscores", "type": "pure-token", + "display_text": "withscores", "token": "WITHSCORES", "optional": true }, { - "name": "offset_count", + "name": "limit", "type": "block", "token": "LIMIT", "optional": true, "arguments": [ { "name": "offset", - "type": "integer" + "type": "integer", + "display_text": "offset" }, { "name": "count", - "type": "integer" + "type": "integer", + "display_text": "count" } ] } @@ -16764,12 +17754,18 @@ "since": "2.0.0", "group": "sorted-set", "complexity": "O(log(N))", + "history": [ + [ + "7.2.0", + "Added the optional `WITHSCORE` argument." + ] + ], "acl_categories": [ "@read", "@sortedset", "@fast" ], - "arity": 3, + "arity": -3, "key_specs": [ { "begin_search": { @@ -16794,11 +17790,20 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "member", - "type": "string" + "type": "string", + "display_text": "member" + }, + { + "name": "withscore", + "type": "pure-token", + "display_text": "withscore", + "token": "WITHSCORE", + "optional": true } ], "command_flags": [ @@ -16810,7 +17815,7 @@ "summary": "Incrementally iterate sorted sets elements and associated scores", "since": "2.8.0", "group": "sorted-set", - "complexity": "O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..", + "complexity": "O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection.", "acl_categories": [ "@read", "@sortedset", @@ -16841,21 +17846,25 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "cursor", - "type": "integer" + "type": "integer", + "display_text": "cursor" }, { "name": "pattern", "type": "pattern", + "display_text": "pattern", "token": "MATCH", "optional": true }, { "name": "count", "type": "integer", + "display_text": "count", "token": "COUNT", "optional": true } @@ -16902,11 +17911,13 @@ { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0 }, { "name": "member", - "type": "string" + "type": "string", + "display_text": "member" } ], "command_flags": [ @@ -16948,17 +17959,20 @@ "arguments": [ { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 0, "multiple": true }, { "name": "weight", "type": "integer", + "display_text": "weight", "token": "WEIGHTS", "optional": true, "multiple": true @@ -16972,16 +17986,19 @@ { "name": "sum", "type": "pure-token", + "display_text": "sum", "token": "SUM" }, { "name": "min", "type": "pure-token", + "display_text": "min", "token": "MIN" }, { "name": "max", "type": "pure-token", + "display_text": "max", "token": "MAX" } ] @@ -16989,6 +18006,7 @@ { "name": "withscores", "type": "pure-token", + "display_text": "withscores", "token": "WITHSCORES", "optional": true } @@ -17051,21 +18069,25 @@ { "name": "destination", "type": "key", + "display_text": "destination", "key_spec_index": 0 }, { "name": "numkeys", - "type": "integer" + "type": "integer", + "display_text": "numkeys" }, { "name": "key", "type": "key", + "display_text": "key", "key_spec_index": 1, "multiple": true }, { "name": "weight", "type": "integer", + "display_text": "weight", "token": "WEIGHTS", "optional": true, "multiple": true @@ -17079,16 +18101,19 @@ { "name": "sum", "type": "pure-token", + "display_text": "sum", "token": "SUM" }, { "name": "min", "type": "pure-token", + "display_text": "min", "token": "MIN" }, { "name": "max", "type": "pure-token", + "display_text": "max", "token": "MAX" } ] From a4d3480b1f8dc38cc40c82fd40eeb90f23edb18f Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Wed, 15 Feb 2023 19:21:32 +0200 Subject: [PATCH 144/377] Fixes #2324 (#2326) --- docs/getting-started/installation/install-redis-from-source.md | 2 +- docs/getting-started/installation/install-redis-on-mac-os.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/getting-started/installation/install-redis-from-source.md b/docs/getting-started/installation/install-redis-from-source.md index 769d84b4ca..0fba3a2250 100644 --- a/docs/getting-started/installation/install-redis-from-source.md +++ b/docs/getting-started/installation/install-redis-from-source.md @@ -10,7 +10,7 @@ You can compile and install Redis from source on variety of platforms and operat ## Downloading the source files -The Redis source files are available on [this site's Download page]. You can verify the integrity of these downloads by checking them against the digests in the [redis-hashes git repository](https://github.com/redis/redis-hashes). +The Redis source files are available on [this site's Download page](/download/). You can verify the integrity of these downloads by checking them against the digests in the [redis-hashes git repository](https://github.com/redis/redis-hashes). To obtain the source files for the latest stable version of Redis from the Redis downloads site, run: diff --git a/docs/getting-started/installation/install-redis-on-mac-os.md b/docs/getting-started/installation/install-redis-on-mac-os.md index 71d9ca2c92..37c6f95fa3 100644 --- a/docs/getting-started/installation/install-redis-on-mac-os.md +++ b/docs/getting-started/installation/install-redis-on-mac-os.md @@ -5,7 +5,7 @@ weight: 1 description: Use Homebrew to install and start Redis on macOS --- -This guide shows you how to install Redis on macOS using Homebrew. Homebrew is the easiest way to install Redis on macOS. If you'd prefer to build Redis from the source files on macOS, see [Installing Redis from Source]. +This guide shows you how to install Redis on macOS using Homebrew. Homebrew is the easiest way to install Redis on macOS. If you'd prefer to build Redis from the source files on macOS, see [Installing Redis from Source](../install-redis-from-source). ## Prerequisites From 2e2468d6a8978907e1a84de7a016effd23240467 Mon Sep 17 00:00:00 2001 From: enjoy-binbin Date: Wed, 22 Feb 2023 18:23:00 +0800 Subject: [PATCH 145/377] Fix CLUSTER SHARDS example, empty hostname will not be displayed It was fixed in 7.0.6, see redis/redis#11297 --- commands/cluster-shards.md | 84 ++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 48 deletions(-) diff --git a/commands/cluster-shards.md b/commands/cluster-shards.md index bcafe027fd..8d79b34239 100644 --- a/commands/cluster-shards.md +++ b/commands/cluster-shards.md @@ -66,14 +66,12 @@ Which endpoint is set is determined by the `cluster-preferred-endpoint-type` con 6) "127.0.0.1" 7) "endpoint" 8) "127.0.0.1" - 9) "hostname" - 10) "" - 11) "role" - 12) "master" - 13) "replication-offset" - 14) (integer) 72156 - 15) "health" - 16) "online" + 9) "role" + 10) "master" + 11) "replication-offset" + 12) (integer) 72156 + 13) "health" + 14) "online" 2) 1) "id" 2) "1901f5962d865341e81c85f9f596b1e7160c35ce" 3) "port" @@ -82,14 +80,12 @@ Which endpoint is set is determined by the `cluster-preferred-endpoint-type` con 6) "127.0.0.1" 7) "endpoint" 8) "127.0.0.1" - 9) "hostname" - 10) "" - 11) "role" - 12) "replica" - 13) "replication-offset" - 14) (integer) 72156 - 15) "health" - 16) "online" + 9) "role" + 10) "replica" + 11) "replication-offset" + 12) (integer) 72156 + 13) "health" + 14) "online" 2) 1) "slots" 2) 1) (integer) 10923 2) (integer) 16383 @@ -102,14 +98,12 @@ Which endpoint is set is determined by the `cluster-preferred-endpoint-type` con 6) "127.0.0.1" 7) "endpoint" 8) "127.0.0.1" - 9) "hostname" - 10) "" - 11) "role" - 12) "master" - 13) "replication-offset" - 14) (integer) 72156 - 15) "health" - 16) "online" + 9) "role" + 10) "master" + 11) "replication-offset" + 12) (integer) 72156 + 13) "health" + 14) "online" 2) 1) "id" 2) "6daa25c08025a0c7e4cc0d1ab255949ce6cee902" 3) "port" @@ -118,14 +112,12 @@ Which endpoint is set is determined by the `cluster-preferred-endpoint-type` con 6) "127.0.0.1" 7) "endpoint" 8) "127.0.0.1" - 9) "hostname" - 10) "" - 11) "role" - 12) "replica" - 13) "replication-offset" - 14) (integer) 72156 - 15) "health" - 16) "online" + 9) "role" + 10) "replica" + 11) "replication-offset" + 12) (integer) 72156 + 13) "health" + 14) "online" 3) 1) "slots" 2) 1) (integer) 5461 2) (integer) 10922 @@ -138,14 +130,12 @@ Which endpoint is set is determined by the `cluster-preferred-endpoint-type` con 6) "127.0.0.1" 7) "endpoint" 8) "127.0.0.1" - 9) "hostname" - 10) "" - 11) "role" - 12) "master" - 13) "replication-offset" - 14) (integer) 72156 - 15) "health" - 16) "online" + 9) "role" + 10) "master" + 11) "replication-offset" + 12) (integer) 72156 + 13) "health" + 14) "online" 2) 1) "id" 2) "da6d5847aa019e9b9d2a8aa24a75f856fd3456cc" 3) "port" @@ -154,12 +144,10 @@ Which endpoint is set is determined by the `cluster-preferred-endpoint-type` con 6) "127.0.0.1" 7) "endpoint" 8) "127.0.0.1" - 9) "hostname" - 10) "" - 11) "role" - 12) "replica" - 13) "replication-offset" - 14) (integer) 72156 - 15) "health" - 16) "online" + 9) "role" + 10) "replica" + 11) "replication-offset" + 12) (integer) 72156 + 13) "health" + 14) "online" ``` \ No newline at end of file From 94bb6d18b7f14b4eb99da406f8993ef5e74a3ced Mon Sep 17 00:00:00 2001 From: Ning Xie Date: Thu, 23 Feb 2023 08:29:10 +0800 Subject: [PATCH 146/377] Clarify description of STREAMS in XREAD (#2150) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explain what it means that the STREAMS option in XREAD must be "the last one". Co-authored-by: Viktor Söderqvist --- docs/data-types/streams-tutorial.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/data-types/streams-tutorial.md b/docs/data-types/streams-tutorial.md index 35e9241adb..01f171dea3 100644 --- a/docs/data-types/streams-tutorial.md +++ b/docs/data-types/streams-tutorial.md @@ -169,7 +169,8 @@ The command that provides the ability to listen for new messages arriving into a The above is the non-blocking form of `XREAD`. Note that the **COUNT** option is not mandatory, in fact the only mandatory option of the command is the **STREAMS** option, that specifies a list of keys together with the corresponding maximum ID already seen for each stream by the calling consumer, so that the command will provide the client only with messages with an ID greater than the one we specified. -In the above command we wrote `STREAMS mystream 0` so we want all the messages in the Stream `mystream` having an ID greater than `0-0`. As you can see in the example above, the command returns the key name, because actually it is possible to call this command with more than one key to read from different streams at the same time. I could write, for instance: `STREAMS mystream otherstream 0 0`. Note how after the **STREAMS** option we need to provide the key names, and later the IDs. For this reason, the **STREAMS** option must always be the last one. +In the above command we wrote `STREAMS mystream 0` so we want all the messages in the Stream `mystream` having an ID greater than `0-0`. As you can see in the example above, the command returns the key name, because actually it is possible to call this command with more than one key to read from different streams at the same time. I could write, for instance: `STREAMS mystream otherstream 0 0`. Note how after the **STREAMS** option we need to provide the key names, and later the IDs. For this reason, the **STREAMS** option must always be the last option. +Any other options must come before the **STREAMS** option. Apart from the fact that `XREAD` can access multiple streams at once, and that we are able to specify the last ID we own to just get newer messages, in this simple form the command is not doing something so different compared to `XRANGE`. However, the interesting part is that we can turn `XREAD` into a *blocking command* easily, by specifying the **BLOCK** argument: From 5efad36d4907cf4940284a2faca8a18fc77a5b70 Mon Sep 17 00:00:00 2001 From: impocode <109408819+impocode@users.noreply.github.com> Date: Mon, 30 Jan 2023 17:21:02 +0500 Subject: [PATCH 147/377] Remove extra spaces --- docs/about/governance.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/about/governance.md b/docs/about/governance.md index 8c10badf77..879f109eb7 100644 --- a/docs/about/governance.md +++ b/docs/about/governance.md @@ -57,11 +57,11 @@ The core team aims to form and empower a community of contributors by further de * Day-to-day approval of pull requests and closing issues * Opening new issues for discussion * **Major decisions** that have a significant impact on the Redis architecture, design, or philosophy as well as core-team structure or membership changes should preferably be determined by full consensus. If the team is not able to achieve a full consensus, a majority vote is required. Examples of major decisions: - * Fundamental changes to the Redis core - * Adding a new data structure - * Creating a new version of RESP (Redis Serialization Protocol) - * Changes that affect backward compatibility - * Adding or changing core team members + * Fundamental changes to the Redis core + * Adding a new data structure + * Creating a new version of RESP (Redis Serialization Protocol) + * Changes that affect backward compatibility + * Adding or changing core team members * Project leads have a right to veto major decisions #### Core team membership From 73104634f912320d61c88ca5d36b8e36f5f52b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20S=C3=B6derqvist?= Date: Thu, 23 Feb 2023 14:47:32 +0100 Subject: [PATCH 148/377] Notes on what *SUBSCRIBE returns (or doesn't return) (#2327) Add return info to *subscribe and *unsubscribe commands. Add some notes about RESP3. --- commands/psubscribe.md | 14 ++++++++++++++ commands/punsubscribe.md | 5 +++++ commands/ssubscribe.md | 6 ++++++ commands/subscribe.md | 10 +++++++++- commands/sunsubscribe.md | 5 +++++ commands/unsubscribe.md | 5 +++++ 6 files changed, 44 insertions(+), 1 deletion(-) diff --git a/commands/psubscribe.md b/commands/psubscribe.md index 81c4bbafb0..e18d910b37 100644 --- a/commands/psubscribe.md +++ b/commands/psubscribe.md @@ -7,3 +7,17 @@ Supported glob-style patterns: * `h[ae]llo` subscribes to `hello` and `hallo,` but not `hillo` Use `\` to escape special characters if you want to match them verbatim. + +Once the client enters the subscribed state it is not supposed to issue any other commands, except for additional `SUBSCRIBE`, `SSUBSCRIBE`, `PSUBSCRIBE`, `UNSUBSCRIBE`, `SUNSUBSCRIBE`, `PUNSUBSCRIBE`, `PING`, `RESET` and `QUIT` commands. +However, if RESP3 is used (see `HELLO`) it is possible for a client to issue any commands while in subscribed state. + +For more information, see [Pub/sub](/docs/manual/pubsub/). + +@return + +When successful, this command doesn't return anything. +Instead, for each pattern, one message with the first element being the string "psubscribe" is pushed as a confirmation that the command succeeded. + +## Behavior change history + +* `>= 6.2.0`: `RESET` can be called to exit subscribed state. diff --git a/commands/punsubscribe.md b/commands/punsubscribe.md index af8ee7e021..65045f60e2 100644 --- a/commands/punsubscribe.md +++ b/commands/punsubscribe.md @@ -5,3 +5,8 @@ When no patterns are specified, the client is unsubscribed from all the previously subscribed patterns. In this case, a message for every unsubscribed pattern will be sent to the client. + +@return + +When successful, this command doesn't return anything. +Instead, for each pattern, one message with the first element being the string "punsubscribe" is pushed as a confirmation that the command succeeded. diff --git a/commands/ssubscribe.md b/commands/ssubscribe.md index bf7d30e859..71c975cb7e 100644 --- a/commands/ssubscribe.md +++ b/commands/ssubscribe.md @@ -7,6 +7,12 @@ A client can subscribe to channels across different slots over separate `SSUBSCR For more information about sharded Pub/Sub, see [Sharded Pub/Sub](/topics/pubsub#sharded-pubsub). +@return + +When successful, this command doesn't return anything. +Instead, for each shard channel, one message with the first element being the string "ssubscribe" is pushed as a confirmation that the command succeeded. +Note that this command can also return a -MOVED redirect. + @examples ``` diff --git a/commands/subscribe.md b/commands/subscribe.md index bbc71272f9..39e21b2bd1 100644 --- a/commands/subscribe.md +++ b/commands/subscribe.md @@ -3,7 +3,15 @@ Subscribes the client to the specified channels. Once the client enters the subscribed state it is not supposed to issue any other commands, except for additional `SUBSCRIBE`, `SSUBSCRIBE`, `PSUBSCRIBE`, `UNSUBSCRIBE`, `SUNSUBSCRIBE`, `PUNSUBSCRIBE`, `PING`, `RESET` and `QUIT` commands. +However, if RESP3 is used (see `HELLO`) it is possible for a client to issue any commands while in subscribed state. + +For more information, see [Pub/sub](/docs/manual/pubsub/). + +@return + +When successful, this command doesn't return anything. +Instead, for each channel, one message with the first element being the string "subscribe" is pushed as a confirmation that the command succeeded. ## Behavior change history -* `>= 6.2.0`: `RESET` can be called to exit subscribed state. \ No newline at end of file +* `>= 6.2.0`: `RESET` can be called to exit subscribed state. diff --git a/commands/sunsubscribe.md b/commands/sunsubscribe.md index 7ce76c333e..36dc8d9a40 100644 --- a/commands/sunsubscribe.md +++ b/commands/sunsubscribe.md @@ -6,3 +6,8 @@ In this case a message for every unsubscribed shard channel will be sent to the Note: The global channels and shard channels needs to be unsubscribed from separately. For more information about sharded Pub/Sub, see [Sharded Pub/Sub](/topics/pubsub#sharded-pubsub). + +@return + +When successful, this command doesn't return anything. +Instead, for each shard channel, one message with the first element being the string "sunsubscribe" is pushed as a confirmation that the command succeeded. diff --git a/commands/unsubscribe.md b/commands/unsubscribe.md index 7bdf1d15e5..e5f53a0e9c 100644 --- a/commands/unsubscribe.md +++ b/commands/unsubscribe.md @@ -5,3 +5,8 @@ When no channels are specified, the client is unsubscribed from all the previously subscribed channels. In this case, a message for every unsubscribed channel will be sent to the client. + +@return + +When successful, this command doesn't return anything. +Instead, for each channel, one message with the first element being the string "unsubscribe" is pushed as a confirmation that the command succeeded. From d8e5a07b0da5cebbbeb3fcfdb34119a5a31f0e1d Mon Sep 17 00:00:00 2001 From: NAM UK KIM Date: Fri, 24 Feb 2023 18:36:13 +0900 Subject: [PATCH 149/377] Clarify note about redis-cli in subscribed mode (#2329) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the pub/sub manual, explicitly mention that UNSUBSCRIBE and PUNSUBSCRIBE cannot be used in redis-cli in subscribed mode (because no commands can be used). Related: redis/redis#11807 Signed-off-by: namuk2004 Co-authored-by: Binbin Co-authored-by: Viktor Söderqvist --- docs/manual/pubsub.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/manual/pubsub.md b/docs/manual/pubsub.md index eb18120a11..71461a2bc7 100644 --- a/docs/manual/pubsub.md +++ b/docs/manual/pubsub.md @@ -38,8 +38,9 @@ stream of messages where the first element indicates the type of message. The commands that are allowed in the context of a subscribed client are `SUBSCRIBE`, `SSUBSCRIBE`, `SUNSUBSCRIBE`, `PSUBSCRIBE`, `UNSUBSCRIBE`, `PUNSUBSCRIBE`, `PING`, `RESET`, and `QUIT`. -Please note that `redis-cli` will not accept any commands once in -subscribed mode and can only quit the mode with `Ctrl-C`. +Please note that when using `redis-cli`, in subscribed mode +commands such as `UNSUBSCRIBE` and `PUNSUBSCRIBE` cannot be used because +`redis-cli` will not accept any commands and can only quit the mode with `Ctrl-C`. ## Format of pushed messages From 0bc34278efa31a5941125fa1489a1a80b2b0a7a7 Mon Sep 17 00:00:00 2001 From: hexcowboy Date: Tue, 31 Jan 2023 14:41:04 -0700 Subject: [PATCH 150/377] Update distributed-locks.md --- docs/manual/patterns/distributed-locks.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/manual/patterns/distributed-locks.md b/docs/manual/patterns/distributed-locks.md index 01aa057b91..603e0e91fc 100644 --- a/docs/manual/patterns/distributed-locks.md +++ b/docs/manual/patterns/distributed-locks.md @@ -50,6 +50,7 @@ already available that can be used for reference. * [Redlock4Net](https://github.com/LiZhenNet/Redlock4Net) (C# .NET implementation). * [node-redlock](https://github.com/mike-marcacci/node-redlock) (NodeJS implementation). Includes support for lock extension. * [Deno DLM](https://github.com/oslabs-beta/Deno-Redlock) (Deno implementation) +* [Rslock](https://github.com/hexcowboy/rslock) (Rust implementation). Includes async and lock extension support. ## Safety and Liveness Guarantees From 3f336d2b1f81a1657891db46d00c772f1967223e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Catanzariti?= Date: Wed, 1 Mar 2023 11:29:10 +0100 Subject: [PATCH 151/377] Added RedisCBOR module (#2338) --- .../github.com/dahomey-technologies/RedisCBOR.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 modules/community/github.com/dahomey-technologies/RedisCBOR.json diff --git a/modules/community/github.com/dahomey-technologies/RedisCBOR.json b/modules/community/github.com/dahomey-technologies/RedisCBOR.json new file mode 100644 index 0000000000..db5f34edd0 --- /dev/null +++ b/modules/community/github.com/dahomey-technologies/RedisCBOR.json @@ -0,0 +1,8 @@ +{ + "name": "RedisCBOR", + "license": "MIT", + "description": "A CBOR data type for Redis", + "github": [ + "dahomey-technologies" + ] +} From ef66d1c5e228336a49eb4a802d49c96f58d0e94b Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Wed, 1 Mar 2023 12:37:25 +0200 Subject: [PATCH 152/377] Update wordlist --- wordlist | 1 + 1 file changed, 1 insertion(+) diff --git a/wordlist b/wordlist index 3d99006a91..fff03ba01f 100644 --- a/wordlist +++ b/wordlist @@ -334,6 +334,7 @@ Retwis-J Retwis-RB Roshi Rx/Tx +Rslock S1 S2 S3 From 09f4e705da63df16356d4ce99c1b599b0be8992d Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Wed, 1 Mar 2023 16:41:11 +0200 Subject: [PATCH 153/377] Edits and mentions CONFIG RESETSTAT (#2340) --- commands/config-resetstat.md | 16 +++++++--------- commands/latency-histogram.md | 33 +++++++++++++++++++-------------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/commands/config-resetstat.md b/commands/config-resetstat.md index cb0232b4e7..be5dee9ebc 100644 --- a/commands/config-resetstat.md +++ b/commands/config-resetstat.md @@ -1,15 +1,13 @@ -Resets the statistics reported by Redis using the `INFO` command. +Resets the statistics reported by Redis using the `INFO` and `LATENCY HISTOGRAM` commands. -These are the counters that are reset: +The following is a non-exhaustive list of values that are reset: -* Keyspace hits -* Keyspace misses -* Number of commands processed -* Number of connections received +* Keyspace hits and misses * Number of expired keys -* Number of rejected connections -* Latest fork(2) time -* The `aof_delayed_fsync` counter +* Command and error statistics +* Connections received, rejected and evicted +* Persistence statistics +* Active defragmentation statistics @return diff --git a/commands/latency-histogram.md b/commands/latency-histogram.md index a97928b614..02496acf31 100644 --- a/commands/latency-histogram.md +++ b/commands/latency-histogram.md @@ -1,20 +1,24 @@ -The `LATENCY HISTOGRAM` command reports a cumulative distribution of latencies in the format of a histogram for each of the specified command names. -If no command names are specified then all commands that contain latency information will be replied. +`LATENCY HISTOGRAM` returns a cumulative distribution of commands' latencies in histogram format. -Each reported histogram has the following fields: +By default, all available latency histograms are returned. +You can filter the reply by providing specific command names. -* Command name. -* The total calls for that command. +Each histogram consists of the following fields: + +* Command name +* The total calls for that command * A map of time buckets: - * Each bucket represents a latency range. - * Each bucket covers twice the previous bucket's range. - * Empty buckets are not printed. - * The tracked latencies are between 1 microsecond and roughly 1 second. - * Everything above 1 sec is considered +Inf. - * At max there will be log2(1000000000)=30 buckets. + * Each bucket represents a latency range + * Each bucket covers twice the previous bucket's range + * Empty buckets are excluded from the reply + * The tracked latencies are between 1 microsecond and roughly 1 second + * Everything above 1 second is considered +Inf + * At max, there will be log2(1,000,000,000)=30 buckets + +This command requires the extended latency monitoring feature to be enabled, which is the default. +If you need to enable it, call `CONFIG SET latency-tracking yes`. -This command requires the extended latency monitoring feature to be enabled (by default it's enabled). -If you need to enable it, use `CONFIG SET latency-tracking yes`. +To delete the latency histograms' data use the `CONFIG RESETSTAT` command. @examples @@ -35,4 +39,5 @@ If you need to enable it, use `CONFIG SET latency-tracking yes`. @array-reply: specifically: -The command returns a map where each key is a command name, and each value is a map with the total calls, and an inner map of the histogram time buckets. +The command returns a map where each key is a command name. +The value is a map with a key for the total calls, and a map of the histogram time buckets. From e621c7918bb46b620a9dee2f6bf58ef8d020e6d4 Mon Sep 17 00:00:00 2001 From: Bjorn Svensson Date: Sun, 12 Mar 2023 12:36:12 +0100 Subject: [PATCH 154/377] Use correct link to the RESP3 specification (#2350) --- commands/hello.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/hello.md b/commands/hello.md index 3eb6597389..776fd814f3 100644 --- a/commands/hello.md +++ b/commands/hello.md @@ -7,7 +7,7 @@ when the connection is in this mode, Redis is able to reply with more semantical replies: for instance, `HGETALL` will return a *map type*, so a client library implementation no longer requires to know in advance to translate the array into a hash before returning it to the caller. For a full coverage of RESP3, please -[check this repository](https://github.com/antirez/resp3). +check the [RESP3 specification](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md). In Redis 6 connections start in RESP2 mode, so clients implementing RESP2 do not need to updated or changed. There are no short term plans to drop support for From 61c4cf0e690e493c2ac6dd8a3bf56477afbfe69b Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Wed, 15 Mar 2023 03:22:50 +0800 Subject: [PATCH 155/377] Fix Typo (#2349) --- commands/auth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/auth.md b/commands/auth.md index 7c1e02a800..5062718f69 100644 --- a/commands/auth.md +++ b/commands/auth.md @@ -1,7 +1,7 @@ The AUTH command authenticates the current connection in two cases: 1. If the Redis server is password protected via the `requirepass` option. -2. If a Redis 6.0 instance, or greater, is using the [Redis ACL system](/topics/acl). +2. A Redis 6.0 instance, or greater, is using the [Redis ACL system](/topics/acl). Redis versions prior of Redis 6 were only able to understand the one argument version of the command: From 97cf00b560c27275c99cd5a58ffc0ae94c587fd4 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Wed, 15 Mar 2023 13:12:33 +0200 Subject: [PATCH 156/377] Update lua-api.md --- docs/manual/programmability/lua-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/programmability/lua-api.md b/docs/manual/programmability/lua-api.md index 39ca8b0c0b..fc7c17d6d0 100644 --- a/docs/manual/programmability/lua-api.md +++ b/docs/manual/programmability/lua-api.md @@ -624,7 +624,7 @@ Once Redis' replies are in RESP3 protocol, all of the [RESP2 to Lua conversion]( * [RESP3 null](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#null-reply) -> Lua `nil`. * [RESP3 true reply](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#boolean-reply) -> Lua true boolean value. * [RESP3 false reply](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#boolean-reply) -> Lua false boolean value. -* [RESP3 double reply](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#double-type) -> Lua table with a single _score_ field containing a Lua number representing the double value. +* [RESP3 double reply](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#double-type) -> Lua table with a single _double_ field containing a Lua number representing the double value. * [RESP3 big number reply](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#big-number-type) -> Lua table with a single _big_number_ field containing a Lua string representing the big number value. * [Redis verbatim string reply](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#verbatim-string-type) -> Lua table with a single _verbatim_string_ field containing a Lua table with two fields, _string_ and _format_, representing the verbatim string and its format, respectively. From f5f3d248d7dde37ed6d6f0b45976b6ea712fba48 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Wed, 15 Mar 2023 15:06:13 +0200 Subject: [PATCH 157/377] Update lua-api.md --- docs/manual/programmability/lua-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/programmability/lua-api.md b/docs/manual/programmability/lua-api.md index fc7c17d6d0..2add93ae46 100644 --- a/docs/manual/programmability/lua-api.md +++ b/docs/manual/programmability/lua-api.md @@ -639,7 +639,7 @@ Although the default protocol for incoming client connections is RESP2, the scri * Lua Boolean -> [RESP3 Boolean reply](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#boolean-reply) (note that this is a change compared to the RESP2, in which returning a Boolean Lua `true` returned the number 1 to the Redis client, and returning a `false` used to return a `null`. * Lua table with a single _map_ field set to an associative Lua table -> [RESP3 map reply](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#map-type). -* Lua table with a single _set field set to an associative Lua table -> [RESP3 set reply](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#set-type). Values can be set to anything and are discarded anyway. +* Lua table with a single _set_ field set to an associative Lua table -> [RESP3 set reply](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#set-type). Values can be set to anything and are discarded anyway. * Lua table with a single _double_ field to an associative Lua table -> [RESP3 double reply](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#double-type). * Lua nil -> [RESP3 null](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#null-reply). From 30a9781d1a6c1650c8758242ead50deb9da1bb4f Mon Sep 17 00:00:00 2001 From: Chayim Date: Wed, 15 Mar 2023 18:38:51 +0200 Subject: [PATCH 158/377] Redis State Machine (#2355) --- .../github.com/RedisStateMachine/RedisStateMachine.json | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 modules/community/github.com/RedisStateMachine/RedisStateMachine.json diff --git a/modules/community/github.com/RedisStateMachine/RedisStateMachine.json b/modules/community/github.com/RedisStateMachine/RedisStateMachine.json new file mode 100644 index 0000000000..2b2e3ac08e --- /dev/null +++ b/modules/community/github.com/RedisStateMachine/RedisStateMachine.json @@ -0,0 +1,9 @@ +{ + "name": "RedisStateMachine", + "license": "Redis Source Available License", + "description": "A module for storing state machines in", + "github": [ + "chayim", + "RedisLabs" + ] +} From d34102dc65a75fe36251ac7cc64eb6979bd1380c Mon Sep 17 00:00:00 2001 From: "PL \"karitham\" Pery" Date: Thu, 16 Mar 2023 12:39:41 +0100 Subject: [PATCH 159/377] fix typo (#2347) --- commands/lmove.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/lmove.md b/commands/lmove.md index ec62ced7ab..a35f177685 100644 --- a/commands/lmove.md +++ b/commands/lmove.md @@ -64,7 +64,7 @@ all the elements of an N-elements list, one after the other, in O(N) without transferring the full list from the server to the client using a single `LRANGE` operation. -The above pattern works even if the following two conditions: +The above pattern works even in the following conditions: * There are multiple clients rotating the list: they'll fetch different elements, until all the elements of the list are visited, and the process From 8ca956996817bcf960db0ceb98f3bd3626307c9b Mon Sep 17 00:00:00 2001 From: Binbin Date: Thu, 16 Mar 2023 19:40:04 +0800 Subject: [PATCH 160/377] Fix minor text inconsistency in key-specs (#2356) --- docs/reference/key-specs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/key-specs.md b/docs/reference/key-specs.md index 8bbc215f76..b911e9f42d 100644 --- a/docs/reference/key-specs.md +++ b/docs/reference/key-specs.md @@ -25,7 +25,7 @@ Even if the client encounters an unfamiliar type of key specification, it can al That said, most cluster-aware clients only require a single key name to perform correct command routing, so it is possible that although a command features one unfamiliar specification, its other specification may still be usable by the client. -Key specifications are maps with three keys: +Key specifications are maps with the following keys: 1. **begin_search:**: the starting index for keys' extraction. 2. **find_keys:** the rule for identifying the keys relative to the BS. From f475ba7f6dc86c52e1821b9d7ea18ea37383ed40 Mon Sep 17 00:00:00 2001 From: Binbin Date: Thu, 16 Mar 2023 20:04:16 +0800 Subject: [PATCH 161/377] Add more config related to momory-optimization (#2351) --- .../optimization/memory-optimization.md | 101 ++++++++++-------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/docs/management/optimization/memory-optimization.md b/docs/management/optimization/memory-optimization.md index 97e503381f..09cc105a06 100644 --- a/docs/management/optimization/memory-optimization.md +++ b/docs/management/optimization/memory-optimization.md @@ -12,21 +12,42 @@ aliases: [ ## Special encoding of small aggregate data types Since Redis 2.2 many data types are optimized to use less space up to a certain size. -Hashes, Lists, Sets composed of just integers, and Sorted Sets, when smaller than a given number of elements, and up to a maximum element size, are encoded in a very memory efficient way that uses *up to 10 times less memory* (with 5 time less memory used being the average saving). +Hashes, Lists, Sets composed of just integers, and Sorted Sets, when smaller than a given number of elements, and up to a maximum element size, are encoded in a very memory-efficient way that uses *up to 10 times less memory* (with 5 times less memory used being the average saving). This is completely transparent from the point of view of the user and API. -Since this is a CPU / memory trade off it is possible to tune the maximum +Since this is a CPU / memory tradeoff it is possible to tune the maximum number of elements and maximum element size for special encoded types -using the following redis.conf directives. +using the following redis.conf directives (defaults are shown): + +### Redis <= 6.2 ``` hash-max-ziplist-entries 512 hash-max-ziplist-value 64 -zset-max-ziplist-entries 128 +zset-max-ziplist-entries 128 zset-max-ziplist-value 64 set-max-intset-entries 512 ``` +### Redis >= 7.0 + +``` +hash-max-listpack-entries 512 +hash-max-listpack-value 64 +zset-max-listpack-entries 128 +zset-max-listpack-value 64 +set-max-intset-entries 512 +``` + +### Redis >= 7.2 + +The following directives are also available: + +``` +set-max-listpack-entries 128 +set-max-listpack-value 64 +``` + If a specially encoded value overflows the configured max size, Redis will automatically convert it into normal encoding. This operation is very fast for small values, @@ -34,63 +55,61 @@ but if you change the setting in order to use specially encoded values for much larger aggregate types the suggestion is to run some benchmarks and tests to check the conversion time. -## Using 32 bit instances +## Using 32-bit instances -Redis compiled with 32 bit target uses a lot less memory per key, since pointers are small, +When Redis is compiled as a 32-bit target, it uses a lot less memory per key, since pointers are small, but such an instance will be limited to 4 GB of maximum memory usage. -To compile Redis as 32 bit binary use *make 32bit*. -RDB and AOF files are compatible between 32 bit and 64 bit instances -(and between little and big endian of course) so you can switch from 32 to 64 bit, or the contrary, without problems. +To compile Redis as 32-bit binary use *make 32bit*. +RDB and AOF files are compatible between 32-bit and 64-bit instances +(and between little and big endian of course) so you can switch from 32 to 64-bit, or the contrary, without problems. ## Bit and byte level operations Redis 2.2 introduced new bit and byte level operations: `GETRANGE`, `SETRANGE`, `GETBIT` and `SETBIT`. Using these commands you can treat the Redis string type as a random access array. -For instance if you have an application where users are identified by a unique progressive integer number, -you can use a bitmap in order to save information about the subscription of users in a mailing list, +For instance, if you have an application where users are identified by a unique progressive integer number, +you can use a bitmap to save information about the subscription of users in a mailing list, setting the bit for subscribed and clearing it for unsubscribed, or the other way around. With 100 million users this data will take just 12 megabytes of RAM in a Redis instance. -You can do the same using `GETRANGE` and `SETRANGE` in order to store one byte of information for each user. -This is just an example but it is actually possible to model a number of problems in very little space with these new primitives. +You can do the same using `GETRANGE` and `SETRANGE` to store one byte of information for each user. +This is just an example but it is possible to model several problems in very little space with these new primitives. ## Use hashes when possible Small hashes are encoded in a very small space, so you should try representing your data using hashes whenever possible. -For instance if you have objects representing users in a web application, +For instance, if you have objects representing users in a web application, instead of using different keys for name, surname, email, password, use a single hash with all the required fields. If you want to know more about this, read the next section. -## Using hashes to abstract a very memory efficient plain key-value store on top of Redis +## Using hashes to abstract a very memory-efficient plain key-value store on top of Redis -I understand the title of this section is a bit scary, but I'm going to explain in details what this is about. +I understand the title of this section is a bit scary, but I'm going to explain in detail what this is about. Basically it is possible to model a plain key-value store using Redis -where values can just be just strings, that is not just more memory efficient +where values can just be just strings, which is not just more memory efficient than Redis plain keys but also much more memory efficient than memcached. Let's start with some facts: a few keys use a lot more memory than a single key containing a hash with a few fields. How is this possible? We use a trick. -In theory in order to guarantee that we perform lookups in constant time +In theory to guarantee that we perform lookups in constant time (also known as O(1) in big O notation) there is the need to use a data structure with a constant time complexity in the average case, like a hash table. But many times hashes contain just a few fields. When hashes are small we can instead just encode them in an O(N) data structure, like a linear -array with length-prefixed key value pairs. Since we do this only when N +array with length-prefixed key-value pairs. Since we do this only when N is small, the amortized time for `HGET` and `HSET` commands is still O(1): the hash will be converted into a real hash table as soon as the number of elements it contains grows too large (you can configure the limit in redis.conf). This does not only work well from the point of view of time complexity, but -also from the point of view of constant times, since a linear array of key -value pairs happens to play very well with the CPU cache (it has a better +also from the point of view of constant times since a linear array of key-value pairs happens to play very well with the CPU cache (it has a better cache locality than a hash table). -However since hash fields and values are not (always) represented as full -featured Redis objects, hash fields can't have an associated time to live +However since hash fields and values are not (always) represented as full-featured Redis objects, hash fields can't have an associated time to live (expire) like a real key, and can only contain a string. But we are okay with this, this was the intention anyway when the hash data type API was designed (we trust simplicity more than features, so nested data structures @@ -100,9 +119,8 @@ So hashes are memory efficient. This is useful when using hashes to represent objects or to model other problems when there are group of related fields. But what about if we have a plain key value business? -Imagine we want to use Redis as a cache for many small objects, that can be -JSON encoded objects, small HTML fragments, simple key -> boolean values -and so forth. Basically anything is a string -> string map with small keys +Imagine we want to use Redis as a cache for many small objects, which can be JSON encoded objects, small HTML fragments, simple key -> boolean values +and so forth. Basically, anything is a string -> string map with small keys and values. Now let's assume the objects we want to cache are numbered, like: @@ -113,7 +131,7 @@ Now let's assume the objects we want to cache are numbered, like: This is what we can do. Every time we perform a SET operation to set a new value, we actually split the key into two parts, -one part used as a key, and the other part used as the field name for the hash. For instance the +one part used as a key, and the other part used as the field name for the hash. For instance, the object named "object:1234" is actually split into: * a Key named object:12 @@ -127,14 +145,11 @@ command: HSET object:12 34 somevalue ``` -As you can see every hash will end containing 100 fields, that -is an optimal compromise between CPU and memory saved. +As you can see every hash will end up containing 100 fields, which is an optimal compromise between CPU and memory saved. There is another important thing to note, with this schema every hash will have more or -less 100 fields regardless of the number of objects we cached. This is since -our objects will always end with a number, and not a random string. In some -way the final number can be considered as a form of implicit pre-sharding. +less 100 fields regardless of the number of objects we cached. This is because our objects will always end with a number and not a random string. In some way, the final number can be considered as a form of implicit pre-sharding. What about small numbers? Like object:2? We handle this case using just "object:" as a key name, and the whole number as the hash field name. @@ -209,12 +224,11 @@ it will be converted into a real hash table, and the memory saving will be lost. You may ask, why don't you do this implicitly in the normal key space so that I don't have to care? There are two reasons: one is that we tend to make tradeoffs explicit, and this is a clear tradeoff between many things: CPU, -memory, max element size. The second is that the top level key space must +memory, and max element size. The second is that the top-level key space must support a lot of interesting things like expires, LRU data, and so forth so it is not practical to do this in a general way. -But the Redis Way is that the user must understand how things work so that -he is able to pick the best compromise, and to understand how the system will +But the Redis Way is that the user must understand how things work so that he can pick the best compromise and to understand how the system will behave exactly. ## Memory allocation @@ -228,34 +242,33 @@ There are a few things that should be noted about how Redis manages memory: * Redis will not always free up (return) memory to the OS when keys are removed. This is not something special about Redis, but it is how most malloc() implementations work. -For example if you fill an instance with 5GB worth of data, and then +For example, if you fill an instance with 5GB worth of data, and then remove the equivalent of 2GB of data, the Resident Set Size (also known as the RSS, which is the number of memory pages consumed by the process) will probably still be around 5GB, even if Redis will claim that the user memory is around 3GB. This happens because the underlying allocator can't easily release the memory. -For example often most of the removed keys were allocated in the same pages as the other keys that still exist. +For example, often most of the removed keys were allocated on the same pages as the other keys that still exist. * The previous point means that you need to provision memory based on your **peak memory usage**. If your workload from time to time requires 10GB, even if -most of the times 5GB could do, you need to provision for 10GB. +most of the time 5GB could do, you need to provision for 10GB. * However allocators are smart and are able to reuse free chunks of memory, -so after you freed 2GB of your 5GB data set, when you start adding more keys +so after you free 2GB of your 5GB data set, when you start adding more keys again, you'll see the RSS (Resident Set Size) stay steady and not grow more, as you add up to 2GB of additional keys. The allocator is basically trying to reuse the 2GB of memory previously (logically) freed. * Because of all this, the fragmentation ratio is not reliable when you -had a memory usage that at peak is much larger than the currently used memory. +had a memory usage that at the peak is much larger than the currently used memory. The fragmentation is calculated as the physical memory actually used (the RSS value) divided by the amount of memory currently in use (as the sum of all the allocations performed by Redis). Because the RSS reflects the peak memory, -when the (virtually) used memory is low since a lot of keys / values were -freed, but the RSS is high, the ratio `RSS / mem_used` will be very high. +when the (virtually) used memory is low since a lot of keys/values were freed, but the RSS is high, the ratio `RSS / mem_used` will be very high. If `maxmemory` is not set Redis will keep allocating memory as it sees fit and thus it can (gradually) eat up all your free memory. -Therefore it is generally advisable to configure some limit. You may also +Therefore it is generally advisable to configure some limits. You may also want to set `maxmemory-policy` to `noeviction` (which is *not* the default value in some older versions of Redis). -It makes Redis return an out of memory error for write commands if and when it reaches the +It makes Redis return an out-of-memory error for write commands if and when it reaches the limit - which in turn may result in errors in the application but will not render the whole machine dead because of memory starvation. From b3d163ae4df74c7052a6263d553f49a759f1eee6 Mon Sep 17 00:00:00 2001 From: agent-ai-consulting <127764692+agent-ai-consulting@users.noreply.github.com> Date: Thu, 16 Mar 2023 07:04:37 -0500 Subject: [PATCH 162/377] More inclusivity in prior knowledge assertions (#2352) --- docs/manual/patterns/twitter-clone.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/patterns/twitter-clone.md b/docs/manual/patterns/twitter-clone.md index f8d39d134e..3c710b27fb 100644 --- a/docs/manual/patterns/twitter-clone.md +++ b/docs/manual/patterns/twitter-clone.md @@ -19,7 +19,7 @@ data layout using Redis, and how to apply different data structures. Our Twitter clone, called [Retwis](https://github.com/antirez/retwis), is structurally simple, has very good performance, and can be distributed among any number of web and Redis servers with little efforts. [View the Retwis source code](https://github.com/antirez/retwis). -I used PHP for the example since it can be read by everybody. The same (or better) results can be obtained using Ruby, Python, Erlang, and so on. +I used PHP for the example because of its universal readability. The same (or better) results can be obtained using Ruby, Python, Erlang, and so on. A few clones exist (however not all the clones use the same data layout as the current version of this tutorial, so please, stick with the official PHP implementation for the sake of following the article better). From 87a6b5291168d5d2dc31bb4982a710a13b739342 Mon Sep 17 00:00:00 2001 From: Anton Ilyushenkov <274471+DriverX@users.noreply.github.com> Date: Thu, 16 Mar 2023 15:06:20 +0300 Subject: [PATCH 163/377] add Python aioredis-cluster client (#2348) --- clients/python/github.com/DriverX/aioredis-cluster.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 clients/python/github.com/DriverX/aioredis-cluster.json diff --git a/clients/python/github.com/DriverX/aioredis-cluster.json b/clients/python/github.com/DriverX/aioredis-cluster.json new file mode 100644 index 0000000000..c23469ec2d --- /dev/null +++ b/clients/python/github.com/DriverX/aioredis-cluster.json @@ -0,0 +1,4 @@ +{ + "name": "aioredis-cluster", + "description": "Redis Cluster client implementation based on aioredis v1.x.x" +} From 538e38e8321c84a7caeba06f2041bf65b0f27426 Mon Sep 17 00:00:00 2001 From: Paulo Tanaka Date: Thu, 16 Mar 2023 06:16:49 -0700 Subject: [PATCH 164/377] Update twitter-clone.md (#2346) Fixing typo --- docs/manual/patterns/twitter-clone.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/patterns/twitter-clone.md b/docs/manual/patterns/twitter-clone.md index 3c710b27fb..10693e9c24 100644 --- a/docs/manual/patterns/twitter-clone.md +++ b/docs/manual/patterns/twitter-clone.md @@ -152,7 +152,7 @@ The Hash data type --- This is the last data structure we use in our program, and is extremely easy -to gasp since there is an equivalent in almost every programming language out +to grasp since there is an equivalent in almost every programming language out there: Hashes. Redis Hashes are basically like Ruby or Python hashes, a collection of fields associated with values: From 591badb7675d38bcbf18bf083915b539b528aa93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20S=C3=B6derqvist?= Date: Thu, 16 Mar 2023 14:17:28 +0100 Subject: [PATCH 165/377] Add some Tools for data migration and rdb manipulation (#2345) --- tools/other/github.com/alibaba/RedisShake.json | 4 ++++ tools/other/github.com/leonchen83/redis-rdb-cli.json | 4 ++++ tools/other/github.com/redis-developer/riot.json | 4 ++++ 3 files changed, 12 insertions(+) create mode 100644 tools/other/github.com/alibaba/RedisShake.json create mode 100644 tools/other/github.com/leonchen83/redis-rdb-cli.json create mode 100644 tools/other/github.com/redis-developer/riot.json diff --git a/tools/other/github.com/alibaba/RedisShake.json b/tools/other/github.com/alibaba/RedisShake.json new file mode 100644 index 0000000000..2bfa7d5cb0 --- /dev/null +++ b/tools/other/github.com/alibaba/RedisShake.json @@ -0,0 +1,4 @@ +{ + "name": "redis-shake", + "description": "redis-shake is a tool for Redis data migration and data filtering." +} diff --git a/tools/other/github.com/leonchen83/redis-rdb-cli.json b/tools/other/github.com/leonchen83/redis-rdb-cli.json new file mode 100644 index 0000000000..659cace58b --- /dev/null +++ b/tools/other/github.com/leonchen83/redis-rdb-cli.json @@ -0,0 +1,4 @@ +{ + "name": "redis-rdb-cli", + "description": "A tool that can parse, filter, split, merge rdb and analyze memory usage offline. It can also sync 2 redis data and allow user define there own sink service to migrate redis data to somewhere." +} diff --git a/tools/other/github.com/redis-developer/riot.json b/tools/other/github.com/redis-developer/riot.json new file mode 100644 index 0000000000..c4a7d20d61 --- /dev/null +++ b/tools/other/github.com/redis-developer/riot.json @@ -0,0 +1,4 @@ +{ + "name": "RIOT", + "description": "Redis Input/Output Tools (RIOT) is a series of utilities designed to help you get data in and out of Redis." +} From 842994c02eb7aacc11b7ad31817709af5ed28cc4 Mon Sep 17 00:00:00 2001 From: jodersky Date: Thu, 16 Mar 2023 14:26:54 +0100 Subject: [PATCH 166/377] Add jodersky/redicl client (#2343) --- clients/scala/github.com/jodersky/redicl.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 clients/scala/github.com/jodersky/redicl.json diff --git a/clients/scala/github.com/jodersky/redicl.json b/clients/scala/github.com/jodersky/redicl.json new file mode 100644 index 0000000000..ffd4d45e88 --- /dev/null +++ b/clients/scala/github.com/jodersky/redicl.json @@ -0,0 +1,5 @@ +{ + "name": "redicl", + "description": "A lean and mean redis client implementation that uses only the Scala standard library. Available for the JVM and native.", + "homepage": "https://github.com/jodersky/redicl" +} From 314c029f134d60cd5bb790eaf1e040caab71b9cb Mon Sep 17 00:00:00 2001 From: JenkingWang <86818420+JenkingWang@users.noreply.github.com> Date: Thu, 16 Mar 2023 21:27:13 +0800 Subject: [PATCH 167/377] Update twitter-clone.md (#2342) --- docs/manual/patterns/twitter-clone.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/patterns/twitter-clone.md b/docs/manual/patterns/twitter-clone.md index 10693e9c24..b7d37e5792 100644 --- a/docs/manual/patterns/twitter-clone.md +++ b/docs/manual/patterns/twitter-clone.md @@ -217,7 +217,7 @@ We can add new followers with: ZADD followers:1000 1401267618 1234 => Add user 1234 with time 1401267618 -Another important thing we need is a place were we can add the updates to display in the user's home page. We'll need to access this data in chronological order later, from the most recent update to the oldest, so the perfect kind of data structure for this is a List. Basically every new update will be `LPUSH`ed in the user updates key, and thanks to `LRANGE`, we can implement pagination and so on. Note that we use the words _updates_ and _posts_ interchangeably, since updates are actually "little posts" in some way. +Another important thing we need is a place where we can add the updates to display in the user's home page. We'll need to access this data in chronological order later, from the most recent update to the oldest, so the perfect kind of data structure for this is a List. Basically every new update will be `LPUSH`ed in the user updates key, and thanks to `LRANGE`, we can implement pagination and so on. Note that we use the words _updates_ and _posts_ interchangeably, since updates are actually "little posts" in some way. posts:1000 => a List of post ids - every new post is LPUSHed here. From 1a2f1b653f4b0b421eb1b00085b6ebec810f2e48 Mon Sep 17 00:00:00 2001 From: Hanif Ariffin Date: Thu, 16 Mar 2023 21:38:11 +0800 Subject: [PATCH 168/377] Simplify SETEX command to use SET as the comparison instead of command transaction (#2214) --- commands/setex.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/commands/setex.md b/commands/setex.md index 7bebf45fda..f0d89d8b6d 100644 --- a/commands/setex.md +++ b/commands/setex.md @@ -1,16 +1,11 @@ Set `key` to hold the string `value` and set `key` to timeout after a given number of seconds. -This command is equivalent to executing the following commands: +This command is equivalent to: ``` -SET mykey value -EXPIRE mykey seconds +SET key value EX seconds ``` -`SETEX` is atomic, and can be reproduced by using the previous two commands -inside an `MULTI` / `EXEC` block. -It is provided as a faster alternative to the given sequence of operations, -because this operation is very common when Redis is used as a cache. An error is returned when `seconds` is invalid. From f9af4b0368851408c0a3444ed3f38bce1e214a75 Mon Sep 17 00:00:00 2001 From: Slava Koyfman Date: Wed, 22 Mar 2023 08:49:21 +0200 Subject: [PATCH 169/377] Add documentation for new WAITAOF command, and update commands.json (#2359) and update commands.json to latest --- commands.json | 74 +++++++++++++++++++++++++++++++++++++++++---- commands/wait.md | 4 +-- commands/waitaof.md | 58 +++++++++++++++++++++++++++++++++++ wordlist | 4 +++ 4 files changed, 132 insertions(+), 8 deletions(-) create mode 100644 commands/waitaof.md diff --git a/commands.json b/commands.json index e5cdb2939c..2863ecce01 100644 --- a/commands.json +++ b/commands.json @@ -1103,7 +1103,6 @@ "command_flags": [ "write", "denyoom", - "noscript", "blocking" ] }, @@ -1245,7 +1244,6 @@ ], "command_flags": [ "write", - "noscript", "blocking" ] }, @@ -1304,7 +1302,6 @@ ], "command_flags": [ "write", - "noscript", "blocking" ] }, @@ -1389,7 +1386,6 @@ "command_flags": [ "write", "denyoom", - "noscript", "blocking" ], "doc_flags": [ @@ -1534,7 +1530,6 @@ ], "command_flags": [ "write", - "noscript", "blocking", "fast" ] @@ -1594,7 +1589,6 @@ ], "command_flags": [ "write", - "noscript", "blocking", "fast" ] @@ -2011,6 +2005,42 @@ "stale" ] }, + "CLIENT NO-TOUCH": { + "summary": "Controls whether commands sent by the client will alter the LRU/LFU of the keys they access.", + "since": "7.2.0", + "group": "connection", + "complexity": "O(1)", + "acl_categories": [ + "@slow", + "@connection" + ], + "arity": 3, + "arguments": [ + { + "name": "enabled", + "type": "oneof", + "arguments": [ + { + "name": "on", + "type": "pure-token", + "display_text": "on", + "token": "ON" + }, + { + "name": "off", + "type": "pure-token", + "display_text": "off", + "token": "OFF" + } + ] + } + ], + "command_flags": [ + "noscript", + "loading", + "stale" + ] + }, "CLIENT PAUSE": { "summary": "Stop processing commands from clients for some time", "since": "3.0.0", @@ -14140,6 +14170,38 @@ "display_text": "timeout" } ], + "hints": [ + "request_policy:all_shards", + "response_policy:agg_min" + ] + }, + "WAITAOF": { + "summary": "Wait for all write commands sent in the context of the current connection to be synced to AOF of local host and/or replicas", + "since": "7.2.0", + "group": "generic", + "complexity": "O(1)", + "acl_categories": [ + "@slow", + "@connection" + ], + "arity": 4, + "arguments": [ + { + "name": "numlocal", + "type": "integer", + "display_text": "numlocal" + }, + { + "name": "numreplicas", + "type": "integer", + "display_text": "numreplicas" + }, + { + "name": "timeout", + "type": "integer", + "display_text": "timeout" + } + ], "command_flags": [ "noscript" ], diff --git a/commands/wait.md b/commands/wait.md index d3636ae0b4..a76f644784 100644 --- a/commands/wait.md +++ b/commands/wait.md @@ -4,13 +4,13 @@ of replicas. If the timeout, specified in milliseconds, is reached, the command returns even if the specified number of replicas were not yet reached. The command **will always return** the number of replicas that acknowledged -the write commands sent before the `WAIT` command, both in the case where +the write commands sent by the current client before the `WAIT` command, both in the case where the specified number of replicas are reached, or when the timeout is reached. A few remarks: 1. When `WAIT` returns, all the previous write commands sent in the context of the current connection are guaranteed to be received by the number of replicas returned by `WAIT`. -2. If the command is sent as part of a `MULTI` transaction, the command does not block but instead just return ASAP the number of replicas that acknowledged the previous write commands. +2. If the command is sent as part of a `MULTI` transaction (since Redis 7.0, any context that does not allow blocking, such as inside scripts), the command does not block but instead just return ASAP the number of replicas that acknowledged the previous write commands. 3. A timeout of 0 means to block forever. 4. Since `WAIT` returns the number of replicas reached both in case of failure and success, the client should check that the returned value is equal or greater to the replication level it demanded. diff --git a/commands/waitaof.md b/commands/waitaof.md new file mode 100644 index 0000000000..4249eb51a5 --- /dev/null +++ b/commands/waitaof.md @@ -0,0 +1,58 @@ +This command blocks the current client until all the previous write commands are acknowledged as having been fsynced to the AOF of the local Redis and/or at least the specified number of replicas. +If the timeout, specified in milliseconds, is reached, the command returns even if the specified number of acknowledgments has not been met. + +The command **will always return** the number of masters and replicas that have fsynced all write commands sent by the current client before the `WAITAOF` command, both in the case where the specified thresholds were met, and when the timeout is reached. + +A few remarks: + +1. When `WAITAOF` returns, all the previous write commands sent in the context of the current connection are guaranteed to be fsynced to the AOF of at least the number of masters and replicas returned by `WAITAOF`. +2. If the command is sent as part of a `MULTI` transaction (or any other context that does not allow blocking, such as inside scripts), the command does not block but instead returns immediately the number of masters and replicas that fsynced all previous write commands. +3. A timeout of 0 means to block forever. +4. Since `WAITAOF` returns the number of fsyncs completed both in case of success and timeout, the client should check that the returned values are equal or greater than the persistence level required. +5. `WAITAOF` cannot be used on replica instances, and the `numlocal` argument cannot be non-zero if the local Redis does not have AOF enabled. + +Limitations +--- +It is possible to write a module or Lua script that propagate writes to the AOF but not the replication stream. +(For modules, this is done using the `fmt` argument to `RedisModule_Call` or `RedisModule_Replicate`; For Lua scripts, this is achieved using `redis.set_repl`.) + +These features are incompatible with the `WAITAOF` command as it is currently implemented, and using them in combination may result in incorrect behavior. + +Consistency and WAITAOF +--- + +Note that, similarly to `WAIT`, `WAITAOF` does not make Redis a strongly-consistent store. +Unless waiting for all members of a cluster to fsync writes to disk, data can still be lost during a failover or a Redis restart. +However, `WAITAOF` does improve real-world data safety. + +Implementation details +--- + +Since Redis 7.2, Redis tracks and increments the replication offset even when no replicas are configured (as long as AOF exists). + +In addition, Redis replicas asynchronously ping their master with two replication offsets: the offset they have processed in the replication stream, and the offset they have fsynced to their AOF. + +Redis remembers, for each client, the replication offset of the produced replication stream when the last write command was executed in the context of that client. +When `WAITAOF` is called, Redis checks if the local Redis and/or the specified number of replicas have confirmed fsyncing this offset or a greater one to their AOF. + +@return + +@array-reply: The command returns an array of two integers: The first is the number of local Redises (0 or 1) that have fsynced to AOF all writes performed in the context of the current connection; The second is the number of replicas that have acknowledged doing the same. + +@examples + +``` +> SET foo bar +OK +> WAITAOF 1 0 0 +1) (integer) 1 +2) (integer) 0 +> WAITAOF 0 1 1000 +1) (integer) 1 +2) (integer) 0 +``` + +In the above example, the first call to `WAITAOF` does not use a timeout and asks for the write to be fsynced to the local Redis only; it returns with [1, 0] when this is completed. + +In the second attempt we instead specify a timeout, and ask for the write to be confirmed as fsynced by a single replica. +Since there are no connected replicas, the `WAITAOF` command unblocks after one second and again returns [1, 0], indicating the write has been fsynced on the local Redis but no replicas. diff --git a/wordlist b/wordlist index fff03ba01f..39144c8b09 100644 --- a/wordlist +++ b/wordlist @@ -959,3 +959,7 @@ zeroed-ACLs ziplists zset ˈrɛd-ɪs +fsynced +fsyncs +WAITAOF +Redises From d2ed22cf282e6680922b2aecb55be22a294b93eb Mon Sep 17 00:00:00 2001 From: guybe7 Date: Wed, 22 Mar 2023 08:15:23 +0100 Subject: [PATCH 170/377] Update docs of consumer seen-time and active-time (#2229) * Update docs of consumer seen-time and active-time * CR fixes --- commands/xinfo-consumers.md | 9 +++++++-- commands/xinfo-stream.md | 17 +++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/commands/xinfo-consumers.md b/commands/xinfo-consumers.md index f65366d3c9..965292e131 100644 --- a/commands/xinfo-consumers.md +++ b/commands/xinfo-consumers.md @@ -3,8 +3,9 @@ This command returns the list of consumers that belong to the `` cons The following information is provided for each consumer in the group: * **name**: the consumer's name -* **pending**: the number of pending messages for the client, which are messages that were delivered but are yet to be acknowledged -* **idle**: the number of milliseconds that have passed since the consumer last interacted with the server +* **pending**: the number of entries in the PEL: pending messages for the consumer, which are messages that were delivered but are yet to be acknowledged +* **idle**: the number of milliseconds that have passed since the consumer's last attempted interaction (Examples: `XREADGROUP`, `XCLAIM`, `XAUTOCLAIM`) +* **inactive**: the number of milliseconds that have passed since the consumer's last successful interaction (Examples: `XREADGROUP` that actually read some entries into the PEL, `XCLAIM`/`XAUTOCLAIM` that actually claimed some entries) @reply @@ -20,10 +21,14 @@ The following information is provided for each consumer in the group: 4) (integer) 1 5) idle 6) (integer) 9104628 + 7) inactive + 8) (integer) 18104698 2) 1) name 2) "Bob" 3) pending 4) (integer) 1 5) idle 6) (integer) 83841983 + 7) inactive + 8) (integer) 993841998 ``` diff --git a/commands/xinfo-stream.md b/commands/xinfo-stream.md index f69760840b..beba33e18e 100644 --- a/commands/xinfo-stream.md +++ b/commands/xinfo-stream.md @@ -107,12 +107,13 @@ OK 14) 1) 1) "name" 2) "Alice" 3) "seen-time" - 4) (integer) 1638125153423 - 5) "pel-count" - 6) (integer) 1 - 7) "pending" - 8) 1) 1) "1638125133432-0" - 2) (integer) 1638125153423 - 3) (integer) 1 -> + 4) (integer) 1638125133422 + 5) "active-time" + 6) (integer) 1638125133432 + 7) "pel-count" + 8) (integer) 1 + 9) "pending" + 10) 1) 1) "1638125133432-0" + 2) (integer) 1638125133432 + 3) (integer) 1 ``` From 804b59ad885ed724d02478cbd687914d579227d5 Mon Sep 17 00:00:00 2001 From: Chen Tianjie Date: Wed, 22 Mar 2023 15:37:53 +0800 Subject: [PATCH 171/377] Add client no-touch. Update reset command. (#2332) --- commands/client-no-touch.md | 9 +++++++++ commands/reset.md | 2 ++ 2 files changed, 11 insertions(+) create mode 100644 commands/client-no-touch.md diff --git a/commands/client-no-touch.md b/commands/client-no-touch.md new file mode 100644 index 0000000000..36e69dec77 --- /dev/null +++ b/commands/client-no-touch.md @@ -0,0 +1,9 @@ +The `CLIENT NO-TOUCH` command controls whether commands sent by the client will alter the LRU/LFU of the keys they access. + +When turned on, the current client will not change LFU/LRU stats, unless it sends the `TOUCH` command. + +When turned off, the client touches LFU/LRU stats just as a normal client. + +@return + +@simple-string-reply: `OK`. diff --git a/commands/reset.md b/commands/reset.md index b3f17d2406..e6bbc1ace6 100644 --- a/commands/reset.md +++ b/commands/reset.md @@ -17,6 +17,8 @@ following: appropriate. * Deauthenticates the connection, requiring a call `AUTH` to reauthenticate when authentication is enabled. +* Turns off `NO-EVICT` mode. +* Turns off `NO-TOUCH` mode. @return From 317919f714cb0ea658ccb20a18757a68c3508ca4 Mon Sep 17 00:00:00 2001 From: Oran Agra Date: Wed, 22 Mar 2023 09:48:53 +0200 Subject: [PATCH 172/377] add docs for CLIENT SETINFO (#2362) also update commands.json with XINFO history --- commands.json | 46 ++++++++++++++++++++++++++++++++++++++ commands/client-setinfo.md | 16 +++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 commands/client-setinfo.md diff --git a/commands.json b/commands.json index 2863ecce01..20a6eb1781 100644 --- a/commands.json +++ b/commands.json @@ -2135,6 +2135,42 @@ "stale" ] }, + "CLIENT SETINFO": { + "summary": "Set client or connection specific info", + "since": "7.2.0", + "group": "connection", + "complexity": "O(1)", + "acl_categories": [ + "@slow", + "@connection" + ], + "arity": 4, + "arguments": [ + { + "name": "attr", + "type": "oneof", + "arguments": [ + { + "name": "libname", + "type": "string", + "display_text": "libname", + "token": "LIB-NAME" + }, + { + "name": "libver", + "type": "string", + "display_text": "libver", + "token": "LIB-VER" + } + ] + } + ], + "command_flags": [ + "noscript", + "loading", + "stale" + ] + }, "CLIENT SETNAME": { "summary": "Set the current connection name", "since": "2.6.9", @@ -15076,6 +15112,12 @@ "since": "5.0.0", "group": "stream", "complexity": "O(1)", + "history": [ + [ + "7.2.0", + "Added the `inactive` field." + ] + ], "acl_categories": [ "@read", "@stream", @@ -15199,6 +15241,10 @@ [ "7.0.0", "Added the `max-deleted-entry-id`, `entries-added`, `recorded-first-entry-id`, `entries-read` and `lag` fields" + ], + [ + "7.2.0", + "Added the `active-time` field, and changed the meaning of `seen-time`." ] ], "acl_categories": [ diff --git a/commands/client-setinfo.md b/commands/client-setinfo.md new file mode 100644 index 0000000000..b6ff217411 --- /dev/null +++ b/commands/client-setinfo.md @@ -0,0 +1,16 @@ +The `CLIENT SETINFO` command assigns various info attributes to the current connection which are displayed in the output of `CLIENT LIST` and `CLIENT INFO`. + +Client libraries are expected to pipeline this command after authentication on all connections +and ignore failures since they could be connected to an older version that doesn't support them. + +Currently the supported attributes are: +* `lib-name` - meant to hold the name of the client library that's in use. +* `lib-ver` - meant to hold the client library's version. + +There is no limit to the length of these attributes. However it is not possible to use spaces, newlines, or other non-printable characters that would violate the format of the `CLIENT LIST` reply. + +Note that these attributes are **not** cleared by the RESET command. + +@return + +@simple-string-reply: `OK` if the attribute name was successfully set. From 80258ecc251e8f7209d480cad77128ba5a43f968 Mon Sep 17 00:00:00 2001 From: Oran Agra Date: Wed, 22 Mar 2023 17:31:08 +0200 Subject: [PATCH 173/377] update module api reference for 7.2-rc1 (#2363) --- docs/reference/modules/modules-api-ref.md | 450 ++++++++++++++++++++-- 1 file changed, 418 insertions(+), 32 deletions(-) diff --git a/docs/reference/modules/modules-api-ref.md b/docs/reference/modules/modules-api-ref.md index 10cc445b99..cd95fa088b 100644 --- a/docs/reference/modules/modules-api-ref.md +++ b/docs/reference/modules/modules-api-ref.md @@ -277,9 +277,15 @@ it allows the ACLs to be checked before the command is executed. Register a new command in the Redis server, that will be handled by calling the function pointer 'cmdfunc' using the RedisModule calling -convention. The function returns `REDISMODULE_ERR` if the specified command -name is already busy or a set of invalid flags were passed, otherwise -`REDISMODULE_OK` is returned and the new command is registered. +convention. + +The function returns `REDISMODULE_ERR` in these cases: +- If creation of module command is called outside the `RedisModule_OnLoad`. +- The specified command is already busy. +- The command name contains some chars that are not allowed. +- A set of invalid flags were passed. + +Otherwise `REDISMODULE_OK` is returned and the new command is registered. This function must be called during the initialization of the module inside the `RedisModule_OnLoad()` function. Calling this function outside @@ -363,7 +369,8 @@ This information is used by ACL, Cluster and the `COMMAND` command. NOTE: The scheme described above serves a limited purpose and can only be used to find keys that exist at constant indices. For non-trivial key arguments, you may pass 0,0,0 and use -[`RedisModule_SetCommandInfo`](#RedisModule_SetCommandInfo) to set key specs using a more advanced scheme. +[`RedisModule_SetCommandInfo`](#RedisModule_SetCommandInfo) to set key specs using a more advanced scheme and use +[`RedisModule_SetCommandACLCategories`](#RedisModule_SetCommandACLCategories) to set Redis ACL categories of the commands. @@ -422,6 +429,28 @@ Returns `REDISMODULE_OK` on success and `REDISMODULE_ERR` in case of the followi * `parent` is already a subcommand (we do not allow more than one level of command nesting) * `parent` is a command with an implementation (`RedisModuleCmdFunc`) (A parent command should be a pure container of subcommands) * `parent` already has a subcommand called `name` +* Creating a subcommand is called outside of `RedisModule_OnLoad`. + + + +### `RedisModule_SetCommandACLCategories` + + int RedisModule_SetCommandACLCategories(RedisModuleCommand *command, + const char *aclflags); + +**Available since:** unreleased + +[`RedisModule_SetCommandACLCategories`](#RedisModule_SetCommandACLCategories) can be used to set ACL categories to module +commands and subcommands. The set of ACL categories should be passed as +a space separated C string 'aclflags'. + +Example, the acl flags 'write slow' marks the command as part of the write and +slow ACL categories. + +On success `REDISMODULE_OK` is returned. On error `REDISMODULE_ERR` is returned. + +This function can only be called during the `RedisModule_OnLoad` function. If called +outside of this function, an error is returned. @@ -753,7 +782,7 @@ Otherwise zero is returned. ### `RedisModule_Milliseconds` - long long RedisModule_Milliseconds(void); + mstime_t RedisModule_Milliseconds(void); **Available since:** 4.0.0 @@ -769,6 +798,31 @@ Return the current UNIX time in milliseconds. Return counter of micro-seconds relative to an arbitrary point in time. + + +### `RedisModule_Microseconds` + + ustime_t RedisModule_Microseconds(); + +**Available since:** unreleased + +Return the current UNIX time in microseconds + + + +### `RedisModule_CachedMicroseconds` + + ustime_t RedisModule_CachedMicroseconds(); + +**Available since:** unreleased + +Return the cached UNIX time in microseconds. +It is updated in the server cron job and before executing a command. +It is useful for complex call stacks, such as a command causing a +key space notification, causing a module to execute a [`RedisModule_Call`](#RedisModule_Call), +causing another notification, etc. +It makes sense that all this callbacks would use the same clock. + ### `RedisModule_BlockedClientMeasureTimeStart` @@ -852,6 +906,13 @@ See [`RedisModule_SignalModifiedKey()`](#RedisModule_SignalModifiedKey). Setting this flag indicates module awareness of diskless async replication (repl-diskless-load=swapdb) and that redis could be serving reads during replication instead of blocking with LOADING status. +`REDISMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS`: +Declare that the module wants to get nested key-space notifications. +By default, Redis will not fire key-space notifications that happened inside +a key-space notification callback. This flag allows to change this behavior +and fire nested key-space notifications. Notice: if enabled, the module +should protected itself from infinite recursion. + ### `RedisModule_SignalModifiedKey` @@ -1225,7 +1286,8 @@ is not a valid string representation of a stream ID. The special IDs "+" and ### `RedisModule_StringCompare` - int RedisModule_StringCompare(RedisModuleString *a, RedisModuleString *b); + int RedisModule_StringCompare(const RedisModuleString *a, + const RedisModuleString *b); **Available since:** 4.0.0 @@ -2045,6 +2107,8 @@ Available flags and their meaning: * `REDISMODULE_CTX_FLAGS_RESP3`: Indicate the that client attached to this context is using RESP3. + * `REDISMODULE_CTX_FLAGS_SERVER_STARTUP`: The Redis instance is starting + ### `RedisModule_AvoidReplicaTraffic` @@ -2123,14 +2187,42 @@ operations on the key. The return value is the handle representing the key, that must be closed with [`RedisModule_CloseKey()`](#RedisModule_CloseKey). -If the key does not exist and WRITE mode is requested, the handle +If the key does not exist and `REDISMODULE_WRITE` mode is requested, the handle is still returned, since it is possible to perform operations on a yet not existing key (that will be created, for example, after -a list push operation). If the mode is just READ instead, and the +a list push operation). If the mode is just `REDISMODULE_READ` instead, and the key does not exist, NULL is returned. However it is still safe to call [`RedisModule_CloseKey()`](#RedisModule_CloseKey) and [`RedisModule_KeyType()`](#RedisModule_KeyType) on a NULL value. +Extra flags that can be pass to the API under the mode argument: +* `REDISMODULE_OPEN_KEY_NOTOUCH` - Avoid touching the LRU/LFU of the key when opened. +* `REDISMODULE_OPEN_KEY_NONOTIFY` - Don't trigger keyspace event on key misses. +* `REDISMODULE_OPEN_KEY_NOSTATS` - Don't update keyspace hits/misses counters. +* `REDISMODULE_OPEN_KEY_NOEXPIRE` - Avoid deleting lazy expired keys. +* `REDISMODULE_OPEN_KEY_NOEFFECTS` - Avoid any effects from fetching the key. + + + +### `RedisModule_GetOpenKeyModesAll` + + int RedisModule_GetOpenKeyModesAll(); + +**Available since:** unreleased + + +Returns the full OpenKey modes mask, using the return value +the module can check if a certain set of OpenKey modes are supported +by the redis server version in use. +Example: + + int supportedMode = RedisModule_GetOpenKeyModesAll(); + if (supportedMode & REDISMODULE_OPEN_KEY_NOTOUCH) { + // REDISMODULE_OPEN_KEY_NOTOUCH is supported + } else{ + // REDISMODULE_OPEN_KEY_NOTOUCH is not supported + } + ### `RedisModule_CloseKey` @@ -3300,6 +3392,7 @@ Return the reply type as one of the following: - `REDISMODULE_REPLY_BIG_NUMBER` - `REDISMODULE_REPLY_VERBATIM_STRING` - `REDISMODULE_REPLY_ATTRIBUTE` +- `REDISMODULE_REPLY_PROMISE` @@ -3439,6 +3532,40 @@ Returns: The `key` and `value` arguments are used to return by reference, and may be NULL if not required. + + +### `RedisModule_CallReplyPromiseSetUnblockHandler` + + void RedisModule_CallReplyPromiseSetUnblockHandler(RedisModuleCallReply *reply, + RedisModuleOnUnblocked on_unblock, + void *private_data); + +**Available since:** unreleased + +Set unblock handler (callback and private data) on the given promise `RedisModuleCallReply`. +The given reply must be of promise type (`REDISMODULE_REPLY_PROMISE`). + + + +### `RedisModule_CallReplyPromiseAbort` + + int RedisModule_CallReplyPromiseAbort(RedisModuleCallReply *reply, + void **private_data); + +**Available since:** unreleased + +Abort the execution of a given promise `RedisModuleCallReply`. +return `REDMODULE_OK` in case the abort was done successfully and `REDISMODULE_ERR` +if its not possible to abort the execution (execution already finished). +In case the execution was aborted (`REDMODULE_OK` was returned), the `private_data` out parameter +will be set with the value of the private data that was given on '[`RedisModule_CallReplyPromiseSetUnblockHandler`](#RedisModule_CallReplyPromiseSetUnblockHandler)' +so the caller will be able to release the private data. + +If the execution was aborted successfully, it is promised that the unblock handler will not be called. +That said, it is possible that the abort operation will successes but the operation will still continue. +This can happened if, for example, a module implements some blocking command and does not respect the +disconnect callback. For pure Redis commands this can not happened. + ### `RedisModule_CallReplyStringPtr` @@ -3528,6 +3655,38 @@ Exported API to call any Redis command from modules. invoking the command, the error is returned using errno mechanism. This flag allows to get the error also as an error CallReply with relevant error message. + * 'D' -- A "Dry Run" mode. Return before executing the underlying call(). + If everything succeeded, it will return with a NULL, otherwise it will + return with a CallReply object denoting the error, as if it was called with + the 'E' code. + * 'K' -- Allow running blocking commands. If enabled and the command gets blocked, a + special REDISMODULE_REPLY_PROMISE will be returned. This reply type + indicates that the command was blocked and the reply will be given asynchronously. + The module can use this reply object to set a handler which will be called when + the command gets unblocked using RedisModule_CallReplyPromiseSetUnblockHandler. + The handler must be set immediately after the command invocation (without releasing + the Redis lock in between). If the handler is not set, the blocking command will + still continue its execution but the reply will be ignored (fire and forget), + notice that this is dangerous in case of role change, as explained below. + The module can use RedisModule_CallReplyPromiseAbort to abort the command invocation + if it was not yet finished (see RedisModule_CallReplyPromiseAbort documentation for more + details). It is also the module's responsibility to abort the execution on role change, either by using + server event (to get notified when the instance becomes a replica) or relying on the disconnect + callback of the original client. Failing to do so can result in a write operation on a replica. + Unlike other call replies, promise call reply **must** be freed while the Redis GIL is locked. + Notice that on unblocking, the only promise is that the unblock handler will be called, + If the blocking RedisModule_Call caused the module to also block some real client (using RedisModule_BlockClient), + it is the module responsibility to unblock this client on the unblock handler. + On the unblock handler it is only allowed to perform the following: + * Calling additional Redis commands using RedisModule_Call + * Open keys using RedisModule_OpenKey + * Replicate data to the replica or AOF + + Specifically, it is not allowed to call any Redis module API which are client related such as: + * RedisModule_Reply* API's + * RedisModule_BlockClient + * RedisModule_GetCurrentUserName + * **...**: The actual arguments to the Redis command. On success a `RedisModuleCallReply` object is returned, otherwise @@ -3686,12 +3845,16 @@ documentation, especially [https://redis.io/topics/modules-native-types](https:/ so that meta information such as key name and db id can be obtained. * **copy2**: Similar to `copy`, but provides the `RedisModuleKeyOptCtx` parameter so that meta information such as key names and db ids can be obtained. +* **aux_save2**: Similar to `aux_save`, but with small semantic change, if the module + saves nothing on this callback then no data about this aux field will be written to the + RDB and it will be possible to load the RDB even if the module is not loaded. Note: the module name "AAAAAAAAA" is reserved and produces an error, it happens to be pretty lame as well. -If there is already a module registering a type with the same name, -and if the module name or encver is invalid, NULL is returned. +If [`RedisModule_CreateDataType()`](#RedisModule_CreateDataType) is called outside of `RedisModule_OnLoad()` function, +there is already a module registering a type with the same name, +or if the module name or encver is invalid, NULL is returned. Otherwise the new type is registered into Redis, and a reference of type `RedisModuleType` is returned: the caller of the function should store this reference into a global variable to make future use of it in the @@ -4235,7 +4398,69 @@ latency-monitor-threshold. ## Blocking clients from modules For a guide about blocking commands in modules, see -[Redis modules and blocking commands](https://redis.io/topics/modules-blocking-ops). +[https://redis.io/topics/modules-blocking-ops](https://redis.io/topics/modules-blocking-ops). + + + +### `RedisModule_RegisterAuthCallback` + + void RedisModule_RegisterAuthCallback(RedisModuleCtx *ctx, + RedisModuleAuthCallback cb); + +**Available since:** unreleased + +This API registers a callback to execute in addition to normal password based authentication. +Multiple callbacks can be registered across different modules. When a Module is unloaded, all the +auth callbacks registered by it are unregistered. +The callbacks are attempted (in the order of most recently registered first) when the AUTH/HELLO +(with AUTH field provided) commands are called. +The callbacks will be called with a module context along with a username and a password, and are +expected to take one of the following actions: +(1) Authenticate - Use the `RedisModule_AuthenticateClient`* API and return `REDISMODULE_AUTH_HANDLED`. +This will immediately end the auth chain as successful and add the OK reply. +(2) Deny Authentication - Return `REDISMODULE_AUTH_HANDLED` without authenticating or blocking the +client. Optionally, `err` can be set to a custom error message and `err` will be automatically +freed by the server. +This will immediately end the auth chain as unsuccessful and add the ERR reply. +(3) Block a client on authentication - Use the [`RedisModule_BlockClientOnAuth`](#RedisModule_BlockClientOnAuth) API and return +`REDISMODULE_AUTH_HANDLED`. Here, the client will be blocked until the [`RedisModule_UnblockClient`](#RedisModule_UnblockClient) API is used +which will trigger the auth reply callback (provided through the [`RedisModule_BlockClientOnAuth`](#RedisModule_BlockClientOnAuth)). +In this reply callback, the Module should authenticate, deny or skip handling authentication. +(4) Skip handling Authentication - Return `REDISMODULE_AUTH_NOT_HANDLED` without blocking the +client. This will allow the engine to attempt the next module auth callback. +If none of the callbacks authenticate or deny auth, then password based auth is attempted and +will authenticate or add failure logs and reply to the clients accordingly. + +Note: If a client is disconnected while it was in the middle of blocking module auth, that +occurrence of the AUTH or HELLO command will not be tracked in the INFO command stats. + +The following is an example of how non-blocking module based authentication can be used: + + int auth_cb(RedisModuleCtx *ctx, RedisModuleString *username, RedisModuleString *password, RedisModuleString **err) { + const char *user = RedisModule_StringPtrLen(username, NULL); + const char *pwd = RedisModule_StringPtrLen(password, NULL); + if (!strcmp(user,"foo") && !strcmp(pwd,"valid_password")) { + RedisModule_AuthenticateClientWithACLUser(ctx, "foo", 3, NULL, NULL, NULL); + return REDISMODULE_AUTH_HANDLED; + } + + else if (!strcmp(user,"foo") && !strcmp(pwd,"wrong_password")) { + RedisModuleString *log = RedisModule_CreateString(ctx, "Module Auth", 11); + RedisModule_ACLAddLogEntryByUserName(ctx, username, log, REDISMODULE_ACL_LOG_AUTH); + RedisModule_FreeString(ctx, log); + const char *err_msg = "Auth denied by Misc Module."; + *err = RedisModule_CreateString(ctx, err_msg, strlen(err_msg)); + return REDISMODULE_AUTH_HANDLED; + } + return REDISMODULE_AUTH_NOT_HANDLED; + } + + int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { + if (RedisModule_Init(ctx,"authmodule",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR) + return REDISMODULE_ERR; + RedisModule_RegisterAuthCallback(ctx, auth_cb); + return REDISMODULE_OK; + } @@ -4243,26 +4468,29 @@ For a guide about blocking commands in modules, see RedisModuleBlockedClient *RedisModule_BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, - RedisModuleCmdFunc timeout_callback, - void (*free_privdata)(RedisModuleCtx*, void*), - long long timeout_ms); + ; **Available since:** 4.0.0 -Block a client in the context of a blocking command, returning a handle that will be used later to unblock the client with a call to +Block a client in the context of a blocking command, returning a handle +which will be used, later, in order to unblock the client with a call to [`RedisModule_UnblockClient()`](#RedisModule_UnblockClient). The arguments specify callback functions and a timeout after which the client is unblocked. The callbacks are called in the following contexts: -* `reply_callback`: called after a successful `RedisModule_UnblockClient()` call to reply to the client and unblock it. + reply_callback: called after a successful RedisModule_UnblockClient() + call in order to reply to the client and unblock it. -* `timeout_callback`: called to send an error to the client when the timeout is reached or if `CLIENT UNBLOCK` is invoked. + timeout_callback: called when the timeout is reached or if `CLIENT UNBLOCK` + is invoked, in order to send an error to the client. -* `free_privdata`: called to free the private data that is passed by `RedisModule_UnblockClient()` call. + free_privdata: called in order to free the private data that is passed + by RedisModule_UnblockClient() call. -Note: [`RedisModule_UnblockClient`](#RedisModule_UnblockClient) should be called for every blocked client, even if client was killed, timed-out or disconnected. -Failing to do so results in memory leaks. +Note: [`RedisModule_UnblockClient`](#RedisModule_UnblockClient) should be called for every blocked client, + even if client was killed, timed-out or disconnected. Failing to do so + will result in memory leaks. There are some cases where [`RedisModule_BlockClient()`](#RedisModule_BlockClient) cannot be used: @@ -4283,18 +4511,49 @@ is not account for the total command duration. To include such time you should use [`RedisModule_BlockedClientMeasureTimeStart()`](#RedisModule_BlockedClientMeasureTimeStart) and [`RedisModule_BlockedClientMeasureTimeEnd()`](#RedisModule_BlockedClientMeasureTimeEnd) one, or multiple times within the blocking command background work. + + +### `RedisModule_BlockClientOnAuth` + + RedisModuleBlockedClient *RedisModule_BlockClientOnAuth(RedisModuleCtx *ctx, + RedisModuleAuthCallback reply_callback, + ; + +**Available since:** unreleased + +Block the current client for module authentication in the background. If module auth is not in +progress on the client, the API returns NULL. Otherwise, the client is blocked and the `RedisModule_BlockedClient` +is returned similar to the [`RedisModule_BlockClient`](#RedisModule_BlockClient) API. +Note: Only use this API from the context of a module auth callback. + + + +### `RedisModule_BlockClientGetPrivateData` + + void *RedisModule_BlockClientGetPrivateData(RedisModuleBlockedClient *blocked_client); + +**Available since:** unreleased + +Get the private data that was previusely set on a blocked client + + + +### `RedisModule_BlockClientSetPrivateData` + + void RedisModule_BlockClientSetPrivateData(RedisModuleBlockedClient *blocked_client, + void *private_data); + +**Available since:** unreleased + +Set private data on a blocked client + ### `RedisModule_BlockClientOnKeys` RedisModuleBlockedClient *RedisModule_BlockClientOnKeys(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, - RedisModuleCmdFunc timeout_callback, - void (*free_privdata)(RedisModuleCtx*, void*), - long long timeout_ms, - RedisModuleString **keys, - int numkeys, - void *privdata); + ; **Available since:** 6.0.0 @@ -4356,6 +4615,25 @@ Note: Under normal circumstances [`RedisModule_UnblockClient`](#RedisModule_Unbl handled as if it were timed-out (You must implement the timeout callback in that case). + + +### `RedisModule_BlockClientOnKeysWithFlags` + + RedisModuleBlockedClient *RedisModule_BlockClientOnKeysWithFlags(RedisModuleCtx *ctx, + RedisModuleCmdFunc reply_callback, + ; + +**Available since:** unreleased + +Same as [`RedisModule_BlockClientOnKeys`](#RedisModule_BlockClientOnKeys), but can take `REDISMODULE_BLOCK_`* flags +Can be either `REDISMODULE_BLOCK_UNBLOCK_DEFAULT`, which means default behavior (same +as calling [`RedisModule_BlockClientOnKeys`](#RedisModule_BlockClientOnKeys)) + +The flags is a bit mask of these: + +- `REDISMODULE_BLOCK_UNBLOCK_DELETED`: The clients should to be awakened in case any of `keys` are deleted. + Mostly useful for commands that require the key to exist (like XREADGROUP) + ### `RedisModule_SignalKeyAsReady` @@ -4368,8 +4646,6 @@ This function is used in order to potentially unblock a client blocked on keys with [`RedisModule_BlockClientOnKeys()`](#RedisModule_BlockClientOnKeys). When this function is called, all the clients blocked for this key will get their `reply_callback` called. -Note: The function has no effect if the signaled key doesn't exist. - ### `RedisModule_UnblockClient` @@ -4390,9 +4666,12 @@ to compute reply or some reply obtained via networking. Note 1: this function can be called from threads spawned by the module. -Note 2: when we unblock a client that is blocked for keys using the API [`RedisModule_BlockClientOnKeys()`](#RedisModule_BlockClientOnKeys), the `privdata` argument here is not used. -Unblocking a client that was blocked for keys using this API will still require the client to get some reply, so the function will use the "timeout" handler in order to do so. -The `privdata` provided in [`RedisModule_BlockClientOnKeys()`](#RedisModule_BlockClientOnKeys) is accessible from the timeout +Note 2: when we unblock a client that is blocked for keys using the API +[`RedisModule_BlockClientOnKeys()`](#RedisModule_BlockClientOnKeys), the privdata argument here is not used. +Unblocking a client that was blocked for keys using this API will still +require the client to get some reply, so the function will use the +"timeout" handler in order to do so (The privdata provided in +[`RedisModule_BlockClientOnKeys()`](#RedisModule_BlockClientOnKeys) is accessible from the timeout callback via [`RedisModule_GetBlockedClientPrivateData`](#RedisModule_GetBlockedClientPrivateData)). @@ -4630,6 +4909,12 @@ is interested in. This can be an ORed mask of any of the following flags: - `REDISMODULE_NOTIFY_STREAM`: Stream events - `REDISMODULE_NOTIFY_MODULE`: Module types events - `REDISMODULE_NOTIFY_KEYMISS`: Key-miss events + Notice, key-miss event is the only type + of event that is fired from within a read command. + Performing RedisModule_Call with a write command from within + this notification is wrong and discourage. It will + cause the read command that trigger the event to be + replicated to the AOF/Replica. - `REDISMODULE_NOTIFY_ALL`: All events (Excluding `REDISMODULE_NOTIFY_KEYMISS`) - `REDISMODULE_NOTIFY_LOADED`: A special notification available only for modules, indicates that the key was loaded from persistence. @@ -4661,8 +4946,40 @@ Warning: the notification callbacks are performed in a synchronous manner, so notification callbacks must to be fast, or they would slow Redis down. If you need to take long actions, use threads to offload them. +Moreover, the fact that the notification is executed synchronously means +that the notification code will be executed in the middle on Redis logic +(commands logic, eviction, expire). Changing the key space while the logic +runs is dangerous and discouraged. In order to react to key space events with +write actions, please refer to `RedisModule_AddPostExecutionUnitJob`. + See [https://redis.io/topics/notifications](https://redis.io/topics/notifications) for more information. + + +### `RedisModule_AddPostNotificationJob` + + int RedisModule_AddPostNotificationJob(RedisModuleCtx *ctx, + RedisModulePostNotificationJobFunc callback, + void *privdata, + void (*free_privdata)(void*)); + +**Available since:** unreleased + +When running inside a key space notification callback, it is dangerous and highly discouraged to perform any write +operation (See [`RedisModule_SubscribeToKeyspaceEvents`](#RedisModule_SubscribeToKeyspaceEvents)). In order to still perform write actions in this scenario, +Redis provides [`RedisModule_AddPostNotificationJob`](#RedisModule_AddPostNotificationJob) API. The API allows to register a job callback which Redis will call +when the following condition are promised to be fulfilled: +1. It is safe to perform any write operation. +2. The job will be called atomically along side the key space notification. + +Notice, one job might trigger key space notifications that will trigger more jobs. +This raises a concerns of entering an infinite loops, we consider infinite loops +as a logical bug that need to be fixed in the module, an attempt to protect against +infinite loops by halting the execution could result in violation of the feature correctness +and so Redis will make no attempt to protect the module from infinite loops. + +'`free_pd`' can be NULL and in such case will not be used. + ### `RedisModule_GetNotifyKeyspaceEvents` @@ -5208,6 +5525,22 @@ Returns `REDISMODULE_OK` on success and `REDISMODULE_ERR` on error. For more information about ACL log, please refer to [https://redis.io/commands/acl-log](https://redis.io/commands/acl-log) + + +### `RedisModule_ACLAddLogEntryByUserName` + + int RedisModule_ACLAddLogEntryByUserName(RedisModuleCtx *ctx, + RedisModuleString *username, + RedisModuleString *object, + RedisModuleACLLogEntryReason reason); + +**Available since:** unreleased + +Adds a new entry in the ACL log with the `username` `RedisModuleString` provided. +Returns `REDISMODULE_OK` on success and `REDISMODULE_ERR` on error. + +For more information about ACL log, please refer to [https://redis.io/commands/acl-log](https://redis.io/commands/acl-log) + ### `RedisModule_AuthenticateClientWithUser` @@ -5976,7 +6309,7 @@ And the function registerAPI() is: static int api_loaded = 0; if (api_loaded != 0) return 1; // APIs already resolved. - myFunctionPointer = RedisModule_GetOtherModuleAPI("..."); + myFunctionPointer = RedisModule_GetSharedAPI("..."); if (myFunctionPointer == NULL) return 0; return 1; @@ -6692,6 +7025,22 @@ Here is a list of events you can use as 'eid' and related sub events: // name of each modified configuration item uint32_t num_changes; // The number of elements in the config_names array +* `RedisModule_Event_Key` + + Called when a key is removed from the keyspace. We can't modify any key in + the event. + The following sub events are available: + + * `REDISMODULE_SUBEVENT_KEY_DELETED` + * `REDISMODULE_SUBEVENT_KEY_EXPIRED` + * `REDISMODULE_SUBEVENT_KEY_EVICTED` + * `REDISMODULE_SUBEVENT_KEY_OVERWRITTEN` + + The data pointer can be casted to a RedisModuleKeyInfo + structure with the following fields: + + RedisModuleKey *key; // Key name + The function returns `REDISMODULE_OK` if the module was successfully subscribed for the specified event. If the API is called from a wrong context or unsupported event is given then `REDISMODULE_ERR` is returned. @@ -6799,6 +7148,7 @@ Example implementation: If the registration fails, `REDISMODULE_ERR` is returned and one of the following errno is set: +* EBUSY: Registering the Config outside of `RedisModule_OnLoad`. * EINVAL: The provided flags are invalid for the registration or the name of the config contains invalid characters. * EALREADY: The provided configuration name is already used. @@ -6901,6 +7251,7 @@ Create an integer config that server clients can interact with via the Applies all pending configurations on the module load. This should be called after all of the configurations have been registered for the module inside of `RedisModule_OnLoad`. +This will return `REDISMODULE_ERR` if it is called outside `RedisModule_OnLoad`. This API needs to be called when configurations are provided in either `MODULE LOADEX` or provided as startup arguments. @@ -6963,6 +7314,27 @@ returns `REDISMODULE_OK` if when key is valid. ## Miscellaneous APIs + + +### `RedisModule_GetModuleOptionsAll` + + int RedisModule_GetModuleOptionsAll(); + +**Available since:** unreleased + + +Returns the full module options flags mask, using the return value +the module can check if a certain set of module options are supported +by the redis server version in use. +Example: + + int supportedFlags = RedisModule_GetModuleOptionsAll(); + if (supportedFlags & REDISMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS) { + // REDISMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS is supported + } else{ + // REDISMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS is not supported + } + ### `RedisModule_GetContextFlagsAll` @@ -7262,20 +7634,27 @@ There is no guarantee that this info is always available, so this may return -1. ## Function index * [`RedisModule_ACLAddLogEntry`](#RedisModule_ACLAddLogEntry) +* [`RedisModule_ACLAddLogEntryByUserName`](#RedisModule_ACLAddLogEntryByUserName) * [`RedisModule_ACLCheckChannelPermissions`](#RedisModule_ACLCheckChannelPermissions) * [`RedisModule_ACLCheckCommandPermissions`](#RedisModule_ACLCheckCommandPermissions) * [`RedisModule_ACLCheckKeyPermissions`](#RedisModule_ACLCheckKeyPermissions) * [`RedisModule_AbortBlock`](#RedisModule_AbortBlock) +* [`RedisModule_AddPostNotificationJob`](#RedisModule_AddPostNotificationJob) * [`RedisModule_Alloc`](#RedisModule_Alloc) * [`RedisModule_AuthenticateClientWithACLUser`](#RedisModule_AuthenticateClientWithACLUser) * [`RedisModule_AuthenticateClientWithUser`](#RedisModule_AuthenticateClientWithUser) * [`RedisModule_AutoMemory`](#RedisModule_AutoMemory) * [`RedisModule_AvoidReplicaTraffic`](#RedisModule_AvoidReplicaTraffic) * [`RedisModule_BlockClient`](#RedisModule_BlockClient) +* [`RedisModule_BlockClientGetPrivateData`](#RedisModule_BlockClientGetPrivateData) +* [`RedisModule_BlockClientOnAuth`](#RedisModule_BlockClientOnAuth) * [`RedisModule_BlockClientOnKeys`](#RedisModule_BlockClientOnKeys) +* [`RedisModule_BlockClientOnKeysWithFlags`](#RedisModule_BlockClientOnKeysWithFlags) +* [`RedisModule_BlockClientSetPrivateData`](#RedisModule_BlockClientSetPrivateData) * [`RedisModule_BlockedClientDisconnected`](#RedisModule_BlockedClientDisconnected) * [`RedisModule_BlockedClientMeasureTimeEnd`](#RedisModule_BlockedClientMeasureTimeEnd) * [`RedisModule_BlockedClientMeasureTimeStart`](#RedisModule_BlockedClientMeasureTimeStart) +* [`RedisModule_CachedMicroseconds`](#RedisModule_CachedMicroseconds) * [`RedisModule_Call`](#RedisModule_Call) * [`RedisModule_CallReplyArrayElement`](#RedisModule_CallReplyArrayElement) * [`RedisModule_CallReplyAttribute`](#RedisModule_CallReplyAttribute) @@ -7286,6 +7665,8 @@ There is no guarantee that this info is always available, so this may return -1. * [`RedisModule_CallReplyInteger`](#RedisModule_CallReplyInteger) * [`RedisModule_CallReplyLength`](#RedisModule_CallReplyLength) * [`RedisModule_CallReplyMapElement`](#RedisModule_CallReplyMapElement) +* [`RedisModule_CallReplyPromiseAbort`](#RedisModule_CallReplyPromiseAbort) +* [`RedisModule_CallReplyPromiseSetUnblockHandler`](#RedisModule_CallReplyPromiseSetUnblockHandler) * [`RedisModule_CallReplyProto`](#RedisModule_CallReplyProto) * [`RedisModule_CallReplySetElement`](#RedisModule_CallReplySetElement) * [`RedisModule_CallReplyStringPtr`](#RedisModule_CallReplyStringPtr) @@ -7394,10 +7775,12 @@ There is no guarantee that this info is always available, so this may return -1. * [`RedisModule_GetKeyspaceNotificationFlagsAll`](#RedisModule_GetKeyspaceNotificationFlagsAll) * [`RedisModule_GetLFU`](#RedisModule_GetLFU) * [`RedisModule_GetLRU`](#RedisModule_GetLRU) +* [`RedisModule_GetModuleOptionsAll`](#RedisModule_GetModuleOptionsAll) * [`RedisModule_GetModuleUserACLString`](#RedisModule_GetModuleUserACLString) * [`RedisModule_GetModuleUserFromUserName`](#RedisModule_GetModuleUserFromUserName) * [`RedisModule_GetMyClusterID`](#RedisModule_GetMyClusterID) * [`RedisModule_GetNotifyKeyspaceEvents`](#RedisModule_GetNotifyKeyspaceEvents) +* [`RedisModule_GetOpenKeyModesAll`](#RedisModule_GetOpenKeyModesAll) * [`RedisModule_GetRandomBytes`](#RedisModule_GetRandomBytes) * [`RedisModule_GetRandomHexChars`](#RedisModule_GetRandomHexChars) * [`RedisModule_GetSelectedDb`](#RedisModule_GetSelectedDb) @@ -7456,6 +7839,7 @@ There is no guarantee that this info is always available, so this may return -1. * [`RedisModule_MallocSizeDict`](#RedisModule_MallocSizeDict) * [`RedisModule_MallocSizeString`](#RedisModule_MallocSizeString) * [`RedisModule_MallocUsableSize`](#RedisModule_MallocUsableSize) +* [`RedisModule_Microseconds`](#RedisModule_Microseconds) * [`RedisModule_Milliseconds`](#RedisModule_Milliseconds) * [`RedisModule_ModuleTypeGetType`](#RedisModule_ModuleTypeGetType) * [`RedisModule_ModuleTypeGetValue`](#RedisModule_ModuleTypeGetValue) @@ -7470,6 +7854,7 @@ There is no guarantee that this info is always available, so this may return -1. * [`RedisModule_RandomKey`](#RedisModule_RandomKey) * [`RedisModule_Realloc`](#RedisModule_Realloc) * [`RedisModule_RedactClientCommandArgument`](#RedisModule_RedactClientCommandArgument) +* [`RedisModule_RegisterAuthCallback`](#RedisModule_RegisterAuthCallback) * [`RedisModule_RegisterBoolConfig`](#RedisModule_RegisterBoolConfig) * [`RedisModule_RegisterClusterMessageReceiver`](#RedisModule_RegisterClusterMessageReceiver) * [`RedisModule_RegisterCommandFilter`](#RedisModule_RegisterCommandFilter) @@ -7531,6 +7916,7 @@ There is no guarantee that this info is always available, so this may return -1. * [`RedisModule_SetAbsExpire`](#RedisModule_SetAbsExpire) * [`RedisModule_SetClientNameById`](#RedisModule_SetClientNameById) * [`RedisModule_SetClusterFlags`](#RedisModule_SetClusterFlags) +* [`RedisModule_SetCommandACLCategories`](#RedisModule_SetCommandACLCategories) * [`RedisModule_SetCommandInfo`](#RedisModule_SetCommandInfo) * [`RedisModule_SetContextUser`](#RedisModule_SetContextUser) * [`RedisModule_SetDisconnectCallback`](#RedisModule_SetDisconnectCallback) From 5ae083d9f44dfbc6bdf049ace0bbe78aede3f6ec Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Tue, 28 Mar 2023 13:31:33 -0400 Subject: [PATCH 174/377] Clients get started (#2256) * Adds client get started with a python guide * Updates wordlist and unit format in one instance * Updates the wordlist * Updates the wordlist * Update _index.md * Update python.md * Updates Python guide, adds JS and Java guides * Updates wordlist * Update docs/redis-clients/_index.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update docs/redis-clients/java.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update docs/redis-clients/java.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update docs/redis-clients/nodejs.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update python.md Applies comments from the code review * Update python.md Applies feedback from the code review * Update python.md Applies feedback from the code review * Update docs/redis-clients/python.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update docs/redis-clients/python.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update python.md Applies feedback from the code review * Update docs/redis-clients/python.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update docs/redis-clients/nodejs.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update docs/redis-clients/java.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update docs/redis-clients/java.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update docs/redis-clients/java.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update docs/redis-clients/java.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update docs/redis-clients/java.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update docs/redis-clients/java.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update docs/redis-clients/python.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update docs/redis-clients/python.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update docs/redis-clients/python.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update python.md Applies feedback from the code review * Update docs/redis-clients/python.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update docs/redis-clients/python.md Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> * Update python.md Applies feedback from the code review * Update python.md Applies feedback from the code review * Update python.md Applies feedback from the code review * Update python.md Applies feedback from the code review * Update python.md Applies feedback from the code review * Update java.md Adds links to Redis Cluster Specification * Update java.md Minor edit * Update python.md Applies feedback from the code review * Update python.md Applies feedback from the code review * Adds go guide * updates the wordlist * Adds minor changes * Updates the go client * Updates clients get started * Updates the node.js guide * Update python.md Applies feedback from code review * Update python.md Applies feedback from code review * Update nodejs.md Applies feedback from code review * Update nodejs.md Applies feedback from code review * Updates the go client * Adds get started for .NET and PHP, updates other guides * Updates wordlist plus php.md file name * Fixes typo in redis-doc * Update dotnet.md * Update python.md * Update nodejs.md * Update python.md * Update python.md * Update wordlist * Update java.md * Update java.md * Update wordlist * Update wordlist * Update java.md * Updates the java guide * Updates wordlist * Updates wordlist * Updates java guide * Updates java guide * Updates java guide * Updates wordlist, java guide * Updates java guide * updates java guide * Clients get started (#2366) * Jedis: Fix formatting of the file * Node-redis: Remove redundant line in aggregate example * Update docs/redis-clients/java.md * Jedis: Remove dependency file name * Redis-Py: Add Cluster and TLS example * Redis-py: Add ACL link embedded into the snippet * Fix typos * Fix code block * node-redis: add cluster and tls example * Remove php client page * Update .Net quick-start * Update Go quick-start * Fix wording in python quick-start * Fix wording in index --------- Co-authored-by: Igor Malinovskiy * Update python.md * Update wordlist * Update python.md * Update dotnet.md * Update nodejs.md * Update dotnet.md * Update java.md * Update python.md * Update dotnet.md * Update go.md * Update nodejs.md * Update python.md * Update dotnet.md --------- Co-authored-by: Rachel Elledge <86307637+rrelledge@users.noreply.github.com> Co-authored-by: Igor Malinovskiy --- docs/getting-started/_index.md | 2 + docs/management/optimization/cpu-profiling.md | 2 +- docs/redis-clients/_index.md | 13 + docs/redis-clients/dotnet.md | 271 ++++++++++++++++ docs/redis-clients/go.md | 167 ++++++++++ docs/redis-clients/java.md | 288 +++++++++++++++++ docs/redis-clients/nodejs.md | 301 ++++++++++++++++++ docs/redis-clients/python.md | 212 ++++++++++++ docs/reference/_index.md | 1 + wordlist | 52 ++- 10 files changed, 1307 insertions(+), 2 deletions(-) create mode 100644 docs/redis-clients/_index.md create mode 100644 docs/redis-clients/dotnet.md create mode 100644 docs/redis-clients/go.md create mode 100644 docs/redis-clients/java.md create mode 100644 docs/redis-clients/nodejs.md create mode 100644 docs/redis-clients/python.md diff --git a/docs/getting-started/_index.md b/docs/getting-started/_index.md index b5366bfc36..cc7f0c0ba0 100644 --- a/docs/getting-started/_index.md +++ b/docs/getting-started/_index.md @@ -1,7 +1,9 @@ --- title: "Getting started with Redis" linkTitle: "Getting started" + weight: 20 + description: > How to get up and running with Redis aliases: diff --git a/docs/management/optimization/cpu-profiling.md b/docs/management/optimization/cpu-profiling.md index 9852b12693..01c19eee59 100644 --- a/docs/management/optimization/cpu-profiling.md +++ b/docs/management/optimization/cpu-profiling.md @@ -26,7 +26,7 @@ of methodologies and their steps are enumerated by Brendan Greg at the We recommend the Utilization Saturation and Errors (USE) Method for answering the question of what is your bottleneck. Check the following mapping between -system resource, metric, and tools for a pratical deep dive: +system resource, metric, and tools for a practical deep dive: [USE method](http://www.brendangregg.com/USEmethod/use-rosetta.html). ### Ensuring the CPU is your bottleneck diff --git a/docs/redis-clients/_index.md b/docs/redis-clients/_index.md new file mode 100644 index 0000000000..562f925d4d --- /dev/null +++ b/docs/redis-clients/_index.md @@ -0,0 +1,13 @@ +--- +title: "Redis client libraries" +linkTitle: "Clients" +description: Connect your application to a Redis database +weight: 45 + +--- + +Here, you will learn how to connect your application to a Redis database. If you're new to Redis, you might first want to [install Redis with Redis Stack and RedisInsight](/docs/stack/get-started/install). + +For more Redis topics, see [Using](/docs/manual/) and [Managing](/docs/management/) Redis. + +If you're ready to get started, see the following guides for the official client libraries you can use with Redis. For a complete list of community-driven clients, see [Clients](/resources/clients/). diff --git a/docs/redis-clients/dotnet.md b/docs/redis-clients/dotnet.md new file mode 100644 index 0000000000..5ab389dfdb --- /dev/null +++ b/docs/redis-clients/dotnet.md @@ -0,0 +1,271 @@ +--- +title: "C#/.NET guide" +linkTitle: "C#/.NET" +description: Connect your .NET application to a Redis database +weight: 1 + +--- + +Install Redis and the Redis client, then connect your .NET application to a Redis database. + +## NRedisStack + +[NRedisStack](https://github.com/redis/NRedisStack) is a .NET client for Redis. +`NredisStack` requires a running Redis or [Redis Stack](https://redis.io/docs/stack/get-started/install/) server. See [Getting started](/docs/getting-started/) for Redis installation instructions. + +### Install + +Using the `dotnet` CLI, run: + +``` +dotnet add package NRedisStack +``` + +### Connect + +Connect to localhost on port 6379. + +``` +using NRedisStack; +using NRedisStack.RedisStackCommands; +using StackExchange.Redis; +//... +ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost"); +IDatabase db = redis.GetDatabase(); +``` + +Store and retrieve a simple string. + +```csharp +db.StringSet("foo", "bar"); +Console.WriteLine(db.StringGet("foo")); // prints bar +``` + +Store and retrieve a HashMap. + +```csharp +var hash = new HashEntry[] { + new HashEntry("name", "John"), + new HashEntry("surname", "Smith"), + new HashEntry("company", "Redis"), + new HashEntry("age", "29"), + }; +db.HashSet("user-session:123", hash); + +var hashFields = db.HashGetAll("user-session:123"); +Console.WriteLine(String.Join("; ", hashFields)); +// Prints: +// name: John; surname: Smith; company: Redis; age: 29 +``` + +To access Redis Stack capabilities, you should use appropriate interface like this: + +``` +IBloomCommands bf = db.BF(); +ICuckooCommands cf = db.CF(); +ICmsCommands cms = db.CMS(); +IGraphCommands graph = db.GRAPH(); +ITopKCommands topk = db.TOPK(); +ITdigestCommands tdigest = db.TDIGEST(); +ISearchCommands ft = db.FT(); +IJsonCommands json = db.JSON(); +ITimeSeriesCommands ts = db.TS(); +``` + +#### Connect to a Redis cluster + +To connect to a Redis cluster, you just need to specify one or all cluster endpoints in the client configuration: + +```csharp +ConfigurationOptions options = new ConfigurationOptions +{ + //list of available nodes of the cluster along with the endpoint port. + EndPoints = { + { "localhost", 16379 }, + { "localhost", 16380 }, + // ... + }, +}; + +ConnectionMultiplexer cluster = ConnectionMultiplexer.Connect(options); +IDatabase db = cluster.GetDatabase(); + +db.StringSet("foo", "bar"); +Console.WriteLine(db.StringGet("foo")); // prints bar +``` + +#### Connect to your production Redis with TLS + +When you deploy your application, use TLS and follow the [Redis security](/docs/management/security/) guidelines. + +Before connecting your application to the TLS-enabled Redis server, ensure that your certificates and private keys are in the correct format. + +To convert user certificate and private key from the PEM format to `pfx`, use this command: + +```bash +openssl pkcs12 -inkey redis_user_private.key -in redis_user.crt -export -out redis.pfx +``` + +Enter password to protect your `pfx` file. + +Establish a secure connection with your Redis database using this snippet. + +```csharp +ConfigurationOptions options = new ConfigurationOptions +{ + EndPoints = { { "my-redis.cloud.redislabs.com", 6379 } }, + User = "default", // use your Redis user. More info https://redis.io/docs/management/security/acl/ + Password = "secret", // use your Redis password + Ssl = true, + SslProtocols = System.Security.Authentication.SslProtocols.Tls12 +}; + +options.CertificateSelection += delegate +{ + return new X509Certificate2("redis.pfx", "secret"); // use the password you specified for pfx file +}; +options.CertificateValidation += ValidateServerCertificate; + +bool ValidateServerCertificate( + object sender, + X509Certificate? certificate, + X509Chain? chain, + SslPolicyErrors sslPolicyErrors) +{ + if (certificate == null) { + return false; + } + + var ca = new X509Certificate2("redis_ca.pem"); + bool verdict = (certificate.Issuer == ca.Subject); + if (verdict) { + return true; + } + Console.WriteLine("Certificate error: {0}", sslPolicyErrors); + return false; +} + +ConnectionMultiplexer muxer = ConnectionMultiplexer.Connect(options); + +//Creation of the connection to the DB +IDatabase conn = muxer.GetDatabase(); + +//send SET command +conn.StringSet("foo", "bar"); + +//send GET command and print the value +Console.WriteLine(conn.StringGet("foo")); +``` + +### Example: Indexing and querying JSON documents + +This example shows how to convert Redis search results to JSON format using `NRedisStack`. + +Make sure that you have Redis Stack and `NRedisStack` installed. + +Import dependencies and connect to the Redis server: + +```csharp +using NRedisStack; +using NRedisStack.RedisStackCommands; +using NRedisStack.Search; +using NRedisStack.Search.Aggregation; +using NRedisStack.Search.Literals.Enums; +using StackExchange.Redis; + +// ... + +ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost"); +``` + +Get a reference to the database and for search and JSON commands. + +```csharp +var db = redis.GetDatabase(); +var ft = db.FT(); +var json = db.JSON(); +``` + +Let's create some test data to add to your database. + +```csharp +var user1 = new { + name = "Paul John", + email = "paul.john@example.com", + age = 42, + city = "London" +}; + +var user2 = new { + name = "Eden Zamir", + email = "eden.zamir@example.com", + age = 29, + city = "Tel Aviv" +}; + +var user3 = new { + name = "Paul Zamir", + email = "paul.zamir@example.com", + age = 35, + city = "Tel Aviv" +}; +``` + +Create an index. In this example, all JSON documents with the key prefix `user:` are indexed. For more information, see [Query syntax](/docs/stack/search/reference/query_syntax). + +```csharp +var schema = new Schema() + .AddTextField(new FieldName("$.name", "name")) + .AddTagField(new FieldName("$.city", "city")) + .AddNumericField(new FieldName("$.age", "age")); + +ft.Create( + "idx:users", + new FTCreateParams().On(IndexDataType.JSON).Prefix("user:"), + schema); +``` + +Use `JSON.SET` to set each user value at the specified path. + +```csharp +json.Set("user:1", "$", user1); +json.Set("user:2", "$", user2); +json.Set("user:3", "$", user3); +``` + +Let's find user `Paul` and filter the results by age. + +```csharp +var res = ft.Search("idx:users", new Query("Paul @age:[30 40]")).Documents.Select(x => x["json"]); +Console.WriteLine(string.Join("\n", res)); +// Prints: {"name":"Paul Zamir","email":"paul.zamir@example.com","age":35,"city":"Tel Aviv"} +``` + +Return only the `city` field. + +```csharp +var res_cities = ft.Search("idx:users", new Query("Paul").ReturnFields(new FieldName("$.city", "city"))).Documents.Select(x => x["city"]); +Console.WriteLine(string.Join(", ", res_cities)); +// Prints: London, Tel Aviv +``` + +Count all users in the same city. + +```csharp +var request = new AggregationRequest("*").GroupBy("@city", Reducers.Count().As("count")); +var result = ft.Aggregate("idx:users", request); + +for (var i=0; i:@localhost:6379/") +if err != nil { + panic(err) +} + +client := redis.NewClient(opt) +``` + +Store and retrieve a simple string. + +```go +err := client.Set(ctx, "foo", "bar", 0).Err() +if err != nil { + panic(err) +} + +val, err := client.Get(ctx, "foo").Result() +if err != nil { + panic(err) +} +fmt.Println("foo", val) +``` + +Store and retrieve a map. + +```go +session := map[string]string{"name": "John", "surname": "Smith", "company": "Redis", "age": "29"} +for k, v := range session { + err := client.HSet(ctx, "user-session:123", k, v).Err() + if err != nil { + panic(err) + } +} + +userSession := client.HGetAll(ctx, "user-session:123").Val() +fmt.Println(userSession) + ``` + +#### Connect to a Redis cluster + +To connect to a Redis cluster, use `NewClusterClient`. + +```go +client := redis.NewClusterClient(&redis.ClusterOptions{ + Addrs: []string{":16379", ":16380", ":16381", ":16382", ":16383", ":16384"}, + + // To route commands by latency or randomly, enable one of the following. + //RouteByLatency: true, + //RouteRandomly: true, +}) +``` + +#### Connect to your production Redis with TLS + +When you deploy your application, use TLS and follow the [Redis security](/docs/management/security/) guidelines. + +Establish a secure connection with your Redis database using this snippet. + +```go +// Load client cert +cert, err := tls.LoadX509KeyPair("redis_user.crt", "redis_user_private.key") +if err != nil { + log.Fatal(err) +} + +// Load CA cert +caCert, err := os.ReadFile("redis_ca.pem") +if err != nil { + log.Fatal(err) +} +caCertPool := x509.NewCertPool() +caCertPool.AppendCertsFromPEM(caCert) + +client := redis.NewClient(&redis.Options{ + Addr: "my-redis.cloud.redislabs.com:6379", + Username: "default", // use your Redis user. More info https://redis.io/docs/management/security/acl/ + Password: "secret", // use your Redis password + TLSConfig: &tls.Config{ + MinVersion: tls.VersionTLS12, + Certificates: []tls.Certificate{cert}, + RootCAs: caCertPool, + }, +}) + +//send SET command +err = client.Set(ctx, "foo", "bar", 0).Err() +if err != nil { + panic(err) +} + +//send GET command and print the value +val, err := client.Get(ctx, "foo").Result() +if err != nil { + panic(err) +} +fmt.Println("foo", val) +``` + + +#### dial tcp: i/o timeout + +You get a `dial tcp: i/o timeout` error when `go-redis` can't connect to the Redis Server, for example, when the server is down or the port is protected by a firewall. To check if Redis Server is listening on the port, run telnet command on the host where the `go-redis` client is running. + +```go +telnet localhost 6379 +Trying 127.0.0.1... +telnet: Unable to connect to remote host: Connection refused +``` + +If you use Docker, Istio, or any other service mesh/sidecar, make sure the app starts after the container is fully available, for example, by configuring healthchecks with Docker and holdApplicationUntilProxyStarts with Istio. +For more information, see [Healthcheck](https://docs.docker.com/engine/reference/run/#healthcheck). + +### Learn more + +* [Documentation](https://redis.uptrace.dev/guide/) +* [GitHub](https://github.com/redis/go-redis) + diff --git a/docs/redis-clients/java.md b/docs/redis-clients/java.md new file mode 100644 index 0000000000..9367c22493 --- /dev/null +++ b/docs/redis-clients/java.md @@ -0,0 +1,288 @@ +--- +title: "Java guide" +linkTitle: "Java" +description: Connect your Java application to a Redis database +weight: 3 + +--- + +Install Redis and the Redis client, then connect your Java application to a Redis database. + +## Jedis + +[Jedis](https://github.com/redis/jedis) is a Java client for Redis designed for performance and ease of use. + +### Install + +To include `Jedis` as a dependency in your application, edit the dependency file, as follows. + +* If you use **Maven**: + + ```xml + + redis.clients + jedis + 4.3.1 + + ``` + +* If you use **Gradle**: + + ``` + repositories { + mavenCentral() + } + //... + dependencies { + implementation 'redis.clients:jedis:4.3.1' + //... + } + ``` + +* If you use the JAR files, download the latest Jedis and Apache Commons Pool2 JAR files from [Maven Central](https://central.sonatype.com/) or any other Maven repository. + +* Build from [source](https://github.com/redis/jedis) + +### Connect + +For many applications, it's best to use a connection pool. You can instantiate and use a `Jedis` connection pool like so: + +```java +package org.example; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; + +public class Main { + public static void main(String[] args) { + JedisPool pool = new JedisPool("localhost", 6379); + + try (Jedis jedis = pool.getResource()) { + // Store & Retrieve a simple string + jedis.set("foo", "bar"); + System.out.println(jedis.get("foo")); // prints bar + + // Store & Retrieve a HashMap + Map hash = new HashMap<>();; + hash.put("name", "John"); + hash.put("surname", "Smith"); + hash.put("company", "Redis"); + hash.put("age", "29"); + jedis.hset("user-session:123", hash); + System.out.println(jedis.hgetAll("user-session:123")); + // Prints: {name=John, surname=Smith, company=Redis, age=29} + } + } +} +``` + +Because adding a `try-with-resources` block for each command can be cumbersome, consider using `JedisPooled` as an easier way to pool connections. + +```java +import redis.clients.jedis.JedisPooled; + +//... + +JedisPooled jedis = new JedisPooled("localhost", 6379); +jedis.set("foo", "bar"); +System.out.println(jedis.get("foo")); // prints "bar" +``` + +#### Connect to a Redis cluster + +To connect to a Redis cluster, use `JedisCluster`. + +```java +import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.HostAndPort; + +//... + +Set jedisClusterNodes = new HashSet(); +jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7379)); +jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7380)); +JedisCluster jedis = new JedisCluster(jedisClusterNodes); +``` + +#### Connect to your production Redis with TLS + +When you deploy your application, use TLS and follow the [Redis security](/docs/management/security/) guidelines. + +Before connecting your application to the TLS-enabled Redis server, ensure that your certificates and private keys are in the correct format. + +To convert user certificate and private key from the PEM format to `pkcs12`, use this command: + +``` +openssl pkcs12 -export -in ./redis_user.crt -inkey ./redis_user_private.key -out redis-user-keystore.p12 -name "redis" +``` + +Enter password to protect your `pkcs12` file. + +Convert the server (CA) certificate to the JKS format using the [keytool](https://docs.oracle.com/en/java/javase/12/tools/keytool.html) shipped with JDK. + +``` +keytool -importcert -keystore truststore.jks \ + -storepass REPLACE_WITH_YOUR_PASSWORD \ + -file redis_ca.pem +``` + +Establish a secure connection with your Redis database using this snippet. + +```java +package org.example; + +import redis.clients.jedis.*; + +import javax.net.ssl.*; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyStore; + +public class Main { + + public static void main(String[] args) throws GeneralSecurityException, IOException { + HostAndPort address = new HostAndPort("my-redis-instance.cloud.redislabs.com", 6379); + + SSLSocketFactory sslFactory = createSslSocketFactory( + "./truststore.jks", + "secret!", // use the password you specified for keytool command + "./redis-user-keystore.p12", + "secret!" // use the password you specified for openssl command + ); + + JedisClientConfig config = DefaultJedisClientConfig.builder() + .ssl(true).sslSocketFactory(sslFactory) + .user("default") // use your Redis user. More info https://redis.io/docs/management/security/acl/ + .password("secret!") // use your Redis password + .build(); + + JedisPooled jedis = new JedisPooled(address, config); + jedis.set("foo", "bar"); + System.out.println(jedis.get("foo")); // prints bar + } + + private static SSLSocketFactory createSslSocketFactory( + String caCertPath, String caCertPassword, String userCertPath, String userCertPassword) + throws IOException, GeneralSecurityException { + + KeyStore keyStore = KeyStore.getInstance("pkcs12"); + keyStore.load(new FileInputStream(userCertPath), userCertPassword.toCharArray()); + + KeyStore trustStore = KeyStore.getInstance("jks"); + trustStore.load(new FileInputStream(caCertPath), caCertPassword.toCharArray()); + + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509"); + trustManagerFactory.init(trustStore); + + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX"); + keyManagerFactory.init(keyStore, userCertPassword.toCharArray()); + + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); + + return sslContext.getSocketFactory(); + } +} +``` + +### Example: Indexing and querying JSON documents + +Make sure that you have Redis Stack and `Jedis` installed. + +Import dependencies and add a sample `User` class: + +```java +import redis.clients.jedis.JedisPooled; +import redis.clients.jedis.search.*; +import redis.clients.jedis.search.aggr.*; +import redis.clients.jedis.search.schemafields.*; + +class User { + private String name; + private String email; + private int age; + private String city; + + public User(String name, String email, int age, String city) { + this.name = name; + this.email = email; + this.age = age; + this.city = city; + } + + //... +} +``` + +Connect to your Redis database with `JedisPooled`. + +```java +JedisPooled jedis = new JedisPooled("localhost", 6379); +``` + +Let's create some test data to add to your database. + +```java +User user1 = new User("Paul John", "paul.john@example.com", 42, "London"); +User user2 = new User("Eden Zamir", "eden.zamir@example.com", 29, "Tel Aviv"); +User user3 = new User("Paul Zamir", "paul.zamir@example.com", 35, "Tel Aviv"); +``` + +Create an index. In this example, all JSON documents with the key prefix `user:` are indexed. For more information, see [Query syntax](/docs/stack/search/reference/query_syntax). + +```java +jedis.ftCreate("idx:users", + FTCreateParams.createParams() + .on(IndexDataType.JSON) + .addPrefix("user:"), + TextField.of("$.name").as("name"), + TagField.of("$.city").as("city"), + NumericField.of("$.age").as("age") +); +``` + +Use `JSON.SET` to set each user value at the specified path. + +```java +jedis.jsonSetWithEscape("user:1", user1); +jedis.jsonSetWithEscape("user:2", user2); +jedis.jsonSetWithEscape("user:3", user3); +``` + +Let's find user `Paul` and filter the results by age. + +```java +var query = new Query("Paul @age:[30 40]"); +var result = jedis.ftSearch("idx:users", query).getDocuments(); +System.out.println(result); +// Prints: [id:user:3, score: 1.0, payload:null, properties:[$={"name":"Paul Zamir","email":"paul.zamir@example.com","age":35,"city":"Tel Aviv"}]] +``` + +Return only the `city` field. + +```java +var city_query = new Query("Paul @age:[30 40]"); +var city_result = jedis.ftSearch("idx:users", city_query.returnFields("city")).getDocuments(); +System.out.println(city_result); +// Prints: [id:user:3, score: 1.0, payload:null, properties:[city=Tel Aviv]] +``` + +Count all users in the same city. + +```java +AggregationBuilder ab = new AggregationBuilder("*") + .groupBy("@city", Reducers.count().as("count")); +AggregationResult ar = jedis.ftAggregate("idx:users", ab); + +for (int idx=0; idx < ar.getTotalResults(); idx++) { + System.out.println(ar.getRow(idx).getString("city") + " - " + ar.getRow(idx).getString("count")); +} +// Prints: +// London - 1 +// Tel Aviv - 2 +``` + +### Learn more + +* [Jedis API reference](https://www.javadoc.io/doc/redis.clients/jedis/latest/index.html) +* [GitHub](https://github.com/redis/jedis) diff --git a/docs/redis-clients/nodejs.md b/docs/redis-clients/nodejs.md new file mode 100644 index 0000000000..8ede0bdf47 --- /dev/null +++ b/docs/redis-clients/nodejs.md @@ -0,0 +1,301 @@ +--- +title: "Node.js guide" +linkTitle: "Node.js" +description: Connect your Node.js application to a Redis database +weight: 4 + +--- + +Install Redis and the Redis client, then connect your Node.js application to a Redis database. + +## node-redis + +[node-redis](https://github.com/redis/node-redis) is a modern, high-performance Redis client for Node.js. +`node-redis` requires a running Redis or [Redis Stack](https://redis.io/docs/stack/get-started/install/) server. See [Getting started](/docs/getting-started/) for Redis installation instructions. + +### Install + +To install node-redis, run: + +``` +npm install redis +``` + +### Connect + +Connect to localhost on port 6379. + +```js +import { createClient } from 'redis'; + +const client = createClient(); + +client.on('error', err => console.log('Redis Client Error', err)); + +await client.connect(); +``` + +Store and retrieve a simple string. + +```js +await client.set('key', 'value'); +const value = await client.get('key'); +``` + +Store and retrieve a map. + +```js +await client.hSet('user-session:123', { + name: 'John', + surname: 'Smith', + company: 'Redis', + age: 29 +}) + +let userSession = await client.hGetAll('user-session:123'); +console.log(JSON.stringify(userSession, null, 2)); +/* +{ + "surname": "Smith", + "name": "John", + "company": "Redis", + "age": "29" +} + */ +``` + +To connect to a different host or port, use a connection string in the format `redis[s]://[[username][:password]@][host][:port][/db-number]`: + +```js +createClient({ + url: 'redis://alice:foobared@awesome.redis.server:6380' +}); +``` +To check if the client is connected and ready to send commands, use `client.isReady`, which returns a Boolean. `client.isOpen` is also available. This returns `true` when the client's underlying socket is open, and `false` when it isn't (for example, when the client is still connecting or reconnecting after a network error). + +#### Connect to a Redis cluster + +To connect to a Redis cluster, use `createCluster`. + +```js +import { createCluster } from 'redis'; + +const cluster = createCluster({ + rootNodes: [ + { + url: 'redis://127.0.0.1:16379' + }, + { + url: 'redis://127.0.0.1:16380' + }, + // ... + ] +}); + +cluster.on('error', (err) => console.log('Redis Cluster Error', err)); + +await cluster.connect(); + +await cluster.set('foo', 'bar'); +const value = await cluster.get('bar'); +console.log(value); // returns 'bar' + +await cluster.quit(); +``` + +#### Connect to your production Redis with TLS + +When you deploy your application, use TLS and follow the [Redis security](/docs/management/security/) guidelines. + +```js +const client = createClient({ + username: 'default', // use your Redis user. More info https://redis.io/docs/management/security/acl/ + password: 'secret', // use your password here + socket: { + host: 'my-redis.cloud.redislabs.com', + port: 6379, + tls: true, + key: readFileSync('./redis_user_private.key'), + cert: readFileSync('./redis_user.crt'), + ca: [readFileSync('./redis_ca.pem')] + } +}); + +client.on('error', (err) => console.log('Redis Client Error', err)); + +await client.connect(); + +await client.set('foo', 'bar'); +const value = await client.get('foo'); +console.log(value) // returns 'bar' + +await client.disconnect(); +``` + +You can also use discrete parameters and UNIX sockets. Details can be found in the [client configuration guide](https://github.com/redis/node-redis/blob/master/docs/client-configuration.md). + +### Example: Indexing and querying JSON documents + +Make sure that you have Redis Stack and `node-redis` installed. Import dependencies: + +```js +import {AggregateSteps, AggregateGroupByReducers, createClient, SchemaFieldTypes} from 'redis'; +const client = createClient(); +await client.connect(); +``` + +Create an index. + +```js +try { + await client.ft.create('idx:users', { + '$.name': { + type: SchemaFieldTypes.TEXT, + sortable: true + }, + '$.city': { + type: SchemaFieldTypes.TEXT, + AS: 'city' + }, + '$.age': { + type: SchemaFieldTypes.NUMERIC, + AS: 'age' + } + }, { + ON: 'JSON', + PREFIX: 'user:' + }); +} catch (e) { + if (e.message === 'Index already exists') { + console.log('Index exists already, skipped creation.'); + } else { + // Something went wrong, perhaps RediSearch isn't installed... + console.error(e); + process.exit(1); + } +} +``` + +Create JSON documents to add to your database. + +```js +await Promise.all([ + client.json.set('user:1', '$', { + "name": "Paul John", + "email": "paul.john@example.com", + "age": 42, + "city": "London" + }), + client.json.set('user:2', '$', { + "name": "Eden Zamir", + "email": "eden.zamir@example.com", + "age": 29, + "city": "Tel Aviv" + }), + client.json.set('user:3', '$', { + "name": "Paul Zamir", + "email": "paul.zamir@example.com", + "age": 35, + "city": "Tel Aviv" + }), +]); +``` + +Let's find user 'Paul` and filter the results by age. + +```js +let result = await client.ft.search( + 'idx:users', + 'Paul @age:[30 40]' +); +console.log(JSON.stringify(result, null, 2)); +/* +{ + "total": 1, + "documents": [ + { + "id": "user:3", + "value": { + "name": "Paul Zamir", + "email": "paul.zamir@example.com", + "age": 35, + "city": "Tel Aviv" + } + } + ] +} + */ +``` + +Return only the city field. + +```js +result = await client.ft.search( + 'idx:users', + 'Paul @age:[30 40]', + { + RETURN: ['$.city'] + } +); +console.log(JSON.stringify(result, null, 2)); + +/* +{ + "total": 1, + "documents": [ + { + "id": "user:3", + "value": { + "$.city": "Tel Aviv" + } + } + ] +} + */ +``` + +Count all users in the same city. + +```js +result = await client.ft.aggregate('idx:users', '*', { + STEPS: [ + { + type: AggregateSteps.GROUPBY, + properties: ['@city'], + REDUCE: [ + { + type: AggregateGroupByReducers.COUNT, + AS: 'count' + } + ] + } + ] +}) +console.log(JSON.stringify(result, null, 2)); + +/* +{ + "total": 2, + "results": [ + { + "city": "London", + "count": "1" + }, + { + "city": "Tel Aviv", + "count": "2" + } + ] +} + */ + +await client.quit(); +``` + +### Learn more + +* [Redis commands](https://redis.js.org/#node-redis-usage-redis-commands) +* [Programmability](https://redis.js.org/#node-redis-usage-programmability) +* [Clustering](https://redis.js.org/#node-redis-usage-clustering) +* [GitHub](https://github.com/redis/node-redis) + diff --git a/docs/redis-clients/python.md b/docs/redis-clients/python.md new file mode 100644 index 0000000000..2a4e9da63a --- /dev/null +++ b/docs/redis-clients/python.md @@ -0,0 +1,212 @@ +--- +title: "Python guide" +linkTitle: "Python" +description: Connect your Python application to a Redis database +weight: 5 + +--- + +Install Redis and the Redis client, then connect your Python application to a Redis database. + +## redis-py + +Get started with the [redis-py](https://github.com/redis/redis-py) client for Redis. + +`redis-py` requires a running Redis or [Redis Stack](/docs/stack/get-started/install/) server. See [Getting started](/docs/getting-started/) for Redis installation instructions. + +### Install + +To install `redis-py`, enter: + +```bash +pip install redis +``` + +For faster performance, install Redis with [`hiredis`](https://github.com/redis/hiredis) support. This provides a compiled response parser, and for most cases requires zero code changes. By default, if `hiredis` >= 1.0 is available, `redis-py` attempts to use it for response parsing. + +```bash +pip install redis[hiredis] +``` + +### Connect + +Connect to localhost on port 6379, set a value in Redis, and retrieve it. All responses are returned as bytes in Python. To receive decoded strings, set `decode_responses=True`. For more connection options, see [these examples](https://redis.readthedocs.io/en/stable/examples.html). + +```python +r = redis.Redis(host='localhost', port=6379, decode_responses=True) +``` + +Store and retrieve a simple string. + +```python +r.set('foo', 'bar') +# True +r.get('foo') +# bar +``` + +Store and retrieve a dict. + +```python +r.hset('user-session:123', mapping={ + 'name': 'John', + "surname": 'Smith', + "company": 'Redis', + "age": 29 +}) +# True + +r.hgetall('user-session:123') +# {'surname': 'Smith', 'name': 'John', 'company': 'Redis', 'age': '29'} +``` + +#### Connect to a Redis cluster + +To connect to a Redis cluster, use `RedisCluster`. + +```python +from redis.cluster import RedisCluster + +rc = RedisCluster(host='localhost', port=16379) + +print(rc.get_nodes()) +# [[host=127.0.0.1,port=16379,name=127.0.0.1:16379,server_type=primary,redis_connection=Redis>>], ... + +rc.set('foo', 'bar') +# True + +rc.get('foo') +# b'bar' +``` +For more information, see [redis-py Clustering](https://redis-py.readthedocs.io/en/stable/clustering.html). + +#### Connect to your production Redis with TLS + +When you deploy your application, use TLS and follow the [Redis security](/docs/management/security/) guidelines. + +```python +import redis + +r = redis.Redis( + host="my-redis.cloud.redislabs.com", port=6379, + username="default", # use your Redis user. More info https://redis.io/docs/management/security/acl/ + password="secret", # use your Redis password + ssl=True, + ssl_certfile="./redis_user.crt", + ssl_keyfile="./redis_user_private.key", + ssl_ca_certs="./redis_ca.pem", +) +r.set('foo', 'bar') +# True + +r.get('foo') +# b'bar' +``` +For more information, see [redis-py TLS examples](https://redis-py.readthedocs.io/en/stable/examples/ssl_connection_examples.html). + +### Example: Indexing and querying JSON documents + +Make sure that you have Redis Stack and `redis-py` installed. Import dependencies: + +```python +import redis +from redis.commands.json.path import Path +import redis.commands.search.aggregation as aggregations +import redis.commands.search.reducers as reducers +from redis.commands.search.field import TextField, NumericField, TagField +from redis.commands.search.indexDefinition import IndexDefinition, IndexType +from redis.commands.search.query import NumericFilter, Query +``` + +Connect to your Redis database. + +```python +r = redis.Redis(host='localhost', port=6379) +``` + +Let's create some test data to add to your database. + +```python +user1 = { + "name": "Paul John", + "email": "paul.john@example.com", + "age": 42, + "city": "London" +} +user2 = { + "name": "Eden Zamir", + "email": "eden.zamir@example.com", + "age": 29, + "city": "Tel Aviv" +} +user3 = { + "name": "Paul Zamir", + "email": "paul.zamir@example.com", + "age": 35, + "city": "Tel Aviv" +} +``` + +Define indexed fields and their data types using `schema`. Use JSON path expressions to map specific JSON elements to the schema fields. + +```python +schema = ( + TextField("$.name", as_name="name"), + TagField("$.city", as_name="city"), + NumericField("$.age", as_name="age") +) +``` + +Create an index. In this example, all JSON documents with the key prefix `user:` will be indexed. For more information, see [Query syntax](/docs/stack/search/reference/query_syntax). + +```python +rs = r.ft("idx:users") +rs.create_index( + schema, + definition=IndexDefinition( + prefix=["user:"], index_type=IndexType.JSON + ) +) +# b'OK' +``` + +Use `JSON.SET` to set each user value at the specified path. + +```python +r.json().set("user:1", Path.root_path(), user1) +r.json().set("user:2", Path.root_path(), user2) +r.json().set("user:3", Path.root_path(), user3) +``` + +Let's find user `Paul` and filter the results by age. + +```python +res = rs.search( + Query("Paul @age:[30 40]") +) +# Result{1 total, docs: [Document {'id': 'user:3', 'payload': None, 'json': '{"name":"Paul Zamir","email":"paul.zamir@example.com","age":35,"city":"Tel Aviv"}'}]} +``` + +Query using JSON Path expressions. + +```python +rs.search( + Query("Paul").return_field("$.city", as_field="city") +).docs +# [Document {'id': 'user:1', 'payload': None, 'city': 'London'}, Document {'id': 'user:3', 'payload': None, 'city': 'Tel Aviv'}] +``` + +Aggregate your results using `FT.AGGREGATE`. + +```python +req = aggregations.AggregateRequest("*").group_by('@city', reducers.count().alias('count')) +print(rs.aggregate(req).rows) +# [[b'city', b'Tel Aviv', b'count', b'2'], [b'city', b'London', b'count', b'1']] +``` + +### Learn more + +* [Command reference](https://redis-py.readthedocs.io/en/stable/commands.html) +* [Tutorials](https://redis.readthedocs.io/en/stable/examples.html) +* [GitHub](https://github.com/redis/redis-py) + diff --git a/docs/reference/_index.md b/docs/reference/_index.md index f4c0481b16..6e3c864bb6 100644 --- a/docs/reference/_index.md +++ b/docs/reference/_index.md @@ -3,4 +3,5 @@ title: "Redis reference" linkTitle: "Reference" description: Specifications and protocols weight: 70 + --- diff --git a/wordlist b/wordlist index 39144c8b09..2c97b139e9 100644 --- a/wordlist +++ b/wordlist @@ -148,6 +148,7 @@ Fsyncing GDB GEODEL GET-MASTER-ADDR-BY-NAME +go-redis GPG Gbit GeoHashes @@ -156,6 +157,8 @@ Geohashes Geospatial Github Gottlieb +Gradle +HashMap HLL HLLs HMAC-SHA256 @@ -183,10 +186,18 @@ IS-MASTER-DOWN-BY-ADDR Identinal IoT Itamar +Jedis +JedisCluster +JedisPool +JedisPooled +JDK +JKS JSON JSON-encoded Janowski +Javadocs Jemalloc +js KEYSPACE Keyspace KeyspaceNotification @@ -234,6 +245,7 @@ NUMA NX NaN Nehalem +node-redis NoSQL NodeJS Noordhuis @@ -263,6 +275,7 @@ PV Parameterization Pieter Pipelining +Pool2 Predis Prev Prioglio @@ -271,6 +284,7 @@ Programmability PubSub-related Pubsub Pubsub. +Pydantic R1 R2 RC1 @@ -368,6 +382,7 @@ Snapcraft Snapshotting Solaris-derived SomeOtherValue +Sonatype SoundCloud StackOverflow StringDMA @@ -377,11 +392,15 @@ T2 TCL TCP TLS +TLS-enabled TTL TTLs Tthe Twemproxy UI +ULID +ULIds +ULIDs URI USD UTF-8 @@ -446,6 +465,10 @@ async atomicity auth authenticateClientWithUser +autoloading +Autoloading +autoload +autoloader auto-reconnection autocomplete backend @@ -485,6 +508,7 @@ cjson cleartext cli cluster-config-file +Cmd cmsgpack codename codenamed @@ -594,6 +618,7 @@ frequencyonly fsSL fsync fsyncing +func gdb geo geohash @@ -607,14 +632,19 @@ hacktoberfest handleClientsWithPendingWrites hardcoded hardlinks +HashSet +Healthcheck +healthchecks hexastore hiredis +holdApplicationUntilProxyStarts hostname hostnames hotspots hyperloglog i8 iamonds +IANA idletime idx idx'-th @@ -632,8 +662,11 @@ iojob iostat ip ip:port +Istio iterable iteratively +jedis +jedisClusterNodes jemalloc jpeg kB @@ -648,6 +681,7 @@ keyspace keyspace-notifications keyspec keystep +keytool knockknock kqueue last-failover-wins @@ -671,6 +705,7 @@ linkTitle little-endian liveness ln +LoadX509KeyPair localhost log2 logfile @@ -724,6 +759,7 @@ nonprintable nopass notify-keyspace-events notifyKeyspaceEvent +NRedisStack num-items numactl numkeys @@ -734,10 +770,12 @@ ok oldval oneof onwards +openssl optionals overcommit p50 p999 +Packagist pades pageview parameterization @@ -752,9 +790,9 @@ pid pidfile pipelined pipelining +pkcs12 pmessage ppa:redislabs -pratical pre-conditions pre-configured pre-existing @@ -763,6 +801,7 @@ pre-loaded pre-populated pre-sharding prepend +Prepend preprocessing prerequesits prev @@ -775,6 +814,7 @@ programmability programmatically programmatically-generated pseudorandom +PSR-4 pubsub qsort queueing @@ -809,6 +849,9 @@ redis-doc redis-hashes redis-lua redis-macOS-demo +redis-om-python +redis-om-python. +redis-py redis-rb-cluster redis-server redis-stable @@ -880,10 +923,13 @@ startfrom status1 status2 stdin +storepass strace struct +structs struct's struct-encoded +stunnel subcommand subcommand's subcommand. @@ -901,6 +947,7 @@ syscall systemctl taskset tcmalloc +tcp tls-port tmp tmux @@ -934,11 +981,14 @@ untuned unwatches urandom used_memory_scripts_eval +userSession usr utf8 utils +v9 value-ptr variadic +venv virginia virtualized vm From 58117e10600511ff5df2b78579ea0b7d8706fd5e Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Wed, 29 Mar 2023 23:09:00 +0300 Subject: [PATCH 175/377] Updates commands.json (#2367) --- commands.json | 739 +++++++++++++++++++++++++------------------------- 1 file changed, 369 insertions(+), 370 deletions(-) diff --git a/commands.json b/commands.json index 20a6eb1781..91f873f9b2 100644 --- a/commands.json +++ b/commands.json @@ -1,6 +1,6 @@ { "ACL": { - "summary": "A container for Access List Control commands ", + "summary": "A container for Access List Control commands.", "since": "6.0.0", "group": "server", "complexity": "Depends on subcommand.", @@ -10,7 +10,7 @@ "arity": -2 }, "ACL CAT": { - "summary": "List the ACL categories or the commands inside a category", + "summary": "Lists the ACL categories, or the commands inside a category.", "since": "6.0.0", "group": "server", "complexity": "O(1) since the categories and commands are a fixed set.", @@ -20,9 +20,9 @@ "arity": -2, "arguments": [ { - "name": "categoryname", + "name": "category", "type": "string", - "display_text": "categoryname", + "display_text": "category", "optional": true } ], @@ -33,7 +33,7 @@ ] }, "ACL DELUSER": { - "summary": "Remove the specified ACL users and the associated rules", + "summary": "Deletes ACL users, and terminates their connections.", "since": "6.0.0", "group": "server", "complexity": "O(1) amortized time considering the typical user.", @@ -59,7 +59,7 @@ ] }, "ACL DRYRUN": { - "summary": "Returns whether the user can execute the given command without executing the command.", + "summary": "Simulates the execution of a command by a user, without executing the command.", "since": "7.0.0", "group": "server", "complexity": "O(1).", @@ -96,7 +96,7 @@ ] }, "ACL GENPASS": { - "summary": "Generate a pseudorandom secure password to use for ACL users", + "summary": "Generates a pseudorandom, secure password that can be used to identify ACL users.", "since": "6.0.0", "group": "server", "complexity": "O(1)", @@ -119,7 +119,7 @@ ] }, "ACL GETUSER": { - "summary": "Get the rules for a specific ACL user", + "summary": "Lists the ACL rules of a user.", "since": "6.0.0", "group": "server", "complexity": "O(N). Where N is the number of password, command and pattern rules that the user has.", @@ -154,7 +154,7 @@ ] }, "ACL HELP": { - "summary": "Show helpful text about the different subcommands", + "summary": "Returns helpful text about the different subcommands.", "since": "6.0.0", "group": "server", "complexity": "O(1)", @@ -168,7 +168,7 @@ ] }, "ACL LIST": { - "summary": "List the current ACL rules in ACL config file format", + "summary": "Dumps the effective rules in ACL file format.", "since": "6.0.0", "group": "server", "complexity": "O(N). Where N is the number of configured users.", @@ -186,7 +186,7 @@ ] }, "ACL LOAD": { - "summary": "Reload the ACLs from the configured ACL file", + "summary": "Reloads the rules from the configured ACL file.", "since": "6.0.0", "group": "server", "complexity": "O(N). Where N is the number of configured users.", @@ -204,7 +204,7 @@ ] }, "ACL LOG": { - "summary": "List latest events denied because of ACLs in place", + "summary": "Lists recent security events generated due to ACL rules.", "since": "6.0.0", "group": "server", "complexity": "O(N) with N being the number of entries shown.", @@ -248,7 +248,7 @@ ] }, "ACL SAVE": { - "summary": "Save the current ACL rules in the configured ACL file", + "summary": "Saves the effective ACL rules in the configured ACL file.", "since": "6.0.0", "group": "server", "complexity": "O(N). Where N is the number of configured users.", @@ -266,7 +266,7 @@ ] }, "ACL SETUSER": { - "summary": "Modify or create the rules for a specific ACL user", + "summary": "Creates and modifies an ACL user and its rules.", "since": "6.0.0", "group": "server", "complexity": "O(N). Where N is the number of rules provided.", @@ -308,7 +308,7 @@ ] }, "ACL USERS": { - "summary": "List the username of all the configured ACL rules", + "summary": "Lists all ACL users.", "since": "6.0.0", "group": "server", "complexity": "O(N). Where N is the number of configured users.", @@ -326,7 +326,7 @@ ] }, "ACL WHOAMI": { - "summary": "Return the name of the user associated to the current connection", + "summary": "Returns the authenticated username of the current connection.", "since": "6.0.0", "group": "server", "complexity": "O(1)", @@ -341,7 +341,7 @@ ] }, "APPEND": { - "summary": "Append a value to a key", + "summary": "Appends a string to the value of a key. Creates the key if it doesn't exist.", "since": "2.0.0", "group": "string", "complexity": "O(1). The amortized time complexity is O(1) assuming the appended value is small and the already present value is of any size, since the dynamic string library used by Redis will double the free space available on every reallocation.", @@ -391,7 +391,7 @@ ] }, "ASKING": { - "summary": "Sent by cluster clients after an -ASK redirect", + "summary": "Signals that a cluster client is following an -ASK redirect.", "since": "3.0.0", "group": "cluster", "complexity": "O(1)", @@ -405,7 +405,7 @@ ] }, "AUTH": { - "summary": "Authenticate to the server", + "summary": "Authenticates the connection.", "since": "1.0.0", "group": "connection", "complexity": "O(N) where N is the number of passwords defined for the user", @@ -444,7 +444,7 @@ ] }, "BGREWRITEAOF": { - "summary": "Asynchronously rewrite the append-only file", + "summary": "Asynchronously rewrites the append-only file to disk.", "since": "1.0.0", "group": "server", "complexity": "O(1)", @@ -461,7 +461,7 @@ ] }, "BGSAVE": { - "summary": "Asynchronously save the dataset to disk", + "summary": "Asynchronously saves the database(s) to disk.", "since": "1.0.0", "group": "server", "complexity": "O(1)", @@ -494,7 +494,7 @@ ] }, "BITCOUNT": { - "summary": "Count set bits in a string", + "summary": "Counts the number of set bits (population counting) in a string.", "since": "2.6.0", "group": "bitmap", "complexity": "O(N)", @@ -580,7 +580,7 @@ ] }, "BITFIELD": { - "summary": "Perform arbitrary bitfield integer operations on strings", + "summary": "Performs arbitrary bitfield integer operations on strings.", "since": "3.2.0", "group": "bitmap", "complexity": "O(1) for each subcommand specified", @@ -734,7 +734,7 @@ ] }, "BITFIELD_RO": { - "summary": "Perform arbitrary bitfield integer operations on strings. Read-only variant of BITFIELD", + "summary": "Performs arbitrary read-only bitfield integer operations on strings.", "since": "6.0.0", "group": "bitmap", "complexity": "O(1) for each subcommand specified", @@ -798,7 +798,7 @@ ] }, "BITOP": { - "summary": "Perform bitwise operations between strings", + "summary": "Performs bitwise operations on multiple strings, and stores the result.", "since": "2.6.0", "group": "bitmap", "complexity": "O(N)", @@ -897,7 +897,7 @@ ] }, "BITPOS": { - "summary": "Find first bit set or clear in a string", + "summary": "Finds the first set (1) or clear (0) bit in a string.", "since": "2.8.7", "group": "bitmap", "complexity": "O(N)", @@ -995,7 +995,7 @@ ] }, "BLMOVE": { - "summary": "Pop an element from a list, push it to another list and return it; or block until one is available", + "summary": "Pops an element from a list, pushes it to another list and returns it. Blocks until an element is available otherwise. Deletes the list if the last element was moved.", "since": "6.2.0", "group": "list", "complexity": "O(1)", @@ -1107,7 +1107,7 @@ ] }, "BLMPOP": { - "summary": "Pop elements from a list, or block until one is available", + "summary": "Pops the first element from one of multiple lists. Blocks until an element is available otherwise. Deletes the list if the last element was popped.", "since": "7.0.0", "group": "list", "complexity": "O(N+M) where N is the number of provided keys and M is the number of elements returned.", @@ -1190,7 +1190,7 @@ ] }, "BLPOP": { - "summary": "Remove and get the first element in a list, or block until one is available", + "summary": "Removes and returns the first element in a list. Blocks until an element is available otherwise. Deletes the list if the last element was popped.", "since": "2.0.0", "group": "list", "complexity": "O(N) where N is the number of provided keys.", @@ -1248,7 +1248,7 @@ ] }, "BRPOP": { - "summary": "Remove and get the last element in a list, or block until one is available", + "summary": "Removes and returns the last element in a list. Blocks until an element is available otherwise. Deletes the list if the last element was popped.", "since": "2.0.0", "group": "list", "complexity": "O(N) where N is the number of provided keys.", @@ -1306,7 +1306,7 @@ ] }, "BRPOPLPUSH": { - "summary": "Pop an element from a list, push it to another list and return it; or block until one is available", + "summary": "Pops an element from a list, pushes it to another list and returns it. Block until an element is available otherwise. Deletes the list if the last element was popped.", "since": "2.2.0", "group": "list", "complexity": "O(1)", @@ -1393,7 +1393,7 @@ ] }, "BZMPOP": { - "summary": "Remove and return members with scores in a sorted set or block until one is available", + "summary": "Removes and returns a member by score from one or more sorted sets. Blocks until a member is available otherwise. Deletes the sorted set if the last element was popped.", "since": "7.0.0", "group": "sorted-set", "complexity": "O(K) + O(M*log(N)) where K is the number of provided keys, N being the number of elements in the sorted set, and M being the number of elements popped.", @@ -1476,7 +1476,7 @@ ] }, "BZPOPMAX": { - "summary": "Remove and return the member with the highest score from one or more sorted sets, or block until one is available", + "summary": "Removes and returns the member with the highest score from one or more sorted sets. Blocks until a member available otherwise. Deletes the sorted set if the last element was popped.", "since": "5.0.0", "group": "sorted-set", "complexity": "O(log(N)) with N being the number of elements in the sorted set.", @@ -1535,7 +1535,7 @@ ] }, "BZPOPMIN": { - "summary": "Remove and return the member with the lowest score from one or more sorted sets, or block until one is available", + "summary": "Removes and returns the member with the lowest score from one or more sorted sets. Blocks until a member is available otherwise. Deletes the sorted set if the last element was popped.", "since": "5.0.0", "group": "sorted-set", "complexity": "O(log(N)) with N being the number of elements in the sorted set.", @@ -1594,7 +1594,7 @@ ] }, "CLIENT": { - "summary": "A container for client connection commands", + "summary": "A container for client connection commands.", "since": "2.4.0", "group": "connection", "complexity": "Depends on subcommand.", @@ -1604,7 +1604,7 @@ "arity": -2 }, "CLIENT CACHING": { - "summary": "Instruct the server about tracking or not keys in the next request", + "summary": "Instructs the server whether to track the keys in the next request.", "since": "6.0.0", "group": "connection", "complexity": "O(1)", @@ -1640,7 +1640,7 @@ ] }, "CLIENT GETNAME": { - "summary": "Get the current connection name", + "summary": "Returns the name of the connection.", "since": "2.6.9", "group": "connection", "complexity": "O(1)", @@ -1656,7 +1656,7 @@ ] }, "CLIENT GETREDIR": { - "summary": "Get tracking notifications redirection client ID if any", + "summary": "Returns the client ID to which the connection's tracking notifications are redirected.", "since": "6.0.0", "group": "connection", "complexity": "O(1)", @@ -1672,7 +1672,7 @@ ] }, "CLIENT HELP": { - "summary": "Show helpful text about the different subcommands", + "summary": "Returns helpful text about the different subcommands.", "since": "5.0.0", "group": "connection", "complexity": "O(1)", @@ -1687,7 +1687,7 @@ ] }, "CLIENT ID": { - "summary": "Returns the client ID for the current connection", + "summary": "Returns the unique client ID of the connection.", "since": "5.0.0", "group": "connection", "complexity": "O(1)", @@ -1703,7 +1703,7 @@ ] }, "CLIENT INFO": { - "summary": "Returns information about the current client connection.", + "summary": "Returns information about the connection.", "since": "6.2.0", "group": "connection", "complexity": "O(1)", @@ -1722,7 +1722,7 @@ ] }, "CLIENT KILL": { - "summary": "Kill the connection of a client", + "summary": "Terminates open connections.", "since": "2.4.0", "group": "connection", "complexity": "O(N) where N is the number of client connections", @@ -1875,7 +1875,7 @@ ] }, "CLIENT LIST": { - "summary": "Get the list of client connections", + "summary": "Lists open connections.", "since": "2.4.0", "group": "connection", "complexity": "O(N) where N is the number of client connections", @@ -1967,7 +1967,7 @@ ] }, "CLIENT NO-EVICT": { - "summary": "Set client eviction mode for the current connection", + "summary": "Sets the client eviction mode of the connection.", "since": "7.0.0", "group": "connection", "complexity": "O(1)", @@ -2006,7 +2006,7 @@ ] }, "CLIENT NO-TOUCH": { - "summary": "Controls whether commands sent by the client will alter the LRU/LFU of the keys they access.", + "summary": "Controls whether commands sent by the client affect the LRU/LFU of accessed keys.", "since": "7.2.0", "group": "connection", "complexity": "O(1)", @@ -2042,7 +2042,7 @@ ] }, "CLIENT PAUSE": { - "summary": "Stop processing commands from clients for some time", + "summary": "Suspends commands processing.", "since": "3.0.0", "group": "connection", "complexity": "O(1)", @@ -2094,7 +2094,7 @@ ] }, "CLIENT REPLY": { - "summary": "Instruct the server whether to reply to commands", + "summary": "Instructs the server whether to reply to commands.", "since": "3.2.0", "group": "connection", "complexity": "O(1)", @@ -2136,7 +2136,7 @@ ] }, "CLIENT SETINFO": { - "summary": "Set client or connection specific info", + "summary": "Sets information specific to the client or connection.", "since": "7.2.0", "group": "connection", "complexity": "O(1)", @@ -2172,7 +2172,7 @@ ] }, "CLIENT SETNAME": { - "summary": "Set the current connection name", + "summary": "Sets the connection name.", "since": "2.6.9", "group": "connection", "complexity": "O(1)", @@ -2195,7 +2195,7 @@ ] }, "CLIENT TRACKING": { - "summary": "Enable or disable server assisted client side caching support", + "summary": "Controls server-assisted client-side caching for the connection.", "since": "6.0.0", "group": "connection", "complexity": "O(1). Some options may introduce additional complexity.", @@ -2275,7 +2275,7 @@ ] }, "CLIENT TRACKINGINFO": { - "summary": "Return information about server assisted client side caching for the current connection", + "summary": "Returns information about server-assisted client-side caching for the connection.", "since": "6.2.0", "group": "connection", "complexity": "O(1)", @@ -2291,7 +2291,7 @@ ] }, "CLIENT UNBLOCK": { - "summary": "Unblock a client blocked in a blocking command from a different connection", + "summary": "Unblocks a client blocked by a blocking command from a different connection.", "since": "5.0.0", "group": "connection", "complexity": "O(log N) where N is the number of client connections", @@ -2336,7 +2336,7 @@ ] }, "CLIENT UNPAUSE": { - "summary": "Resume processing of clients that were paused", + "summary": "Resumes processing commands from paused clients.", "since": "6.2.0", "group": "connection", "complexity": "O(N) Where N is the number of paused clients", @@ -2355,7 +2355,7 @@ ] }, "CLUSTER": { - "summary": "A container for cluster commands", + "summary": "A container for Redis Cluster commands.", "since": "3.0.0", "group": "cluster", "complexity": "Depends on subcommand.", @@ -2365,7 +2365,7 @@ "arity": -2 }, "CLUSTER ADDSLOTS": { - "summary": "Assign new hash slots to receiving node", + "summary": "Assigns new hash slots to a node.", "since": "3.0.0", "group": "cluster", "complexity": "O(N) where N is the total number of hash slot arguments", @@ -2390,7 +2390,7 @@ ] }, "CLUSTER ADDSLOTSRANGE": { - "summary": "Assign new hash slots to receiving node", + "summary": "Assigns new hash slot ranges to a node.", "since": "7.0.0", "group": "cluster", "complexity": "O(N) where N is the total number of the slots between the start slot and end slot arguments.", @@ -2426,7 +2426,7 @@ ] }, "CLUSTER BUMPEPOCH": { - "summary": "Advance the cluster config epoch", + "summary": "Advances the cluster config epoch.", "since": "3.0.0", "group": "cluster", "complexity": "O(1)", @@ -2446,7 +2446,7 @@ ] }, "CLUSTER COUNT-FAILURE-REPORTS": { - "summary": "Return the number of failure reports active for a given node", + "summary": "Returns the number of active failure reports active for a node.", "since": "3.0.0", "group": "cluster", "complexity": "O(N) where N is the number of failure reports", @@ -2472,7 +2472,7 @@ ] }, "CLUSTER COUNTKEYSINSLOT": { - "summary": "Return the number of local keys in the specified hash slot", + "summary": "Returns the number of keys in a hash slot.", "since": "3.0.0", "group": "cluster", "complexity": "O(1)", @@ -2492,7 +2492,7 @@ ] }, "CLUSTER DELSLOTS": { - "summary": "Set hash slots as unbound in receiving node", + "summary": "Sets hash slots as unbound for a node.", "since": "3.0.0", "group": "cluster", "complexity": "O(N) where N is the total number of hash slot arguments", @@ -2517,7 +2517,7 @@ ] }, "CLUSTER DELSLOTSRANGE": { - "summary": "Set hash slots as unbound in receiving node", + "summary": "Sets hash slot ranges as unbound for a node.", "since": "7.0.0", "group": "cluster", "complexity": "O(N) where N is the total number of the slots between the start slot and end slot arguments.", @@ -2591,7 +2591,7 @@ ] }, "CLUSTER FLUSHSLOTS": { - "summary": "Delete a node's own slots information", + "summary": "Deletes all slots information from a node.", "since": "3.0.0", "group": "cluster", "complexity": "O(1)", @@ -2608,7 +2608,7 @@ ] }, "CLUSTER FORGET": { - "summary": "Remove a node from the nodes table", + "summary": "Removes a node from the nodes table.", "since": "3.0.0", "group": "cluster", "complexity": "O(1)", @@ -2632,7 +2632,7 @@ ] }, "CLUSTER GETKEYSINSLOT": { - "summary": "Return local key names in the specified hash slot", + "summary": "Returns the key names in a hash slot.", "since": "3.0.0", "group": "cluster", "complexity": "O(N) where N is the number of requested keys", @@ -2660,7 +2660,7 @@ ] }, "CLUSTER HELP": { - "summary": "Show helpful text about the different subcommands", + "summary": "Returns helpful text about the different subcommands.", "since": "5.0.0", "group": "cluster", "complexity": "O(1)", @@ -2674,7 +2674,7 @@ ] }, "CLUSTER INFO": { - "summary": "Provides info about Redis Cluster node state", + "summary": "Returns information about the state of a node.", "since": "3.0.0", "group": "cluster", "complexity": "O(1)", @@ -2690,7 +2690,7 @@ ] }, "CLUSTER KEYSLOT": { - "summary": "Returns the hash slot of the specified key", + "summary": "Returns the hash slot for a key.", "since": "3.0.0", "group": "cluster", "complexity": "O(N) where N is the number of bytes in the key", @@ -2710,7 +2710,7 @@ ] }, "CLUSTER LINKS": { - "summary": "Returns a list of all TCP links to and from peer nodes in cluster", + "summary": "Returns a list of all TCP links to and from peer nodes.", "since": "7.0.0", "group": "cluster", "complexity": "O(N) where N is the total number of Cluster nodes", @@ -2726,7 +2726,7 @@ ] }, "CLUSTER MEET": { - "summary": "Force a node cluster to handshake with another node", + "summary": "Forces a node to handshake with another node.", "since": "3.0.0", "group": "cluster", "complexity": "O(1)", @@ -2768,7 +2768,7 @@ ] }, "CLUSTER MYID": { - "summary": "Return the node id", + "summary": "Returns the ID of a node.", "since": "3.0.0", "group": "cluster", "complexity": "O(1)", @@ -2781,7 +2781,7 @@ ] }, "CLUSTER MYSHARDID": { - "summary": "Return the node shard id", + "summary": "Returns the shard ID of a node.", "since": "7.2.0", "group": "cluster", "complexity": "O(1)", @@ -2797,7 +2797,7 @@ ] }, "CLUSTER NODES": { - "summary": "Get Cluster config for the node", + "summary": "Returns the cluster configuration for a node.", "since": "3.0.0", "group": "cluster", "complexity": "O(N) where N is the total number of Cluster nodes", @@ -2813,7 +2813,7 @@ ] }, "CLUSTER REPLICAS": { - "summary": "List replica nodes of the specified master node", + "summary": "Lists the replica nodes of a master node.", "since": "5.0.0", "group": "cluster", "complexity": "O(1)", @@ -2839,7 +2839,7 @@ ] }, "CLUSTER REPLICATE": { - "summary": "Reconfigure a node as a replica of the specified master node", + "summary": "Configure a node as replica of a master node.", "since": "3.0.0", "group": "cluster", "complexity": "O(1)", @@ -2863,7 +2863,7 @@ ] }, "CLUSTER RESET": { - "summary": "Reset a Redis Cluster node", + "summary": "Resets a node.", "since": "3.0.0", "group": "cluster", "complexity": "O(N) where N is the number of known nodes. The command may execute a FLUSHALL as a side effect.", @@ -2901,7 +2901,7 @@ ] }, "CLUSTER SAVECONFIG": { - "summary": "Forces the node to save cluster state on disk", + "summary": "Forces a node to save the cluster configuration to disk.", "since": "3.0.0", "group": "cluster", "complexity": "O(1)", @@ -2918,7 +2918,7 @@ ] }, "CLUSTER SET-CONFIG-EPOCH": { - "summary": "Set the configuration epoch in a new node", + "summary": "Sets the configuration epoch for a new node.", "since": "3.0.0", "group": "cluster", "complexity": "O(1)", @@ -2942,7 +2942,7 @@ ] }, "CLUSTER SETSLOT": { - "summary": "Bind a hash slot to a specific node", + "summary": "Binds a hash slot to a node.", "since": "3.0.0", "group": "cluster", "complexity": "O(1)", @@ -2996,7 +2996,7 @@ ] }, "CLUSTER SHARDS": { - "summary": "Get array of cluster slots to node mappings", + "summary": "Returns the mapping of cluster slots to shards.", "since": "7.0.0", "group": "cluster", "complexity": "O(N) where N is the total number of cluster nodes", @@ -3012,7 +3012,7 @@ ] }, "CLUSTER SLAVES": { - "summary": "List replica nodes of the specified master node", + "summary": "Lists the replica nodes of a master node.", "since": "3.0.0", "group": "cluster", "complexity": "O(1)", @@ -3043,7 +3043,7 @@ ] }, "CLUSTER SLOTS": { - "summary": "Get array of Cluster slot to node mappings", + "summary": "Returns the mapping of cluster slots to nodes.", "since": "3.0.0", "group": "cluster", "complexity": "O(N) where N is the total number of Cluster nodes", @@ -3074,7 +3074,7 @@ ] }, "COMMAND": { - "summary": "Get array of Redis command details", + "summary": "Returns detailed information about all commands.", "since": "2.8.13", "group": "server", "complexity": "O(N) where N is the total number of Redis commands", @@ -3092,7 +3092,7 @@ ] }, "COMMAND COUNT": { - "summary": "Get total number of Redis commands", + "summary": "Returns a count of commands.", "since": "2.8.13", "group": "server", "complexity": "O(1)", @@ -3107,7 +3107,7 @@ ] }, "COMMAND DOCS": { - "summary": "Get array of specific Redis command documentation", + "summary": "Returns documentary information about a command.", "since": "7.0.0", "group": "server", "complexity": "O(N) where N is the number of commands to look up", @@ -3134,7 +3134,7 @@ ] }, "COMMAND GETKEYS": { - "summary": "Extract keys given a full Redis command", + "summary": "Extracts the key names from an arbitrary command.", "since": "2.8.13", "group": "server", "complexity": "O(N) where N is the number of arguments to the command", @@ -3163,7 +3163,7 @@ ] }, "COMMAND GETKEYSANDFLAGS": { - "summary": "Extract keys and access flags given a full Redis command", + "summary": "Extracts the key names and access flags for an arbitrary command.", "since": "7.0.0", "group": "server", "complexity": "O(N) where N is the number of arguments to the command", @@ -3192,7 +3192,7 @@ ] }, "COMMAND HELP": { - "summary": "Show helpful text about the different subcommands", + "summary": "Returns helpful text about the different subcommands.", "since": "5.0.0", "group": "server", "complexity": "O(1)", @@ -3207,7 +3207,7 @@ ] }, "COMMAND INFO": { - "summary": "Get array of specific Redis command details, or all when no argument is given.", + "summary": "Returns information about one, multiple or all commands.", "since": "2.8.13", "group": "server", "complexity": "O(N) where N is the number of commands to look up", @@ -3240,7 +3240,7 @@ ] }, "COMMAND LIST": { - "summary": "Get an array of Redis command names", + "summary": "Returns a list of command names.", "since": "7.0.0", "group": "server", "complexity": "O(N) where N is the total number of Redis commands", @@ -3286,7 +3286,7 @@ ] }, "CONFIG": { - "summary": "A container for server configuration commands", + "summary": "A container for server configuration commands.", "since": "2.0.0", "group": "server", "complexity": "Depends on subcommand.", @@ -3296,7 +3296,7 @@ "arity": -2 }, "CONFIG GET": { - "summary": "Get the values of configuration parameters", + "summary": "Returns the effective values of configuration parameters.", "since": "2.0.0", "group": "server", "complexity": "O(N) when N is the number of configuration parameters provided", @@ -3328,7 +3328,7 @@ ] }, "CONFIG HELP": { - "summary": "Show helpful text about the different subcommands", + "summary": "Returns helpful text about the different subcommands.", "since": "5.0.0", "group": "server", "complexity": "O(1)", @@ -3342,7 +3342,7 @@ ] }, "CONFIG RESETSTAT": { - "summary": "Reset the stats returned by INFO", + "summary": "Resets the server's statistics.", "since": "2.0.0", "group": "server", "complexity": "O(1)", @@ -3360,7 +3360,7 @@ ] }, "CONFIG REWRITE": { - "summary": "Rewrite the configuration file with the in memory configuration", + "summary": "Persists the effective configuration to file.", "since": "2.8.0", "group": "server", "complexity": "O(1)", @@ -3378,7 +3378,7 @@ ] }, "CONFIG SET": { - "summary": "Set configuration parameters to the given values", + "summary": "Sets configuration parameters in-flight.", "since": "2.0.0", "group": "server", "complexity": "O(N) when N is the number of configuration parameters provided", @@ -3425,7 +3425,7 @@ ] }, "COPY": { - "summary": "Copy a key", + "summary": "Copies the value of a key to a new key.", "since": "6.2.0", "group": "generic", "complexity": "O(N) worst case for collections, where N is the number of nested items. O(1) for string values.", @@ -3507,7 +3507,7 @@ ] }, "DBSIZE": { - "summary": "Return the number of keys in the selected database", + "summary": "Returns the number of keys in the database.", "since": "1.0.0", "group": "server", "complexity": "O(1)", @@ -3527,7 +3527,7 @@ ] }, "DEBUG": { - "summary": "A container for debugging commands", + "summary": "A container for debugging commands.", "since": "1.0.0", "group": "server", "complexity": "Depends on subcommand.", @@ -3548,7 +3548,7 @@ ] }, "DECR": { - "summary": "Decrement the integer value of a key by one", + "summary": "Decrements the integer value of a key by one. Uses 0 as initial value if the key doesn't exist.", "since": "1.0.0", "group": "string", "complexity": "O(1)", @@ -3594,7 +3594,7 @@ ] }, "DECRBY": { - "summary": "Decrement the integer value of a key by the given number", + "summary": "Decrements a number from the integer value of a key. Uses 0 as initial value if the key doesn't exist.", "since": "1.0.0", "group": "string", "complexity": "O(1)", @@ -3645,7 +3645,7 @@ ] }, "DEL": { - "summary": "Delete a key", + "summary": "Deletes one or more keys.", "since": "1.0.0", "group": "generic", "complexity": "O(N) where N is the number of keys that will be removed. When a key to remove holds a value other than a string, the individual complexity for this key is O(M) where M is the number of elements in the list, set, sorted set or hash. Removing a single key that holds a string value is O(1).", @@ -3693,7 +3693,7 @@ ] }, "DISCARD": { - "summary": "Discard all commands issued after MULTI", + "summary": "Discards a transaction.", "since": "2.0.0", "group": "transactions", "complexity": "O(N), when N is the number of queued commands", @@ -3711,7 +3711,7 @@ ] }, "DUMP": { - "summary": "Return a serialized version of the value stored at the specified key.", + "summary": "Returns a serialized representation of the value stored at a key.", "since": "2.6.0", "group": "generic", "complexity": "O(1) to access the key and additional O(N*M) to serialize it, where N is the number of Redis objects composing the value and M their average size. For small string values the time complexity is thus O(1)+O(1*M) where M is small, so simply O(1).", @@ -3757,7 +3757,7 @@ ] }, "ECHO": { - "summary": "Echo the given string", + "summary": "Returns the given string.", "since": "1.0.0", "group": "connection", "complexity": "O(1)", @@ -3780,7 +3780,7 @@ ] }, "EVAL": { - "summary": "Execute a Lua script server side", + "summary": "Executes a server-side Lua script.", "since": "2.6.0", "group": "scripting", "complexity": "Depends on the script that is executed.", @@ -3847,7 +3847,7 @@ ] }, "EVALSHA": { - "summary": "Execute a Lua script server side", + "summary": "Executes a server-side Lua script by SHA1 digest.", "since": "2.6.0", "group": "scripting", "complexity": "Depends on the script that is executed.", @@ -3913,7 +3913,7 @@ ] }, "EVALSHA_RO": { - "summary": "Execute a read-only Lua script server side", + "summary": "Executes a read-only server-side Lua script by SHA1 digest.", "since": "7.0.0", "group": "scripting", "complexity": "Depends on the script that is executed.", @@ -3979,7 +3979,7 @@ ] }, "EVAL_RO": { - "summary": "Execute a read-only Lua script server side", + "summary": "Executes a read-only server-side Lua script.", "since": "7.0.0", "group": "scripting", "complexity": "Depends on the script that is executed.", @@ -4046,7 +4046,7 @@ ] }, "EXEC": { - "summary": "Execute all commands issued after MULTI", + "summary": "Executes all commands in a transaction.", "since": "1.2.0", "group": "transactions", "complexity": "Depends on commands in the transaction", @@ -4063,7 +4063,7 @@ ] }, "EXISTS": { - "summary": "Determine if a key exists", + "summary": "Determines whether one or more keys exist.", "since": "1.0.0", "group": "generic", "complexity": "O(N) where N is the number of keys to check.", @@ -4117,7 +4117,7 @@ ] }, "EXPIRE": { - "summary": "Set a key's time to live in seconds", + "summary": "Sets the expiration time of a key in seconds.", "since": "1.0.0", "group": "generic", "complexity": "O(1)", @@ -4204,7 +4204,7 @@ ] }, "EXPIREAT": { - "summary": "Set the expiration for a key as a UNIX timestamp", + "summary": "Sets the expiration time of a key to a Unix timestamp.", "since": "1.2.0", "group": "generic", "complexity": "O(1)", @@ -4291,7 +4291,7 @@ ] }, "EXPIRETIME": { - "summary": "Get the expiration Unix timestamp for a key", + "summary": "Returns the expiration time of a key as a Unix timestamp.", "since": "7.0.0", "group": "generic", "complexity": "O(1)", @@ -4335,7 +4335,7 @@ ] }, "FAILOVER": { - "summary": "Start a coordinated failover between this server and one of its replicas.", + "summary": "Starts a coordinated failover from a server to one of its replicas.", "since": "6.2.0", "group": "server", "complexity": "O(1)", @@ -4393,7 +4393,7 @@ ] }, "FCALL": { - "summary": "Invoke a function", + "summary": "Invokes a function.", "since": "7.0.0", "group": "scripting", "complexity": "Depends on the function that is executed.", @@ -4460,7 +4460,7 @@ ] }, "FCALL_RO": { - "summary": "Invoke a read-only function", + "summary": "Invokes a read-only function.", "since": "7.0.0", "group": "scripting", "complexity": "Depends on the function that is executed.", @@ -4527,7 +4527,7 @@ ] }, "FLUSHALL": { - "summary": "Remove all keys from all databases", + "summary": "Removes all keys from all databases.", "since": "1.0.0", "group": "server", "complexity": "O(N) where N is the total number of keys in all databases", @@ -4580,7 +4580,7 @@ ] }, "FLUSHDB": { - "summary": "Remove all keys from the current database", + "summary": "Remove all keys from the current database.", "since": "1.0.0", "group": "server", "complexity": "O(N) where N is the number of keys in the selected database", @@ -4633,7 +4633,7 @@ ] }, "FUNCTION": { - "summary": "A container for function commands", + "summary": "A container for function commands.", "since": "7.0.0", "group": "scripting", "complexity": "Depends on subcommand.", @@ -4643,7 +4643,7 @@ "arity": -2 }, "FUNCTION DELETE": { - "summary": "Delete a function by name", + "summary": "Deletes a library and its functions.", "since": "7.0.0", "group": "scripting", "complexity": "O(1)", @@ -4670,7 +4670,7 @@ ] }, "FUNCTION DUMP": { - "summary": "Dump all functions into a serialized binary payload", + "summary": "Dumps all libraries into a serialized binary payload.", "since": "7.0.0", "group": "scripting", "complexity": "O(N) where N is the number of functions", @@ -4684,7 +4684,7 @@ ] }, "FUNCTION FLUSH": { - "summary": "Deleting all functions", + "summary": "Deletes all libraries and functions.", "since": "7.0.0", "group": "scripting", "complexity": "O(N) where N is the number of functions deleted", @@ -4725,7 +4725,7 @@ ] }, "FUNCTION HELP": { - "summary": "Show helpful text about the different subcommands", + "summary": "Returns helpful text about the different subcommands.", "since": "7.0.0", "group": "scripting", "complexity": "O(1)", @@ -4740,7 +4740,7 @@ ] }, "FUNCTION KILL": { - "summary": "Kill the function currently in execution.", + "summary": "Terminates a function during execution.", "since": "7.0.0", "group": "scripting", "complexity": "O(1)", @@ -4759,7 +4759,7 @@ ] }, "FUNCTION LIST": { - "summary": "List information about all the functions", + "summary": "Returns information about all libraries.", "since": "7.0.0", "group": "scripting", "complexity": "O(N) where N is the number of functions", @@ -4792,7 +4792,7 @@ ] }, "FUNCTION LOAD": { - "summary": "Create a function with the given arguments (name, code, description)", + "summary": "Creates a library.", "since": "7.0.0", "group": "scripting", "complexity": "O(1) (considering compilation time is redundant)", @@ -4827,7 +4827,7 @@ ] }, "FUNCTION RESTORE": { - "summary": "Restore all the functions on the given payload", + "summary": "Restores all libraries from a payload.", "since": "7.0.0", "group": "scripting", "complexity": "O(N) where N is the number of functions on the payload", @@ -4880,7 +4880,7 @@ ] }, "FUNCTION STATS": { - "summary": "Return information about the function currently running (name, description, duration)", + "summary": "Returns information about a function during execution.", "since": "7.0.0", "group": "scripting", "complexity": "O(1)", @@ -4900,7 +4900,7 @@ ] }, "GEOADD": { - "summary": "Add one or more geospatial items in the geospatial index represented using a sorted set", + "summary": "Adds one or more members to a geospatial index. The key is created if it doesn't exist.", "since": "3.2.0", "group": "geo", "complexity": "O(log(N)) for each item added, where N is the number of elements in the sorted set.", @@ -5000,7 +5000,7 @@ ] }, "GEODIST": { - "summary": "Returns the distance between two members of a geospatial index", + "summary": "Returns the distance between two members of a geospatial index.", "since": "3.2.0", "group": "geo", "complexity": "O(log(N))", @@ -5084,7 +5084,7 @@ ] }, "GEOHASH": { - "summary": "Returns members of a geospatial index as standard geohash strings", + "summary": "Returns members from a geospatial index as geohash strings.", "since": "3.2.0", "group": "geo", "complexity": "O(log(N)) for each member requested, where N is the number of elements in the sorted set.", @@ -5134,7 +5134,7 @@ ] }, "GEOPOS": { - "summary": "Returns longitude and latitude of members of a geospatial index", + "summary": "Returns the longitude and latitude of members from a geospatial index.", "since": "3.2.0", "group": "geo", "complexity": "O(N) where N is the number of members requested.", @@ -5184,7 +5184,7 @@ ] }, "GEORADIUS": { - "summary": "Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a point", + "summary": "Queries a geospatial index for members within a distance from a coordinate, optionally stores the result.", "since": "3.2.0", "group": "geo", "complexity": "O(N+log(M)) where N is the number of elements inside the bounding box of the circular area delimited by center and radius and M is the number of items inside the index.", @@ -5404,7 +5404,7 @@ ] }, "GEORADIUSBYMEMBER": { - "summary": "Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a member", + "summary": "Queries a geospatial index for members within a distance from a member, optionally stores the result.", "since": "3.2.0", "group": "geo", "complexity": "O(N+log(M)) where N is the number of elements inside the bounding box of the circular area delimited by center and radius and M is the number of items inside the index.", @@ -5614,7 +5614,7 @@ ] }, "GEORADIUSBYMEMBER_RO": { - "summary": "A read-only variant for GEORADIUSBYMEMBER", + "summary": "Returns members from a geospatial index that are within a distance from a member.", "since": "3.2.10", "group": "geo", "complexity": "O(N+log(M)) where N is the number of elements inside the bounding box of the circular area delimited by center and radius and M is the number of items inside the index.", @@ -5762,7 +5762,7 @@ ] }, "GEORADIUS_RO": { - "summary": "A read-only variant for GEORADIUS", + "summary": "Returns members from a geospatial index that are within a distance from a coordinate.", "since": "3.2.10", "group": "geo", "complexity": "O(N+log(M)) where N is the number of elements inside the bounding box of the circular area delimited by center and radius and M is the number of items inside the index.", @@ -5922,7 +5922,7 @@ ] }, "GEOSEARCH": { - "summary": "Query a sorted set representing a geospatial index to fetch members inside an area of a box or a circle.", + "summary": "Queries a geospatial index for members inside an area of a box or a circle.", "since": "6.2.0", "group": "geo", "complexity": "O(N+log(M)) where N is the number of elements in the grid-aligned bounding box area around the shape provided as the filter and M is the number of items inside the shape", @@ -6155,7 +6155,7 @@ ] }, "GEOSEARCHSTORE": { - "summary": "Query a sorted set representing a geospatial index to fetch members inside an area of a box or a circle, and store the result in another key.", + "summary": "Queries a geospatial index for members inside an area of a box or a circle, optionally stores the result.", "since": "6.2.0", "group": "geo", "complexity": "O(N+log(M)) where N is the number of elements in the grid-aligned bounding box area around the shape provided as the filter and M is the number of items inside the shape", @@ -6399,7 +6399,7 @@ ] }, "GET": { - "summary": "Get the value of a key", + "summary": "Returns the string value of a key.", "since": "1.0.0", "group": "string", "complexity": "O(1)", @@ -6443,7 +6443,7 @@ ] }, "GETBIT": { - "summary": "Returns the bit value at offset in the string value stored at key", + "summary": "Returns a bit value by offset.", "since": "2.2.0", "group": "bitmap", "complexity": "O(1)", @@ -6492,7 +6492,7 @@ ] }, "GETDEL": { - "summary": "Get the value of a key and delete the key", + "summary": "Returns the string value of a key after deleting the key.", "since": "6.2.0", "group": "string", "complexity": "O(1)", @@ -6537,7 +6537,7 @@ ] }, "GETEX": { - "summary": "Get the value of a key and optionally set its expiration", + "summary": "Returns the string value of a key after setting its expiration time.", "since": "6.2.0", "group": "string", "complexity": "O(1)", @@ -6620,7 +6620,7 @@ ] }, "GETRANGE": { - "summary": "Get a substring of the string stored at a key", + "summary": "Returns a substring of the string stored at a key.", "since": "2.4.0", "group": "string", "complexity": "O(N) where N is the length of the returned string. The complexity is ultimately determined by the returned length, but because creating a substring from an existing string is very cheap, it can be considered O(1) for small strings.", @@ -6673,7 +6673,7 @@ ] }, "GETSET": { - "summary": "Set the string value of a key and return its old value", + "summary": "Returns the previous string value of a key after setting it to a new value.", "since": "1.0.0", "group": "string", "complexity": "O(1)", @@ -6729,7 +6729,7 @@ ] }, "HDEL": { - "summary": "Delete one or more hash fields", + "summary": "Deletes one or more fields and their values from a hash. Deletes the hash if no fields remain.", "since": "2.0.0", "group": "hash", "complexity": "O(N) where N is the number of fields to be removed.", @@ -6785,7 +6785,7 @@ ] }, "HELLO": { - "summary": "Handshake with Redis", + "summary": "Handshakes with the Redis server.", "since": "6.0.0", "group": "connection", "complexity": "O(1)", @@ -6849,7 +6849,7 @@ ] }, "HEXISTS": { - "summary": "Determine if a hash field exists", + "summary": "Determines whether a field exists in a hash.", "since": "2.0.0", "group": "hash", "complexity": "O(1)", @@ -6897,7 +6897,7 @@ ] }, "HGET": { - "summary": "Get the value of a hash field", + "summary": "Returns the value of a field in a hash.", "since": "2.0.0", "group": "hash", "complexity": "O(1)", @@ -6946,7 +6946,7 @@ ] }, "HGETALL": { - "summary": "Get all the fields and values in a hash", + "summary": "Returns all fields and values in a hash.", "since": "2.0.0", "group": "hash", "complexity": "O(N) where N is the size of the hash.", @@ -6992,7 +6992,7 @@ ] }, "HINCRBY": { - "summary": "Increment the integer value of a hash field by the given number", + "summary": "Increments the integer value of a field in a hash by a number. Uses 0 as initial value if the field doesn't exist.", "since": "2.0.0", "group": "hash", "complexity": "O(1)", @@ -7048,7 +7048,7 @@ ] }, "HINCRBYFLOAT": { - "summary": "Increment the float value of a hash field by the given amount", + "summary": "Increments the floating point value of a field by a number. Uses 0 as initial value if the field doesn't exist.", "since": "2.6.0", "group": "hash", "complexity": "O(1)", @@ -7104,7 +7104,7 @@ ] }, "HKEYS": { - "summary": "Get all the fields in a hash", + "summary": "Returns all fields in a hash.", "since": "2.0.0", "group": "hash", "complexity": "O(N) where N is the size of the hash.", @@ -7150,7 +7150,7 @@ ] }, "HLEN": { - "summary": "Get the number of fields in a hash", + "summary": "Returns the number of fields in a hash.", "since": "2.0.0", "group": "hash", "complexity": "O(1)", @@ -7193,7 +7193,7 @@ ] }, "HMGET": { - "summary": "Get the values of all the given hash fields", + "summary": "Returns the values of all fields in a hash.", "since": "2.0.0", "group": "hash", "complexity": "O(N) where N is the number of fields being requested.", @@ -7243,7 +7243,7 @@ ] }, "HMSET": { - "summary": "Set multiple hash fields to multiple values", + "summary": "Sets the values of multiple fields.", "since": "2.0.0", "group": "hash", "complexity": "O(N) where N is the number of fields being set.", @@ -7310,7 +7310,7 @@ ] }, "HRANDFIELD": { - "summary": "Get one or multiple random fields from a hash", + "summary": "Returns one or more random fields from a hash.", "since": "6.2.0", "group": "hash", "complexity": "O(N) where N is the number of fields returned", @@ -7375,7 +7375,7 @@ ] }, "HSCAN": { - "summary": "Incrementally iterate hash fields and associated values", + "summary": "Iterates over fields and values of a hash.", "since": "2.8.0", "group": "hash", "complexity": "O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection.", @@ -7440,7 +7440,7 @@ ] }, "HSET": { - "summary": "Set the string value of a hash field", + "summary": "Creates or modifies the value of a field in a hash.", "since": "2.0.0", "group": "hash", "complexity": "O(1) for each field/value pair added, so O(N) to add N field/value pairs when the command is called with multiple field/value pairs.", @@ -7508,7 +7508,7 @@ ] }, "HSETNX": { - "summary": "Set the value of a hash field, only if the field does not exist", + "summary": "Sets the value of a field in a hash only when the field doesn't exist.", "since": "2.0.0", "group": "hash", "complexity": "O(1)", @@ -7563,7 +7563,7 @@ ] }, "HSTRLEN": { - "summary": "Get the length of the value of a hash field", + "summary": "Returns the length of the value of a field.", "since": "3.2.0", "group": "hash", "complexity": "O(1)", @@ -7611,7 +7611,7 @@ ] }, "HVALS": { - "summary": "Get all the values in a hash", + "summary": "Returns all values in a hash.", "since": "2.0.0", "group": "hash", "complexity": "O(N) where N is the size of the hash.", @@ -7657,7 +7657,7 @@ ] }, "INCR": { - "summary": "Increment the integer value of a key by one", + "summary": "Increments the integer value of a key by one. Uses 0 as initial value if the key doesn't exist.", "since": "1.0.0", "group": "string", "complexity": "O(1)", @@ -7703,7 +7703,7 @@ ] }, "INCRBY": { - "summary": "Increment the integer value of a key by the given amount", + "summary": "Increments the integer value of a key by a number. Uses 0 as initial value if the key doesn't exist.", "since": "1.0.0", "group": "string", "complexity": "O(1)", @@ -7754,7 +7754,7 @@ ] }, "INCRBYFLOAT": { - "summary": "Increment the float value of a key by the given amount", + "summary": "Increment the floating point value of a key by a number. Uses 0 as initial value if the key doesn't exist.", "since": "2.6.0", "group": "string", "complexity": "O(1)", @@ -7805,7 +7805,7 @@ ] }, "INFO": { - "summary": "Get information and statistics about the server", + "summary": "Returns information and statistics about the server.", "since": "1.0.0", "group": "server", "complexity": "O(1)", @@ -7840,7 +7840,7 @@ ] }, "KEYS": { - "summary": "Find all keys matching the given pattern", + "summary": "Returns all key names that match a pattern.", "since": "1.0.0", "group": "generic", "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.", @@ -7867,7 +7867,7 @@ ] }, "LASTSAVE": { - "summary": "Get the UNIX time stamp of the last successful save to disk", + "summary": "Returns the Unix timestamp of the last successful save to disk.", "since": "1.0.0", "group": "server", "complexity": "O(1)", @@ -7887,7 +7887,7 @@ ] }, "LATENCY": { - "summary": "A container for latency diagnostics commands", + "summary": "A container for latency diagnostics commands.", "since": "2.8.13", "group": "server", "complexity": "Depends on subcommand.", @@ -7897,7 +7897,7 @@ "arity": -2 }, "LATENCY DOCTOR": { - "summary": "Return a human readable latency analysis report.", + "summary": "Returns a human-readable latency analysis report.", "since": "2.8.13", "group": "server", "complexity": "O(1)", @@ -7920,7 +7920,7 @@ ] }, "LATENCY GRAPH": { - "summary": "Return a latency graph for the event.", + "summary": "Returns a latency graph for an event.", "since": "2.8.13", "group": "server", "complexity": "O(1)", @@ -7950,7 +7950,7 @@ ] }, "LATENCY HELP": { - "summary": "Show helpful text about the different subcommands.", + "summary": "Returns helpful text about the different subcommands.", "since": "2.8.13", "group": "server", "complexity": "O(1)", @@ -7964,7 +7964,7 @@ ] }, "LATENCY HISTOGRAM": { - "summary": "Return the cumulative distribution of latencies of a subset of commands or all.", + "summary": "Returns the cumulative distribution of latencies of a subset or all commands.", "since": "7.0.0", "group": "server", "complexity": "O(N) where N is the number of commands with latency information being retrieved.", @@ -7996,7 +7996,7 @@ ] }, "LATENCY HISTORY": { - "summary": "Return timestamp-latency samples for the event.", + "summary": "Returns timestamp-latency samples for an event.", "since": "2.8.13", "group": "server", "complexity": "O(1)", @@ -8026,7 +8026,7 @@ ] }, "LATENCY LATEST": { - "summary": "Return the latest latency samples for all events.", + "summary": "Returns the latest latency samples for all events.", "since": "2.8.13", "group": "server", "complexity": "O(1)", @@ -8049,7 +8049,7 @@ ] }, "LATENCY RESET": { - "summary": "Reset latency data for one or more events.", + "summary": "Resets the latency data for one or more events.", "since": "2.8.13", "group": "server", "complexity": "O(1)", @@ -8080,7 +8080,7 @@ ] }, "LCS": { - "summary": "Find longest common substring", + "summary": "Finds the longest common substring.", "since": "7.0.0", "group": "string", "complexity": "O(N*M) where N and M are the lengths of s1 and s2, respectively", @@ -8157,7 +8157,7 @@ ] }, "LINDEX": { - "summary": "Get an element from a list by its index", + "summary": "Returns an element from a list by its index.", "since": "1.0.0", "group": "list", "complexity": "O(N) where N is the number of elements to traverse to get to the element at index. This makes asking for the first or the last element of the list O(1).", @@ -8205,7 +8205,7 @@ ] }, "LINSERT": { - "summary": "Insert an element before or after another element in a list", + "summary": "Inserts an element before or after another element in a list.", "since": "2.2.0", "group": "list", "complexity": "O(N) where N is the number of elements to traverse before seeing the value pivot. This means that inserting somewhere on the left end on the list (head) can be considered O(1) and inserting somewhere on the right end (tail) is O(N).", @@ -8277,7 +8277,7 @@ ] }, "LLEN": { - "summary": "Get the length of a list", + "summary": "Returns the length of a list.", "since": "1.0.0", "group": "list", "complexity": "O(1)", @@ -8320,7 +8320,7 @@ ] }, "LMOVE": { - "summary": "Pop an element from a list, push it to another list and return it", + "summary": "Returns an element after popping it from one list and pushing it to another. Deletes the list if the last element was moved.", "since": "6.2.0", "group": "list", "complexity": "O(1)", @@ -8425,7 +8425,7 @@ ] }, "LMPOP": { - "summary": "Pop elements from a list", + "summary": "Returns multiple elements from a list after removing them. Deletes the list if the last element was popped.", "since": "7.0.0", "group": "list", "complexity": "O(N+M) where N is the number of provided keys and M is the number of elements returned.", @@ -8501,7 +8501,7 @@ ] }, "LOLWUT": { - "summary": "Display some computer art and the Redis version", + "summary": "Displays computer art and the Redis version", "since": "5.0.0", "group": "server", "acl_categories": [ @@ -8524,7 +8524,7 @@ ] }, "LPOP": { - "summary": "Remove and get the first elements in a list", + "summary": "Returns the first elements in a list after removing it. Deletes the list if the last element was popped.", "since": "1.0.0", "group": "list", "complexity": "O(N) where N is the number of elements returned", @@ -8582,7 +8582,7 @@ ] }, "LPOS": { - "summary": "Return the index of matching elements on a list", + "summary": "Returns the index of matching elements in a list.", "since": "6.0.6", "group": "list", "complexity": "O(N) where N is the number of elements in the list, for the average case. When searching for elements near the head or the tail of the list, or when the MAXLEN option is provided, the command may run in constant time.", @@ -8651,7 +8651,7 @@ ] }, "LPUSH": { - "summary": "Prepend one or multiple elements to a list", + "summary": "Prepends one or more elements to a list. Creates the key if it doesn't exist.", "since": "1.0.0", "group": "list", "complexity": "O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments.", @@ -8708,7 +8708,7 @@ ] }, "LPUSHX": { - "summary": "Prepend an element to a list, only if the list exists", + "summary": "Prepends one or more elements to a list only when the list exists.", "since": "2.2.0", "group": "list", "complexity": "O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments.", @@ -8765,7 +8765,7 @@ ] }, "LRANGE": { - "summary": "Get a range of elements from a list", + "summary": "Returns a range of elements from a list.", "since": "1.0.0", "group": "list", "complexity": "O(S+N) where S is the distance of start offset from HEAD for small lists, from nearest end (HEAD or TAIL) for large lists; and N is the number of elements in the specified range.", @@ -8818,7 +8818,7 @@ ] }, "LREM": { - "summary": "Remove elements from a list", + "summary": "Removes elements from a list. Deletes the list if the last element was removed.", "since": "1.0.0", "group": "list", "complexity": "O(N+M) where N is the length of the list and M is the number of elements removed.", @@ -8871,7 +8871,7 @@ ] }, "LSET": { - "summary": "Set the value of an element in a list by its index", + "summary": "Sets the value of an element in a list by its index.", "since": "1.0.0", "group": "list", "complexity": "O(N) where N is the length of the list. Setting either the first or the last element of the list is O(1).", @@ -8925,7 +8925,7 @@ ] }, "LTRIM": { - "summary": "Trim a list to the specified range", + "summary": "Removes elements from both ends a list. Deletes the list if all elements were trimmed.", "since": "1.0.0", "group": "list", "complexity": "O(N) where N is the number of elements to be removed by the operation.", @@ -8978,7 +8978,7 @@ ] }, "MEMORY": { - "summary": "A container for memory diagnostics commands", + "summary": "A container for memory diagnostics commands.", "since": "4.0.0", "group": "server", "complexity": "Depends on subcommand.", @@ -8988,7 +8988,7 @@ "arity": -2 }, "MEMORY DOCTOR": { - "summary": "Outputs memory problems report", + "summary": "Outputs a memory problems report.", "since": "4.0.0", "group": "server", "complexity": "O(1)", @@ -9003,7 +9003,7 @@ ] }, "MEMORY HELP": { - "summary": "Show helpful text about the different subcommands", + "summary": "Returns helpful text about the different subcommands.", "since": "4.0.0", "group": "server", "complexity": "O(1)", @@ -9017,7 +9017,7 @@ ] }, "MEMORY MALLOC-STATS": { - "summary": "Show allocator internal stats", + "summary": "Returns the allocator statistics.", "since": "4.0.0", "group": "server", "complexity": "Depends on how much memory is allocated, could be slow", @@ -9032,7 +9032,7 @@ ] }, "MEMORY PURGE": { - "summary": "Ask the allocator to release memory", + "summary": "Asks the allocator to release memory.", "since": "4.0.0", "group": "server", "complexity": "Depends on how much memory is allocated, could be slow", @@ -9046,7 +9046,7 @@ ] }, "MEMORY STATS": { - "summary": "Show memory usage details", + "summary": "Returns details about memory usage.", "since": "4.0.0", "group": "server", "complexity": "O(1)", @@ -9061,7 +9061,7 @@ ] }, "MEMORY USAGE": { - "summary": "Estimate the memory usage of a key", + "summary": "Estimates the memory usage of a key.", "since": "4.0.0", "group": "server", "complexity": "O(N) where N is the number of samples.", @@ -9109,7 +9109,7 @@ ] }, "MGET": { - "summary": "Get the values of all the given keys", + "summary": "Atomically returns the string values of one or more keys.", "since": "1.0.0", "group": "string", "complexity": "O(N) where N is the number of keys to retrieve.", @@ -9157,7 +9157,7 @@ ] }, "MIGRATE": { - "summary": "Atomically transfer a key from a Redis instance to another one.", + "summary": "Atomically transfers a key from one Redis instance to another.", "since": "2.6.0", "group": "generic", "complexity": "This command actually executes a DUMP+DEL in the source instance, and a RESTORE in the target instance. See the pages of these commands for time complexity. Also an O(N) data transfer between the two instances is performed.", @@ -9335,7 +9335,7 @@ ] }, "MODULE": { - "summary": "A container for module commands", + "summary": "A container for module commands.", "since": "4.0.0", "group": "server", "complexity": "Depends on subcommand.", @@ -9345,7 +9345,7 @@ "arity": -2 }, "MODULE HELP": { - "summary": "Show helpful text about the different subcommands", + "summary": "Returns helpful text about the different subcommands.", "since": "5.0.0", "group": "server", "complexity": "O(1)", @@ -9359,7 +9359,7 @@ ] }, "MODULE LIST": { - "summary": "List all modules loaded by the server", + "summary": "Returns all loaded modules.", "since": "4.0.0", "group": "server", "complexity": "O(N) where N is the number of loaded modules.", @@ -9378,7 +9378,7 @@ ] }, "MODULE LOAD": { - "summary": "Load a module", + "summary": "Loads a module.", "since": "4.0.0", "group": "server", "complexity": "O(1)", @@ -9409,7 +9409,7 @@ ] }, "MODULE LOADEX": { - "summary": "Load a module with extended parameters", + "summary": "Loads a module using extended parameters.", "since": "7.0.0", "group": "server", "complexity": "O(1)", @@ -9461,7 +9461,7 @@ ] }, "MODULE UNLOAD": { - "summary": "Unload a module", + "summary": "Unloads a module.", "since": "4.0.0", "group": "server", "complexity": "O(1)", @@ -9485,7 +9485,7 @@ ] }, "MONITOR": { - "summary": "Listen for all requests received by the server in real time", + "summary": "Listens for all requests received by the server in real-time.", "since": "1.0.0", "group": "server", "acl_categories": [ @@ -9502,7 +9502,7 @@ ] }, "MOVE": { - "summary": "Move a key to another database", + "summary": "Moves a key to another database.", "since": "1.0.0", "group": "generic", "complexity": "O(1)", @@ -9552,7 +9552,7 @@ ] }, "MSET": { - "summary": "Set multiple keys to multiple values", + "summary": "Atomically creates or modifies the string values of one or more keys.", "since": "1.0.1", "group": "string", "complexity": "O(N) where N is the number of keys to set.", @@ -9612,7 +9612,7 @@ ] }, "MSETNX": { - "summary": "Set multiple keys to multiple values, only if none of the keys exist", + "summary": "Atomically modifies the string values of one or more keys only when all keys don't exist.", "since": "1.0.1", "group": "string", "complexity": "O(N) where N is the number of keys to set.", @@ -9672,7 +9672,7 @@ ] }, "MULTI": { - "summary": "Mark the start of a transaction block", + "summary": "Starts a transaction.", "since": "1.2.0", "group": "transactions", "complexity": "O(1)", @@ -9690,7 +9690,7 @@ ] }, "OBJECT": { - "summary": "A container for object introspection commands", + "summary": "A container for object introspection commands.", "since": "2.2.3", "group": "generic", "complexity": "Depends on subcommand.", @@ -9700,7 +9700,7 @@ "arity": -2 }, "OBJECT ENCODING": { - "summary": "Inspect the internal encoding of a Redis object", + "summary": "Returns the internal encoding of a Redis object.", "since": "2.2.3", "group": "generic", "complexity": "O(1)", @@ -9745,7 +9745,7 @@ ] }, "OBJECT FREQ": { - "summary": "Get the logarithmic access frequency counter of a Redis object", + "summary": "Returns the logarithmic access frequency counter of a Redis object.", "since": "4.0.0", "group": "generic", "complexity": "O(1)", @@ -9790,7 +9790,7 @@ ] }, "OBJECT HELP": { - "summary": "Show helpful text about the different subcommands", + "summary": "Returns helpful text about the different subcommands.", "since": "6.2.0", "group": "generic", "complexity": "O(1)", @@ -9805,7 +9805,7 @@ ] }, "OBJECT IDLETIME": { - "summary": "Get the time since a Redis object was last accessed", + "summary": "Returns the time since the last access to a Redis object.", "since": "2.2.3", "group": "generic", "complexity": "O(1)", @@ -9850,7 +9850,7 @@ ] }, "OBJECT REFCOUNT": { - "summary": "Get the number of references to the value of the key", + "summary": "Returns the reference count of a value of a key.", "since": "2.2.3", "group": "generic", "complexity": "O(1)", @@ -9895,7 +9895,7 @@ ] }, "PERSIST": { - "summary": "Remove the expiration from a key", + "summary": "Removes the expiration time of a key.", "since": "2.2.0", "group": "generic", "complexity": "O(1)", @@ -9939,7 +9939,7 @@ ] }, "PEXPIRE": { - "summary": "Set a key's time to live in milliseconds", + "summary": "Sets the expiration time of a key in milliseconds.", "since": "2.6.0", "group": "generic", "complexity": "O(1)", @@ -10026,7 +10026,7 @@ ] }, "PEXPIREAT": { - "summary": "Set the expiration for a key as a UNIX timestamp specified in milliseconds", + "summary": "Sets the expiration time of a key to a Unix milliseconds timestamp.", "since": "2.6.0", "group": "generic", "complexity": "O(1)", @@ -10113,7 +10113,7 @@ ] }, "PEXPIRETIME": { - "summary": "Get the expiration Unix timestamp for a key in milliseconds", + "summary": "Returns the expiration time of a key as a Unix milliseconds timestamp.", "since": "7.0.0", "group": "generic", "complexity": "O(1)", @@ -10157,7 +10157,7 @@ ] }, "PFADD": { - "summary": "Adds the specified elements to the specified HyperLogLog.", + "summary": "Adds elements to a HyperLogLog key. Creates the key if it doesn't exist.", "since": "2.8.9", "group": "hyperloglog", "complexity": "O(1) to add every element.", @@ -10209,7 +10209,7 @@ ] }, "PFCOUNT": { - "summary": "Return the approximated cardinality of the set(s) observed by the HyperLogLog at key(s).", + "summary": "Returns the approximated cardinality of the set(s) observed by the HyperLogLog key(s).", "since": "2.8.9", "group": "hyperloglog", "complexity": "O(1) with a very small average constant time when called with a single key. O(N) with N being the number of keys, and much bigger constant times, when called with multiple keys.", @@ -10254,7 +10254,7 @@ ] }, "PFDEBUG": { - "summary": "Internal commands for debugging HyperLogLog values", + "summary": "Internal commands for debugging HyperLogLog values.", "since": "2.8.9", "group": "hyperloglog", "complexity": "N/A", @@ -10309,7 +10309,7 @@ ] }, "PFMERGE": { - "summary": "Merge N different HyperLogLogs into a single one.", + "summary": "Merges one or more HyperLogLog values into a single key.", "since": "2.8.9", "group": "hyperloglog", "complexity": "O(N) to merge N HyperLogLogs, but with high constant times.", @@ -10380,7 +10380,7 @@ ] }, "PFSELFTEST": { - "summary": "An internal command for testing HyperLogLog values", + "summary": "An internal command for testing HyperLogLog values.", "since": "2.8.9", "group": "hyperloglog", "complexity": "N/A", @@ -10399,7 +10399,7 @@ ] }, "PING": { - "summary": "Ping the server", + "summary": "Returns the server's liveliness response.", "since": "1.0.0", "group": "connection", "complexity": "O(1)", @@ -10425,7 +10425,7 @@ ] }, "PSETEX": { - "summary": "Set the value and expiration in milliseconds of a key", + "summary": "Sets both string value and expiration time in milliseconds of a key. The key is created if it doesn't exist.", "since": "2.6.0", "group": "string", "complexity": "O(1)", @@ -10484,7 +10484,7 @@ ] }, "PSUBSCRIBE": { - "summary": "Listen for messages published to channels matching the given patterns", + "summary": "Listens for messages published to channels that match one or more patterns.", "since": "2.0.0", "group": "pubsub", "complexity": "O(N) where N is the number of patterns the client is already subscribed to.", @@ -10509,7 +10509,7 @@ ] }, "PSYNC": { - "summary": "Internal command used for replication", + "summary": "An internal command used in replication.", "since": "2.8.0", "group": "server", "acl_categories": [ @@ -10538,7 +10538,7 @@ ] }, "PTTL": { - "summary": "Get the time to live for a key in milliseconds", + "summary": "Returns the expiration time in milliseconds of a key.", "since": "2.6.0", "group": "generic", "complexity": "O(1)", @@ -10591,7 +10591,7 @@ ] }, "PUBLISH": { - "summary": "Post a message to a channel", + "summary": "Posts a message to a channel.", "since": "2.0.0", "group": "pubsub", "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).", @@ -10620,7 +10620,7 @@ ] }, "PUBSUB": { - "summary": "A container for Pub/Sub commands", + "summary": "A container for Pub/Sub commands.", "since": "2.8.0", "group": "pubsub", "complexity": "Depends on subcommand.", @@ -10630,7 +10630,7 @@ "arity": -2 }, "PUBSUB CHANNELS": { - "summary": "List active channels", + "summary": "Returns the active channels.", "since": "2.8.0", "group": "pubsub", "complexity": "O(N) where N is the number of active channels, and assuming constant time pattern matching (relatively short channels and patterns)", @@ -10654,7 +10654,7 @@ ] }, "PUBSUB HELP": { - "summary": "Show helpful text about the different subcommands", + "summary": "Returns helpful text about the different subcommands.", "since": "6.2.0", "group": "pubsub", "complexity": "O(1)", @@ -10668,7 +10668,7 @@ ] }, "PUBSUB NUMPAT": { - "summary": "Get the count of unique patterns pattern subscriptions", + "summary": "Returns a count of unique pattern subscriptions.", "since": "2.8.0", "group": "pubsub", "complexity": "O(1)", @@ -10684,7 +10684,7 @@ ] }, "PUBSUB NUMSUB": { - "summary": "Get the count of subscribers for channels", + "summary": "Returns a count of subscribers to channels.", "since": "2.8.0", "group": "pubsub", "complexity": "O(N) for the NUMSUB subcommand, where N is the number of requested channels", @@ -10709,7 +10709,7 @@ ] }, "PUBSUB SHARDCHANNELS": { - "summary": "List active shard channels", + "summary": "Returns the active shard channels.", "since": "7.0.0", "group": "pubsub", "complexity": "O(N) where N is the number of active shard channels, and assuming constant time pattern matching (relatively short shard channels).", @@ -10733,7 +10733,7 @@ ] }, "PUBSUB SHARDNUMSUB": { - "summary": "Get the count of subscribers for shard channels", + "summary": "Returns the count of subscribers of shard channels.", "since": "7.0.0", "group": "pubsub", "complexity": "O(N) for the SHARDNUMSUB subcommand, where N is the number of requested shard channels", @@ -10758,7 +10758,7 @@ ] }, "PUNSUBSCRIBE": { - "summary": "Stop listening for messages posted to channels matching the given patterns", + "summary": "Stops listening to messages published to channels that match one or more patterns.", "since": "2.0.0", "group": "pubsub", "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).", @@ -10784,7 +10784,7 @@ ] }, "QUIT": { - "summary": "Close the connection", + "summary": "Closes the connection.", "since": "1.0.0", "group": "connection", "complexity": "O(1)", @@ -10808,7 +10808,7 @@ ] }, "RANDOMKEY": { - "summary": "Return a random key from the keyspace", + "summary": "Returns a random key name from the database.", "since": "1.0.0", "group": "generic", "complexity": "O(1)", @@ -10827,7 +10827,7 @@ ] }, "READONLY": { - "summary": "Enables read queries for a connection to a cluster replica node", + "summary": "Enables read-only queries for a connection to a Redis Cluster replica node.", "since": "3.0.0", "group": "cluster", "complexity": "O(1)", @@ -10843,7 +10843,7 @@ ] }, "READWRITE": { - "summary": "Disables read queries for a connection to a cluster replica node", + "summary": "Enables read-write queries for a connection to a Reids Cluster replica node.", "since": "3.0.0", "group": "cluster", "complexity": "O(1)", @@ -10859,7 +10859,7 @@ ] }, "RENAME": { - "summary": "Rename a key", + "summary": "Renames a key and overwrites the destination.", "since": "1.0.0", "group": "generic", "complexity": "O(1)", @@ -10927,7 +10927,7 @@ ] }, "RENAMENX": { - "summary": "Rename a key, only if the new key does not exist", + "summary": "Renames a key only when the target key name doesn't exist.", "since": "1.0.0", "group": "generic", "complexity": "O(1)", @@ -11002,7 +11002,7 @@ ] }, "REPLCONF": { - "summary": "An internal command for configuring the replication stream", + "summary": "An internal command for configuring the replication stream.", "since": "3.0.0", "group": "server", "complexity": "O(1)", @@ -11024,7 +11024,7 @@ ] }, "REPLICAOF": { - "summary": "Make the server a replica of another instance, or promote it as master.", + "summary": "Configures a server as replica of another, or promotes it to a master.", "since": "5.0.0", "group": "server", "complexity": "O(1)", @@ -11054,7 +11054,7 @@ ] }, "RESET": { - "summary": "Reset the connection", + "summary": "Resets the connection.", "since": "6.2.0", "group": "connection", "complexity": "O(1)", @@ -11073,7 +11073,7 @@ ] }, "RESTORE": { - "summary": "Create a key using the provided serialized value, previously obtained using DUMP.", + "summary": "Creates a key from the serialized representation of a value.", "since": "2.6.0", "group": "generic", "complexity": "O(1) to create the new key and additional O(N*M) to reconstruct the serialized value, where N is the number of Redis objects composing the value and M their average size. For small string values the time complexity is thus O(1)+O(1*M) where M is small, so simply O(1). However for sorted set values the complexity is O(N*M*log(N)) because inserting values into sorted sets is O(log(N)).", @@ -11174,7 +11174,7 @@ ] }, "RESTORE-ASKING": { - "summary": "An internal command for migrating keys in a cluster", + "summary": "An internal command for migrating keys in a cluster.", "since": "3.0.0", "group": "server", "complexity": "O(1) to create the new key and additional O(N*M) to reconstruct the serialized value, where N is the number of Redis objects composing the value and M their average size. For small string values the time complexity is thus O(1)+O(1*M) where M is small, so simply O(1). However for sorted set values the complexity is O(N*M*log(N)) because inserting values into sorted sets is O(log(N)).", @@ -11279,7 +11279,7 @@ ] }, "ROLE": { - "summary": "Return the role of the instance in the context of replication", + "summary": "Returns the replication role.", "since": "2.8.12", "group": "server", "complexity": "O(1)", @@ -11297,7 +11297,7 @@ ] }, "RPOP": { - "summary": "Remove and get the last elements in a list", + "summary": "Returns and removes the last elements of a list. Deletes the list if the lst element was popped.", "since": "1.0.0", "group": "list", "complexity": "O(N) where N is the number of elements returned", @@ -11355,7 +11355,7 @@ ] }, "RPOPLPUSH": { - "summary": "Remove the last element in a list, prepend it to another list and return it", + "summary": "Returns the last element of a list after removing and pushing it to another list. Deletes the list if the lst element was popped.", "since": "1.2.0", "group": "list", "complexity": "O(1)", @@ -11429,7 +11429,7 @@ ] }, "RPUSH": { - "summary": "Append one or multiple elements to a list", + "summary": "Appends one or more elements to a list. Creates the key if it doesn't exist.", "since": "1.0.0", "group": "list", "complexity": "O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments.", @@ -11486,7 +11486,7 @@ ] }, "RPUSHX": { - "summary": "Append an element to a list, only if the list exists", + "summary": "Appends an element to a list only when the list exists.", "since": "2.2.0", "group": "list", "complexity": "O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments.", @@ -11543,7 +11543,7 @@ ] }, "SADD": { - "summary": "Add one or more members to a set", + "summary": "Adds one or more members to a set. Creates the key if it doesn't exist.", "since": "1.0.0", "group": "set", "complexity": "O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments.", @@ -11600,7 +11600,7 @@ ] }, "SAVE": { - "summary": "Synchronously save the dataset to disk", + "summary": "Synchronously saves the database(s) to disk.", "since": "1.0.0", "group": "server", "complexity": "O(N) where N is the total number of keys in all databases", @@ -11618,7 +11618,7 @@ ] }, "SCAN": { - "summary": "Incrementally iterate the keys space", + "summary": "Iterates over the key names in the database.", "since": "2.8.0", "group": "generic", "complexity": "O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection.", @@ -11672,7 +11672,7 @@ ] }, "SCARD": { - "summary": "Get the number of members in a set", + "summary": "Returns the number of members in a set.", "since": "1.0.0", "group": "set", "complexity": "O(1)", @@ -11715,7 +11715,7 @@ ] }, "SCRIPT": { - "summary": "A container for Lua scripts management commands", + "summary": "A container for Lua scripts management commands.", "since": "2.6.0", "group": "scripting", "complexity": "Depends on subcommand.", @@ -11725,7 +11725,7 @@ "arity": -2 }, "SCRIPT DEBUG": { - "summary": "Set the debug mode for executed scripts.", + "summary": "Sets the debug mode of server-side Lua scripts.", "since": "3.2.0", "group": "scripting", "complexity": "O(1)", @@ -11765,7 +11765,7 @@ ] }, "SCRIPT EXISTS": { - "summary": "Check existence of scripts in the script cache.", + "summary": "Determines whether server-side Lua scripts exist in the script cache.", "since": "2.6.0", "group": "scripting", "complexity": "O(N) with N being the number of scripts to check (so checking a single script is an O(1) operation).", @@ -11791,7 +11791,7 @@ ] }, "SCRIPT FLUSH": { - "summary": "Remove all the scripts from the script cache.", + "summary": "Removes all server-side Lua scripts from the script cache.", "since": "2.6.0", "group": "scripting", "complexity": "O(N) with N being the number of scripts in cache", @@ -11837,7 +11837,7 @@ ] }, "SCRIPT HELP": { - "summary": "Show helpful text about the different subcommands", + "summary": "Returns helpful text about the different subcommands.", "since": "5.0.0", "group": "scripting", "complexity": "O(1)", @@ -11852,7 +11852,7 @@ ] }, "SCRIPT KILL": { - "summary": "Kill the script currently in execution.", + "summary": "Terminates a server-side Lua script during execution.", "since": "2.6.0", "group": "scripting", "complexity": "O(1)", @@ -11871,7 +11871,7 @@ ] }, "SCRIPT LOAD": { - "summary": "Load the specified Lua script into the script cache.", + "summary": "Loads a server-side Lua script to the script cache.", "since": "2.6.0", "group": "scripting", "complexity": "O(N) with N being the length in bytes of the script body.", @@ -11897,7 +11897,7 @@ ] }, "SDIFF": { - "summary": "Subtract multiple sets", + "summary": "Returns the difference of multiple sets.", "since": "1.0.0", "group": "set", "complexity": "O(N) where N is the total number of elements in all given sets.", @@ -11944,7 +11944,7 @@ ] }, "SDIFFSTORE": { - "summary": "Subtract multiple sets and store the resulting set in a key", + "summary": "Stores the difference of multiple sets in a key.", "since": "1.0.0", "group": "set", "complexity": "O(N) where N is the total number of elements in all given sets.", @@ -12013,7 +12013,7 @@ ] }, "SELECT": { - "summary": "Change the selected database for the current connection", + "summary": "Changes the selected database.", "since": "1.0.0", "group": "connection", "complexity": "O(1)", @@ -12036,7 +12036,7 @@ ] }, "SET": { - "summary": "Set the string value of a key", + "summary": "Sets the string value of a key, ignoring its type. The key is created if it doesn't exist.", "since": "1.0.0", "group": "string", "complexity": "O(1)", @@ -12176,7 +12176,7 @@ ] }, "SETBIT": { - "summary": "Sets or clears the bit at offset in the string value stored at key", + "summary": "Sets or clears the bit at offset of the string value. Creates the key if it doesn't exist.", "since": "2.2.0", "group": "bitmap", "complexity": "O(1)", @@ -12231,7 +12231,7 @@ ] }, "SETEX": { - "summary": "Set the value and expiration of a key", + "summary": "Sets the string value and expiration time of a key. Creates the key if it doesn't exist.", "since": "2.0.0", "group": "string", "complexity": "O(1)", @@ -12290,7 +12290,7 @@ ] }, "SETNX": { - "summary": "Set the value of a key, only if the key does not exist", + "summary": "Set the string value of a key only when the key doesn't exist.", "since": "1.0.0", "group": "string", "complexity": "O(1)", @@ -12345,7 +12345,7 @@ ] }, "SETRANGE": { - "summary": "Overwrite part of a string at key starting at the specified offset", + "summary": "Overwrites a part of a string value with another by an offset. Creates the key if it doesn't exist.", "since": "2.2.0", "group": "string", "complexity": "O(1), not counting the time taken to copy the new string in place. Usually, this string is very small so the amortized complexity is O(1). Otherwise, complexity is O(M) with M being the length of the value argument.", @@ -12399,7 +12399,7 @@ ] }, "SHUTDOWN": { - "summary": "Synchronously save the dataset to disk and then shut down the server", + "summary": "Synchronously saves the database(s) to disk and shuts down the Redis server.", "since": "1.0.0", "group": "server", "complexity": "O(N) when saving, where N is the total number of keys in all databases when saving data, otherwise O(1)", @@ -12470,7 +12470,7 @@ ] }, "SINTER": { - "summary": "Intersect multiple sets", + "summary": "Returns the intersect of multiple sets.", "since": "1.0.0", "group": "set", "complexity": "O(N*M) worst case where N is the cardinality of the smallest set and M is the number of sets.", @@ -12517,7 +12517,7 @@ ] }, "SINTERCARD": { - "summary": "Intersect multiple sets and return the cardinality of the result", + "summary": "Returns the number of members of the intersect of multiple sets.", "since": "7.0.0", "group": "set", "complexity": "O(N*M) worst case where N is the cardinality of the smallest set and M is the number of sets.", @@ -12574,7 +12574,7 @@ ] }, "SINTERSTORE": { - "summary": "Intersect multiple sets and store the resulting set in a key", + "summary": "Stores the intersect of multiple sets in a key.", "since": "1.0.0", "group": "set", "complexity": "O(N*M) worst case where N is the cardinality of the smallest set and M is the number of sets.", @@ -12643,7 +12643,7 @@ ] }, "SISMEMBER": { - "summary": "Determine if a given value is a member of a set", + "summary": "Determines whether a member belongs to a set.", "since": "1.0.0", "group": "set", "complexity": "O(1)", @@ -12691,7 +12691,7 @@ ] }, "SLAVEOF": { - "summary": "Make the server a replica of another instance, or promote it as master.", + "summary": "Sets a Redis server as a replica of another, or promotes it to being a master.", "since": "1.0.0", "group": "server", "complexity": "O(1)", @@ -12726,7 +12726,7 @@ ] }, "SLOWLOG": { - "summary": "A container for slow log commands", + "summary": "A container for slow log commands.", "since": "2.2.12", "group": "server", "complexity": "Depends on subcommand.", @@ -12736,7 +12736,7 @@ "arity": -2 }, "SLOWLOG GET": { - "summary": "Get the slow log's entries", + "summary": "Returns the slow log's entries.", "since": "2.2.12", "group": "server", "complexity": "O(N) where N is the number of entries returned", @@ -12785,7 +12785,7 @@ ] }, "SLOWLOG LEN": { - "summary": "Get the slow log's length", + "summary": "Returns the number of entries in the slow log.", "since": "2.2.12", "group": "server", "complexity": "O(1)", @@ -12807,7 +12807,7 @@ ] }, "SLOWLOG RESET": { - "summary": "Clear all entries from the slow log", + "summary": "Clears all entries from the slow log.", "since": "2.2.12", "group": "server", "complexity": "O(N) where N is the number of entries in the slowlog", @@ -12828,7 +12828,7 @@ ] }, "SMEMBERS": { - "summary": "Get all the members in a set", + "summary": "Returns all members of a set.", "since": "1.0.0", "group": "set", "complexity": "O(N) where N is the set cardinality.", @@ -12874,7 +12874,7 @@ ] }, "SMISMEMBER": { - "summary": "Returns the membership associated with the given elements for a set", + "summary": "Determines whether multiple members belong to a set.", "since": "6.2.0", "group": "set", "complexity": "O(N) where N is the number of elements being checked for membership", @@ -12924,7 +12924,7 @@ ] }, "SMOVE": { - "summary": "Move a member from one set to another", + "summary": "Moves a member from one set to another.", "since": "1.0.0", "group": "set", "complexity": "O(1)", @@ -12998,7 +12998,7 @@ ] }, "SORT": { - "summary": "Sort the elements in a list, set or sorted set", + "summary": "Sorts the elements in a list, a set, or a sorted set, optionally storing the result.", "since": "1.0.0", "group": "generic", "complexity": "O(N+M*log(M)) where N is the number of elements in the list or set to sort, and M the number of returned elements. When the elements are not sorted, complexity is O(N).", @@ -13142,7 +13142,7 @@ ] }, "SORT_RO": { - "summary": "Sort the elements in a list, set or sorted set. Read-only variant of SORT.", + "summary": "Returns the sorted elements of a list, a set, or a sorted set.", "since": "7.0.0", "group": "generic", "complexity": "O(N+M*log(M)) where N is the number of elements in the list or set to sort, and M the number of returned elements. When the elements are not sorted, complexity is O(N).", @@ -13264,7 +13264,7 @@ ] }, "SPOP": { - "summary": "Remove and return one or multiple random members from a set", + "summary": "Returns one or more random members from a set after removing them. Deletes the set if the last member was popped.", "since": "1.0.0", "group": "set", "complexity": "Without the count argument O(1), otherwise O(N) where N is the value of the passed count.", @@ -13432,7 +13432,7 @@ ] }, "SREM": { - "summary": "Remove one or more members from a set", + "summary": "Removes one or more members from a set. Deletes the set if the last member was removed.", "since": "1.0.0", "group": "set", "complexity": "O(N) where N is the number of members to be removed.", @@ -13488,7 +13488,7 @@ ] }, "SSCAN": { - "summary": "Incrementally iterate Set elements", + "summary": "Iterates over members of a set.", "since": "2.8.0", "group": "set", "complexity": "O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection.", @@ -13553,7 +13553,7 @@ ] }, "SSUBSCRIBE": { - "summary": "Listen for messages published to the given shard channels", + "summary": "Listens for messages published to shard channels.", "since": "7.0.0", "group": "pubsub", "complexity": "O(N) where N is the number of shard channels to subscribe to.", @@ -13597,7 +13597,7 @@ ] }, "STRLEN": { - "summary": "Get the length of the value stored in a key", + "summary": "Returns the length of a string value.", "since": "2.2.0", "group": "string", "complexity": "O(1)", @@ -13640,7 +13640,7 @@ ] }, "SUBSCRIBE": { - "summary": "Listen for messages published to the given channels", + "summary": "Listens for messages published to channels.", "since": "2.0.0", "group": "pubsub", "complexity": "O(N) where N is the number of channels to subscribe to.", @@ -13665,7 +13665,7 @@ ] }, "SUBSTR": { - "summary": "Get a substring of the string stored at a key", + "summary": "Returns a substring from a string value.", "since": "1.0.0", "group": "string", "complexity": "O(N) where N is the length of the returned string. The complexity is ultimately determined by the returned length, but because creating a substring from an existing string is very cheap, it can be considered O(1) for small strings.", @@ -13723,7 +13723,7 @@ ] }, "SUNION": { - "summary": "Add multiple sets", + "summary": "Returns the union of multiple sets.", "since": "1.0.0", "group": "set", "complexity": "O(N) where N is the total number of elements in all given sets.", @@ -13770,7 +13770,7 @@ ] }, "SUNIONSTORE": { - "summary": "Add multiple sets and store the resulting set in a key", + "summary": "Stores the union of multiple sets in a key.", "since": "1.0.0", "group": "set", "complexity": "O(N) where N is the total number of elements in all given sets.", @@ -13839,7 +13839,7 @@ ] }, "SUNSUBSCRIBE": { - "summary": "Stop listening for messages posted to the given shard channels", + "summary": "Stops listening to messages posted to shard channels.", "since": "7.0.0", "group": "pubsub", "complexity": "O(N) where N is the number of clients already subscribed to a shard channel.", @@ -13884,7 +13884,7 @@ ] }, "SWAPDB": { - "summary": "Swaps two Redis databases", + "summary": "Swaps two Redis databases.", "since": "4.0.0", "group": "server", "complexity": "O(N) where N is the count of clients watching or blocking on keys from both databases.", @@ -13913,7 +13913,7 @@ ] }, "SYNC": { - "summary": "Internal command used for replication", + "summary": "An internal command used in replication.", "since": "1.0.0", "group": "server", "acl_categories": [ @@ -13930,7 +13930,7 @@ ] }, "TIME": { - "summary": "Return the current server time", + "summary": "Returns the server time.", "since": "2.6.0", "group": "server", "complexity": "O(1)", @@ -13948,7 +13948,7 @@ ] }, "TOUCH": { - "summary": "Alters the last access time of a key(s). Returns the number of existing keys specified.", + "summary": "Returns the number of existing keys out of those specified after updating the time they were last accessed.", "since": "3.2.1", "group": "generic", "complexity": "O(N) where N is the number of keys that will be touched.", @@ -13996,7 +13996,7 @@ ] }, "TTL": { - "summary": "Get the time to live for a key in seconds", + "summary": "Returns the expiration time in seconds of a key.", "since": "1.0.0", "group": "generic", "complexity": "O(1)", @@ -14049,7 +14049,7 @@ ] }, "TYPE": { - "summary": "Determine the type stored at key", + "summary": "Determines the type of value stored at a key.", "since": "1.0.0", "group": "generic", "complexity": "O(1)", @@ -14092,7 +14092,7 @@ ] }, "UNLINK": { - "summary": "Delete a key asynchronously in another thread. Otherwise it is just as DEL, but non blocking.", + "summary": "Asynchronously deletes one or more keys.", "since": "4.0.0", "group": "generic", "complexity": "O(1) for each key removed regardless of its size. Then the command does O(N) work in a different thread in order to reclaim memory, where N is the number of allocations the deleted objects where composed of.", @@ -14141,7 +14141,7 @@ ] }, "UNSUBSCRIBE": { - "summary": "Stop listening for messages posted to the given channels", + "summary": "Stops listening to messages posted to channels.", "since": "2.0.0", "group": "pubsub", "complexity": "O(N) where N is the number of clients already subscribed to a channel.", @@ -14167,7 +14167,7 @@ ] }, "UNWATCH": { - "summary": "Forget about all watched keys", + "summary": "Forgets about watched keys of a transaction.", "since": "2.2.0", "group": "transactions", "complexity": "O(1)", @@ -14185,7 +14185,7 @@ ] }, "WAIT": { - "summary": "Wait for the synchronous replication of all the write commands sent in the context of the current connection", + "summary": "Blocks until the asynchronous replication of all preceding write commands sent by the connection is completed.", "since": "3.0.0", "group": "generic", "complexity": "O(1)", @@ -14212,7 +14212,7 @@ ] }, "WAITAOF": { - "summary": "Wait for all write commands sent in the context of the current connection to be synced to AOF of local host and/or replicas", + "summary": "Blocks until all of the preceding write commands sent by the connection are written to the append-only file of the master and/or replicas.", "since": "7.2.0", "group": "generic", "complexity": "O(1)", @@ -14247,7 +14247,7 @@ ] }, "WATCH": { - "summary": "Watch the given keys to determine execution of the MULTI/EXEC block", + "summary": "Monitors changes to keys to determine the execution of a transaction.", "since": "2.2.0", "group": "transactions", "complexity": "O(1) for every key.", @@ -14293,7 +14293,7 @@ ] }, "XACK": { - "summary": "Marks a pending message as correctly processed, effectively removing it from the pending entries list of the consumer group. Return value of the command is the number of messages successfully acknowledged, that is, the IDs we were actually able to resolve in the PEL.", + "summary": "Returns the number of messages that were successfully acknowledged by the consumer group member of a stream.", "since": "5.0.0", "group": "stream", "complexity": "O(1) for each message ID processed.", @@ -14348,7 +14348,7 @@ ] }, "XADD": { - "summary": "Appends a new entry to a stream", + "summary": "Appends a new message to a stream. Creates the key if it doesn't exist.", "since": "5.0.0", "group": "stream", "complexity": "O(1) when adding a new entry, O(N) when trimming where N being the number of entries evicted.", @@ -14507,7 +14507,7 @@ ] }, "XAUTOCLAIM": { - "summary": "Changes (or acquires) ownership of messages in a consumer group, as if the messages were delivered to the specified consumer.", + "summary": "Changes, or acquires, ownership of messages in a consumer group, as if the messages were delivered to as consumer group member.", "since": "6.2.0", "group": "stream", "complexity": "O(1) if COUNT is small.", @@ -14594,7 +14594,7 @@ ] }, "XCLAIM": { - "summary": "Changes (or acquires) ownership of a message in a consumer group, as if the message was delivered to the specified consumer.", + "summary": "Changes, or acquires, ownership of a message in a consumer group, as if the message was delivered a consumer group member.", "since": "5.0.0", "group": "stream", "complexity": "O(log N) with N being the number of messages in the PEL of the consumer group.", @@ -14704,7 +14704,7 @@ ] }, "XDEL": { - "summary": "Removes the specified entries from the stream. Returns the number of items actually deleted, that may be different from the number of IDs passed in case certain IDs do not exist.", + "summary": "Returns the number of messages after removing them from a stream.", "since": "5.0.0", "group": "stream", "complexity": "O(1) for each single item to delete in the stream, regardless of the stream size.", @@ -14754,7 +14754,7 @@ ] }, "XGROUP": { - "summary": "A container for consumer groups commands", + "summary": "A container for consumer groups commands.", "since": "5.0.0", "group": "stream", "complexity": "Depends on subcommand.", @@ -14764,7 +14764,7 @@ "arity": -2 }, "XGROUP CREATE": { - "summary": "Create a consumer group.", + "summary": "Creates a consumer group.", "since": "5.0.0", "group": "stream", "complexity": "O(1)", @@ -14850,7 +14850,7 @@ ] }, "XGROUP CREATECONSUMER": { - "summary": "Create a consumer in a consumer group.", + "summary": "Creates a consumer in a consumer group.", "since": "6.2.0", "group": "stream", "complexity": "O(1)", @@ -14904,7 +14904,7 @@ ] }, "XGROUP DELCONSUMER": { - "summary": "Delete a consumer from a consumer group.", + "summary": "Deletes a consumer from a consumer group.", "since": "5.0.0", "group": "stream", "complexity": "O(1)", @@ -14957,7 +14957,7 @@ ] }, "XGROUP DESTROY": { - "summary": "Destroy a consumer group.", + "summary": "Destroys a consumer group.", "since": "5.0.0", "group": "stream", "complexity": "O(N) where N is the number of entries in the group's pending entries list (PEL).", @@ -15005,7 +15005,7 @@ ] }, "XGROUP HELP": { - "summary": "Show helpful text about the different subcommands", + "summary": "Returns helpful text about the different subcommands.", "since": "5.0.0", "group": "stream", "complexity": "O(1)", @@ -15020,7 +15020,7 @@ ] }, "XGROUP SETID": { - "summary": "Set a consumer group to an arbitrary last delivered ID value.", + "summary": "Sets the last-delivered ID of a consumer group.", "since": "5.0.0", "group": "stream", "complexity": "O(1)", @@ -15098,7 +15098,7 @@ ] }, "XINFO": { - "summary": "A container for stream introspection commands", + "summary": "A container for stream introspection commands.", "since": "5.0.0", "group": "stream", "complexity": "Depends on subcommand.", @@ -15108,7 +15108,7 @@ "arity": -2 }, "XINFO CONSUMERS": { - "summary": "List the consumers in a consumer group", + "summary": "Returns a list of the consumers in a consumer group.", "since": "5.0.0", "group": "stream", "complexity": "O(1)", @@ -15165,7 +15165,7 @@ ] }, "XINFO GROUPS": { - "summary": "List the consumer groups of a stream", + "summary": "Returns a list of the consumer groups of a stream.", "since": "5.0.0", "group": "stream", "complexity": "O(1)", @@ -15214,7 +15214,7 @@ ] }, "XINFO HELP": { - "summary": "Show helpful text about the different subcommands", + "summary": "Returns helpful text about the different subcommands.", "since": "5.0.0", "group": "stream", "complexity": "O(1)", @@ -15229,7 +15229,7 @@ ] }, "XINFO STREAM": { - "summary": "Get information about a stream", + "summary": "Returns information about a stream.", "since": "5.0.0", "group": "stream", "complexity": "O(1)", @@ -15306,7 +15306,7 @@ ] }, "XLEN": { - "summary": "Return the number of entries in a stream", + "summary": "Return the number of messages in a stream.", "since": "5.0.0", "group": "stream", "complexity": "O(1)", @@ -15349,7 +15349,7 @@ ] }, "XPENDING": { - "summary": "Return information and entries from a stream consumer group pending entries list, that are messages fetched but never acknowledged.", + "summary": "Returns the information and entries from a stream consumer group's pending entries list.", "since": "5.0.0", "group": "stream", "complexity": "O(N) with N being the number of elements returned, so asking for a small fixed number of entries per call is O(1). O(M), where M is the total number of entries scanned when used with the IDLE filter. When the command returns just the summary and the list of consumers is small, it runs in O(1) time; otherwise, an additional O(N) time for iterating every consumer.", @@ -15442,7 +15442,7 @@ ] }, "XRANGE": { - "summary": "Return a range of elements in a stream, with IDs matching the specified IDs interval", + "summary": "Returns the messages from a stream within a range of IDs.", "since": "5.0.0", "group": "stream", "complexity": "O(N) with N being the number of elements being returned. If N is constant (e.g. always asking for the first 10 elements with COUNT), you can consider it O(1).", @@ -15508,10 +15508,9 @@ ] }, "XREAD": { - "summary": "Return never seen elements in multiple streams, with IDs greater than the ones reported by the caller for each stream. Can block.", + "summary": "Returns messages from multiple streams with IDs greater than the ones requested. Blocks until a message is available otherwise.", "since": "5.0.0", "group": "stream", - "complexity": "For each stream mentioned: O(N) with N being the number of elements being returned, it means that XREAD-ing with a fixed COUNT is O(1). Note that when the BLOCK option is used, XADD will pay O(M) time in order to serve the M clients blocked on the stream getting new data.", "acl_categories": [ "@read", "@stream", @@ -15583,7 +15582,7 @@ ] }, "XREADGROUP": { - "summary": "Return new entries from a stream using a consumer group, or access the history of the pending entries for a given consumer. Can block.", + "summary": "Returns new or historical messages from a stream for a consumer in agroup. Blocks until a message is available otherwise.", "since": "5.0.0", "group": "stream", "complexity": "For each stream mentioned: O(M) with M being the number of elements returned. If M is constant (e.g. always asking for the first 10 elements with COUNT), you can consider it O(1). On the other side when XREADGROUP blocks, XADD will pay the O(N) time in order to serve the N clients blocked on the stream getting new data.", @@ -15682,7 +15681,7 @@ ] }, "XREVRANGE": { - "summary": "Return a range of elements in a stream, with IDs matching the specified IDs interval, in reverse order (from greater to smaller IDs) compared to XRANGE", + "summary": "Returns the messages from a stream within a range of IDs in reverse order.", "since": "5.0.0", "group": "stream", "complexity": "O(N) with N being the number of elements returned. If N is constant (e.g. always asking for the first 10 elements with COUNT), you can consider it O(1).", @@ -15748,7 +15747,7 @@ ] }, "XSETID": { - "summary": "An internal command for replicating stream values", + "summary": "An internal command for replicating stream values.", "since": "5.0.0", "group": "stream", "complexity": "O(1)", @@ -15820,7 +15819,7 @@ ] }, "XTRIM": { - "summary": "Trims the stream to (approximately if '~' is passed) a certain size", + "summary": "Deletes messages from the beginning of a stream.", "since": "5.0.0", "group": "stream", "complexity": "O(N), with N being the number of evicted entries. Constant times are very small however, since entries are organized in macro nodes containing multiple entries that can be released with a single deallocation.", @@ -15929,7 +15928,7 @@ ] }, "ZADD": { - "summary": "Add one or more members to a sorted set, or update its score if it already exists", + "summary": "Adds one or more members to a sorted set, or updates their scores. Creates the key if it doesn't exist.", "since": "1.2.0", "group": "sorted-set", "complexity": "O(log(N)) for each item added, where N is the number of elements in the sorted set.", @@ -16061,7 +16060,7 @@ ] }, "ZCARD": { - "summary": "Get the number of members in a sorted set", + "summary": "Returns the number of members in a sorted set.", "since": "1.2.0", "group": "sorted-set", "complexity": "O(1)", @@ -16104,7 +16103,7 @@ ] }, "ZCOUNT": { - "summary": "Count the members in a sorted set with scores within the given values", + "summary": "Returns the count of members in a sorted set that have scores within a range.", "since": "2.0.0", "group": "sorted-set", "complexity": "O(log(N)) with N being the number of elements in the sorted set.", @@ -16158,7 +16157,7 @@ ] }, "ZDIFF": { - "summary": "Subtract multiple sorted sets", + "summary": "Returns the difference between multiple sorted sets.", "since": "6.2.0", "group": "sorted-set", "complexity": "O(L + (N-K)log(N)) worst case where L is the total number of elements in all the sets, N is the size of the first set, and K is the size of the result set.", @@ -16215,7 +16214,7 @@ ] }, "ZDIFFSTORE": { - "summary": "Subtract multiple sorted sets and store the resulting sorted set in a new key", + "summary": "Stores the difference of multiple sorted sets in a key.", "since": "6.2.0", "group": "sorted-set", "complexity": "O(L + (N-K)log(N)) worst case where L is the total number of elements in all the sets, N is the size of the first set, and K is the size of the result set.", @@ -16290,7 +16289,7 @@ ] }, "ZINCRBY": { - "summary": "Increment the score of a member in a sorted set", + "summary": "Increments the score of a member in a sorted set.", "since": "1.2.0", "group": "sorted-set", "complexity": "O(log(N)) where N is the number of elements in the sorted set.", @@ -16346,7 +16345,7 @@ ] }, "ZINTER": { - "summary": "Intersect multiple sorted sets", + "summary": "Returns the intersect of multiple sorted sets.", "since": "6.2.0", "group": "sorted-set", "complexity": "O(N*K)+O(M*log(M)) worst case with N being the smallest input sorted set, K being the number of input sorted sets and M being the number of elements in the resulting sorted set.", @@ -16437,7 +16436,7 @@ ] }, "ZINTERCARD": { - "summary": "Intersect multiple sorted sets and return the cardinality of the result", + "summary": "Returns the number of members of the intersect of multiple sorted sets.", "since": "7.0.0", "group": "sorted-set", "complexity": "O(N*K) worst case with N being the smallest input sorted set, K being the number of input sorted sets.", @@ -16494,7 +16493,7 @@ ] }, "ZINTERSTORE": { - "summary": "Intersect multiple sorted sets and store the resulting sorted set in a new key", + "summary": "Stores the intersect of multiple sorted sets in a key.", "since": "2.0.0", "group": "sorted-set", "complexity": "O(N*K)+O(M*log(M)) worst case with N being the smallest input sorted set, K being the number of input sorted sets and M being the number of elements in the resulting sorted set.", @@ -16603,7 +16602,7 @@ ] }, "ZLEXCOUNT": { - "summary": "Count the number of members in a sorted set between a given lexicographical range", + "summary": "Returns the number of members in a sorted set within a lexicographical range.", "since": "2.8.9", "group": "sorted-set", "complexity": "O(log(N)) with N being the number of elements in the sorted set.", @@ -16657,7 +16656,7 @@ ] }, "ZMPOP": { - "summary": "Remove and return members with scores in a sorted set", + "summary": "Returns the highest- or lowest-scoring members from one or more sorted sets after removing them. Deletes the sorted set if the last member was popped.", "since": "7.0.0", "group": "sorted-set", "complexity": "O(K) + O(M*log(N)) where K is the number of provided keys, N being the number of elements in the sorted set, and M being the number of elements popped.", @@ -16733,7 +16732,7 @@ ] }, "ZMSCORE": { - "summary": "Get the score associated with the given members in a sorted set", + "summary": "Returns the score of one or more members in a sorted set.", "since": "6.2.0", "group": "sorted-set", "complexity": "O(N) where N is the number of members being requested.", @@ -16783,7 +16782,7 @@ ] }, "ZPOPMAX": { - "summary": "Remove and return members with the highest scores in a sorted set", + "summary": "Returns the highest-scoring members from a sorted set after removing them. Deletes the sorted set if the last member was popped.", "since": "5.0.0", "group": "sorted-set", "complexity": "O(log(N)*M) with N being the number of elements in the sorted set, and M being the number of elements popped.", @@ -16834,7 +16833,7 @@ ] }, "ZPOPMIN": { - "summary": "Remove and return members with the lowest scores in a sorted set", + "summary": "Returns the lowest-scoring members from a sorted set after removing them. Deletes the sorted set if the last member was popped.", "since": "5.0.0", "group": "sorted-set", "complexity": "O(log(N)*M) with N being the number of elements in the sorted set, and M being the number of elements popped.", @@ -16885,10 +16884,10 @@ ] }, "ZRANDMEMBER": { - "summary": "Get one or multiple random elements from a sorted set", + "summary": "Returns one or more random members from a sorted set.", "since": "6.2.0", "group": "sorted-set", - "complexity": "O(N) where N is the number of elements returned", + "complexity": "O(N) where N is the number of members returned", "acl_categories": [ "@read", "@sortedset", @@ -16950,7 +16949,7 @@ ] }, "ZRANGE": { - "summary": "Return a range of members in a sorted set", + "summary": "Returns members in a sorted set within a range of indexes.", "since": "1.2.0", "group": "sorted-set", "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.", @@ -17063,7 +17062,7 @@ ] }, "ZRANGEBYLEX": { - "summary": "Return a range of members in a sorted set, by lexicographical range", + "summary": "Returns members in a sorted set within a lexicographical range.", "since": "2.8.9", "group": "sorted-set", "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).", @@ -17139,7 +17138,7 @@ ] }, "ZRANGEBYSCORE": { - "summary": "Return a range of members in a sorted set, by score", + "summary": "Returns members in a sorted set within a range of scores.", "since": "1.0.5", "group": "sorted-set", "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).", @@ -17229,7 +17228,7 @@ ] }, "ZRANGESTORE": { - "summary": "Store a range of members from sorted set into another key", + "summary": "Stores a range of members from sorted set in a key.", "since": "6.2.0", "group": "sorted-set", "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements stored into the destination key.", @@ -17351,7 +17350,7 @@ ] }, "ZRANK": { - "summary": "Determine the index of a member in a sorted set", + "summary": "Returns the index of a member in a sorted set ordered by ascending scores.", "since": "2.0.0", "group": "sorted-set", "complexity": "O(log(N))", @@ -17413,7 +17412,7 @@ ] }, "ZREM": { - "summary": "Remove one or more members from a sorted set", + "summary": "Removes one or more members from a sorted set. Deletes the sorted set if all members were removed.", "since": "1.2.0", "group": "sorted-set", "complexity": "O(M*log(N)) with N being the number of elements in the sorted set and M the number of elements to be removed.", @@ -17469,7 +17468,7 @@ ] }, "ZREMRANGEBYLEX": { - "summary": "Remove all members in a sorted set between the given lexicographical range", + "summary": "Removes members in a sorted set within a lexicographical range. Deletes the sorted set if all members were removed.", "since": "2.8.9", "group": "sorted-set", "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.", @@ -17522,7 +17521,7 @@ ] }, "ZREMRANGEBYRANK": { - "summary": "Remove all members in a sorted set within the given indexes", + "summary": "Removes members in a sorted set within a range of indexes. Deletes the sorted set if all members were removed.", "since": "2.0.0", "group": "sorted-set", "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.", @@ -17575,7 +17574,7 @@ ] }, "ZREMRANGEBYSCORE": { - "summary": "Remove all members in a sorted set within the given scores", + "summary": "Removes members in a sorted set within a range of scores. Deletes the sorted set if all members were removed.", "since": "1.2.0", "group": "sorted-set", "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.", @@ -17628,7 +17627,7 @@ ] }, "ZREVRANGE": { - "summary": "Return a range of members in a sorted set, by index, with scores ordered from high to low", + "summary": "Returns members in a sorted set within a range of indexes in reverse order.", "since": "1.2.0", "group": "sorted-set", "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.", @@ -17693,7 +17692,7 @@ ] }, "ZREVRANGEBYLEX": { - "summary": "Return a range of members in a sorted set, by lexicographical range, ordered from higher to lower strings.", + "summary": "Returns members in a sorted set within a lexicographical range in reverse order.", "since": "2.8.9", "group": "sorted-set", "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).", @@ -17769,7 +17768,7 @@ ] }, "ZREVRANGEBYSCORE": { - "summary": "Return a range of members in a sorted set, by score, with scores ordered from high to low", + "summary": "Returns members in a sorted set within a range of scores in reverse order.", "since": "2.2.0", "group": "sorted-set", "complexity": "O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).", @@ -17858,7 +17857,7 @@ ] }, "ZREVRANK": { - "summary": "Determine the index of a member in a sorted set, with scores ordered from high to low", + "summary": "Returns the index of a member in a sorted set ordered by descending scores.", "since": "2.0.0", "group": "sorted-set", "complexity": "O(log(N))", @@ -17920,7 +17919,7 @@ ] }, "ZSCAN": { - "summary": "Incrementally iterate sorted sets elements and associated scores", + "summary": "Iterates over members and scores of a sorted set.", "since": "2.8.0", "group": "sorted-set", "complexity": "O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection.", @@ -17985,7 +17984,7 @@ ] }, "ZSCORE": { - "summary": "Get the score associated with the given member in a sorted set", + "summary": "Returns the score of a member in a sorted set.", "since": "1.2.0", "group": "sorted-set", "complexity": "O(1)", @@ -18034,7 +18033,7 @@ ] }, "ZUNION": { - "summary": "Add multiple sorted sets", + "summary": "Returns the union of multiple sorted sets.", "since": "6.2.0", "group": "sorted-set", "complexity": "O(N)+O(M*log(M)) with N being the sum of the sizes of the input sorted sets, and M being the number of elements in the resulting sorted set.", @@ -18125,7 +18124,7 @@ ] }, "ZUNIONSTORE": { - "summary": "Add multiple sorted sets and store the resulting sorted set in a new key", + "summary": "Stores the union of multiple sorted sets in a key.", "since": "2.0.0", "group": "sorted-set", "complexity": "O(N)+O(M log(M)) with N being the sum of the sizes of the input sorted sets, and M being the number of elements in the resulting sorted set.", From 2693400c9e6d95e67d274746cb1513897ab001b1 Mon Sep 17 00:00:00 2001 From: Igor Malinovskiy Date: Thu, 30 Mar 2023 21:11:24 +0200 Subject: [PATCH 176/377] Move official clients to /docs/clients (#2369) --- docs/{redis-clients => clients}/_index.md | 0 docs/{redis-clients => clients}/dotnet.md | 0 docs/{redis-clients => clients}/go.md | 0 docs/{redis-clients => clients}/java.md | 0 docs/{redis-clients => clients}/nodejs.md | 0 docs/{redis-clients => clients}/python.md | 0 resources/clients/index.md | 1 - 7 files changed, 1 deletion(-) rename docs/{redis-clients => clients}/_index.md (100%) rename docs/{redis-clients => clients}/dotnet.md (100%) rename docs/{redis-clients => clients}/go.md (100%) rename docs/{redis-clients => clients}/java.md (100%) rename docs/{redis-clients => clients}/nodejs.md (100%) rename docs/{redis-clients => clients}/python.md (100%) diff --git a/docs/redis-clients/_index.md b/docs/clients/_index.md similarity index 100% rename from docs/redis-clients/_index.md rename to docs/clients/_index.md diff --git a/docs/redis-clients/dotnet.md b/docs/clients/dotnet.md similarity index 100% rename from docs/redis-clients/dotnet.md rename to docs/clients/dotnet.md diff --git a/docs/redis-clients/go.md b/docs/clients/go.md similarity index 100% rename from docs/redis-clients/go.md rename to docs/clients/go.md diff --git a/docs/redis-clients/java.md b/docs/clients/java.md similarity index 100% rename from docs/redis-clients/java.md rename to docs/clients/java.md diff --git a/docs/redis-clients/nodejs.md b/docs/clients/nodejs.md similarity index 100% rename from docs/redis-clients/nodejs.md rename to docs/clients/nodejs.md diff --git a/docs/redis-clients/python.md b/docs/clients/python.md similarity index 100% rename from docs/redis-clients/python.md rename to docs/clients/python.md diff --git a/resources/clients/index.md b/resources/clients/index.md index 288ab72292..9378847afa 100644 --- a/resources/clients/index.md +++ b/resources/clients/index.md @@ -8,6 +8,5 @@ bazzar: clients aliases: - /clients - /clients/ - - /docs/clients --- From 65f6bf60926af8512a112e4b260bb3901347162e Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Thu, 30 Mar 2023 15:42:26 -0400 Subject: [PATCH 177/377] Updates clients quickstart and clients inventory descriptions (#2370) * Updates clients quickstart and clients inventory description to improve SEO * Updates wordlist --- docs/clients/_index.md | 6 +++--- resources/clients/index.md | 2 +- wordlist | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/clients/_index.md b/docs/clients/_index.md index 562f925d4d..f1b37ab7c7 100644 --- a/docs/clients/_index.md +++ b/docs/clients/_index.md @@ -1,7 +1,7 @@ --- -title: "Redis client libraries" -linkTitle: "Clients" -description: Connect your application to a Redis database +title: "Get started using Redis clients" +linkTitle: "Client quickstarts" +description: Get started using Redis clients. Select your library and connect your application to a Redis database. Then, try an example. weight: 45 --- diff --git a/resources/clients/index.md b/resources/clients/index.md index 9378847afa..11e1cad773 100644 --- a/resources/clients/index.md +++ b/resources/clients/index.md @@ -2,7 +2,7 @@ title: "Clients" linkTitle: "Clients" weight: 10 -description: Implementations of the Redis' protocol in different programming languages +description: Implementations of the Redis protocol in different programming languages. To get started see [Client quickstarts](/docs/clients/). layout: bazzar bazzar: clients aliases: diff --git a/wordlist b/wordlist index 2c97b139e9..1104149f67 100644 --- a/wordlist +++ b/wordlist @@ -817,6 +817,7 @@ pseudorandom PSR-4 pubsub qsort +quickstarts queueing radix rc From 0c0735f65b6822a05ccb523c5e50588078ca2399 Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Thu, 30 Mar 2023 15:53:16 -0400 Subject: [PATCH 178/377] Updates alias (#2371) --- docs/clients/_index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/clients/_index.md b/docs/clients/_index.md index f1b37ab7c7..373386c665 100644 --- a/docs/clients/_index.md +++ b/docs/clients/_index.md @@ -3,7 +3,8 @@ title: "Get started using Redis clients" linkTitle: "Client quickstarts" description: Get started using Redis clients. Select your library and connect your application to a Redis database. Then, try an example. weight: 45 - +aliases: + - /docs/clients --- Here, you will learn how to connect your application to a Redis database. If you're new to Redis, you might first want to [install Redis with Redis Stack and RedisInsight](/docs/stack/get-started/install). From a382cfe28aa4226ba047db243826c104c3b3e897 Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Thu, 30 Mar 2023 16:06:13 -0400 Subject: [PATCH 179/377] updates alias (#2372) --- docs/clients/_index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/clients/_index.md b/docs/clients/_index.md index 373386c665..afc4c80cee 100644 --- a/docs/clients/_index.md +++ b/docs/clients/_index.md @@ -5,6 +5,7 @@ description: Get started using Redis clients. Select your library and connect yo weight: 45 aliases: - /docs/clients + - /docs/redis-clients --- Here, you will learn how to connect your application to a Redis database. If you're new to Redis, you might first want to [install Redis with Redis Stack and RedisInsight](/docs/stack/get-started/install). From c6dc86a19d61628e6fd051473d2f18f8b22b3fbc Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Thu, 30 Mar 2023 16:25:53 -0400 Subject: [PATCH 180/377] Updates alias (#2373) --- resources/clients/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/clients/index.md b/resources/clients/index.md index 11e1cad773..74cd2070ed 100644 --- a/resources/clients/index.md +++ b/resources/clients/index.md @@ -6,7 +6,7 @@ description: Implementations of the Redis protocol in different programming lang layout: bazzar bazzar: clients aliases: - - /clients - - /clients/ + - /resources/clients + - /resources/clients/ --- From 232ab5d1623bcad90db91919ec85fafd87d09bab Mon Sep 17 00:00:00 2001 From: Robert Kulagowski Date: Thu, 30 Mar 2023 15:39:36 -0500 Subject: [PATCH 181/377] Update install-redis-from-source.md (#2009) * Update install-redis-from-source.md Markdown didn't actually have a link to the download page. * Update docs/getting-started/installation/install-redis-from-source.md --------- Co-authored-by: Nermina Miller <102551568+nermiller@users.noreply.github.com> --- docs/getting-started/installation/install-redis-from-source.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/installation/install-redis-from-source.md b/docs/getting-started/installation/install-redis-from-source.md index 0fba3a2250..d885bca190 100644 --- a/docs/getting-started/installation/install-redis-from-source.md +++ b/docs/getting-started/installation/install-redis-from-source.md @@ -10,7 +10,7 @@ You can compile and install Redis from source on variety of platforms and operat ## Downloading the source files -The Redis source files are available on [this site's Download page](/download/). You can verify the integrity of these downloads by checking them against the digests in the [redis-hashes git repository](https://github.com/redis/redis-hashes). +The Redis source files are available from the [Download](/download) page. You can verify the integrity of these downloads by checking them against the digests in the [redis-hashes git repository](https://github.com/redis/redis-hashes). To obtain the source files for the latest stable version of Redis from the Redis downloads site, run: From e8d96dc9e6014a38f96f55b101d6759e97053a45 Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Thu, 30 Mar 2023 17:15:33 -0400 Subject: [PATCH 182/377] Alias update (#2374) --- docs/clients/_index.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/clients/_index.md b/docs/clients/_index.md index afc4c80cee..8b4e2dc646 100644 --- a/docs/clients/_index.md +++ b/docs/clients/_index.md @@ -4,8 +4,7 @@ linkTitle: "Client quickstarts" description: Get started using Redis clients. Select your library and connect your application to a Redis database. Then, try an example. weight: 45 aliases: - - /docs/clients - - /docs/redis-clients + --- Here, you will learn how to connect your application to a Redis database. If you're new to Redis, you might first want to [install Redis with Redis Stack and RedisInsight](/docs/stack/get-started/install). From 7dfbed0fe0cddbbe08486328c8e84a770b363583 Mon Sep 17 00:00:00 2001 From: Nermina Miller <102551568+nermiller@users.noreply.github.com> Date: Thu, 30 Mar 2023 17:25:02 -0400 Subject: [PATCH 183/377] Updates alias (#2375) --- docs/clients/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/clients/_index.md b/docs/clients/_index.md index 8b4e2dc646..b8fc945a62 100644 --- a/docs/clients/_index.md +++ b/docs/clients/_index.md @@ -4,7 +4,7 @@ linkTitle: "Client quickstarts" description: Get started using Redis clients. Select your library and connect your application to a Redis database. Then, try an example. weight: 45 aliases: - + - /docs/redis-clients --- Here, you will learn how to connect your application to a Redis database. If you're new to Redis, you might first want to [install Redis with Redis Stack and RedisInsight](/docs/stack/get-started/install). From f40e3dcb6cb03d8c9d367919d5430e5228de204b Mon Sep 17 00:00:00 2001 From: Binbin Date: Sat, 1 Apr 2023 20:24:02 +0800 Subject: [PATCH 184/377] Add redis-clients to wordlist to fix spellcheck (#2377) --- wordlist | 1 + 1 file changed, 1 insertion(+) diff --git a/wordlist b/wordlist index 1104149f67..388ccf2d2c 100644 --- a/wordlist +++ b/wordlist @@ -846,6 +846,7 @@ redis redis-benchmark redis-check-aof redis-cli +redis-clients redis-doc redis-hashes redis-lua From 64f1af6d702204042f033f936b9c8bab9a693e5c Mon Sep 17 00:00:00 2001 From: judeng Date: Tue, 4 Apr 2023 04:27:55 +0800 Subject: [PATCH 185/377] Update the description of the `count` parameter in the slowlog-get command (#2381) fix the default return messages and add the sepcial count value '-1' --- commands/slowlog-get.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/slowlog-get.md b/commands/slowlog-get.md index d496e39439..a99910ad87 100644 --- a/commands/slowlog-get.md +++ b/commands/slowlog-get.md @@ -6,7 +6,7 @@ The execution time does not include I/O operations like talking with the client, A new entry is added to the slow log whenever a command exceeds the execution time threshold defined by the `slowlog-log-slower-than` configuration directive. The maximum number of entries in the slow log is governed by the `slowlog-max-len` configuration directive. -By default the command returns all of the entries in the log. The optional `count` argument limits the number of returned entries, so the command returns at most up to `count` entries. +By default the command returns latest ten entries in the log. The optional `count` argument limits the number of returned entries, so the command returns at most up to `count` entries, the special number -1 means return all entries. Each entry from the slow log is comprised of the following six values: From 666330aa331d9cf7f310170a02c924cc760cf143 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Tue, 4 Apr 2023 00:20:06 +0300 Subject: [PATCH 186/377] Adds delivery semantics clause to Pub/Sub (#2379) --- docs/manual/pubsub.md | 153 ++++++++++++++++++------------------------ 1 file changed, 64 insertions(+), 89 deletions(-) diff --git a/docs/manual/pubsub.md b/docs/manual/pubsub.md index 71461a2bc7..ada1dae322 100644 --- a/docs/manual/pubsub.md +++ b/docs/manual/pubsub.md @@ -8,39 +8,47 @@ aliases: - /docs/manual/pub-sub --- -`SUBSCRIBE`, `UNSUBSCRIBE` and `PUBLISH` -implement the [Publish/Subscribe messaging -paradigm](http://en.wikipedia.org/wiki/Publish/subscribe) where -(citing Wikipedia) senders (publishers) are not programmed to send -their messages to specific receivers (subscribers). Rather, published -messages are characterized into channels, without knowledge of what (if -any) subscribers there may be. Subscribers express interest in one or -more channels, and only receive messages that are of interest, without -knowledge of what (if any) publishers there are. This decoupling of -publishers and subscribers can allow for greater scalability and a more -dynamic network topology. - -For instance in order to subscribe to channels `foo` and `bar` the -client issues a `SUBSCRIBE` providing the names of the channels: +`SUBSCRIBE`, `UNSUBSCRIBE` and `PUBLISH` implement the [Publish/Subscribe messaging paradigm](http://en.wikipedia.org/wiki/Publish/subscribe) where (citing Wikipedia) senders (publishers) are not programmed to send their messages to specific receivers (subscribers). +Rather, published messages are characterized into channels, without knowledge of what (if any) subscribers there may be. +Subscribers express interest in one or more channels and only receive messages that are of interest, without knowledge of what (if any) publishers there are. +This decoupling of publishers and subscribers allows for greater scalability and a more dynamic network topology. + +For instance, to subscribe to channels "channel11" and "4chan" the client issues a `SUBSCRIBE` providing the names of the channels: ```bash -SUBSCRIBE foo bar +SUBSCRIBE channel11 4chan ``` -Messages sent by other clients to these channels will be pushed by Redis -to all the subscribed clients. +Messages sent by other clients to these channels will be pushed by Redis to all the subscribed clients. +Subscribers receive the messages in the order that the messages are published. + +A client subscribed to one or more channels shouldn't issue commands, although it can `SUBSCRIBE` and `UNSUBSCRIBE` to and from other channels. +The replies to subscription and unsubscribing operations are sent in the form of messages so that the client can just read a coherent stream of messages where the first element indicates the type of message. +The commands that are allowed in the context of a subscribed RESP2 client are: + +* `PING` +* `PSUBSCRIBE` +* `PUNSUBSCRIBE` +* `QUIT` +* `RESET` +* `SSUBSCRIBE` +* `SUBSCRIBE` +* `SUNSUBSCRIBE` +* `UNSUBSCRIBE` + +However, if RESP3 is used (see `HELLO`), a client can issue any commands while in the subscribed state. -A client subscribed to one or more channels should not issue commands, -although it can subscribe and unsubscribe to and from other channels. -The replies to subscription and unsubscribing operations are sent in -the form of messages, so that the client can just read a coherent -stream of messages where the first element indicates the type of -message. The commands that are allowed in the context of a subscribed -client are `SUBSCRIBE`, `SSUBSCRIBE`, `SUNSUBSCRIBE`, `PSUBSCRIBE`, `UNSUBSCRIBE`, `PUNSUBSCRIBE`, `PING`, `RESET`, and `QUIT`. +Please note that when using `redis-cli`, in subscribed mode commands such as `UNSUBSCRIBE` and `PUNSUBSCRIBE` cannot be used because `redis-cli` will not accept any commands and can only quit the mode with `Ctrl-C`. -Please note that when using `redis-cli`, in subscribed mode -commands such as `UNSUBSCRIBE` and `PUNSUBSCRIBE` cannot be used because -`redis-cli` will not accept any commands and can only quit the mode with `Ctrl-C`. +## Delivery semantics + +Redis' Pub/Sub exhibits _at-most-once_ message delivery semantics. +As the name suggests, it means that a message will be delivered once if at all. +Once the message is sent by the Redis server, there's no chance of it being sent again. +If the subscriber is unable to handle the message (for example, due to an error or a network disconnect) the message is forever lost. + +If your application requires stronger delivery guarantees, you may want to learn about [Redis Streams](/docs/data-types/streams-tutorial). +Messages in streams are persisted, and support both _at-most-once_ as well as _at-least-once_ delivery semantics. ## Format of pushed messages @@ -48,21 +56,15 @@ A message is an [array-reply](/topics/protocol#array-reply) with three elements. The first element is the kind of message: -* `subscribe`: means that we successfully subscribed to the channel -given as the second element in the reply. The third argument represents -the number of channels we are currently subscribed to. +* `subscribe`: means that we successfully subscribed to the channel given as the second element in the reply. + The third argument represents the number of channels we are currently subscribed to. -* `unsubscribe`: means that we successfully unsubscribed from the -channel given as second element in the reply. The third argument -represents the number of channels we are currently subscribed to. When -the last argument is zero, we are no longer subscribed to any channel, -and the client can issue any kind of Redis command as we are outside the -Pub/Sub state. +* `unsubscribe`: means that we successfully unsubscribed from the channel given as second element in the reply. + The third argument represents the number of channels we are currently subscribed to. + When the last argument is zero, we are no longer subscribed to any channel, and the client can issue any kind of Redis command as we are outside the Pub/Sub state. -* `message`: it is a message received as result of a `PUBLISH` command -issued by another client. The second element is the name of the -originating channel, and the third argument is the actual message -payload. +* `message`: it is a message received as a result of a `PUBLISH` command issued by another client. + The second element is the name of the originating channel, and the third argument is the actual message payload. ## Database & Scoping @@ -71,8 +73,7 @@ It was made to not interfere with it on any level, including database numbers. Publishing on db 10, will be heard by a subscriber on db 1. -If you need scoping of some kind, prefix the channels with the name of the -environment (test, staging, production...). +If you need scoping of some kind, prefix the channels with the name of the environment (test, staging, production...). ## Wire protocol example @@ -92,8 +93,7 @@ second :2 ``` -At this point, from another client we issue a `PUBLISH` operation -against the channel named `second`: +At this point, from another client we issue a `PUBLISH` operation against the channel named `second`: ``` > PUBLISH second Hello @@ -111,8 +111,7 @@ $5 Hello ``` -Now the client unsubscribes itself from all the channels using the -`UNSUBSCRIBE` command without additional arguments: +Now the client unsubscribes itself from all the channels using the `UNSUBSCRIBE` command without additional arguments: ``` UNSUBSCRIBE @@ -132,9 +131,8 @@ first ## Pattern-matching subscriptions -The Redis Pub/Sub implementation supports pattern matching. Clients may -subscribe to glob-style patterns in order to receive all the messages -sent to channel names matching a given pattern. +The Redis Pub/Sub implementation supports pattern matching. +Clients may subscribe to glob-style patterns to receive all the messages sent to channel names matching a given pattern. For instance: @@ -142,8 +140,7 @@ For instance: PSUBSCRIBE news.* ``` -Will receive all the messages sent to the channel `news.art.figurative`, -`news.music.jazz`, etc. +Will receive all the messages sent to the channel `news.art.figurative`, `news.music.jazz`, etc. All the glob-style patterns are valid, so multiple wildcards are supported. ``` @@ -153,71 +150,49 @@ PUNSUBSCRIBE news.* Will then unsubscribe the client from that pattern. No other subscriptions will be affected by this call. -Messages received as a result of pattern matching are sent in a -different format: +Messages received as a result of pattern matching are sent in a different format: -* The type of the message is `pmessage`: it is a message received -as result of a `PUBLISH` command issued by another client, matching -a pattern-matching subscription. The second element is the original -pattern matched, the third element is the name of the originating -channel, and the last element the actual message payload. +* The type of the message is `pmessage`: it is a message received as a result from a `PUBLISH` command issued by another client, matching a pattern-matching subscription. + The second element is the original pattern matched, the third element is the name of the originating channel, and the last element is the actual message payload. -Similarly to `SUBSCRIBE` and `UNSUBSCRIBE`, `PSUBSCRIBE` and -`PUNSUBSCRIBE` commands are acknowledged by the system sending a message -of type `psubscribe` and `punsubscribe` using the same format as the -`subscribe` and `unsubscribe` message format. +Similarly to `SUBSCRIBE` and `UNSUBSCRIBE`, `PSUBSCRIBE` and `PUNSUBSCRIBE` commands are acknowledged by the system sending a message of type `psubscribe` and `punsubscribe` using the same format as the `subscribe` and `unsubscribe` message format. ## Messages matching both a pattern and a channel subscription -A client may receive a single message multiple times if it's subscribed -to multiple patterns matching a published message, or if it is -subscribed to both patterns and channels matching the message. Like in -the following example: +A client may receive a single message multiple times if it's subscribed to multiple patterns matching a published message, or if it is subscribed to both patterns and channels matching the message. +This is shown by the following example: ``` SUBSCRIBE foo PSUBSCRIBE f* ``` -In the above example, if a message is sent to channel `foo`, the client -will receive two messages: one of type `message` and one of type -`pmessage`. +In the above example, if a message is sent to channel `foo`, the client will receive two messages: one of type `message` and one of type `pmessage`. ## The meaning of the subscription count with pattern matching -In `subscribe`, `unsubscribe`, `psubscribe` and `punsubscribe` -message types, the last argument is the count of subscriptions still -active. This number is actually the total number of channels and -patterns the client is still subscribed to. So the client will exit -the Pub/Sub state only when this count drops to zero as a result of -unsubscribing from all the channels and patterns. +In `subscribe`, `unsubscribe`, `psubscribe` and `punsubscribe` message types, the last argument is the count of subscriptions still active. +This number is the total number of channels and patterns the client is still subscribed to. +So the client will exit the Pub/Sub state only when this count drops to zero as a result of unsubscribing from all the channels and patterns. ## Sharded Pub/Sub -From 7.0, sharded Pub/Sub is introduced in which shard channels are assigned to slots by the same algorithm used to assign keys to slots. -A shard message must be sent to a node that own the slot the shard channel is hashed to. +From Redis 7.0, sharded Pub/Sub is introduced in which shard channels are assigned to slots by the same algorithm used to assign keys to slots. +A shard message must be sent to a node that owns the slot the shard channel is hashed to. The cluster makes sure the published shard messages are forwarded to all nodes in the shard, so clients can subscribe to a shard channel by connecting to either the master responsible for the slot, or to any of its replicas. `SSUBSCRIBE`, `SUNSUBSCRIBE` and `SPUBLISH` are used to implement sharded Pub/Sub. Sharded Pub/Sub helps to scale the usage of Pub/Sub in cluster mode. -It restricts the propagation of message to be within the shard of a cluster. +It restricts the propagation of messages to be within the shard of a cluster. Hence, the amount of data passing through the cluster bus is limited in comparison to global Pub/Sub where each message propagates to each node in the cluster. This allows users to horizontally scale the Pub/Sub usage by adding more shards. - ## Programming example -Pieter Noordhuis provided a great example using EventMachine -and Redis to create [a multi user high performance web -chat](https://gist.github.com/pietern/348262). +Pieter Noordhuis provided a great example using EventMachine and Redis to create [a multi user high performance web chat](https://gist.github.com/pietern/348262). ## Client library implementation hints -Because all the messages received contain the original subscription -causing the message delivery (the channel in the case of message type, -and the original pattern in the case of pmessage type) client libraries -may bind the original subscription to callbacks (that can be anonymous -functions, blocks, function pointers), using a hash table. +Because all the messages received contain the original subscription causing the message delivery (the channel in the case of message type, and the original pattern in the case of pmessage type) client libraries may bind the original subscription to callbacks (that can be anonymous functions, blocks, function pointers), using a hash table. -When a message is received an O(1) lookup can be done in order to -deliver the message to the registered callback. +When a message is received an O(1) lookup can be done to deliver the message to the registered callback. From 5c2fe58275ef43db97d16edea5cb1ae403c5a947 Mon Sep 17 00:00:00 2001 From: Yossi Gottlieb Date: Thu, 13 Apr 2023 12:33:39 +0300 Subject: [PATCH 187/377] Clarify error code conventions for Lua. (#2382) Clarify error code conventions for Lua. --- docs/manual/programmability/lua-api.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/manual/programmability/lua-api.md b/docs/manual/programmability/lua-api.md index 2add93ae46..e2ef46353f 100644 --- a/docs/manual/programmability/lua-api.md +++ b/docs/manual/programmability/lua-api.md @@ -163,7 +163,7 @@ local reply = redis.pcall('ECHO', unpack(ARGV)) if reply['err'] ~= nil then -- Handle the error sometime, but for now just log it redis.log(redis.LOG_WARNING, reply['err']) - reply['err'] = 'Something is wrong, but no worries, everything is under control' + reply['err'] = 'ERR Something is wrong, but no worries, everything is under control' end return reply ``` @@ -172,7 +172,7 @@ Evaluating this script with more than one argument will return: ``` redis> EVAL "..." 0 hello world -(error) Something is wrong, but no worries, everything is under control +(error) ERR Something is wrong, but no worries, everything is under control ``` ### `redis.error_reply(x)` @@ -187,7 +187,7 @@ The helper accepts a single string argument and returns a Lua table with the _er The outcome of the following code is that _error1_ and _error2_ are identical for all intents and purposes: ```lua -local text = 'My very special error' +local text = 'ERR My very special error' local reply1 = { err = text } local reply2 = redis.error_reply(text) ``` @@ -195,15 +195,19 @@ local reply2 = redis.error_reply(text) Therefore, both forms are valid as means for returning an error reply from scripts: ``` -redis> EVAL "return { err = 'My very special table error' }" 0 -(error) My very special table error -redis> EVAL "return redis.error_reply('My very special reply error')" 0 -(error) My very special reply error +redis> EVAL "return { err = 'ERR My very special table error' }" 0 +(error) ERR My very special table error +redis> EVAL "return redis.error_reply('ERR My very special reply error')" 0 +(error) ERR My very special reply error ``` For returning Redis status replies refer to [`redis.status_reply()`](#redis.status_reply). Refer to the [Data type conversion](#data-type-conversion) for returning other response types. +**Note:** +By convention, Redis uses the first word of an error string as a unique error code for specific errors or `ERR` for general-purpose errors. +Scripts are advised to follow this convention, as shown in the example above, but this is not mandatory. + ### `redis.status_reply(x)` * Since version: 2.6.0 From 51596d07f8557c8084d1cd6329d3e3620fa7c36c Mon Sep 17 00:00:00 2001 From: Dhiraj Suthar <52701640+Dhiraj5789@users.noreply.github.com> Date: Thu, 13 Apr 2023 17:04:37 +0530 Subject: [PATCH 188/377] removal of $ from $ brew -version command (#2383) --- docs/getting-started/installation/install-redis-on-mac-os.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/installation/install-redis-on-mac-os.md b/docs/getting-started/installation/install-redis-on-mac-os.md index 37c6f95fa3..cb838e5ae2 100644 --- a/docs/getting-started/installation/install-redis-on-mac-os.md +++ b/docs/getting-started/installation/install-redis-on-mac-os.md @@ -12,7 +12,7 @@ This guide shows you how to install Redis on macOS using Homebrew. Homebrew is t First, make sure you have Homebrew installed. From the terminal, run: {{< highlight bash >}} -$ brew --version +brew --version {{< / highlight >}} If this command fails, you'll need to [follow the Homebrew installation instructions](https://brew.sh/). From c7880ba85fd67cb09110a4be790da47d4a6cec80 Mon Sep 17 00:00:00 2001 From: Josh Richards Date: Sun, 16 Apr 2023 15:21:23 -0400 Subject: [PATCH 189/377] Add context to kernel parameter changes (#2386) --- docs/management/admin.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/management/admin.md b/docs/management/admin.md index 3c1992877b..79bfb70b5f 100644 --- a/docs/management/admin.md +++ b/docs/management/admin.md @@ -17,11 +17,9 @@ aliases: [ * Deploy Redis using the Linux operating system. Redis is also tested on OS X, and from time to time on FreeBSD and OpenBSD systems. However, Linux is where most of the stress testing is performed, and where most production deployments are run. -* Set the Linux kernel overcommit memory setting to 1. Add `vm.overcommit_memory = 1` to `/etc/sysctl.conf`. Then, reboot or run the command `sysctl vm.overcommit_memory=1` to activate the setting. +* Set the Linux kernel overcommit memory setting to 1. Add `vm.overcommit_memory = 1` to `/etc/sysctl.conf`. Then, reboot or run the command `sysctl vm.overcommit_memory=1` to activate the setting. See [FAQ: Background saving fails with a fork() error on Linux?](https://redis.io/docs/getting-started/faq/#background-saving-fails-with-a-fork-error-on-linux) for details. -* To ensure the Linux kernel feature Transparent Huge Pages does not impact Redis memory usage and latency, use this command: - -`echo never > /sys/kernel/mm/transparent_hugepage/enabled` +* To ensure the Linux kernel feature Transparent Huge Pages does not impact Redis memory usage and latency, run the command: `echo never > /sys/kernel/mm/transparent_hugepage/enabled` to disable it. See [Latency Diagnosis - Latency induced by transparent huge pages](https://redis.io/docs/management/optimization/latency/#latency-induced-by-transparent-huge-pages) for additional context. ### Memory From 53c09b35806338fb778c10654024d7f1295112fe Mon Sep 17 00:00:00 2001 From: Per Persson Date: Wed, 19 Apr 2023 16:26:08 +0200 Subject: [PATCH 190/377] Spelling: filed -> field (#2391) --- commands/cluster-nodes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/cluster-nodes.md b/commands/cluster-nodes.md index 2152c94c78..8ccc52152d 100644 --- a/commands/cluster-nodes.md +++ b/commands/cluster-nodes.md @@ -36,7 +36,7 @@ Each line is composed of the following fields: ... ``` -The meaning of each filed is the following: +The meaning of each field is the following: 1. `id`: The node ID, a 40-character globally unique string generated when a node is created and never changed again (unless `CLUSTER RESET HARD` is used). 2. `ip:port@cport`: The node address that clients should contact to run queries. From 1aec91af07d237648d1b34c20df4d6b4c5682da3 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Thu, 20 Apr 2023 12:16:17 +0300 Subject: [PATCH 191/377] Updates commands.json (#2393) --- commands.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commands.json b/commands.json index 91f873f9b2..a7825f74cb 100644 --- a/commands.json +++ b/commands.json @@ -11297,7 +11297,7 @@ ] }, "RPOP": { - "summary": "Returns and removes the last elements of a list. Deletes the list if the lst element was popped.", + "summary": "Returns and removes the last elements of a list. Deletes the list if the last element was popped.", "since": "1.0.0", "group": "list", "complexity": "O(N) where N is the number of elements returned", @@ -11355,7 +11355,7 @@ ] }, "RPOPLPUSH": { - "summary": "Returns the last element of a list after removing and pushing it to another list. Deletes the list if the lst element was popped.", + "summary": "Returns the last element of a list after removing and pushing it to another list. Deletes the list if the last element was popped.", "since": "1.2.0", "group": "list", "complexity": "O(1)", From 8543225a775ef04277928b811e2b52350658ffc1 Mon Sep 17 00:00:00 2001 From: huyuansong Date: Thu, 20 Apr 2023 17:20:35 +0800 Subject: [PATCH 192/377] Update latency.md (#2392) From c37e2932b7419491187fbc244858e4203b1aa03d Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Thu, 20 Apr 2023 12:50:23 +0300 Subject: [PATCH 193/377] Removes REDISMODULE_EXPERIMENTAL_API (#2394) Ref: https://github.com/redis/redis/pull/10527 --- docs/reference/modules/modules-blocking-ops.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/docs/reference/modules/modules-blocking-ops.md b/docs/reference/modules/modules-blocking-ops.md index cda8f869ae..80bb4bc51b 100644 --- a/docs/reference/modules/modules-blocking-ops.md +++ b/docs/reference/modules/modules-blocking-ops.md @@ -23,15 +23,6 @@ Redis modules have the ability to implement blocking commands as well, this documentation shows how the API works and describes a few patterns that can be used in order to model blocking commands. -NOTE: This API is currently *experimental*, so it can only be used if -the macro `REDISMODULE_EXPERIMENTAL_API` is defined. This is required because -these calls are still not in their final stage of design, so may change -in the future, certain parts may be deprecated and so forth. - -To use this part of the modules API include the modules header like that: - - #define REDISMODULE_EXPERIMENTAL_API - #include "redismodule.h" How blocking and resuming works. --- From 006bbfae2bce73e150ea0633e1995beb7b255172 Mon Sep 17 00:00:00 2001 From: Andrei Banu <93577418+Andrei-Banu@users.noreply.github.com> Date: Sun, 23 Apr 2023 14:40:31 +0300 Subject: [PATCH 194/377] Update zrange.md (#2395) --- commands/zrange.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/commands/zrange.md b/commands/zrange.md index 1a8e4215a4..e28d5c3994 100644 --- a/commands/zrange.md +++ b/commands/zrange.md @@ -108,9 +108,7 @@ their scores, in case the `WITHSCORES` option is given). @examples ```cli -ZADD myzset 1 "one" -ZADD myzset 2 "two" -ZADD myzset 3 "three" +ZADD myzset 1 "one" 2 "two" 3 "three" ZRANGE myzset 0 -1 ZRANGE myzset 2 3 ZRANGE myzset -2 -1 @@ -119,11 +117,13 @@ ZRANGE myzset -2 -1 The following example using `WITHSCORES` shows how the command returns always an array, but this time, populated with *element_1*, *score_1*, *element_2*, *score_2*, ..., *element_N*, *score_N*. ```cli +ZADD myzset 1 "one" 2 "two" 3 "three" ZRANGE myzset 0 1 WITHSCORES ``` This example shows how to query the sorted set by score, excluding the value `1` and up to infinity, returning only the second element of the result: ```cli +ZADD myzset 1 "one" 2 "two" 3 "three" ZRANGE myzset (1 +inf BYSCORE LIMIT 1 1 -``` \ No newline at end of file +``` From d2271071092b4b0df5c0eee7d62f119ae4a6ff97 Mon Sep 17 00:00:00 2001 From: Binbin Date: Sun, 23 Apr 2023 19:47:11 +0800 Subject: [PATCH 195/377] Minor fixes in cluster-addslots / cluster-addslotsrange (#2396) --- commands/cluster-addslots.md | 2 +- commands/cluster-addslotsrange.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/commands/cluster-addslots.md b/commands/cluster-addslots.md index 060406661d..9c9a8c012e 100644 --- a/commands/cluster-addslots.md +++ b/commands/cluster-addslots.md @@ -29,7 +29,7 @@ are already assigned: This command only works in cluster mode and is useful in the following Redis Cluster operations: -1. To create a new cluster ADDSLOTS is used in order to initially setup master nodes splitting the available hash slots among them. +1. To create a new `cluster ADDSLOTS` is used in order to initially setup master nodes splitting the available hash slots among them. 2. In order to fix a broken cluster where certain slots are unassigned. ## Information about slots propagation and warnings diff --git a/commands/cluster-addslotsrange.md b/commands/cluster-addslotsrange.md index a00e23f709..6e7c545fc1 100644 --- a/commands/cluster-addslotsrange.md +++ b/commands/cluster-addslotsrange.md @@ -1,15 +1,15 @@ The `CLUSTER ADDSLOTSRANGE` is similar to the `CLUSTER ADDSLOTS` command in that they both assign hash slots to nodes. -The difference between the two commands is that `ADDSLOTS` takes a list of slots to assign to the node, while `ADDSLOTSRANGE` takes a list of slot ranges (specified by start and end slots) to assign to the node. +The difference between the two commands is that `CLUSTER ADDSLOTS` takes a list of slots to assign to the node, while `CLUSTER ADDSLOTSRANGE` takes a list of slot ranges (specified by start and end slots) to assign to the node. ## Example -To assign slots 1 2 3 4 5 to the node, the `ADDSLOTS` command is: +To assign slots 1 2 3 4 5 to the node, the `CLUSTER ADDSLOTS` command is: > CLUSTER ADDSLOTS 1 2 3 4 5 OK -The same operation can be completed with the following `ADDSLOTSRANGE` command: +The same operation can be completed with the following `CLUSTER ADDSLOTSRANGE` command: > CLUSTER ADDSLOTSRANGE 1 5 OK @@ -19,7 +19,7 @@ The same operation can be completed with the following `ADDSLOTSRANGE` command: This command only works in cluster mode and is useful in the following Redis Cluster operations: -1. To create a new cluster ADDSLOTSRANGE is used in order to initially setup master nodes splitting the available hash slots among them. +1. To create a new cluster, `CLUSTER ADDSLOTSRANGE` is used to initially set up master nodes splitting the available hash slots among them. 2. In order to fix a broken cluster where certain slots are unassigned. @return From 29252add61fe5be66460a90966927ce84bf32989 Mon Sep 17 00:00:00 2001 From: Ananda Ilyasa Putra <71200519+AnandaIlyasa@users.noreply.github.com> Date: Tue, 25 Apr 2023 00:17:40 +0700 Subject: [PATCH 196/377] Update context parameter in go.md (#2397) * Update context parameter in go.md ctx parameter is not yet initialized * add ctx := context.Background() --- docs/clients/go.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/clients/go.md b/docs/clients/go.md index 3cbcca08c6..77bcd053de 100644 --- a/docs/clients/go.md +++ b/docs/clients/go.md @@ -59,6 +59,8 @@ client := redis.NewClient(opt) Store and retrieve a simple string. ```go +ctx := context.Background() + err := client.Set(ctx, "foo", "bar", 0).Err() if err != nil { panic(err) From dbe9296f0a7c9c2a05b73c06d5774f078e68fd7e Mon Sep 17 00:00:00 2001 From: Binbin Date: Tue, 25 Apr 2023 22:13:21 +0800 Subject: [PATCH 197/377] Do not generate command hyperlinks in headlines (#2398) --- docs/manual/programmability/eval-intro.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/manual/programmability/eval-intro.md b/docs/manual/programmability/eval-intro.md index 28678360eb..f1a4e9b97c 100644 --- a/docs/manual/programmability/eval-intro.md +++ b/docs/manual/programmability/eval-intro.md @@ -179,7 +179,7 @@ In this case, the application should first load it with `SCRIPT LOAD` and then c Most of [Redis' clients](/clients) already provide utility APIs for doing that automatically. Please consult your client's documentation regarding the specific details. -### `EVALSHA` in the context of pipelining +### `!EVALSHA` in the context of pipelining Special care should be given executing `EVALSHA` in the context of a [pipelined request](/topics/pipelining). The commands in a pipelined request run in the order they are sent, but other clients' commands may be interleaved for execution between these. @@ -206,7 +206,7 @@ However, from the point of view of the Redis client, there are only two ways to Practically speaking, it is much simpler for the client to assume that in the context of a given connection, cached scripts are guaranteed to be there unless the administrator explicitly invoked the `SCRIPT FLUSH` command. The fact that the user can count on Redis to retain cached scripts is semantically helpful in the context of pipelining. -## The `SCRIPT` command +## The `!SCRIPT` command The Redis `SCRIPT` provides several ways for controlling the scripting subsystem. These are: From 99a66a581c1fc0b9b3151a3de4443dac8850fe38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Santos?= Date: Thu, 4 May 2023 15:04:17 +0100 Subject: [PATCH 198/377] fix broken hash in link to "read-only scripts" heading (#2403) --- commands/eval_ro.md | 2 +- commands/evalsha_ro.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/eval_ro.md b/commands/eval_ro.md index bbbdb8deb4..bc166c84dd 100644 --- a/commands/eval_ro.md +++ b/commands/eval_ro.md @@ -1,6 +1,6 @@ This is a read-only variant of the `EVAL` command that cannot execute commands that modify data. -For more information about when to use this command vs `EVAL`, please refer to [Read-only scripts](/docs/manual/programmability/#read-only_scripts). +For more information about when to use this command vs `EVAL`, please refer to [Read-only scripts](/docs/manual/programmability/#read-only-scripts). For more information about `EVAL` scripts please refer to [Introduction to Eval Scripts](/topics/eval-intro). diff --git a/commands/evalsha_ro.md b/commands/evalsha_ro.md index ccb45d6722..b6164b3303 100644 --- a/commands/evalsha_ro.md +++ b/commands/evalsha_ro.md @@ -1,5 +1,5 @@ This is a read-only variant of the `EVALSHA` command that cannot execute commands that modify data. -For more information about when to use this command vs `EVALSHA`, please refer to [Read-only scripts](/docs/manual/programmability/#read-only_scripts). +For more information about when to use this command vs `EVALSHA`, please refer to [Read-only scripts](/docs/manual/programmability/#read-only-scripts). For more information about `EVALSHA` scripts please refer to [Introduction to Eval Scripts](/topics/eval-intro). From 509c75086c65a21e7a07500fb7ddb8bcdc58baa8 Mon Sep 17 00:00:00 2001 From: Chayim Date: Sun, 7 May 2023 15:55:22 +0300 Subject: [PATCH 199/377] Update go.md (#2405) Wrapping the base example with a main --- docs/clients/go.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/clients/go.md b/docs/clients/go.md index 77bcd053de..cbbefe2b42 100644 --- a/docs/clients/go.md +++ b/docs/clients/go.md @@ -38,11 +38,13 @@ import ( "github.com/redis/go-redis/v9" ) -client := redis.NewClient(&redis.Options{ - Addr: "localhost:6379", - Password: "", // no password set - DB: 0, // use default DB -}) +func main() { + client := redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + Password: "", // no password set + DB: 0, // use default DB + }) +} ``` Another way to connect is using a connection string. From 9eda2fe59cfb24ecae46ae27186c5a12f7e69ac3 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Sun, 7 May 2023 22:38:30 +0600 Subject: [PATCH 200/377] Fix PUBSUB SHARDCHANNELS example (#2407) --- commands/pubsub-shardchannels.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/pubsub-shardchannels.md b/commands/pubsub-shardchannels.md index 543eab0edc..b2b5da3355 100644 --- a/commands/pubsub-shardchannels.md +++ b/commands/pubsub-shardchannels.md @@ -15,6 +15,6 @@ The information returned about the active shard channels are at the shard level ``` > PUBSUB SHARDCHANNELS 1) "orders" -PUBSUB SHARDCHANNELS o* +> PUBSUB SHARDCHANNELS o* 1) "orders" ``` From a43b9ab5f6ba7c4a182b3b987406ddacf16da610 Mon Sep 17 00:00:00 2001 From: Chayim Date: Sun, 14 May 2023 14:25:32 +0300 Subject: [PATCH 201/377] state machine url change (#2410) --- .../redis-state-machine.json} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename modules/community/github.com/{RedisStateMachine/RedisStateMachine.json => RedisLabsModules/redis-state-machine.json} (61%) diff --git a/modules/community/github.com/RedisStateMachine/RedisStateMachine.json b/modules/community/github.com/RedisLabsModules/redis-state-machine.json similarity index 61% rename from modules/community/github.com/RedisStateMachine/RedisStateMachine.json rename to modules/community/github.com/RedisLabsModules/redis-state-machine.json index 2b2e3ac08e..d25220766d 100644 --- a/modules/community/github.com/RedisStateMachine/RedisStateMachine.json +++ b/modules/community/github.com/RedisLabsModules/redis-state-machine.json @@ -1,7 +1,7 @@ { "name": "RedisStateMachine", "license": "Redis Source Available License", - "description": "A module for storing state machines in", + "description": "A module for storing state machines, and transitioning them in Redis", "github": [ "chayim", "RedisLabs" From 7f52d5cc22e273af909773c783b6d5eed2ee56ee Mon Sep 17 00:00:00 2001 From: Oran Agra Date: Mon, 15 May 2023 13:41:26 +0300 Subject: [PATCH 202/377] update commands.json and module docs with 7.2 RC2 (#2411) includes some minor edits for commands.json arguments, and a few new module APIs --- commands.json | 70 +++++++----- docs/reference/modules/modules-api-ref.md | 133 +++++++++++++++++++--- 2 files changed, 159 insertions(+), 44 deletions(-) diff --git a/commands.json b/commands.json index a7825f74cb..8cfc9c9777 100644 --- a/commands.json +++ b/commands.json @@ -3107,7 +3107,7 @@ ] }, "COMMAND DOCS": { - "summary": "Returns documentary information about a command.", + "summary": "Returns documentary information about one, multiple or all commands.", "since": "7.0.0", "group": "server", "complexity": "O(N) where N is the number of commands to look up", @@ -5378,20 +5378,25 @@ ] }, { - "name": "storekey", - "type": "key", - "display_text": "key", - "key_spec_index": 1, - "token": "STORE", - "optional": true - }, - { - "name": "storedistkey", - "type": "key", - "display_text": "key", - "key_spec_index": 2, - "token": "STOREDIST", - "optional": true + "name": "store", + "type": "oneof", + "optional": true, + "arguments": [ + { + "name": "storekey", + "type": "key", + "display_text": "key", + "key_spec_index": 1, + "token": "STORE" + }, + { + "name": "storedistkey", + "type": "key", + "display_text": "key", + "key_spec_index": 2, + "token": "STOREDIST" + } + ] } ], "command_flags": [ @@ -5588,20 +5593,25 @@ ] }, { - "name": "storekey", - "type": "key", - "display_text": "key", - "key_spec_index": 1, - "token": "STORE", - "optional": true - }, - { - "name": "storedistkey", - "type": "key", - "display_text": "key", - "key_spec_index": 2, - "token": "STOREDIST", - "optional": true + "name": "store", + "type": "oneof", + "optional": true, + "arguments": [ + { + "name": "storekey", + "type": "key", + "display_text": "key", + "key_spec_index": 1, + "token": "STORE" + }, + { + "name": "storedistkey", + "type": "key", + "display_text": "key", + "key_spec_index": 2, + "token": "STOREDIST" + } + ] } ], "command_flags": [ @@ -15582,7 +15592,7 @@ ] }, "XREADGROUP": { - "summary": "Returns new or historical messages from a stream for a consumer in agroup. Blocks until a message is available otherwise.", + "summary": "Returns new or historical messages from a stream for a consumer in a group. Blocks until a message is available otherwise.", "since": "5.0.0", "group": "stream", "complexity": "For each stream mentioned: O(M) with M being the number of elements returned. If M is constant (e.g. always asking for the first 10 elements with COUNT), you can consider it O(1). On the other side when XREADGROUP blocks, XADD will pay the O(N) time in order to serve the N clients blocked on the stream getting new data.", diff --git a/docs/reference/modules/modules-api-ref.md b/docs/reference/modules/modules-api-ref.md index cd95fa088b..f116749578 100644 --- a/docs/reference/modules/modules-api-ref.md +++ b/docs/reference/modules/modules-api-ref.md @@ -50,6 +50,7 @@ aliases: * [Module fork API](#section-module-fork-api) * [Server hooks implementation](#section-server-hooks-implementation) * [Module Configurations API](#section-module-configurations-api) +* [RDB load/save API](#section-rdb-load-save-api) * [Key eviction API](#section-key-eviction-api) * [Miscellaneous APIs](#section-miscellaneous-apis) * [Defrag API](#section-defrag-api) @@ -802,7 +803,7 @@ Return counter of micro-seconds relative to an arbitrary point in time. ### `RedisModule_Microseconds` - ustime_t RedisModule_Microseconds(); + ustime_t RedisModule_Microseconds(void); **Available since:** unreleased @@ -812,7 +813,7 @@ Return the current UNIX time in microseconds ### `RedisModule_CachedMicroseconds` - ustime_t RedisModule_CachedMicroseconds(); + ustime_t RedisModule_CachedMicroseconds(void); **Available since:** unreleased @@ -1413,6 +1414,30 @@ and not just: The function always returns `REDISMODULE_OK`. + + +### `RedisModule_ReplyWithErrorFormat` + + int RedisModule_ReplyWithErrorFormat(RedisModuleCtx *ctx, + const char *fmt, + ...); + +**Available since:** unreleased + +Reply with the error create from a printf format and arguments. + +If the error code is already passed in the string 'fmt', the error +code provided is used, otherwise the string "-ERR " for the generic +error code is automatically added. + +The usage is, for example: + + RedisModule_ReplyWithErrorFormat(ctx, "An error: %s", "foo"); + + RedisModule_ReplyWithErrorFormat(ctx, "-WRONGTYPE Wrong Type: %s", "foo"); + +The function always returns `REDISMODULE_OK`. + ### `RedisModule_ReplyWithSimpleString` @@ -2113,7 +2138,7 @@ Available flags and their meaning: ### `RedisModule_AvoidReplicaTraffic` - int RedisModule_AvoidReplicaTraffic(); + int RedisModule_AvoidReplicaTraffic(void); **Available since:** 6.0.0 @@ -2206,7 +2231,7 @@ Extra flags that can be pass to the API under the mode argument: ### `RedisModule_GetOpenKeyModesAll` - int RedisModule_GetOpenKeyModesAll(); + int RedisModule_GetOpenKeyModesAll(void); **Available since:** unreleased @@ -4950,7 +4975,7 @@ Moreover, the fact that the notification is executed synchronously means that the notification code will be executed in the middle on Redis logic (commands logic, eviction, expire). Changing the key space while the logic runs is dangerous and discouraged. In order to react to key space events with -write actions, please refer to `RedisModule_AddPostExecutionUnitJob`. +write actions, please refer to [`RedisModule_AddPostNotificationJob`](#RedisModule_AddPostNotificationJob). See [https://redis.io/topics/notifications](https://redis.io/topics/notifications) for more information. @@ -4984,7 +5009,7 @@ and so Redis will make no attempt to protect the module from infinite loops. ### `RedisModule_GetNotifyKeyspaceEvents` - int RedisModule_GetNotifyKeyspaceEvents(); + int RedisModule_GetNotifyKeyspaceEvents(void); **Available since:** 6.0.0 @@ -6295,7 +6320,7 @@ command should return an error. Here is an example: - int ... myCommandImplementation() { + int ... myCommandImplementation(void) { if (getExternalAPIs() == 0) { reply with an error here if we cannot have the APIs } @@ -6507,7 +6532,7 @@ it does not include the allocation size of the keys and values. ### `RedisModule_GetUsedMemoryRatio` - float RedisModule_GetUsedMemoryRatio(); + float RedisModule_GetUsedMemoryRatio(void); **Available since:** 6.0.0 @@ -6527,7 +6552,7 @@ currently used, relative to the Redis "maxmemory" configuration. ### `RedisModule_ScanCursorCreate` - RedisModuleScanCursor *RedisModule_ScanCursorCreate(); + RedisModuleScanCursor *RedisModule_ScanCursorCreate(void); **Available since:** 6.0.0 @@ -7255,6 +7280,81 @@ This will return `REDISMODULE_ERR` if it is called outside `RedisModule_OnLoad`. This API needs to be called when configurations are provided in either `MODULE LOADEX` or provided as startup arguments. + + +## RDB load/save API + + + +### `RedisModule_RdbStreamCreateFromFile` + + RedisModuleRdbStream *RedisModule_RdbStreamCreateFromFile(const char *filename); + +**Available since:** unreleased + +Create a stream object to save/load RDB to/from a file. + +This function returns a pointer to `RedisModuleRdbStream` which is owned +by the caller. It requires a call to [`RedisModule_RdbStreamFree()`](#RedisModule_RdbStreamFree) to free +the object. + + + +### `RedisModule_RdbStreamFree` + + void RedisModule_RdbStreamFree(RedisModuleRdbStream *stream); + +**Available since:** unreleased + +Release an RDB stream object. + + + +### `RedisModule_RdbLoad` + + int RedisModule_RdbLoad(RedisModuleCtx *ctx, + RedisModuleRdbStream *stream, + int flags); + +**Available since:** unreleased + +Load RDB file from the `stream`. Dataset will be cleared first and then RDB +file will be loaded. + +`flags` must be zero. This parameter is for future use. + +On success `REDISMODULE_OK` is returned, otherwise `REDISMODULE_ERR` is returned +and errno is set accordingly. + +Example: + + RedisModuleRdbStream *s = RedisModule_RdbStreamCreateFromFile("exp.rdb"); + RedisModule_RdbLoad(ctx, s, 0); + RedisModule_RdbStreamFree(s); + + + +### `RedisModule_RdbSave` + + int RedisModule_RdbSave(RedisModuleCtx *ctx, + RedisModuleRdbStream *stream, + int flags); + +**Available since:** unreleased + +Save dataset to the RDB stream. + +`flags` must be zero. This parameter is for future use. + +On success `REDISMODULE_OK` is returned, otherwise `REDISMODULE_ERR` is returned +and errno is set accordingly. + +Example: + + RedisModuleRdbStream *s = RedisModule_RdbStreamCreateFromFile("exp.rdb"); + RedisModule_RdbSave(ctx, s, 0); + RedisModule_RdbStreamFree(s); + ## Key eviction API @@ -7318,7 +7418,7 @@ returns `REDISMODULE_OK` if when key is valid. ### `RedisModule_GetModuleOptionsAll` - int RedisModule_GetModuleOptionsAll(); + int RedisModule_GetModuleOptionsAll(void); **Available since:** unreleased @@ -7339,7 +7439,7 @@ Example: ### `RedisModule_GetContextFlagsAll` - int RedisModule_GetContextFlagsAll(); + int RedisModule_GetContextFlagsAll(void); **Available since:** 6.0.9 @@ -7360,7 +7460,7 @@ Example: ### `RedisModule_GetKeyspaceNotificationFlagsAll` - int RedisModule_GetKeyspaceNotificationFlagsAll(); + int RedisModule_GetKeyspaceNotificationFlagsAll(void); **Available since:** 6.0.9 @@ -7381,7 +7481,7 @@ Example: ### `RedisModule_GetServerVersion` - int RedisModule_GetServerVersion(); + int RedisModule_GetServerVersion(void); **Available since:** 6.0.9 @@ -7393,7 +7493,7 @@ Example for 6.0.7 the return value will be 0x00060007. ### `RedisModule_GetTypeMethodVersion` - int RedisModule_GetTypeMethodVersion(); + int RedisModule_GetTypeMethodVersion(void); **Available since:** 6.2.0 @@ -7852,6 +7952,10 @@ There is no guarantee that this info is always available, so this may return -1. * [`RedisModule_PublishMessage`](#RedisModule_PublishMessage) * [`RedisModule_PublishMessageShard`](#RedisModule_PublishMessageShard) * [`RedisModule_RandomKey`](#RedisModule_RandomKey) +* [`RedisModule_RdbLoad`](#RedisModule_RdbLoad) +* [`RedisModule_RdbSave`](#RedisModule_RdbSave) +* [`RedisModule_RdbStreamCreateFromFile`](#RedisModule_RdbStreamCreateFromFile) +* [`RedisModule_RdbStreamFree`](#RedisModule_RdbStreamFree) * [`RedisModule_Realloc`](#RedisModule_Realloc) * [`RedisModule_RedactClientCommandArgument`](#RedisModule_RedactClientCommandArgument) * [`RedisModule_RegisterAuthCallback`](#RedisModule_RegisterAuthCallback) @@ -7879,6 +7983,7 @@ There is no guarantee that this info is always available, so this may return -1. * [`RedisModule_ReplyWithEmptyArray`](#RedisModule_ReplyWithEmptyArray) * [`RedisModule_ReplyWithEmptyString`](#RedisModule_ReplyWithEmptyString) * [`RedisModule_ReplyWithError`](#RedisModule_ReplyWithError) +* [`RedisModule_ReplyWithErrorFormat`](#RedisModule_ReplyWithErrorFormat) * [`RedisModule_ReplyWithLongDouble`](#RedisModule_ReplyWithLongDouble) * [`RedisModule_ReplyWithLongLong`](#RedisModule_ReplyWithLongLong) * [`RedisModule_ReplyWithMap`](#RedisModule_ReplyWithMap) From d1cde3472ea50fb22a0b7b9eb74691b4aefb8dcf Mon Sep 17 00:00:00 2001 From: Jeffrey Chen Date: Mon, 15 May 2023 06:48:27 -0700 Subject: [PATCH 203/377] Fix typos in cpu-profiling.md (#2409) --- docs/management/optimization/cpu-profiling.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/management/optimization/cpu-profiling.md b/docs/management/optimization/cpu-profiling.md index 01c19eee59..9f1383c95e 100644 --- a/docs/management/optimization/cpu-profiling.md +++ b/docs/management/optimization/cpu-profiling.md @@ -20,7 +20,7 @@ are pursuing a performance regression investigation you will need a concise methodical way of monitoring and analyzing Redis performance. To do so you can rely on different methodologies (some more suited than other -depending on the class of issues/analysis we intent to make). A curated list +depending on the class of issues/analysis we intend to make). A curated list of methodologies and their steps are enumerated by Brendan Greg at the [following link](http://www.brendangregg.com/methodology.html). @@ -71,13 +71,13 @@ and cache misses, etc. For that we will rely on toolkits (perf, bcc tools), and hardware specific PMCs (Performance Monitoring Counters), to proceed with: -- Hotspot analysis (pref or bcc tools): to profile code execution and determine which functions are consuming the most time and thus are targets for optimization. We'll present two options to collect, report, and visualize hotspots either with perf or bcc/BPF tracing tools. +- Hotspot analysis (perf or bcc tools): to profile code execution and determine which functions are consuming the most time and thus are targets for optimization. We'll present two options to collect, report, and visualize hotspots either with perf or bcc/BPF tracing tools. - Call counts analysis: to count events including function calls, enabling us to correlate several calls/components at once, relying on bcc/BPF tracing tools. - Hardware event sampling: crucial for understanding CPU behavior, including memory I/O, stall cycles, and cache misses. -### Tool prerequesits +### Tool prerequisites The following steps rely on Linux perf_events (aka ["perf"](https://man7.org/linux/man-pages/man1/perf.1.html)), [bcc/BPF tracing tools](https://github.com/iovisor/bcc), and Brendan Greg’s [FlameGraph repo](https://github.com/brendangregg/FlameGraph). From af0bb2a08c73b76e312bb410d45494047a0ea153 Mon Sep 17 00:00:00 2001 From: Bryan Ricker <978899+bricker@users.noreply.github.com> Date: Tue, 16 May 2023 17:04:53 -0700 Subject: [PATCH 204/377] Update set.md (#2413) --- commands/set.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/set.md b/commands/set.md index 6f1ceca75a..3d8f483166 100644 --- a/commands/set.md +++ b/commands/set.md @@ -11,7 +11,7 @@ The `SET` command supports a set of options that modify its behavior: * `EXAT` *timestamp-seconds* -- Set the specified Unix time at which the key will expire, in seconds. * `PXAT` *timestamp-milliseconds* -- Set the specified Unix time at which the key will expire, in milliseconds. * `NX` -- Only set the key if it does not already exist. -* `XX` -- Only set the key if it already exist. +* `XX` -- Only set the key if it already exists. * `KEEPTTL` -- Retain the time to live associated with the key. * `!GET` -- Return the old string stored at key, or nil if key did not exist. An error is returned and `SET` aborted if the value stored at key is not a string. From ec99cd76b473e8660149c86e624293efc8e241ee Mon Sep 17 00:00:00 2001 From: Igor Malinovskiy Date: Wed, 17 May 2023 14:20:43 +0200 Subject: [PATCH 205/377] Add set&get code example (#2414) --- commands/get.md | 4 ++++ commands/set.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/commands/get.md b/commands/get.md index 20a3feb4cb..2e1517afb7 100644 --- a/commands/get.md +++ b/commands/get.md @@ -14,3 +14,7 @@ GET nonexisting SET mykey "Hello" GET mykey ``` + +### Code examples + +{{< clients-example set_and_get />}} diff --git a/commands/set.md b/commands/set.md index 3d8f483166..2d8f626eed 100644 --- a/commands/set.md +++ b/commands/set.md @@ -38,6 +38,10 @@ GET mykey SET anotherkey "will expire in a minute" EX 60 ``` +### Code examples + +{{< clients-example set_and_get />}} + ## Patterns **Note:** The following pattern is discouraged in favor of [the Redlock algorithm](https://redis.io/topics/distlock) which is only a bit more complex to implement, but offers better guarantees and is fault tolerant. From 284dc0af0fe8b6a3518e4313fa5c7677aca9b648 Mon Sep 17 00:00:00 2001 From: Wen Hui Date: Thu, 18 May 2023 04:57:07 -0400 Subject: [PATCH 206/377] correcting return value when destination key already exists for copy command (#2415) As per the current design of copy commands it returns zero when destination already exist. this is also documented in the `Returns` section below this text. --- commands/copy.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/copy.md b/commands/copy.md index 2803d2a00c..62b04fc651 100644 --- a/commands/copy.md +++ b/commands/copy.md @@ -5,7 +5,7 @@ By default, the `destination` key is created in the logical database used by the connection. The `DB` option allows specifying an alternative logical database index for the destination key. -The command returns an error when the `destination` key already exists. The +The command returns zero when the `destination` key already exists. The `REPLACE` option removes the `destination` key before copying the value to it. @return @@ -21,4 +21,4 @@ The command returns an error when the `destination` key already exists. The SET dolly "sheep" COPY dolly clone GET clone -``` \ No newline at end of file +``` From daccc7bcf0ec79484842ff29605a964cd443d736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20S=C3=B6derqvist?= Date: Tue, 23 May 2023 16:13:53 +0200 Subject: [PATCH 207/377] Document endpoint values "" and "?" in CLUSTER SHARDS and SLOTS --- commands/cluster-shards.md | 7 ++++++- commands/cluster-slots.md | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/commands/cluster-shards.md b/commands/cluster-shards.md index 8d79b34239..02b83048dd 100644 --- a/commands/cluster-shards.md +++ b/commands/cluster-shards.md @@ -45,6 +45,11 @@ The endpoint, along with the port, defines the location that clients should use A NULL value for the endpoint indicates the node has an unknown endpoint and the client should connect to the same endpoint it used to send the `CLUSTER SHARDS` command but with the port returned from the command. This unknown endpoint configuration is useful when the Redis nodes are behind a load balancer that Redis doesn't know the endpoint of. Which endpoint is set is determined by the `cluster-preferred-endpoint-type` config. +The endpoint may also be the string `"?"` if the node is configured to use hostnames as the preferred endpoint type but no hostname is configured using `cluster-announce-hostname`. +This is considered a configuration error. +An empty string `""` is another abnormal value of the endpoint field, as well as for the ip field, which is returned if the node doesn't know its own IP address. +This can happen in a cluster that consists of only one node. +Clients may treat the empty string in the same way as NULL, that is the same endpoint it used to send the current command to, while `"?"` should be treated as an unknonwn node, not necessarily the same node as the one serving the current command. @return @@ -150,4 +155,4 @@ Which endpoint is set is determined by the `cluster-preferred-endpoint-type` con 12) (integer) 72156 13) "health" 14) "online" -``` \ No newline at end of file +``` diff --git a/commands/cluster-slots.md b/commands/cluster-slots.md index 68901fe81c..b26f34da17 100644 --- a/commands/cluster-slots.md +++ b/commands/cluster-slots.md @@ -12,6 +12,11 @@ The preferred endpoint, along with the port, defines the location that clients s A NULL value for the endpoint indicates the node has an unknown endpoint and the client should connect to the same endpoint it used to send the `CLUSTER SLOTS` command but with the port returned from the command. This unknown endpoint configuration is useful when the Redis nodes are behind a load balancer that Redis doesn't know the endpoint of. Which endpoint is set as preferred is determined by the `cluster-preferred-endpoint-type` config. +The endpoint may also be the string `"?"` if the node is configured to use hostnames as the preferred endpoint type but no hostname is configured using `cluster-announce-hostname`. +This is considered a configuration error. +An empty string `""` is another abnormal value of the endpoint field, as well as for the ip field, which is returned if the node doesn't know its own IP address. +This can happen in a cluster that consists of only one node. +Clients may treat the empty string in the same way as NULL, that is the same endpoint it used to send the current command to, while `"?"` should be treated as an unknonwn node, not necessarily the same node as the one serving the current command. Additional networking metadata is provided as a map on the fourth argument for each node. The following networking metadata may be returned: @@ -89,4 +94,4 @@ Similarly a client library should try if possible to cope with the fact that old ## Behavior change history -* `>= 7.0.0`: Added support for hostnames and unknown endpoints in first field of node response. \ No newline at end of file +* `>= 7.0.0`: Added support for hostnames and unknown endpoints in first field of node response. From 66581b81cee73b53b0fc3172fcf1c8930a6e2ce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20S=C3=B6derqvist?= Date: Tue, 23 May 2023 16:17:54 +0200 Subject: [PATCH 208/377] Spelling --- commands/cluster-shards.md | 2 +- commands/cluster-slots.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/cluster-shards.md b/commands/cluster-shards.md index 02b83048dd..6f969bb6c4 100644 --- a/commands/cluster-shards.md +++ b/commands/cluster-shards.md @@ -49,7 +49,7 @@ The endpoint may also be the string `"?"` if the node is configured to use hostn This is considered a configuration error. An empty string `""` is another abnormal value of the endpoint field, as well as for the ip field, which is returned if the node doesn't know its own IP address. This can happen in a cluster that consists of only one node. -Clients may treat the empty string in the same way as NULL, that is the same endpoint it used to send the current command to, while `"?"` should be treated as an unknonwn node, not necessarily the same node as the one serving the current command. +Clients may treat the empty string in the same way as NULL, that is the same endpoint it used to send the current command to, while `"?"` should be treated as an unknown node, not necessarily the same node as the one serving the current command. @return diff --git a/commands/cluster-slots.md b/commands/cluster-slots.md index b26f34da17..4126291082 100644 --- a/commands/cluster-slots.md +++ b/commands/cluster-slots.md @@ -16,7 +16,7 @@ The endpoint may also be the string `"?"` if the node is configured to use hostn This is considered a configuration error. An empty string `""` is another abnormal value of the endpoint field, as well as for the ip field, which is returned if the node doesn't know its own IP address. This can happen in a cluster that consists of only one node. -Clients may treat the empty string in the same way as NULL, that is the same endpoint it used to send the current command to, while `"?"` should be treated as an unknonwn node, not necessarily the same node as the one serving the current command. +Clients may treat the empty string in the same way as NULL, that is the same endpoint it used to send the current command to, while `"?"` should be treated as an unknown node, not necessarily the same node as the one serving the current command. Additional networking metadata is provided as a map on the fourth argument for each node. The following networking metadata may be returned: From 3b60fef4d4ea2ba4a10ab60348d2cf4d86da2d16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20S=C3=B6derqvist?= Date: Thu, 25 May 2023 16:31:48 +0200 Subject: [PATCH 209/377] Address review comments Co-authored-by: Madelyn Olson --- commands/cluster-shards.md | 5 ++--- commands/cluster-slots.md | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/commands/cluster-shards.md b/commands/cluster-shards.md index 6f969bb6c4..8d5c8fd4cc 100644 --- a/commands/cluster-shards.md +++ b/commands/cluster-shards.md @@ -45,10 +45,9 @@ The endpoint, along with the port, defines the location that clients should use A NULL value for the endpoint indicates the node has an unknown endpoint and the client should connect to the same endpoint it used to send the `CLUSTER SHARDS` command but with the port returned from the command. This unknown endpoint configuration is useful when the Redis nodes are behind a load balancer that Redis doesn't know the endpoint of. Which endpoint is set is determined by the `cluster-preferred-endpoint-type` config. -The endpoint may also be the string `"?"` if the node is configured to use hostnames as the preferred endpoint type but no hostname is configured using `cluster-announce-hostname`. -This is considered a configuration error. An empty string `""` is another abnormal value of the endpoint field, as well as for the ip field, which is returned if the node doesn't know its own IP address. -This can happen in a cluster that consists of only one node. +This can happen in a cluster that consists of only one node or the node has not yet been joined with the rest of the cluster. +The value `?` is displayed if the node is incorrectly configured to use announced hostnames but no hostname is configured using `cluster-announce-hostname`. Clients may treat the empty string in the same way as NULL, that is the same endpoint it used to send the current command to, while `"?"` should be treated as an unknown node, not necessarily the same node as the one serving the current command. @return diff --git a/commands/cluster-slots.md b/commands/cluster-slots.md index 4126291082..b3166bbf28 100644 --- a/commands/cluster-slots.md +++ b/commands/cluster-slots.md @@ -12,10 +12,9 @@ The preferred endpoint, along with the port, defines the location that clients s A NULL value for the endpoint indicates the node has an unknown endpoint and the client should connect to the same endpoint it used to send the `CLUSTER SLOTS` command but with the port returned from the command. This unknown endpoint configuration is useful when the Redis nodes are behind a load balancer that Redis doesn't know the endpoint of. Which endpoint is set as preferred is determined by the `cluster-preferred-endpoint-type` config. -The endpoint may also be the string `"?"` if the node is configured to use hostnames as the preferred endpoint type but no hostname is configured using `cluster-announce-hostname`. -This is considered a configuration error. An empty string `""` is another abnormal value of the endpoint field, as well as for the ip field, which is returned if the node doesn't know its own IP address. -This can happen in a cluster that consists of only one node. +This can happen in a cluster that consists of only one node or the node has not yet been joined with the rest of the cluster. +The value `?` is displayed if the node is incorrectly configured to use announced hostnames but no hostname is configured using `cluster-announce-hostname`. Clients may treat the empty string in the same way as NULL, that is the same endpoint it used to send the current command to, while `"?"` should be treated as an unknown node, not necessarily the same node as the one serving the current command. Additional networking metadata is provided as a map on the fourth argument for each node. From b47f36ea925c53a305c5c46f9ab9498220184aa4 Mon Sep 17 00:00:00 2001 From: Leibale Eidelman Date: Mon, 29 May 2023 09:18:41 -0400 Subject: [PATCH 210/377] Update nodejs.md (#2422) --- docs/clients/nodejs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/clients/nodejs.md b/docs/clients/nodejs.md index 8ede0bdf47..467ddb6169 100644 --- a/docs/clients/nodejs.md +++ b/docs/clients/nodejs.md @@ -151,7 +151,7 @@ try { await client.ft.create('idx:users', { '$.name': { type: SchemaFieldTypes.TEXT, - sortable: true + SORTABLE: true }, '$.city': { type: SchemaFieldTypes.TEXT, From 73fcd392ca6ab22d2aff1da1c339440dc118ae5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Ng=E1=BB=8Dc=20Minh?= <45934641+minhnndev@users.noreply.github.com> Date: Wed, 31 May 2023 04:56:37 +0700 Subject: [PATCH 211/377] Update get key cluster nodejs.md (#2424) --- docs/clients/nodejs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/clients/nodejs.md b/docs/clients/nodejs.md index 467ddb6169..8f2e2593de 100644 --- a/docs/clients/nodejs.md +++ b/docs/clients/nodejs.md @@ -97,7 +97,7 @@ cluster.on('error', (err) => console.log('Redis Cluster Error', err)); await cluster.connect(); await cluster.set('foo', 'bar'); -const value = await cluster.get('bar'); +const value = await cluster.get('foo'); console.log(value); // returns 'bar' await cluster.quit(); From 81423aea5a3035acfa7b379cc9de5847816b3eb1 Mon Sep 17 00:00:00 2001 From: Camden Moors <66680985+camdenmoors@users.noreply.github.com> Date: Mon, 5 Jun 2023 09:07:47 -0700 Subject: [PATCH 212/377] Add cURL & GPG to minimal linux install requirements (#2426) --- docs/getting-started/installation/install-redis-on-linux.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/getting-started/installation/install-redis-on-linux.md b/docs/getting-started/installation/install-redis-on-linux.md index ac2464f587..41b0041351 100644 --- a/docs/getting-started/installation/install-redis-on-linux.md +++ b/docs/getting-started/installation/install-redis-on-linux.md @@ -13,10 +13,10 @@ Most major Linux distributions provide packages for Redis. You can install recent stable versions of Redis from the official `packages.redis.io` APT repository. {{% alert title="Prerequisites" color="warning" %}} -If you're running a very minimal distribution (such as a Docker container) you may need to install `lsb-release` first: +If you're running a very minimal distribution (such as a Docker container) you may need to install `lsb-release`, `curl` and `gpg` first: {{< highlight bash >}} -sudo apt install lsb-release +sudo apt install lsb-release curl gpg {{< / highlight >}} {{% /alert %}} From af6e4f159f4ce0ef62c3c8a8c09d02f68fb9f691 Mon Sep 17 00:00:00 2001 From: Slava Koyfman Date: Tue, 6 Jun 2023 17:34:25 +0300 Subject: [PATCH 213/377] Clarify WAITAOF documentation (#2428) Description was worded in a way that might have made it unclear the command would only wait for write commands _by the same client_ that executed it. --- commands/waitaof.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/waitaof.md b/commands/waitaof.md index 4249eb51a5..58b4c7abab 100644 --- a/commands/waitaof.md +++ b/commands/waitaof.md @@ -1,4 +1,4 @@ -This command blocks the current client until all the previous write commands are acknowledged as having been fsynced to the AOF of the local Redis and/or at least the specified number of replicas. +This command blocks the current client until all previous write commands by that client are acknowledged as having been fsynced to the AOF of the local Redis and/or at least the specified number of replicas. If the timeout, specified in milliseconds, is reached, the command returns even if the specified number of acknowledgments has not been met. The command **will always return** the number of masters and replicas that have fsynced all write commands sent by the current client before the `WAITAOF` command, both in the case where the specified thresholds were met, and when the timeout is reached. From 7141bac654f18cbbb4acfefd4090cd5952e02d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=C6=B0=E1=BB=9Bc=20Trung?= <93299415+trungdlp-wolffun@users.noreply.github.com> Date: Tue, 6 Jun 2023 22:16:14 +0700 Subject: [PATCH 214/377] Update text leaderboard (#2425) --- docs/data-types/tutorial.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data-types/tutorial.md b/docs/data-types/tutorial.md index 8681607964..2514e8fcf7 100644 --- a/docs/data-types/tutorial.md +++ b/docs/data-types/tutorial.md @@ -843,7 +843,7 @@ and get the element's value discarding the prefix. If you want to see the feature in the context of a more serious demo, check the [Redis autocomplete demo](http://autocomplete.redis.io). -Updating the score: leader boards +Updating the score: leaderboards --- Just a final note about sorted sets before switching to the next topic. @@ -852,7 +852,7 @@ an element already included in the sorted set will update its score (and position) with O(log(N)) time complexity. As such, sorted sets are suitable when there are tons of updates. -Because of this characteristic a common use case is leader boards. +Because of this characteristic a common use case is leaderboards. The typical application is a Facebook game where you combine the ability to take users sorted by their high score, plus the get-rank operation, in order to show the top-N users, and the user rank in the leader board (e.g., "you are From a740b282df2a6656f8980c8cdfdce1d722915768 Mon Sep 17 00:00:00 2001 From: Binbin Date: Thu, 8 Jun 2023 21:05:45 +0800 Subject: [PATCH 215/377] Update Lua debugging help message commands for consistency (#2436) --- docs/manual/programmability/lua-debugging.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/manual/programmability/lua-debugging.md b/docs/manual/programmability/lua-debugging.md index 3c5c9df8b7..61719370a5 100644 --- a/docs/manual/programmability/lua-debugging.md +++ b/docs/manual/programmability/lua-debugging.md @@ -71,11 +71,11 @@ Redis Lua debugger help: [h]elp Show this help. [s]tep Run current line and stop again. [n]ext Alias for step. -[c]continue Run till next breakpoint. -[l]list List source code around current line. -[l]list [line] List source code around [line]. +[c]ontinue Run till next breakpoint. +[l]ist List source code around current line. +[l]ist [line] List source code around [line]. line = 0 means: current position. -[l]list [line] [ctx] In this form [ctx] specifies how many lines +[l]ist [line] [ctx] In this form [ctx] specifies how many lines to show before/after [line]. [w]hole List all source code. Alias for 'list 1 1000000'. [p]rint Show all the local variables. @@ -86,11 +86,11 @@ Redis Lua debugger help: [b]reak - Remove breakpoint from the specified line. [b]reak 0 Remove all breakpoints. [t]race Show a backtrace. -[e]eval Execute some Lua code (in a different callframe). +[e]val Execute some Lua code (in a different callframe). [r]edis Execute a Redis command. [m]axlen [len] Trim logged Redis replies and Lua var dumps to len. Specifying zero as means unlimited. -[a]abort Stop the execution of the script. In sync +[a]bort Stop the execution of the script. In sync mode dataset changes will be retained. Debugger functions you can call from Lua scripts: From 968fc38f5ae61b2a9bb73c41cad6a544532cbad3 Mon Sep 17 00:00:00 2001 From: Binbin Date: Sun, 11 Jun 2023 22:12:55 +0800 Subject: [PATCH 216/377] Cleanups in Lua Api doc (#2438) --- docs/manual/programmability/lua-api.md | 14 +++++++------- wordlist | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/manual/programmability/lua-api.md b/docs/manual/programmability/lua-api.md index e2ef46353f..4ff6006645 100644 --- a/docs/manual/programmability/lua-api.md +++ b/docs/manual/programmability/lua-api.md @@ -133,16 +133,16 @@ return redis.call('ECHO', 'Echo, echo... eco... o...') ``` If and when `redis.call()` triggers a runtime exception, the raw exception is raised back to the user as an error, automatically. -Therefore, attempting to execute the following ephemeral script will fail and generate a runtime exception because `ECHO` accepts exactly zero or one argument: +Therefore, attempting to execute the following ephemeral script will fail and generate a runtime exception because `ECHO` accepts exactly one argument: ```lua redis> EVAL "return redis.call('ECHO', 'Echo,', 'echo... ', 'eco... ', 'o...')" 0 -(error) ERR Error running script (call to b0345693f4b77517a711221050e76d24ae60b7f7): @user_script:1: @user_script: 1: Wrong number of args calling Redis command from script +(error) ERR Wrong number of args calling Redis command from script script: b0345693f4b77517a711221050e76d24ae60b7f7, on @user_script:1. ``` Note that the call can fail due to various reasons, see [Execution under low memory conditions](/topics/eval-intro#execution-under-low-memory-conditions) and [Script flags](#script_flags) -To handle Redis runtime errors use `redis.pcall() instead. +To handle Redis runtime errors use `redis.pcall()` instead. ### `redis.pcall(command [,arg...])` @@ -331,7 +331,7 @@ It then picks five random elements (`SRANDMEMBER`) from the intersection and sto Finally, before returning, it deletes the temporary key that stores the intersection of the two source sets. In this case, only the new set with its five randomly-chosen elements needs to be replicated. -Replicating the `SUNIONSTORE` command and the `DEL'ition of the temporary key is unnecessary and wasteful. +Replicating the `SUNIONSTORE` command and the `DEL`ition of the temporary key is unnecessary and wasteful. The `redis.set_repl()` function instructs the server how to treat subsequent write commands in terms of replication. It accepts a single input argument that only be one of the following: @@ -379,7 +379,7 @@ For more information, please refer to [`Replicating commands instead of scripts` * Available in scripts: yes * Available in functions: no -This function triggers a breakpoint when using the Redis Lua debugger](/topics/ldb). +This function triggers a breakpoint when using the [Redis Lua debugger](/topics/ldb). ### `redis.debug(x)` @@ -538,7 +538,7 @@ that reply is automatically converted to Redis' protocol. Put differently; there's a one-to-one mapping between Redis' replies and Lua's data types and a one-to-one mapping between Lua's data types and the [Redis Protocol](/topics/protocol) data types. The underlying design is such that if a Redis type is converted into a Lua type and converted back into a Redis type, the result is the same as the initial value. -Type conversion from Redis protocol replies (i.e., the replies from `redis.call()` and `redis.pcall()` to Lua data types depends on the Redis Serialization Protocol version used by the script. +Type conversion from Redis protocol replies (i.e., the replies from `redis.call()` and `redis.pcall()`) to Lua data types depends on the Redis Serialization Protocol version used by the script. The default protocol version during script executions is RESP2. The script may switch the replies' protocol versions by calling the `redis.setresp()` function. @@ -648,7 +648,7 @@ Although the default protocol for incoming client connections is RESP2, the scri * Lua nil -> [RESP3 null](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md#null-reply). However, if the connection is set use the RESP2 protocol, and even if the script replies with RESP3-typed responses, Redis will automatically perform a RESP3 to RESP2 conversion of the reply as is the case for regular commands. -That means, for example, that returning the RESP3 map type to a RESP2 connection will result in the repy being converted to a flat RESP2 array that consists of alternating field names and their values, rather than a RESP3 map. +That means, for example, that returning the RESP3 map type to a RESP2 connection will result in the reply being converted to a flat RESP2 array that consists of alternating field names and their values, rather than a RESP3 map. ## Additional notes about scripting diff --git a/wordlist b/wordlist index 388ccf2d2c..6751de130a 100644 --- a/wordlist +++ b/wordlist @@ -104,7 +104,6 @@ Costin Craigslist Ctrl-a DBs -DEL'ition DLM DMA dnf @@ -1015,3 +1014,4 @@ fsynced fsyncs WAITAOF Redises +ition From 79647e8bc23a623404fe57169ac307b3387d670d Mon Sep 17 00:00:00 2001 From: Chen Tianjie Date: Tue, 13 Jun 2023 20:43:03 +0800 Subject: [PATCH 217/377] Update info command with new eventloop metrics. (#2439) * Update info command with new eventloop metrics. * Update word list. * Add illustration to eventloop_duration_sum. Co-authored-by: Oran Agra * Warn Co-authored-by: Oran Agra * Edits --------- Co-authored-by: Oran Agra Co-authored-by: Itamar Haber --- commands/info.md | 17 ++++++++++++++++- wordlist | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/commands/info.md b/commands/info.md index 9f7b7226db..0668c769cc 100644 --- a/commands/info.md +++ b/commands/info.md @@ -265,7 +265,7 @@ Here is the meaning of all fields in the **stats** section: * `expired_keys`: Total number of key expiration events * `expired_stale_perc`: The percentage of keys probably expired * `expired_time_cap_reached_count`: The count of times that active expiry cycles have stopped early -* `expire_cycle_cpu_milliseconds`: The cumulative amount of time spend on active expiry cycles +* `expire_cycle_cpu_milliseconds`: The cumulative amount of time spent on active expiry cycles * `evicted_keys`: Number of evicted keys due to `maxmemory` limit * `evicted_clients`: Number of evicted clients due to `maxmemory-clients` limit. Added in Redis 7.0. * `total_eviction_exceeded_time`: Total time `used_memory` was greater than `maxmemory` since server startup, in milliseconds @@ -306,6 +306,13 @@ Here is the meaning of all fields in the **stats** section: * `total_writes_processed`: Total number of write events processed * `io_threaded_reads_processed`: Number of read events processed by the main and I/O threads * `io_threaded_writes_processed`: Number of write events processed by the main and I/O threads +* `stat_reply_buffer_shrinks`: Total number of output buffer shrinks +* `stat_reply_buffer_expands`: Total number of output buffer expands +* `eventloop_cycles`: Total number of eventloop cycles +* `eventloop_duration_sum`: Total time spent in the eventloop in microseconds (including I/O and command processing) +* `eventloop_duration_cmd_sum`: Total time spent on executing commands in microseconds +* `instantaneous_eventloop_cycles_per_sec`: Number of eventloop cycles per second +* `instantaneous_eventloop_duration_usec`: Average time spent in a single eventloop cycle in microseconds * `acl_access_denied_auth`: Number of authentication failures * `acl_access_denied_cmd`: Number of commands rejected because of access denied to the command * `acl_access_denied_key`: Number of commands rejected because of access denied to a key @@ -433,6 +440,14 @@ For each database, the following line is added: * `dbXXX`: `keys=XXX,expires=XXX` +The **debug** section contains experimental metrics, which might change or get removed in future versions. +It won't be included when `INFO` or `INFO ALL` are called, and it is returned only when `INFO DEBUG` is used. + +* `eventloop_duration_aof_sum`: Total time spent on flushing AOF in eventloop in microseconds +* `eventloop_duration_cron_sum`: Total time consumption of cron in microseconds (including serverCron and beforeSleep, but excluding IO and AOF flushing) +* `eventloop_duration_max`: The maximal time spent in a single eventloop cycle in microseconds +* `eventloop_cmd_per_cycle_max`: The maximal number of commands processed in a single eventloop cycle + [hcgcpgp]: http://code.google.com/p/google-perftools/ **A note about the word slave used in this man page**: Starting with Redis 5, if not for backward compatibility, the Redis project no longer uses the word slave. Unfortunately in this command the word slave is part of the protocol, so we'll be able to remove such occurrences only when this API will be naturally deprecated. diff --git a/wordlist b/wordlist index 6751de130a..f9869c3ccb 100644 --- a/wordlist +++ b/wordlist @@ -480,6 +480,7 @@ bazzar bc bcc bcc's +beforeSleep behaviour benchmarked benchmarking @@ -582,6 +583,7 @@ errorstats ethernet eval eval-intro +eventloop everysec executables expiries From 5becda1cc8a9980f0a7c585abdf3f47521ea57b5 Mon Sep 17 00:00:00 2001 From: Leibale Eidelman Date: Tue, 27 Jun 2023 06:32:04 -0400 Subject: [PATCH 218/377] Replace `@reply` with `@return` (#2448) --- commands/slowlog-get.md | 2 +- commands/slowlog-len.md | 2 +- commands/slowlog-reset.md | 2 +- commands/xinfo-consumers.md | 2 +- commands/xinfo-groups.md | 10 +++++----- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/commands/slowlog-get.md b/commands/slowlog-get.md index a99910ad87..3773cfbcd3 100644 --- a/commands/slowlog-get.md +++ b/commands/slowlog-get.md @@ -21,6 +21,6 @@ The entry's unique ID can be used in order to avoid processing slow log entries The ID is never reset in the course of the Redis server execution, only a server restart will reset it. -@reply +@return @array-reply: a list of slow log entries. diff --git a/commands/slowlog-len.md b/commands/slowlog-len.md index 6f0d97758a..6cc062f2a1 100644 --- a/commands/slowlog-len.md +++ b/commands/slowlog-len.md @@ -5,7 +5,7 @@ The maximum number of entries in the slow log is governed by the `slowlog-max-le Once the slog log reaches its maximal size, the oldest entry is removed whenever a new entry is created. The slow log can be cleared with the `SLOWLOG RESET` command. -@reply +@return @integer-reply diff --git a/commands/slowlog-reset.md b/commands/slowlog-reset.md index b522c26a5c..2b6d436aaf 100644 --- a/commands/slowlog-reset.md +++ b/commands/slowlog-reset.md @@ -2,6 +2,6 @@ This command resets the slow log, clearing all entries in it. Once deleted the information is lost forever. -@reply +@return @simple-string-reply: `OK` diff --git a/commands/xinfo-consumers.md b/commands/xinfo-consumers.md index 965292e131..d4bb878b8e 100644 --- a/commands/xinfo-consumers.md +++ b/commands/xinfo-consumers.md @@ -7,7 +7,7 @@ The following information is provided for each consumer in the group: * **idle**: the number of milliseconds that have passed since the consumer's last attempted interaction (Examples: `XREADGROUP`, `XCLAIM`, `XAUTOCLAIM`) * **inactive**: the number of milliseconds that have passed since the consumer's last successful interaction (Examples: `XREADGROUP` that actually read some entries into the PEL, `XCLAIM`/`XAUTOCLAIM` that actually claimed some entries) -@reply +@return @array-reply: a list of consumers. diff --git a/commands/xinfo-groups.md b/commands/xinfo-groups.md index 03eafecfa2..08af1c9ae1 100644 --- a/commands/xinfo-groups.md +++ b/commands/xinfo-groups.md @@ -1,12 +1,12 @@ -This command returns the list of all consumers groups of the stream stored at ``. +This command returns the list of all consumer groups of the stream stored at ``. By default, only the following information is provided for each of the groups: * **name**: the consumer group's name * **consumers**: the number of consumers in the group * **pending**: the length of the group's pending entries list (PEL), which are messages that were delivered but are yet to be acknowledged -* **last-delivered-id**: the ID of the last entry delivered the group's consumers -* **entries-read**: the logical "read counter" of the last entry delivered to group's consumers +* **last-delivered-id**: the ID of the last entry delivered to the group's consumers +* **entries-read**: the logical "read counter" of the last entry delivered to the group's consumers * **lag**: the number of entries in the stream that are still waiting to be delivered to the group's consumers, or a NULL when that number can't be determined. ### Consumer group lag @@ -22,7 +22,7 @@ The lag is the difference between these two. The stream's counter (the `entries_added` field of the `XINFO STREAM` command) is incremented by one with every `XADD` and counts all of the entries added to the stream during its lifetime. -The consumer group's counter, `entries_read`, is the logical counter of entries that the group had read. +The consumer group's counter, `entries_read`, is the logical counter of entries the group had read. It is important to note that this counter is only a heuristic rather than an accurate counter, and therefore the use of the term "logical". The counter attempts to reflect the number of entries that the group **should have read** to get to its current `last-delivered-id`. The `entries_read` counter is accurate only in a perfect world, where a consumer group starts at the stream's first entry and processes all of its entries (i.e., no entries deleted before processing). @@ -39,7 +39,7 @@ However, the lag is only temporarily unavailable. It is restored automatically during regular operation as consumers keep processing messages. Once the consumer group delivers the last message in the stream to its members, it will be set with the correct logical read counter, and tracking its lag can be resumed. -@reply +@return @array-reply: a list of consumer groups. From 9a1f95933202e9e4a856f829d1fcc056ed4762a3 Mon Sep 17 00:00:00 2001 From: Binbin Date: Tue, 27 Jun 2023 19:50:04 +0800 Subject: [PATCH 219/377] Add new total_blocking_keys and total_blocking_keys_on_nokey fields in INFO (#2449) --- commands/info.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/commands/info.md b/commands/info.md index 0668c769cc..d1ebe5481a 100644 --- a/commands/info.md +++ b/commands/info.md @@ -92,6 +92,8 @@ Here is the meaning of all fields in the **clients** section: `BRPOP`, `BRPOPLPUSH`, `BLMOVE`, `BZPOPMIN`, `BZPOPMAX`) * `tracking_clients`: Number of clients being tracked (`CLIENT TRACKING`) * `clients_in_timeout_table`: Number of clients in the clients timeout table +* `total_blocking_keys`: Number of blocking keys. Added in Redis 7.2. +* `total_blocking_keys_on_nokey`: Number of blocking keys that one or more clients that would like to be unblocked when the key is deleted. Added in Redis 7.2. Here is the meaning of all fields in the **memory** section: From 957185ef6fd8b4f4c18447a81b363186258bc322 Mon Sep 17 00:00:00 2001 From: Binbin Date: Wed, 28 Jun 2023 20:31:37 +0800 Subject: [PATCH 220/377] Update MEMORY USAGE examples to latest version (#2450) --- commands/memory-usage.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/commands/memory-usage.md b/commands/memory-usage.md index 4d68dcd6fe..68b23aec1b 100644 --- a/commands/memory-usage.md +++ b/commands/memory-usage.md @@ -10,29 +10,32 @@ By default, this option is set to `5`. To sample the all of the nested values, u @examples -With Redis v4.0.1 64-bit and **jemalloc**, the empty string measures as follows: +With Redis v7.2.0 64-bit and **jemalloc**, the empty string measures as follows: ``` > SET "" "" OK > MEMORY USAGE "" -(integer) 51 +(integer) 56 ``` These bytes are pure overhead at the moment as no actual data is stored, and are -used for maintaining the internal data structures of the server. Longer keys and +used for maintaining the internal data structures of the server (include internal allocator fragmentation). Longer keys and values show asymptotically linear usage. ``` > SET foo bar OK > MEMORY USAGE foo -(integer) 54 -> SET cento 01234567890123456789012345678901234567890123 -45678901234567890123456789012345678901234567890123456789 +(integer) 56 +> SET foo2 mybar OK -127.0.0.1:6379> MEMORY USAGE cento -(integer) 153 +> MEMORY USAGE foo2 +(integer) 64 +> SET foo3 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +OK +> MEMORY USAGE foo3 +(integer) 160 ``` @return From 347af66b1fe9ba938e6e3d4fa6ad64137a40dd39 Mon Sep 17 00:00:00 2001 From: Simon Prickett Date: Mon, 3 Jul 2023 12:37:53 +0100 Subject: [PATCH 221/377] Fixed typo in bitmaps page (#2452) Fixed erroneous reference to "server" that should be "sensor". --- docs/data-types/bitmaps.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data-types/bitmaps.md b/docs/data-types/bitmaps.md index d1d4440644..b05f63aeb1 100644 --- a/docs/data-types/bitmaps.md +++ b/docs/data-types/bitmaps.md @@ -32,7 +32,7 @@ You can represent this scenario using a bitmap whose key references the current 1 ``` -* What about server 456? +* What about sensor 456? ``` > GETBIT pings:2024-01-01-00:00 456 0 @@ -54,4 +54,4 @@ See the [complete list of bitmap commands](https://redis.io/commands/?group=bitm ## Learn more * [Redis Bitmaps Explained](https://www.youtube.com/watch?v=oj8LdJQjhJo) teaches you how to use bitmaps for map exploration in an online game. -* [Redis University's RU101](https://university.redis.com/courses/ru101/) covers Redis bitmaps in detail. \ No newline at end of file +* [Redis University's RU101](https://university.redis.com/courses/ru101/) covers Redis bitmaps in detail. From 0faf31080f1ecec3298b9b74258d840169fdaace Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Tue, 4 Jul 2023 16:33:05 +0300 Subject: [PATCH 222/377] Edit Pub/Sub example (#2456) --- docs/manual/pubsub.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/manual/pubsub.md b/docs/manual/pubsub.md index ada1dae322..e746095ada 100644 --- a/docs/manual/pubsub.md +++ b/docs/manual/pubsub.md @@ -13,10 +13,10 @@ Rather, published messages are characterized into channels, without knowledge of Subscribers express interest in one or more channels and only receive messages that are of interest, without knowledge of what (if any) publishers there are. This decoupling of publishers and subscribers allows for greater scalability and a more dynamic network topology. -For instance, to subscribe to channels "channel11" and "4chan" the client issues a `SUBSCRIBE` providing the names of the channels: +For instance, to subscribe to channels "channel11" and "ch:00" the client issues a `SUBSCRIBE` providing the names of the channels: ```bash -SUBSCRIBE channel11 4chan +SUBSCRIBE channel11 ch:00 ``` Messages sent by other clients to these channels will be pushed by Redis to all the subscribed clients. From 882c184514f88f048df3d773e300a39882773e9d Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Wed, 5 Jul 2023 13:25:21 +0100 Subject: [PATCH 223/377] Docs reorg (#2419) --- .gitignore | 1 + commands/scan.md | 182 +--- docs/about/_index.md | 2 + docs/about/license.md | 79 +- docs/clients/_index.md | 13 + docs/data-types/_index.md | 4 +- docs/data-types/bitfields.md | 11 +- docs/data-types/bitmaps.md | 89 +- docs/data-types/geospatial.md | 15 +- docs/data-types/hashes.md | 105 +- docs/data-types/hyperloglogs.md | 51 - docs/data-types/lists.md | 306 +++++- docs/data-types/probabilistic/hyperloglogs.md | 110 ++ docs/data-types/sets.md | 152 ++- docs/data-types/sorted-sets.md | 210 +++- docs/data-types/streams-tutorial.md | 794 -------------- docs/data-types/streams.md | 804 +++++++++++++- docs/data-types/strings.md | 108 +- docs/data-types/tutorial.md | 997 ------------------ docs/getting-started/_index.md | 26 +- docs/getting-started/installation/_index.md | 2 +- docs/interact-with-data/_index.md | 9 + .../programmability/_index.md | 3 +- .../programmability/eval-intro.md | 1 + .../programmability/functions-intro.md | 1 + .../programmability/lua-api.md | 1 + .../programmability/lua-debugging.md | 1 + docs/{manual => interact-with-data}/pubsub.md | 2 +- .../transactions.md | 3 +- docs/management/_index.md | 4 +- docs/management/admin.md | 4 +- docs/management/replication.md | 12 +- docs/manual/_index.md | 4 +- docs/manual/client-side-caching.md | 2 +- docs/manual/keyspace-notifications.md | 2 +- docs/manual/keyspace.md | 324 ++++++ wordlist | 15 + 37 files changed, 2262 insertions(+), 2187 deletions(-) delete mode 100644 docs/data-types/hyperloglogs.md create mode 100644 docs/data-types/probabilistic/hyperloglogs.md delete mode 100644 docs/data-types/streams-tutorial.md delete mode 100644 docs/data-types/tutorial.md create mode 100644 docs/interact-with-data/_index.md rename docs/{manual => interact-with-data}/programmability/_index.md (99%) rename docs/{manual => interact-with-data}/programmability/eval-intro.md (99%) rename docs/{manual => interact-with-data}/programmability/functions-intro.md (99%) rename docs/{manual => interact-with-data}/programmability/lua-api.md (99%) rename docs/{manual => interact-with-data}/programmability/lua-debugging.md (99%) rename docs/{manual => interact-with-data}/pubsub.md (99%) rename docs/{manual => interact-with-data}/transactions.md (99%) create mode 100644 docs/manual/keyspace.md diff --git a/.gitignore b/.gitignore index 17952c7fd0..4610ac14e8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea tmp +.DS_Store diff --git a/commands/scan.md b/commands/scan.md index dcc94de9cb..84ec7634c1 100644 --- a/commands/scan.md +++ b/commands/scan.md @@ -11,188 +11,8 @@ However while blocking commands like `SMEMBERS` are able to provide all the elem Note that `SCAN`, `SSCAN`, `HSCAN` and `ZSCAN` all work very similarly, so this documentation covers all the four commands. However an obvious difference is that in the case of `SSCAN`, `HSCAN` and `ZSCAN` the first argument is the name of the key holding the Set, Hash or Sorted Set value. The `SCAN` command does not need any key name argument as it iterates keys in the current database, so the iterated object is the database itself. -## SCAN basic usage -SCAN is a cursor based iterator. This means that at every call of the command, the server returns an updated cursor that the user needs to use as the cursor argument in the next call. - -An iteration starts when the cursor is set to 0, and terminates when the cursor returned by the server is 0. The following is an example of SCAN iteration: - -``` -redis 127.0.0.1:6379> scan 0 -1) "17" -2) 1) "key:12" - 2) "key:8" - 3) "key:4" - 4) "key:14" - 5) "key:16" - 6) "key:17" - 7) "key:15" - 8) "key:10" - 9) "key:3" - 10) "key:7" - 11) "key:1" -redis 127.0.0.1:6379> scan 17 -1) "0" -2) 1) "key:5" - 2) "key:18" - 3) "key:0" - 4) "key:2" - 5) "key:19" - 6) "key:13" - 7) "key:6" - 8) "key:9" - 9) "key:11" -``` - -In the example above, the first call uses zero as a cursor, to start the iteration. The second call uses the cursor returned by the previous call as the first element of the reply, that is, 17. - -As you can see the **SCAN return value** is an array of two values: the first value is the new cursor to use in the next call, the second value is an array of elements. - -Since in the second call the returned cursor is 0, the server signaled to the caller that the iteration finished, and the collection was completely explored. Starting an iteration with a cursor value of 0, and calling `SCAN` until the returned cursor is 0 again is called a **full iteration**. - -## Scan guarantees - -The `SCAN` command, and the other commands in the `SCAN` family, are able to provide to the user a set of guarantees associated to full iterations. - -* A full iteration always retrieves all the elements that were present in the collection from the start to the end of a full iteration. This means that if a given element is inside the collection when an iteration is started, and is still there when an iteration terminates, then at some point `SCAN` returned it to the user. -* A full iteration never returns any element that was NOT present in the collection from the start to the end of a full iteration. So if an element was removed before the start of an iteration, and is never added back to the collection for all the time an iteration lasts, `SCAN` ensures that this element will never be returned. - -However because `SCAN` has very little state associated (just the cursor) it has the following drawbacks: - -* A given element may be returned multiple times. It is up to the application to handle the case of duplicated elements, for example only using the returned elements in order to perform operations that are safe when re-applied multiple times. -* Elements that were not constantly present in the collection during a full iteration, may be returned or not: it is undefined. - -## Number of elements returned at every SCAN call - -`SCAN` family functions do not guarantee that the number of elements returned per call are in a given range. The commands are also allowed to return zero elements, and the client should not consider the iteration complete as long as the returned cursor is not zero. - -However the number of returned elements is reasonable, that is, in practical terms SCAN may return a maximum number of elements in the order of a few tens of elements when iterating a large collection, or may return all the elements of the collection in a single call when the iterated collection is small enough to be internally represented as an encoded data structure (this happens for small sets, hashes and sorted sets). - -However there is a way for the user to tune the order of magnitude of the number of returned elements per call using the **COUNT** option. - -## The COUNT option - -While `SCAN` does not provide guarantees about the number of elements returned at every iteration, it is possible to empirically adjust the behavior of `SCAN` using the **COUNT** option. Basically with COUNT the user specified the *amount of work that should be done at every call in order to retrieve elements from the collection*. This is **just a hint** for the implementation, however generally speaking this is what you could expect most of the times from the implementation. - -* The default COUNT value is 10. -* When iterating the key space, or a Set, Hash or Sorted Set that is big enough to be represented by a hash table, assuming no **MATCH** option is used, the server will usually return *count* or a bit more than *count* elements per call. Please check the *why SCAN may return all the elements at once* section later in this document. -* When iterating Sets encoded as intsets (small sets composed of just integers), or Hashes and Sorted Sets encoded as ziplists (small hashes and sets composed of small individual values), usually all the elements are returned in the first `SCAN` call regardless of the COUNT value. - -Important: **there is no need to use the same COUNT value** for every iteration. The caller is free to change the count from one iteration to the other as required, as long as the cursor passed in the next call is the one obtained in the previous call to the command. - -## The MATCH option - -It is possible to only iterate elements matching a given glob-style pattern, similarly to the behavior of the `KEYS` command that takes a pattern as its only argument. - -To do so, just append the `MATCH ` arguments at the end of the `SCAN` command (it works with all the SCAN family commands). - -This is an example of iteration using **MATCH**: - -``` -redis 127.0.0.1:6379> sadd myset 1 2 3 foo foobar feelsgood -(integer) 6 -redis 127.0.0.1:6379> sscan myset 0 match f* -1) "0" -2) 1) "foo" - 2) "feelsgood" - 3) "foobar" -redis 127.0.0.1:6379> -``` - -It is important to note that the **MATCH** filter is applied after elements are retrieved from the collection, just before returning data to the client. This means that if the pattern matches very little elements inside the collection, `SCAN` will likely return no elements in most iterations. An example is shown below: - -``` -redis 127.0.0.1:6379> scan 0 MATCH *11* -1) "288" -2) 1) "key:911" -redis 127.0.0.1:6379> scan 288 MATCH *11* -1) "224" -2) (empty list or set) -redis 127.0.0.1:6379> scan 224 MATCH *11* -1) "80" -2) (empty list or set) -redis 127.0.0.1:6379> scan 80 MATCH *11* -1) "176" -2) (empty list or set) -redis 127.0.0.1:6379> scan 176 MATCH *11* COUNT 1000 -1) "0" -2) 1) "key:611" - 2) "key:711" - 3) "key:118" - 4) "key:117" - 5) "key:311" - 6) "key:112" - 7) "key:111" - 8) "key:110" - 9) "key:113" - 10) "key:211" - 11) "key:411" - 12) "key:115" - 13) "key:116" - 14) "key:114" - 15) "key:119" - 16) "key:811" - 17) "key:511" - 18) "key:11" -redis 127.0.0.1:6379> -``` - -As you can see most of the calls returned zero elements, but the last call where a COUNT of 1000 was used in order to force the command to do more scanning for that iteration. - - -## The TYPE option - -You can use the `!TYPE` option to ask `SCAN` to only return objects that match a given `type`, allowing you to iterate through the database looking for keys of a specific type. The **TYPE** option is only available on the whole-database `SCAN`, not `HSCAN` or `ZSCAN` etc. - -The `type` argument is the same string name that the `TYPE` command returns. Note a quirk where some Redis types, such as GeoHashes, HyperLogLogs, Bitmaps, and Bitfields, may internally be implemented using other Redis types, such as a string or zset, so can't be distinguished from other keys of that same type by `SCAN`. For example, a ZSET and GEOHASH: - -``` -redis 127.0.0.1:6379> GEOADD geokey 0 0 value -(integer) 1 -redis 127.0.0.1:6379> ZADD zkey 1000 value -(integer) 1 -redis 127.0.0.1:6379> TYPE geokey -zset -redis 127.0.0.1:6379> TYPE zkey -zset -redis 127.0.0.1:6379> SCAN 0 TYPE zset -1) "0" -2) 1) "geokey" - 2) "zkey" -``` - -It is important to note that the **TYPE** filter is also applied after elements are retrieved from the database, so the option does not reduce the amount of work the server has to do to complete a full iteration, and for rare types you may receive no elements in many iterations. - -## Multiple parallel iterations - -It is possible for an infinite number of clients to iterate the same collection at the same time, as the full state of the iterator is in the cursor, that is obtained and returned to the client at every call. No server side state is taken at all. - -## Terminating iterations in the middle - -Since there is no state server side, but the full state is captured by the cursor, the caller is free to terminate an iteration half-way without signaling this to the server in any way. An infinite number of iterations can be started and never terminated without any issue. - -## Calling SCAN with a corrupted cursor - -Calling `SCAN` with a broken, negative, out of range, or otherwise invalid cursor, will result in undefined behavior but never in a crash. What will be undefined is that the guarantees about the returned elements can no longer be ensured by the `SCAN` implementation. - -The only valid cursors to use are: - -* The cursor value of 0 when starting an iteration. -* The cursor returned by the previous call to SCAN in order to continue the iteration. - -## Guarantee of termination - -The `SCAN` algorithm is guaranteed to terminate only if the size of the iterated collection remains bounded to a given maximum size, otherwise iterating a collection that always grows may result into `SCAN` to never terminate a full iteration. - -This is easy to see intuitively: if the collection grows there is more and more work to do in order to visit all the possible elements, and the ability to terminate the iteration depends on the number of calls to `SCAN` and its COUNT option value compared with the rate at which the collection grows. - -## Why SCAN may return all the items of an aggregate data type in a single call? - -In the `COUNT` option documentation, we state that sometimes this family of commands may return all the elements of a Set, Hash or Sorted Set at once in a single call, regardless of the `COUNT` option value. The reason why this happens is that the cursor-based iterator can be implemented, and is useful, only when the aggregate data type that we are scanning is represented as a hash table. However Redis uses a [memory optimization](/topics/memory-optimization) where small aggregate data types, until they reach a given amount of items or a given max size of single elements, are represented using a compact single-allocation packed encoding. When this is the case, `SCAN` has no meaningful cursor to return, and must iterate the whole data structure at once, so the only sane behavior it has is to return everything in a call. - -However once the data structures are bigger and are promoted to use real hash tables, the `SCAN` family of commands will resort to the normal behavior. Note that since this special behavior of returning all the elements is true only for small aggregates, it has no effects on the command complexity or latency. However the exact limits to get converted into real hash tables are [user configurable](/topics/memory-optimization), so the maximum number of elements you can see returned in a single call depends on how big an aggregate data type could be and still use the packed representation. - -Also note that this behavior is specific of `SSCAN`, `HSCAN` and `ZSCAN`. `SCAN` itself never shows this behavior because the key space is always represented by hash tables. +For more information on `SCAN` please refer to the [The Redis Keyspace](/docs/manual/the-redis-keyspace.md) tutorial. ## Return value diff --git a/docs/about/_index.md b/docs/about/_index.md index ce2fb7769a..4b80f25497 100644 --- a/docs/about/_index.md +++ b/docs/about/_index.md @@ -39,3 +39,5 @@ You can use Redis from [most programming languages](/clients). Redis is written in **ANSI C** and works on most POSIX systems like Linux, \*BSD, and Mac OS X, without external dependencies. Linux and OS X are the two operating systems where Redis is developed and tested the most, and we **recommend using Linux for deployment**. Redis may work in Solaris-derived systems like SmartOS, but support is *best effort*. There is no official support for Windows builds. + +
\ No newline at end of file diff --git a/docs/about/license.md b/docs/about/license.md index 5bcada4c4f..ba95aad298 100644 --- a/docs/about/license.md +++ b/docs/about/license.md @@ -6,14 +6,23 @@ description: > Redis license and trademark information aliases: - /topics/license + - /docs/stack/license/ --- -Redis is **open source software** released under the terms of the **three clause BSD license**. Most of the Redis source code was written and is copyrighted by Salvatore Sanfilippo and Pieter Noordhuis. A list of other contributors can be found in the git history. -The Redis trademark and logo are owned by Redis Ltd. and can be +* Redis is **open source software** released under the terms of the **three clause BSD license**. Most of the Redis source code was written and is copyrighted by Salvatore Sanfilippo and Pieter Noordhuis. A list of other contributors can be found in the git history. + + The Redis trademark and logo are owned by Redis Ltd. and can be used in accordance with the [Redis Trademark Guidelines](https://redis.com/legal/trademark-guidelines/). -## Three clause BSD license +* RedisInsight is licensed under the Server Side Public License (SSPL). + +* Redis Stack Server, which combines open source Redis with Search and Query features, JSON, Time Series, and Probabilistic data structures is dual-licensed under the Redis Source Available License (RSALv2), as described below, and the [Server Side Public License](https://en.wikipedia.org/wiki/Server_Side_Public_License) (SSPL). For information about licensing per version, see [Versions and licenses](/docs/stack/#versions-and-licenses). + + +## Licences: + +### Three clause BSD license Every file in the Redis distribution, with the exceptions of third party files specified in the list below, contain the following license: @@ -43,7 +52,66 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -## Third-party files and licenses +### REDIS SOURCE AVAILABLE LICENSE (RSAL) 2.0 + + +_Last updated: November 15, 2022_ + +#### Acceptance + +By using the software, you agree to all of the terms and conditions below. + +#### Copyright License + +The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations and conditions below. + +#### Limitations + +You may not make the functionality of the software or a modified version available to third parties as a service, or distribute the software or a modified version in a manner that makes the functionality of the software available to third parties. +Making the functionality of the software or modified version available to third parties includes, without limitation, enabling third parties to interact with the functionality of the software or modified version in distributed form or remotely through a computer network, offering a product or service the value of which entirely or primarily derives from the value of the software or modified version, or offering a product or service that accomplishes for users the primary purpose of the software or modified version. + +You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor’s trademarks is subject to applicable law. + +#### Patents + +The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company. + +#### Notices + +You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms. +If you modify the software, you must include in any modified copies of the software prominent notices stating that you have modified the software. + +#### No Other Rights + +These terms do not imply any licenses other than those expressly granted in these terms. + +#### Termination + +If you use the software in violation of these terms, such use is not licensed, and your licenses will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violations of this license no later than 30 days after you receive that notice, your licenses will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your licenses to terminate automatically and permanently. + +#### No Liability + +_**As far as the law allows, the **software** comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.**_ + +#### Definitions + +The **licensor** is the entity offering these terms, and the software is the software the licensor makes available under these terms, including any portion of it. + +To **modify** a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission other than making an exact copy. The resulting work is called a **modified version** of the earlier work. + +**you** refers to the individual or entity agreeing to these terms. + +**your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. + +**control** means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect. + +**your licenses** are all the licenses granted to you for the software under these terms. +use means anything you do with the software requiring one of your licenses. + +**trademark** means trademarks, service marks, and similar rights. + + +### Third-party files and licenses Redis uses source code from third parties. All this code contains a BSD or BSD-compatible license. The following is a list of third-party files and information about their copyright. @@ -57,5 +125,4 @@ Redis uses source code from third parties. All this code contains a BSD or BSD-c * Inside Jemalloc the files `inttypes.h`, `stdbool.h`, `stdint.h`, `strings.h` under the `msvc_compat` directory are copyright Alexander Chemeris and released under the **three-clause BSD license**. -* The libraries **hiredis** and **linenoise** also included inside the Redis distribution are copyright Salvatore Sanfilippo and Pieter Noordhuis and released under the terms respectively of the **three-clause BSD license** and **two-clause BSD license**. - +* The libraries **hiredis** and **linenoise** also included inside the Redis distribution are copyright Salvatore Sanfilippo and Pieter Noordhuis and released under the terms respectively of the **three-clause BSD license** and **two-clause BSD license**. \ No newline at end of file diff --git a/docs/clients/_index.md b/docs/clients/_index.md index b8fc945a62..3b1a4981a7 100644 --- a/docs/clients/_index.md +++ b/docs/clients/_index.md @@ -5,6 +5,7 @@ description: Get started using Redis clients. Select your library and connect yo weight: 45 aliases: - /docs/redis-clients + - /docs/stack/get-started/clients/ --- Here, you will learn how to connect your application to a Redis database. If you're new to Redis, you might first want to [install Redis with Redis Stack and RedisInsight](/docs/stack/get-started/install). @@ -12,3 +13,15 @@ Here, you will learn how to connect your application to a Redis database. If you For more Redis topics, see [Using](/docs/manual/) and [Managing](/docs/management/) Redis. If you're ready to get started, see the following guides for the official client libraries you can use with Redis. For a complete list of community-driven clients, see [Clients](/resources/clients/). + + +## High-level client libraries + +The Redis OM client libraries let you use the document modeling, indexing, and querying capabilities of Redis Stack much like the way you'd use an [ORM](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping). The following Redis OM libraries support Redis Stack: + +* [Redis OM .NET](/docs/clients/stack-dotnet/) +* [Redis OM Node](/docs/clients/stack-node/) +* [Redis OM Python](/docs/clients/stack-python/) +* [Redis OM Spring](/docs/clients/stack-spring/) + +
\ No newline at end of file diff --git a/docs/data-types/_index.md b/docs/data-types/_index.md index 8deccd2271..0defc77a43 100644 --- a/docs/data-types/_index.md +++ b/docs/data-types/_index.md @@ -2,7 +2,7 @@ title: "Redis data types" linkTitle: "Data types" description: Overview of data types supported by Redis -weight: 40 +weight: 35 aliases: - /docs/manual/data-types - /topics/data-types @@ -107,3 +107,5 @@ To extend the features provided by the included data types, use one of these opt 1. Write your own custom [server-side functions in Lua](/docs/manual/programmability/). 1. Write your own Redis module using the [modules API](/docs/reference/modules/) or check out the [community-supported modules](/docs/modules/). 1. Use [JSON](/docs/stack/json/), [querying](/docs/stack/search/), [time series](/docs/stack/timeseries/), and other capabilities provided by [Redis Stack](/docs/stack/). + +
\ No newline at end of file diff --git a/docs/data-types/bitfields.md b/docs/data-types/bitfields.md index 0643aeea71..fb74fc5d1f 100644 --- a/docs/data-types/bitfields.md +++ b/docs/data-types/bitfields.md @@ -12,6 +12,13 @@ For example, you can operate on anything from unsigned 1-bit integers to signed These values are stored using binary-encoded Redis strings. Bitfields support atomic read, write and increment operations, making them a good choice for managing counters and similar numerical values. + +## Basic commands + +* `BITFIELD` atomically sets, increments and reads one or more values. +* `BITFIELD_RO` is a read-only variant of `BITFIELD`. + + ## Examples Suppose you're keeping track of activity in an online game. @@ -46,10 +53,6 @@ You can represent these counters with one bitfield per player. 2) (integer) 1 ``` -## Basic commands - -* `BITFIELD` atomically sets, increments and reads one or more values. -* `BITFIELD_RO` is a read-only variant of `BITFIELD`. ## Performance diff --git a/docs/data-types/bitmaps.md b/docs/data-types/bitmaps.md index b05f63aeb1..e9db26536a 100644 --- a/docs/data-types/bitmaps.md +++ b/docs/data-types/bitmaps.md @@ -6,13 +6,26 @@ description: > Introduction to Redis bitmaps --- -Redis bitmaps are an extension of the string data type that lets you treat a string like a bit vector. -You can also perform bitwise operations on one or more strings. +Bitmaps are not an actual data type, but a set of bit-oriented operations +defined on the String type which is treated like a bit vector. +Since strings are binary safe blobs and their maximum length is 512 MB, +they are suitable to set up to 2^32 different bits. + +You can perform bitwise operations on one or more strings. Some examples of bitmap use cases include: * Efficient set representations for cases where the members of a set correspond to the integers 0-N. * Object permissions, where each bit represents a particular permission, similar to the way that file systems store permissions. +## Basic commands + +* `SETBIT` sets a bit at the provided offset to 0 or 1. +* `GETBIT` returns the value of a bit at a given offset. +* `BITOP` lets you perform bitwise operations against one or more strings. + +See the [complete list of bitmap commands](https://redis.io/commands/?group=bitmap). + + ## Examples Suppose you have 1000 sensors deployed in the field, labeled 0-999. @@ -38,13 +51,75 @@ You can represent this scenario using a bitmap whose key references the current 0 ``` -## Basic commands -* `SETBIT` sets a bit at the provided offset to 0 or 1. -* `GETBIT` returns the value of a bit at a given offset. -* `BITOP` lets you perform bitwise operations against one or more strings. -See the [complete list of bitmap commands](https://redis.io/commands/?group=bitmap). +Bit operations are divided into two groups: constant-time single bit +operations, like setting a bit to 1 or 0, or getting its value, and +operations on groups of bits, for example counting the number of set +bits in a given range of bits (e.g., population counting). + +One of the biggest advantages of bitmaps is that they often provide +extreme space savings when storing information. For example in a system +where different users are represented by incremental user IDs, it is possible +to remember a single bit information (for example, knowing whether +a user wants to receive a newsletter) of 4 billion of users using just 512 MB of memory. + +Bits are set and retrieved using the `SETBIT` and `GETBIT` commands: + + > setbit key 10 1 + (integer) 0 + > getbit key 10 + (integer) 1 + > getbit key 11 + (integer) 0 + +The `SETBIT` command takes as its first argument the bit number, and as its second +argument the value to set the bit to, which is 1 or 0. The command +automatically enlarges the string if the addressed bit is outside the +current string length. + +`GETBIT` just returns the value of the bit at the specified index. +Out of range bits (addressing a bit that is outside the length of the string +stored into the target key) are always considered to be zero. + +There are three commands operating on group of bits: + +1. `BITOP` performs bit-wise operations between different strings. The provided operations are AND, OR, XOR and NOT. +2. `BITCOUNT` performs population counting, reporting the number of bits set to 1. +3. `BITPOS` finds the first bit having the specified value of 0 or 1. + +Both `BITPOS` and `BITCOUNT` are able to operate with byte ranges of the +string, instead of running for the whole length of the string. The following +is a trivial example of `BITCOUNT` call: + + > setbit key 0 1 + (integer) 0 + > setbit key 100 1 + (integer) 0 + > bitcount key + (integer) 2 + +For example imagine you want to know the longest streak of daily visits of +your web site users. You start counting days starting from zero, that is the +day you made your web site public, and set a bit with `SETBIT` every time +the user visits the web site. As a bit index you simply take the current unix +time, subtract the initial offset, and divide by the number of seconds in a day +(normally, 3600\*24). + +This way for each user you have a small string containing the visit +information for each day. With `BITCOUNT` it is possible to easily get +the number of days a given user visited the web site, while with +a few `BITPOS` calls, or simply fetching and analyzing the bitmap client-side, +it is possible to easily compute the longest streak. + +Bitmaps are trivial to split into multiple keys, for example for +the sake of sharding the data set and because in general it is better to +avoid working with huge keys. To split a bitmap across different keys +instead of setting all the bits into a key, a trivial strategy is just +to store M bits per key and obtain the key name with `bit-number/M` and +the Nth bit to address inside the key with `bit-number MOD M`. + + ## Performance diff --git a/docs/data-types/geospatial.md b/docs/data-types/geospatial.md index 0f1e7ccdcb..6e8d6cd9dd 100644 --- a/docs/data-types/geospatial.md +++ b/docs/data-types/geospatial.md @@ -9,6 +9,14 @@ description: > Redis geospatial indexes let you store coordinates and search for them. This data structure is useful for finding nearby points within a given radius or bounding box. +## Basic commands + +* `GEOADD` adds a location to a given geospatial index (note that longitude comes before latitude with this command). +* `GEOSEARCH` returns locations with a given radius or a bounding box. + +See the [complete list of geospatial index commands](https://redis.io/commands/?group=geo). + + ## Examples Suppose you're building a mobile app that lets you find all of the electric car charging stations closest to your current location. @@ -34,13 +42,6 @@ Find all locations within a 5 kilometer radius of a given location, and return t 2) "2.2441" ``` -## Basic commands - -* `GEOADD` adds a location to a given geospatial index (note that longitude comes before latitude with this command). -* `GEOSEARCH` returns locations with a given radius or a bounding box. - -See the [complete list of geospatial index commands](https://redis.io/commands/?group=geo). - ## Learn more * [Redis Geospatial Explained](https://www.youtube.com/watch?v=qftiVQraxmI) introduces geospatial indexes by showing you how to build a map of local park attractions. diff --git a/docs/data-types/hashes.md b/docs/data-types/hashes.md index 2bafb4ab61..2409955a13 100644 --- a/docs/data-types/hashes.md +++ b/docs/data-types/hashes.md @@ -9,52 +9,85 @@ description: > Redis hashes are record types structured as collections of field-value pairs. You can use hashes to represent basic objects and to store groupings of counters, among other things. +{{< clients-example hash_tutorial set_get_all >}} +> hset bike:1 model Deimos brand Ergonom type 'Enduro bikes' price 4972 +(integer) 4 +> hget bike:1 model +"Deimos" +> hget bike:1 price +"4972" +> hgetall bike:1 +1) "model" +2) "Deimos" +3) "brand" +4) "Ergonom" +5) "type" +6) "Enduro bikes" +7) "price" +8) "4972" + +{{< /clients-example >}} + +While hashes are handy to represent *objects*, actually the number of fields you can +put inside a hash has no practical limits (other than available memory), so you can use +hashes in many different ways inside your application. + +The command `HSET` sets multiple fields of the hash, while `HGET` retrieves +a single field. `HMGET` is similar to `HGET` but returns an array of values: + +{{< clients-example hash_tutorial hmget >}} +> hmget bike:1 model price no-such-field +1) "Deimos" +2) "4972" +3) (nil) +{{< /clients-example >}} + +There are commands that are able to perform operations on individual fields +as well, like `HINCRBY`: + +{{< clients-example hash_tutorial hincrby >}} +> hincrby bike:1 price 100 +(integer) 5072 +> hincrby bike:1 price -100 +(integer) 4972 +{{< /clients-example >}} + +You can find the [full list of hash commands in the documentation](https://redis.io/commands#hash). + +It is worth noting that small hashes (i.e., a few elements with small values) are +encoded in special way in memory that make them very memory efficient. + +## Basic commands + +* `HSET` sets the value of one or more fields on a hash. +* `HGET` returns the value at a given field. +* `HMGET` returns the values at one or more given fields. +* `HINCRBY` increments the value at a given field by the integer provided. + +See the [complete list of hash commands](https://redis.io/commands/?group=hash). + + ## Examples -* Represent a basic user profile as a hash: -``` -> HSET user:123 username martina firstName Martina lastName Elisa country GB -(integer) 4 -> HGET user:123 username -"martina" -> HGETALL user:123 -1) "username" -2) "martina" -3) "firstName" -4) "Martina" -5) "lastName" -6) "Elisa" -7) "country" -8) "GB" -``` - -* Store counters for the number of times device 777 had pinged the server, issued a request, or sent an error: -``` -> HINCRBY device:777:stats pings 1 +* Store counters for the number of times bike:1 has been ridden, has crashed, or has changed owners: +{{< clients-example hash_tutorial incrby_get_mget >}} +> HINCRBY bike:1:stats rides 1 (integer) 1 -> HINCRBY device:777:stats pings 1 +> HINCRBY bike:1:stats rides 1 (integer) 2 -> HINCRBY device:777:stats pings 1 +> HINCRBY bike:1:stats rides 1 (integer) 3 -> HINCRBY device:777:stats errors 1 +> HINCRBY bike:1:stats crashes 1 (integer) 1 -> HINCRBY device:777:stats requests 1 +> HINCRBY bike:1:stats owners 1 (integer) 1 -> HGET device:777:stats pings +> HGET bike:1:stats rides "3" -> HMGET device:777:stats requests errors +> HMGET bike:1:stats owners crashes 1) "1" 2) "1" -``` - -## Basic commands +{{< /clients-example >}} -* `HSET` sets the value of one or more fields on a hash. -* `HGET` returns the value at a given field. -* `HMGET` returns the values at one or more given fields. -* `HINCRBY` increments the value at a given field by the integer provided. - -See the [complete list of hash commands](https://redis.io/commands/?group=hash). ## Performance @@ -70,4 +103,4 @@ In practice, your hashes are limited only by the overall memory on the VMs hosti ## Learn more * [Redis Hashes Explained](https://www.youtube.com/watch?v=-KdITaRkQ-U) is a short, comprehensive video explainer covering Redis hashes. -* [Redis University's RU101](https://university.redis.com/courses/ru101/) covers Redis hashes in detail. +* [Redis University's RU101](https://university.redis.com/courses/ru101/) covers Redis hashes in detail. \ No newline at end of file diff --git a/docs/data-types/hyperloglogs.md b/docs/data-types/hyperloglogs.md deleted file mode 100644 index 3c60947af6..0000000000 --- a/docs/data-types/hyperloglogs.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: "Redis HyperLogLog" -linkTitle: "HyperLogLog" -weight: 90 -description: > - Introduction to the Redis HyperLogLog data type ---- - -HyperLogLog is a data structure that estimates the cardinality of a set. As a probabilistic data structure, HyperLogLog trades perfect accuracy for efficient space utilization. - -The Redis HyperLogLog implementation uses up to 12 KB and provides a standard error of 0.81%. - -## Examples - -* Add some items to the HyperLogLog: -``` -> PFADD members 123 -(integer) 1 -> PFADD members 500 -(integer) 1 -> PFADD members 12 -(integer) 1 -``` - -* Estimate the number of members in the set: -``` -> PFCOUNT members -(integer) 3 -``` - -## Basic commands - -* `PFADD` adds an item to a HyperLogLog. -* `PFCOUNT` returns an estimate of the number of items in the set. -* `PFMERGE` combines two or more HyperLogLogs into one. - -See the [complete list of HyperLogLog commands](https://redis.io/commands/?group=hyperloglog). - -## Performance - -Writing (`PFADD`) to and reading from (`PFCOUNT`) the HyperLogLog is done in constant time and space. -Merging HLLs is O(n), where _n_ is the number of sketches. - -## Limits - -The HyperLogLog can estimate the cardinality of sets with up to 18,446,744,073,709,551,616 (2^64) members. - -## Learn more - -* [Redis new data structure: the HyperLogLog](http://antirez.com/news/75) has a lot of details about the data structure and its implementation in Redis. -* [Redis HyperLogLog Explained](https://www.youtube.com/watch?v=MunL8nnwscQ) shows you how to use Redis HyperLogLog data structures to build a traffic heat map. diff --git a/docs/data-types/lists.md b/docs/data-types/lists.md index b4769f5bfc..a73f676d7a 100644 --- a/docs/data-types/lists.md +++ b/docs/data-types/lists.md @@ -12,6 +12,26 @@ Redis lists are frequently used to: * Implement stacks and queues. * Build queue management for background worker systems. +## Basic commands + +* `LPUSH` adds a new element to the head of a list; `RPUSH` adds to the tail. +* `LPOP` removes and returns an element from the head of a list; `RPOP` does the same but from the tails of a list. +* `LLEN` returns the length of a list. +* `LMOVE` atomically moves elements from one list to another. +* `LTRIM` reduces a list to the specified range of elements. + +### Blocking commands + +Lists support several blocking commands. +For example: + +* `BLPOP` removes and returns an element from the head of a list. + If the list is empty, the command blocks until an element becomes available or until the specified timeout is reached. +* `BLMOVE` atomically moves elements from a source list to a target list. + If the source list is empty, the command will block until a new element becomes available. + +See the [complete series of list commands](https://redis.io/commands/?group=list). + ## Examples * Treat a list like a queue (first in, first out): @@ -70,29 +90,283 @@ OK OK ``` -## Limits +### What are Lists? +To explain the List data type it's better to start with a little bit of theory, +as the term *List* is often used in an improper way by information technology +folks. For instance "Python Lists" are not what the name may suggest (Linked +Lists), but rather Arrays (the same data type is called Array in +Ruby actually). -The max length of a Redis list is 2^32 - 1 (4,294,967,295) elements. +From a very general point of view a List is just a sequence of ordered +elements: 10,20,1,2,3 is a list. But the properties of a List implemented using +an Array are very different from the properties of a List implemented using a +*Linked List*. -## Basic commands +Redis lists are implemented via Linked Lists. This means that even if you have +millions of elements inside a list, the operation of adding a new element in +the head or in the tail of the list is performed *in constant time*. The speed of adding a +new element with the `LPUSH` command to the head of a list with ten +elements is the same as adding an element to the head of list with 10 +million elements. -* `LPUSH` adds a new element to the head of a list; `RPUSH` adds to the tail. -* `LPOP` removes and returns an element from the head of a list; `RPOP` does the same but from the tails of a list. -* `LLEN` returns the length of a list. -* `LMOVE` atomically moves elements from one list to another. -* `LTRIM` reduces a list to the specified range of elements. +What's the downside? Accessing an element *by index* is very fast in lists +implemented with an Array (constant time indexed access) and not so fast in +lists implemented by linked lists (where the operation requires an amount of +work proportional to the index of the accessed element). -### Blocking commands +Redis Lists are implemented with linked lists because for a database system it +is crucial to be able to add elements to a very long list in a very fast way. +Another strong advantage, as you'll see in a moment, is that Redis Lists can be +taken at constant length in constant time. -Lists support several blocking commands. -For example: +When fast access to the middle of a large collection of elements is important, +there is a different data structure that can be used, called sorted sets. +Sorted sets are covered in the [Sorted sets](/docs/data-types/sorted-sets) tutorial page. -* `BLPOP` removes and returns an element from the head of a list. - If the list is empty, the command blocks until an element becomes available or until the specified timeout is reached. -* `BLMOVE` atomically moves elements from a source list to a target list. - If the source list is empty, the command will block until a new element becomes available. +### First steps with Redis Lists + +The `LPUSH` command adds a new element into a list, on the +left (at the head), while the `RPUSH` command adds a new +element into a list, on the right (at the tail). Finally the +`LRANGE` command extracts ranges of elements from lists: + + > rpush mylist A + (integer) 1 + > rpush mylist B + (integer) 2 + > lpush mylist first + (integer) 3 + > lrange mylist 0 -1 + 1) "first" + 2) "A" + 3) "B" + +Note that `LRANGE` takes two indexes, the first and the last +element of the range to return. Both the indexes can be negative, telling Redis +to start counting from the end: so -1 is the last element, -2 is the +penultimate element of the list, and so forth. + +As you can see `RPUSH` appended the elements on the right of the list, while +the final `LPUSH` appended the element on the left. + +Both commands are *variadic commands*, meaning that you are free to push +multiple elements into a list in a single call: + + > rpush mylist 1 2 3 4 5 "foo bar" + (integer) 9 + > lrange mylist 0 -1 + 1) "first" + 2) "A" + 3) "B" + 4) "1" + 5) "2" + 6) "3" + 7) "4" + 8) "5" + 9) "foo bar" + +An important operation defined on Redis lists is the ability to *pop elements*. +Popping elements is the operation of both retrieving the element from the list, +and eliminating it from the list, at the same time. You can pop elements +from left and right, similarly to how you can push elements in both sides +of the list: + + > rpush mylist a b c + (integer) 3 + > rpop mylist + "c" + > rpop mylist + "b" + > rpop mylist + "a" + +We added three elements and popped three elements, so at the end of this +sequence of commands the list is empty and there are no more elements to +pop. If we try to pop yet another element, this is the result we get: + + > rpop mylist + (nil) + +Redis returned a NULL value to signal that there are no elements in the +list. + +### Common use cases for lists + +Lists are useful for a number of tasks, two very representative use cases +are the following: + +* Remember the latest updates posted by users into a social network. +* Communication between processes, using a consumer-producer pattern where the producer pushes items into a list, and a consumer (usually a *worker*) consumes those items and executes actions. Redis has special list commands to make this use case both more reliable and efficient. + +For example both the popular Ruby libraries [resque](https://github.com/resque/resque) and +[sidekiq](https://github.com/mperham/sidekiq) use Redis lists under the hood in order to +implement background jobs. + +The popular Twitter social network [takes the latest tweets](http://www.infoq.com/presentations/Real-Time-Delivery-Twitter) +posted by users into Redis lists. + +To describe a common use case step by step, imagine your home page shows the latest +photos published in a photo sharing social network and you want to speedup access. + +* Every time a user posts a new photo, we add its ID into a list with `LPUSH`. +* When users visit the home page, we use `LRANGE 0 9` in order to get the latest 10 posted items. + +### Capped lists + +In many use cases we just want to use lists to store the *latest items*, +whatever they are: social network updates, logs, or anything else. + +Redis allows us to use lists as a capped collection, only remembering the latest +N items and discarding all the oldest items using the `LTRIM` command. + +The `LTRIM` command is similar to `LRANGE`, but **instead of displaying the +specified range of elements** it sets this range as the new list value. All +the elements outside the given range are removed. + +An example will make it more clear: + + > rpush mylist 1 2 3 4 5 + (integer) 5 + > ltrim mylist 0 2 + OK + > lrange mylist 0 -1 + 1) "1" + 2) "2" + 3) "3" + +The above `LTRIM` command tells Redis to keep just list elements from index +0 to 2, everything else will be discarded. This allows for a very simple but +useful pattern: doing a List push operation + a List trim operation together +in order to add a new element and discard elements exceeding a limit: + + LPUSH mylist + LTRIM mylist 0 999 + +The above combination adds a new element and keeps only the 1000 +newest elements into the list. With `LRANGE` you can access the top items +without any need to remember very old data. + +Note: while `LRANGE` is technically an O(N) command, accessing small ranges +towards the head or the tail of the list is a constant time operation. + +Blocking operations on lists +--- + +Lists have a special feature that make them suitable to implement queues, +and in general as a building block for inter process communication systems: +blocking operations. + +Imagine you want to push items into a list with one process, and use +a different process in order to actually do some kind of work with those +items. This is the usual producer / consumer setup, and can be implemented +in the following simple way: + +* To push items into the list, producers call `LPUSH`. +* To extract / process items from the list, consumers call `RPOP`. + +However it is possible that sometimes the list is empty and there is nothing +to process, so `RPOP` just returns NULL. In this case a consumer is forced to wait +some time and retry again with `RPOP`. This is called *polling*, and is not +a good idea in this context because it has several drawbacks: + +1. Forces Redis and clients to process useless commands (all the requests when the list is empty will get no actual work done, they'll just return NULL). +2. Adds a delay to the processing of items, since after a worker receives a NULL, it waits some time. To make the delay smaller, we could wait less between calls to `RPOP`, with the effect of amplifying problem number 1, i.e. more useless calls to Redis. + +So Redis implements commands called `BRPOP` and `BLPOP` which are versions +of `RPOP` and `LPOP` able to block if the list is empty: they'll return to +the caller only when a new element is added to the list, or when a user-specified +timeout is reached. + +This is an example of a `BRPOP` call we could use in the worker: + + > brpop tasks 5 + 1) "tasks" + 2) "do_something" + +It means: "wait for elements in the list `tasks`, but return if after 5 seconds +no element is available". + +Note that you can use 0 as timeout to wait for elements forever, and you can +also specify multiple lists and not just one, in order to wait on multiple +lists at the same time, and get notified when the first list receives an +element. + +A few things to note about `BRPOP`: + +1. Clients are served in an ordered way: the first client that blocked waiting for a list, is served first when an element is pushed by some other client, and so forth. +2. The return value is different compared to `RPOP`: it is a two-element array since it also includes the name of the key, because `BRPOP` and `BLPOP` are able to block waiting for elements from multiple lists. +3. If the timeout is reached, NULL is returned. + +There are more things you should know about lists and blocking ops. We +suggest that you read more on the following: + +* It is possible to build safer queues or rotating queues using `LMOVE`. +* There is also a blocking variant of the command, called `BLMOVE`. + +## Automatic creation and removal of keys + +So far in our examples we never had to create empty lists before pushing +elements, or removing empty lists when they no longer have elements inside. +It is Redis' responsibility to delete keys when lists are left empty, or to create +an empty list if the key does not exist and we are trying to add elements +to it, for example, with `LPUSH`. + +This is not specific to lists, it applies to all the Redis data types +composed of multiple elements -- Streams, Sets, Sorted Sets and Hashes. + +Basically we can summarize the behavior with three rules: + +1. When we add an element to an aggregate data type, if the target key does not exist, an empty aggregate data type is created before adding the element. +2. When we remove elements from an aggregate data type, if the value remains empty, the key is automatically destroyed. The Stream data type is the only exception to this rule. +3. Calling a read-only command such as `LLEN` (which returns the length of the list), or a write command removing elements, with an empty key, always produces the same result as if the key is holding an empty aggregate type of the type the command expects to find. + +Examples of rule 1: + + > del mylist + (integer) 1 + > lpush mylist 1 2 3 + (integer) 3 + +However we can't perform operations against the wrong type if the key exists: + + > set foo bar + OK + > lpush foo 1 2 3 + (error) WRONGTYPE Operation against a key holding the wrong kind of value + > type foo + string + +Example of rule 2: + + > lpush mylist 1 2 3 + (integer) 3 + > exists mylist + (integer) 1 + > lpop mylist + "3" + > lpop mylist + "2" + > lpop mylist + "1" + > exists mylist + (integer) 0 + +The key no longer exists after all the elements are popped. + +Example of rule 3: + + > del mylist + (integer) 0 + > llen mylist + (integer) 0 + > lpop mylist + (nil) + + +## Limits + +The max length of a Redis list is 2^32 - 1 (4,294,967,295) elements. -See the [complete series of list commands](https://redis.io/commands/?group=list). ## Performance diff --git a/docs/data-types/probabilistic/hyperloglogs.md b/docs/data-types/probabilistic/hyperloglogs.md new file mode 100644 index 0000000000..1f00455e74 --- /dev/null +++ b/docs/data-types/probabilistic/hyperloglogs.md @@ -0,0 +1,110 @@ +--- +title: "HyperLogLog" +linkTitle: "HyperLogLog" +weight: 1 +description: > + HyperLogLog is a probabilistic data structure that estimates the cardinality of a set. +aliases: + - /docs/data-types/hyperloglogs/ +--- + +HyperLogLog is a probabilistic data structure that estimates the cardinality of a set. As a probabilistic data structure, HyperLogLog trades perfect accuracy for efficient space utilization. + +The Redis HyperLogLog implementation uses up to 12 KB and provides a standard error of 0.81%. + +Counting unique items usually requires an amount of memory +proportional to the number of items you want to count, because you need +to remember the elements you have already seen in the past in order to avoid +counting them multiple times. However, a set of algorithms exist that trade +memory for precision: they return an estimated measure with a standard error, +which, in the case of the Redis implementation for HyperLogLog, is less than 1%. +The magic of this algorithm is that you no longer need to use an amount of memory +proportional to the number of items counted, and instead can use a +constant amount of memory; 12k bytes in the worst case, or a lot less if your +HyperLogLog (We'll just call them HLL from now) has seen very few elements. + +HLLs in Redis, while technically a different data structure, are encoded +as a Redis string, so you can call `GET` to serialize a HLL, and `SET` +to deserialize it back to the server. + +Conceptually the HLL API is like using Sets to do the same task. You would +`SADD` every observed element into a set, and would use `SCARD` to check the +number of elements inside the set, which are unique since `SADD` will not +re-add an existing element. + +While you don't really *add items* into an HLL, because the data structure +only contains a state that does not include actual elements, the API is the +same: + +* Every time you see a new element, you add it to the count with `PFADD`. +* Every time you want to retrieve the current approximation of the unique elements *added* with `PFADD` so far, you use the `PFCOUNT`. + + > pfadd hll a b c d + (integer) 1 + > pfcount hll + (integer) 4 + +Some examples of use cases for this data structure is counting unique queries +performed by users in a search form every day, number of unique visitors to a web page and other similar cases. + +Redis is also able to perform the union of HLLs, please check the +[full documentation](/commands#hyperloglog) for more information. + +## Use cases + +**Anonymous unique visits of a web page (SaaS, analytics tools)** + +This application answers these questions: + +- How many unique visits has this page had on this day? +- How many unique users have played this song? +- How many unique users have viewed this video? + +{{% alert title="Note" color="warning" %}} + +Storing the IP address or any other kind of personal identifier is against the law in some countries, which makes it impossible to get unique visitor statistics on your website. + +{{% /alert %}} + +One HyperLogLog is created per page (video/song) per period, and every IP/identifier is added to it on every visit. + + +## Examples + +* Add some items to the HyperLogLog: +``` +> PFADD members 123 +(integer) 1 +> PFADD members 500 +(integer) 1 +> PFADD members 12 +(integer) 1 +``` + +* Estimate the number of members in the set: +``` +> PFCOUNT members +(integer) 3 +``` + +## Basic commands + +* `PFADD` adds an item to a HyperLogLog. +* `PFCOUNT` returns an estimate of the number of items in the set. +* `PFMERGE` combines two or more HyperLogLogs into one. + +See the [complete list of HyperLogLog commands](https://redis.io/commands/?group=hyperloglog). + +## Performance + +Writing (`PFADD`) to and reading from (`PFCOUNT`) the HyperLogLog is done in constant time and space. +Merging HLLs is O(n), where _n_ is the number of sketches. + +## Limits + +The HyperLogLog can estimate the cardinality of sets with up to 18,446,744,073,709,551,616 (2^64) members. + +## Learn more + +* [Redis new data structure: the HyperLogLog](http://antirez.com/news/75) has a lot of details about the data structure and its implementation in Redis. +* [Redis HyperLogLog Explained](https://www.youtube.com/watch?v=MunL8nnwscQ) shows you how to use Redis HyperLogLog data structures to build a traffic heat map. diff --git a/docs/data-types/sets.md b/docs/data-types/sets.md index 76ce907a3a..1ad2dcbdfd 100644 --- a/docs/data-types/sets.md +++ b/docs/data-types/sets.md @@ -13,6 +13,16 @@ You can use Redis sets to efficiently: * Represent relations (e.g., the set of all users with a given role). * Perform common set operations such as intersection, unions, and differences. +## Basic commands + +* `SADD` adds a new member to a set. +* `SREM` removes the specified member from the set. +* `SISMEMBER` tests a string for set membership. +* `SINTER` returns the set of members that two or more sets have in common (i.e., the intersection). +* `SCARD` returns the size (a.k.a. cardinality) of a set. + +See the [complete list of set commands](https://redis.io/commands/?group=set). + ## Examples * Store the set of favorited book IDs for users 123 and 456: @@ -47,19 +57,141 @@ You can use Redis sets to efficiently: (integer) 3 ``` -## Limits +## Tutorial -The max size of a Redis set is 2^32 - 1 (4,294,967,295) members. +The `SADD` command adds new elements to a set. It's also possible +to do a number of other operations against sets like testing if a given element +already exists, performing the intersection, union or difference between +multiple sets, and so forth. -## Basic commands + > sadd myset 1 2 3 + (integer) 3 + > smembers myset + 1. 3 + 2. 1 + 3. 2 + +Here I've added three elements to my set and told Redis to return all the +elements. As you can see they are not sorted -- Redis is free to return the +elements in any order at every call, since there is no contract with the +user about element ordering. + +Redis has commands to test for membership. For example, checking if an element exists: + + > sismember myset 3 + (integer) 1 + > sismember myset 30 + (integer) 0 -* `SADD` adds a new member to a set. -* `SREM` removes the specified member from the set. -* `SISMEMBER` tests a string for set membership. -* `SINTER` returns the set of members that two or more sets have in common (i.e., the intersection). -* `SCARD` returns the size (a.k.a. cardinality) of a set. +"3" is a member of the set, while "30" is not. -See the [complete list of set commands](https://redis.io/commands/?group=set). +Sets are good for expressing relations between objects. +For instance we can easily use sets in order to implement tags. + +A simple way to model this problem is to have a set for every object we +want to tag. The set contains the IDs of the tags associated with the object. + +One illustration is tagging news articles. +If article ID 1000 is tagged with tags 1, 2, 5 and 77, a set +can associate these tag IDs with the news item: + + > sadd news:1000:tags 1 2 5 77 + (integer) 4 + +We may also want to have the inverse relation as well: the list +of all the news tagged with a given tag: + + > sadd tag:1:news 1000 + (integer) 1 + > sadd tag:2:news 1000 + (integer) 1 + > sadd tag:5:news 1000 + (integer) 1 + > sadd tag:77:news 1000 + (integer) 1 + +To get all the tags for a given object is trivial: + + > smembers news:1000:tags + 1. 5 + 2. 1 + 3. 77 + 4. 2 + +Note: in the example we assume you have another data structure, for example +a Redis hash, which maps tag IDs to tag names. + +There are other non trivial operations that are still easy to implement +using the right Redis commands. For instance we may want a list of all the +objects with the tags 1, 2, 10, and 27 together. We can do this using +the `SINTER` command, which performs the intersection between different +sets. We can use: + + > sinter tag:1:news tag:2:news tag:10:news tag:27:news + ... results here ... + +In addition to intersection you can also perform +unions, difference, extract a random element, and so forth. + +The command to extract an element is called `SPOP`, and is handy to model +certain problems. For example in order to implement a web-based poker game, +you may want to represent your deck with a set. Imagine we use a one-char +prefix for (C)lubs, (D)iamonds, (H)earts, (S)pades: + + > sadd deck C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 CJ CQ CK + D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 DJ DQ DK H1 H2 H3 + H4 H5 H6 H7 H8 H9 H10 HJ HQ HK S1 S2 S3 S4 S5 S6 + S7 S8 S9 S10 SJ SQ SK + (integer) 52 + +Now we want to provide each player with 5 cards. The `SPOP` command +removes a random element, returning it to the client, so it is the +perfect operation in this case. + +However if we call it against our deck directly, in the next play of the +game we'll need to populate the deck of cards again, which may not be +ideal. So to start, we can make a copy of the set stored in the `deck` key +into the `game:1:deck` key. + +This is accomplished using `SUNIONSTORE`, which normally performs the +union between multiple sets, and stores the result into another set. +However, since the union of a single set is itself, I can copy my deck +with: + + > sunionstore game:1:deck deck + (integer) 52 + +Now I'm ready to provide the first player with five cards: + + > spop game:1:deck + "C6" + > spop game:1:deck + "CQ" + > spop game:1:deck + "D1" + > spop game:1:deck + "CJ" + > spop game:1:deck + "SJ" + +One pair of jacks, not great... + +This is a good time to introduce the set command that provides the number +of elements inside a set. This is often called the *cardinality of a set* +in the context of set theory, so the Redis command is called `SCARD`. + + > scard game:1:deck + (integer) 47 + +The math works: 52 - 5 = 47. + +When you need to just get random elements without removing them from the +set, there is the `SRANDMEMBER` command suitable for the task. It also features +the ability to return both repeating and non-repeating elements. + +## Limits + +The max size of a Redis set is 2^32 - 1 (4,294,967,295) members. ## Performance @@ -75,7 +207,7 @@ Sets membership checks on large datasets (or on streaming data) can use a lot of If you're concerned about memory usage and don't need perfect precision, consider a [Bloom filter or Cuckoo filter](/docs/stack/bloom) as an alternative to a set. Redis sets are frequently used as a kind of index. -If you need to index and query your data, consider [RediSearch](/docs/stack/search) and [RedisJSON](/docs/stack/json). +If you need to index and query your data, consider the [JSON](/docs/stack/json) data type and the [Search and query](/docs/stack/search) features. ## Learn more diff --git a/docs/data-types/sorted-sets.md b/docs/data-types/sorted-sets.md index d7049f94b9..a43fdbb0b8 100644 --- a/docs/data-types/sorted-sets.md +++ b/docs/data-types/sorted-sets.md @@ -13,6 +13,214 @@ Some use cases for sorted sets include: * Leaderboards. For example, you can use sorted sets to easily maintain ordered lists of the highest scores in a massive online game. * Rate limiters. In particular, you can use a sorted set to build a sliding-window rate limiter to prevent excessive API requests. +You can think of sorted sets as a mix between a Set and +a Hash. Like sets, sorted sets are composed of unique, non-repeating +string elements, so in some sense a sorted set is a set as well. + +However while elements inside sets are not ordered, every element in +a sorted set is associated with a floating point value, called *the score* +(this is why the type is also similar to a hash, since every element +is mapped to a value). + +Moreover, elements in a sorted set are *taken in order* (so they are not +ordered on request, order is a peculiarity of the data structure used to +represent sorted sets). They are ordered according to the following rule: + +* If B and A are two elements with a different score, then A > B if A.score is > B.score. +* If B and A have exactly the same score, then A > B if the A string is lexicographically greater than the B string. B and A strings can't be equal since sorted sets only have unique elements. + +Let's start with a simple example, adding a few selected hackers names as +sorted set elements, with their year of birth as "score". + + > zadd hackers 1940 "Alan Kay" + (integer) 1 + > zadd hackers 1957 "Sophie Wilson" + (integer) 1 + > zadd hackers 1953 "Richard Stallman" + (integer) 1 + > zadd hackers 1949 "Anita Borg" + (integer) 1 + > zadd hackers 1965 "Yukihiro Matsumoto" + (integer) 1 + > zadd hackers 1914 "Hedy Lamarr" + (integer) 1 + > zadd hackers 1916 "Claude Shannon" + (integer) 1 + > zadd hackers 1969 "Linus Torvalds" + (integer) 1 + > zadd hackers 1912 "Alan Turing" + (integer) 1 + + +As you can see `ZADD` is similar to `SADD`, but takes one additional argument +(placed before the element to be added) which is the score. +`ZADD` is also variadic, so you are free to specify multiple score-value +pairs, even if this is not used in the example above. + +With sorted sets it is trivial to return a list of hackers sorted by their +birth year because actually *they are already sorted*. + +Implementation note: Sorted sets are implemented via a +dual-ported data structure containing both a skip list and a hash table, so +every time we add an element Redis performs an O(log(N)) operation. That's +good, but when we ask for sorted elements Redis does not have to do any work at +all, it's already all sorted: + + > zrange hackers 0 -1 + 1) "Alan Turing" + 2) "Hedy Lamarr" + 3) "Claude Shannon" + 4) "Alan Kay" + 5) "Anita Borg" + 6) "Richard Stallman" + 7) "Sophie Wilson" + 8) "Yukihiro Matsumoto" + 9) "Linus Torvalds" + +Note: 0 and -1 means from element index 0 to the last element (-1 works +here just as it does in the case of the `LRANGE` command). + +What if I want to order them the opposite way, youngest to oldest? +Use `ZREVRANGE` instead of `ZRANGE`: + + > zrevrange hackers 0 -1 + 1) "Linus Torvalds" + 2) "Yukihiro Matsumoto" + 3) "Sophie Wilson" + 4) "Richard Stallman" + 5) "Anita Borg" + 6) "Alan Kay" + 7) "Claude Shannon" + 8) "Hedy Lamarr" + 9) "Alan Turing" + +It is possible to return scores as well, using the `WITHSCORES` argument: + + > zrange hackers 0 -1 withscores + 1) "Alan Turing" + 2) "1912" + 3) "Hedy Lamarr" + 4) "1914" + 5) "Claude Shannon" + 6) "1916" + 7) "Alan Kay" + 8) "1940" + 9) "Anita Borg" + 10) "1949" + 11) "Richard Stallman" + 12) "1953" + 13) "Sophie Wilson" + 14) "1957" + 15) "Yukihiro Matsumoto" + 16) "1965" + 17) "Linus Torvalds" + 18) "1969" + +### Operating on ranges + +Sorted sets are more powerful than this. They can operate on ranges. +Let's get all the individuals that were born up to 1950 inclusive. We +use the `ZRANGEBYSCORE` command to do it: + + > zrangebyscore hackers -inf 1950 + 1) "Alan Turing" + 2) "Hedy Lamarr" + 3) "Claude Shannon" + 4) "Alan Kay" + 5) "Anita Borg" + +We asked Redis to return all the elements with a score between negative +infinity and 1950 (both extremes are included). + +It's also possible to remove ranges of elements. Let's remove all +the hackers born between 1940 and 1960 from the sorted set: + + > zremrangebyscore hackers 1940 1960 + (integer) 4 + +`ZREMRANGEBYSCORE` is perhaps not the best command name, +but it can be very useful, and returns the number of removed elements. + +Another extremely useful operation defined for sorted set elements +is the get-rank operation. It is possible to ask what is the +position of an element in the set of the ordered elements. + + > zrank hackers "Anita Borg" + (integer) 4 + +The `ZREVRANK` command is also available in order to get the rank, considering +the elements sorted a descending way. + +### Lexicographical scores + +In version Redis 2.8, a new feature was introduced that allows +getting ranges lexicographically, assuming elements in a sorted set are all +inserted with the same identical score (elements are compared with the C +`memcmp` function, so it is guaranteed that there is no collation, and every +Redis instance will reply with the same output). + +The main commands to operate with lexicographical ranges are `ZRANGEBYLEX`, +`ZREVRANGEBYLEX`, `ZREMRANGEBYLEX` and `ZLEXCOUNT`. + +For example, let's add again our list of famous hackers, but this time +use a score of zero for all the elements: + + > zadd hackers 0 "Alan Kay" 0 "Sophie Wilson" 0 "Richard Stallman" 0 + "Anita Borg" 0 "Yukihiro Matsumoto" 0 "Hedy Lamarr" 0 "Claude Shannon" + 0 "Linus Torvalds" 0 "Alan Turing" + +Because of the sorted sets ordering rules, they are already sorted +lexicographically: + + > zrange hackers 0 -1 + 1) "Alan Kay" + 2) "Alan Turing" + 3) "Anita Borg" + 4) "Claude Shannon" + 5) "Hedy Lamarr" + 6) "Linus Torvalds" + 7) "Richard Stallman" + 8) "Sophie Wilson" + 9) "Yukihiro Matsumoto" + +Using `ZRANGEBYLEX` we can ask for lexicographical ranges: + + > zrangebylex hackers [B [P + 1) "Claude Shannon" + 2) "Hedy Lamarr" + 3) "Linus Torvalds" + +Ranges can be inclusive or exclusive (depending on the first character), +also string infinite and minus infinite are specified respectively with +the `+` and `-` strings. See the documentation for more information. + +This feature is important because it allows us to use sorted sets as a generic +index. For example, if you want to index elements by a 128-bit unsigned +integer argument, all you need to do is to add elements into a sorted +set with the same score (for example 0) but with a 16 byte prefix +consisting of **the 128 bit number in big endian**. Since numbers in big +endian, when ordered lexicographically (in raw bytes order) are actually +ordered numerically as well, you can ask for ranges in the 128 bit space, +and get the element's value discarding the prefix. + +If you want to see the feature in the context of a more serious demo, +check the [Redis autocomplete demo](http://autocomplete.redis.io). + +Updating the score: leaderboards +--- + +Just a final note about sorted sets before switching to the next topic. +Sorted sets' scores can be updated at any time. Just calling `ZADD` against +an element already included in the sorted set will update its score +(and position) with O(log(N)) time complexity. As such, sorted sets are suitable +when there are tons of updates. + +Because of this characteristic a common use case is leaderboards. +The typical application is a Facebook game where you combine the ability to +take users sorted by their high score, plus the get-rank operation, in order +to show the top-N users, and the user rank in the leader board (e.g., "you are +the #4932 best score here"). + ## Examples * Update a real-time leaderboard as players' scores change: @@ -67,7 +275,7 @@ This command's time complexity is O(log(n) + m), where _m_ is the number of resu ## Alternatives Redis sorted sets are sometimes used for indexing other Redis data structures. -If you need to index and query your data, consider [RediSearch](/docs/stack/search) and [RedisJSON](/docs/stack/json). +If you need to index and query your data, consider the [JSON](/docs/stack/json) data type and the [Search and query](/docs/stack/search) features. ## Learn more diff --git a/docs/data-types/streams-tutorial.md b/docs/data-types/streams-tutorial.md deleted file mode 100644 index 01f171dea3..0000000000 --- a/docs/data-types/streams-tutorial.md +++ /dev/null @@ -1,794 +0,0 @@ ---- -title: "Redis Streams tutorial" -linkTitle: "Streams tutorial" -weight: 61 -description: > - A comprehensive tutorial on Redis streams -aliases: - - /topics/streams-intro - - /docs/manual/data-types/streams ---- - -If you're new to streams, see the [Redis Streams introduction](/docs/data-types/streams/). For a more comprehensive tutorial, read on. - -## Introduction - -The Redis stream data type was introduced in Redis 5.0. Streams model a log data structure but also implement several operations to overcome some of the limits of a typical append-only log. These include random access in O(1) time and complex consumption strategies, such as consumer groups. - -## Streams basics - -Streams are an append-only data structure. The fundamental write command, called [XADD](/commands/xadd), appends a new entry to the specified stream. - -Each stream entry consists of one or more field-value pairs, somewhat like a record or a Redis hash: - -``` -> XADD mystream * sensor-id 1234 temperature 19.8 -1518951480106-0 -``` - -The above call to the `XADD` command adds an entry `sensor-id: 1234, temperature: 19.8` to the stream at key `mystream`, using an auto-generated entry ID, which is the one returned by the command, specifically `1518951480106-0`. It gets as its first argument the key name `mystream`, the second argument is the entry ID that identifies every entry inside a stream. However, in this case, we passed `*` because we want the server to generate a new ID for us. Every new ID will be monotonically increasing, so in more simple terms, every new entry added will have a higher ID compared to all the past entries. Auto-generation of IDs by the server is almost always what you want, and the reasons for specifying an ID explicitly are very rare. We'll talk more about this later. The fact that each Stream entry has an ID is another similarity with log files, where line numbers, or the byte offset inside the file, can be used in order to identify a given entry. Returning back at our `XADD` example, after the key name and ID, the next arguments are the field-value pairs composing our stream entry. - -It is possible to get the number of items inside a Stream just using the `XLEN` command: - -``` -> XLEN mystream -(integer) 1 -``` - -### Entry IDs - -The entry ID returned by the `XADD` command, and identifying univocally each entry inside a given stream, is composed of two parts: - -``` -- -``` - -The milliseconds time part is actually the local time in the local Redis node generating the stream ID, however if the current milliseconds time happens to be smaller than the previous entry time, then the previous entry time is used instead, so if a clock jumps backward the monotonically incrementing ID property still holds. The sequence number is used for entries created in the same millisecond. Since the sequence number is 64 bit wide, in practical terms there is no limit to the number of entries that can be generated within the same millisecond. - -The format of such IDs may look strange at first, and the gentle reader may wonder why the time is part of the ID. The reason is that Redis streams support range queries by ID. Because the ID is related to the time the entry is generated, this gives the ability to query for time ranges basically for free. We will see this soon while covering the `XRANGE` command. - -If for some reason the user needs incremental IDs that are not related to time but are actually associated to another external system ID, as previously mentioned, the `XADD` command can take an explicit ID instead of the `*` wildcard ID that triggers auto-generation, like in the following examples: - -``` -> XADD somestream 0-1 field value -0-1 -> XADD somestream 0-2 foo bar -0-2 -``` - -Note that in this case, the minimum ID is 0-1 and that the command will not accept an ID equal or smaller than a previous one: - -``` -> XADD somestream 0-1 foo bar -(error) ERR The ID specified in XADD is equal or smaller than the target stream top item -``` - -If you're running Redis 7 or later, you can also provide an explicit ID consisting of the milliseconds part only. In this case, the sequence portion of the ID will be automatically generated. To do this, use the syntax below: - -``` -> XADD somestream 0-* baz qux -0-3 -``` - -## Getting data from Streams - -Now we are finally able to append entries in our stream via `XADD`. However, while appending data to a stream is quite obvious, the way streams can be queried in order to extract data is not so obvious. If we continue with the analogy of the log file, one obvious way is to mimic what we normally do with the Unix command `tail -f`, that is, we may start to listen in order to get the new messages that are appended to the stream. Note that unlike the blocking list operations of Redis, where a given element will reach a single client which is blocking in a *pop style* operation like `BLPOP`, with streams we want multiple consumers to see the new messages appended to the stream (the same way many `tail -f` processes can see what is added to a log). Using the traditional terminology we want the streams to be able to *fan out* messages to multiple clients. - -However, this is just one potential access mode. We could also see a stream in quite a different way: not as a messaging system, but as a *time series store*. In this case, maybe it's also useful to get the new messages appended, but another natural query mode is to get messages by ranges of time, or alternatively to iterate the messages using a cursor to incrementally check all the history. This is definitely another useful access mode. - -Finally, if we see a stream from the point of view of consumers, we may want to access the stream in yet another way, that is, as a stream of messages that can be partitioned to multiple consumers that are processing such messages, so that groups of consumers can only see a subset of the messages arriving in a single stream. In this way, it is possible to scale the message processing across different consumers, without single consumers having to process all the messages: each consumer will just get different messages to process. This is basically what Kafka (TM) does with consumer groups. Reading messages via consumer groups is yet another interesting mode of reading from a Redis Stream. - -Redis Streams support all three of the query modes described above via different commands. The next sections will show them all, starting from the simplest and most direct to use: range queries. - -### Querying by range: XRANGE and XREVRANGE - -To query the stream by range we are only required to specify two IDs, *start* and *end*. The range returned will include the elements having start or end as ID, so the range is inclusive. The two special IDs `-` and `+` respectively mean the smallest and the greatest ID possible. - -``` -> XRANGE mystream - + -1) 1) 1518951480106-0 - 2) 1) "sensor-id" - 2) "1234" - 3) "temperature" - 4) "19.8" -2) 1) 1518951482479-0 - 2) 1) "sensor-id" - 2) "9999" - 3) "temperature" - 4) "18.2" -``` - -Each entry returned is an array of two items: the ID and the list of field-value pairs. We already said that the entry IDs have a relation with the time, because the part at the left of the `-` character is the Unix time in milliseconds of the local node that created the stream entry, at the moment the entry was created (however note that streams are replicated with fully specified `XADD` commands, so the replicas will have identical IDs to the master). This means that I could query a range of time using `XRANGE`. In order to do so, however, I may want to omit the sequence part of the ID: if omitted, in the start of the range it will be assumed to be 0, while in the end part it will be assumed to be the maximum sequence number available. This way, querying using just two milliseconds Unix times, we get all the entries that were generated in that range of time, in an inclusive way. For instance, if I want to query a two milliseconds period I could use: - -``` -> XRANGE mystream 1518951480106 1518951480107 -1) 1) 1518951480106-0 - 2) 1) "sensor-id" - 2) "1234" - 3) "temperature" - 4) "19.8" -``` - -I have only a single entry in this range, however in real data sets, I could query for ranges of hours, or there could be many items in just two milliseconds, and the result returned could be huge. For this reason, `XRANGE` supports an optional **COUNT** option at the end. By specifying a count, I can just get the first *N* items. If I want more, I can get the last ID returned, increment the sequence part by one, and query again. Let's see this in the following example. We start adding 10 items with `XADD` (I won't show that, lets assume that the stream `mystream` was populated with 10 items). To start my iteration, getting 2 items per command, I start with the full range, but with a count of 2. - -``` -> XRANGE mystream - + COUNT 2 -1) 1) 1519073278252-0 - 2) 1) "foo" - 2) "value_1" -2) 1) 1519073279157-0 - 2) 1) "foo" - 2) "value_2" -``` - -In order to continue the iteration with the next two items, I have to pick the last ID returned, that is `1519073279157-0` and add the prefix `(` to it. The resulting exclusive range interval, that is `(1519073279157-0` in this case, can now be used as the new *start* argument for the next `XRANGE` call: - -``` -> XRANGE mystream (1519073279157-0 + COUNT 2 -1) 1) 1519073280281-0 - 2) 1) "foo" - 2) "value_3" -2) 1) 1519073281432-0 - 2) 1) "foo" - 2) "value_4" -``` - -And so forth. Since `XRANGE` complexity is *O(log(N))* to seek, and then *O(M)* to return M elements, with a small count the command has a logarithmic time complexity, which means that each step of the iteration is fast. So `XRANGE` is also the de facto *streams iterator* and does not require an **XSCAN** command. - -The command `XREVRANGE` is the equivalent of `XRANGE` but returning the elements in inverted order, so a practical use for `XREVRANGE` is to check what is the last item in a Stream: - -``` -> XREVRANGE mystream + - COUNT 1 -1) 1) 1519073287312-0 - 2) 1) "foo" - 2) "value_10" -``` - -Note that the `XREVRANGE` command takes the *start* and *stop* arguments in reverse order. - -## Listening for new items with XREAD - -When we do not want to access items by a range in a stream, usually what we want instead is to *subscribe* to new items arriving to the stream. This concept may appear related to Redis Pub/Sub, where you subscribe to a channel, or to Redis blocking lists, where you wait for a key to get new elements to fetch, but there are fundamental differences in the way you consume a stream: - -1. A stream can have multiple clients (consumers) waiting for data. Every new item, by default, will be delivered to *every consumer* that is waiting for data in a given stream. This behavior is different than blocking lists, where each consumer will get a different element. However, the ability to *fan out* to multiple consumers is similar to Pub/Sub. -2. While in Pub/Sub messages are *fire and forget* and are never stored anyway, and while when using blocking lists, when a message is received by the client it is *popped* (effectively removed) from the list, streams work in a fundamentally different way. All the messages are appended in the stream indefinitely (unless the user explicitly asks to delete entries): different consumers will know what is a new message from its point of view by remembering the ID of the last message received. -3. Streams Consumer Groups provide a level of control that Pub/Sub or blocking lists cannot achieve, with different groups for the same stream, explicit acknowledgment of processed items, ability to inspect the pending items, claiming of unprocessed messages, and coherent history visibility for each single client, that is only able to see its private past history of messages. - -The command that provides the ability to listen for new messages arriving into a stream is called `XREAD`. It's a bit more complex than `XRANGE`, so we'll start showing simple forms, and later the whole command layout will be provided. - -``` -> XREAD COUNT 2 STREAMS mystream 0 -1) 1) "mystream" - 2) 1) 1) 1519073278252-0 - 2) 1) "foo" - 2) "value_1" - 2) 1) 1519073279157-0 - 2) 1) "foo" - 2) "value_2" -``` - -The above is the non-blocking form of `XREAD`. Note that the **COUNT** option is not mandatory, in fact the only mandatory option of the command is the **STREAMS** option, that specifies a list of keys together with the corresponding maximum ID already seen for each stream by the calling consumer, so that the command will provide the client only with messages with an ID greater than the one we specified. - -In the above command we wrote `STREAMS mystream 0` so we want all the messages in the Stream `mystream` having an ID greater than `0-0`. As you can see in the example above, the command returns the key name, because actually it is possible to call this command with more than one key to read from different streams at the same time. I could write, for instance: `STREAMS mystream otherstream 0 0`. Note how after the **STREAMS** option we need to provide the key names, and later the IDs. For this reason, the **STREAMS** option must always be the last option. -Any other options must come before the **STREAMS** option. - -Apart from the fact that `XREAD` can access multiple streams at once, and that we are able to specify the last ID we own to just get newer messages, in this simple form the command is not doing something so different compared to `XRANGE`. However, the interesting part is that we can turn `XREAD` into a *blocking command* easily, by specifying the **BLOCK** argument: - -``` -> XREAD BLOCK 0 STREAMS mystream $ -``` - -Note that in the example above, other than removing **COUNT**, I specified the new **BLOCK** option with a timeout of 0 milliseconds (that means to never timeout). Moreover, instead of passing a normal ID for the stream `mystream` I passed the special ID `$`. This special ID means that `XREAD` should use as last ID the maximum ID already stored in the stream `mystream`, so that we will receive only *new* messages, starting from the time we started listening. This is similar to the `tail -f` Unix command in some way. - -Note that when the **BLOCK** option is used, we do not have to use the special ID `$`. We can use any valid ID. If the command is able to serve our request immediately without blocking, it will do so, otherwise it will block. Normally if we want to consume the stream starting from new entries, we start with the ID `$`, and after that we continue using the ID of the last message received to make the next call, and so forth. - -The blocking form of `XREAD` is also able to listen to multiple Streams, just by specifying multiple key names. If the request can be served synchronously because there is at least one stream with elements greater than the corresponding ID we specified, it returns with the results. Otherwise, the command will block and will return the items of the first stream which gets new data (according to the specified ID). - -Similarly to blocking list operations, blocking stream reads are *fair* from the point of view of clients waiting for data, since the semantics is FIFO style. The first client that blocked for a given stream will be the first to be unblocked when new items are available. - -`XREAD` has no other options than **COUNT** and **BLOCK**, so it's a pretty basic command with a specific purpose to attach consumers to one or multiple streams. More powerful features to consume streams are available using the consumer groups API, however reading via consumer groups is implemented by a different command called `XREADGROUP`, covered in the next section of this guide. - -## Consumer groups - -When the task at hand is to consume the same stream from different clients, then `XREAD` already offers a way to *fan-out* to N clients, potentially also using replicas in order to provide more read scalability. However in certain problems what we want to do is not to provide the same stream of messages to many clients, but to provide a *different subset* of messages from the same stream to many clients. An obvious case where this is useful is that of messages which are slow to process: the ability to have N different workers that will receive different parts of the stream allows us to scale message processing, by routing different messages to different workers that are ready to do more work. - -In practical terms, if we imagine having three consumers C1, C2, C3, and a stream that contains the messages 1, 2, 3, 4, 5, 6, 7 then what we want is to serve the messages according to the following diagram: - -``` -1 -> C1 -2 -> C2 -3 -> C3 -4 -> C1 -5 -> C2 -6 -> C3 -7 -> C1 -``` - -In order to achieve this, Redis uses a concept called *consumer groups*. It is very important to understand that Redis consumer groups have nothing to do, from an implementation standpoint, with Kafka (TM) consumer groups. Yet they are similar in functionality, so I decided to keep Kafka's (TM) terminology, as it originally popularized this idea. - -A consumer group is like a *pseudo consumer* that gets data from a stream, and actually serves multiple consumers, providing certain guarantees: - -1. Each message is served to a different consumer so that it is not possible that the same message will be delivered to multiple consumers. -2. Consumers are identified, within a consumer group, by a name, which is a case-sensitive string that the clients implementing consumers must choose. This means that even after a disconnect, the stream consumer group retains all the state, since the client will claim again to be the same consumer. However, this also means that it is up to the client to provide a unique identifier. -3. Each consumer group has the concept of the *first ID never consumed* so that, when a consumer asks for new messages, it can provide just messages that were not previously delivered. -4. Consuming a message, however, requires an explicit acknowledgment using a specific command. Redis interprets the acknowledgment as: this message was correctly processed so it can be evicted from the consumer group. -5. A consumer group tracks all the messages that are currently pending, that is, messages that were delivered to some consumer of the consumer group, but are yet to be acknowledged as processed. Thanks to this feature, when accessing the message history of a stream, each consumer *will only see messages that were delivered to it*. - -In a way, a consumer group can be imagined as some *amount of state* about a stream: - -``` -+----------------------------------------+ -| consumer_group_name: mygroup | -| consumer_group_stream: somekey | -| last_delivered_id: 1292309234234-92 | -| | -| consumers: | -| "consumer-1" with pending messages | -| 1292309234234-4 | -| 1292309234232-8 | -| "consumer-42" with pending messages | -| ... (and so forth) | -+----------------------------------------+ -``` - -If you see this from this point of view, it is very simple to understand what a consumer group can do, how it is able to just provide consumers with their history of pending messages, and how consumers asking for new messages will just be served with message IDs greater than `last_delivered_id`. At the same time, if you look at the consumer group as an auxiliary data structure for Redis streams, it is obvious that a single stream can have multiple consumer groups, that have a different set of consumers. Actually, it is even possible for the same stream to have clients reading without consumer groups via `XREAD`, and clients reading via `XREADGROUP` in different consumer groups. - -Now it's time to zoom in to see the fundamental consumer group commands. They are the following: - -* `XGROUP` is used in order to create, destroy and manage consumer groups. -* `XREADGROUP` is used to read from a stream via a consumer group. -* `XACK` is the command that allows a consumer to mark a pending message as correctly processed. - -## Creating a consumer group - -Assuming I have a key `mystream` of type stream already existing, in order to create a consumer group I just need to do the following: - -``` -> XGROUP CREATE mystream mygroup $ -OK -``` - -As you can see in the command above when creating the consumer group we have to specify an ID, which in the example is just `$`. This is needed because the consumer group, among the other states, must have an idea about what message to serve next at the first consumer connecting, that is, what was the *last message ID* when the group was just created. If we provide `$` as we did, then only new messages arriving in the stream from now on will be provided to the consumers in the group. If we specify `0` instead the consumer group will consume *all* the messages in the stream history to start with. Of course, you can specify any other valid ID. What you know is that the consumer group will start delivering messages that are greater than the ID you specify. Because `$` means the current greatest ID in the stream, specifying `$` will have the effect of consuming only new messages. - -`XGROUP CREATE` also supports creating the stream automatically, if it doesn't exist, using the optional `MKSTREAM` subcommand as the last argument: - -``` -> XGROUP CREATE newstream mygroup $ MKSTREAM -OK -``` - -Now that the consumer group is created we can immediately try to read messages via the consumer group using the `XREADGROUP` command. We'll read from consumers, that we will call Alice and Bob, to see how the system will return different messages to Alice or Bob. - -`XREADGROUP` is very similar to `XREAD` and provides the same **BLOCK** option, otherwise it is a synchronous command. However there is a *mandatory* option that must be always specified, which is **GROUP** and has two arguments: the name of the consumer group, and the name of the consumer that is attempting to read. The option **COUNT** is also supported and is identical to the one in `XREAD`. - -Before reading from the stream, let's put some messages inside: - -``` -> XADD mystream * message apple -1526569495631-0 -> XADD mystream * message orange -1526569498055-0 -> XADD mystream * message strawberry -1526569506935-0 -> XADD mystream * message apricot -1526569535168-0 -> XADD mystream * message banana -1526569544280-0 -``` - -Note: *here message is the field name, and the fruit is the associated value, remember that stream items are small dictionaries.* - -It is time to try reading something using the consumer group: - -``` -> XREADGROUP GROUP mygroup Alice COUNT 1 STREAMS mystream > -1) 1) "mystream" - 2) 1) 1) 1526569495631-0 - 2) 1) "message" - 2) "apple" -``` - -`XREADGROUP` replies are just like `XREAD` replies. Note however the `GROUP ` provided above. It states that I want to read from the stream using the consumer group `mygroup` and I'm the consumer `Alice`. Every time a consumer performs an operation with a consumer group, it must specify its name, uniquely identifying this consumer inside the group. - -There is another very important detail in the command line above, after the mandatory **STREAMS** option the ID requested for the key `mystream` is the special ID `>`. This special ID is only valid in the context of consumer groups, and it means: **messages never delivered to other consumers so far**. - -This is almost always what you want, however it is also possible to specify a real ID, such as `0` or any other valid ID, in this case, however, what happens is that we request from `XREADGROUP` to just provide us with the **history of pending messages**, and in such case, will never see new messages in the group. So basically `XREADGROUP` has the following behavior based on the ID we specify: - -* If the ID is the special ID `>` then the command will return only new messages never delivered to other consumers so far, and as a side effect, will update the consumer group's *last ID*. -* If the ID is any other valid numerical ID, then the command will let us access our *history of pending messages*. That is, the set of messages that were delivered to this specified consumer (identified by the provided name), and never acknowledged so far with `XACK`. - -We can test this behavior immediately specifying an ID of 0, without any **COUNT** option: we'll just see the only pending message, that is, the one about apples: - -``` -> XREADGROUP GROUP mygroup Alice STREAMS mystream 0 -1) 1) "mystream" - 2) 1) 1) 1526569495631-0 - 2) 1) "message" - 2) "apple" -``` - -However, if we acknowledge the message as processed, it will no longer be part of the pending messages history, so the system will no longer report anything: - -``` -> XACK mystream mygroup 1526569495631-0 -(integer) 1 -> XREADGROUP GROUP mygroup Alice STREAMS mystream 0 -1) 1) "mystream" - 2) (empty list or set) -``` - -Don't worry if you yet don't know how `XACK` works, the idea is just that processed messages are no longer part of the history that we can access. - -Now it's Bob's turn to read something: - -``` -> XREADGROUP GROUP mygroup Bob COUNT 2 STREAMS mystream > -1) 1) "mystream" - 2) 1) 1) 1526569498055-0 - 2) 1) "message" - 2) "orange" - 2) 1) 1526569506935-0 - 2) 1) "message" - 2) "strawberry" -``` - -Bob asked for a maximum of two messages and is reading via the same group `mygroup`. So what happens is that Redis reports just *new* messages. As you can see the "apple" message is not delivered, since it was already delivered to Alice, so Bob gets orange and strawberry, and so forth. - -This way Alice, Bob, and any other consumer in the group, are able to read different messages from the same stream, to read their history of yet to process messages, or to mark messages as processed. This allows creating different topologies and semantics for consuming messages from a stream. - -There are a few things to keep in mind: - -* Consumers are auto-created the first time they are mentioned, no need for explicit creation. -* Even with `XREADGROUP` you can read from multiple keys at the same time, however for this to work, you need to create a consumer group with the same name in every stream. This is not a common need, but it is worth mentioning that the feature is technically available. -* `XREADGROUP` is a *write command* because even if it reads from the stream, the consumer group is modified as a side effect of reading, so it can only be called on master instances. - -An example of a consumer implementation, using consumer groups, written in the Ruby language could be the following. The Ruby code is aimed to be readable by virtually any experienced programmer, even if they do not know Ruby: - -```ruby -require 'redis' - -if ARGV.length == 0 - puts "Please specify a consumer name" - exit 1 -end - -ConsumerName = ARGV[0] -GroupName = "mygroup" -r = Redis.new - -def process_message(id,msg) - puts "[#{ConsumerName}] #{id} = #{msg.inspect}" -end - -$lastid = '0-0' - -puts "Consumer #{ConsumerName} starting..." -check_backlog = true -while true - # Pick the ID based on the iteration: the first time we want to - # read our pending messages, in case we crashed and are recovering. - # Once we consumed our history, we can start getting new messages. - if check_backlog - myid = $lastid - else - myid = '>' - end - - items = r.xreadgroup('GROUP',GroupName,ConsumerName,'BLOCK','2000','COUNT','10','STREAMS',:my_stream_key,myid) - - if items == nil - puts "Timeout!" - next - end - - # If we receive an empty reply, it means we were consuming our history - # and that the history is now empty. Let's start to consume new messages. - check_backlog = false if items[0][1].length == 0 - - items[0][1].each{|i| - id,fields = i - - # Process the message - process_message(id,fields) - - # Acknowledge the message as processed - r.xack(:my_stream_key,GroupName,id) - - $lastid = id - } -end -``` - -As you can see the idea here is to start by consuming the history, that is, our list of pending messages. This is useful because the consumer may have crashed before, so in the event of a restart we want to re-read messages that were delivered to us without getting acknowledged. Note that we might process a message multiple times or one time (at least in the case of consumer failures, but there are also the limits of Redis persistence and replication involved, see the specific section about this topic). - -Once the history was consumed, and we get an empty list of messages, we can switch to using the `>` special ID in order to consume new messages. - -## Recovering from permanent failures - -The example above allows us to write consumers that participate in the same consumer group, each taking a subset of messages to process, and when recovering from failures re-reading the pending messages that were delivered just to them. However in the real world consumers may permanently fail and never recover. What happens to the pending messages of the consumer that never recovers after stopping for any reason? - -Redis consumer groups offer a feature that is used in these situations in order to *claim* the pending messages of a given consumer so that such messages will change ownership and will be re-assigned to a different consumer. The feature is very explicit. A consumer has to inspect the list of pending messages, and will have to claim specific messages using a special command, otherwise the server will leave the messages pending forever and assigned to the old consumer. In this way different applications can choose if to use such a feature or not, and exactly how to use it. - -The first step of this process is just a command that provides observability of pending entries in the consumer group and is called `XPENDING`. -This is a read-only command which is always safe to call and will not change ownership of any message. -In its simplest form, the command is called with two arguments, which are the name of the stream and the name of the consumer group. - -``` -> XPENDING mystream mygroup -1) (integer) 2 -2) 1526569498055-0 -3) 1526569506935-0 -4) 1) 1) "Bob" - 2) "2" -``` - -When called in this way, the command outputs the total number of pending messages in the consumer group (two in this case), the lower and higher message ID among the pending messages, and finally a list of consumers and the number of pending messages they have. -We have only Bob with two pending messages because the single message that Alice requested was acknowledged using `XACK`. - -We can ask for more information by giving more arguments to `XPENDING`, because the full command signature is the following: - -``` -XPENDING [[IDLE ] []] -``` - -By providing a start and end ID (that can be just `-` and `+` as in `XRANGE`) and a count to control the amount of information returned by the command, we are able to know more about the pending messages. The optional final argument, the consumer name, is used if we want to limit the output to just messages pending for a given consumer, but won't use this feature in the following example. - -``` -> XPENDING mystream mygroup - + 10 -1) 1) 1526569498055-0 - 2) "Bob" - 3) (integer) 74170458 - 4) (integer) 1 -2) 1) 1526569506935-0 - 2) "Bob" - 3) (integer) 74170458 - 4) (integer) 1 -``` - -Now we have the details for each message: the ID, the consumer name, the *idle time* in milliseconds, which is how many milliseconds have passed since the last time the message was delivered to some consumer, and finally the number of times that a given message was delivered. -We have two messages from Bob, and they are idle for 74170458 milliseconds, about 20 hours. - -Note that nobody prevents us from checking what the first message content was by just using `XRANGE`. - -``` -> XRANGE mystream 1526569498055-0 1526569498055-0 -1) 1) 1526569498055-0 - 2) 1) "message" - 2) "orange" -``` - -We have just to repeat the same ID twice in the arguments. Now that we have some ideas, Alice may decide that after 20 hours of not processing messages, Bob will probably not recover in time, and it's time to *claim* such messages and resume the processing in place of Bob. To do so, we use the `XCLAIM` command. - -This command is very complex and full of options in its full form, since it is used for replication of consumer groups changes, but we'll use just the arguments that we need normally. In this case it is as simple as: - -``` -XCLAIM ... -``` - -Basically we say, for this specific key and group, I want that the message IDs specified will change ownership, and will be assigned to the specified consumer name ``. However, we also provide a minimum idle time, so that the operation will only work if the idle time of the mentioned messages is greater than the specified idle time. This is useful because maybe two clients are retrying to claim a message at the same time: - -``` -Client 1: XCLAIM mystream mygroup Alice 3600000 1526569498055-0 -Client 2: XCLAIM mystream mygroup Lora 3600000 1526569498055-0 -``` - -However, as a side effect, claiming a message will reset its idle time and will increment its number of deliveries counter, so the second client will fail claiming it. In this way we avoid trivial re-processing of messages (even if in the general case you cannot obtain exactly once processing). - -This is the result of the command execution: - -``` -> XCLAIM mystream mygroup Alice 3600000 1526569498055-0 -1) 1) 1526569498055-0 - 2) 1) "message" - 2) "orange" -``` - -The message was successfully claimed by Alice, who can now process the message and acknowledge it, and move things forward even if the original consumer is not recovering. - -It is clear from the example above that as a side effect of successfully claiming a given message, the `XCLAIM` command also returns it. However this is not mandatory. The **JUSTID** option can be used in order to return just the IDs of the message successfully claimed. This is useful if you want to reduce the bandwidth used between the client and the server (and also the performance of the command) and you are not interested in the message because your consumer is implemented in a way that it will rescan the history of pending messages from time to time. - -Claiming may also be implemented by a separate process: one that just checks the list of pending messages, and assigns idle messages to consumers that appear to be active. Active consumers can be obtained using one of the observability features of Redis streams. This is the topic of the next section. - -## Automatic claiming - -The `XAUTOCLAIM` command, added in Redis 6.2, implements the claiming process that we've described above. -`XPENDING` and `XCLAIM` provide the basic building blocks for different types of recovery mechanisms. -This command optimizes the generic process by having Redis manage it and offers a simple solution for most recovery needs. - -`XAUTOCLAIM` identifies idle pending messages and transfers ownership of them to a consumer. -The command's signature looks like this: - -``` -XAUTOCLAIM [COUNT count] [JUSTID] -``` - -So, in the example above, I could have used automatic claiming to claim a single message like this: - -``` -> XAUTOCLAIM mystream mygroup Alice 3600000 0-0 COUNT 1 -1) 1526569498055-0 -2) 1) 1526569498055-0 - 2) 1) "message" - 2) "orange" -``` - -Like `XCLAIM`, the command replies with an array of the claimed messages, but it also returns a stream ID that allows iterating the pending entries. -The stream ID is a cursor, and I can use it in my next call to continue in claiming idle pending messages: - -``` -> XAUTOCLAIM mystream mygroup Lora 3600000 1526569498055-0 COUNT 1 -1) 0-0 -2) 1) 1526569506935-0 - 2) 1) "message" - 2) "strawberry" -``` -When `XAUTOCLAIM` returns the "0-0" stream ID as a cursor, that means that it reached the end of the consumer group pending entries list. -That doesn't mean that there are no new idle pending messages, so the process continues by calling `XAUTOCLAIM` from the beginning of the stream. - -## Claiming and the delivery counter - -The counter that you observe in the `XPENDING` output is the number of deliveries of each message. The counter is incremented in two ways: when a message is successfully claimed via `XCLAIM` or when an `XREADGROUP` call is used in order to access the history of pending messages. - -When there are failures, it is normal that messages will be delivered multiple times, but eventually they usually get processed and acknowledged. However there might be a problem processing some specific message, because it is corrupted or crafted in a way that triggers a bug in the processing code. In such a case what happens is that consumers will continuously fail to process this particular message. Because we have the counter of the delivery attempts, we can use that counter to detect messages that for some reason are not processable. So once the deliveries counter reaches a given large number that you chose, it is probably wiser to put such messages in another stream and send a notification to the system administrator. This is basically the way that Redis Streams implements the *dead letter* concept. - -## Streams observability - -Messaging systems that lack observability are very hard to work with. Not knowing who is consuming messages, what messages are pending, the set of consumer groups active in a given stream, makes everything opaque. For this reason, Redis Streams and consumer groups have different ways to observe what is happening. We already covered `XPENDING`, which allows us to inspect the list of messages that are under processing at a given moment, together with their idle time and number of deliveries. - -However we may want to do more than that, and the `XINFO` command is an observability interface that can be used with sub-commands in order to get information about streams or consumer groups. - -This command uses subcommands in order to show different information about the status of the stream and its consumer groups. For instance **XINFO STREAM ** reports information about the stream itself. - -``` -> XINFO STREAM mystream - 1) "length" - 2) (integer) 2 - 3) "radix-tree-keys" - 4) (integer) 1 - 5) "radix-tree-nodes" - 6) (integer) 2 - 7) "last-generated-id" - 8) "1638125141232-0" - 9) "max-deleted-entryid" -10) "0-0" -11) "entries-added" -12) (integer) 2 -13) "groups" -14) (integer) 1 -15) "first-entry" -16) 1) "1638125133432-0" - 2) 1) "message" - 2) "apple" -17) "last-entry" -18) 1) "1638125141232-0" - 2) 1) "message" - 2) "banana" -``` - -The output shows information about how the stream is encoded internally, and also shows the first and last message in the stream. Another piece of information available is the number of consumer groups associated with this stream. We can dig further asking for more information about the consumer groups. - -``` -> XINFO GROUPS mystream -1) 1) "name" - 2) "mygroup" - 3) "consumers" - 4) (integer) 2 - 5) "pending" - 6) (integer) 2 - 7) "last-delivered-id" - 8) "1638126030001-0" - 9) "entries-read" - 10) (integer) 2 - 11) "lag" - 12) (integer) 0 -2) 1) "name" - 2) "some-other-group" - 3) "consumers" - 4) (integer) 1 - 5) "pending" - 6) (integer) 0 - 7) "last-delivered-id" - 8) "1638126028070-0" - 9) "entries-read" - 10) (integer) 1 - 11) "lag" - 12) (integer) 1 -``` - -As you can see in this and in the previous output, the `XINFO` command outputs a sequence of field-value items. Because it is an observability command this allows the human user to immediately understand what information is reported, and allows the command to report more information in the future by adding more fields without breaking compatibility with older clients. Other commands that must be more bandwidth efficient, like `XPENDING`, just report the information without the field names. - -The output of the example above, where the **GROUPS** subcommand is used, should be clear observing the field names. We can check in more detail the state of a specific consumer group by checking the consumers that are registered in the group. - -``` -> XINFO CONSUMERS mystream mygroup -1) 1) name - 2) "Alice" - 3) pending - 4) (integer) 1 - 5) idle - 6) (integer) 9104628 -2) 1) name - 2) "Bob" - 3) pending - 4) (integer) 1 - 5) idle - 6) (integer) 83841983 -``` - -In case you do not remember the syntax of the command, just ask the command itself for help: - -``` -> XINFO HELP -1) XINFO [ [value] [opt] ...]. Subcommands are: -2) CONSUMERS -3) Show consumers of . -4) GROUPS -5) Show the stream consumer groups. -6) STREAM [FULL [COUNT ] -7) Show information about the stream. -8) HELP -9) Prints this help. -``` - -## Differences with Kafka (TM) partitions - -Consumer groups in Redis streams may resemble in some way Kafka (TM) partitioning-based consumer groups, however note that Redis streams are, in practical terms, very different. The partitions are only *logical* and the messages are just put into a single Redis key, so the way the different clients are served is based on who is ready to process new messages, and not from which partition clients are reading. For instance, if the consumer C3 at some point fails permanently, Redis will continue to serve C1 and C2 all the new messages arriving, as if now there are only two *logical* partitions. - -Similarly, if a given consumer is much faster at processing messages than the other consumers, this consumer will receive proportionally more messages in the same unit of time. This is possible since Redis tracks all the unacknowledged messages explicitly, and remembers who received which message and the ID of the first message never delivered to any consumer. - -However, this also means that in Redis if you really want to partition messages in the same stream into multiple Redis instances, you have to use multiple keys and some sharding system such as Redis Cluster or some other application-specific sharding system. A single Redis stream is not automatically partitioned to multiple instances. - -We could say that schematically the following is true: - -* If you use 1 stream -> 1 consumer, you are processing messages in order. -* If you use N streams with N consumers, so that only a given consumer hits a subset of the N streams, you can scale the above model of 1 stream -> 1 consumer. -* If you use 1 stream -> N consumers, you are load balancing to N consumers, however in that case, messages about the same logical item may be consumed out of order, because a given consumer may process message 3 faster than another consumer is processing message 4. - -So basically Kafka partitions are more similar to using N different Redis keys, while Redis consumer groups are a server-side load balancing system of messages from a given stream to N different consumers. - -## Capped Streams - -Many applications do not want to collect data into a stream forever. Sometimes it is useful to have at maximum a given number of items inside a stream, other times once a given size is reached, it is useful to move data from Redis to a storage which is not in memory and not as fast but suited to store the history for, potentially, decades to come. Redis streams have some support for this. One is the **MAXLEN** option of the `XADD` command. This option is very simple to use: - -``` -> XADD mystream MAXLEN 2 * value 1 -1526654998691-0 -> XADD mystream MAXLEN 2 * value 2 -1526654999635-0 -> XADD mystream MAXLEN 2 * value 3 -1526655000369-0 -> XLEN mystream -(integer) 2 -> XRANGE mystream - + -1) 1) 1526654999635-0 - 2) 1) "value" - 2) "2" -2) 1) 1526655000369-0 - 2) 1) "value" - 2) "3" -``` - -Using **MAXLEN** the old entries are automatically evicted when the specified length is reached, so that the stream is left at a constant size. There is currently no option to tell the stream to just retain items that are not older than a given period, because such command, in order to run consistently, would potentially block for a long time in order to evict items. Imagine for example what happens if there is an insertion spike, then a long pause, and another insertion, all with the same maximum time. The stream would block to evict the data that became too old during the pause. So it is up to the user to do some planning and understand what is the maximum stream length desired. Moreover, while the length of the stream is proportional to the memory used, trimming by time is less simple to control and anticipate: it depends on the insertion rate which often changes over time (and when it does not change, then to just trim by size is trivial). - -However trimming with **MAXLEN** can be expensive: streams are represented by macro nodes into a radix tree, in order to be very memory efficient. Altering the single macro node, consisting of a few tens of elements, is not optimal. So it's possible to use the command in the following special form: - -``` -XADD mystream MAXLEN ~ 1000 * ... entry fields here ... -``` - -The `~` argument between the **MAXLEN** option and the actual count means, I don't really need this to be exactly 1000 items. It can be 1000 or 1010 or 1030, just make sure to save at least 1000 items. With this argument, the trimming is performed only when we can remove a whole node. This makes it much more efficient, and it is usually what you want. - -There is also the `XTRIM` command, which performs something very similar to what the **MAXLEN** option does above, except that it can be run by itself: - -``` -> XTRIM mystream MAXLEN 10 -``` - -Or, as for the `XADD` option: - -``` -> XTRIM mystream MAXLEN ~ 10 -``` - -However, `XTRIM` is designed to accept different trimming strategies. Another trimming strategy is **MINID**, that evicts entries with IDs lower than the one specified. - -As `XTRIM` is an explicit command, the user is expected to know about the possible shortcomings of different trimming strategies. - -Another useful eviction strategy that may be added to `XTRIM` in the future, is to remove by a range of IDs to ease use of `XRANGE` and `XTRIM` to move data from Redis to other storage systems if needed. - -## Special IDs in the streams API - -You may have noticed that there are several special IDs that can be used in the Redis API. Here is a short recap, so that they can make more sense in the future. - -The first two special IDs are `-` and `+`, and are used in range queries with the `XRANGE` command. Those two IDs respectively mean the smallest ID possible (that is basically `0-1`) and the greatest ID possible (that is `18446744073709551615-18446744073709551615`). As you can see it is a lot cleaner to write `-` and `+` instead of those numbers. - -Then there are APIs where we want to say, the ID of the item with the greatest ID inside the stream. This is what `$` means. So for instance if I want only new entries with `XREADGROUP` I use this ID to signify I already have all the existing entries, but not the new ones that will be inserted in the future. Similarly when I create or set the ID of a consumer group, I can set the last delivered item to `$` in order to just deliver new entries to the consumers in the group. - -As you can see `$` does not mean `+`, they are two different things, as `+` is the greatest ID possible in every possible stream, while `$` is the greatest ID in a given stream containing given entries. Moreover APIs will usually only understand `+` or `$`, yet it was useful to avoid loading a given symbol with multiple meanings. - -Another special ID is `>`, that is a special meaning only related to consumer groups and only when the `XREADGROUP` command is used. This special ID means that we want only entries that were never delivered to other consumers so far. So basically the `>` ID is the *last delivered ID* of a consumer group. - -Finally the special ID `*`, that can be used only with the `XADD` command, means to auto select an ID for us for the new entry. - -So we have `-`, `+`, `$`, `>` and `*`, and all have a different meaning, and most of the time, can be used in different contexts. - -## Persistence, replication and message safety - -A Stream, like any other Redis data structure, is asynchronously replicated to replicas and persisted into AOF and RDB files. However what may not be so obvious is that also the consumer groups full state is propagated to AOF, RDB and replicas, so if a message is pending in the master, also the replica will have the same information. Similarly, after a restart, the AOF will restore the consumer groups' state. - -However note that Redis streams and consumer groups are persisted and replicated using the Redis default replication, so: - -* AOF must be used with a strong fsync policy if persistence of messages is important in your application. -* By default the asynchronous replication will not guarantee that `XADD` commands or consumer groups state changes are replicated: after a failover something can be missing depending on the ability of replicas to receive the data from the master. -* The `WAIT` command may be used in order to force the propagation of the changes to a set of replicas. However note that while this makes it very unlikely that data is lost, the Redis failover process as operated by Sentinel or Redis Cluster performs only a *best effort* check to failover to the replica which is the most updated, and under certain specific failure conditions may promote a replica that lacks some data. - -So when designing an application using Redis streams and consumer groups, make sure to understand the semantical properties your application should have during failures, and configure things accordingly, evaluating whether it is safe enough for your use case. - -## Removing single items from a stream - -Streams also have a special command for removing items from the middle of a stream, just by ID. Normally for an append only data structure this may look like an odd feature, but it is actually useful for applications involving, for instance, privacy regulations. The command is called `XDEL` and receives the name of the stream followed by the IDs to delete: - -``` -> XRANGE mystream - + COUNT 2 -1) 1) 1526654999635-0 - 2) 1) "value" - 2) "2" -2) 1) 1526655000369-0 - 2) 1) "value" - 2) "3" -> XDEL mystream 1526654999635-0 -(integer) 1 -> XRANGE mystream - + COUNT 2 -1) 1) 1526655000369-0 - 2) 1) "value" - 2) "3" -``` - -However in the current implementation, memory is not really reclaimed until a macro node is completely empty, so you should not abuse this feature. - -## Zero length streams - -A difference between streams and other Redis data structures is that when the other data structures no longer have any elements, as a side effect of calling commands that remove elements, the key itself will be removed. So for instance, a sorted set will be completely removed when a call to `ZREM` will remove the last element in the sorted set. Streams, on the other hand, are allowed to stay at zero elements, both as a result of using a **MAXLEN** option with a count of zero (`XADD` and `XTRIM` commands), or because `XDEL` was called. - -The reason why such an asymmetry exists is because Streams may have associated consumer groups, and we do not want to lose the state that the consumer groups defined just because there are no longer any items in the stream. Currently the stream is not deleted even when it has no associated consumer groups. - -## Total latency of consuming a message - -Non blocking stream commands like `XRANGE` and `XREAD` or `XREADGROUP` without the BLOCK option are served synchronously like any other Redis command, so to discuss latency of such commands is meaningless: it is more interesting to check the time complexity of the commands in the Redis documentation. It should be enough to say that stream commands are at least as fast as sorted set commands when extracting ranges, and that `XADD` is very fast and can easily insert from half a million to one million items per second in an average machine if pipelining is used. - -However latency becomes an interesting parameter if we want to understand the delay of processing a message, in the context of blocking consumers in a consumer group, from the moment the message is produced via `XADD`, to the moment the message is obtained by the consumer because `XREADGROUP` returned with the message. - -## How serving blocked consumers works - -Before providing the results of performed tests, it is interesting to understand what model Redis uses in order to route stream messages (and in general actually how any blocking operation waiting for data is managed). - -* The blocked client is referenced in a hash table that maps keys for which there is at least one blocking consumer, to a list of consumers that are waiting for such key. This way, given a key that received data, we can resolve all the clients that are waiting for such data. -* When a write happens, in this case when the `XADD` command is called, it calls the `signalKeyAsReady()` function. This function will put the key into a list of keys that need to be processed, because such keys may have new data for blocked consumers. Note that such *ready keys* will be processed later, so in the course of the same event loop cycle, it is possible that the key will receive other writes. -* Finally, before returning into the event loop, the *ready keys* are finally processed. For each key the list of clients waiting for data is scanned, and if applicable, such clients will receive the new data that arrived. In the case of streams the data is the messages in the applicable range requested by the consumer. - -As you can see, basically, before returning to the event loop both the client calling `XADD` and the clients blocked to consume messages, will have their reply in the output buffers, so the caller of `XADD` should receive the reply from Redis at about the same time the consumers will receive the new messages. - -This model is *push-based*, since adding data to the consumers buffers will be performed directly by the action of calling `XADD`, so the latency tends to be quite predictable. - -## Latency tests results - -In order to check these latency characteristics a test was performed using multiple instances of Ruby programs pushing messages having as an additional field the computer millisecond time, and Ruby programs reading the messages from the consumer group and processing them. The message processing step consisted of comparing the current computer time with the message timestamp, in order to understand the total latency. - -Results obtained: - -``` -Processed between 0 and 1 ms -> 74.11% -Processed between 1 and 2 ms -> 25.80% -Processed between 2 and 3 ms -> 0.06% -Processed between 3 and 4 ms -> 0.01% -Processed between 4 and 5 ms -> 0.02% -``` - -So 99.9% of requests have a latency <= 2 milliseconds, with the outliers that remain still very close to the average. - -Adding a few million unacknowledged messages to the stream does not change the gist of the benchmark, with most queries still processed with very short latency. - -A few remarks: - -* Here we processed up to 10k messages per iteration, this means that the `COUNT` parameter of `XREADGROUP` was set to 10000. This adds a lot of latency but is needed in order to allow the slow consumers to be able to keep with the message flow. So you can expect a real world latency that is a lot smaller. -* The system used for this benchmark is very slow compared to today's standards. diff --git a/docs/data-types/streams.md b/docs/data-types/streams.md index f55469df06..6488c5519a 100644 --- a/docs/data-types/streams.md +++ b/docs/data-types/streams.md @@ -4,9 +4,12 @@ linkTitle: "Streams" weight: 60 description: > Introduction to Redis streams +aliases: + - /topics/streams-intro + - /docs/manual/data-types/streams --- -A Redis stream is a data structure that acts like an append-only log. +A Redis stream is a data structure that acts like an append-only log but also implements several operations to overcome some of the limits of a typical append-only log. These include random access in O(1) time and complex consumption strategies, such as consumer groups. You can use streams to record and simultaneously syndicate events in real time. Examples of Redis stream use cases include: @@ -19,6 +22,15 @@ You can use these IDs to retrieve their associated entries later or to read and Redis streams support several trimming strategies (to prevent streams from growing unbounded) and more than one consumption strategy (see `XREAD`, `XREADGROUP`, and `XRANGE`). +## Basic commands +* `XADD` adds a new entry to a stream. +* `XREAD` reads one or more entries, starting at a given position and moving forward in time. +* `XRANGE` returns a range of entries between two supplied entry IDs. +* `XLEN` returns the length of a stream. + +See the [complete list of stream commands](https://redis.io/commands/?group=stream). + + ## Examples * Add several temperature readings to a stream @@ -56,14 +68,6 @@ Redis streams support several trimming strategies (to prevent streams from growi (nil) ``` -## Basic commands -* `XADD` adds a new entry to a stream. -* `XREAD` reads one or more entries, starting at a given position and moving forward in time. -* `XRANGE` returns a range of entries between two supplied entry IDs. -* `XLEN` returns the length of a stream. - -See the [complete list of stream commands](https://redis.io/commands/?group=stream). - ## Performance Adding an entry to a stream is O(1). @@ -74,6 +78,788 @@ For details on why, note that streams are implemented as [radix trees](https://e Simply put, Redis streams provide highly efficient inserts and reads. See each command's time complexity for the details. + +## Streams basics + +Streams are an append-only data structure. The fundamental write command, called `XADD`, appends a new entry to the specified stream. + +Each stream entry consists of one or more field-value pairs, somewhat like a record or a Redis hash: + +``` +> XADD mystream * sensor-id 1234 temperature 19.8 +1518951480106-0 +``` + +The above call to the `XADD` command adds an entry `sensor-id: 1234, temperature: 19.8` to the stream at key `mystream`, using an auto-generated entry ID, which is the one returned by the command, specifically `1518951480106-0`. It gets as its first argument the key name `mystream`, the second argument is the entry ID that identifies every entry inside a stream. However, in this case, we passed `*` because we want the server to generate a new ID for us. Every new ID will be monotonically increasing, so in more simple terms, every new entry added will have a higher ID compared to all the past entries. Auto-generation of IDs by the server is almost always what you want, and the reasons for specifying an ID explicitly are very rare. We'll talk more about this later. The fact that each Stream entry has an ID is another similarity with log files, where line numbers, or the byte offset inside the file, can be used in order to identify a given entry. Returning back at our `XADD` example, after the key name and ID, the next arguments are the field-value pairs composing our stream entry. + +It is possible to get the number of items inside a Stream just using the `XLEN` command: + +``` +> XLEN mystream +(integer) 1 +``` + +### Entry IDs + +The entry ID returned by the `XADD` command, and identifying univocally each entry inside a given stream, is composed of two parts: + +``` +- +``` + +The milliseconds time part is actually the local time in the local Redis node generating the stream ID, however if the current milliseconds time happens to be smaller than the previous entry time, then the previous entry time is used instead, so if a clock jumps backward the monotonically incrementing ID property still holds. The sequence number is used for entries created in the same millisecond. Since the sequence number is 64 bit wide, in practical terms there is no limit to the number of entries that can be generated within the same millisecond. + +The format of such IDs may look strange at first, and the gentle reader may wonder why the time is part of the ID. The reason is that Redis streams support range queries by ID. Because the ID is related to the time the entry is generated, this gives the ability to query for time ranges basically for free. We will see this soon while covering the `XRANGE` command. + +If for some reason the user needs incremental IDs that are not related to time but are actually associated to another external system ID, as previously mentioned, the `XADD` command can take an explicit ID instead of the `*` wildcard ID that triggers auto-generation, like in the following examples: + +``` +> XADD somestream 0-1 field value +0-1 +> XADD somestream 0-2 foo bar +0-2 +``` + +Note that in this case, the minimum ID is 0-1 and that the command will not accept an ID equal or smaller than a previous one: + +``` +> XADD somestream 0-1 foo bar +(error) ERR The ID specified in XADD is equal or smaller than the target stream top item +``` + +If you're running Redis 7 or later, you can also provide an explicit ID consisting of the milliseconds part only. In this case, the sequence portion of the ID will be automatically generated. To do this, use the syntax below: + +``` +> XADD somestream 0-* baz qux +0-3 +``` + +## Getting data from Streams + +Now we are finally able to append entries in our stream via `XADD`. However, while appending data to a stream is quite obvious, the way streams can be queried in order to extract data is not so obvious. If we continue with the analogy of the log file, one obvious way is to mimic what we normally do with the Unix command `tail -f`, that is, we may start to listen in order to get the new messages that are appended to the stream. Note that unlike the blocking list operations of Redis, where a given element will reach a single client which is blocking in a *pop style* operation like `BLPOP`, with streams we want multiple consumers to see the new messages appended to the stream (the same way many `tail -f` processes can see what is added to a log). Using the traditional terminology we want the streams to be able to *fan out* messages to multiple clients. + +However, this is just one potential access mode. We could also see a stream in quite a different way: not as a messaging system, but as a *time series store*. In this case, maybe it's also useful to get the new messages appended, but another natural query mode is to get messages by ranges of time, or alternatively to iterate the messages using a cursor to incrementally check all the history. This is definitely another useful access mode. + +Finally, if we see a stream from the point of view of consumers, we may want to access the stream in yet another way, that is, as a stream of messages that can be partitioned to multiple consumers that are processing such messages, so that groups of consumers can only see a subset of the messages arriving in a single stream. In this way, it is possible to scale the message processing across different consumers, without single consumers having to process all the messages: each consumer will just get different messages to process. This is basically what Kafka (TM) does with consumer groups. Reading messages via consumer groups is yet another interesting mode of reading from a Redis Stream. + +Redis Streams support all three of the query modes described above via different commands. The next sections will show them all, starting from the simplest and most direct to use: range queries. + +### Querying by range: XRANGE and XREVRANGE + +To query the stream by range we are only required to specify two IDs, *start* and *end*. The range returned will include the elements having start or end as ID, so the range is inclusive. The two special IDs `-` and `+` respectively mean the smallest and the greatest ID possible. + +``` +> XRANGE mystream - + +1) 1) 1518951480106-0 + 2) 1) "sensor-id" + 2) "1234" + 3) "temperature" + 4) "19.8" +2) 1) 1518951482479-0 + 2) 1) "sensor-id" + 2) "9999" + 3) "temperature" + 4) "18.2" +``` + +Each entry returned is an array of two items: the ID and the list of field-value pairs. We already said that the entry IDs have a relation with the time, because the part at the left of the `-` character is the Unix time in milliseconds of the local node that created the stream entry, at the moment the entry was created (however note that streams are replicated with fully specified `XADD` commands, so the replicas will have identical IDs to the master). This means that I could query a range of time using `XRANGE`. In order to do so, however, I may want to omit the sequence part of the ID: if omitted, in the start of the range it will be assumed to be 0, while in the end part it will be assumed to be the maximum sequence number available. This way, querying using just two milliseconds Unix times, we get all the entries that were generated in that range of time, in an inclusive way. For instance, if I want to query a two milliseconds period I could use: + +``` +> XRANGE mystream 1518951480106 1518951480107 +1) 1) 1518951480106-0 + 2) 1) "sensor-id" + 2) "1234" + 3) "temperature" + 4) "19.8" +``` + +I have only a single entry in this range, however in real data sets, I could query for ranges of hours, or there could be many items in just two milliseconds, and the result returned could be huge. For this reason, `XRANGE` supports an optional **COUNT** option at the end. By specifying a count, I can just get the first *N* items. If I want more, I can get the last ID returned, increment the sequence part by one, and query again. Let's see this in the following example. We start adding 10 items with `XADD` (I won't show that, lets assume that the stream `mystream` was populated with 10 items). To start my iteration, getting 2 items per command, I start with the full range, but with a count of 2. + +``` +> XRANGE mystream - + COUNT 2 +1) 1) 1519073278252-0 + 2) 1) "foo" + 2) "value_1" +2) 1) 1519073279157-0 + 2) 1) "foo" + 2) "value_2" +``` + +In order to continue the iteration with the next two items, I have to pick the last ID returned, that is `1519073279157-0` and add the prefix `(` to it. The resulting exclusive range interval, that is `(1519073279157-0` in this case, can now be used as the new *start* argument for the next `XRANGE` call: + +``` +> XRANGE mystream (1519073279157-0 + COUNT 2 +1) 1) 1519073280281-0 + 2) 1) "foo" + 2) "value_3" +2) 1) 1519073281432-0 + 2) 1) "foo" + 2) "value_4" +``` + +And so forth. Since `XRANGE` complexity is *O(log(N))* to seek, and then *O(M)* to return M elements, with a small count the command has a logarithmic time complexity, which means that each step of the iteration is fast. So `XRANGE` is also the de facto *streams iterator* and does not require an **XSCAN** command. + +The command `XREVRANGE` is the equivalent of `XRANGE` but returning the elements in inverted order, so a practical use for `XREVRANGE` is to check what is the last item in a Stream: + +``` +> XREVRANGE mystream + - COUNT 1 +1) 1) 1519073287312-0 + 2) 1) "foo" + 2) "value_10" +``` + +Note that the `XREVRANGE` command takes the *start* and *stop* arguments in reverse order. + +## Listening for new items with XREAD + +When we do not want to access items by a range in a stream, usually what we want instead is to *subscribe* to new items arriving to the stream. This concept may appear related to Redis Pub/Sub, where you subscribe to a channel, or to Redis blocking lists, where you wait for a key to get new elements to fetch, but there are fundamental differences in the way you consume a stream: + +1. A stream can have multiple clients (consumers) waiting for data. Every new item, by default, will be delivered to *every consumer* that is waiting for data in a given stream. This behavior is different than blocking lists, where each consumer will get a different element. However, the ability to *fan out* to multiple consumers is similar to Pub/Sub. +2. While in Pub/Sub messages are *fire and forget* and are never stored anyway, and while when using blocking lists, when a message is received by the client it is *popped* (effectively removed) from the list, streams work in a fundamentally different way. All the messages are appended in the stream indefinitely (unless the user explicitly asks to delete entries): different consumers will know what is a new message from its point of view by remembering the ID of the last message received. +3. Streams Consumer Groups provide a level of control that Pub/Sub or blocking lists cannot achieve, with different groups for the same stream, explicit acknowledgment of processed items, ability to inspect the pending items, claiming of unprocessed messages, and coherent history visibility for each single client, that is only able to see its private past history of messages. + +The command that provides the ability to listen for new messages arriving into a stream is called `XREAD`. It's a bit more complex than `XRANGE`, so we'll start showing simple forms, and later the whole command layout will be provided. + +``` +> XREAD COUNT 2 STREAMS mystream 0 +1) 1) "mystream" + 2) 1) 1) 1519073278252-0 + 2) 1) "foo" + 2) "value_1" + 2) 1) 1519073279157-0 + 2) 1) "foo" + 2) "value_2" +``` + +The above is the non-blocking form of `XREAD`. Note that the **COUNT** option is not mandatory, in fact the only mandatory option of the command is the **STREAMS** option, that specifies a list of keys together with the corresponding maximum ID already seen for each stream by the calling consumer, so that the command will provide the client only with messages with an ID greater than the one we specified. + +In the above command we wrote `STREAMS mystream 0` so we want all the messages in the Stream `mystream` having an ID greater than `0-0`. As you can see in the example above, the command returns the key name, because actually it is possible to call this command with more than one key to read from different streams at the same time. I could write, for instance: `STREAMS mystream otherstream 0 0`. Note how after the **STREAMS** option we need to provide the key names, and later the IDs. For this reason, the **STREAMS** option must always be the last option. +Any other options must come before the **STREAMS** option. + +Apart from the fact that `XREAD` can access multiple streams at once, and that we are able to specify the last ID we own to just get newer messages, in this simple form the command is not doing something so different compared to `XRANGE`. However, the interesting part is that we can turn `XREAD` into a *blocking command* easily, by specifying the **BLOCK** argument: + +``` +> XREAD BLOCK 0 STREAMS mystream $ +``` + +Note that in the example above, other than removing **COUNT**, I specified the new **BLOCK** option with a timeout of 0 milliseconds (that means to never timeout). Moreover, instead of passing a normal ID for the stream `mystream` I passed the special ID `$`. This special ID means that `XREAD` should use as last ID the maximum ID already stored in the stream `mystream`, so that we will receive only *new* messages, starting from the time we started listening. This is similar to the `tail -f` Unix command in some way. + +Note that when the **BLOCK** option is used, we do not have to use the special ID `$`. We can use any valid ID. If the command is able to serve our request immediately without blocking, it will do so, otherwise it will block. Normally if we want to consume the stream starting from new entries, we start with the ID `$`, and after that we continue using the ID of the last message received to make the next call, and so forth. + +The blocking form of `XREAD` is also able to listen to multiple Streams, just by specifying multiple key names. If the request can be served synchronously because there is at least one stream with elements greater than the corresponding ID we specified, it returns with the results. Otherwise, the command will block and will return the items of the first stream which gets new data (according to the specified ID). + +Similarly to blocking list operations, blocking stream reads are *fair* from the point of view of clients waiting for data, since the semantics is FIFO style. The first client that blocked for a given stream will be the first to be unblocked when new items are available. + +`XREAD` has no other options than **COUNT** and **BLOCK**, so it's a pretty basic command with a specific purpose to attach consumers to one or multiple streams. More powerful features to consume streams are available using the consumer groups API, however reading via consumer groups is implemented by a different command called `XREADGROUP`, covered in the next section of this guide. + +## Consumer groups + +When the task at hand is to consume the same stream from different clients, then `XREAD` already offers a way to *fan-out* to N clients, potentially also using replicas in order to provide more read scalability. However in certain problems what we want to do is not to provide the same stream of messages to many clients, but to provide a *different subset* of messages from the same stream to many clients. An obvious case where this is useful is that of messages which are slow to process: the ability to have N different workers that will receive different parts of the stream allows us to scale message processing, by routing different messages to different workers that are ready to do more work. + +In practical terms, if we imagine having three consumers C1, C2, C3, and a stream that contains the messages 1, 2, 3, 4, 5, 6, 7 then what we want is to serve the messages according to the following diagram: + +``` +1 -> C1 +2 -> C2 +3 -> C3 +4 -> C1 +5 -> C2 +6 -> C3 +7 -> C1 +``` + +In order to achieve this, Redis uses a concept called *consumer groups*. It is very important to understand that Redis consumer groups have nothing to do, from an implementation standpoint, with Kafka (TM) consumer groups. Yet they are similar in functionality, so I decided to keep Kafka's (TM) terminology, as it originally popularized this idea. + +A consumer group is like a *pseudo consumer* that gets data from a stream, and actually serves multiple consumers, providing certain guarantees: + +1. Each message is served to a different consumer so that it is not possible that the same message will be delivered to multiple consumers. +2. Consumers are identified, within a consumer group, by a name, which is a case-sensitive string that the clients implementing consumers must choose. This means that even after a disconnect, the stream consumer group retains all the state, since the client will claim again to be the same consumer. However, this also means that it is up to the client to provide a unique identifier. +3. Each consumer group has the concept of the *first ID never consumed* so that, when a consumer asks for new messages, it can provide just messages that were not previously delivered. +4. Consuming a message, however, requires an explicit acknowledgment using a specific command. Redis interprets the acknowledgment as: this message was correctly processed so it can be evicted from the consumer group. +5. A consumer group tracks all the messages that are currently pending, that is, messages that were delivered to some consumer of the consumer group, but are yet to be acknowledged as processed. Thanks to this feature, when accessing the message history of a stream, each consumer *will only see messages that were delivered to it*. + +In a way, a consumer group can be imagined as some *amount of state* about a stream: + +``` ++----------------------------------------+ +| consumer_group_name: mygroup | +| consumer_group_stream: somekey | +| last_delivered_id: 1292309234234-92 | +| | +| consumers: | +| "consumer-1" with pending messages | +| 1292309234234-4 | +| 1292309234232-8 | +| "consumer-42" with pending messages | +| ... (and so forth) | ++----------------------------------------+ +``` + +If you see this from this point of view, it is very simple to understand what a consumer group can do, how it is able to just provide consumers with their history of pending messages, and how consumers asking for new messages will just be served with message IDs greater than `last_delivered_id`. At the same time, if you look at the consumer group as an auxiliary data structure for Redis streams, it is obvious that a single stream can have multiple consumer groups, that have a different set of consumers. Actually, it is even possible for the same stream to have clients reading without consumer groups via `XREAD`, and clients reading via `XREADGROUP` in different consumer groups. + +Now it's time to zoom in to see the fundamental consumer group commands. They are the following: + +* `XGROUP` is used in order to create, destroy and manage consumer groups. +* `XREADGROUP` is used to read from a stream via a consumer group. +* `XACK` is the command that allows a consumer to mark a pending message as correctly processed. + +## Creating a consumer group + +Assuming I have a key `mystream` of type stream already existing, in order to create a consumer group I just need to do the following: + +``` +> XGROUP CREATE mystream mygroup $ +OK +``` + +As you can see in the command above when creating the consumer group we have to specify an ID, which in the example is just `$`. This is needed because the consumer group, among the other states, must have an idea about what message to serve next at the first consumer connecting, that is, what was the *last message ID* when the group was just created. If we provide `$` as we did, then only new messages arriving in the stream from now on will be provided to the consumers in the group. If we specify `0` instead the consumer group will consume *all* the messages in the stream history to start with. Of course, you can specify any other valid ID. What you know is that the consumer group will start delivering messages that are greater than the ID you specify. Because `$` means the current greatest ID in the stream, specifying `$` will have the effect of consuming only new messages. + +`XGROUP CREATE` also supports creating the stream automatically, if it doesn't exist, using the optional `MKSTREAM` subcommand as the last argument: + +``` +> XGROUP CREATE newstream mygroup $ MKSTREAM +OK +``` + +Now that the consumer group is created we can immediately try to read messages via the consumer group using the `XREADGROUP` command. We'll read from consumers, that we will call Alice and Bob, to see how the system will return different messages to Alice or Bob. + +`XREADGROUP` is very similar to `XREAD` and provides the same **BLOCK** option, otherwise it is a synchronous command. However there is a *mandatory* option that must be always specified, which is **GROUP** and has two arguments: the name of the consumer group, and the name of the consumer that is attempting to read. The option **COUNT** is also supported and is identical to the one in `XREAD`. + +Before reading from the stream, let's put some messages inside: + +``` +> XADD mystream * message apple +1526569495631-0 +> XADD mystream * message orange +1526569498055-0 +> XADD mystream * message strawberry +1526569506935-0 +> XADD mystream * message apricot +1526569535168-0 +> XADD mystream * message banana +1526569544280-0 +``` + +Note: *here message is the field name, and the fruit is the associated value, remember that stream items are small dictionaries.* + +It is time to try reading something using the consumer group: + +``` +> XREADGROUP GROUP mygroup Alice COUNT 1 STREAMS mystream > +1) 1) "mystream" + 2) 1) 1) 1526569495631-0 + 2) 1) "message" + 2) "apple" +``` + +`XREADGROUP` replies are just like `XREAD` replies. Note however the `GROUP ` provided above. It states that I want to read from the stream using the consumer group `mygroup` and I'm the consumer `Alice`. Every time a consumer performs an operation with a consumer group, it must specify its name, uniquely identifying this consumer inside the group. + +There is another very important detail in the command line above, after the mandatory **STREAMS** option the ID requested for the key `mystream` is the special ID `>`. This special ID is only valid in the context of consumer groups, and it means: **messages never delivered to other consumers so far**. + +This is almost always what you want, however it is also possible to specify a real ID, such as `0` or any other valid ID, in this case, however, what happens is that we request from `XREADGROUP` to just provide us with the **history of pending messages**, and in such case, will never see new messages in the group. So basically `XREADGROUP` has the following behavior based on the ID we specify: + +* If the ID is the special ID `>` then the command will return only new messages never delivered to other consumers so far, and as a side effect, will update the consumer group's *last ID*. +* If the ID is any other valid numerical ID, then the command will let us access our *history of pending messages*. That is, the set of messages that were delivered to this specified consumer (identified by the provided name), and never acknowledged so far with `XACK`. + +We can test this behavior immediately specifying an ID of 0, without any **COUNT** option: we'll just see the only pending message, that is, the one about apples: + +``` +> XREADGROUP GROUP mygroup Alice STREAMS mystream 0 +1) 1) "mystream" + 2) 1) 1) 1526569495631-0 + 2) 1) "message" + 2) "apple" +``` + +However, if we acknowledge the message as processed, it will no longer be part of the pending messages history, so the system will no longer report anything: + +``` +> XACK mystream mygroup 1526569495631-0 +(integer) 1 +> XREADGROUP GROUP mygroup Alice STREAMS mystream 0 +1) 1) "mystream" + 2) (empty list or set) +``` + +Don't worry if you yet don't know how `XACK` works, the idea is just that processed messages are no longer part of the history that we can access. + +Now it's Bob's turn to read something: + +``` +> XREADGROUP GROUP mygroup Bob COUNT 2 STREAMS mystream > +1) 1) "mystream" + 2) 1) 1) 1526569498055-0 + 2) 1) "message" + 2) "orange" + 2) 1) 1526569506935-0 + 2) 1) "message" + 2) "strawberry" +``` + +Bob asked for a maximum of two messages and is reading via the same group `mygroup`. So what happens is that Redis reports just *new* messages. As you can see the "apple" message is not delivered, since it was already delivered to Alice, so Bob gets orange and strawberry, and so forth. + +This way Alice, Bob, and any other consumer in the group, are able to read different messages from the same stream, to read their history of yet to process messages, or to mark messages as processed. This allows creating different topologies and semantics for consuming messages from a stream. + +There are a few things to keep in mind: + +* Consumers are auto-created the first time they are mentioned, no need for explicit creation. +* Even with `XREADGROUP` you can read from multiple keys at the same time, however for this to work, you need to create a consumer group with the same name in every stream. This is not a common need, but it is worth mentioning that the feature is technically available. +* `XREADGROUP` is a *write command* because even if it reads from the stream, the consumer group is modified as a side effect of reading, so it can only be called on master instances. + +An example of a consumer implementation, using consumer groups, written in the Ruby language could be the following. The Ruby code is aimed to be readable by virtually any experienced programmer, even if they do not know Ruby: + +```ruby +require 'redis' + +if ARGV.length == 0 + puts "Please specify a consumer name" + exit 1 +end + +ConsumerName = ARGV[0] +GroupName = "mygroup" +r = Redis.new + +def process_message(id,msg) + puts "[#{ConsumerName}] #{id} = #{msg.inspect}" +end + +$lastid = '0-0' + +puts "Consumer #{ConsumerName} starting..." +check_backlog = true +while true + # Pick the ID based on the iteration: the first time we want to + # read our pending messages, in case we crashed and are recovering. + # Once we consumed our history, we can start getting new messages. + if check_backlog + myid = $lastid + else + myid = '>' + end + + items = r.xreadgroup('GROUP',GroupName,ConsumerName,'BLOCK','2000','COUNT','10','STREAMS',:my_stream_key,myid) + + if items == nil + puts "Timeout!" + next + end + + # If we receive an empty reply, it means we were consuming our history + # and that the history is now empty. Let's start to consume new messages. + check_backlog = false if items[0][1].length == 0 + + items[0][1].each{|i| + id,fields = i + + # Process the message + process_message(id,fields) + + # Acknowledge the message as processed + r.xack(:my_stream_key,GroupName,id) + + $lastid = id + } +end +``` + +As you can see the idea here is to start by consuming the history, that is, our list of pending messages. This is useful because the consumer may have crashed before, so in the event of a restart we want to re-read messages that were delivered to us without getting acknowledged. Note that we might process a message multiple times or one time (at least in the case of consumer failures, but there are also the limits of Redis persistence and replication involved, see the specific section about this topic). + +Once the history was consumed, and we get an empty list of messages, we can switch to using the `>` special ID in order to consume new messages. + +## Recovering from permanent failures + +The example above allows us to write consumers that participate in the same consumer group, each taking a subset of messages to process, and when recovering from failures re-reading the pending messages that were delivered just to them. However in the real world consumers may permanently fail and never recover. What happens to the pending messages of the consumer that never recovers after stopping for any reason? + +Redis consumer groups offer a feature that is used in these situations in order to *claim* the pending messages of a given consumer so that such messages will change ownership and will be re-assigned to a different consumer. The feature is very explicit. A consumer has to inspect the list of pending messages, and will have to claim specific messages using a special command, otherwise the server will leave the messages pending forever and assigned to the old consumer. In this way different applications can choose if to use such a feature or not, and exactly how to use it. + +The first step of this process is just a command that provides observability of pending entries in the consumer group and is called `XPENDING`. +This is a read-only command which is always safe to call and will not change ownership of any message. +In its simplest form, the command is called with two arguments, which are the name of the stream and the name of the consumer group. + +``` +> XPENDING mystream mygroup +1) (integer) 2 +2) 1526569498055-0 +3) 1526569506935-0 +4) 1) 1) "Bob" + 2) "2" +``` + +When called in this way, the command outputs the total number of pending messages in the consumer group (two in this case), the lower and higher message ID among the pending messages, and finally a list of consumers and the number of pending messages they have. +We have only Bob with two pending messages because the single message that Alice requested was acknowledged using `XACK`. + +We can ask for more information by giving more arguments to `XPENDING`, because the full command signature is the following: + +``` +XPENDING [[IDLE ] []] +``` + +By providing a start and end ID (that can be just `-` and `+` as in `XRANGE`) and a count to control the amount of information returned by the command, we are able to know more about the pending messages. The optional final argument, the consumer name, is used if we want to limit the output to just messages pending for a given consumer, but won't use this feature in the following example. + +``` +> XPENDING mystream mygroup - + 10 +1) 1) 1526569498055-0 + 2) "Bob" + 3) (integer) 74170458 + 4) (integer) 1 +2) 1) 1526569506935-0 + 2) "Bob" + 3) (integer) 74170458 + 4) (integer) 1 +``` + +Now we have the details for each message: the ID, the consumer name, the *idle time* in milliseconds, which is how many milliseconds have passed since the last time the message was delivered to some consumer, and finally the number of times that a given message was delivered. +We have two messages from Bob, and they are idle for 74170458 milliseconds, about 20 hours. + +Note that nobody prevents us from checking what the first message content was by just using `XRANGE`. + +``` +> XRANGE mystream 1526569498055-0 1526569498055-0 +1) 1) 1526569498055-0 + 2) 1) "message" + 2) "orange" +``` + +We have just to repeat the same ID twice in the arguments. Now that we have some ideas, Alice may decide that after 20 hours of not processing messages, Bob will probably not recover in time, and it's time to *claim* such messages and resume the processing in place of Bob. To do so, we use the `XCLAIM` command. + +This command is very complex and full of options in its full form, since it is used for replication of consumer groups changes, but we'll use just the arguments that we need normally. In this case it is as simple as: + +``` +XCLAIM ... +``` + +Basically we say, for this specific key and group, I want that the message IDs specified will change ownership, and will be assigned to the specified consumer name ``. However, we also provide a minimum idle time, so that the operation will only work if the idle time of the mentioned messages is greater than the specified idle time. This is useful because maybe two clients are retrying to claim a message at the same time: + +``` +Client 1: XCLAIM mystream mygroup Alice 3600000 1526569498055-0 +Client 2: XCLAIM mystream mygroup Lora 3600000 1526569498055-0 +``` + +However, as a side effect, claiming a message will reset its idle time and will increment its number of deliveries counter, so the second client will fail claiming it. In this way we avoid trivial re-processing of messages (even if in the general case you cannot obtain exactly once processing). + +This is the result of the command execution: + +``` +> XCLAIM mystream mygroup Alice 3600000 1526569498055-0 +1) 1) 1526569498055-0 + 2) 1) "message" + 2) "orange" +``` + +The message was successfully claimed by Alice, who can now process the message and acknowledge it, and move things forward even if the original consumer is not recovering. + +It is clear from the example above that as a side effect of successfully claiming a given message, the `XCLAIM` command also returns it. However this is not mandatory. The **JUSTID** option can be used in order to return just the IDs of the message successfully claimed. This is useful if you want to reduce the bandwidth used between the client and the server (and also the performance of the command) and you are not interested in the message because your consumer is implemented in a way that it will rescan the history of pending messages from time to time. + +Claiming may also be implemented by a separate process: one that just checks the list of pending messages, and assigns idle messages to consumers that appear to be active. Active consumers can be obtained using one of the observability features of Redis streams. This is the topic of the next section. + +## Automatic claiming + +The `XAUTOCLAIM` command, added in Redis 6.2, implements the claiming process that we've described above. +`XPENDING` and `XCLAIM` provide the basic building blocks for different types of recovery mechanisms. +This command optimizes the generic process by having Redis manage it and offers a simple solution for most recovery needs. + +`XAUTOCLAIM` identifies idle pending messages and transfers ownership of them to a consumer. +The command's signature looks like this: + +``` +XAUTOCLAIM [COUNT count] [JUSTID] +``` + +So, in the example above, I could have used automatic claiming to claim a single message like this: + +``` +> XAUTOCLAIM mystream mygroup Alice 3600000 0-0 COUNT 1 +1) 1526569498055-0 +2) 1) 1526569498055-0 + 2) 1) "message" + 2) "orange" +``` + +Like `XCLAIM`, the command replies with an array of the claimed messages, but it also returns a stream ID that allows iterating the pending entries. +The stream ID is a cursor, and I can use it in my next call to continue in claiming idle pending messages: + +``` +> XAUTOCLAIM mystream mygroup Lora 3600000 1526569498055-0 COUNT 1 +1) 0-0 +2) 1) 1526569506935-0 + 2) 1) "message" + 2) "strawberry" +``` +When `XAUTOCLAIM` returns the "0-0" stream ID as a cursor, that means that it reached the end of the consumer group pending entries list. +That doesn't mean that there are no new idle pending messages, so the process continues by calling `XAUTOCLAIM` from the beginning of the stream. + +## Claiming and the delivery counter + +The counter that you observe in the `XPENDING` output is the number of deliveries of each message. The counter is incremented in two ways: when a message is successfully claimed via `XCLAIM` or when an `XREADGROUP` call is used in order to access the history of pending messages. + +When there are failures, it is normal that messages will be delivered multiple times, but eventually they usually get processed and acknowledged. However there might be a problem processing some specific message, because it is corrupted or crafted in a way that triggers a bug in the processing code. In such a case what happens is that consumers will continuously fail to process this particular message. Because we have the counter of the delivery attempts, we can use that counter to detect messages that for some reason are not processable. So once the deliveries counter reaches a given large number that you chose, it is probably wiser to put such messages in another stream and send a notification to the system administrator. This is basically the way that Redis Streams implements the *dead letter* concept. + +## Streams observability + +Messaging systems that lack observability are very hard to work with. Not knowing who is consuming messages, what messages are pending, the set of consumer groups active in a given stream, makes everything opaque. For this reason, Redis Streams and consumer groups have different ways to observe what is happening. We already covered `XPENDING`, which allows us to inspect the list of messages that are under processing at a given moment, together with their idle time and number of deliveries. + +However we may want to do more than that, and the `XINFO` command is an observability interface that can be used with sub-commands in order to get information about streams or consumer groups. + +This command uses subcommands in order to show different information about the status of the stream and its consumer groups. For instance **XINFO STREAM ** reports information about the stream itself. + +``` +> XINFO STREAM mystream + 1) "length" + 2) (integer) 2 + 3) "radix-tree-keys" + 4) (integer) 1 + 5) "radix-tree-nodes" + 6) (integer) 2 + 7) "last-generated-id" + 8) "1638125141232-0" + 9) "max-deleted-entryid" +10) "0-0" +11) "entries-added" +12) (integer) 2 +13) "groups" +14) (integer) 1 +15) "first-entry" +16) 1) "1638125133432-0" + 2) 1) "message" + 2) "apple" +17) "last-entry" +18) 1) "1638125141232-0" + 2) 1) "message" + 2) "banana" +``` + +The output shows information about how the stream is encoded internally, and also shows the first and last message in the stream. Another piece of information available is the number of consumer groups associated with this stream. We can dig further asking for more information about the consumer groups. + +``` +> XINFO GROUPS mystream +1) 1) "name" + 2) "mygroup" + 3) "consumers" + 4) (integer) 2 + 5) "pending" + 6) (integer) 2 + 7) "last-delivered-id" + 8) "1638126030001-0" + 9) "entries-read" + 10) (integer) 2 + 11) "lag" + 12) (integer) 0 +2) 1) "name" + 2) "some-other-group" + 3) "consumers" + 4) (integer) 1 + 5) "pending" + 6) (integer) 0 + 7) "last-delivered-id" + 8) "1638126028070-0" + 9) "entries-read" + 10) (integer) 1 + 11) "lag" + 12) (integer) 1 +``` + +As you can see in this and in the previous output, the `XINFO` command outputs a sequence of field-value items. Because it is an observability command this allows the human user to immediately understand what information is reported, and allows the command to report more information in the future by adding more fields without breaking compatibility with older clients. Other commands that must be more bandwidth efficient, like `XPENDING`, just report the information without the field names. + +The output of the example above, where the **GROUPS** subcommand is used, should be clear observing the field names. We can check in more detail the state of a specific consumer group by checking the consumers that are registered in the group. + +``` +> XINFO CONSUMERS mystream mygroup +1) 1) name + 2) "Alice" + 3) pending + 4) (integer) 1 + 5) idle + 6) (integer) 9104628 +2) 1) name + 2) "Bob" + 3) pending + 4) (integer) 1 + 5) idle + 6) (integer) 83841983 +``` + +In case you do not remember the syntax of the command, just ask the command itself for help: + +``` +> XINFO HELP +1) XINFO [ [value] [opt] ...]. Subcommands are: +2) CONSUMERS +3) Show consumers of . +4) GROUPS +5) Show the stream consumer groups. +6) STREAM [FULL [COUNT ] +7) Show information about the stream. +8) HELP +9) Prints this help. +``` + +## Differences with Kafka (TM) partitions + +Consumer groups in Redis streams may resemble in some way Kafka (TM) partitioning-based consumer groups, however note that Redis streams are, in practical terms, very different. The partitions are only *logical* and the messages are just put into a single Redis key, so the way the different clients are served is based on who is ready to process new messages, and not from which partition clients are reading. For instance, if the consumer C3 at some point fails permanently, Redis will continue to serve C1 and C2 all the new messages arriving, as if now there are only two *logical* partitions. + +Similarly, if a given consumer is much faster at processing messages than the other consumers, this consumer will receive proportionally more messages in the same unit of time. This is possible since Redis tracks all the unacknowledged messages explicitly, and remembers who received which message and the ID of the first message never delivered to any consumer. + +However, this also means that in Redis if you really want to partition messages in the same stream into multiple Redis instances, you have to use multiple keys and some sharding system such as Redis Cluster or some other application-specific sharding system. A single Redis stream is not automatically partitioned to multiple instances. + +We could say that schematically the following is true: + +* If you use 1 stream -> 1 consumer, you are processing messages in order. +* If you use N streams with N consumers, so that only a given consumer hits a subset of the N streams, you can scale the above model of 1 stream -> 1 consumer. +* If you use 1 stream -> N consumers, you are load balancing to N consumers, however in that case, messages about the same logical item may be consumed out of order, because a given consumer may process message 3 faster than another consumer is processing message 4. + +So basically Kafka partitions are more similar to using N different Redis keys, while Redis consumer groups are a server-side load balancing system of messages from a given stream to N different consumers. + +## Capped Streams + +Many applications do not want to collect data into a stream forever. Sometimes it is useful to have at maximum a given number of items inside a stream, other times once a given size is reached, it is useful to move data from Redis to a storage which is not in memory and not as fast but suited to store the history for, potentially, decades to come. Redis streams have some support for this. One is the **MAXLEN** option of the `XADD` command. This option is very simple to use: + +``` +> XADD mystream MAXLEN 2 * value 1 +1526654998691-0 +> XADD mystream MAXLEN 2 * value 2 +1526654999635-0 +> XADD mystream MAXLEN 2 * value 3 +1526655000369-0 +> XLEN mystream +(integer) 2 +> XRANGE mystream - + +1) 1) 1526654999635-0 + 2) 1) "value" + 2) "2" +2) 1) 1526655000369-0 + 2) 1) "value" + 2) "3" +``` + +Using **MAXLEN** the old entries are automatically evicted when the specified length is reached, so that the stream is left at a constant size. There is currently no option to tell the stream to just retain items that are not older than a given period, because such command, in order to run consistently, would potentially block for a long time in order to evict items. Imagine for example what happens if there is an insertion spike, then a long pause, and another insertion, all with the same maximum time. The stream would block to evict the data that became too old during the pause. So it is up to the user to do some planning and understand what is the maximum stream length desired. Moreover, while the length of the stream is proportional to the memory used, trimming by time is less simple to control and anticipate: it depends on the insertion rate which often changes over time (and when it does not change, then to just trim by size is trivial). + +However trimming with **MAXLEN** can be expensive: streams are represented by macro nodes into a radix tree, in order to be very memory efficient. Altering the single macro node, consisting of a few tens of elements, is not optimal. So it's possible to use the command in the following special form: + +``` +XADD mystream MAXLEN ~ 1000 * ... entry fields here ... +``` + +The `~` argument between the **MAXLEN** option and the actual count means, I don't really need this to be exactly 1000 items. It can be 1000 or 1010 or 1030, just make sure to save at least 1000 items. With this argument, the trimming is performed only when we can remove a whole node. This makes it much more efficient, and it is usually what you want. + +There is also the `XTRIM` command, which performs something very similar to what the **MAXLEN** option does above, except that it can be run by itself: + +``` +> XTRIM mystream MAXLEN 10 +``` + +Or, as for the `XADD` option: + +``` +> XTRIM mystream MAXLEN ~ 10 +``` + +However, `XTRIM` is designed to accept different trimming strategies. Another trimming strategy is **MINID**, that evicts entries with IDs lower than the one specified. + +As `XTRIM` is an explicit command, the user is expected to know about the possible shortcomings of different trimming strategies. + +Another useful eviction strategy that may be added to `XTRIM` in the future, is to remove by a range of IDs to ease use of `XRANGE` and `XTRIM` to move data from Redis to other storage systems if needed. + +## Special IDs in the streams API + +You may have noticed that there are several special IDs that can be used in the Redis API. Here is a short recap, so that they can make more sense in the future. + +The first two special IDs are `-` and `+`, and are used in range queries with the `XRANGE` command. Those two IDs respectively mean the smallest ID possible (that is basically `0-1`) and the greatest ID possible (that is `18446744073709551615-18446744073709551615`). As you can see it is a lot cleaner to write `-` and `+` instead of those numbers. + +Then there are APIs where we want to say, the ID of the item with the greatest ID inside the stream. This is what `$` means. So for instance if I want only new entries with `XREADGROUP` I use this ID to signify I already have all the existing entries, but not the new ones that will be inserted in the future. Similarly when I create or set the ID of a consumer group, I can set the last delivered item to `$` in order to just deliver new entries to the consumers in the group. + +As you can see `$` does not mean `+`, they are two different things, as `+` is the greatest ID possible in every possible stream, while `$` is the greatest ID in a given stream containing given entries. Moreover APIs will usually only understand `+` or `$`, yet it was useful to avoid loading a given symbol with multiple meanings. + +Another special ID is `>`, that is a special meaning only related to consumer groups and only when the `XREADGROUP` command is used. This special ID means that we want only entries that were never delivered to other consumers so far. So basically the `>` ID is the *last delivered ID* of a consumer group. + +Finally the special ID `*`, that can be used only with the `XADD` command, means to auto select an ID for us for the new entry. + +So we have `-`, `+`, `$`, `>` and `*`, and all have a different meaning, and most of the time, can be used in different contexts. + +## Persistence, replication and message safety + +A Stream, like any other Redis data structure, is asynchronously replicated to replicas and persisted into AOF and RDB files. However what may not be so obvious is that also the consumer groups full state is propagated to AOF, RDB and replicas, so if a message is pending in the master, also the replica will have the same information. Similarly, after a restart, the AOF will restore the consumer groups' state. + +However note that Redis streams and consumer groups are persisted and replicated using the Redis default replication, so: + +* AOF must be used with a strong fsync policy if persistence of messages is important in your application. +* By default the asynchronous replication will not guarantee that `XADD` commands or consumer groups state changes are replicated: after a failover something can be missing depending on the ability of replicas to receive the data from the master. +* The `WAIT` command may be used in order to force the propagation of the changes to a set of replicas. However note that while this makes it very unlikely that data is lost, the Redis failover process as operated by Sentinel or Redis Cluster performs only a *best effort* check to failover to the replica which is the most updated, and under certain specific failure conditions may promote a replica that lacks some data. + +So when designing an application using Redis streams and consumer groups, make sure to understand the semantical properties your application should have during failures, and configure things accordingly, evaluating whether it is safe enough for your use case. + +## Removing single items from a stream + +Streams also have a special command for removing items from the middle of a stream, just by ID. Normally for an append only data structure this may look like an odd feature, but it is actually useful for applications involving, for instance, privacy regulations. The command is called `XDEL` and receives the name of the stream followed by the IDs to delete: + +``` +> XRANGE mystream - + COUNT 2 +1) 1) 1526654999635-0 + 2) 1) "value" + 2) "2" +2) 1) 1526655000369-0 + 2) 1) "value" + 2) "3" +> XDEL mystream 1526654999635-0 +(integer) 1 +> XRANGE mystream - + COUNT 2 +1) 1) 1526655000369-0 + 2) 1) "value" + 2) "3" +``` + +However in the current implementation, memory is not really reclaimed until a macro node is completely empty, so you should not abuse this feature. + +## Zero length streams + +A difference between streams and other Redis data structures is that when the other data structures no longer have any elements, as a side effect of calling commands that remove elements, the key itself will be removed. So for instance, a sorted set will be completely removed when a call to `ZREM` will remove the last element in the sorted set. Streams, on the other hand, are allowed to stay at zero elements, both as a result of using a **MAXLEN** option with a count of zero (`XADD` and `XTRIM` commands), or because `XDEL` was called. + +The reason why such an asymmetry exists is because Streams may have associated consumer groups, and we do not want to lose the state that the consumer groups defined just because there are no longer any items in the stream. Currently the stream is not deleted even when it has no associated consumer groups. + +## Total latency of consuming a message + +Non blocking stream commands like `XRANGE` and `XREAD` or `XREADGROUP` without the BLOCK option are served synchronously like any other Redis command, so to discuss latency of such commands is meaningless: it is more interesting to check the time complexity of the commands in the Redis documentation. It should be enough to say that stream commands are at least as fast as sorted set commands when extracting ranges, and that `XADD` is very fast and can easily insert from half a million to one million items per second in an average machine if pipelining is used. + +However latency becomes an interesting parameter if we want to understand the delay of processing a message, in the context of blocking consumers in a consumer group, from the moment the message is produced via `XADD`, to the moment the message is obtained by the consumer because `XREADGROUP` returned with the message. + +## How serving blocked consumers works + +Before providing the results of performed tests, it is interesting to understand what model Redis uses in order to route stream messages (and in general actually how any blocking operation waiting for data is managed). + +* The blocked client is referenced in a hash table that maps keys for which there is at least one blocking consumer, to a list of consumers that are waiting for such key. This way, given a key that received data, we can resolve all the clients that are waiting for such data. +* When a write happens, in this case when the `XADD` command is called, it calls the `signalKeyAsReady()` function. This function will put the key into a list of keys that need to be processed, because such keys may have new data for blocked consumers. Note that such *ready keys* will be processed later, so in the course of the same event loop cycle, it is possible that the key will receive other writes. +* Finally, before returning into the event loop, the *ready keys* are finally processed. For each key the list of clients waiting for data is scanned, and if applicable, such clients will receive the new data that arrived. In the case of streams the data is the messages in the applicable range requested by the consumer. + +As you can see, basically, before returning to the event loop both the client calling `XADD` and the clients blocked to consume messages, will have their reply in the output buffers, so the caller of `XADD` should receive the reply from Redis at about the same time the consumers will receive the new messages. + +This model is *push-based*, since adding data to the consumers buffers will be performed directly by the action of calling `XADD`, so the latency tends to be quite predictable. + +## Latency tests results + +In order to check these latency characteristics a test was performed using multiple instances of Ruby programs pushing messages having as an additional field the computer millisecond time, and Ruby programs reading the messages from the consumer group and processing them. The message processing step consisted of comparing the current computer time with the message timestamp, in order to understand the total latency. + +Results obtained: + +``` +Processed between 0 and 1 ms -> 74.11% +Processed between 1 and 2 ms -> 25.80% +Processed between 2 and 3 ms -> 0.06% +Processed between 3 and 4 ms -> 0.01% +Processed between 4 and 5 ms -> 0.02% +``` + +So 99.9% of requests have a latency <= 2 milliseconds, with the outliers that remain still very close to the average. + +Adding a few million unacknowledged messages to the stream does not change the gist of the benchmark, with most queries still processed with very short latency. + +A few remarks: + +* Here we processed up to 10k messages per iteration, this means that the `COUNT` parameter of `XREADGROUP` was set to 10000. This adds a lot of latency but is needed in order to allow the slow consumers to be able to keep with the message flow. So you can expect a real world latency that is a lot smaller. +* The system used for this benchmark is very slow compared to today's standards. + + + + ## Learn more * The [Redis Streams Tutorial](/docs/data-types/streams-tutorial) explains Redis streams with many examples. diff --git a/docs/data-types/strings.md b/docs/data-types/strings.md index 77dbe16d73..7a5f0dfdc2 100644 --- a/docs/data-types/strings.md +++ b/docs/data-types/strings.md @@ -7,34 +7,88 @@ description: > --- Redis strings store sequences of bytes, including text, serialized objects, and binary arrays. -As such, strings are the most basic Redis data type. +As such, strings are the simplest type of value you can associate with +a Redis key. They're often used for caching, but they support additional functionality that lets you implement counters and perform bitwise operations, too. -## Examples +Since Redis keys are strings, when we use the string type as a value too, +we are mapping a string to another string. The string data type is useful +for a number of use cases, like caching HTML fragments or pages. + +Let's play a bit with the string type, using `redis-cli` (all the examples +will be performed via `redis-cli` in this tutorial). + + > set mykey somevalue + OK + > get mykey + "somevalue" + +As you can see using the `SET` and the `GET` commands are the way we set +and retrieve a string value. Note that `SET` will replace any existing value +already stored into the key, in the case that the key already exists, even if +the key is associated with a non-string value. So `SET` performs an assignment. + +Values can be strings (including binary data) of every kind, for instance you +can store a jpeg image inside a value. A value can't be bigger than 512 MB. + +The `SET` command has interesting options, that are provided as additional +arguments. For example, I may ask `SET` to fail if the key already exists, +or the opposite, that it only succeed if the key already exists: + + > set mykey newval nx + (nil) + > set mykey newval xx + OK + +There are a number of other commands for operating on strings. For example +the `GETSET` command sets a key to a new value, returning the old value as the +result. You can use this command, for example, if you have a +system that increments a Redis key using `INCR` +every time your web site receives a new visitor. You may want to collect this +information once every hour, without losing a single increment. +You can `GETSET` the key, assigning it the new value of "0" and reading the +old value back. + +The ability to set or retrieve the value of multiple keys in a single +command is also useful for reduced latency. For this reason there are +the `MSET` and `MGET` commands: + + > mset a 10 b 20 c 30 + OK + > mget a b c + 1) "10" + 2) "20" + 3) "30" + +When `MGET` is used, Redis returns an array of values. + +### Strings as counters +Even if strings are the basic values of Redis, there are interesting operations +you can perform with them. For instance, one is atomic increment: + + > set counter 100 + OK + > incr counter + (integer) 101 + > incr counter + (integer) 102 + > incrby counter 50 + (integer) 152 + +The `INCRBY` command parses the string value as an integer, +increments it by one, and finally sets the obtained value as the new value. +There are other similar commands like `INCRBY`, +`DECR` and `DECRBY`. Internally it's +always the same command, acting in a slightly different way. + +What does it mean that INCR is atomic? +That even multiple clients issuing INCR against +the same key will never enter into a race condition. For instance, it will never +happen that client 1 reads "10", client 2 reads "10" at the same time, both +increment to 11, and set the new value to 11. The final value will always be +12 and the read-increment-set operation is performed while all the other +clients are not executing a command at the same time. -* Store and then retrieve a string in Redis: - -``` -> SET user:1 salvatore -OK -> GET user:1 -"salvatore" -``` - -* Store a serialized JSON string and set it to expire 100 seconds from now: - -``` -> SET ticket:27 "\"{'username': 'priya', 'ticket_id': 321}\"" EX 100 -``` - -* Increment a counter: - -``` -> INCR views:page:2 -(integer) 1 -> INCRBY views:page:2 10 -(integer) 11 -``` ## Limits @@ -52,7 +106,7 @@ By default, a single Redis string can be a maximum of 512 MB. ### Managing counters * `INCRBY` atomically increments (and decrements when passing a negative number) counters stored at a given key. -* Another command exists for floating point counters: [INCRBYFLOAT](/commands/incrbyfloat). +* Another command exists for floating point counters: `INCRBYFLOAT`. ### Bitwise operations @@ -68,7 +122,7 @@ These random-access string commands may cause performance issues when dealing wi ## Alternatives -If you're storing structured data as a serialized string, you may also want to consider [Redis hashes](/docs/data-types/hashes) or [RedisJSON](/docs/stack/json). +If you're storing structured data as a serialized string, you may also want to consider Redis [hashes](/docs/data-types/hashes) or [JSON](/docs/stack/json). ## Learn more diff --git a/docs/data-types/tutorial.md b/docs/data-types/tutorial.md deleted file mode 100644 index 2514e8fcf7..0000000000 --- a/docs/data-types/tutorial.md +++ /dev/null @@ -1,997 +0,0 @@ ---- -title: "Redis data types tutorial" -linkTitle: "Tutorial" -description: Learning the basic Redis data types and how to use them -weight: 1 -aliases: - - /topics/data-types-intro - - /docs/manual/data-types/data-types-tutorial ---- - -The following is a hands-on tutorial that teaches the core Redis data types using the Redis CLI. For a general overview of the data types, see the [data types introduction](/docs/data-types/). - -## Keys - -Redis keys are binary safe, this means that you can use any binary sequence as a -key, from a string like "foo" to the content of a JPEG file. -The empty string is also a valid key. - -A few other rules about keys: - -* Very long keys are not a good idea. For instance a key of 1024 bytes is a bad - idea not only memory-wise, but also because the lookup of the key in the - dataset may require several costly key-comparisons. Even when the task at hand - is to match the existence of a large value, hashing it (for example - with SHA1) is a better idea, especially from the perspective of memory - and bandwidth. -* Very short keys are often not a good idea. There is little point in writing - "u1000flw" as a key if you can instead write "user:1000:followers". The latter - is more readable and the added space is minor compared to the space used by - the key object itself and the value object. While short keys will obviously - consume a bit less memory, your job is to find the right balance. -* Try to stick with a schema. For instance "object-type:id" is a good - idea, as in "user:1000". Dots or dashes are often used for multi-word - fields, as in "comment:4321:reply.to" or "comment:4321:reply-to". -* The maximum allowed key size is 512 MB. - - -## Strings - -The Redis String type is the simplest type of value you can associate with -a Redis key. It is the only data type in Memcached, so it is also very natural -for newcomers to use it in Redis. - -Since Redis keys are strings, when we use the string type as a value too, -we are mapping a string to another string. The string data type is useful -for a number of use cases, like caching HTML fragments or pages. - -Let's play a bit with the string type, using `redis-cli` (all the examples -will be performed via `redis-cli` in this tutorial). - - > set mykey somevalue - OK - > get mykey - "somevalue" - -As you can see using the `SET` and the `GET` commands are the way we set -and retrieve a string value. Note that `SET` will replace any existing value -already stored into the key, in the case that the key already exists, even if -the key is associated with a non-string value. So `SET` performs an assignment. - -Values can be strings (including binary data) of every kind, for instance you -can store a jpeg image inside a value. A value can't be bigger than 512 MB. - -The `SET` command has interesting options, that are provided as additional -arguments. For example, I may ask `SET` to fail if the key already exists, -or the opposite, that it only succeed if the key already exists: - - > set mykey newval nx - (nil) - > set mykey newval xx - OK - -Even if strings are the basic values of Redis, there are interesting operations -you can perform with them. For instance, one is atomic increment: - - > set counter 100 - OK - > incr counter - (integer) 101 - > incr counter - (integer) 102 - > incrby counter 50 - (integer) 152 - -The [INCR](/commands/incr) command parses the string value as an integer, -increments it by one, and finally sets the obtained value as the new value. -There are other similar commands like [INCRBY](/commands/incrby), -[DECR](/commands/decr) and [DECRBY](/commands/decrby). Internally it's -always the same command, acting in a slightly different way. - -What does it mean that INCR is atomic? -That even multiple clients issuing INCR against -the same key will never enter into a race condition. For instance, it will never -happen that client 1 reads "10", client 2 reads "10" at the same time, both -increment to 11, and set the new value to 11. The final value will always be -12 and the read-increment-set operation is performed while all the other -clients are not executing a command at the same time. - -There are a number of commands for operating on strings. For example -the `GETSET` command sets a key to a new value, returning the old value as the -result. You can use this command, for example, if you have a -system that increments a Redis key using `INCR` -every time your web site receives a new visitor. You may want to collect this -information once every hour, without losing a single increment. -You can `GETSET` the key, assigning it the new value of "0" and reading the -old value back. - -The ability to set or retrieve the value of multiple keys in a single -command is also useful for reduced latency. For this reason there are -the `MSET` and `MGET` commands: - - > mset a 10 b 20 c 30 - OK - > mget a b c - 1) "10" - 2) "20" - 3) "30" - -When `MGET` is used, Redis returns an array of values. - -## Altering and querying the key space - -There are commands that are not defined on particular types, but are useful -in order to interact with the space of keys, and thus, can be used with -keys of any type. - -For example the `EXISTS` command returns 1 or 0 to signal if a given key -exists or not in the database, while the `DEL` command deletes a key -and associated value, whatever the value is. - - > set mykey hello - OK - > exists mykey - (integer) 1 - > del mykey - (integer) 1 - > exists mykey - (integer) 0 - -From the examples you can also see how `DEL` itself returns 1 or 0 depending on whether -the key was removed (it existed) or not (there was no such key with that -name). - -There are many key space related commands, but the above two are the -essential ones together with the `TYPE` command, which returns the kind -of value stored at the specified key: - - > set mykey x - OK - > type mykey - string - > del mykey - (integer) 1 - > type mykey - none - -## Key expiration - -Before moving on, we should look at an important Redis feature that works regardless of the type of value you're storing: key expiration. Key expiration lets you set a timeout for a key, also known as a "time to live", or "TTL". When the time to live elapses, the key is automatically destroyed. - -A few important notes about key expiration: - -* They can be set both using seconds or milliseconds precision. -* However the expire time resolution is always 1 millisecond. -* Information about expires are replicated and persisted on disk, the time virtually passes when your Redis server remains stopped (this means that Redis saves the date at which a key will expire). - -Use the `EXPIRE` command to set a key's expiration: - - > set key some-value - OK - > expire key 5 - (integer) 1 - > get key (immediately) - "some-value" - > get key (after some time) - (nil) - -The key vanished between the two `GET` calls, since the second call was -delayed more than 5 seconds. In the example above we used `EXPIRE` in -order to set the expire (it can also be used in order to set a different -expire to a key already having one, like `PERSIST` can be used in order -to remove the expire and make the key persistent forever). However we -can also create keys with expires using other Redis commands. For example -using `SET` options: - - > set key 100 ex 10 - OK - > ttl key - (integer) 9 - -The example above sets a key with the string value `100`, having an expire -of ten seconds. Later the `TTL` command is called in order to check the -remaining time to live for the key. - -In order to set and check expires in milliseconds, check the `PEXPIRE` and -the `PTTL` commands, and the full list of `SET` options. - - -## Lists - -To explain the List data type it's better to start with a little bit of theory, -as the term *List* is often used in an improper way by information technology -folks. For instance "Python Lists" are not what the name may suggest (Linked -Lists), but rather Arrays (the same data type is called Array in -Ruby actually). - -From a very general point of view a List is just a sequence of ordered -elements: 10,20,1,2,3 is a list. But the properties of a List implemented using -an Array are very different from the properties of a List implemented using a -*Linked List*. - -Redis lists are implemented via Linked Lists. This means that even if you have -millions of elements inside a list, the operation of adding a new element in -the head or in the tail of the list is performed *in constant time*. The speed of adding a -new element with the `LPUSH` command to the head of a list with ten -elements is the same as adding an element to the head of list with 10 -million elements. - -What's the downside? Accessing an element *by index* is very fast in lists -implemented with an Array (constant time indexed access) and not so fast in -lists implemented by linked lists (where the operation requires an amount of -work proportional to the index of the accessed element). - -Redis Lists are implemented with linked lists because for a database system it -is crucial to be able to add elements to a very long list in a very fast way. -Another strong advantage, as you'll see in a moment, is that Redis Lists can be -taken at constant length in constant time. - -When fast access to the middle of a large collection of elements is important, -there is a different data structure that can be used, called sorted sets. -Sorted sets will be covered later in this tutorial. - -### First steps with Redis Lists - -The `LPUSH` command adds a new element into a list, on the -left (at the head), while the `RPUSH` command adds a new -element into a list, on the right (at the tail). Finally the -`LRANGE` command extracts ranges of elements from lists: - - > rpush mylist A - (integer) 1 - > rpush mylist B - (integer) 2 - > lpush mylist first - (integer) 3 - > lrange mylist 0 -1 - 1) "first" - 2) "A" - 3) "B" - -Note that [LRANGE](/commands/lrange) takes two indexes, the first and the last -element of the range to return. Both the indexes can be negative, telling Redis -to start counting from the end: so -1 is the last element, -2 is the -penultimate element of the list, and so forth. - -As you can see `RPUSH` appended the elements on the right of the list, while -the final `LPUSH` appended the element on the left. - -Both commands are *variadic commands*, meaning that you are free to push -multiple elements into a list in a single call: - - > rpush mylist 1 2 3 4 5 "foo bar" - (integer) 9 - > lrange mylist 0 -1 - 1) "first" - 2) "A" - 3) "B" - 4) "1" - 5) "2" - 6) "3" - 7) "4" - 8) "5" - 9) "foo bar" - -An important operation defined on Redis lists is the ability to *pop elements*. -Popping elements is the operation of both retrieving the element from the list, -and eliminating it from the list, at the same time. You can pop elements -from left and right, similarly to how you can push elements in both sides -of the list: - - > rpush mylist a b c - (integer) 3 - > rpop mylist - "c" - > rpop mylist - "b" - > rpop mylist - "a" - -We added three elements and popped three elements, so at the end of this -sequence of commands the list is empty and there are no more elements to -pop. If we try to pop yet another element, this is the result we get: - - > rpop mylist - (nil) - -Redis returned a NULL value to signal that there are no elements in the -list. - -### Common use cases for lists - -Lists are useful for a number of tasks, two very representative use cases -are the following: - -* Remember the latest updates posted by users into a social network. -* Communication between processes, using a consumer-producer pattern where the producer pushes items into a list, and a consumer (usually a *worker*) consumes those items and executes actions. Redis has special list commands to make this use case both more reliable and efficient. - -For example both the popular Ruby libraries [resque](https://github.com/resque/resque) and -[sidekiq](https://github.com/mperham/sidekiq) use Redis lists under the hood in order to -implement background jobs. - -The popular Twitter social network [takes the latest tweets](http://www.infoq.com/presentations/Real-Time-Delivery-Twitter) -posted by users into Redis lists. - -To describe a common use case step by step, imagine your home page shows the latest -photos published in a photo sharing social network and you want to speedup access. - -* Every time a user posts a new photo, we add its ID into a list with `LPUSH`. -* When users visit the home page, we use `LRANGE 0 9` in order to get the latest 10 posted items. - -### Capped lists - -In many use cases we just want to use lists to store the *latest items*, -whatever they are: social network updates, logs, or anything else. - -Redis allows us to use lists as a capped collection, only remembering the latest -N items and discarding all the oldest items using the `LTRIM` command. - -The `LTRIM` command is similar to `LRANGE`, but **instead of displaying the -specified range of elements** it sets this range as the new list value. All -the elements outside the given range are removed. - -An example will make it more clear: - - > rpush mylist 1 2 3 4 5 - (integer) 5 - > ltrim mylist 0 2 - OK - > lrange mylist 0 -1 - 1) "1" - 2) "2" - 3) "3" - -The above `LTRIM` command tells Redis to take just list elements from index -0 to 2, everything else will be discarded. This allows for a very simple but -useful pattern: doing a List push operation + a List trim operation together -in order to add a new element and discard elements exceeding a limit: - - LPUSH mylist - LTRIM mylist 0 999 - -The above combination adds a new element and takes only the 1000 -newest elements into the list. With `LRANGE` you can access the top items -without any need to remember very old data. - -Note: while `LRANGE` is technically an O(N) command, accessing small ranges -towards the head or the tail of the list is a constant time operation. - -Blocking operations on lists ---- - -Lists have a special feature that make them suitable to implement queues, -and in general as a building block for inter process communication systems: -blocking operations. - -Imagine you want to push items into a list with one process, and use -a different process in order to actually do some kind of work with those -items. This is the usual producer / consumer setup, and can be implemented -in the following simple way: - -* To push items into the list, producers call `LPUSH`. -* To extract / process items from the list, consumers call `RPOP`. - -However it is possible that sometimes the list is empty and there is nothing -to process, so `RPOP` just returns NULL. In this case a consumer is forced to wait -some time and retry again with `RPOP`. This is called *polling*, and is not -a good idea in this context because it has several drawbacks: - -1. Forces Redis and clients to process useless commands (all the requests when the list is empty will get no actual work done, they'll just return NULL). -2. Adds a delay to the processing of items, since after a worker receives a NULL, it waits some time. To make the delay smaller, we could wait less between calls to `RPOP`, with the effect of amplifying problem number 1, i.e. more useless calls to Redis. - -So Redis implements commands called `BRPOP` and `BLPOP` which are versions -of `RPOP` and `LPOP` able to block if the list is empty: they'll return to -the caller only when a new element is added to the list, or when a user-specified -timeout is reached. - -This is an example of a `BRPOP` call we could use in the worker: - - > brpop tasks 5 - 1) "tasks" - 2) "do_something" - -It means: "wait for elements in the list `tasks`, but return if after 5 seconds -no element is available". - -Note that you can use 0 as timeout to wait for elements forever, and you can -also specify multiple lists and not just one, in order to wait on multiple -lists at the same time, and get notified when the first list receives an -element. - -A few things to note about `BRPOP`: - -1. Clients are served in an ordered way: the first client that blocked waiting for a list, is served first when an element is pushed by some other client, and so forth. -2. The return value is different compared to `RPOP`: it is a two-element array since it also includes the name of the key, because `BRPOP` and `BLPOP` are able to block waiting for elements from multiple lists. -3. If the timeout is reached, NULL is returned. - -There are more things you should know about lists and blocking ops. We -suggest that you read more on the following: - -* It is possible to build safer queues or rotating queues using `LMOVE`. -* There is also a blocking variant of the command, called `BLMOVE`. - -## Automatic creation and removal of keys - -So far in our examples we never had to create empty lists before pushing -elements, or removing empty lists when they no longer have elements inside. -It is Redis' responsibility to delete keys when lists are left empty, or to create -an empty list if the key does not exist and we are trying to add elements -to it, for example, with `LPUSH`. - -This is not specific to lists, it applies to all the Redis data types -composed of multiple elements -- Streams, Sets, Sorted Sets and Hashes. - -Basically we can summarize the behavior with three rules: - -1. When we add an element to an aggregate data type, if the target key does not exist, an empty aggregate data type is created before adding the element. -2. When we remove elements from an aggregate data type, if the value remains empty, the key is automatically destroyed. The Stream data type is the only exception to this rule. -3. Calling a read-only command such as `LLEN` (which returns the length of the list), or a write command removing elements, with an empty key, always produces the same result as if the key is holding an empty aggregate type of the type the command expects to find. - -Examples of rule 1: - - > del mylist - (integer) 1 - > lpush mylist 1 2 3 - (integer) 3 - -However we can't perform operations against the wrong type if the key exists: - - > set foo bar - OK - > lpush foo 1 2 3 - (error) WRONGTYPE Operation against a key holding the wrong kind of value - > type foo - string - -Example of rule 2: - - > lpush mylist 1 2 3 - (integer) 3 - > exists mylist - (integer) 1 - > lpop mylist - "3" - > lpop mylist - "2" - > lpop mylist - "1" - > exists mylist - (integer) 0 - -The key no longer exists after all the elements are popped. - -Example of rule 3: - - > del mylist - (integer) 0 - > llen mylist - (integer) 0 - > lpop mylist - (nil) - - -## Hashes - -Redis hashes look exactly how one might expect a "hash" to look, with field-value pairs: - - > hset user:1000 username antirez birthyear 1977 verified 1 - (integer) 3 - > hget user:1000 username - "antirez" - > hget user:1000 birthyear - "1977" - > hgetall user:1000 - 1) "username" - 2) "antirez" - 3) "birthyear" - 4) "1977" - 5) "verified" - 6) "1" - -While hashes are handy to represent *objects*, actually the number of fields you can -put inside a hash has no practical limits (other than available memory), so you can use -hashes in many different ways inside your application. - -The command `HSET` sets multiple fields of the hash, while `HGET` retrieves -a single field. `HMGET` is similar to `HGET` but returns an array of values: - - > hmget user:1000 username birthyear no-such-field - 1) "antirez" - 2) "1977" - 3) (nil) - -There are commands that are able to perform operations on individual fields -as well, like `HINCRBY`: - - > hincrby user:1000 birthyear 10 - (integer) 1987 - > hincrby user:1000 birthyear 10 - (integer) 1997 - -You can find the [full list of hash commands in the documentation](https://redis.io/commands#hash). - -It is worth noting that small hashes (i.e., a few elements with small values) are -encoded in special way in memory that make them very memory efficient. - - -## Sets - -Redis Sets are unordered collections of strings. The -`SADD` command adds new elements to a set. It's also possible -to do a number of other operations against sets like testing if a given element -already exists, performing the intersection, union or difference between -multiple sets, and so forth. - - > sadd myset 1 2 3 - (integer) 3 - > smembers myset - 1. 3 - 2. 1 - 3. 2 - -Here I've added three elements to my set and told Redis to return all the -elements. As you can see they are not sorted -- Redis is free to return the -elements in any order at every call, since there is no contract with the -user about element ordering. - -Redis has commands to test for membership. For example, checking if an element exists: - - > sismember myset 3 - (integer) 1 - > sismember myset 30 - (integer) 0 - -"3" is a member of the set, while "30" is not. - -Sets are good for expressing relations between objects. -For instance we can easily use sets in order to implement tags. - -A simple way to model this problem is to have a set for every object we -want to tag. The set contains the IDs of the tags associated with the object. - -One illustration is tagging news articles. -If article ID 1000 is tagged with tags 1, 2, 5 and 77, a set -can associate these tag IDs with the news item: - - > sadd news:1000:tags 1 2 5 77 - (integer) 4 - -We may also want to have the inverse relation as well: the list -of all the news tagged with a given tag: - - > sadd tag:1:news 1000 - (integer) 1 - > sadd tag:2:news 1000 - (integer) 1 - > sadd tag:5:news 1000 - (integer) 1 - > sadd tag:77:news 1000 - (integer) 1 - -To get all the tags for a given object is trivial: - - > smembers news:1000:tags - 1. 5 - 2. 1 - 3. 77 - 4. 2 - -Note: in the example we assume you have another data structure, for example -a Redis hash, which maps tag IDs to tag names. - -There are other non trivial operations that are still easy to implement -using the right Redis commands. For instance we may want a list of all the -objects with the tags 1, 2, 10, and 27 together. We can do this using -the `SINTER` command, which performs the intersection between different -sets. We can use: - - > sinter tag:1:news tag:2:news tag:10:news tag:27:news - ... results here ... - -In addition to intersection you can also perform -unions, difference, extract a random element, and so forth. - -The command to extract an element is called `SPOP`, and is handy to model -certain problems. For example in order to implement a web-based poker game, -you may want to represent your deck with a set. Imagine we use a one-char -prefix for (C)lubs, (D)iamonds, (H)earts, (S)pades: - - > sadd deck C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 CJ CQ CK - D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 DJ DQ DK H1 H2 H3 - H4 H5 H6 H7 H8 H9 H10 HJ HQ HK S1 S2 S3 S4 S5 S6 - S7 S8 S9 S10 SJ SQ SK - (integer) 52 - -Now we want to provide each player with 5 cards. The `SPOP` command -removes a random element, returning it to the client, so it is the -perfect operation in this case. - -However if we call it against our deck directly, in the next play of the -game we'll need to populate the deck of cards again, which may not be -ideal. So to start, we can make a copy of the set stored in the `deck` key -into the `game:1:deck` key. - -This is accomplished using `SUNIONSTORE`, which normally performs the -union between multiple sets, and stores the result into another set. -However, since the union of a single set is itself, I can copy my deck -with: - - > sunionstore game:1:deck deck - (integer) 52 - -Now I'm ready to provide the first player with five cards: - - > spop game:1:deck - "C6" - > spop game:1:deck - "CQ" - > spop game:1:deck - "D1" - > spop game:1:deck - "CJ" - > spop game:1:deck - "SJ" - -One pair of jacks, not great... - -This is a good time to introduce the set command that provides the number -of elements inside a set. This is often called the *cardinality of a set* -in the context of set theory, so the Redis command is called `SCARD`. - - > scard game:1:deck - (integer) 47 - -The math works: 52 - 5 = 47. - -When you need to just get random elements without removing them from the -set, there is the `SRANDMEMBER` command suitable for the task. It also features -the ability to return both repeating and non-repeating elements. - - -## Sorted sets - -Sorted sets are a data type which is similar to a mix between a Set and -a Hash. Like sets, sorted sets are composed of unique, non-repeating -string elements, so in some sense a sorted set is a set as well. - -However while elements inside sets are not ordered, every element in -a sorted set is associated with a floating point value, called *the score* -(this is why the type is also similar to a hash, since every element -is mapped to a value). - -Moreover, elements in a sorted set are *taken in order* (so they are not -ordered on request, order is a peculiarity of the data structure used to -represent sorted sets). They are ordered according to the following rule: - -* If B and A are two elements with a different score, then A > B if A.score is > B.score. -* If B and A have exactly the same score, then A > B if the A string is lexicographically greater than the B string. B and A strings can't be equal since sorted sets only have unique elements. - -Let's start with a simple example, adding a few selected hackers names as -sorted set elements, with their year of birth as "score". - - > zadd hackers 1940 "Alan Kay" - (integer) 1 - > zadd hackers 1957 "Sophie Wilson" - (integer) 1 - > zadd hackers 1953 "Richard Stallman" - (integer) 1 - > zadd hackers 1949 "Anita Borg" - (integer) 1 - > zadd hackers 1965 "Yukihiro Matsumoto" - (integer) 1 - > zadd hackers 1914 "Hedy Lamarr" - (integer) 1 - > zadd hackers 1916 "Claude Shannon" - (integer) 1 - > zadd hackers 1969 "Linus Torvalds" - (integer) 1 - > zadd hackers 1912 "Alan Turing" - (integer) 1 - - -As you can see `ZADD` is similar to `SADD`, but takes one additional argument -(placed before the element to be added) which is the score. -`ZADD` is also variadic, so you are free to specify multiple score-value -pairs, even if this is not used in the example above. - -With sorted sets it is trivial to return a list of hackers sorted by their -birth year because actually *they are already sorted*. - -Implementation note: Sorted sets are implemented via a -dual-ported data structure containing both a skip list and a hash table, so -every time we add an element Redis performs an O(log(N)) operation. That's -good, but when we ask for sorted elements Redis does not have to do any work at -all, it's already all sorted: - - > zrange hackers 0 -1 - 1) "Alan Turing" - 2) "Hedy Lamarr" - 3) "Claude Shannon" - 4) "Alan Kay" - 5) "Anita Borg" - 6) "Richard Stallman" - 7) "Sophie Wilson" - 8) "Yukihiro Matsumoto" - 9) "Linus Torvalds" - -Note: 0 and -1 means from element index 0 to the last element (-1 works -here just as it does in the case of the `LRANGE` command). - -What if I want to order them the opposite way, youngest to oldest? -Use [ZREVRANGE](/commands/zrevrange) instead of [ZRANGE](/commands/zrange): - - > zrevrange hackers 0 -1 - 1) "Linus Torvalds" - 2) "Yukihiro Matsumoto" - 3) "Sophie Wilson" - 4) "Richard Stallman" - 5) "Anita Borg" - 6) "Alan Kay" - 7) "Claude Shannon" - 8) "Hedy Lamarr" - 9) "Alan Turing" - -It is possible to return scores as well, using the `WITHSCORES` argument: - - > zrange hackers 0 -1 withscores - 1) "Alan Turing" - 2) "1912" - 3) "Hedy Lamarr" - 4) "1914" - 5) "Claude Shannon" - 6) "1916" - 7) "Alan Kay" - 8) "1940" - 9) "Anita Borg" - 10) "1949" - 11) "Richard Stallman" - 12) "1953" - 13) "Sophie Wilson" - 14) "1957" - 15) "Yukihiro Matsumoto" - 16) "1965" - 17) "Linus Torvalds" - 18) "1969" - -### Operating on ranges - -Sorted sets are more powerful than this. They can operate on ranges. -Let's get all the individuals that were born up to 1950 inclusive. We -use the `ZRANGEBYSCORE` command to do it: - - > zrangebyscore hackers -inf 1950 - 1) "Alan Turing" - 2) "Hedy Lamarr" - 3) "Claude Shannon" - 4) "Alan Kay" - 5) "Anita Borg" - -We asked Redis to return all the elements with a score between negative -infinity and 1950 (both extremes are included). - -It's also possible to remove ranges of elements. Let's remove all -the hackers born between 1940 and 1960 from the sorted set: - - > zremrangebyscore hackers 1940 1960 - (integer) 4 - -`ZREMRANGEBYSCORE` is perhaps not the best command name, -but it can be very useful, and returns the number of removed elements. - -Another extremely useful operation defined for sorted set elements -is the get-rank operation. It is possible to ask what is the -position of an element in the set of the ordered elements. - - > zrank hackers "Anita Borg" - (integer) 4 - -The `ZREVRANK` command is also available in order to get the rank, considering -the elements sorted a descending way. - -### Lexicographical scores - -With recent versions of Redis 2.8, a new feature was introduced that allows -getting ranges lexicographically, assuming elements in a sorted set are all -inserted with the same identical score (elements are compared with the C -`memcmp` function, so it is guaranteed that there is no collation, and every -Redis instance will reply with the same output). - -The main commands to operate with lexicographical ranges are `ZRANGEBYLEX`, -`ZREVRANGEBYLEX`, `ZREMRANGEBYLEX` and `ZLEXCOUNT`. - -For example, let's add again our list of famous hackers, but this time -use a score of zero for all the elements: - - > zadd hackers 0 "Alan Kay" 0 "Sophie Wilson" 0 "Richard Stallman" 0 - "Anita Borg" 0 "Yukihiro Matsumoto" 0 "Hedy Lamarr" 0 "Claude Shannon" - 0 "Linus Torvalds" 0 "Alan Turing" - -Because of the sorted sets ordering rules, they are already sorted -lexicographically: - - > zrange hackers 0 -1 - 1) "Alan Kay" - 2) "Alan Turing" - 3) "Anita Borg" - 4) "Claude Shannon" - 5) "Hedy Lamarr" - 6) "Linus Torvalds" - 7) "Richard Stallman" - 8) "Sophie Wilson" - 9) "Yukihiro Matsumoto" - -Using `ZRANGEBYLEX` we can ask for lexicographical ranges: - - > zrangebylex hackers [B [P - 1) "Claude Shannon" - 2) "Hedy Lamarr" - 3) "Linus Torvalds" - -Ranges can be inclusive or exclusive (depending on the first character), -also string infinite and minus infinite are specified respectively with -the `+` and `-` strings. See the documentation for more information. - -This feature is important because it allows us to use sorted sets as a generic -index. For example, if you want to index elements by a 128-bit unsigned -integer argument, all you need to do is to add elements into a sorted -set with the same score (for example 0) but with a 16 byte prefix -consisting of **the 128 bit number in big endian**. Since numbers in big -endian, when ordered lexicographically (in raw bytes order) are actually -ordered numerically as well, you can ask for ranges in the 128 bit space, -and get the element's value discarding the prefix. - -If you want to see the feature in the context of a more serious demo, -check the [Redis autocomplete demo](http://autocomplete.redis.io). - -Updating the score: leaderboards ---- - -Just a final note about sorted sets before switching to the next topic. -Sorted sets' scores can be updated at any time. Just calling `ZADD` against -an element already included in the sorted set will update its score -(and position) with O(log(N)) time complexity. As such, sorted sets are suitable -when there are tons of updates. - -Because of this characteristic a common use case is leaderboards. -The typical application is a Facebook game where you combine the ability to -take users sorted by their high score, plus the get-rank operation, in order -to show the top-N users, and the user rank in the leader board (e.g., "you are -the #4932 best score here"). - - -## Bitmaps - -Bitmaps are not an actual data type, but a set of bit-oriented operations -defined on the String type. Since strings are binary safe blobs and their -maximum length is 512 MB, they are suitable to set up to 2^32 different -bits. - -Bit operations are divided into two groups: constant-time single bit -operations, like setting a bit to 1 or 0, or getting its value, and -operations on groups of bits, for example counting the number of set -bits in a given range of bits (e.g., population counting). - -One of the biggest advantages of bitmaps is that they often provide -extreme space savings when storing information. For example in a system -where different users are represented by incremental user IDs, it is possible -to remember a single bit information (for example, knowing whether -a user wants to receive a newsletter) of 4 billion of users using just 512 MB of memory. - -Bits are set and retrieved using the `SETBIT` and `GETBIT` commands: - - > setbit key 10 1 - (integer) 0 - > getbit key 10 - (integer) 1 - > getbit key 11 - (integer) 0 - -The `SETBIT` command takes as its first argument the bit number, and as its second -argument the value to set the bit to, which is 1 or 0. The command -automatically enlarges the string if the addressed bit is outside the -current string length. - -`GETBIT` just returns the value of the bit at the specified index. -Out of range bits (addressing a bit that is outside the length of the string -stored into the target key) are always considered to be zero. - -There are three commands operating on group of bits: - -1. `BITOP` performs bit-wise operations between different strings. The provided operations are AND, OR, XOR and NOT. -2. `BITCOUNT` performs population counting, reporting the number of bits set to 1. -3. `BITPOS` finds the first bit having the specified value of 0 or 1. - -Both `BITPOS` and `BITCOUNT` are able to operate with byte ranges of the -string, instead of running for the whole length of the string. The following -is a trivial example of `BITCOUNT` call: - - > setbit key 0 1 - (integer) 0 - > setbit key 100 1 - (integer) 0 - > bitcount key - (integer) 2 - -Common use cases for bitmaps are: - -* Real time analytics of all kinds. -* Storing space efficient but high performance boolean information associated with object IDs. - -For example imagine you want to know the longest streak of daily visits of -your web site users. You start counting days starting from zero, that is the -day you made your web site public, and set a bit with `SETBIT` every time -the user visits the web site. As a bit index you simply take the current unix -time, subtract the initial offset, and divide by the number of seconds in a day -(normally, 3600\*24). - -This way for each user you have a small string containing the visit -information for each day. With `BITCOUNT` it is possible to easily get -the number of days a given user visited the web site, while with -a few `BITPOS` calls, or simply fetching and analyzing the bitmap client-side, -it is possible to easily compute the longest streak. - -Bitmaps are trivial to split into multiple keys, for example for -the sake of sharding the data set and because in general it is better to -avoid working with huge keys. To split a bitmap across different keys -instead of setting all the bits into a key, a trivial strategy is just -to store M bits per key and obtain the key name with `bit-number/M` and -the Nth bit to address inside the key with `bit-number MOD M`. - - -## HyperLogLogs - -A HyperLogLog is a probabilistic data structure used in order to count -unique things (technically this is referred to estimating the cardinality -of a set). Usually counting unique items requires using an amount of memory -proportional to the number of items you want to count, because you need -to remember the elements you have already seen in the past in order to avoid -counting them multiple times. However there is a set of algorithms that trade -memory for precision: you end with an estimated measure with a standard error, -which in the case of the Redis implementation is less than 1%. The -magic of this algorithm is that you no longer need to use an amount of memory -proportional to the number of items counted, and instead can use a -constant amount of memory! 12k bytes in the worst case, or a lot less if your -HyperLogLog (We'll just call them HLL from now) has seen very few elements. - -HLLs in Redis, while technically a different data structure, are encoded -as a Redis string, so you can call `GET` to serialize a HLL, and `SET` -to deserialize it back to the server. - -Conceptually the HLL API is like using Sets to do the same task. You would -`SADD` every observed element into a set, and would use `SCARD` to check the -number of elements inside the set, which are unique since `SADD` will not -re-add an existing element. - -While you don't really *add items* into an HLL, because the data structure -only contains a state that does not include actual elements, the API is the -same: - -* Every time you see a new element, you add it to the count with `PFADD`. -* Every time you want to retrieve the current approximation of the unique elements *added* with `PFADD` so far, you use the `PFCOUNT`. - - > pfadd hll a b c d - (integer) 1 - > pfcount hll - (integer) 4 - -An example of use case for this data structure is counting unique queries -performed by users in a search form every day. - -Redis is also able to perform the union of HLLs, please check the -[full documentation](/commands#hyperloglog) for more information. - -## Other notable features - -There are other important things in the Redis API that can't be explored -in the context of this document, but are worth your attention: - -* It is possible to [iterate the key space of a large collection incrementally](/commands/scan). -* It is possible to run [Lua scripts server side](/commands/eval) to improve latency and bandwidth. -* Redis is also a [Pub-Sub server](/topics/pubsub). - -## Learn more - -This tutorial is in no way complete and has covered just the basics of the API. -Read the [command reference](/commands) to discover a lot more. - -Thanks for reading, and have fun hacking with Redis! diff --git a/docs/getting-started/_index.md b/docs/getting-started/_index.md index cc7f0c0ba0..12352e5220 100644 --- a/docs/getting-started/_index.md +++ b/docs/getting-started/_index.md @@ -1,6 +1,6 @@ --- -title: "Getting started with Redis" -linkTitle: "Getting started" +title: "Get started with Redis" +linkTitle: "Get started" weight: 20 @@ -68,26 +68,6 @@ the goal is to use it from your application. In order to do so you need to download and install a Redis client library for your programming language. You'll find a [full list of clients for different languages in this page](https://redis.io/clients). -For instance if you happen to use the Ruby programming language our best advice -is to use the [Redis-rb](https://github.com/redis/redis-rb) client. -You can install it using the command **gem install redis**. - -These instructions are Ruby specific but actually many library clients for -popular languages look quite similar: you create a Redis object and execute -commands calling methods. A short interactive example using Ruby: - - >> require 'rubygems' - => false - >> require 'redis' - => true - >> r = Redis.new - => # - >> r.ping - => "PONG" - >> r.set('foo','bar') - => "OK" - >> r.get('foo') - => "bar" ## Redis persistence @@ -158,3 +138,5 @@ Make sure that everything is working as expected: Note: The above instructions don't include all of the Redis configuration parameters that you could change, for instance, to use AOF persistence instead of RDB persistence, or to set up replication, and so forth. Make sure to read the example [`redis.conf`](https://github.com/redis/redis/blob/6.2/redis.conf) file (that is heavily commented). + +
\ No newline at end of file diff --git a/docs/getting-started/installation/_index.md b/docs/getting-started/installation/_index.md index aa07f2716a..4a8845d356 100644 --- a/docs/getting-started/installation/_index.md +++ b/docs/getting-started/installation/_index.md @@ -1,6 +1,6 @@ --- title: "Installing Redis" -linkTitle: "Install" +linkTitle: "Install Redis" weight: 1 description: > Install Redis on Linux, macOS, and Windows diff --git a/docs/interact-with-data/_index.md b/docs/interact-with-data/_index.md new file mode 100644 index 0000000000..a69055546b --- /dev/null +++ b/docs/interact-with-data/_index.md @@ -0,0 +1,9 @@ +--- +title: "Interact with data in Redis" +linkTitle: "Interact with data" + +weight: 40 + +description: > + How to interact with data in Redis, including searching, querying, triggered functions, transactions, and pub/sub. +--- \ No newline at end of file diff --git a/docs/manual/programmability/_index.md b/docs/interact-with-data/programmability/_index.md similarity index 99% rename from docs/manual/programmability/_index.md rename to docs/interact-with-data/programmability/_index.md index 9508d17e04..14ac7489c3 100644 --- a/docs/manual/programmability/_index.md +++ b/docs/interact-with-data/programmability/_index.md @@ -1,11 +1,12 @@ --- title: "Redis programmability" linkTitle: "Programmability" -weight: 7 +weight: 20 description: > Extending Redis with Lua and Redis Functions aliases: - /topics/programmability + - /docs/manual/programmability/ --- Redis provides a programming interface that lets you execute custom scripts on the server itself. In Redis 7 and beyond, you can use [Redis Functions](/docs/manual/programmability/functions-intro) to manage and run your scripts. In Redis 6.2 and below, you use [Lua scripting with the EVAL command](/docs/manual/programmability/eval-intro) to program the server. diff --git a/docs/manual/programmability/eval-intro.md b/docs/interact-with-data/programmability/eval-intro.md similarity index 99% rename from docs/manual/programmability/eval-intro.md rename to docs/interact-with-data/programmability/eval-intro.md index f1a4e9b97c..0a1b70982d 100644 --- a/docs/manual/programmability/eval-intro.md +++ b/docs/interact-with-data/programmability/eval-intro.md @@ -6,6 +6,7 @@ description: > Executing Lua in Redis aliases: - /topics/eval-intro + - /docs/manual/programmability/eval-intro/ --- Redis lets users upload and execute Lua scripts on the server. diff --git a/docs/manual/programmability/functions-intro.md b/docs/interact-with-data/programmability/functions-intro.md similarity index 99% rename from docs/manual/programmability/functions-intro.md rename to docs/interact-with-data/programmability/functions-intro.md index 5686d12852..b4dc77033c 100644 --- a/docs/manual/programmability/functions-intro.md +++ b/docs/interact-with-data/programmability/functions-intro.md @@ -6,6 +6,7 @@ description: > Scripting with Redis 7 and beyond aliases: - /topics/functions-intro + - /docs/manual/programmability/functions-intro/ --- Redis Functions is an API for managing code to be executed on the server. This feature, which became available in Redis 7, supersedes the use of [EVAL](/docs/manual/programmability/eval-intro) in prior versions of Redis. diff --git a/docs/manual/programmability/lua-api.md b/docs/interact-with-data/programmability/lua-api.md similarity index 99% rename from docs/manual/programmability/lua-api.md rename to docs/interact-with-data/programmability/lua-api.md index 4ff6006645..f5d6e3e505 100644 --- a/docs/manual/programmability/lua-api.md +++ b/docs/interact-with-data/programmability/lua-api.md @@ -6,6 +6,7 @@ description: > Executing Lua in Redis aliases: - /topics/lua-api + - /docs/manual/programmability/lua-api/ --- Redis includes an embedded [Lua 5.1](https://www.lua.org/) interpreter. diff --git a/docs/manual/programmability/lua-debugging.md b/docs/interact-with-data/programmability/lua-debugging.md similarity index 99% rename from docs/manual/programmability/lua-debugging.md rename to docs/interact-with-data/programmability/lua-debugging.md index 61719370a5..26b4b05e1d 100644 --- a/docs/manual/programmability/lua-debugging.md +++ b/docs/interact-with-data/programmability/lua-debugging.md @@ -5,6 +5,7 @@ description: How to use the built-in Lua debugger weight: 4 aliases: - /topics/ldb + - /docs/manual/programmability/lua-debugging/ --- Starting with version 3.2 Redis includes a complete Lua debugger, that can be diff --git a/docs/manual/pubsub.md b/docs/interact-with-data/pubsub.md similarity index 99% rename from docs/manual/pubsub.md rename to docs/interact-with-data/pubsub.md index e746095ada..7b3373d049 100644 --- a/docs/manual/pubsub.md +++ b/docs/interact-with-data/pubsub.md @@ -1,7 +1,7 @@ --- title: Redis Pub/Sub linkTitle: "Pub/sub" -weight: 4 +weight: 40 description: How to use pub/sub channels in Redis aliases: - /topics/pubsub diff --git a/docs/manual/transactions.md b/docs/interact-with-data/transactions.md similarity index 99% rename from docs/manual/transactions.md rename to docs/interact-with-data/transactions.md index b75a41d838..9641f986bb 100644 --- a/docs/manual/transactions.md +++ b/docs/interact-with-data/transactions.md @@ -1,10 +1,11 @@ --- title: Transactions linkTitle: Transactions -weight: 5 +weight: 30 description: How transactions work in Redis aliases: - /topics/transactions + - /docs/manual/transactions/ --- Redis Transactions allow the execution of a group of commands diff --git a/docs/management/_index.md b/docs/management/_index.md index df79a1b191..bc67c5ceae 100644 --- a/docs/management/_index.md +++ b/docs/management/_index.md @@ -1,6 +1,6 @@ --- -title: "Managing Redis" -linkTitle: "Managing Redis" +title: "Manage Redis" +linkTitle: "Manage Redis" description: An administrator's guide to Redis weight: 60 --- diff --git a/docs/management/admin.md b/docs/management/admin.md index 79bfb70b5f..8d31b9a14d 100644 --- a/docs/management/admin.md +++ b/docs/management/admin.md @@ -56,7 +56,7 @@ aliases: [ ## Upgrading or restarting a Redis instance without downtime -Redis is designed to be a long-running process in your server. You can modify many configuration options without a restart using the [CONFIG SET command](/commands/config-set). You can also switch from AOF to RDB snapshots persistence, or the other way around, without restarting Redis. Check the output of the `CONFIG GET *` command for more information. +Redis is designed to be a long-running process in your server. You can modify many configuration options without a restart using the `CONFIG SET` command. You can also switch from AOF to RDB snapshots persistence, or the other way around, without restarting Redis. Check the output of the `CONFIG GET *` command for more information. From time to time, a restart is required, for example, to upgrade the Redis process to a newer version, or when you need to modify a configuration parameter that is currently not supported by the `CONFIG` command. @@ -74,7 +74,7 @@ Follow these steps to avoid downtime. * Configure all your clients to use the new instance (the replica). Note that you may want to use the `CLIENT PAUSE` command to ensure that no client can write to the old master during the switch. -* Once you confirm that the master is no longer receiving any queries (you can check this using the [MONITOR command](/commands/monitor)), elect the replica to master using the `REPLICAOF NO ONE` command, and then shut down your master. +* Once you confirm that the master is no longer receiving any queries (you can check this using the `MONITOR` command), elect the replica to master using the `REPLICAOF NO ONE` command, and then shut down your master. If you are using [Redis Sentinel](/topics/sentinel) or [Redis Cluster](/topics/cluster-tutorial), the simplest way to upgrade to newer versions is to upgrade one replica after the other. Then you can perform a manual failover to promote one of the upgraded replicas to master, and finally promote the last replica. diff --git a/docs/management/replication.md b/docs/management/replication.md index 801638a563..79e7e341fc 100644 --- a/docs/management/replication.md +++ b/docs/management/replication.md @@ -200,14 +200,14 @@ Historically, there were some use cases that were considered legitimate for writ As of version 7.0, these use cases are now all obsolete and the same can be achieved by other means. For example: -* Computing slow Set or Sorted set operations and storing the result in temporary local keys using commands like [SUNIONSTORE](/commands/sunionstore) and [ZINTERSTORE](/commands/zinterstore). - Instead, use commands that return the result without storing it, such as [SUNION](/commands/sunion) and [ZINTER](/commands/zinter). +* Computing slow Set or Sorted set operations and storing the result in temporary local keys using commands like `SUNIONSTORE` and `ZINTERSTORE`. + Instead, use commands that return the result without storing it, such as `SUNION` and `ZINTER`. -* Using the [SORT](/commands/sort) command (which is not considered a read-only command because of the optional STORE option and therefore cannot be used on a read-only replica). - Instead, use [SORT_RO](/commands/sort_ro), which is a read-only command. +* Using the `SORT` command (which is not considered a read-only command because of the optional STORE option and therefore cannot be used on a read-only replica). + Instead, use `SORT_RO`, which is a read-only command. -* Using [EVAL](/commands/eval) and [EVALSHA](/commands/evalsha) are also not considered read-only commands, because the Lua script may call write commands. - Instead, use [EVAL_RO](/commands/eval_ro) and [EVALSHA_RO](/commands/evalsha_ro) where the Lua script can only call read-only commands. +* Using `EVAL` and `EVALSHA` are also not considered read-only commands, because the Lua script may call write commands. + Instead, use `EVAL_RO` and `EVALSHA_RO` where the Lua script can only call read-only commands. While writes to a replica will be discarded if the replica and the master resync or if the replica is restarted, there is no guarantee that they will sync automatically. diff --git a/docs/manual/_index.md b/docs/manual/_index.md index 0b0eccb8e7..b7b72b871e 100644 --- a/docs/manual/_index.md +++ b/docs/manual/_index.md @@ -1,6 +1,6 @@ --- -title: "Using Redis" -linkTitle: "Using Redis" +title: "Use Redis" +linkTitle: "Use Redis" description: A developer's guide to Redis weight: 50 --- diff --git a/docs/manual/client-side-caching.md b/docs/manual/client-side-caching.md index 61da7dd6c6..5961fe906f 100644 --- a/docs/manual/client-side-caching.md +++ b/docs/manual/client-side-caching.md @@ -1,7 +1,7 @@ --- title: "Client-side caching in Redis" linkTitle: "Client-side caching" -weight: 1 +weight: 2 description: > Server-assisted, client-side caching in Redis aliases: diff --git a/docs/manual/keyspace-notifications.md b/docs/manual/keyspace-notifications.md index 380180a771..d46a750999 100644 --- a/docs/manual/keyspace-notifications.md +++ b/docs/manual/keyspace-notifications.md @@ -1,7 +1,7 @@ --- title: "Redis keyspace notifications" linkTitle: "Keyspace notifications" -weight: 3 +weight: 4 description: > Monitor changes to Redis keys and values in real time aliases: diff --git a/docs/manual/keyspace.md b/docs/manual/keyspace.md new file mode 100644 index 0000000000..0bd903e655 --- /dev/null +++ b/docs/manual/keyspace.md @@ -0,0 +1,324 @@ +--- +title: "Keyspace" +linkTitle: "Keyspace" +weight: 1 +description: > + Managing keys in Redis: Key expiration, scanning, altering and querying the key space +--- + +Redis keys are binary safe; this means that you can use any binary sequence as a +key, from a string like "foo" to the content of a JPEG file. +The empty string is also a valid key. + +A few other rules about keys: + +* Very long keys are not a good idea. For instance a key of 1024 bytes is a bad + idea not only memory-wise, but also because the lookup of the key in the + dataset may require several costly key-comparisons. Even when the task at hand + is to match the existence of a large value, hashing it (for example + with SHA1) is a better idea, especially from the perspective of memory + and bandwidth. +* Very short keys are often not a good idea. There is little point in writing + "u1000flw" as a key if you can instead write "user:1000:followers". The latter + is more readable and the added space is minor compared to the space used by + the key object itself and the value object. While short keys will obviously + consume a bit less memory, your job is to find the right balance. +* Try to stick with a schema. For instance "object-type:id" is a good + idea, as in "user:1000". Dots or dashes are often used for multi-word + fields, as in "comment:4321:reply.to" or "comment:4321:reply-to". +* The maximum allowed key size is 512 MB. + +## Altering and querying the key space + +There are commands that are not defined on particular types, but are useful +in order to interact with the space of keys, and thus, can be used with +keys of any type. + +For example the `EXISTS` command returns 1 or 0 to signal if a given key +exists or not in the database, while the `DEL` command deletes a key +and associated value, whatever the value is. + + > set mykey hello + OK + > exists mykey + (integer) 1 + > del mykey + (integer) 1 + > exists mykey + (integer) 0 + +From the examples you can also see how `DEL` itself returns 1 or 0 depending on whether +the key was removed (it existed) or not (there was no such key with that +name). + +There are many key space related commands, but the above two are the +essential ones together with the `TYPE` command, which returns the kind +of value stored at the specified key: + + > set mykey x + OK + > type mykey + string + > del mykey + (integer) 1 + > type mykey + none + +## Key expiration + +Before moving on, we should look at an important Redis feature that works regardless of the type of value you're storing: key expiration. Key expiration lets you set a timeout for a key, also known as a "time to live", or "TTL". When the time to live elapses, the key is automatically destroyed. + +A few important notes about key expiration: + +* They can be set both using seconds or milliseconds precision. +* However the expire time resolution is always 1 millisecond. +* Information about expires are replicated and persisted on disk, the time virtually passes when your Redis server remains stopped (this means that Redis saves the date at which a key will expire). + +Use the `EXPIRE` command to set a key's expiration: + + > set key some-value + OK + > expire key 5 + (integer) 1 + > get key (immediately) + "some-value" + > get key (after some time) + (nil) + +The key vanished between the two `GET` calls, since the second call was +delayed more than 5 seconds. In the example above we used `EXPIRE` in +order to set the expire (it can also be used in order to set a different +expire to a key already having one, like `PERSIST` can be used in order +to remove the expire and make the key persistent forever). However we +can also create keys with expires using other Redis commands. For example +using `SET` options: + + > set key 100 ex 10 + OK + > ttl key + (integer) 9 + +The example above sets a key with the string value `100`, having an expire +of ten seconds. Later the `TTL` command is called in order to check the +remaining time to live for the key. + +In order to set and check expires in milliseconds, check the `PEXPIRE` and +the `PTTL` commands, and the full list of `SET` options. + +## Navigating the keyspace + +### Scan +To incrementally iterate over the keys in a Redis database in an efficient manner, you can use the `SCAN` command. + +Since `SCAN` allows for incremental iteration, returning only a small number of elements per call, it can be used in production without the downside of commands like `KEYS` or `SMEMBERS` that may block the server for a long time (even several seconds) when called against big collections of keys or elements. + +However while blocking commands like `SMEMBERS` are able to provide all the elements that are part of a Set in a given moment, The SCAN family of commands only offer limited guarantees about the returned elements since the collection that we incrementally iterate can change during the iteration process. + +#### SCAN basic usage + +SCAN is a cursor based iterator. This means that at every call of the command, the server returns an updated cursor that the user needs to use as the cursor argument in the next call. + +An iteration starts when the cursor is set to 0, and terminates when the cursor returned by the server is 0. The following is an example of SCAN iteration: + +``` +redis 127.0.0.1:6379> scan 0 +1) "17" +2) 1) "key:12" + 2) "key:8" + 3) "key:4" + 4) "key:14" + 5) "key:16" + 6) "key:17" + 7) "key:15" + 8) "key:10" + 9) "key:3" + 10) "key:7" + 11) "key:1" +redis 127.0.0.1:6379> scan 17 +1) "0" +2) 1) "key:5" + 2) "key:18" + 3) "key:0" + 4) "key:2" + 5) "key:19" + 6) "key:13" + 7) "key:6" + 8) "key:9" + 9) "key:11" +``` + +In the example above, the first call uses zero as a cursor, to start the iteration. The second call uses the cursor returned by the previous call as the first element of the reply, that is, 17. + +As you can see the **SCAN return value** is an array of two values: the first value is the new cursor to use in the next call, the second value is an array of elements. + +Since in the second call the returned cursor is 0, the server signaled to the caller that the iteration finished, and the collection was completely explored. Starting an iteration with a cursor value of 0, and calling `SCAN` until the returned cursor is 0 again is called a **full iteration**. + +#### Scan guarantees + +The `SCAN` command, and the other commands in the `SCAN` family, are able to provide to the user a set of guarantees associated to full iterations. + +* A full iteration always retrieves all the elements that were present in the collection from the start to the end of a full iteration. This means that if a given element is inside the collection when an iteration is started, and is still there when an iteration terminates, then at some point `SCAN` returned it to the user. +* A full iteration never returns any element that was NOT present in the collection from the start to the end of a full iteration. So if an element was removed before the start of an iteration, and is never added back to the collection for all the time an iteration lasts, `SCAN` ensures that this element will never be returned. + +However because `SCAN` has very little state associated (just the cursor) it has the following drawbacks: + +* A given element may be returned multiple times. It is up to the application to handle the case of duplicated elements, for example only using the returned elements in order to perform operations that are safe when re-applied multiple times. +* Elements that were not constantly present in the collection during a full iteration, may be returned or not: it is undefined. + +#### Number of elements returned at every SCAN call + +`SCAN` family functions do not guarantee that the number of elements returned per call are in a given range. The commands are also allowed to return zero elements, and the client should not consider the iteration complete as long as the returned cursor is not zero. + +However the number of returned elements is reasonable, that is, in practical terms SCAN may return a maximum number of elements in the order of a few tens of elements when iterating a large collection, or may return all the elements of the collection in a single call when the iterated collection is small enough to be internally represented as an encoded data structure (this happens for small sets, hashes and sorted sets). + +However there is a way for the user to tune the order of magnitude of the number of returned elements per call using the **COUNT** option. + +#### The COUNT option + +While `SCAN` does not provide guarantees about the number of elements returned at every iteration, it is possible to empirically adjust the behavior of `SCAN` using the **COUNT** option. Basically with COUNT the user specified the *amount of work that should be done at every call in order to retrieve elements from the collection*. This is **just a hint** for the implementation, however generally speaking this is what you could expect most of the times from the implementation. + +* The default COUNT value is 10. +* When iterating the key space, or a Set, Hash or Sorted Set that is big enough to be represented by a hash table, assuming no **MATCH** option is used, the server will usually return *count* or a bit more than *count* elements per call. Please check the *why SCAN may return all the elements at once* section later in this document. +* When iterating Sets encoded as intsets (small sets composed of just integers), or Hashes and Sorted Sets encoded as ziplists (small hashes and sets composed of small individual values), usually all the elements are returned in the first `SCAN` call regardless of the COUNT value. + +Important: **there is no need to use the same COUNT value** for every iteration. The caller is free to change the count from one iteration to the other as required, as long as the cursor passed in the next call is the one obtained in the previous call to the command. + +#### The MATCH option + +It is possible to only iterate elements matching a given glob-style pattern, similarly to the behavior of the `KEYS` command that takes a pattern as its only argument. + +To do so, just append the `MATCH ` arguments at the end of the `SCAN` command (it works with all the SCAN family commands). + +This is an example of iteration using **MATCH**: + +``` +redis 127.0.0.1:6379> sadd myset 1 2 3 foo foobar feelsgood +(integer) 6 +redis 127.0.0.1:6379> sscan myset 0 match f* +1) "0" +2) 1) "foo" + 2) "feelsgood" + 3) "foobar" +redis 127.0.0.1:6379> +``` + +It is important to note that the **MATCH** filter is applied after elements are retrieved from the collection, just before returning data to the client. This means that if the pattern matches very little elements inside the collection, `SCAN` will likely return no elements in most iterations. An example is shown below: + +``` +redis 127.0.0.1:6379> scan 0 MATCH *11* +1) "288" +2) 1) "key:911" +redis 127.0.0.1:6379> scan 288 MATCH *11* +1) "224" +2) (empty list or set) +redis 127.0.0.1:6379> scan 224 MATCH *11* +1) "80" +2) (empty list or set) +redis 127.0.0.1:6379> scan 80 MATCH *11* +1) "176" +2) (empty list or set) +redis 127.0.0.1:6379> scan 176 MATCH *11* COUNT 1000 +1) "0" +2) 1) "key:611" + 2) "key:711" + 3) "key:118" + 4) "key:117" + 5) "key:311" + 6) "key:112" + 7) "key:111" + 8) "key:110" + 9) "key:113" + 10) "key:211" + 11) "key:411" + 12) "key:115" + 13) "key:116" + 14) "key:114" + 15) "key:119" + 16) "key:811" + 17) "key:511" + 18) "key:11" +redis 127.0.0.1:6379> +``` + +As you can see most of the calls returned zero elements, but the last call where a COUNT of 1000 was used in order to force the command to do more scanning for that iteration. + + +#### The TYPE option + +You can use the `!TYPE` option to ask `SCAN` to only return objects that match a given `type`, allowing you to iterate through the database looking for keys of a specific type. The **TYPE** option is only available on the whole-database `SCAN`, not `HSCAN` or `ZSCAN` etc. + +The `type` argument is the same string name that the `TYPE` command returns. Note a quirk where some Redis types, such as GeoHashes, HyperLogLogs, Bitmaps, and Bitfields, may internally be implemented using other Redis types, such as a string or zset, so can't be distinguished from other keys of that same type by `SCAN`. For example, a ZSET and GEOHASH: + +``` +redis 127.0.0.1:6379> GEOADD geokey 0 0 value +(integer) 1 +redis 127.0.0.1:6379> ZADD zkey 1000 value +(integer) 1 +redis 127.0.0.1:6379> TYPE geokey +zset +redis 127.0.0.1:6379> TYPE zkey +zset +redis 127.0.0.1:6379> SCAN 0 TYPE zset +1) "0" +2) 1) "geokey" + 2) "zkey" +``` + +It is important to note that the **TYPE** filter is also applied after elements are retrieved from the database, so the option does not reduce the amount of work the server has to do to complete a full iteration, and for rare types you may receive no elements in many iterations. + +#### Multiple parallel iterations + +It is possible for an infinite number of clients to iterate the same collection at the same time, as the full state of the iterator is in the cursor, that is obtained and returned to the client at every call. No server side state is taken at all. + +#### Terminating iterations in the middle + +Since there is no state server side, but the full state is captured by the cursor, the caller is free to terminate an iteration half-way without signaling this to the server in any way. An infinite number of iterations can be started and never terminated without any issue. + +#### Calling SCAN with a corrupted cursor + +Calling `SCAN` with a broken, negative, out of range, or otherwise invalid cursor, will result in undefined behavior but never in a crash. What will be undefined is that the guarantees about the returned elements can no longer be ensured by the `SCAN` implementation. + +The only valid cursors to use are: + +* The cursor value of 0 when starting an iteration. +* The cursor returned by the previous call to SCAN in order to continue the iteration. + +#### Guarantee of termination + +The `SCAN` algorithm is guaranteed to terminate only if the size of the iterated collection remains bounded to a given maximum size, otherwise iterating a collection that always grows may result into `SCAN` to never terminate a full iteration. + +This is easy to see intuitively: if the collection grows there is more and more work to do in order to visit all the possible elements, and the ability to terminate the iteration depends on the number of calls to `SCAN` and its COUNT option value compared with the rate at which the collection grows. + +#### Why SCAN may return all the items of an aggregate data type in a single call? + +In the `COUNT` option documentation, we state that sometimes this family of commands may return all the elements of a Set, Hash or Sorted Set at once in a single call, regardless of the `COUNT` option value. The reason why this happens is that the cursor-based iterator can be implemented, and is useful, only when the aggregate data type that we are scanning is represented as a hash table. However Redis uses a [memory optimization](/topics/memory-optimization) where small aggregate data types, until they reach a given amount of items or a given max size of single elements, are represented using a compact single-allocation packed encoding. When this is the case, `SCAN` has no meaningful cursor to return, and must iterate the whole data structure at once, so the only sane behavior it has is to return everything in a call. + +However once the data structures are bigger and are promoted to use real hash tables, the `SCAN` family of commands will resort to the normal behavior. Note that since this special behavior of returning all the elements is true only for small aggregates, it has no effects on the command complexity or latency. However the exact limits to get converted into real hash tables are [user configurable](/topics/memory-optimization), so the maximum number of elements you can see returned in a single call depends on how big an aggregate data type could be and still use the packed representation. + +Also note that this behavior is specific of `SSCAN`, `HSCAN` and `ZSCAN`. `SCAN` itself never shows this behavior because the key space is always represented by hash tables. + +### Keys + +Another way to iterate over the keyspace is to use the `KEYS` command, but this approach should be used with care, since `KEYS` will block the Redis server until all keys are returned. + +**Warning**: consider `KEYS` as a command that should only be used in production +environments with extreme care. + +`KEYS` may ruin performance when it is executed against large databases. +This command is intended for debugging and special operations, such as changing +your keyspace layout. +Don't use `KEYS` in your regular application code. +If you're looking for a way to find keys in a subset of your keyspace, consider +using `SCAN` or [sets][tdts]. + +[tdts]: /topics/data-types#sets + +Supported glob-style patterns: + +* `h?llo` matches `hello`, `hallo` and `hxllo` +* `h*llo` matches `hllo` and `heeeello` +* `h[ae]llo` matches `hello` and `hallo,` but not `hillo` +* `h[^e]llo` matches `hallo`, `hbllo`, ... but not `hello` +* `h[a-b]llo` matches `hallo` and `hbllo` + +Use `\` to escape special characters if you want to match them verbatim. diff --git a/wordlist b/wordlist index f9869c3ccb..6a74dd2934 100644 --- a/wordlist +++ b/wordlist @@ -61,6 +61,7 @@ B2 B3 BCC's BDFL-style +birthyear BPF BPF's BPF-optimized @@ -124,6 +125,8 @@ EDOM EEXIST EFBIG EINVAL +Enduro +Ergonom ENOENT ENOTSUP EOF @@ -169,13 +172,19 @@ HashMaps HashSets Haversine Hexastore +hget +hgetall +hincrby +hmget Hitmeister Homebrew Hotspot +hset HyperLogLog HyperLogLog. HyperLogLogs Hyperloglogs +hyperloglogs IOPs IPC IPs @@ -184,6 +193,7 @@ IPv6 IS-MASTER-DOWN-BY-ADDR Identinal IoT +incrby_get_mget Itamar Jedis JedisCluster @@ -216,11 +226,14 @@ Leaderboards Leau Lehmann Levelgraph +licensor +licensor's LibLZF Linode Liveness Lua Lua's +lua-debugging Lua-to-Redis Lucraft M1 @@ -258,6 +271,7 @@ Ok OpenBSD OpenSSL Opteron +ORM PEL PELs PEM @@ -352,6 +366,7 @@ S1 S2 S3 S4 +SaaS SCP SDOWN SHA-256 From 1a3e46873ce5add8b88fe4577e19addd06a7c71c Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Wed, 5 Jul 2023 13:56:07 +0100 Subject: [PATCH 224/377] =?UTF-8?q?Change=20path=20of=20=E2=80=9Cinteract-?= =?UTF-8?q?with-data=E2=80=9D=20(#2459)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/{interact-with-data => interact}/_index.md | 0 docs/{interact-with-data => interact}/programmability/_index.md | 0 .../programmability/eval-intro.md | 0 .../programmability/functions-intro.md | 0 docs/{interact-with-data => interact}/programmability/lua-api.md | 0 .../programmability/lua-debugging.md | 0 docs/{interact-with-data => interact}/pubsub.md | 0 docs/{interact-with-data => interact}/transactions.md | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename docs/{interact-with-data => interact}/_index.md (100%) rename docs/{interact-with-data => interact}/programmability/_index.md (100%) rename docs/{interact-with-data => interact}/programmability/eval-intro.md (100%) rename docs/{interact-with-data => interact}/programmability/functions-intro.md (100%) rename docs/{interact-with-data => interact}/programmability/lua-api.md (100%) rename docs/{interact-with-data => interact}/programmability/lua-debugging.md (100%) rename docs/{interact-with-data => interact}/pubsub.md (100%) rename docs/{interact-with-data => interact}/transactions.md (100%) diff --git a/docs/interact-with-data/_index.md b/docs/interact/_index.md similarity index 100% rename from docs/interact-with-data/_index.md rename to docs/interact/_index.md diff --git a/docs/interact-with-data/programmability/_index.md b/docs/interact/programmability/_index.md similarity index 100% rename from docs/interact-with-data/programmability/_index.md rename to docs/interact/programmability/_index.md diff --git a/docs/interact-with-data/programmability/eval-intro.md b/docs/interact/programmability/eval-intro.md similarity index 100% rename from docs/interact-with-data/programmability/eval-intro.md rename to docs/interact/programmability/eval-intro.md diff --git a/docs/interact-with-data/programmability/functions-intro.md b/docs/interact/programmability/functions-intro.md similarity index 100% rename from docs/interact-with-data/programmability/functions-intro.md rename to docs/interact/programmability/functions-intro.md diff --git a/docs/interact-with-data/programmability/lua-api.md b/docs/interact/programmability/lua-api.md similarity index 100% rename from docs/interact-with-data/programmability/lua-api.md rename to docs/interact/programmability/lua-api.md diff --git a/docs/interact-with-data/programmability/lua-debugging.md b/docs/interact/programmability/lua-debugging.md similarity index 100% rename from docs/interact-with-data/programmability/lua-debugging.md rename to docs/interact/programmability/lua-debugging.md diff --git a/docs/interact-with-data/pubsub.md b/docs/interact/pubsub.md similarity index 100% rename from docs/interact-with-data/pubsub.md rename to docs/interact/pubsub.md diff --git a/docs/interact-with-data/transactions.md b/docs/interact/transactions.md similarity index 100% rename from docs/interact-with-data/transactions.md rename to docs/interact/transactions.md From 069ddafd5376ace098fff5d40c522be64c73cae5 Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Thu, 6 Jul 2023 15:15:41 +0100 Subject: [PATCH 225/377] Fixes broken links --- commands/psubscribe.md | 2 +- commands/scan.md | 2 +- commands/subscribe.md | 2 +- docs/clients/_index.md | 8 ++++---- docs/clients/dotnet.md | 2 +- docs/clients/java.md | 2 +- docs/clients/python.md | 2 +- docs/data-types/_index.md | 4 ++-- docs/data-types/streams.md | 1 + docs/interact/pubsub.md | 1 + docs/manual/keyspace.md | 4 +++- wordlist | 1 + 12 files changed, 18 insertions(+), 13 deletions(-) diff --git a/commands/psubscribe.md b/commands/psubscribe.md index e18d910b37..c5936489f2 100644 --- a/commands/psubscribe.md +++ b/commands/psubscribe.md @@ -11,7 +11,7 @@ Use `\` to escape special characters if you want to match them verbatim. Once the client enters the subscribed state it is not supposed to issue any other commands, except for additional `SUBSCRIBE`, `SSUBSCRIBE`, `PSUBSCRIBE`, `UNSUBSCRIBE`, `SUNSUBSCRIBE`, `PUNSUBSCRIBE`, `PING`, `RESET` and `QUIT` commands. However, if RESP3 is used (see `HELLO`) it is possible for a client to issue any commands while in subscribed state. -For more information, see [Pub/sub](/docs/manual/pubsub/). +For more information, see [Pub/sub](/docs/interact/pubsub/). @return diff --git a/commands/scan.md b/commands/scan.md index 84ec7634c1..5a10ec6e8b 100644 --- a/commands/scan.md +++ b/commands/scan.md @@ -12,7 +12,7 @@ However while blocking commands like `SMEMBERS` are able to provide all the elem Note that `SCAN`, `SSCAN`, `HSCAN` and `ZSCAN` all work very similarly, so this documentation covers all the four commands. However an obvious difference is that in the case of `SSCAN`, `HSCAN` and `ZSCAN` the first argument is the name of the key holding the Set, Hash or Sorted Set value. The `SCAN` command does not need any key name argument as it iterates keys in the current database, so the iterated object is the database itself. -For more information on `SCAN` please refer to the [The Redis Keyspace](/docs/manual/the-redis-keyspace.md) tutorial. +For more information on `SCAN` please refer to the [The Redis Keyspace](/docs/manual/keyspace) tutorial. ## Return value diff --git a/commands/subscribe.md b/commands/subscribe.md index 39e21b2bd1..b9b4682775 100644 --- a/commands/subscribe.md +++ b/commands/subscribe.md @@ -5,7 +5,7 @@ other commands, except for additional `SUBSCRIBE`, `SSUBSCRIBE`, `PSUBSCRIBE`, ` `PUNSUBSCRIBE`, `PING`, `RESET` and `QUIT` commands. However, if RESP3 is used (see `HELLO`) it is possible for a client to issue any commands while in subscribed state. -For more information, see [Pub/sub](/docs/manual/pubsub/). +For more information, see [Pub/sub](/docs/interact/pubsub/). @return diff --git a/docs/clients/_index.md b/docs/clients/_index.md index 3b1a4981a7..b6dc6ae5b2 100644 --- a/docs/clients/_index.md +++ b/docs/clients/_index.md @@ -19,9 +19,9 @@ If you're ready to get started, see the following guides for the official client The Redis OM client libraries let you use the document modeling, indexing, and querying capabilities of Redis Stack much like the way you'd use an [ORM](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping). The following Redis OM libraries support Redis Stack: -* [Redis OM .NET](/docs/clients/stack-dotnet/) -* [Redis OM Node](/docs/clients/stack-node/) -* [Redis OM Python](/docs/clients/stack-python/) -* [Redis OM Spring](/docs/clients/stack-spring/) +* [Redis OM .NET](/docs/clients/om-clients/stack-dotnet/) +* [Redis OM Node](/docs/clients/om-clients/stack-node/) +* [Redis OM Python](/docs/clients/om-clients/stack-python/) +* [Redis OM Spring](/docs/clients/om-clients/stack-spring/)
\ No newline at end of file diff --git a/docs/clients/dotnet.md b/docs/clients/dotnet.md index 5ab389dfdb..3f3c309bb6 100644 --- a/docs/clients/dotnet.md +++ b/docs/clients/dotnet.md @@ -211,7 +211,7 @@ var user3 = new { }; ``` -Create an index. In this example, all JSON documents with the key prefix `user:` are indexed. For more information, see [Query syntax](/docs/stack/search/reference/query_syntax). +Create an index. In this example, all JSON documents with the key prefix `user:` are indexed. For more information, see [Query syntax](/docs/interact/search-and-query/query/). ```csharp var schema = new Schema() diff --git a/docs/clients/java.md b/docs/clients/java.md index 9367c22493..ccde8b5b7e 100644 --- a/docs/clients/java.md +++ b/docs/clients/java.md @@ -228,7 +228,7 @@ User user2 = new User("Eden Zamir", "eden.zamir@example.com", 29, "Tel Aviv"); User user3 = new User("Paul Zamir", "paul.zamir@example.com", 35, "Tel Aviv"); ``` -Create an index. In this example, all JSON documents with the key prefix `user:` are indexed. For more information, see [Query syntax](/docs/stack/search/reference/query_syntax). +Create an index. In this example, all JSON documents with the key prefix `user:` are indexed. For more information, see [Query syntax](/docs/interact/search-and-query/query/). ```java jedis.ftCreate("idx:users", diff --git a/docs/clients/python.md b/docs/clients/python.md index 2a4e9da63a..1b3d920831 100644 --- a/docs/clients/python.md +++ b/docs/clients/python.md @@ -157,7 +157,7 @@ schema = ( ) ``` -Create an index. In this example, all JSON documents with the key prefix `user:` will be indexed. For more information, see [Query syntax](/docs/stack/search/reference/query_syntax). +Create an index. In this example, all JSON documents with the key prefix `user:` will be indexed. For more information, see [Query syntax](/docs/interact/search-and-query/query/). ```python rs = r.ft("idx:users") diff --git a/docs/data-types/_index.md b/docs/data-types/_index.md index 0defc77a43..2a12c89089 100644 --- a/docs/data-types/_index.md +++ b/docs/data-types/_index.md @@ -12,7 +12,8 @@ Redis is a data structure server. At its core, Redis provides a collection of native data types that help you solve a wide variety of problems, from [caching](/docs/manual/client-side-caching/) to [queuing](/docs/data-types/lists/) to [event processing](/docs/data-types/streams/). Below is a short description of each data type, with links to broader overviews and command references. -If you'd like to try a comprehensive tutorial, see the [Redis data types tutorial](/docs/data-types/tutorial/). +If you'd like to try a comprehensive tutorial for each data structure, see their overview pages below. + ## Core @@ -66,7 +67,6 @@ For more information, see: * [Overview of Redis Streams](/docs/data-types/streams) * [Redis Streams command reference](/commands/?group=stream) -* [Redis Streams tutorial](/docs/data-types/streams-tutorial) ### Geospatial indexes diff --git a/docs/data-types/streams.md b/docs/data-types/streams.md index 6488c5519a..807cc994d4 100644 --- a/docs/data-types/streams.md +++ b/docs/data-types/streams.md @@ -7,6 +7,7 @@ description: > aliases: - /topics/streams-intro - /docs/manual/data-types/streams + - /docs/data-types/streams-tutorial/ --- A Redis stream is a data structure that acts like an append-only log but also implements several operations to overcome some of the limits of a typical append-only log. These include random access in O(1) time and complex consumption strategies, such as consumer groups. diff --git a/docs/interact/pubsub.md b/docs/interact/pubsub.md index 7b3373d049..d9ed33e98c 100644 --- a/docs/interact/pubsub.md +++ b/docs/interact/pubsub.md @@ -6,6 +6,7 @@ description: How to use pub/sub channels in Redis aliases: - /topics/pubsub - /docs/manual/pub-sub + - /docs/manual/pubsub --- `SUBSCRIBE`, `UNSUBSCRIBE` and `PUBLISH` implement the [Publish/Subscribe messaging paradigm](http://en.wikipedia.org/wiki/Publish/subscribe) where (citing Wikipedia) senders (publishers) are not programmed to send their messages to specific receivers (subscribers). diff --git a/docs/manual/keyspace.md b/docs/manual/keyspace.md index 0bd903e655..11a534434d 100644 --- a/docs/manual/keyspace.md +++ b/docs/manual/keyspace.md @@ -4,13 +4,15 @@ linkTitle: "Keyspace" weight: 1 description: > Managing keys in Redis: Key expiration, scanning, altering and querying the key space +alias: + - /docs/manual/the-redis-keyspace --- Redis keys are binary safe; this means that you can use any binary sequence as a key, from a string like "foo" to the content of a JPEG file. The empty string is also a valid key. -A few other rules about keys: +A few other rules about keys: * Very long keys are not a good idea. For instance a key of 1024 bytes is a bad idea not only memory-wise, but also because the lookup of the key in the diff --git a/wordlist b/wordlist index 6a74dd2934..601a8a6947 100644 --- a/wordlist +++ b/wordlist @@ -966,6 +966,7 @@ systemctl taskset tcmalloc tcp +the-redis-keyspace tls-port tmp tmux From 093e10ac0c03ba83ff6d9a1703b3f082b73d3edc Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Thu, 6 Jul 2023 15:53:14 +0100 Subject: [PATCH 226/377] Fixes more broken links --- docs/clients/_index.md | 2 +- docs/clients/dotnet.md | 2 +- docs/clients/nodejs.md | 2 +- docs/clients/python.md | 2 +- docs/getting-started/_index.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/clients/_index.md b/docs/clients/_index.md index b6dc6ae5b2..a5d1b09dd0 100644 --- a/docs/clients/_index.md +++ b/docs/clients/_index.md @@ -8,7 +8,7 @@ aliases: - /docs/stack/get-started/clients/ --- -Here, you will learn how to connect your application to a Redis database. If you're new to Redis, you might first want to [install Redis with Redis Stack and RedisInsight](/docs/stack/get-started/install). +Here, you will learn how to connect your application to a Redis database. If you're new to Redis, you might first want to [install Redis with Redis Stack and RedisInsight](/docs/getting-started/install-stack/). For more Redis topics, see [Using](/docs/manual/) and [Managing](/docs/management/) Redis. diff --git a/docs/clients/dotnet.md b/docs/clients/dotnet.md index 3f3c309bb6..4f62fd34b5 100644 --- a/docs/clients/dotnet.md +++ b/docs/clients/dotnet.md @@ -11,7 +11,7 @@ Install Redis and the Redis client, then connect your .NET application to a Redi ## NRedisStack [NRedisStack](https://github.com/redis/NRedisStack) is a .NET client for Redis. -`NredisStack` requires a running Redis or [Redis Stack](https://redis.io/docs/stack/get-started/install/) server. See [Getting started](/docs/getting-started/) for Redis installation instructions. +`NredisStack` requires a running Redis or [Redis Stack](https://redis.io/docs/getting-started/install-stack/) server. See [Getting started](/docs/getting-started/) for Redis installation instructions. ### Install diff --git a/docs/clients/nodejs.md b/docs/clients/nodejs.md index 8f2e2593de..17faa6d7d1 100644 --- a/docs/clients/nodejs.md +++ b/docs/clients/nodejs.md @@ -11,7 +11,7 @@ Install Redis and the Redis client, then connect your Node.js application to a R ## node-redis [node-redis](https://github.com/redis/node-redis) is a modern, high-performance Redis client for Node.js. -`node-redis` requires a running Redis or [Redis Stack](https://redis.io/docs/stack/get-started/install/) server. See [Getting started](/docs/getting-started/) for Redis installation instructions. +`node-redis` requires a running Redis or [Redis Stack](https://redis.io/docs/getting-started/install-stack/) server. See [Getting started](/docs/getting-started/) for Redis installation instructions. ### Install diff --git a/docs/clients/python.md b/docs/clients/python.md index 1b3d920831..1a7610e3b6 100644 --- a/docs/clients/python.md +++ b/docs/clients/python.md @@ -12,7 +12,7 @@ Install Redis and the Redis client, then connect your Python application to a Re Get started with the [redis-py](https://github.com/redis/redis-py) client for Redis. -`redis-py` requires a running Redis or [Redis Stack](/docs/stack/get-started/install/) server. See [Getting started](/docs/getting-started/) for Redis installation instructions. +`redis-py` requires a running Redis or [Redis Stack](/docs/getting-started/install-stack/) server. See [Getting started](/docs/getting-started/) for Redis installation instructions. ### Install diff --git a/docs/getting-started/_index.md b/docs/getting-started/_index.md index 12352e5220..8a97629bcc 100644 --- a/docs/getting-started/_index.md +++ b/docs/getting-started/_index.md @@ -20,7 +20,7 @@ How you install Redis depends on your operating system and whether you'd like to * [Install Redis on Linux](/docs/getting-started/installation/install-redis-on-linux) * [Install Redis on macOS](/docs/getting-started/installation/install-redis-on-mac-os) * [Install Redis on Windows](/docs/getting-started/installation/install-redis-on-windows) -* [Install Redis with Redis Stack and RedisInsight](/docs/stack/get-started/install) +* [Install Redis with Redis Stack and RedisInsight](/docs/getting-started/install-stack/) Once you have Redis up and running, and can connect using `redis-cli`, you can continue with the steps below. From 30d34af3c0058c6afb8bdf65dab39639be7e271f Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Thu, 6 Jul 2023 18:22:04 +0100 Subject: [PATCH 227/377] Fixes more links --- docs/about/license.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/about/license.md b/docs/about/license.md index ba95aad298..31291c669e 100644 --- a/docs/about/license.md +++ b/docs/about/license.md @@ -17,7 +17,7 @@ used in accordance with the [Redis Trademark Guidelines](https://redis.com/legal * RedisInsight is licensed under the Server Side Public License (SSPL). -* Redis Stack Server, which combines open source Redis with Search and Query features, JSON, Time Series, and Probabilistic data structures is dual-licensed under the Redis Source Available License (RSALv2), as described below, and the [Server Side Public License](https://en.wikipedia.org/wiki/Server_Side_Public_License) (SSPL). For information about licensing per version, see [Versions and licenses](/docs/stack/#versions-and-licenses). +* Redis Stack Server, which combines open source Redis with Search and Query features, JSON, Time Series, and Probabilistic data structures is dual-licensed under the Redis Source Available License (RSALv2), as described below, and the [Server Side Public License](https://en.wikipedia.org/wiki/Server_Side_Public_License) (SSPL). For information about licensing per version, see [Versions and licenses](/docs/about/about-stack/#redis-stack-license). ## Licences: From 147a9f694aaee4d63f2017c3cbc86cbdcf693c46 Mon Sep 17 00:00:00 2001 From: Savannah Date: Fri, 7 Jul 2023 11:36:40 -0400 Subject: [PATCH 228/377] Update strings.md update strings datatype page to include hugo short codes for tabbed examples, removed "Let's play a bit with the string type, using redis-cli (all the examples will be performed via redis-cli in this tutorial)." as these examples will be in all the client languages --- docs/data-types/strings.md | 43 ++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/docs/data-types/strings.md b/docs/data-types/strings.md index 7a5f0dfdc2..a38d565a8c 100644 --- a/docs/data-types/strings.md +++ b/docs/data-types/strings.md @@ -15,13 +15,12 @@ Since Redis keys are strings, when we use the string type as a value too, we are mapping a string to another string. The string data type is useful for a number of use cases, like caching HTML fragments or pages. -Let's play a bit with the string type, using `redis-cli` (all the examples -will be performed via `redis-cli` in this tutorial). - - > set mykey somevalue +{{< clients-example set_tutorial set_get >}} + > set bike:1 Deimos OK - > get mykey - "somevalue" + > get bike:1 + "Deimos" +{{< /clients-example >}} As you can see using the `SET` and the `GET` commands are the way we set and retrieve a string value. Note that `SET` will replace any existing value @@ -35,10 +34,12 @@ The `SET` command has interesting options, that are provided as additional arguments. For example, I may ask `SET` to fail if the key already exists, or the opposite, that it only succeed if the key already exists: - > set mykey newval nx +{{< clients-example set_tutorial setnx_xx >}} + > set bike:1 bike nx (nil) - > set mykey newval xx + > set bike:1 bike xx OK +{{< /clients-example >}} There are a number of other commands for operating on strings. For example the `GETSET` command sets a key to a new value, returning the old value as the @@ -53,12 +54,14 @@ The ability to set or retrieve the value of multiple keys in a single command is also useful for reduced latency. For this reason there are the `MSET` and `MGET` commands: - > mset a 10 b 20 c 30 +{{< clients-example set_tutorial mset >}} + > mset bike:1 "Deimos" bike:2 "Ares" bike:3 "Vanth" OK - > mget a b c - 1) "10" - 2) "20" - 3) "30" + > mget bike:1 bike:2 bike:3 + 1) "Deimos" + 2) "Ares" + 3) "Vanth" +{{< /clients-example >}} When `MGET` is used, Redis returns an array of values. @@ -66,14 +69,14 @@ When `MGET` is used, Redis returns an array of values. Even if strings are the basic values of Redis, there are interesting operations you can perform with them. For instance, one is atomic increment: - > set counter 100 +{{< clients-example set_tutorial incr >}} + > set total_crashes 0 OK - > incr counter - (integer) 101 - > incr counter - (integer) 102 - > incrby counter 50 - (integer) 152 + > incr total_crashes + (integer) 1 + > incrby total_crashes 10 + (integer) 11 +{{< /clients-example >}} The `INCRBY` command parses the string value as an integer, increments it by one, and finally sets the obtained value as the new value. From db8bee493da85f8f8967a06104503bb94ac66b86 Mon Sep 17 00:00:00 2001 From: Valentino Geron Date: Sun, 9 Jul 2023 20:17:48 +0300 Subject: [PATCH 229/377] Remove duplication of "modules" section (#2478) --- commands/info.md | 1 - 1 file changed, 1 deletion(-) diff --git a/commands/info.md b/commands/info.md index d1ebe5481a..0ea28bd41b 100644 --- a/commands/info.md +++ b/commands/info.md @@ -16,7 +16,6 @@ The optional parameter can be used to select a specific section of information: * `cluster`: Redis Cluster section * `modules`: Modules section * `keyspace`: Database related statistics -* `modules`: Module related sections * `errorstats`: Redis error statistics It can also take the following values: From ab025f62797f2622ddad7bad938e747bebb6ab09 Mon Sep 17 00:00:00 2001 From: Oran Agra Date: Mon, 10 Jul 2023 15:25:59 +0300 Subject: [PATCH 230/377] update docs from 7.2-rc3 release (#2479) --- commands.json | 10 +++++---- docs/reference/modules/modules-api-ref.md | 26 +++++++++++++++++------ 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/commands.json b/commands.json index 8cfc9c9777..1d4ef0df12 100644 --- a/commands.json +++ b/commands.json @@ -3005,6 +3005,7 @@ ], "arity": 2, "command_flags": [ + "loading", "stale" ], "hints": [ @@ -3064,6 +3065,7 @@ ], "arity": 2, "command_flags": [ + "loading", "stale" ], "doc_flags": [ @@ -10497,7 +10499,7 @@ "summary": "Listens for messages published to channels that match one or more patterns.", "since": "2.0.0", "group": "pubsub", - "complexity": "O(N) where N is the number of patterns the client is already subscribed to.", + "complexity": "O(N) where N is the number of patterns to subscribe to.", "acl_categories": [ "@pubsub", "@slow" @@ -10771,7 +10773,7 @@ "summary": "Stops listening to messages published to channels that match one or more patterns.", "since": "2.0.0", "group": "pubsub", - "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).", + "complexity": "O(N) where N is the number of patterns to unsubscribe.", "acl_categories": [ "@pubsub", "@slow" @@ -13852,7 +13854,7 @@ "summary": "Stops listening to messages posted to shard channels.", "since": "7.0.0", "group": "pubsub", - "complexity": "O(N) where N is the number of clients already subscribed to a shard channel.", + "complexity": "O(N) where N is the number of shard channels to unsubscribe.", "acl_categories": [ "@pubsub", "@slow" @@ -14154,7 +14156,7 @@ "summary": "Stops listening to messages posted to channels.", "since": "2.0.0", "group": "pubsub", - "complexity": "O(N) where N is the number of clients already subscribed to a channel.", + "complexity": "O(N) where N is the number of channels to unsubscribe.", "acl_categories": [ "@pubsub", "@slow" diff --git a/docs/reference/modules/modules-api-ref.md b/docs/reference/modules/modules-api-ref.md index f116749578..cea9ba6493 100644 --- a/docs/reference/modules/modules-api-ref.md +++ b/docs/reference/modules/modules-api-ref.md @@ -1426,15 +1426,15 @@ The function always returns `REDISMODULE_OK`. Reply with the error create from a printf format and arguments. -If the error code is already passed in the string 'fmt', the error -code provided is used, otherwise the string "-ERR " for the generic -error code is automatically added. +Note that 'fmt' must contain all the error, including +the initial error code. The function only provides the initial "-", so +the usage is, for example: -The usage is, for example: + RedisModule_ReplyWithErrorFormat(ctx,"ERR Wrong Type: %s",type); - RedisModule_ReplyWithErrorFormat(ctx, "An error: %s", "foo"); +and not just: - RedisModule_ReplyWithErrorFormat(ctx, "-WRONGTYPE Wrong Type: %s", "foo"); + RedisModule_ReplyWithErrorFormat(ctx,"Wrong Type: %s",type); The function always returns `REDISMODULE_OK`. @@ -5005,6 +5005,9 @@ and so Redis will make no attempt to protect the module from infinite loops. '`free_pd`' can be NULL and in such case will not be used. +Return `REDISMODULE_OK` on success and `REDISMODULE_ERR` if was called while loading data from disk (AOF or RDB) or +if the instance is a readonly replica. + ### `RedisModule_GetNotifyKeyspaceEvents` @@ -6481,6 +6484,16 @@ or used elsewhere. Modify the filtered command by deleting an argument at the specified position. + + +### `RedisModule_CommandFilterGetClientId` + + unsigned long long RedisModule_CommandFilterGetClientId(RedisModuleCommandFilterCtx *fctx); + +**Available since:** unreleased + +Get Client ID for client that issued the command we are filtering + ### `RedisModule_MallocSize` @@ -7780,6 +7793,7 @@ There is no guarantee that this info is always available, so this may return -1. * [`RedisModule_CommandFilterArgInsert`](#RedisModule_CommandFilterArgInsert) * [`RedisModule_CommandFilterArgReplace`](#RedisModule_CommandFilterArgReplace) * [`RedisModule_CommandFilterArgsCount`](#RedisModule_CommandFilterArgsCount) +* [`RedisModule_CommandFilterGetClientId`](#RedisModule_CommandFilterGetClientId) * [`RedisModule_CreateCommand`](#RedisModule_CreateCommand) * [`RedisModule_CreateDataType`](#RedisModule_CreateDataType) * [`RedisModule_CreateDict`](#RedisModule_CreateDict) From eccc0547bfe4fa81a4894a2bdeec6475931dbd59 Mon Sep 17 00:00:00 2001 From: sewenew Date: Mon, 10 Jul 2023 21:53:24 +0800 Subject: [PATCH 231/377] Add redis-llm to community module list (#2477) --- modules/community/github.com/sewenew/redis-llm.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 modules/community/github.com/sewenew/redis-llm.json diff --git a/modules/community/github.com/sewenew/redis-llm.json b/modules/community/github.com/sewenew/redis-llm.json new file mode 100644 index 0000000000..bf82312fd1 --- /dev/null +++ b/modules/community/github.com/sewenew/redis-llm.json @@ -0,0 +1,8 @@ +{ + "name": "redis-llm", + "license": "Apache-2.0", + "description": "Redis module integrating LLM (Large Language Model) with Redis", + "github": [ + "sewenew" + ] +} From e3dfe4306be5fa3f0d9299835fad274f2ff5cdfd Mon Sep 17 00:00:00 2001 From: Fuchi Takeshi Date: Mon, 10 Jul 2023 22:54:36 +0900 Subject: [PATCH 232/377] add RedisMMap.json (#2444) --- modules/community/github.com/t-fuchi/RedisMMap.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 modules/community/github.com/t-fuchi/RedisMMap.json diff --git a/modules/community/github.com/t-fuchi/RedisMMap.json b/modules/community/github.com/t-fuchi/RedisMMap.json new file mode 100644 index 0000000000..91705768e7 --- /dev/null +++ b/modules/community/github.com/t-fuchi/RedisMMap.json @@ -0,0 +1,8 @@ +{ + "name": "RedisMMap", + "license": "MIT", + "description": "Redis module for accessing values on mmapped file.", + "github": [ + "t-fuchi" + ] +} \ No newline at end of file From 07acdfb2dff38baa494649a1b95a3822af26cb86 Mon Sep 17 00:00:00 2001 From: Jerrod Carpenter <4128301+JerrodCarpenter@users.noreply.github.com> Date: Mon, 10 Jul 2023 08:55:29 -0500 Subject: [PATCH 233/377] Remove archived ruby client (#2423) --- clients/ruby/github.com/etehtsea/oxblood.json | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 clients/ruby/github.com/etehtsea/oxblood.json diff --git a/clients/ruby/github.com/etehtsea/oxblood.json b/clients/ruby/github.com/etehtsea/oxblood.json deleted file mode 100644 index 642946babc..0000000000 --- a/clients/ruby/github.com/etehtsea/oxblood.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "oxblood", - "description": "Straightforward Ruby client.", - "twitter": [ - "etehtsea" - ] -} \ No newline at end of file From 9d1137324d66b638ad93f546a9ee8e811ffd862a Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Mon, 10 Jul 2023 17:05:46 +0300 Subject: [PATCH 234/377] Fixes some broken links (#2480) * Removes 404s * Use wikipedia's page - site is dead --- clients/php/github.com/swoole/redis-async.json | 4 ---- docs/about/sponsors.md | 2 +- modules/community/github.com/Clement-Jean/RedisIMS.json | 8 -------- 3 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 clients/php/github.com/swoole/redis-async.json delete mode 100644 modules/community/github.com/Clement-Jean/RedisIMS.json diff --git a/clients/php/github.com/swoole/redis-async.json b/clients/php/github.com/swoole/redis-async.json deleted file mode 100644 index cf010cb66f..0000000000 --- a/clients/php/github.com/swoole/redis-async.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "redis-async", - "description": "Asynchronous redis client library for PHP." -} \ No newline at end of file diff --git a/docs/about/sponsors.md b/docs/about/sponsors.md index 8c9180a783..1426a14509 100644 --- a/docs/about/sponsors.md +++ b/docs/about/sponsors.md @@ -11,7 +11,7 @@ From 2015 to 2020, Salvatore Sanfilippo's work on Redis was sponsored by [Redis Past sponsorships: -* The [Shuttleworth Foundation](http://www.shuttleworthfoundation.org) has donated 5000 USD to the Redis project in form of a flash grant. +* The [Shuttleworth Foundation](https://en.wikipedia.org/wiki/Shuttleworth_Foundation) has donated 5000 USD to the Redis project in form of a flash grant. * From May 2013 to June 2015, the work [Salvatore Sanfilippo](http://twitter.com/antirez) did to develop Redis was sponsored by [Pivotal](http://gopivotal.com). * Before May 2013, the project was sponsored by VMware with the work of [Salvatore Sanfilippo](http://twitter.com/antirez) and [Pieter Noordhuis](http://twitter.com/pnoordhuis). * [VMware](http://vmware.com) and later [Pivotal](http://pivotal.io) provided a 24 GB RAM workstation for Salvatore to run the Redis CI test and other long running tests. Later, Salvatore equipped the server with an SSD drive in order to test in the same hardware with rotating and flash drives. diff --git a/modules/community/github.com/Clement-Jean/RedisIMS.json b/modules/community/github.com/Clement-Jean/RedisIMS.json deleted file mode 100644 index 6725b620df..0000000000 --- a/modules/community/github.com/Clement-Jean/RedisIMS.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "redisims", - "license": "MIT", - "description": "A lightweight Redis module following the If Modified Since (IMS) pattern for caching", - "github": [ - "Clement-Jean" - ] -} \ No newline at end of file From 16f7810069623c40dc20726578dc2e6e5bc0a07d Mon Sep 17 00:00:00 2001 From: Elena Kolevska Date: Mon, 10 Jul 2023 22:56:23 +0100 Subject: [PATCH 235/377] =?UTF-8?q?Fixes=20redirect=20for=20the=20?= =?UTF-8?q?=E2=80=9CKeyspace=E2=80=9D=20page=20(#2481)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/manual/keyspace.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/keyspace.md b/docs/manual/keyspace.md index 11a534434d..5e37c2bf1f 100644 --- a/docs/manual/keyspace.md +++ b/docs/manual/keyspace.md @@ -4,7 +4,7 @@ linkTitle: "Keyspace" weight: 1 description: > Managing keys in Redis: Key expiration, scanning, altering and querying the key space -alias: +aliases: - /docs/manual/the-redis-keyspace --- From 196c169158decc199d9205e10f2bb91ec5ca73a6 Mon Sep 17 00:00:00 2001 From: chentianjie Date: Fri, 14 Jul 2023 11:20:05 +0800 Subject: [PATCH 236/377] Update doc of command cluster nodes. --- commands/cluster-nodes.md | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/commands/cluster-nodes.md b/commands/cluster-nodes.md index 8ccc52152d..dfdd88ce6c 100644 --- a/commands/cluster-nodes.md +++ b/commands/cluster-nodes.md @@ -17,23 +17,24 @@ It is also used by `redis-cli` in order to manage a cluster. ## Serialization format The output of the command is just a space-separated CSV string, where -each line represents a node in the cluster. Starting from 7.2.0, the -output of the command always contains a new auxiliary field called -shard-id. The following is an example of output on Redis 7.2.0. +each line represents a node in the cluster. The auxiliary fields +(including shard ID, human node name and extra port number) stored in +nodes.conf file are currently hidden from client commands. The following +is an example of output on Redis 7.2.0. ``` -07c37dfeb235213a872192d90877d0cd55635b91 127.0.0.1:30004@31004,,shard-id=69bc080733d1355567173199cff4a6a039a2f024 slave e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca 0 1426238317239 4 connected -67ed2db8d677e59ec4a4cefb06858cf2a1a89fa1 127.0.0.1:30002@31002,,shard-id=114f6674a35b84949fe567f5dfd41415ee776261 master - 0 1426238316232 2 connected 5461-10922 -292f8b365bb7edb5e285caf0b7e6ddc7265d2f4f 127.0.0.1:30003@31003,,shard-id=fdb36c73e72dd027bc19811b7c219ef6e55c550e master - 0 1426238318243 3 connected 10923-16383 -6ec23923021cf3ffec47632106199cb7f496ce01 127.0.0.1:30005@31005,,shard-id=114f6674a35b84949fe567f5dfd41415ee776261 slave 67ed2db8d677e59ec4a4cefb06858cf2a1a89fa1 0 1426238316232 5 connected -824fe116063bc5fcf9f4ffd895bc17aee7731ac3 127.0.0.1:30006@31006,,shard-id=fdb36c73e72dd027bc19811b7c219ef6e55c550e slave 292f8b365bb7edb5e285caf0b7e6ddc7265d2f4f 0 1426238317741 6 connected -e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca 127.0.0.1:30001@31001,,shard-id=69bc080733d1355567173199cff4a6a039a2f024 myself,master - 0 0 1 connected 0-5460 +07c37dfeb235213a872192d90877d0cd55635b91 127.0.0.1:30004@31004,hostname4 slave e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca 0 1426238317239 4 connected +67ed2db8d677e59ec4a4cefb06858cf2a1a89fa1 127.0.0.1:30002@31002,hostname2 master - 0 1426238316232 2 connected 5461-10922 +292f8b365bb7edb5e285caf0b7e6ddc7265d2f4f 127.0.0.1:30003@31003,hostname3 master - 0 1426238318243 3 connected 10923-16383 +6ec23923021cf3ffec47632106199cb7f496ce01 127.0.0.1:30005@31005,hostname5 slave 67ed2db8d677e59ec4a4cefb06858cf2a1a89fa1 0 1426238316232 5 connected +824fe116063bc5fcf9f4ffd895bc17aee7731ac3 127.0.0.1:30006@31006,hostname6 slave 292f8b365bb7edb5e285caf0b7e6ddc7265d2f4f 0 1426238317741 6 connected +e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca 127.0.0.1:30001@31001,hostname1 myself,master - 0 0 1 connected 0-5460 ``` Each line is composed of the following fields: ``` - ... + ... ``` The meaning of each field is the following: @@ -41,17 +42,13 @@ The meaning of each field is the following: 1. `id`: The node ID, a 40-character globally unique string generated when a node is created and never changed again (unless `CLUSTER RESET HARD` is used). 2. `ip:port@cport`: The node address that clients should contact to run queries. 3. `hostname`: A human readable string that can be configured via the `cluster-annouce-hostname` setting. The max length of the string is 256 characters, excluding the null terminator. The name can contain ASCII alphanumeric characters, '-', and '.' only. -4. `[,auxiliary_field=value]*`: A list of comma-separated key-value pairs that represent various node properties, such as `shard-id`. There is no intrinsic order among auxiliary fields. The auxiliary fields can appear at different position in the list from release to release. Both the key name and value can contain ASCII alphanumeric characters and the characters in `!#$%&()*+-.:;<>?@[]^_{|}~` only. Auxiliary fields are explained in detail in the section below. -5. `flags`: A list of comma separated flags: `myself`, `master`, `slave`, `fail?`, `fail`, `handshake`, `noaddr`, `nofailover`, `noflags`. Flags are explained below. -6. `master`: If the node is a replica, and the primary is known, the primary node ID, otherwise the "-" character. -7. `ping-sent`: Unix time at which the currently active ping was sent, or zero if there are no pending pings, in milliseconds. -8. `pong-recv`: Unix time the last pong was received, in milliseconds. -9. `config-epoch`: The configuration epoch (or version) of the current node (or of the current primary if the node is a replica). Each time there is a failover, a new, unique, monotonically increasing configuration epoch is created. If multiple nodes claim to serve the same hash slots, the one with the higher configuration epoch wins. -10. `link-state`: The state of the link used for the node-to-node cluster bus. Use this link to communicate with the node. Can be `connected` or `disconnected`. -11. `slot`: A hash slot number or range. Starting from argument number 9, but there may be up to 16384 entries in total (limit never reached). This is the list of hash slots served by this node. If the entry is just a number, it is parsed as such. If it is a range, it is in the form `start-end`, and means that the node is responsible for all the hash slots from `start` to `end` including the start and end values. - -Auxiliary fields are: -* `shard-id`: a 40-character globally unique string generated when a node is created. A node's shard id changes only when the node joins a different shard via `cluster replicate` and there the node's shard id is updated to its primary's. +4. `flags`: A list of comma separated flags: `myself`, `master`, `slave`, `fail?`, `fail`, `handshake`, `noaddr`, `nofailover`, `noflags`. Flags are explained below. +5. `master`: If the node is a replica, and the primary is known, the primary node ID, otherwise the "-" character. +6. `ping-sent`: Unix time at which the currently active ping was sent, or zero if there are no pending pings, in milliseconds. +7. `pong-recv`: Unix time the last pong was received, in milliseconds. +8. `config-epoch`: The configuration epoch (or version) of the current node (or of the current primary if the node is a replica). Each time there is a failover, a new, unique, monotonically increasing configuration epoch is created. If multiple nodes claim to serve the same hash slots, the one with the higher configuration epoch wins. +9. `link-state`: The state of the link used for the node-to-node cluster bus. Use this link to communicate with the node. Can be `connected` or `disconnected`. +10. `slot`: A hash slot number or range. Starting from argument number 9, but there may be up to 16384 entries in total (limit never reached). This is the list of hash slots served by this node. If the entry is just a number, it is parsed as such. If it is a range, it is in the form `start-end`, and means that the node is responsible for all the hash slots from `start` to `end` including the start and end values.s Flags are: From d8c8a8ecb947bafeb855eeeab525eb5d64924ced Mon Sep 17 00:00:00 2001 From: Binbin Date: Fri, 14 Jul 2023 21:37:23 +0800 Subject: [PATCH 237/377] Fix WRONGTYPE code example in transcation.md (#2483) --- docs/interact/transactions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/interact/transactions.md b/docs/interact/transactions.md index 9641f986bb..e9504fd47e 100644 --- a/docs/interact/transactions.md +++ b/docs/interact/transactions.md @@ -112,11 +112,11 @@ LPOP a EXEC *2 +OK --ERR Operation against a key holding the wrong kind of value +-WRONGTYPE Operation against a key holding the wrong kind of value ``` `EXEC` returned two-element [bulk string reply](/topics/protocol#bulk-string-reply) where one is an `OK` code and -the other an `-ERR` reply. It's up to the client library to find a +the other an error reply. It's up to the client library to find a sensible way to provide the error to the user. It's important to note that From d4df8b06fdbad0a2f007852d327519165d0e3934 Mon Sep 17 00:00:00 2001 From: Madelyn Olson <34459052+madolson@users.noreply.github.com> Date: Sat, 15 Jul 2023 20:09:03 -0700 Subject: [PATCH 238/377] Update commands/cluster-nodes.md Revert the numbering --- commands/cluster-nodes.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/commands/cluster-nodes.md b/commands/cluster-nodes.md index dfdd88ce6c..b175ec64e7 100644 --- a/commands/cluster-nodes.md +++ b/commands/cluster-nodes.md @@ -42,13 +42,13 @@ The meaning of each field is the following: 1. `id`: The node ID, a 40-character globally unique string generated when a node is created and never changed again (unless `CLUSTER RESET HARD` is used). 2. `ip:port@cport`: The node address that clients should contact to run queries. 3. `hostname`: A human readable string that can be configured via the `cluster-annouce-hostname` setting. The max length of the string is 256 characters, excluding the null terminator. The name can contain ASCII alphanumeric characters, '-', and '.' only. -4. `flags`: A list of comma separated flags: `myself`, `master`, `slave`, `fail?`, `fail`, `handshake`, `noaddr`, `nofailover`, `noflags`. Flags are explained below. -5. `master`: If the node is a replica, and the primary is known, the primary node ID, otherwise the "-" character. -6. `ping-sent`: Unix time at which the currently active ping was sent, or zero if there are no pending pings, in milliseconds. -7. `pong-recv`: Unix time the last pong was received, in milliseconds. -8. `config-epoch`: The configuration epoch (or version) of the current node (or of the current primary if the node is a replica). Each time there is a failover, a new, unique, monotonically increasing configuration epoch is created. If multiple nodes claim to serve the same hash slots, the one with the higher configuration epoch wins. -9. `link-state`: The state of the link used for the node-to-node cluster bus. Use this link to communicate with the node. Can be `connected` or `disconnected`. -10. `slot`: A hash slot number or range. Starting from argument number 9, but there may be up to 16384 entries in total (limit never reached). This is the list of hash slots served by this node. If the entry is just a number, it is parsed as such. If it is a range, it is in the form `start-end`, and means that the node is responsible for all the hash slots from `start` to `end` including the start and end values.s +5. `flags`: A list of comma separated flags: `myself`, `master`, `slave`, `fail?`, `fail`, `handshake`, `noaddr`, `nofailover`, `noflags`. Flags are explained below. +6. `master`: If the node is a replica, and the primary is known, the primary node ID, otherwise the "-" character. +7. `ping-sent`: Unix time at which the currently active ping was sent, or zero if there are no pending pings, in milliseconds. +8. `pong-recv`: Unix time the last pong was received, in milliseconds. +9. `config-epoch`: The configuration epoch (or version) of the current node (or of the current primary if the node is a replica). Each time there is a failover, a new, unique, monotonically increasing configuration epoch is created. If multiple nodes claim to serve the same hash slots, the one with the higher configuration epoch wins. +10. `link-state`: The state of the link used for the node-to-node cluster bus. Use this link to communicate with the node. Can be `connected` or `disconnected`. +11. `slot`: A hash slot number or range. Starting from argument number 9, but there may be up to 16384 entries in total (limit never reached). This is the list of hash slots served by this node. If the entry is just a number, it is parsed as such. If it is a range, it is in the form `start-end`, and means that the node is responsible for all the hash slots from `start` to `end` including the start and end values. Flags are: From 91efa419320420910c25d43573bfc94441bd22cb Mon Sep 17 00:00:00 2001 From: Madelyn Olson <34459052+madolson@users.noreply.github.com> Date: Sat, 15 Jul 2023 20:11:15 -0700 Subject: [PATCH 239/377] Update commands/cluster-nodes.md Remove unnecessary wording --- commands/cluster-nodes.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/commands/cluster-nodes.md b/commands/cluster-nodes.md index b175ec64e7..e5bfb7bc95 100644 --- a/commands/cluster-nodes.md +++ b/commands/cluster-nodes.md @@ -17,9 +17,7 @@ It is also used by `redis-cli` in order to manage a cluster. ## Serialization format The output of the command is just a space-separated CSV string, where -each line represents a node in the cluster. The auxiliary fields -(including shard ID, human node name and extra port number) stored in -nodes.conf file are currently hidden from client commands. The following +each line represents a node in the cluster. The following is an example of output on Redis 7.2.0. ``` From b631446e49b1ff626b54204ac956a270ed2e0eff Mon Sep 17 00:00:00 2001 From: Pavel Skuratovich Date: Sun, 16 Jul 2023 16:52:53 +0300 Subject: [PATCH 240/377] Update eval-intro.md (#2484) --- docs/interact/programmability/eval-intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/interact/programmability/eval-intro.md b/docs/interact/programmability/eval-intro.md index 0a1b70982d..04776e3dbf 100644 --- a/docs/interact/programmability/eval-intro.md +++ b/docs/interact/programmability/eval-intro.md @@ -22,7 +22,7 @@ These include: * Providing locality by executing logic where data lives. Data locality reduces overall latency and saves networking resources. * Blocking semantics that ensure the script's atomic execution. -* Enabling the composition of simple capabilities that are either missing from Redis or are too niche to a part of it. +* Enabling the composition of simple capabilities that are either missing from Redis or are too niche to be a part of it. Lua lets you run part of your application logic inside Redis. Such scripts can perform conditional updates across multiple keys, possibly combining several different data types atomically. From 6216f32122b4579f5b7f3bfa44e4b8b8fb525d01 Mon Sep 17 00:00:00 2001 From: Seonghyeon Cho Date: Mon, 17 Jul 2023 21:01:58 +0900 Subject: [PATCH 241/377] Fix typo (`@readonly` -> `@read`) (#2486) --- docs/management/security/acl.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/management/security/acl.md b/docs/management/security/acl.md index 508e781887..6b1baeed1f 100644 --- a/docs/management/security/acl.md +++ b/docs/management/security/acl.md @@ -440,7 +440,7 @@ Permissions are defined as individual characters that map to the following key p Permissions can be composed together by specifying multiple characters. Specifying the permission as 'RW' is considered full access and is analogous to just passing in `~`. -For a concrete example, consider a user with ACL rules `+@all ~app1:* (+@readonly ~app2:*)`. +For a concrete example, consider a user with ACL rules `+@all ~app1:* (+@read ~app2:*)`. This user has full access on `app1:*` and readonly access on `app2:*`. However, some commands support reading data from one key, doing some transformation, and storing it into another key. One such command is the `COPY` command, which copies the data from the source key into the destination key. From 982b4f2007ad854a77b3bed9fac877d7b14743e0 Mon Sep 17 00:00:00 2001 From: Nikita Koksharov Date: Tue, 18 Jul 2023 18:37:29 +0300 Subject: [PATCH 242/377] Update redisson.json (#2487) recommendation deletion reverted --- clients/java/github.com/mrniko/redisson.json | 1 + 1 file changed, 1 insertion(+) diff --git a/clients/java/github.com/mrniko/redisson.json b/clients/java/github.com/mrniko/redisson.json index b2c4ed4d13..861873ffa2 100644 --- a/clients/java/github.com/mrniko/redisson.json +++ b/clients/java/github.com/mrniko/redisson.json @@ -1,6 +1,7 @@ { "name": "Redisson", "description": "distributed and scalable Java data structures on top of Redis server", + "recommended": true, "twitter": [ "mrniko" ] From af1734cafec11cd9bb67afc9f48fa876a66f7465 Mon Sep 17 00:00:00 2001 From: Savannah Date: Tue, 18 Jul 2023 12:48:22 -0400 Subject: [PATCH 243/377] Update lists.md update lists data type page to include short codes for tabbed examples. updated some text to reflect changes. --- docs/data-types/lists.md | 240 ++++++++++++++++++++++----------------- 1 file changed, 135 insertions(+), 105 deletions(-) diff --git a/docs/data-types/lists.md b/docs/data-types/lists.md index a73f676d7a..587547703a 100644 --- a/docs/data-types/lists.md +++ b/docs/data-types/lists.md @@ -35,60 +35,60 @@ See the [complete series of list commands](https://redis.io/commands/?group=list ## Examples * Treat a list like a queue (first in, first out): -``` -> LPUSH work:queue:ids 101 +{{< clients-example list_tutorial queue >}} +> LPUSH bikes:repairs bike:1 (integer) 1 -> LPUSH work:queue:ids 237 +> LPUSH bikes:repairs bike:2 (integer) 2 -> RPOP work:queue:ids -"101" -> RPOP work:queue:ids -"237" -``` +> RPOP bikes:repairs +"bike:1" +> RPOP bikes:repairs +"bike:2" +{{< /clients-example >}} * Treat a list like a stack (first in, last out): -``` -> LPUSH work:queue:ids 101 +{{< clients-example list_tutorial stack >}} +> LPUSH bikes:repairs bike:1 (integer) 1 -> LPUSH work:queue:ids 237 +> LPUSH bikes:repairs bike:2 (integer) 2 -> LPOP work:queue:ids -"237" -> LPOP work:queue:ids -"101" -``` +> LPOP bikes:repairs +"bike:2" +> LPOP bikes:repairs +"bike:1" +{{< /clients-example >}} * Check the length of a list: -``` -> LLEN work:queue:ids +{{< clients-example list_tutorial llen >}} +> LLEN bikes:repairs (integer) 0 -``` +{{< /clients-example >}} * Atomically pop an element from one list and push to another: -``` -> LPUSH board:todo:ids 101 +{{< clients-example list_tutorial lmove_lrange >}} +> LPUSH bikes:repairs bike:1 (integer) 1 -> LPUSH board:todo:ids 273 +> LPUSH bikes:repairs bike:2 (integer) 2 -> LMOVE board:todo:ids board:in-progress:ids LEFT LEFT -"273" -> LRANGE board:todo:ids 0 -1 -1) "101" -> LRANGE board:in-progress:ids 0 -1 -1) "273" -``` - -* To create a capped list that never grows beyond 100 elements, you can call `LTRIM` after each call to `LPUSH`: -``` -> LPUSH notifications:user:1 "You've got mail!" -(integer) 1 -> LTRIM notifications:user:1 0 99 -OK -> LPUSH notifications:user:1 "Your package will be delivered at 12:01 today." -(integer) 2 -> LTRIM notifications:user:1 0 99 -OK -``` +> LMOVE bikes:repairs bikes:finished LEFT LEFT +"bike:2" +> LRANGE bikes:repairs 0 -1 +1) "bike:1" +> LRANGE bikes:finished 0 -1 +1) "bike:2" +{{< /clients-example >}} + +* To limit the length of a list you can call `LTRIM`: +{{< clients-example list_tutorial ltrim >}} + > lpush bikes:repairs:priority bike:1 bike:2 bike:3 bike:4 bike:5 + (integer) 5 + > ltrim bikes:repairs 0 2 + OK + > lrange bikes:repairs 0 -1 + 1) "bike:5" + 2) "bike:4" + 3) "bike:3" +{{< /clients-example >}} ### What are Lists? To explain the List data type it's better to start with a little bit of theory, @@ -130,16 +130,18 @@ left (at the head), while the `RPUSH` command adds a new element into a list, on the right (at the tail). Finally the `LRANGE` command extracts ranges of elements from lists: - > rpush mylist A +{{< clients-example list_tutorial lpush_rpush >}} + > rpush bikes:repairs bike:1 (integer) 1 - > rpush mylist B + > rpush bikes:repairs bike:2 (integer) 2 - > lpush mylist first + > lpush bikes:repairs bike:important_bike (integer) 3 - > lrange mylist 0 -1 - 1) "first" - 2) "A" - 3) "B" + > lrange bikes:repairs 0 -1 + 1) "bike:important_bike" + 2) "bike:1" + 3) "bike:2" +{{< /clients-example >}} Note that `LRANGE` takes two indexes, the first and the last element of the range to return. Both the indexes can be negative, telling Redis @@ -152,40 +154,38 @@ the final `LPUSH` appended the element on the left. Both commands are *variadic commands*, meaning that you are free to push multiple elements into a list in a single call: - > rpush mylist 1 2 3 4 5 "foo bar" - (integer) 9 +{{< clients-example list_tutorial variadic >}} + > rpush bikes:repairs bike:1 bike:2 bike:3 + (integer) 3 + > lpush bikes:repairs bike:important_bike bike:very_important_bike > lrange mylist 0 -1 - 1) "first" - 2) "A" - 3) "B" - 4) "1" - 5) "2" - 6) "3" - 7) "4" - 8) "5" - 9) "foo bar" + 1) "bike:very_important_bike" + 2) "bike:important_bike" + 3) "bike:1" + 4) "bike:2" + 5) "bike:3" +{{< /clients-example >}} An important operation defined on Redis lists is the ability to *pop elements*. Popping elements is the operation of both retrieving the element from the list, and eliminating it from the list, at the same time. You can pop elements from left and right, similarly to how you can push elements in both sides -of the list: - - > rpush mylist a b c - (integer) 3 - > rpop mylist - "c" - > rpop mylist - "b" - > rpop mylist - "a" - -We added three elements and popped three elements, so at the end of this +of the list. We'll add three elements and popp three elements, so at the end of this sequence of commands the list is empty and there are no more elements to -pop. If we try to pop yet another element, this is the result we get: +pop: - > rpop mylist +{{< clients-example list_tutorial lpop_rpop >}} + > rpush bikes:repairs bike:1 bike:2 bike:3 + (integer) 3 + > rpop bikes:repairs + "bike:3" + > lpop bikes:repairs + "bike:1" + > rpop bikes:repairs + "bike:2" + > rpop bikes:repairs (nil) +{{< /clients-example >}} Redis returned a NULL value to signal that there are no elements in the list. @@ -223,26 +223,38 @@ The `LTRIM` command is similar to `LRANGE`, but **instead of displaying the specified range of elements** it sets this range as the new list value. All the elements outside the given range are removed. -An example will make it more clear: +For example, if you're adding bikes on the end of a list of repairs, but only +want to worry about the 3 that have been on the list the longest: - > rpush mylist 1 2 3 4 5 +{{< clients-example list_tutorial ltrim >}} + > rpush bikes:repairs bike:1 bike:2 bike:3 bike:4 bike:5 (integer) 5 - > ltrim mylist 0 2 + > ltrim bikes:repairs 0 2 OK - > lrange mylist 0 -1 - 1) "1" - 2) "2" - 3) "3" + > lrange bikes:repairs 0 -1 + 1) "bike:1" + 2) "bike:2" + 3) "bike:3" +{{< /clients-example >}} The above `LTRIM` command tells Redis to keep just list elements from index 0 to 2, everything else will be discarded. This allows for a very simple but useful pattern: doing a List push operation + a List trim operation together -in order to add a new element and discard elements exceeding a limit: +in order to add a new element and discard elements exceeding a limit. Using +`LTRIM` with negative indices can then be used to keep only the 3 most recently added: - LPUSH mylist - LTRIM mylist 0 999 +{{< clients-example list_tutorial ltrim_end_of_list >}} + > rpush bikes:repairs bike:1 bike:2 bike:3 bike:4 bike:5 + (integer) 5 + > ltrim bikes:repairs -3 -1 + OK + > lrange bikes:repairs 0 -1 + 1) "bike:3" + 2) "bike:4" + 3) "bike:5" +{{< /clients-example >}} -The above combination adds a new element and keeps only the 1000 +The above combination adds new elements and keeps only the 3 newest elements into the list. With `LRANGE` you can access the top items without any need to remember very old data. @@ -279,9 +291,19 @@ timeout is reached. This is an example of a `BRPOP` call we could use in the worker: - > brpop tasks 5 - 1) "tasks" - 2) "do_something" +{{< clients-example list_tutorial brpop >}} + > rpush bikes:repairs bike:1 bike:2 + (integer) 5 + > brpop bikes:repairs 1 + 1) "bikes:repairs" + 2) "bike:2" + > brpop bikes:repairs 1 + 1) "bikes:repairs" + 2) "bike:1" + > brpop bikes:repairs 1 + (nil) + (2.01s) +{{< /clients-example >}} It means: "wait for elements in the list `tasks`, but return if after 5 seconds no element is available". @@ -322,45 +344,53 @@ Basically we can summarize the behavior with three rules: Examples of rule 1: - > del mylist +{{< clients-example list_tutorial rule_1 >}} + > del new_bikes (integer) 1 - > lpush mylist 1 2 3 + > lpush new_bikes bike:1 bike:2 bike:3 (integer) 3 +{{< /clients-example >}} However we can't perform operations against the wrong type if the key exists: - > set foo bar +{{< clients-example list_tutorial rule_1.1 >}} + > set new_bikes bike:1 OK - > lpush foo 1 2 3 - (error) WRONGTYPE Operation against a key holding the wrong kind of value - > type foo + > type new_bikes string + > lpush new_bikes bike:2 bike:3 + (error) WRONGTYPE Operation against a key holding the wrong kind of value +{{< /clients-example >}} Example of rule 2: - > lpush mylist 1 2 3 +{{< clients-example list_tutorial rule_2 >}} + > rpush bikes:repairs bike:1 bike:2 bike:3 (integer) 3 - > exists mylist + > exists bikes:repairs (integer) 1 - > lpop mylist - "3" - > lpop mylist - "2" - > lpop mylist - "1" - > exists mylist + > lpop bikes:repairs + "bike:3" + > lpop bikes:repairs + "bike:2" + > lpop bikes:repairs + "bike:1" + > exists bikes:repairs (integer) 0 +{{< /clients-example >}} The key no longer exists after all the elements are popped. Example of rule 3: - > del mylist +{{< clients-example list_tutorial rule_3 >}} + > del bikes:repairs (integer) 0 - > llen mylist + > llen bikes:repairs (integer) 0 - > lpop mylist + > lpop bikes:repairs (nil) +{{< /clients-example >}} ## Limits From 70ec5c2211f4c384675007335264a83ae3096de6 Mon Sep 17 00:00:00 2001 From: Savannah Date: Tue, 18 Jul 2023 12:57:11 -0400 Subject: [PATCH 244/377] Update wordlist update wordlist to include commands for tabbed examples for lists and strings --- wordlist | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/wordlist b/wordlist index 601a8a6947..64567b3c7f 100644 --- a/wordlist +++ b/wordlist @@ -70,6 +70,7 @@ BigNumber BitOp Bitfields Bitwise +brpop C1 C2 C3 @@ -185,6 +186,8 @@ HyperLogLog. HyperLogLogs Hyperloglogs hyperloglogs +incr +incrby IOPs IPC IPs @@ -218,6 +221,7 @@ LF LFU LHF LLOOGG +lmove_lrange LRU LRU's LRU. @@ -231,6 +235,14 @@ licensor's LibLZF Linode Liveness +llen +lmove_lrange +lpop +lpop_rpop +lpush_rpush +lrange +ltrim +ltrim_end_of_list Lua Lua's lua-debugging @@ -244,8 +256,10 @@ Matteo Maxmemory Memcache MessagePack +mget Movablekeys Mrkris +mset NAS NATted NFS @@ -360,6 +374,7 @@ Retwis Retwis-J Retwis-RB Roshi +rpush Rx/Tx Rslock S1 @@ -387,6 +402,7 @@ Sanfilippo Sanfilippo's ScarletLock Selectable +setnx_xx Sharded Shuttleworth Slicehost @@ -1022,6 +1038,7 @@ wherefrom whitespace whitespaces whos-using-redis +WRONGTYPE xff xzvf zeroed-ACLs From e5cf15572abe67cb0db5882e012a56889f7d1f92 Mon Sep 17 00:00:00 2001 From: Savannah Date: Tue, 18 Jul 2023 13:39:50 -0400 Subject: [PATCH 245/377] fix popp -> pop --- docs/data-types/lists.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/lists.md b/docs/data-types/lists.md index 587547703a..5918d63c67 100644 --- a/docs/data-types/lists.md +++ b/docs/data-types/lists.md @@ -170,7 +170,7 @@ An important operation defined on Redis lists is the ability to *pop elements*. Popping elements is the operation of both retrieving the element from the list, and eliminating it from the list, at the same time. You can pop elements from left and right, similarly to how you can push elements in both sides -of the list. We'll add three elements and popp three elements, so at the end of this +of the list. We'll add three elements and pop three elements, so at the end of this sequence of commands the list is empty and there are no more elements to pop: From a605fed208d5f53d43c4b4445ada587af1ac2de1 Mon Sep 17 00:00:00 2001 From: Savannah Date: Tue, 18 Jul 2023 17:09:10 -0400 Subject: [PATCH 246/377] update dt_list capitalize CLI commands - remove whitespace - fix example being used twice not rendering --- docs/data-types/lists.md | 186 +++++++++++++++++++-------------------- 1 file changed, 93 insertions(+), 93 deletions(-) diff --git a/docs/data-types/lists.md b/docs/data-types/lists.md index 5918d63c67..3597d81f74 100644 --- a/docs/data-types/lists.md +++ b/docs/data-types/lists.md @@ -79,15 +79,15 @@ See the [complete series of list commands](https://redis.io/commands/?group=list {{< /clients-example >}} * To limit the length of a list you can call `LTRIM`: -{{< clients-example list_tutorial ltrim >}} - > lpush bikes:repairs:priority bike:1 bike:2 bike:3 bike:4 bike:5 - (integer) 5 - > ltrim bikes:repairs 0 2 - OK - > lrange bikes:repairs 0 -1 - 1) "bike:5" - 2) "bike:4" - 3) "bike:3" +{{< clients-example list_tutorial ltrim.1 >}} +> RPUSH bikes:repairs bike:1 bike:2 bike:3 bike:4 bike:5 +(integer) 5 +> LTRIM bikes:repairs 0 2 +OK +> LRANGE bikes:repairs 0 -1 +1) "bike:1" +2) "bike:2" +3) "bike:3" {{< /clients-example >}} ### What are Lists? @@ -131,16 +131,16 @@ element into a list, on the right (at the tail). Finally the `LRANGE` command extracts ranges of elements from lists: {{< clients-example list_tutorial lpush_rpush >}} - > rpush bikes:repairs bike:1 - (integer) 1 - > rpush bikes:repairs bike:2 - (integer) 2 - > lpush bikes:repairs bike:important_bike - (integer) 3 - > lrange bikes:repairs 0 -1 - 1) "bike:important_bike" - 2) "bike:1" - 3) "bike:2" +> RPUSH bikes:repairs bike:1 +(integer) 1 +> RPUSH bikes:repairs bike:2 +(integer) 2 +> LPUSH bikes:repairs bike:important_bike +(integer) 3 +> LRANGE bikes:repairs 0 -1 +1) "bike:important_bike" +2) "bike:1" +3) "bike:2" {{< /clients-example >}} Note that `LRANGE` takes two indexes, the first and the last @@ -155,15 +155,15 @@ Both commands are *variadic commands*, meaning that you are free to push multiple elements into a list in a single call: {{< clients-example list_tutorial variadic >}} - > rpush bikes:repairs bike:1 bike:2 bike:3 - (integer) 3 - > lpush bikes:repairs bike:important_bike bike:very_important_bike - > lrange mylist 0 -1 - 1) "bike:very_important_bike" - 2) "bike:important_bike" - 3) "bike:1" - 4) "bike:2" - 5) "bike:3" +> RPUSH bikes:repairs bike:1 bike:2 bike:3 +(integer) 3 +> LPUSH bikes:repairs bike:important_bike bike:very_important_bike +> LRANGE mylist 0 -1 +1) "bike:very_important_bike" +2) "bike:important_bike" +3) "bike:1" +4) "bike:2" +5) "bike:3" {{< /clients-example >}} An important operation defined on Redis lists is the ability to *pop elements*. @@ -175,16 +175,16 @@ sequence of commands the list is empty and there are no more elements to pop: {{< clients-example list_tutorial lpop_rpop >}} - > rpush bikes:repairs bike:1 bike:2 bike:3 - (integer) 3 - > rpop bikes:repairs - "bike:3" - > lpop bikes:repairs - "bike:1" - > rpop bikes:repairs - "bike:2" - > rpop bikes:repairs - (nil) +> RPUSH bikes:repairs bike:1 bike:2 bike:3 +(integer) 3 +> RPOP bikes:repairs +"bike:3" +> LPOP bikes:repairs +"bike:1" +> RPOP bikes:repairs +"bike:2" +> RPOP bikes:repairs +(nil) {{< /clients-example >}} Redis returned a NULL value to signal that there are no elements in the @@ -227,14 +227,14 @@ For example, if you're adding bikes on the end of a list of repairs, but only want to worry about the 3 that have been on the list the longest: {{< clients-example list_tutorial ltrim >}} - > rpush bikes:repairs bike:1 bike:2 bike:3 bike:4 bike:5 - (integer) 5 - > ltrim bikes:repairs 0 2 - OK - > lrange bikes:repairs 0 -1 - 1) "bike:1" - 2) "bike:2" - 3) "bike:3" +> RPUSH bikes:repairs bike:1 bike:2 bike:3 bike:4 bike:5 +(integer) 5 +> LTRIM bikes:repairs 0 2 +OK +> LRANGE bikes:repairs 0 -1 +1) "bike:1" +2) "bike:2" +3) "bike:3" {{< /clients-example >}} The above `LTRIM` command tells Redis to keep just list elements from index @@ -244,14 +244,14 @@ in order to add a new element and discard elements exceeding a limit. Using `LTRIM` with negative indices can then be used to keep only the 3 most recently added: {{< clients-example list_tutorial ltrim_end_of_list >}} - > rpush bikes:repairs bike:1 bike:2 bike:3 bike:4 bike:5 - (integer) 5 - > ltrim bikes:repairs -3 -1 - OK - > lrange bikes:repairs 0 -1 - 1) "bike:3" - 2) "bike:4" - 3) "bike:5" +> RPUSH bikes:repairs bike:1 bike:2 bike:3 bike:4 bike:5 +(integer) 5 +> LTRIM bikes:repairs -3 -1 +OK +> LRANGE bikes:repairs 0 -1 +1) "bike:3" +2) "bike:4" +3) "bike:5" {{< /clients-example >}} The above combination adds new elements and keeps only the 3 @@ -292,17 +292,17 @@ timeout is reached. This is an example of a `BRPOP` call we could use in the worker: {{< clients-example list_tutorial brpop >}} - > rpush bikes:repairs bike:1 bike:2 - (integer) 5 - > brpop bikes:repairs 1 - 1) "bikes:repairs" - 2) "bike:2" - > brpop bikes:repairs 1 - 1) "bikes:repairs" - 2) "bike:1" - > brpop bikes:repairs 1 - (nil) - (2.01s) +> RPUSH bikes:repairs bike:1 bike:2 +(integer) 5 +> BRPOP bikes:repairs 1 +1) "bikes:repairs" +2) "bike:2" +> BRPOP bikes:repairs 1 +1) "bikes:repairs" +2) "bike:1" +> BRPOP bikes:repairs 1 +(nil) +(2.01s) {{< /clients-example >}} It means: "wait for elements in the list `tasks`, but return if after 5 seconds @@ -345,38 +345,38 @@ Basically we can summarize the behavior with three rules: Examples of rule 1: {{< clients-example list_tutorial rule_1 >}} - > del new_bikes - (integer) 1 - > lpush new_bikes bike:1 bike:2 bike:3 - (integer) 3 +> DEL new_bikes +(integer) 1 +> LPUSH new_bikes bike:1 bike:2 bike:3 +(integer) 3 {{< /clients-example >}} However we can't perform operations against the wrong type if the key exists: {{< clients-example list_tutorial rule_1.1 >}} - > set new_bikes bike:1 - OK - > type new_bikes - string - > lpush new_bikes bike:2 bike:3 - (error) WRONGTYPE Operation against a key holding the wrong kind of value +> SET new_bikes bike:1 +OK +> TYPE new_bikes +string +> LPUSH new_bikes bike:2 bike:3 +(error) WRONGTYPE Operation against a key holding the wrong kind of value {{< /clients-example >}} Example of rule 2: {{< clients-example list_tutorial rule_2 >}} - > rpush bikes:repairs bike:1 bike:2 bike:3 - (integer) 3 - > exists bikes:repairs - (integer) 1 - > lpop bikes:repairs - "bike:3" - > lpop bikes:repairs - "bike:2" - > lpop bikes:repairs - "bike:1" - > exists bikes:repairs - (integer) 0 +> RPUSH bikes:repairs bike:1 bike:2 bike:3 +(integer) 3 +> EXISTS bikes:repairs +(integer) 1 +> LPOP bikes:repairs +"bike:3" +> LPOP bikes:repairs +"bike:2" +> LPOP bikes:repairs +"bike:1" +> EXISTS bikes:repairs +(integer) 0 {{< /clients-example >}} The key no longer exists after all the elements are popped. @@ -384,12 +384,12 @@ The key no longer exists after all the elements are popped. Example of rule 3: {{< clients-example list_tutorial rule_3 >}} - > del bikes:repairs - (integer) 0 - > llen bikes:repairs - (integer) 0 - > lpop bikes:repairs - (nil) +> DEL bikes:repairs +(integer) 0 +> LLEN bikes:repairs +(integer) 0 +> LPOP bikes:repairs +(nil) {{< /clients-example >}} From b7235ba472cfcbe9d5c2f5dea0932dfe1aebb376 Mon Sep 17 00:00:00 2001 From: Savannah Date: Wed, 19 Jul 2023 15:59:35 -0400 Subject: [PATCH 247/377] Update geospatial.md update geo tutorial to include hugo shortcodes for tabbed examples --- docs/data-types/geospatial.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/data-types/geospatial.md b/docs/data-types/geospatial.md index 6e8d6cd9dd..0869a4b989 100644 --- a/docs/data-types/geospatial.md +++ b/docs/data-types/geospatial.md @@ -19,28 +19,28 @@ See the [complete list of geospatial index commands](https://redis.io/commands/? ## Examples -Suppose you're building a mobile app that lets you find all of the electric car charging stations closest to your current location. +Suppose you're building a mobile app that lets you find all of the rentable bike stations closest to your current location. Add several locations to a geospatial index: -``` -> GEOADD locations:ca -122.27652 37.805186 station:1 +{{< clients-example geo_tutorial geoadd >}} +> GEOADD bikes:rentable -122.27652 37.805186 station:1 (integer) 1 -> GEOADD locations:ca -122.2674626 37.8062344 station:2 +> GEOADD bikes:rentable -122.2674626 37.8062344 station:2 (integer) 1 -> GEOADD locations:ca -122.2469854 37.8104049 station:3 +> GEOADD bikes:rentable -122.2469854 37.8104049 station:3 (integer) 1 -``` +{{< /clients-example >}} Find all locations within a 5 kilometer radius of a given location, and return the distance to each location: -``` -> GEOSEARCH locations:ca FROMLONLAT -122.2612767 37.7936847 BYRADIUS 5 km WITHDIST +{{< clients-example geo_tutorial geosearch >}} +> GEOSEARCH bikes:rentable FROMLONLAT -122.2612767 37.7936847 BYRADIUS 5 km WITHDIST 1) 1) "station:1" 2) "1.8523" 2) 1) "station:2" 2) "1.4979" 3) 1) "station:3" 2) "2.2441" -``` +{{< /clients-example >}} ## Learn more From 89551916ead61bb79cac1c6b0aaef2c836a67e2f Mon Sep 17 00:00:00 2001 From: "David W. Dougherty" Date: Tue, 25 Jul 2023 07:03:26 -0700 Subject: [PATCH 248/377] DOC-2550: add redirect to correct 404 error --- docs/data-types/_index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/data-types/_index.md b/docs/data-types/_index.md index 2a12c89089..9ac395f381 100644 --- a/docs/data-types/_index.md +++ b/docs/data-types/_index.md @@ -6,6 +6,7 @@ weight: 35 aliases: - /docs/manual/data-types - /topics/data-types + - /docs/data-types/tutorial --- Redis is a data structure server. @@ -108,4 +109,4 @@ To extend the features provided by the included data types, use one of these opt 1. Write your own Redis module using the [modules API](/docs/reference/modules/) or check out the [community-supported modules](/docs/modules/). 1. Use [JSON](/docs/stack/json/), [querying](/docs/stack/search/), [time series](/docs/stack/timeseries/), and other capabilities provided by [Redis Stack](/docs/stack/). -
\ No newline at end of file +
From bca8041ba40fdc5858d5040e7c734653ed31a9bd Mon Sep 17 00:00:00 2001 From: Savannah Date: Tue, 25 Jul 2023 14:37:22 -0400 Subject: [PATCH 249/377] indices -> indexes, remove extra words --- docs/data-types/lists.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/data-types/lists.md b/docs/data-types/lists.md index 3597d81f74..a91cd40c40 100644 --- a/docs/data-types/lists.md +++ b/docs/data-types/lists.md @@ -239,9 +239,9 @@ OK The above `LTRIM` command tells Redis to keep just list elements from index 0 to 2, everything else will be discarded. This allows for a very simple but -useful pattern: doing a List push operation + a List trim operation together -in order to add a new element and discard elements exceeding a limit. Using -`LTRIM` with negative indices can then be used to keep only the 3 most recently added: +useful pattern: doing a List push operation + a List trim operation together +to add a new element and discard elements exceeding a limit. Using +`LTRIM` with negative indexes can then be used to keep only the 3 most recently added: {{< clients-example list_tutorial ltrim_end_of_list >}} > RPUSH bikes:repairs bike:1 bike:2 bike:3 bike:4 bike:5 From 9aa4024273ec0732e5c1940a53625f2801a28d2e Mon Sep 17 00:00:00 2001 From: Savannah Date: Tue, 25 Jul 2023 14:41:44 -0400 Subject: [PATCH 250/377] Update wordlist for sets datatype --- wordlist | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/wordlist b/wordlist index 64567b3c7f..dcba9b22bd 100644 --- a/wordlist +++ b/wordlist @@ -260,6 +260,7 @@ mget Movablekeys Mrkris mset +multisets NAS NATted NFS @@ -397,16 +398,23 @@ SSD SSL SVGs SYNC_RDB_START +sadd +sadd_smembers Sandboxed Sanfilippo Sanfilippo's +scard ScarletLock +sdiff Selectable setnx_xx Sharded Shuttleworth +sinter +sismember Slicehost SmartOS +smismember Snapchat Snapcraft Snapshotting @@ -414,6 +422,7 @@ Solaris-derived SomeOtherValue Sonatype SoundCloud +srem StackOverflow StringDMA Subcommands From 19f8a12ff71057332ad0e0a85206f9c0f1c4ed8e Mon Sep 17 00:00:00 2001 From: Savannah Date: Tue, 25 Jul 2023 14:43:51 -0400 Subject: [PATCH 251/377] add nx --- wordlist | 1 + 1 file changed, 1 insertion(+) diff --git a/wordlist b/wordlist index dcba9b22bd..504bc19b16 100644 --- a/wordlist +++ b/wordlist @@ -805,6 +805,7 @@ num-items numactl numkeys nullarray +nx observability odown ok From 658504d3d02003895d2798110db6c3cc1bca9753 Mon Sep 17 00:00:00 2001 From: Savannah Date: Wed, 26 Jul 2023 14:29:09 -0400 Subject: [PATCH 252/377] sets update for tabbed examples with bikes updated the sets data type page to include hugo short codes, updated the story to be about bikes, made the examples as relevant as possible --- docs/data-types/sets.md | 245 +++++++++++++++++----------------------- 1 file changed, 106 insertions(+), 139 deletions(-) diff --git a/docs/data-types/sets.md b/docs/data-types/sets.md index 1ad2dcbdfd..c95a1de7b3 100644 --- a/docs/data-types/sets.md +++ b/docs/data-types/sets.md @@ -25,38 +25,38 @@ See the [complete list of set commands](https://redis.io/commands/?group=set). ## Examples -* Store the set of favorited book IDs for users 123 and 456: -``` -> SADD user:123:favorites 347 +* Store the sets of bikes racing in France and the USA. Note that +if you add a member that already exists, it will be ignored. +{{< clients-example sets_tutorial sadd >}} +> SADD bikes:racing:france bike:1 (integer) 1 -> SADD user:123:favorites 561 -(integer) 1 -> SADD user:123:favorites 742 -(integer) 1 -> SADD user:456:favorites 561 -(integer) 1 -``` - -* Check whether user 123 likes books 742 and 299 -``` -> SISMEMBER user:123:favorites 742 +> SADD bikes:racing:france bike:1 +(integer) 0 +> SADD bikes:racing:france bike:2 bike:3 +(integer) 2 +> SADD bikes:racing:usa bike:1 bike:4 +(integer) 2 +{{< /clients-example >}} + +* Check whether bike:1 or bike:2 are racing in the US. +{{< clients-example sets_tutorial sismember >}} +> SISMEMBER bikes:racing:usa bike:1 (integer) 1 -> SISMEMBER user:123:favorites 299 +> SISMEMBER bikes:racing:usa bike:2 (integer) 0 -``` +{{< /clients-example >}} -* Do user 123 and 456 have any favorite books in common? -``` -> SINTER user:123:favorites user:456:favorites -1) "561" -``` +* Which bikes are competing in both races? +{{< clients-example sets_tutorial sinter >}} +> SINTER bikes:racing:france bikes:racing:usa +1) "bike:1" +{{< /clients-example >}} -* How many books has user 123 favorited? -``` -> SCARD user:123:favorites +* How many bikes are racing in France? +{{< clients-example sets_tutorial scard >}} +> SCARD bikes:racing:france (integer) 3 -``` - +{{< /clients-example >}} ## Tutorial The `SADD` command adds new elements to a set. It's also possible @@ -64,130 +64,97 @@ to do a number of other operations against sets like testing if a given element already exists, performing the intersection, union or difference between multiple sets, and so forth. - > sadd myset 1 2 3 - (integer) 3 - > smembers myset - 1. 3 - 2. 1 - 3. 2 +{{< clients-example sets_tutorial sadd_smembers >}} +> SADD bikes:racing:france bike:1 bike:2 bike:3 +(integer) 3 +> SMEMBERS bikes:racing:france +1) bike:3 +2) bike:1 +3) bike:2 +{{< /clients-example >}} Here I've added three elements to my set and told Redis to return all the -elements. As you can see they are not sorted -- Redis is free to return the +elements. There is no order guarantee with a set -- Redis is free to return the elements in any order at every call, since there is no contract with the user about element ordering. -Redis has commands to test for membership. For example, checking if an element exists: - - > sismember myset 3 - (integer) 1 - > sismember myset 30 - (integer) 0 - -"3" is a member of the set, while "30" is not. +Redis has commands to test for membership. This can be both a single item +or a variadic command to test membership for multiple items at once: -Sets are good for expressing relations between objects. -For instance we can easily use sets in order to implement tags. - -A simple way to model this problem is to have a set for every object we -want to tag. The set contains the IDs of the tags associated with the object. - -One illustration is tagging news articles. -If article ID 1000 is tagged with tags 1, 2, 5 and 77, a set -can associate these tag IDs with the news item: - - > sadd news:1000:tags 1 2 5 77 - (integer) 4 - -We may also want to have the inverse relation as well: the list -of all the news tagged with a given tag: - - > sadd tag:1:news 1000 - (integer) 1 - > sadd tag:2:news 1000 - (integer) 1 - > sadd tag:5:news 1000 - (integer) 1 - > sadd tag:77:news 1000 - (integer) 1 - -To get all the tags for a given object is trivial: - - > smembers news:1000:tags - 1. 5 - 2. 1 - 3. 77 - 4. 2 - -Note: in the example we assume you have another data structure, for example -a Redis hash, which maps tag IDs to tag names. +{{< clients-example sets_tutorial smismember >}} +> SISMEMBER bikes:racing:france bike:1 +(integer) 1 +> SMISMEMBER bikes:racing:france bike:2 bike:3 bike:4 +1) (integer) 1 +2) (integer) 1 +3) (integer) 0 +{{< /clients-example >}} + +We can also find the difference between two sets. For instance, we may want +to know which bikes are racing in France but not in the USA: + +{{< clients-example sets_tutorial sdiff >}} +> SADD bikes:racing:usa bike:1 bike:4 +(integer) 2 +> SDIFF bikes:racing:france bikes:racing:usa +1) "bike:3" +2) "bike:2" +{{< /clients-example >}} There are other non trivial operations that are still easy to implement using the right Redis commands. For instance we may want a list of all the -objects with the tags 1, 2, 10, and 27 together. We can do this using +bikes racing in France, the USA, and some other races. We can do this using the `SINTER` command, which performs the intersection between different -sets. We can use: +sets. In addition to intersection you can also perform +unions, difference, and more. For example +if we add a third race we can see some of these commands in action: - > sinter tag:1:news tag:2:news tag:10:news tag:27:news - ... results here ... - -In addition to intersection you can also perform -unions, difference, extract a random element, and so forth. - -The command to extract an element is called `SPOP`, and is handy to model -certain problems. For example in order to implement a web-based poker game, -you may want to represent your deck with a set. Imagine we use a one-char -prefix for (C)lubs, (D)iamonds, (H)earts, (S)pades: - - > sadd deck C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 CJ CQ CK - D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 DJ DQ DK H1 H2 H3 - H4 H5 H6 H7 H8 H9 H10 HJ HQ HK S1 S2 S3 S4 S5 S6 - S7 S8 S9 S10 SJ SQ SK - (integer) 52 - -Now we want to provide each player with 5 cards. The `SPOP` command -removes a random element, returning it to the client, so it is the -perfect operation in this case. - -However if we call it against our deck directly, in the next play of the -game we'll need to populate the deck of cards again, which may not be -ideal. So to start, we can make a copy of the set stored in the `deck` key -into the `game:1:deck` key. - -This is accomplished using `SUNIONSTORE`, which normally performs the -union between multiple sets, and stores the result into another set. -However, since the union of a single set is itself, I can copy my deck -with: - - > sunionstore game:1:deck deck - (integer) 52 - -Now I'm ready to provide the first player with five cards: - - > spop game:1:deck - "C6" - > spop game:1:deck - "CQ" - > spop game:1:deck - "D1" - > spop game:1:deck - "CJ" - > spop game:1:deck - "SJ" - -One pair of jacks, not great... - -This is a good time to introduce the set command that provides the number -of elements inside a set. This is often called the *cardinality of a set* -in the context of set theory, so the Redis command is called `SCARD`. - - > scard game:1:deck - (integer) 47 - -The math works: 52 - 5 = 47. - -When you need to just get random elements without removing them from the -set, there is the `SRANDMEMBER` command suitable for the task. It also features -the ability to return both repeating and non-repeating elements. +{{< clients-example sets_tutorial multisets >}} +> SADD bikes:racing:france bike:1 bike:2 bike:3 +(integer) 3 +> SADD bikes:racing:usa bike:1 bike:4 +(integer) 2 +> SADD bikes:racing:italy bike:1 bike:2 bike:3 bike:4 +(integer) 4 +> SINTER bikes:racing:france bikes:racing:usa bikes:racing:italy +1) "bike:1" +> SUNION bikes:racing:france bikes:racing:usa bikes:racing:italy +1) "bike:2" +2) "bike:1" +3) "bike:4" +4) "bike:3" +> SDIFF bikes:racing:france bikes:racing:usa bikes:racing:italy +(empty array) +> SDIFF bikes:racing:france bikes:racing:usa +1) "bike:3" +2) "bike:2" +> SDIFF bikes:racing:usa bikes:racing:france +1) "bike:4" +{{< /clients-example >}} + +You'll note that the `SDIFF` command returns an empty array when the +difference between all sets is empty. You'll also note that the order of sets +passed to `SDIFF` matters, since the difference is not commutative. + +When you want to remove items from a set, you can use the `SREM` command to +remove one or more items from a set, or you can use the `SPOP` command to +remove a random item from a set. You can also _return_ a random item from a +set without removing it using the `SRANDMEMBER` command: + +{{< clients-example sets_tutorial srem >}} +> SADD bikes:racing:france bike:1 bike:2 bike:3 bike:4 bike:5 +(integer) 3 +> SREM bikes:racing:france bike:1 +(integer) 1 +> SPOP bikes:racing:france +"bike:3" +> SMEMBERS bikes:racing:france +1) "bike:2" +2) "bike:4" +3) "bike:5" +> SRANDMEMBER bikes:racing:france +"bike:2" +{{< /clients-example >}} ## Limits From ea8c4e836db044ef8fb2fb1928ab669368b2325d Mon Sep 17 00:00:00 2001 From: "David W. Dougherty" Date: Thu, 27 Jul 2023 11:35:20 -0700 Subject: [PATCH 253/377] DOC-2511: reorder the clients by language list --- clients/csharp/github.com/redis/NRedisStack.json | 2 +- clients/go/github.com/redis/go-redis.json | 4 ++-- clients/java/github.com/redis/jedis.json | 4 ++-- clients/nodejs/github.com/redis/node-redis.json | 4 ++-- clients/python/github.com/redis/redis-py.json | 2 +- resources/clients/index.md | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/clients/csharp/github.com/redis/NRedisStack.json b/clients/csharp/github.com/redis/NRedisStack.json index 5108698fbd..b02b4895c6 100644 --- a/clients/csharp/github.com/redis/NRedisStack.json +++ b/clients/csharp/github.com/redis/NRedisStack.json @@ -1,5 +1,5 @@ { "name": "NRedisStack", "description": "This client is developed by Redis to bring RedisStack support to CSharp.", - "recommended": true + "official": true } diff --git a/clients/go/github.com/redis/go-redis.json b/clients/go/github.com/redis/go-redis.json index ad7e3e6f1a..06de74d8c1 100644 --- a/clients/go/github.com/redis/go-redis.json +++ b/clients/go/github.com/redis/go-redis.json @@ -1,5 +1,5 @@ { "name": "go-redis", "description": "Redis client for Golang supporting Redis Sentinel and Redis Cluster out of the box.", - "recommended": true -} \ No newline at end of file + "official": true +} diff --git a/clients/java/github.com/redis/jedis.json b/clients/java/github.com/redis/jedis.json index 356a16aa42..f7324174e9 100644 --- a/clients/java/github.com/redis/jedis.json +++ b/clients/java/github.com/redis/jedis.json @@ -1,9 +1,9 @@ { "name": "Jedis", "description": "A blazingly small and sane Redis Java client", - "recommended": true, + "official": true, "twitter": [ "xetorthio", "g_korland" ] -} \ No newline at end of file +} diff --git a/clients/nodejs/github.com/redis/node-redis.json b/clients/nodejs/github.com/redis/node-redis.json index c92544ab8c..7caa592234 100644 --- a/clients/nodejs/github.com/redis/node-redis.json +++ b/clients/nodejs/github.com/redis/node-redis.json @@ -1,5 +1,5 @@ { "name": "node-redis", "description": "Recommended client for node.", - "recommended": true -} \ No newline at end of file + "official": true +} diff --git a/clients/python/github.com/redis/redis-py.json b/clients/python/github.com/redis/redis-py.json index 4ad33550f8..68dd999ec1 100644 --- a/clients/python/github.com/redis/redis-py.json +++ b/clients/python/github.com/redis/redis-py.json @@ -1,5 +1,5 @@ { "name": "redis-py", "description": "Mature and supported. The way to go for Python.", - "recommended": true + "official": true } diff --git a/resources/clients/index.md b/resources/clients/index.md index 74cd2070ed..23ed93d657 100644 --- a/resources/clients/index.md +++ b/resources/clients/index.md @@ -2,7 +2,7 @@ title: "Clients" linkTitle: "Clients" weight: 10 -description: Implementations of the Redis protocol in different programming languages. To get started see [Client quickstarts](/docs/clients/). +description: Implementations of the Redis protocol in different programming languages. To get started with an official client, click on one of the quickstart guide links below. layout: bazzar bazzar: clients aliases: From 92166ac0b573502a88d9fc3b1c31c05d8cd77a57 Mon Sep 17 00:00:00 2001 From: Savannah Date: Mon, 31 Jul 2023 09:46:32 -0400 Subject: [PATCH 254/377] Update docs/data-types/geospatial.md Co-authored-by: David Dougherty --- docs/data-types/geospatial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/geospatial.md b/docs/data-types/geospatial.md index 0869a4b989..1f87de74c3 100644 --- a/docs/data-types/geospatial.md +++ b/docs/data-types/geospatial.md @@ -19,7 +19,7 @@ See the [complete list of geospatial index commands](https://redis.io/commands/? ## Examples -Suppose you're building a mobile app that lets you find all of the rentable bike stations closest to your current location. +Suppose you're building a mobile app that lets you find all of the bike rental stations closest to your current location. Add several locations to a geospatial index: {{< clients-example geo_tutorial geoadd >}} From 75f05c0b64105548019496cf8bf7c18fba725743 Mon Sep 17 00:00:00 2001 From: Savannah Date: Tue, 1 Aug 2023 17:03:31 -0400 Subject: [PATCH 255/377] wording changes addresses feedback on some wording changes --- docs/data-types/sets.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/data-types/sets.md b/docs/data-types/sets.md index c95a1de7b3..6a71637983 100644 --- a/docs/data-types/sets.md +++ b/docs/data-types/sets.md @@ -74,12 +74,10 @@ multiple sets, and so forth. {{< /clients-example >}} Here I've added three elements to my set and told Redis to return all the -elements. There is no order guarantee with a set -- Redis is free to return the -elements in any order at every call, since there is no contract with the -user about element ordering. +elements. There is no order guarantee with a set. Redis is free to return the +elements in any order at every call. -Redis has commands to test for membership. This can be both a single item -or a variadic command to test membership for multiple items at once: +Redis has commands to test for set membership. These commands can be used on single as well as multiple items: {{< clients-example sets_tutorial smismember >}} > SISMEMBER bikes:racing:france bike:1 From c349441cd6cb5563beb09cc382e8a0f21f663761 Mon Sep 17 00:00:00 2001 From: Futao Wei <95689995+unfode@users.noreply.github.com> Date: Wed, 2 Aug 2023 08:06:43 -0400 Subject: [PATCH 256/377] Fix grammar (#2499) --- docs/data-types/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/_index.md b/docs/data-types/_index.md index 9ac395f381..0d31ff18e3 100644 --- a/docs/data-types/_index.md +++ b/docs/data-types/_index.md @@ -37,7 +37,7 @@ For more information, see: ### Sets [Redis sets](/docs/data-types/sets) are unordered collections of unique strings that act like the sets from your favorite programming language (for example, [Java HashSets](https://docs.oracle.com/javase/7/docs/api/java/util/HashSet.html), [Python sets](https://docs.python.org/3.10/library/stdtypes.html#set-types-set-frozenset), and so on). -With a Redis set, you can add, remove, and test for existence O(1) time (in other words, regardless of the number of set elements). +With a Redis set, you can add, remove, and test for existence in O(1) time (in other words, regardless of the number of set elements). For more information, see: * [Overview of Redis sets](/docs/data-types/sets/) From f15715b79f3119c35382060b205aea809805f556 Mon Sep 17 00:00:00 2001 From: Talimul Bari Shrestho <58276377+SHresTho12@users.noreply.github.com> Date: Wed, 2 Aug 2023 18:07:41 +0600 Subject: [PATCH 257/377] Update strings.md (#2503) The string value is parsed into integer and incremented by one by the `INCR` command not the `INCRBY`. `INCRBY` command increments the value with a given value not by 1 automatically. It increments the value by one if only it is explicitly told : `incrby total_crashes 1` --- docs/data-types/strings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/strings.md b/docs/data-types/strings.md index a38d565a8c..55909e3185 100644 --- a/docs/data-types/strings.md +++ b/docs/data-types/strings.md @@ -78,7 +78,7 @@ you can perform with them. For instance, one is atomic increment: (integer) 11 {{< /clients-example >}} -The `INCRBY` command parses the string value as an integer, +The `INCR` command parses the string value as an integer, increments it by one, and finally sets the obtained value as the new value. There are other similar commands like `INCRBY`, `DECR` and `DECRBY`. Internally it's From 712943bc70696011d47b0f978fcaae5463ae292a Mon Sep 17 00:00:00 2001 From: qii404 Date: Wed, 2 Aug 2023 05:14:59 -0700 Subject: [PATCH 258/377] Add ARDM to the tools page (#2500) --- .../gui/github.com/qishibo/AnotherRedisDesktopManager.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tools/gui/github.com/qishibo/AnotherRedisDesktopManager.json diff --git a/tools/gui/github.com/qishibo/AnotherRedisDesktopManager.json b/tools/gui/github.com/qishibo/AnotherRedisDesktopManager.json new file mode 100644 index 0000000000..28b7514e10 --- /dev/null +++ b/tools/gui/github.com/qishibo/AnotherRedisDesktopManager.json @@ -0,0 +1,6 @@ +{ + "name": "Another Redis Desktop Manager", + "description": "🚀🚀🚀A faster, better and more stable Redis desktop manager [GUI client], compatible with Linux, Windows, Mac.", + "homepage": "https://github.com/qishibo/AnotherRedisDesktopManager", + "twitter": ["qii404"] +} From fd5eb3761a88c11c44a48ee7f3c378457e79517c Mon Sep 17 00:00:00 2001 From: Ilia Date: Thu, 3 Aug 2023 16:38:29 +0300 Subject: [PATCH 259/377] Fix typo (#2504) --- docs/reference/clients.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/clients.md b/docs/reference/clients.md index 25068b5ec1..b71007c3f2 100644 --- a/docs/reference/clients.md +++ b/docs/reference/clients.md @@ -112,7 +112,7 @@ Every client is also subject to a query buffer limit. This is a non-configurable Redis is built to handle a very large number of client connections. Client connections tend to consume memory, and when there are many of them, the aggregate memory consumption can be extremely high, leading to data eviction or out-of-memory errors. -These cases can be mitigated to an extent using [output buffer limits](#output-buffers-limits), but Redis allows us a more robust configuration to limit the aggregate memory used by all clients' connections. +These cases can be mitigated to an extent using [output buffer limits](#output-buffer-limits), but Redis allows us a more robust configuration to limit the aggregate memory used by all clients' connections. This mechanism is called **client eviction**, and it's essentially a safety mechanism that will disconnect clients once the aggregate memory usage of all clients is above a threshold. From 45afd278d880841f7402b91836c19f7f73cce7e4 Mon Sep 17 00:00:00 2001 From: Xavientois <34867186+Xavientois@users.noreply.github.com> Date: Wed, 9 Aug 2023 09:07:27 -0400 Subject: [PATCH 260/377] Change `don't` to `not` for grammar (#2509) --- docs/management/scaling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/management/scaling.md b/docs/management/scaling.md index 519242ac7d..bb47574241 100644 --- a/docs/management/scaling.md +++ b/docs/management/scaling.md @@ -960,7 +960,7 @@ by the application, and how. There are three different cases: 3. Multiple keys operations, or transactions, or Lua scripts involving multiple keys are used with key names not having an explicit, or the same, hash tag. The third case is not handled by Redis Cluster: the application requires to -be modified in order to don't use multi keys operations or only use them in +be modified in order to not use multi keys operations or only use them in the context of the same hash tag. Case 1 and 2 are covered, so we'll focus on those two cases, that are handled From 037fe9f955458a6d108c37830ec492ccb2c5fc9a Mon Sep 17 00:00:00 2001 From: Shane O'Hanlon Date: Thu, 10 Aug 2023 06:26:17 -0400 Subject: [PATCH 261/377] Fix typo in bitmaps.md (#2510) --- docs/data-types/bitmaps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/bitmaps.md b/docs/data-types/bitmaps.md index e9db26536a..0d45d4fc67 100644 --- a/docs/data-types/bitmaps.md +++ b/docs/data-types/bitmaps.md @@ -62,7 +62,7 @@ One of the biggest advantages of bitmaps is that they often provide extreme space savings when storing information. For example in a system where different users are represented by incremental user IDs, it is possible to remember a single bit information (for example, knowing whether -a user wants to receive a newsletter) of 4 billion of users using just 512 MB of memory. +a user wants to receive a newsletter) of 4 billion users using just 512 MB of memory. Bits are set and retrieved using the `SETBIT` and `GETBIT` commands: From d72c9854ba5cb927e28c4a57d35d85456e413eb8 Mon Sep 17 00:00:00 2001 From: savynorem Date: Mon, 14 Aug 2023 11:10:30 -0400 Subject: [PATCH 262/377] updating streams data type page with bike story for CLI commands and hugo short codes for tabbed examples --- docs/data-types/streams.md | 680 ++++++++++++++++++++----------------- 1 file changed, 372 insertions(+), 308 deletions(-) diff --git a/docs/data-types/streams.md b/docs/data-types/streams.md index 807cc994d4..60d691ce92 100644 --- a/docs/data-types/streams.md +++ b/docs/data-types/streams.md @@ -19,7 +19,7 @@ Examples of Redis stream use cases include: * Notifications (e.g., storing a record of each user's notifications in a separate stream) Redis generates a unique ID for each stream entry. -You can use these IDs to retrieve their associated entries later or to read and process all subsequent entries in the stream. +You can use these IDs to retrieve their associated entries later or to read and process all subsequent entries in the stream. Note that because these IDs are related to time, the ones shown here may vary and will be different from the IDs you see in your own Redis instance. Redis streams support several trimming strategies (to prevent streams from growing unbounded) and more than one consumption strategy (see `XREAD`, `XREADGROUP`, and `XRANGE`). @@ -34,40 +34,44 @@ See the [complete list of stream commands](https://redis.io/commands/?group=stre ## Examples -* Add several temperature readings to a stream -``` -> XADD temperatures:us-ny:10007 * temp_f 87.2 pressure 29.69 humidity 46 -"1658354918398-0" -> XADD temperatures:us-ny:10007 * temp_f 83.1 pressure 29.21 humidity 46.5 -"1658354934941-0" -> XADD temperatures:us-ny:10007 * temp_f 81.9 pressure 28.37 humidity 43.7 -"1658354957524-0" -``` - -* Read the first two stream entries starting at ID `1658354934941-0`: -``` -> XRANGE temperatures:us-ny:10007 1658354934941-0 + COUNT 2 -1) 1) "1658354934941-0" - 2) 1) "temp_f" - 2) "83.1" - 3) "pressure" - 4) "29.21" - 5) "humidity" - 6) "46.5" -2) 1) "1658354957524-0" - 2) 1) "temp_f" - 2) "81.9" - 3) "pressure" - 4) "28.37" - 5) "humidity" - 6) "43.7" -``` +* When our racers pass a checkpoint, we add a stream entry for each racer that includes the racer's name, speed, position, and location ID: +{{< clients-example stream_tutorial xadd >}} +> XADD race:france * rider Castilla speed 30.2 position 1 location_id 1 +"1691762745152-0" +> XADD race:france * rider Norem speed 28.8 position 3 location_id 1 +"1691765278160-0" +> XADD race:france * rider Prickett speed 29.7 position 2 location_id 1 +"1691765289770-0" +{{< /clients-example >}} + +* Read two stream entries starting at ID `1691765278160-0`: +{{< clients-example streams_tutorial xrange >}} +> XRANGE race:france 1691765278160-0 + COUNT 2 +1) 1) "1691765278160-0" + 2) 1) "rider" + 2) "Norem" + 3) "speed" + 4) "28.8" + 5) "position" + 6) "3" + 7) "location_id" + 8) "1" +2) 1) "1691765289770-0" + 2) 1) "rider" + 2) "Prickett" + 3) "speed" + 4) "29.7" + 5) "position" + 6) "2" + 7) "location_id" + 8) "1" +{{< /clients-example >}} * Read up to 100 new stream entries, starting at the end of the stream, and block for up to 300 ms if no entries are being written: -``` -> XREAD COUNT 100 BLOCK 300 STREAMS temperatures:us-ny:10007 $ +{{< clients-example stream_tutorial xread_block >}} +> XREAD COUNT 100 BLOCK 300 STREAMS race:france $ (nil) -``` +{{< /clients-example >}} ## Performance @@ -84,21 +88,21 @@ See each command's time complexity for the details. Streams are an append-only data structure. The fundamental write command, called `XADD`, appends a new entry to the specified stream. -Each stream entry consists of one or more field-value pairs, somewhat like a record or a Redis hash: +Each stream entry consists of one or more field-value pairs, somewhat like a dictionary or a Redis hash: -``` -> XADD mystream * sensor-id 1234 temperature 19.8 -1518951480106-0 -``` +{{< clients-example stream_tutorial xadd_2 >}} +> XADD race:france * rider Castilla speed 29.9 position 1 location_id 2 +"1691765375865-0" +{{< /clients-example >}} -The above call to the `XADD` command adds an entry `sensor-id: 1234, temperature: 19.8` to the stream at key `mystream`, using an auto-generated entry ID, which is the one returned by the command, specifically `1518951480106-0`. It gets as its first argument the key name `mystream`, the second argument is the entry ID that identifies every entry inside a stream. However, in this case, we passed `*` because we want the server to generate a new ID for us. Every new ID will be monotonically increasing, so in more simple terms, every new entry added will have a higher ID compared to all the past entries. Auto-generation of IDs by the server is almost always what you want, and the reasons for specifying an ID explicitly are very rare. We'll talk more about this later. The fact that each Stream entry has an ID is another similarity with log files, where line numbers, or the byte offset inside the file, can be used in order to identify a given entry. Returning back at our `XADD` example, after the key name and ID, the next arguments are the field-value pairs composing our stream entry. +The above call to the `XADD` command adds an entry `rider: Castilla, speed: 29.9, position: 1, location_id: 2` to the stream at key `race:france`, using an auto-generated entry ID, which is the one returned by the command, specifically `1691762745152-0`. It gets as its first argument the key name `race:france`, the second argument is the entry ID that identifies every entry inside a stream. However, in this case, we passed `*` because we want the server to generate a new ID for us. Every new ID will be monotonically increasing, so in more simple terms, every new entry added will have a higher ID compared to all the past entries. Auto-generation of IDs by the server is almost always what you want, and the reasons for specifying an ID explicitly are very rare. We'll talk more about this later. The fact that each Stream entry has an ID is another similarity with log files, where line numbers, or the byte offset inside the file, can be used in order to identify a given entry. Returning back at our `XADD` example, after the key name and ID, the next arguments are the field-value pairs composing our stream entry. It is possible to get the number of items inside a Stream just using the `XLEN` command: -``` -> XLEN mystream -(integer) 1 -``` +{{< clients-example stream_tutorial xlen >}} +> XLEN race:france +(integer) 4 +{{< /clients-example >}} ### Entry IDs @@ -114,26 +118,26 @@ The format of such IDs may look strange at first, and the gentle reader may wond If for some reason the user needs incremental IDs that are not related to time but are actually associated to another external system ID, as previously mentioned, the `XADD` command can take an explicit ID instead of the `*` wildcard ID that triggers auto-generation, like in the following examples: -``` -> XADD somestream 0-1 field value +{{< clients-example streams_toturial xadd_id >}} +> XADD race:usa 0-1 racer Castilla 0-1 -> XADD somestream 0-2 foo bar +> XADD race:usa 0-2 racer Norem 0-2 -``` +{{< /clients-example >}} Note that in this case, the minimum ID is 0-1 and that the command will not accept an ID equal or smaller than a previous one: -``` -> XADD somestream 0-1 foo bar +{{< clients-example streams_toturial xadd_bad_id >}} +> XADD race:usa 0-1 racer Prickett (error) ERR The ID specified in XADD is equal or smaller than the target stream top item -``` +{{< /clients-example >}} If you're running Redis 7 or later, you can also provide an explicit ID consisting of the milliseconds part only. In this case, the sequence portion of the ID will be automatically generated. To do this, use the syntax below: -``` -> XADD somestream 0-* baz qux +{{< clients-example streams_toturial xadd_7 >}} +> XADD race:usa 0-* racer Prickett 0-3 -``` +{{< /clients-example >}} ## Getting data from Streams @@ -149,65 +153,132 @@ Redis Streams support all three of the query modes described above via different To query the stream by range we are only required to specify two IDs, *start* and *end*. The range returned will include the elements having start or end as ID, so the range is inclusive. The two special IDs `-` and `+` respectively mean the smallest and the greatest ID possible. -``` -> XRANGE mystream - + -1) 1) 1518951480106-0 - 2) 1) "sensor-id" - 2) "1234" - 3) "temperature" - 4) "19.8" -2) 1) 1518951482479-0 - 2) 1) "sensor-id" - 2) "9999" - 3) "temperature" - 4) "18.2" -``` +{{< clients-example streams_toturial xrange_all >}} +> XRANGE race:france - + +1) 1) "1691762745152-0" + 2) 1) "rider" + 2) "Castilla" + 3) "speed" + 4) "30.2" + 5) "position" + 6) "1" + 7) "location_id" + 8) "1" +2) 1) "1691765278160-0" + 2) 1) "rider" + 2) "Norem" + 3) "speed" + 4) "28.8" + 5) "position" + 6) "3" + 7) "location_id" + 8) "1" +3) 1) "1691765289770-0" + 2) 1) "rider" + 2) "Prickett" + 3) "speed" + 4) "29.7" + 5) "position" + 6) "2" + 7) "location_id" + 8) "1" +4) 1) "1691765375865-0" + 2) 1) "rider" + 2) "Castilla" + 3) "speed" + 4) "29.9" + 5) "position" + 6) "1" + 7) "location_id" + 8) "2" +{{< /clients-example >}} Each entry returned is an array of two items: the ID and the list of field-value pairs. We already said that the entry IDs have a relation with the time, because the part at the left of the `-` character is the Unix time in milliseconds of the local node that created the stream entry, at the moment the entry was created (however note that streams are replicated with fully specified `XADD` commands, so the replicas will have identical IDs to the master). This means that I could query a range of time using `XRANGE`. In order to do so, however, I may want to omit the sequence part of the ID: if omitted, in the start of the range it will be assumed to be 0, while in the end part it will be assumed to be the maximum sequence number available. This way, querying using just two milliseconds Unix times, we get all the entries that were generated in that range of time, in an inclusive way. For instance, if I want to query a two milliseconds period I could use: -``` -> XRANGE mystream 1518951480106 1518951480107 -1) 1) 1518951480106-0 - 2) 1) "sensor-id" - 2) "1234" - 3) "temperature" - 4) "19.8" -``` - -I have only a single entry in this range, however in real data sets, I could query for ranges of hours, or there could be many items in just two milliseconds, and the result returned could be huge. For this reason, `XRANGE` supports an optional **COUNT** option at the end. By specifying a count, I can just get the first *N* items. If I want more, I can get the last ID returned, increment the sequence part by one, and query again. Let's see this in the following example. We start adding 10 items with `XADD` (I won't show that, lets assume that the stream `mystream` was populated with 10 items). To start my iteration, getting 2 items per command, I start with the full range, but with a count of 2. - -``` -> XRANGE mystream - + COUNT 2 -1) 1) 1519073278252-0 - 2) 1) "foo" - 2) "value_1" -2) 1) 1519073279157-0 - 2) 1) "foo" - 2) "value_2" -``` - -In order to continue the iteration with the next two items, I have to pick the last ID returned, that is `1519073279157-0` and add the prefix `(` to it. The resulting exclusive range interval, that is `(1519073279157-0` in this case, can now be used as the new *start* argument for the next `XRANGE` call: - -``` -> XRANGE mystream (1519073279157-0 + COUNT 2 -1) 1) 1519073280281-0 - 2) 1) "foo" - 2) "value_3" -2) 1) 1519073281432-0 - 2) 1) "foo" - 2) "value_4" -``` - -And so forth. Since `XRANGE` complexity is *O(log(N))* to seek, and then *O(M)* to return M elements, with a small count the command has a logarithmic time complexity, which means that each step of the iteration is fast. So `XRANGE` is also the de facto *streams iterator* and does not require an **XSCAN** command. +{{< clients-example streams_toturial xrange_time >}} +> XRANGE race:france 1691765375864 1691765375866 +1) 1) "1691765375865-0" + 2) 1) "rider" + 2) "Castilla" + 3) "speed" + 4) "29.9" + 5) "position" + 6) "1" + 7) "location_id" + 8) "2" +{{< /clients-example >}} + +I have only a single entry in this range, however in real data sets, I could query for ranges of hours, or there could be many items in just two milliseconds, and the result returned could be huge. For this reason, `XRANGE` supports an optional **COUNT** option at the end. By specifying a count, I can just get the first *N* items. If I want more, I can get the last ID returned, increment the sequence part by one, and query again. Let's see this in the following example. Let's assume that the stream `race:france` was populated with 4 items. To start my iteration, getting 2 items per command, I start with the full range, but with a count of 2. + +{{< clients-example streams_toturial xrange_step_1 >}} +> XRANGE race:france - + COUNT 2 +1) 1) "1691762745152-0" + 2) 1) "rider" + 2) "Castilla" + 3) "speed" + 4) "30.2" + 5) "position" + 6) "1" + 7) "location_id" + 8) "1" +2) 1) "1691765278160-0" + 2) 1) "rider" + 2) "Norem" + 3) "speed" + 4) "28.8" + 5) "position" + 6) "3" + 7) "location_id" + 8) "1" +{{< /clients-example >}} + +In order to continue the iteration with the next two items, I have to pick the last ID returned, that is `1691765278160-0` and add the prefix `(` to it. The resulting exclusive range interval, that is `(1691765278160-0` in this case, can now be used as the new *start* argument for the next `XRANGE` call: + +{{< clients-example streams_toturial xrange_step_2 >}} +> XRANGE race:france (1691765278160-0 + COUNT 2 +1) 1) "1691765289770-0" + 2) 1) "rider" + 2) "Prickett" + 3) "speed" + 4) "29.7" + 5) "position" + 6) "2" + 7) "location_id" + 8) "1" +2) 1) "1691765375865-0" + 2) 1) "rider" + 2) "Castilla" + 3) "speed" + 4) "29.9" + 5) "position" + 6) "1" + 7) "location_id" + 8) "2" +{{< /clients-example >}} + +Now that we've gotten 4 items out of a stream that only had 4 things in it, if we try to get more items, we'll get an empty array: + +{{< clients-example streams_toturial xrange_empty >}} +> XRANGE race:france (1691765375865-0 + COUNT 2 +(empty array) +{{< /clients-example >}} + +Since `XRANGE` complexity is *O(log(N))* to seek, and then *O(M)* to return M elements, with a small count the command has a logarithmic time complexity, which means that each step of the iteration is fast. So `XRANGE` is also the de facto *streams iterator* and does not require an **XSCAN** command. The command `XREVRANGE` is the equivalent of `XRANGE` but returning the elements in inverted order, so a practical use for `XREVRANGE` is to check what is the last item in a Stream: -``` -> XREVRANGE mystream + - COUNT 1 -1) 1) 1519073287312-0 - 2) 1) "foo" - 2) "value_10" -``` +{{< clients-example streams_toturial xrevrange >}} +> XREVRANGE race:france + - COUNT 1 +1) 1) "1691765375865-0" + 2) 1) "rider" + 2) "Castilla" + 3) "speed" + 4) "29.9" + 5) "position" + 6) "1" + 7) "location_id" + 8) "2" +{{< /clients-example >}} Note that the `XREVRANGE` command takes the *start* and *stop* arguments in reverse order. @@ -221,26 +292,38 @@ When we do not want to access items by a range in a stream, usually what we want The command that provides the ability to listen for new messages arriving into a stream is called `XREAD`. It's a bit more complex than `XRANGE`, so we'll start showing simple forms, and later the whole command layout will be provided. -``` -> XREAD COUNT 2 STREAMS mystream 0 -1) 1) "mystream" - 2) 1) 1) 1519073278252-0 - 2) 1) "foo" - 2) "value_1" - 2) 1) 1519073279157-0 - 2) 1) "foo" - 2) "value_2" -``` +{{< clients-example streams_toturial xread >}} +> XREAD COUNT 2 STREAMS race:france 0 +1) 1) "race:france" + 2) 1) 1) "1691762745152-0" + 2) 1) "rider" + 2) "Castilla" + 3) "speed" + 4) "30.2" + 5) "position" + 6) "1" + 7) "location_id" + 8) "1" + 2) 1) "1691765278160-0" + 2) 1) "rider" + 2) "Norem" + 3) "speed" + 4) "28.8" + 5) "position" + 6) "3" + 7) "location_id" + 8) "1" +{{< /clients-example >}} The above is the non-blocking form of `XREAD`. Note that the **COUNT** option is not mandatory, in fact the only mandatory option of the command is the **STREAMS** option, that specifies a list of keys together with the corresponding maximum ID already seen for each stream by the calling consumer, so that the command will provide the client only with messages with an ID greater than the one we specified. -In the above command we wrote `STREAMS mystream 0` so we want all the messages in the Stream `mystream` having an ID greater than `0-0`. As you can see in the example above, the command returns the key name, because actually it is possible to call this command with more than one key to read from different streams at the same time. I could write, for instance: `STREAMS mystream otherstream 0 0`. Note how after the **STREAMS** option we need to provide the key names, and later the IDs. For this reason, the **STREAMS** option must always be the last option. +In the above command we wrote `STREAMS race:france 0` so we want all the messages in the Stream `race:france` having an ID greater than `0-0`. As you can see in the example above, the command returns the key name, because actually it is possible to call this command with more than one key to read from different streams at the same time. I could write, for instance: `STREAMS race:france race:italy 0 0`. Note how after the **STREAMS** option we need to provide the key names, and later the IDs. For this reason, the **STREAMS** option must always be the last option. Any other options must come before the **STREAMS** option. Apart from the fact that `XREAD` can access multiple streams at once, and that we are able to specify the last ID we own to just get newer messages, in this simple form the command is not doing something so different compared to `XRANGE`. However, the interesting part is that we can turn `XREAD` into a *blocking command* easily, by specifying the **BLOCK** argument: ``` -> XREAD BLOCK 0 STREAMS mystream $ +> XREAD BLOCK 0 STREAMS race:france $ ``` Note that in the example above, other than removing **COUNT**, I specified the new **BLOCK** option with a timeout of 0 milliseconds (that means to never timeout). Moreover, instead of passing a normal ID for the stream `mystream` I passed the special ID `$`. This special ID means that `XREAD` should use as last ID the maximum ID already stored in the stream `mystream`, so that we will receive only *new* messages, starting from the time we started listening. This is similar to the `tail -f` Unix command in some way. @@ -306,52 +389,46 @@ Now it's time to zoom in to see the fundamental consumer group commands. They ar ## Creating a consumer group -Assuming I have a key `mystream` of type stream already existing, in order to create a consumer group I just need to do the following: +Assuming I have a key `race:france` of type stream already existing, in order to create a consumer group I just need to do the following: -``` -> XGROUP CREATE mystream mygroup $ +{{< clients-example streams_toturial xgroup_create >}} +> XGROUP CREATE race:france france_location $ OK -``` +{{< /clients-example >}} As you can see in the command above when creating the consumer group we have to specify an ID, which in the example is just `$`. This is needed because the consumer group, among the other states, must have an idea about what message to serve next at the first consumer connecting, that is, what was the *last message ID* when the group was just created. If we provide `$` as we did, then only new messages arriving in the stream from now on will be provided to the consumers in the group. If we specify `0` instead the consumer group will consume *all* the messages in the stream history to start with. Of course, you can specify any other valid ID. What you know is that the consumer group will start delivering messages that are greater than the ID you specify. Because `$` means the current greatest ID in the stream, specifying `$` will have the effect of consuming only new messages. `XGROUP CREATE` also supports creating the stream automatically, if it doesn't exist, using the optional `MKSTREAM` subcommand as the last argument: -``` -> XGROUP CREATE newstream mygroup $ MKSTREAM +{{< clients-example streams_toturial xgroup_create_mkstream >}} +> XGROUP CREATE race:italy italy_racers $ MKSTREAM OK -``` +{{< /clients-example >}} Now that the consumer group is created we can immediately try to read messages via the consumer group using the `XREADGROUP` command. We'll read from consumers, that we will call Alice and Bob, to see how the system will return different messages to Alice or Bob. `XREADGROUP` is very similar to `XREAD` and provides the same **BLOCK** option, otherwise it is a synchronous command. However there is a *mandatory* option that must be always specified, which is **GROUP** and has two arguments: the name of the consumer group, and the name of the consumer that is attempting to read. The option **COUNT** is also supported and is identical to the one in `XREAD`. -Before reading from the stream, let's put some messages inside: - -``` -> XADD mystream * message apple -1526569495631-0 -> XADD mystream * message orange -1526569498055-0 -> XADD mystream * message strawberry -1526569506935-0 -> XADD mystream * message apricot -1526569535168-0 -> XADD mystream * message banana -1526569544280-0 -``` - -Note: *here message is the field name, and the fruit is the associated value, remember that stream items are small dictionaries.* - -It is time to try reading something using the consumer group: - -``` -> XREADGROUP GROUP mygroup Alice COUNT 1 STREAMS mystream > -1) 1) "mystream" - 2) 1) 1) 1526569495631-0 - 2) 1) "message" - 2) "apple" -``` +We'll add racers to the race:italy stream and try reading something using the consumer group: +Note: *here racer is the field name, and the name is the associated value, remember that stream items are small dictionaries.* + +{{< clients-example streams_toturial xgroup_read >}} +> XADD race:italy * racer Castilla +"1691766245113-0" +> XADD race:italy * racer Royce +"1691766256307-0" +> XADD race:italy * racer Sam-Bodden +"1691766261145-0" +> XADD race:italy * racer Prickett +"1691766685178-0" +> XADD race:italy * racer Norem +"1691766698493-0" +> XREADGROUP GROUP italy_racers Alice COUNT 1 STREAMS race:italy > +1) 1) "race:italy" + 2) 1) 1) "1691766245113-0" + 2) 1) "racer" + 2) "Castilla" +{{< /clients-example >}} `XREADGROUP` replies are just like `XREAD` replies. Note however the `GROUP ` provided above. It states that I want to read from the stream using the consumer group `mygroup` and I'm the consumer `Alice`. Every time a consumer performs an operation with a consumer group, it must specify its name, uniquely identifying this consumer inside the group. @@ -364,38 +441,38 @@ This is almost always what you want, however it is also possible to specify a re We can test this behavior immediately specifying an ID of 0, without any **COUNT** option: we'll just see the only pending message, that is, the one about apples: -``` -> XREADGROUP GROUP mygroup Alice STREAMS mystream 0 -1) 1) "mystream" - 2) 1) 1) 1526569495631-0 - 2) 1) "message" - 2) "apple" -``` +{{< clients-example streams_toturial xgroup_read_id >}} +> XREADGROUP GROUP italy_racers Alice STREAMS race:italy 0 +1) 1) "race:italy" + 2) 1) 1) "1691766245113-0" + 2) 1) "racer" + 2) "Castilla" +{{< /clients-example >}} However, if we acknowledge the message as processed, it will no longer be part of the pending messages history, so the system will no longer report anything: -``` -> XACK mystream mygroup 1526569495631-0 +{{< clients-example streams_toturial xack >}} +> XACK race:italy italy_racers 1691766245113-0 (integer) 1 -> XREADGROUP GROUP mygroup Alice STREAMS mystream 0 -1) 1) "mystream" - 2) (empty list or set) -``` +> XREADGROUP GROUP italy_racers Alice STREAMS race:italy 0 +1) 1) "race:italy" + 2) (empty array) +{{< /clients-example >}} Don't worry if you yet don't know how `XACK` works, the idea is just that processed messages are no longer part of the history that we can access. Now it's Bob's turn to read something: -``` -> XREADGROUP GROUP mygroup Bob COUNT 2 STREAMS mystream > -1) 1) "mystream" - 2) 1) 1) 1526569498055-0 - 2) 1) "message" - 2) "orange" - 2) 1) 1526569506935-0 - 2) 1) "message" - 2) "strawberry" -``` +{{< clients-example streams_toturial xgroup_read_bob >}} +> XREADGROUP GROUP italy_racers Bob COUNT 2 STREAMS race:italy > +1) 1) "race:italy" + 2) 1) 1) "1691766256307-0" + 2) 1) "racer" + 2) "Royce" + 2) 1) "1691766261145-0" + 2) 1) "racer" + 2) "Sam-Bodden" +{{< /clients-example >}} Bob asked for a maximum of two messages and is reading via the same group `mygroup`. So what happens is that Redis reports just *new* messages. As you can see the "apple" message is not delivered, since it was already delivered to Alice, so Bob gets orange and strawberry, and so forth. @@ -478,14 +555,14 @@ The first step of this process is just a command that provides observability of This is a read-only command which is always safe to call and will not change ownership of any message. In its simplest form, the command is called with two arguments, which are the name of the stream and the name of the consumer group. -``` -> XPENDING mystream mygroup +{{< clients-example streams_toturial xpending >}} +> XPENDING race:italy italy_racers 1) (integer) 2 -2) 1526569498055-0 -3) 1526569506935-0 +2) "1691766256307-0" +3) "1691766261145-0" 4) 1) 1) "Bob" 2) "2" -``` +{{< /clients-example >}} When called in this way, the command outputs the total number of pending messages in the consumer group (two in this case), the lower and higher message ID among the pending messages, and finally a list of consumers and the number of pending messages they have. We have only Bob with two pending messages because the single message that Alice requested was acknowledged using `XACK`. @@ -498,31 +575,31 @@ XPENDING [[IDLE ] [ By providing a start and end ID (that can be just `-` and `+` as in `XRANGE`) and a count to control the amount of information returned by the command, we are able to know more about the pending messages. The optional final argument, the consumer name, is used if we want to limit the output to just messages pending for a given consumer, but won't use this feature in the following example. -``` -> XPENDING mystream mygroup - + 10 -1) 1) 1526569498055-0 +{{< clients-example streams_toturial xpending_plus_minus >}} +> XPENDING race:italy italy_racers - + 10 +1) 1) "1691766256307-0" 2) "Bob" - 3) (integer) 74170458 + 3) (integer) 60644 4) (integer) 1 -2) 1) 1526569506935-0 +2) 1) "1691766261145-0" 2) "Bob" - 3) (integer) 74170458 + 3) (integer) 60644 4) (integer) 1 -``` +{{< /clients-example >}} Now we have the details for each message: the ID, the consumer name, the *idle time* in milliseconds, which is how many milliseconds have passed since the last time the message was delivered to some consumer, and finally the number of times that a given message was delivered. -We have two messages from Bob, and they are idle for 74170458 milliseconds, about 20 hours. +We have two messages from Bob, and they are idle for 60000+ milliseconds, about a minute. Note that nobody prevents us from checking what the first message content was by just using `XRANGE`. -``` -> XRANGE mystream 1526569498055-0 1526569498055-0 -1) 1) 1526569498055-0 - 2) 1) "message" - 2) "orange" -``` +{{< clients-example streams_toturial xrange_pending >}} +> XRANGE race:italy 1691766256307-0 1691766256307-0 +1) 1) "1691766256307-0" + 2) 1) "racer" + 2) "Royce" +{{< /clients-example >}} -We have just to repeat the same ID twice in the arguments. Now that we have some ideas, Alice may decide that after 20 hours of not processing messages, Bob will probably not recover in time, and it's time to *claim* such messages and resume the processing in place of Bob. To do so, we use the `XCLAIM` command. +We have just to repeat the same ID twice in the arguments. Now that we have some ideas, Alice may decide that after 1 minute of not processing messages, Bob will probably not recover quickly, and it's time to *claim* such messages and resume the processing in place of Bob. To do so, we use the `XCLAIM` command. This command is very complex and full of options in its full form, since it is used for replication of consumer groups changes, but we'll use just the arguments that we need normally. In this case it is as simple as: @@ -533,20 +610,20 @@ XCLAIM ... Basically we say, for this specific key and group, I want that the message IDs specified will change ownership, and will be assigned to the specified consumer name ``. However, we also provide a minimum idle time, so that the operation will only work if the idle time of the mentioned messages is greater than the specified idle time. This is useful because maybe two clients are retrying to claim a message at the same time: ``` -Client 1: XCLAIM mystream mygroup Alice 3600000 1526569498055-0 -Client 2: XCLAIM mystream mygroup Lora 3600000 1526569498055-0 +Client 1: XCLAIM race:italy italy_racers Alice 60000 1691766256307-0 +Client 2: XCLAIM race:italy italy_racers Lora 60000 1691766256307-0 ``` However, as a side effect, claiming a message will reset its idle time and will increment its number of deliveries counter, so the second client will fail claiming it. In this way we avoid trivial re-processing of messages (even if in the general case you cannot obtain exactly once processing). This is the result of the command execution: -``` -> XCLAIM mystream mygroup Alice 3600000 1526569498055-0 -1) 1) 1526569498055-0 - 2) 1) "message" - 2) "orange" -``` +{{< clients-example streams_toturial xclaim >}} +> XCLAIM race:italy italy_racers Alice 60000 1691766256307-0 +1) 1) "1691766256307-0" + 2) 1) "racer" + 2) "Royce" +{{< /clients-example >}} The message was successfully claimed by Alice, who can now process the message and acknowledge it, and move things forward even if the original consumer is not recovering. @@ -569,24 +646,25 @@ XAUTOCLAIM [COUNT count] [JUSTI So, in the example above, I could have used automatic claiming to claim a single message like this: -``` -> XAUTOCLAIM mystream mygroup Alice 3600000 0-0 COUNT 1 -1) 1526569498055-0 -2) 1) 1526569498055-0 - 2) 1) "message" - 2) "orange" -``` +{{< clients-example streams_toturial xautoclaim >}} +> XAUTOCLAIM race:italy italy_racers Alice 60000 0-0 COUNT 1 +1) "1691766261145-0" +2) 1) 1) "1691766256307-0" + 2) 1) "racer" + 2) "Royce" +{{< /clients-example >}} Like `XCLAIM`, the command replies with an array of the claimed messages, but it also returns a stream ID that allows iterating the pending entries. The stream ID is a cursor, and I can use it in my next call to continue in claiming idle pending messages: -``` -> XAUTOCLAIM mystream mygroup Lora 3600000 1526569498055-0 COUNT 1 -1) 0-0 -2) 1) 1526569506935-0 - 2) 1) "message" - 2) "strawberry" -``` +{{< clients-example streams_toturial xautoclaim_cursor >}} +> XAUTOCLAIM race:italy italy_racers Lora 60000 1526569498055-0 COUNT 1 +1) "0-0" +2) 1) 1) "1691766261145-0" + 2) 1) "racer" + 2) "Sam-Bodden" +{{< /clients-example >}} + When `XAUTOCLAIM` returns the "0-0" stream ID as a cursor, that means that it reached the end of the consumer group pending entries list. That doesn't mean that there are no new idle pending messages, so the process continues by calling `XAUTOCLAIM` from the beginning of the stream. @@ -604,81 +682,67 @@ However we may want to do more than that, and the `XINFO` command is an observab This command uses subcommands in order to show different information about the status of the stream and its consumer groups. For instance **XINFO STREAM ** reports information about the stream itself. -``` -> XINFO STREAM mystream +{{< clients-example streams_toturial xinfo >}} +> XINFO STREAM race:italy 1) "length" - 2) (integer) 2 + 2) (integer) 5 3) "radix-tree-keys" 4) (integer) 1 5) "radix-tree-nodes" 6) (integer) 2 7) "last-generated-id" - 8) "1638125141232-0" - 9) "max-deleted-entryid" -10) "0-0" -11) "entries-added" -12) (integer) 2 -13) "groups" -14) (integer) 1 -15) "first-entry" -16) 1) "1638125133432-0" - 2) 1) "message" - 2) "apple" -17) "last-entry" -18) 1) "1638125141232-0" - 2) 1) "message" - 2) "banana" -``` + 8) "1691766698493-0" + 9) "groups" +10) (integer) 1 +11) "first-entry" +12) 1) "1691766245113-0" + 2) 1) "racer" + 2) "Castilla" +13) "last-entry" +14) 1) "1691766698493-0" + 2) 1) "racer" + 2) "Norem" +{{< /clients-example >}} The output shows information about how the stream is encoded internally, and also shows the first and last message in the stream. Another piece of information available is the number of consumer groups associated with this stream. We can dig further asking for more information about the consumer groups. -``` -> XINFO GROUPS mystream -1) 1) "name" - 2) "mygroup" - 3) "consumers" - 4) (integer) 2 - 5) "pending" - 6) (integer) 2 - 7) "last-delivered-id" - 8) "1638126030001-0" - 9) "entries-read" - 10) (integer) 2 - 11) "lag" - 12) (integer) 0 -2) 1) "name" - 2) "some-other-group" - 3) "consumers" - 4) (integer) 1 - 5) "pending" - 6) (integer) 0 - 7) "last-delivered-id" - 8) "1638126028070-0" - 9) "entries-read" - 10) (integer) 1 - 11) "lag" - 12) (integer) 1 -``` +{{< clients-example streams_toturial xinfo_groups >}} +> XINFO GROUPS race:italy +1) 1) "name" + 2) "italy_racers" + 3) "consumers" + 4) (integer) 3 + 5) "pending" + 6) (integer) 2 + 7) "last-delivered-id" + 8) "1691766261145-0" +{{< /clients-example >}} As you can see in this and in the previous output, the `XINFO` command outputs a sequence of field-value items. Because it is an observability command this allows the human user to immediately understand what information is reported, and allows the command to report more information in the future by adding more fields without breaking compatibility with older clients. Other commands that must be more bandwidth efficient, like `XPENDING`, just report the information without the field names. The output of the example above, where the **GROUPS** subcommand is used, should be clear observing the field names. We can check in more detail the state of a specific consumer group by checking the consumers that are registered in the group. -``` -> XINFO CONSUMERS mystream mygroup -1) 1) name +{{< clients-example streams_toturial xinfo_consumers >}}} +> XINFO CONSUMERS race:italy italy_racers +1) 1) "name" 2) "Alice" - 3) pending + 3) "pending" 4) (integer) 1 - 5) idle - 6) (integer) 9104628 -2) 1) name + 5) "idle" + 6) (integer) 130215 +2) 1) "name" 2) "Bob" - 3) pending + 3) "pending" + 4) (integer) 0 + 5) "idle" + 6) (integer) 2581506 +3) 1) "name" + 2) "Lora" + 3) "pending" 4) (integer) 1 - 5) idle - 6) (integer) 83841983 -``` + 5) "idle" + 6) (integer) 102218 +{{< /clients-example >}} In case you do not remember the syntax of the command, just ask the command itself for help: @@ -715,45 +779,45 @@ So basically Kafka partitions are more similar to using N different Redis keys, Many applications do not want to collect data into a stream forever. Sometimes it is useful to have at maximum a given number of items inside a stream, other times once a given size is reached, it is useful to move data from Redis to a storage which is not in memory and not as fast but suited to store the history for, potentially, decades to come. Redis streams have some support for this. One is the **MAXLEN** option of the `XADD` command. This option is very simple to use: -``` -> XADD mystream MAXLEN 2 * value 1 -1526654998691-0 -> XADD mystream MAXLEN 2 * value 2 -1526654999635-0 -> XADD mystream MAXLEN 2 * value 3 -1526655000369-0 -> XLEN mystream +{{< clients-example stream_tutorial maxlen >}} +> XADD race:italy MAXLEN 2 * racer Jones +"1691769379388-0" +> XADD race:italy MAXLEN 2 * racer Wood +"1691769438199-0" +> XADD race:italy MAXLEN 2 * racer Henshaw +"1691769502417-0" +> XLEN race:italy (integer) 2 -> XRANGE mystream - + -1) 1) 1526654999635-0 - 2) 1) "value" - 2) "2" -2) 1) 1526655000369-0 - 2) 1) "value" - 2) "3" -``` +> XRANGE race:italy - + +1) 1) "1691769438199-0" + 2) 1) "racer" + 2) "Wood" +2) 1) "1691769502417-0" + 2) 1) "racer" + 2) "Henshaw" +{{< /clients-example >}} Using **MAXLEN** the old entries are automatically evicted when the specified length is reached, so that the stream is left at a constant size. There is currently no option to tell the stream to just retain items that are not older than a given period, because such command, in order to run consistently, would potentially block for a long time in order to evict items. Imagine for example what happens if there is an insertion spike, then a long pause, and another insertion, all with the same maximum time. The stream would block to evict the data that became too old during the pause. So it is up to the user to do some planning and understand what is the maximum stream length desired. Moreover, while the length of the stream is proportional to the memory used, trimming by time is less simple to control and anticipate: it depends on the insertion rate which often changes over time (and when it does not change, then to just trim by size is trivial). However trimming with **MAXLEN** can be expensive: streams are represented by macro nodes into a radix tree, in order to be very memory efficient. Altering the single macro node, consisting of a few tens of elements, is not optimal. So it's possible to use the command in the following special form: ``` -XADD mystream MAXLEN ~ 1000 * ... entry fields here ... +XADD race:italy MAXLEN ~ 1000 * ... entry fields here ... ``` The `~` argument between the **MAXLEN** option and the actual count means, I don't really need this to be exactly 1000 items. It can be 1000 or 1010 or 1030, just make sure to save at least 1000 items. With this argument, the trimming is performed only when we can remove a whole node. This makes it much more efficient, and it is usually what you want. There is also the `XTRIM` command, which performs something very similar to what the **MAXLEN** option does above, except that it can be run by itself: -``` -> XTRIM mystream MAXLEN 10 -``` +{{< clients-example stream_tutorial xtrim >}} +> XTRIM race:italy MAXLEN 10 +{{< /clients-example >}} Or, as for the `XADD` option: -``` +{{< clients-example stream_tutorial xtrim2 >}} > XTRIM mystream MAXLEN ~ 10 -``` +{{< /clients-example >}} However, `XTRIM` is designed to accept different trimming strategies. Another trimming strategy is **MINID**, that evicts entries with IDs lower than the one specified. @@ -793,21 +857,21 @@ So when designing an application using Redis streams and consumer groups, make s Streams also have a special command for removing items from the middle of a stream, just by ID. Normally for an append only data structure this may look like an odd feature, but it is actually useful for applications involving, for instance, privacy regulations. The command is called `XDEL` and receives the name of the stream followed by the IDs to delete: -``` -> XRANGE mystream - + COUNT 2 -1) 1) 1526654999635-0 - 2) 1) "value" - 2) "2" -2) 1) 1526655000369-0 - 2) 1) "value" - 2) "3" -> XDEL mystream 1526654999635-0 +{{< clients-example stream_tutorial xdel >}} +> XRANGE race:italy - + COUNT 2 +1) 1) "1691769438199-0" + 2) 1) "racer" + 2) "Wood" +2) 1) "1691769502417-0" + 2) 1) "racer" + 2) "Henshaw" +> XDEL race:italy 1691769502417-0 (integer) 1 -> XRANGE mystream - + COUNT 2 -1) 1) 1526655000369-0 - 2) 1) "value" - 2) "3" -``` +> XRANGE race:italy - + COUNT 2 +1) 1) "1691769438199-0" + 2) 1) "racer" + 2) "Wood" +{{< /clients-example >}} However in the current implementation, memory is not really reclaimed until a macro node is completely empty, so you should not abuse this feature. From 2ed656648a2f3423052694e43e61515f0c822ef2 Mon Sep 17 00:00:00 2001 From: savynorem Date: Mon, 14 Aug 2023 11:22:53 -0400 Subject: [PATCH 263/377] updating wordlist for geo and streams --- wordlist | 998 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 502 insertions(+), 496 deletions(-) diff --git a/wordlist b/wordlist index 504bc19b16..257e9657de 100644 --- a/wordlist +++ b/wordlist @@ -1,481 +1,52 @@ - +3:00 AM +4:00 AM +5:00 AM +6:00 AM .rdb -0s -0x00060007 -0x00MMmmpp -100MB -100k -10GB -10k -128MB -12k -1GB -1s -1th -2GB -300ms -30ms -32MB -32bit -3GB -3MB -3am -3c3a0c -3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e -4GB -4am -4k -500MB -512MB -5GB -5am -60s -6am -6sync -80ms -85MB -8MB -8ms -90s -97a3a64667477371c4479320d683e4c8db5858b1 -A1 -ACKs -ACLs -AMD64 -AOF -AOFRW -AOF_START -APIs -ARGV -ASN -AUTOID -Aioredlock -Alibaba -Arity -Async -Asyncio -Atomicvar -Auth -B1 -B2 -B3 -BCC's -BDFL-style -birthyear -BPF -BPF's -BPF-optimized -Benchmarking -BigNumber -BitOp -Bitfields -Bitwise -brpop -C1 -C2 -C3 -C4 -C5 -CAS -CAs -CFIELD -CKQUORUM -CLI -CLI's -CP -CPUs -CRC -CRC-16 -CRC16 -CRC64 -CRDTs -CRLF -CRLF-terminated -CSV -CallReply -CentOS -Changelog -Chemeris -Citrusbyte -CloseKey -Cn -Collina's -Config -ContextFlags -Costin -Craigslist -Ctrl-a -DBs -DLM -DMA -dnf -DNF -DNS -DSL -Deauthenticate -Deauthenticates -Defrag -Deno -Diskless -DistLock -Dynomite -EBADF -EBS -EC2 -EDOM -EEXIST -EFBIG -EINVAL -Enduro -Ergonom -ENOENT -ENOTSUP -EOF -EP -EPEL -EPSG:3785 -EPSG:900913 -ERANGE -Enum -Eval -EventLoop -EventMachine -FLUSHCONFIG -Failover -Failover-based -Failovers -FlameGraph -FreeBSD -FreeString -Fsyncing -GDB -GEODEL -GET-MASTER-ADDR-BY-NAME -go-redis -GPG -Gbit -GeoHashes -Geohash -Geohashes -Geospatial -Github -Gottlieb -Gradle -HashMap -HLL -HLLs -HMAC-SHA256 -HVM -HW -Hacktoberfest -Hardcoded -HashMaps -HashSets -Haversine -Hexastore -hget -hgetall -hincrby -hmget -Hitmeister -Homebrew -Hotspot -hset -HyperLogLog -HyperLogLog. -HyperLogLogs -Hyperloglogs -hyperloglogs -incr -incrby -IOPs -IPC -IPs -IPv4 -IPv6 -IS-MASTER-DOWN-BY-ADDR -Identinal -IoT -incrby_get_mget -Itamar -Jedis -JedisCluster -JedisPool -JedisPooled -JDK -JKS -JSON -JSON-encoded -Janowski -Javadocs -Jemalloc -js -KEYSPACE -Keyspace -KeyspaceNotification -Kleppman's -Kleppmann -L3 -LDB -LF -LFU -LHF -LLOOGG -lmove_lrange -LRU -LRU's -LRU. -LUA -Leaderboards -Leau -Lehmann -Levelgraph -licensor -licensor's -LibLZF -Linode -Liveness -llen -lmove_lrange -lpop -lpop_rpop -lpush_rpush -lrange -ltrim -ltrim_end_of_list -Lua -Lua's -lua-debugging -Lua-to-Redis -Lucraft -M1 -MASTERDOWN -MERCHANTABILITY -MacBook -Matteo -Maxmemory -Memcache -MessagePack -mget -Movablekeys -Mrkris -mset -multisets -NAS -NATted -NFS -NIC -NICs -NOOP -NTP -NUMA -NX -NaN -Nehalem -node-redis -NoSQL -NodeJS -Noordhuis -NullArray -ODOWN -OOM -OR-ing -ORed -OSGEO:41001 -Ok -OpenBSD -OpenSSL -Opteron -ORM -PEL -PELs -PEM -PFAIL -PHPRedisMutex -PID -PMCs -PMU -POP3 -POSIX -POV -PRNG -PV -Parameterization -Pieter -Pipelining -Pool2 -Predis -Prev -Prioglio -Programm -Programmability -PubSub-related -Pubsub -Pubsub. -Pydantic -R1 -R2 -RC1 -RC3 -RC4 -RDB -RDB-saving -RedisInsight -REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD -REDISPORT -REPL -RESP2 -RESP2. -RESP3 -RESP3's -RESP3-typed -RESP3. -REdis -RHEL -RM_CreateCommand -RM_CreateStringFromString -RM_IsKeysPositionRequest -RM_KeyAtPosWithFlags -RM_SetCommandInfo -RM_.* -RPC -RSS -RTT -RU101 -RU102 -RU202 -RW -Rebranding -Reconfiguring -Reddit's -RediSearch -Redimension -Redis-rb -Redis-to-Lua -RedisCallReply -RedisConf -RedisHost. -RedisJSON -RedisModule.* -Redisson -Redistributions -Redlock -Redlock-cpp -Redlock-cs -Redlock-php -Redlock-py -Redlock-rb -Redlock4Net -Redsync -Reshard -Resharding -Resque -RetainString -Retwis -Retwis-J -Retwis-RB -Roshi -rpush -Rx/Tx -Rslock -S1 -S2 -S3 -S4 -SaaS -SCP -SDOWN -SHA-256 -SHA1 -SHA256 -SIGBUS -SIGFPE -SIGILL -SIGINT -SIGSEGV -SIGTERM -SSD -SSL -SVGs -SYNC_RDB_START -sadd -sadd_smembers -Sandboxed -Sanfilippo -Sanfilippo's -scard -ScarletLock -sdiff -Selectable -setnx_xx -Sharded -Shuttleworth -sinter -sismember -Slicehost -SmartOS -smismember -Snapchat -Snapcraft -Snapshotting -Solaris-derived -SomeOtherValue -Sonatype -SoundCloud -srem -StackOverflow -StringDMA -Subcommands -T1 -T2 -TCL -TCP -TLS -TLS-enabled -TTL -TTLs -Tthe -Twemproxy -UI -ULID -ULIds -ULIDs -URI -USD -UTF-8 -Unmodifiable -Unregister -Untrusted -Unwatches -VM -VMs -VMware -VPS -ValueN -Variadic -Virtualized -Vladev -WSL -WSL2 -Westmere -XMODEM -XSCAN -XYZ -Xen -Xen-specific -Xeon -YCSB -Yossi -Z1 -ZMODEM -ZPOP -ZSET -ZeroBrane -Zhao +ˈrɛd-ɪs +0s +0x00060007 +0x00MMmmpp +100k +100MB +10GB +10k +128MB +12k +1GB +1s +1th +2GB +300ms +30ms +32bit +32MB +3c3a0c +3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e +3GB +3MB +4GB +4k +500MB +512MB +5GB +60s +6sync +80ms +85MB +8MB +8ms +90s +97a3a64667477371c4479320d683e4c8db5858b1 +A1 acknowledgement +ACKs acl acl-pubsub-default +ACLs ad-hoc +Aioredlock +Alibaba alice allchannels allkeys @@ -484,32 +55,48 @@ allkeys-random allocator allocator's allocators +AMD64 analytics antirez antirez's +AOF aof +AOF_START aof-1 aof-2 aof-N +AOFRW api apiname +APIs appendfsync appendonly applicative args +ARGV argv argvs +Arity arity +ASN +Async async +Asyncio atomicity +Atomicvar +Auth auth authenticateClientWithUser -autoloading -Autoloading -autoload -autoloader auto-reconnection autocomplete +AUTOID +autoload +autoloader +autoloading +Autoloading +B1 +B2 +B3 backend backported backslashed @@ -519,50 +106,100 @@ balancer bazzar bc bcc +BCC's bcc's +BDFL-style beforeSleep behaviour benchmarked +Benchmarking benchmarking big-endian +BigNumber +bikes:racing:france +bikes:racing:italy +bikes:racing:usa +bikes:rentable +birthyear bitfield bitfield +Bitfields bitfields +BitOp bitop +Bitwise bitwise bitwise bool +BPF +BPF-optimized +BPF's breakpoint broadcasted +brpop bt btree1-az +C1 +C2 +C3 +C4 +C5 +CallReply cancelled cardinalities cardinality +CAS +CAs casted cd +CentOS +CFIELD +Changelog changelogs charset +Chemeris cheprasov +Citrusbyte cjson +CKQUORUM cleartext +CLI cli +CLI's +CloseKey cluster-config-file Cmd cmsgpack +Cn codename codenamed +Collina's commandstats commnad +Config config config-file configEpoch configs const +ContextFlags +Costin +CP cpu cpu-profiling +CPUs +Craigslist +CRC +CRC-16 +CRC16 +CRC64 +CRDTs +CRLF +CRLF-terminated cron cryptographic +CSV +Ctrl-a ctx daemonize daemonized @@ -570,14 +207,18 @@ daemontools dataset datastore dbid +DBs de de-serialization de-serialize deallocated dearmor +Deauthenticate deauthenticate deauthenticated +Deauthenticates deduplicated +Defrag defrag defragging defragment @@ -585,6 +226,7 @@ defragmentable defragmentation defragmented del +Deno deny-oom deserialize deserialized @@ -593,11 +235,27 @@ desync desynchronize dev dir +Diskless diskless +DistLock distlock +DLM +DMA +dnf +DNF +DNS +DSL dup-sentinel -eBPF +Dynomite earts +EBADF +eBPF +EBS +EC2 +EDOM +EEXIST +EFBIG +EINVAL ele emented enable-protected-configs @@ -610,20 +268,34 @@ end-slot2 end-slotN endian endianness +Enduro +ENOENT +ENOTSUP +Enum enum enum_val enum_vals enums +EOF +EP +EPEL epel-release epoll +EPSG:3785 +EPSG:900913 +ERANGE +Ergonom errno error1 error2 errorstats ethernet +Eval eval eval-intro +EventLoop eventloop +EventMachine everysec executables expiries @@ -631,7 +303,9 @@ explainer explainers facto factorializing +Failover failover +Failover-based failover-detected failover-end failover-end-for-timeout @@ -639,6 +313,7 @@ failover-state-reconf-slaves failover-state-select-slave failover-state-send-slaveof-noone failover. +Failovers failovers fanout faq @@ -650,45 +325,97 @@ firewalling first-arg first-args firstkey +FlameGraph +FLUSHCONFIG fmt foo0 foo1 foo2 formatter +FreeBSD +FreeString frequencyonly fsSL fsync +fsynced +Fsyncing fsyncing +fsyncs func +Gbit +GDB gdb geo +geo_tutorial +geoadd +GEODEL +Geohash geohash geohash-encoded +GeoHashes +Geohashes +geosearch +Geospatial geospatial +GET-MASTER-ADDR-BY-NAME getkeys-api +Github github globals +go-redis +Gottlieb +GPG gpg +Gradle +Hacktoberfest hacktoberfest handleClientsWithPendingWrites +Hardcoded hardcoded hardlinks +HashMap +HashMaps HashSet +HashSets +Haversine Healthcheck healthchecks +Hexastore hexastore +hget +hgetall +hincrby hiredis +Hitmeister +HLL +HLLs +HMAC-SHA256 +hmget holdApplicationUntilProxyStarts +Homebrew hostname hostnames +Hotspot hotspots +hset +HVM +HW +HyperLogLog hyperloglog +HyperLogLog. +HyperLogLogs +Hyperloglogs +hyperloglogs i8 iamonds IANA +Identinal idletime idx idx'-th +incr +incrby +incrby_get_mget indexable ing init @@ -700,51 +427,95 @@ internals-vm intsets invalidations iojob +IOPs iostat +IoT ip ip:port +IPC +IPs +IPv4 +IPv6 +IS-MASTER-DOWN-BY-ADDR Istio +Itamar iterable iteratively +ition +Janowski +Javadocs +JDK +Jedis jedis +JedisCluster jedisClusterNodes +JedisPool +JedisPooled +Jemalloc jemalloc +JKS jpeg +js +JSON +JSON-encoded kB keepalive -keyN keylen +keyN keyname keynum keynumidx keyrings +KEYSPACE +Keyspace keyspace keyspace-notifications +KeyspaceNotification keyspec keystep keytool +Kleppman's +Kleppmann knockknock kqueue +L3 last-failover-wins -lastVoteEpoch lastkey +lastVoteEpoch late-defrag latencies latencystats launchd lazyfree-lazy-user-flush +LDB ldb leaderboard +Leaderboards leaderboards +Leau +Lehmann len lenptr +Levelgraph lexicographically +LF +LFU +LHF libc +LibLZF libssl-dev +licensor +licensor's linenoise linkTitle +Linode little-endian +Liveness liveness +llen +LLOOGG +lmove_lrange +lmove_lrange ln LoadX509KeyPair localhost @@ -754,30 +525,58 @@ logics loglevel lookups loopback +lpop +lpop_rpop lpush +lpush_rpush +lrange +LRU lru_cache -lsb-release +LRU. +LRU's lsb_release +lsb-release +ltrim +ltrim_end_of_list +LUA +Lua lua-api +lua-debugging lua-replicate-commands +Lua-to-Redis +Lua's lubs +Lucraft +M1 +MacBook macOS macroscopically malloc +MASTERDOWN +Matteo matteocollina +Maxmemory maxmemory +Memcache memcached memset memtest86 memtier_benchmark +MERCHANTABILITY +MessagePack metatag +mget middleware miranda misconfiguration misconfigured -moduleType modules-api-ref +moduleType +Movablekeys movablekeys +Mrkris +mset +multisets mutex mylist mymaster @@ -785,55 +584,96 @@ myuser myzset namespace namespacing +NaN +NAS natively +NATted +Nehalem netcat newjobs +NFS +NIC +NICs nils no-appendfsync-on-rewrite +node-redis node-redlock +NodeJS noeviction +non-reachability non-TCP non-TLS -non-reachability non-virtualized nonprintable +NOOP +Noordhuis nopass +NoSQL notify-keyspace-events notifyKeyspaceEvent NRedisStack +NTP +NullArray +nullarray num-items +NUMA numactl numkeys -nullarray +NX nx observability +ODOWN odown +Ok ok oldval oneof onwards +OOM +OpenBSD +OpenSSL openssl +Opteron optionals +OR-ing +ORed +ORM +OSGEO:41001 overcommit p50 p999 Packagist pades pageview +Parameterization parameterization parametrize params parsable +PEL +PELs +PEM perf perf_events performance-on-cpu +PFAIL php-redis-lock +PHPRedisMutex +PID pid pidfile +Pieter pipelined +Pipelining pipelining pkcs12 +PMCs pmessage +PMU +Pool2 +POP3 +POSIX +POV ppa:redislabs pre-conditions pre-configured @@ -842,28 +682,46 @@ pre-imported pre-loaded pre-populated pre-sharding +Predis prepend Prepend preprocessing prerequesits +Prev prev printf printf-alike +Prioglio privdata +PRNG probabilistically proc +Programm +Programmability programmability programmatically programmatically-generated pseudorandom PSR-4 +Pubsub pubsub +PubSub-related +Pubsub. +PV +Pydantic qsort -quickstarts queueing +quickstarts +R1 +R2 radix rc +RC1 +RC3 +RC4 +RDB rdb-preamble +RDB-saving rdd rdd-1 rdd-2 @@ -878,12 +736,17 @@ realtime reauthenticate rebalance rebalancing +Rebranding reconfigurations reconfigures +Reconfiguring reconfiguring reconnection reconnections +Reddit's +Redimension redirections +REdis redis redis-benchmark redis-check-aof @@ -896,12 +759,35 @@ redis-macOS-demo redis-om-python redis-om-python. redis-py +Redis-rb redis-rb-cluster redis-server redis-stable +Redis-to-Lua +RedisCallReply +RedisConf +RediSearch +Redises +RedisHost. +RedisInsight +RedisJSON +REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD +RedisModule.* redisObjectVM +REDISPORT +Redisson +Redistributions +Redlock +Redlock-cpp +Redlock-cs +Redlock-php +Redlock-py +Redlock-rb +Redlock4Net +Redsync registerAPI reimplements +REPL repl-diskless-load repo representable @@ -913,53 +799,128 @@ rescanned reseek resends resetpass +Reshard reshard resharded +Resharding resharding reshardings +RESP2 +RESP2. +RESP3 +RESP3-typed +RESP3. +RESP3's +Resque resque resync resynchronization resynchronizations resyncs +RetainString retcode returing +Retwis +Retwis-J +Retwis-RB +RHEL +RM_.* +RM_CreateCommand +RM_CreateStringFromString +RM_IsKeysPositionRequest +RM_KeyAtPosWithFlags +RM_SetCommandInfo roadmap robj +Roshi roundtrips +RPC rpc-perf rpop +rpush +Rslock +RSS rss rtckit +RTT +RU101 +RU102 +RU202 runid runlevels +RW +Rx/Tx +S1 +S2 +S3 +S4 +SaaS +sadd +sadd_smembers +Sandboxed sandboxed +Sanfilippo +Sanfilippo's scalable +scard +ScarletLock +SCP +sdiff +SDOWN sdown sds se seeked +Selectable semantical serverCron +setnx_xx +SHA-256 +SHA1 +SHA256 +Sharded sharded sharding +Shuttleworth si sidekiq +SIGBUS +SIGFPE +SIGILL +SIGINT signle +SIGSEGV +SIGTERM +sinter +sismember slave-reconf-done slave-reconf-inprog slave-reconf-sent +Slicehost slot1 slowlog smaps +SmartOS +smismember +Snapchat +Snapcraft snapd +Snapshotting snapshotting +Solaris-derived somekey +SomeOtherValue +Sonatype +SoundCloud spectrogram spellchecker-cli spiped spo sponsorships +srem +SSD +SSL +StackOverflow start-slot1 start-slot2 start-slotN @@ -969,14 +930,16 @@ status2 stdin storepass strace +StringDMA struct -structs -struct's struct-encoded +struct's +structs stunnel subcommand -subcommand's subcommand. +subcommand's +Subcommands subcommands subevent subevents @@ -984,15 +947,23 @@ suboptimal subsequence substring sudo +SVGs swapdb swappability +SYNC_RDB_START syncd syscall systemctl +T1 +T2 taskset +TCL tcmalloc +TCP tcp the-redis-keyspace +TLS +TLS-enabled tls-port tmp tmux @@ -1002,9 +973,17 @@ tradeoff tradeoffs transactional try-failover +Tthe +TTL +TTLs tty tunable +Twemproxy typemethods_ptr +UI +ULID +ULIds +ULIDs un-authenticated un-gated unclaimable @@ -1016,47 +995,74 @@ unix unlink unlinked unlinks +Unmodifiable unmodifiable unpause unreachability +Unregister unregister unregisters +Untrusted untrusted untuned +Unwatches unwatches urandom +URI +USD used_memory_scripts_eval userSession usr +UTF-8 utf8 utils v9 value-ptr +ValueN +Variadic variadic venv virginia +Virtualized virtualized +Vladev +VM vm vm-max-memory -vmSwapOneObject +VMs vmstat +vmSwapOneObject +VMware volatile-lru volatile-ttl +VPS vtype +WAITAOF +Westmere wget wherefrom whitespace whitespaces whos-using-redis WRONGTYPE +WSL +WSL2 +Xen +Xen-specific +Xeon xff +XMODEM +XSCAN +XYZ xzvf +YCSB +Yossi +Z1 +ZeroBrane zeroed-ACLs +Zhao ziplists -zset -ˈrɛd-ɪs -fsynced -fsyncs -WAITAOF -Redises -ition +ZMODEM +ZPOP +ZSET +zset \ No newline at end of file From 93e1b6f135272c45340bf9d6699b80c88cf11526 Mon Sep 17 00:00:00 2001 From: Oran Agra Date: Tue, 15 Aug 2023 13:33:52 +0300 Subject: [PATCH 264/377] update command metadata and module API ref from 7.2.0 release (#2517) --- commands.json | 18 +++++----- docs/reference/modules/modules-api-ref.md | 40 +++++++++++------------ 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/commands.json b/commands.json index 1d4ef0df12..268c9bfd5c 100644 --- a/commands.json +++ b/commands.json @@ -2816,7 +2816,7 @@ "summary": "Lists the replica nodes of a master node.", "since": "5.0.0", "group": "cluster", - "complexity": "O(1)", + "complexity": "O(N) where N is the number of replicas.", "acl_categories": [ "@admin", "@slow", @@ -3016,7 +3016,7 @@ "summary": "Lists the replica nodes of a master node.", "since": "3.0.0", "group": "cluster", - "complexity": "O(1)", + "complexity": "O(N) where N is the number of replicas.", "deprecated_since": "5.0.0", "replaced_by": "`CLUSTER REPLICAS`", "acl_categories": [ @@ -5005,7 +5005,7 @@ "summary": "Returns the distance between two members of a geospatial index.", "since": "3.2.0", "group": "geo", - "complexity": "O(log(N))", + "complexity": "O(1)", "acl_categories": [ "@read", "@geo", @@ -5089,7 +5089,7 @@ "summary": "Returns members from a geospatial index as geohash strings.", "since": "3.2.0", "group": "geo", - "complexity": "O(log(N)) for each member requested, where N is the number of elements in the sorted set.", + "complexity": "O(1) for each member requested.", "acl_categories": [ "@read", "@geo", @@ -5139,7 +5139,7 @@ "summary": "Returns the longitude and latitude of members from a geospatial index.", "since": "3.2.0", "group": "geo", - "complexity": "O(N) where N is the number of members requested.", + "complexity": "O(1) for each member requested.", "acl_categories": [ "@read", "@geo", @@ -9677,10 +9677,6 @@ "command_flags": [ "write", "denyoom" - ], - "hints": [ - "request_policy:multi_shard", - "response_policy:agg_min" ] }, "MULTI": { @@ -10835,6 +10831,7 @@ ], "hints": [ "request_policy:all_shards", + "response_policy:special", "nondeterministic_output" ] }, @@ -11680,7 +11677,8 @@ ], "hints": [ "nondeterministic_output", - "request_policy:special" + "request_policy:special", + "response_policy:special" ] }, "SCARD": { diff --git a/docs/reference/modules/modules-api-ref.md b/docs/reference/modules/modules-api-ref.md index cea9ba6493..0471a18b8e 100644 --- a/docs/reference/modules/modules-api-ref.md +++ b/docs/reference/modules/modules-api-ref.md @@ -439,7 +439,7 @@ Returns `REDISMODULE_OK` on success and `REDISMODULE_ERR` in case of the followi int RedisModule_SetCommandACLCategories(RedisModuleCommand *command, const char *aclflags); -**Available since:** unreleased +**Available since:** 7.2.0 [`RedisModule_SetCommandACLCategories`](#RedisModule_SetCommandACLCategories) can be used to set ACL categories to module commands and subcommands. The set of ACL categories should be passed as @@ -805,7 +805,7 @@ Return counter of micro-seconds relative to an arbitrary point in time. ustime_t RedisModule_Microseconds(void); -**Available since:** unreleased +**Available since:** 7.2.0 Return the current UNIX time in microseconds @@ -815,7 +815,7 @@ Return the current UNIX time in microseconds ustime_t RedisModule_CachedMicroseconds(void); -**Available since:** unreleased +**Available since:** 7.2.0 Return the cached UNIX time in microseconds. It is updated in the server cron job and before executing a command. @@ -1422,7 +1422,7 @@ The function always returns `REDISMODULE_OK`. const char *fmt, ...); -**Available since:** unreleased +**Available since:** 7.2.0 Reply with the error create from a printf format and arguments. @@ -2233,7 +2233,7 @@ Extra flags that can be pass to the API under the mode argument: int RedisModule_GetOpenKeyModesAll(void); -**Available since:** unreleased +**Available since:** 7.2.0 Returns the full OpenKey modes mask, using the return value @@ -3565,7 +3565,7 @@ NULL if not required. RedisModuleOnUnblocked on_unblock, void *private_data); -**Available since:** unreleased +**Available since:** 7.2.0 Set unblock handler (callback and private data) on the given promise `RedisModuleCallReply`. The given reply must be of promise type (`REDISMODULE_REPLY_PROMISE`). @@ -3577,7 +3577,7 @@ The given reply must be of promise type (`REDISMODULE_REPLY_PROMISE`). int RedisModule_CallReplyPromiseAbort(RedisModuleCallReply *reply, void **private_data); -**Available since:** unreleased +**Available since:** 7.2.0 Abort the execution of a given promise `RedisModuleCallReply`. return `REDMODULE_OK` in case the abort was done successfully and `REDISMODULE_ERR` @@ -4432,7 +4432,7 @@ For a guide about blocking commands in modules, see void RedisModule_RegisterAuthCallback(RedisModuleCtx *ctx, RedisModuleAuthCallback cb); -**Available since:** unreleased +**Available since:** 7.2.0 This API registers a callback to execute in addition to normal password based authentication. Multiple callbacks can be registered across different modules. When a Module is unloaded, all the @@ -4544,7 +4544,7 @@ or multiple times within the blocking command background work. RedisModuleAuthCallback reply_callback, ; -**Available since:** unreleased +**Available since:** 7.2.0 Block the current client for module authentication in the background. If module auth is not in progress on the client, the API returns NULL. Otherwise, the client is blocked and the `RedisModule_BlockedClient` @@ -4557,7 +4557,7 @@ Note: Only use this API from the context of a module auth callback. void *RedisModule_BlockClientGetPrivateData(RedisModuleBlockedClient *blocked_client); -**Available since:** unreleased +**Available since:** 7.2.0 Get the private data that was previusely set on a blocked client @@ -4568,7 +4568,7 @@ Get the private data that was previusely set on a blocked client void RedisModule_BlockClientSetPrivateData(RedisModuleBlockedClient *blocked_client, void *private_data); -**Available since:** unreleased +**Available since:** 7.2.0 Set private data on a blocked client @@ -4648,7 +4648,7 @@ Note: Under normal circumstances [`RedisModule_UnblockClient`](#RedisModule_Unbl RedisModuleCmdFunc reply_callback, ; -**Available since:** unreleased +**Available since:** 7.2.0 Same as [`RedisModule_BlockClientOnKeys`](#RedisModule_BlockClientOnKeys), but can take `REDISMODULE_BLOCK_`* flags Can be either `REDISMODULE_BLOCK_UNBLOCK_DEFAULT`, which means default behavior (same @@ -4988,7 +4988,7 @@ See [https://redis.io/topics/notifications](https://redis.io/topics/notification void *privdata, void (*free_privdata)(void*)); -**Available since:** unreleased +**Available since:** 7.2.0 When running inside a key space notification callback, it is dangerous and highly discouraged to perform any write operation (See [`RedisModule_SubscribeToKeyspaceEvents`](#RedisModule_SubscribeToKeyspaceEvents)). In order to still perform write actions in this scenario, @@ -5562,7 +5562,7 @@ For more information about ACL log, please refer to [https://redis.io/commands/a RedisModuleString *object, RedisModuleACLLogEntryReason reason); -**Available since:** unreleased +**Available since:** 7.2.0 Adds a new entry in the ACL log with the `username` `RedisModuleString` provided. Returns `REDISMODULE_OK` on success and `REDISMODULE_ERR` on error. @@ -6490,7 +6490,7 @@ position. unsigned long long RedisModule_CommandFilterGetClientId(RedisModuleCommandFilterCtx *fctx); -**Available since:** unreleased +**Available since:** 7.2.0 Get Client ID for client that issued the command we are filtering @@ -7303,7 +7303,7 @@ or provided as startup arguments. RedisModuleRdbStream *RedisModule_RdbStreamCreateFromFile(const char *filename); -**Available since:** unreleased +**Available since:** 7.2.0 Create a stream object to save/load RDB to/from a file. @@ -7317,7 +7317,7 @@ the object. void RedisModule_RdbStreamFree(RedisModuleRdbStream *stream); -**Available since:** unreleased +**Available since:** 7.2.0 Release an RDB stream object. @@ -7329,7 +7329,7 @@ Release an RDB stream object. RedisModuleRdbStream *stream, int flags); -**Available since:** unreleased +**Available since:** 7.2.0 Load RDB file from the `stream`. Dataset will be cleared first and then RDB file will be loaded. @@ -7353,7 +7353,7 @@ Example: RedisModuleRdbStream *stream, int flags); -**Available since:** unreleased +**Available since:** 7.2.0 Save dataset to the RDB stream. @@ -7433,7 +7433,7 @@ returns `REDISMODULE_OK` if when key is valid. int RedisModule_GetModuleOptionsAll(void); -**Available since:** unreleased +**Available since:** 7.2.0 Returns the full module options flags mask, using the return value From 03ac2563d930a13dd65743f69ca42bf853a377b6 Mon Sep 17 00:00:00 2001 From: Binbin Date: Tue, 15 Aug 2023 20:32:21 +0800 Subject: [PATCH 265/377] Add 7.2 redis.conf link (#2518) --- docs/management/config.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/management/config.md b/docs/management/config.md index a971ae0bdc..4a834763be 100644 --- a/docs/management/config.md +++ b/docs/management/config.md @@ -39,6 +39,7 @@ The list of configuration directives, and their meaning and intended usage is available in the self documented example redis.conf shipped into the Redis distribution. +* The self documented [redis.conf for Redis 7.2](https://raw.githubusercontent.com/redis/redis/7.2/redis.conf). * The self documented [redis.conf for Redis 7.0](https://raw.githubusercontent.com/redis/redis/7.0/redis.conf). * The self documented [redis.conf for Redis 6.2](https://raw.githubusercontent.com/redis/redis/6.2/redis.conf). * The self documented [redis.conf for Redis 6.0](https://raw.githubusercontent.com/redis/redis/6.0/redis.conf). From 47e506c203cb876141d195429b45c01a52f62650 Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Tue, 15 Aug 2023 16:51:47 +0300 Subject: [PATCH 266/377] Adds RESP3 to protocol specification (#2120) --- docs/reference/protocol-spec.md | 701 +++++++++++++++++++++++--------- wordlist | 9 + 2 files changed, 524 insertions(+), 186 deletions(-) diff --git a/docs/reference/protocol-spec.md b/docs/reference/protocol-spec.md index 732e81b01a..bbb9f331cc 100644 --- a/docs/reference/protocol-spec.md +++ b/docs/reference/protocol-spec.md @@ -1,214 +1,274 @@ --- -title: "RESP protocol spec" +title: "Redis serialization protocol specification" linkTitle: "Protocol spec" weight: 4 -description: Redis serialization protocol (RESP) specification +description: Redis serialization protocol (RESP) is the wire protocol that clients implement aliases: - /topics/protocol --- -Redis clients use a protocol called **RESP** (REdis Serialization Protocol) to communicate with the Redis server. While the protocol was designed specifically for Redis, it can be used for other client-server software projects. +To communicate with the Redis server, Redis clients use a protocol called REdis Serialization Protocol (RESP). +While the protocol was designed specifically for Redis, you can use it for other client-server software projects. -RESP is a compromise between the following things: +RESP is a compromise among the following considerations: * Simple to implement. * Fast to parse. * Human readable. -RESP can serialize different data types like integers, strings, and arrays. There is also a specific type for errors. Requests are sent from the client to the Redis server as arrays of strings that represent the arguments of the command to execute. Redis replies with a command-specific data type. +RESP can serialize different data types including integers, strings, and arrays. +It also features an error-specific type. +A client sends a request to the Redis server as an array of strings. +The array's contents are the command and its arguments that the server should execute. +The server's reply type is command-specific. -RESP is binary-safe and does not require processing of bulk data transferred from one process to another because it uses prefixed-length to transfer bulk data. +RESP is binary-safe and uses prefixed length to transfer bulk data so it does not require processing bulk data transferred from one process to another. -Note: the protocol outlined here is only used for client-server communication. Redis Cluster uses a different binary protocol in order to exchange messages between nodes. +RESP is the protocol you should implement in your Redis client. -## Network layer +{{% alert title="Note" color="info" %}} +The protocol outlined here is used only for client-server communication. +[Redis Cluster](/docs/reference/cluster-spec) uses a different binary protocol for exchanging messages between nodes. +{{% /alert %}} -A client connects to a Redis server by creating a TCP connection to the port 6379. +## RESP versions +Support for the first version of the RESP protocol was introduced in Redis 1.2. +Using RESP with Redis 1.2 was optional and had mainly served the purpose of working the kinks out of the protocol. -While RESP is technically non-TCP specific, the protocol is only used with TCP connections (or equivalent stream-oriented connections like Unix sockets) in the context of Redis. +In Redis 2.0, the protocol's next version, a.k.a RESP2, became the standard communication method for clients with the Redis server. -## Request-Response model +[RESP3](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md) is a superset of RESP2 that mainly aims to make a client author's life a little bit easier. +Redis 6.0 introduced experimental opt-in support of RESP3's features (excluding streaming strings and streaming aggregates). +In addition, the introduction of the `HELLO` command allows clients to handshake and upgrade the connection's protocol version (see [Client handshake](#client-handshake)). -Redis accepts commands composed of different arguments. -Once a command is received, it is processed and a reply is sent back to the client. +Up to and including Redis 7, both RESP2 and RESP3 clients can invoke all core commands. +However, commands may return differently typed replies for different protocol versions. -This is the simplest model possible; however, there are two exceptions: +Future versions of Redis may change the default protocol version, but it is unlikely that RESP2 will become entirely deprecated. +It is possible, however, that new features in upcoming versions will require the use of RESP3. + +## Network layer +A client connects to a Redis server by creating a TCP connection to its port (the default is 6379). -* Redis supports pipelining (covered later in this document). So it is possible for clients to send multiple commands at once and wait for replies later. -* When a Redis client subscribes to a Pub/Sub channel, the protocol changes semantics and becomes a *push* protocol. The client no longer requires sending commands because the server will automatically send new messages to the client (for the channels the client is subscribed to) as soon as they are received. +While RESP is technically non-TCP specific, the protocol is used exclusively with TCP connections (or equivalent stream-oriented connections like Unix sockets) in the context of Redis. -Excluding these two exceptions, the Redis protocol is a simple request-response protocol. +## Request-Response model +The Redis server accepts commands composed of different arguments. +Then, the server processes the command and sends the reply back to the client. + +This is the simplest model possible; however, there are some exceptions: + +* Redis requests can be [pipelined](#multiple-commands-and-pipelining). + Pipelining enables clients to send multiple commands at once and wait for replies later. +* When a RESP2 connection subscribes to a [Pub/Sub](/docs/manual/pubsub) channel, the protocol changes semantics and becomes a *push* protocol. + The client no longer requires sending commands because the server will automatically send new messages to the client (for the channels the client is subscribed to) as soon as they are received. +* The `MONITOR` command. + Invoking the `MONITOR` command switches the connection to an ad-hoc push mode. + The protocol of this mode is not specified but is obvious to parse. +* [Protected mode](/docs/management/security/#protected-mode). + Connections opened from a non-loopback address to a Redis while in protected mode are denied and terminated by the server. + Before terminating the connection, Redis unconditionally sends `-DENIED` reply, irregardless of whether the client writes to the socket. +* The [RESP3 Push type](#resp3-pushes). + As the name suggests, a push type allows the server to send out-of-band data to the connection. + The server may push data at any time, and the data isn't necessarily related to specific commands executed by the client. + +Excluding these exceptions, the Redis protocol is a simple request-response protocol. ## RESP protocol description +RESP is essentially a serialization protocol that supports several data types. +In RESP, the first byte of data determines its type. -The RESP protocol was introduced in Redis 1.2, but it became the -standard way for talking with the Redis server in Redis 2.0. -This is the protocol you should implement in your Redis client. +Redis generally uses RESP as a [request-response](#request-response-model) protocol in the following way: -RESP is actually a serialization protocol that supports the following -data types: Simple Strings, Errors, Integers, Bulk Strings, and Arrays. +* Clients send commands to a Redis server as an [array](#arrays) of [bulk strings](#bulk-strings). + The first (and sometimes also the second) bulk string in the array is the command's name. + Subsequent elements of the array are the arguments for the command. +* The server replies with a RESP type. + The reply's type is determined by the command's implementation and possibly by the client's protocol version. -Redis uses RESP as a request-response protocol in the -following way: +RESP is a binary protocol that uses control sequences encoded in standard ASCII. +The `A` character, for example, is encoded with the binary byte of value 65. +Similarly, the characters CR (`\r`), LF (`\n`) and SP (` `) have binary byte values of 13, 10 and 32, respectively. -* Clients send commands to a Redis server as a RESP Array of Bulk Strings. -* The server replies with one of the RESP types according to the command implementation. +The `\r\n` (CRLF) is the protocol's _terminator_, which **always** separates its parts. -In RESP, the first byte determines the data type: +The first byte in an RESP-serialized payload always identifies its type. +Subsequent bytes constitute the type's contents. -* For **Simple Strings**, the first byte of the reply is "+" -* For **Errors**, the first byte of the reply is "-" -* For **Integers**, the first byte of the reply is ":" -* For **Bulk Strings**, the first byte of the reply is "$" -* For **Arrays**, the first byte of the reply is "`*`" +We categorize every RESP data type as either _simple_, _bulk_ or _aggregate_. -RESP can represent a Null value using a special variation of Bulk Strings or Array as specified later. +Simple types are similar to scalars in programming languages that represent plain literal values. Booleans and Integers are such examples. -In RESP, different parts of the protocol are always terminated with "\r\n" (CRLF). +RESP strings are either _simple_ or _bulk_. +Simple strings never contain carriage return (`\r`) or line feed (`\n`) characters. +Bulk strings can contain any binary data and may also be referred to as _binary_ or _blob_. +Note that bulk strings may be further encoded and decoded, e.g. with a wide multi-byte encoding, by the client. - +Aggregates, such as Arrays and Maps, can have varying numbers of sub-elements and nesting levels. -## RESP Simple Strings +The following table summarizes the RESP data types that Redis supports: -Simple Strings are encoded as follows: a plus character, followed by a string that cannot contain a CR or LF character (no newlines are allowed), and terminated by CRLF (that is "\r\n"). +| RESP data type | Minimal protocol version | Category | First byte | +| --- | --- | --- | --- | +| [Simple strings](#simple-strings) | RESP2 | Simple | `+` | +| [Simple Errors](#simple-errors) | RESP2 | Simple | `-` | +| [Integers](#integers) | RESP2 | Simple | `:` | +| [Bulk strings](#bulk-strings) | RESP2 | Aggregate | `$` | +| [Arrays](#arrays) | RESP2 | Aggregate | `*` | +| [Nulls](#nulls) | RESP3 | Simple | `_` | +| [Booleans](#booleans) | RESP3 | Simple | `#` | +| [Doubles](#doubles) | RESP3 | Simple | `,` | +| [Big numbers](#big-numbers) | RESP3 | Simple | `(` | +| [Bulk errors](#bulk-errors) | RESP3 | Aggregate | `!` | +| [Verbatim strings](#verbatim-strings) | RESP3 | Aggregate | `=` | +| [Maps](#maps) | RESP3 | Aggregate | `%` | +| [Sets](#sets) | RESP3 | Aggregate | `~` | +| [Pushes](#pushes) | RESP3 | Aggregate | `>` | -Simple Strings are used to transmit non binary-safe strings with minimal overhead. For example, many Redis commands reply with just "OK" on success. The RESP Simple String is encoded with the following 5 bytes: + - "+OK\r\n" +### Simple strings +Simple strings are encoded as a plus (`+`) character, followed by a string. +The string mustn't contain a CR (`\r`) or LF (`\n`) character and is terminated by CRLF (i.e., `\r\n`). -In order to send binary-safe strings, use RESP Bulk Strings instead. +Simple strings transmit short, non-binary strings with minimal overhead. +For example, many Redis commands reply with just "OK" on success. +The encoding of this Simple String is the following 5 bytes: -When Redis replies with a Simple String, a client library should respond with a string composed of the first character after the '+' -up to the end of the string, excluding the final CRLF bytes. + +OK\r\n - +When Redis replies with a simple string, a client library should return to the caller a string value composed of the first character after the `+` up to the end of the string, excluding the final CRLF bytes. -## RESP Errors +To send binary strings, use [bulk strings](#bulk-strings) instead. -RESP has a specific data type for errors. They are similar to -RESP Simple Strings, but the first character is a minus '-' character instead -of a plus. The real difference between Simple Strings and Errors in RESP is that clients treat errors -as exceptions, and the string that composes -the Error type is the error message itself. + + +### Simple errors +RESP has specific data types for errors. +Simple errors, or simply just errors, are similar to [simple strings](#simple-strings), but their first character is the minus (`-`) character. +The difference between simple strings and errors in RESP is that clients should treat errors as exceptions, whereas the string encoded in the error type is the error message itself. The basic format is: - "-Error message\r\n" + -Error message\r\n -Error replies are only sent when something goes wrong, for instance if -you try to perform an operation against the wrong data type, or if the command -does not exist. The client should raise an exception when it receives an Error reply. +Redis replies with an error only when something goes wrong, for example, when you try to operate against the wrong data type, or when the command does not exist. +The client should raise an exception when it receives an Error reply. The following are examples of error replies: - -ERR unknown command 'helloworld' + -ERR unknown command 'asdf' -WRONGTYPE Operation against a key holding the wrong kind of value -The first word after the "-", up to the first space or newline, represents -the kind of error returned. This is just a convention used by Redis and is not -part of the RESP Error format. +The first upper-case word after the `-`, up to the first space or newline, represents the kind of error returned. +This word is called an _error prefix_. +Note that the error prefix is a convention used by Redis rather than part of the RESP error type. -For example, `ERR` is the generic error, while `WRONGTYPE` is a more specific -error that implies that the client tried to perform an operation against the -wrong data type. This is called an **Error Prefix** and is a way to allow -the client to understand the kind of error returned by the server without checking the exact error message. +For example, in Redis, `ERR` is a generic error, whereas `WRONGTYPE` is a more specific error that implies that the client attempted an operation against the wrong data type. +The error prefix allows the client to understand the type of error returned by the server without checking the exact error message. -A client implementation may return different types of exceptions for different -errors or provide a generic way to trap errors by directly providing -the error name to the caller as a string. +A client implementation can return different types of exceptions for various errors, or provide a generic way for trapping errors by directly providing the error name to the caller as a string. -However, such a feature should not be considered vital as it is rarely useful, and a limited client implementation may simply return a generic error condition, such as `false`. +However, such a feature should not be considered vital as it is rarely useful. +Also, simpler client implementations can return a generic error value, such as `false`. -## RESP Integers +### Integers +This type is a CRLF-terminated string that represents a signed, base-10, 64-bit integer. -This type is just a CRLF-terminated string that represents an integer, -prefixed by a ":" byte. For example, ":0\r\n" and ":1000\r\n" are integer replies. +RESP encodes integers in the following way: -Many Redis commands return RESP Integers, like `INCR`, `LLEN`, and `LASTSAVE`. + :[<+|->]\r\n -There is no special meaning for the returned integer. It is just an -incremental number for `INCR`, a UNIX time for `LASTSAVE`, and so forth. However, -the returned integer is guaranteed to be in the range of a signed 64-bit integer. +* The colon (`:`) as the first byte. +* An optional plus (`+`) or minus (`-`) as the sign. +* One or more decimal digits (`0`..`9`) as the integer's unsigned, base-10 value. +* The CRLF terminator. -Integer replies are also used in order to return true or false. -For instance, commands like `EXISTS` or `SISMEMBER` will return 1 for true -and 0 for false. +For example, `:0\r\n` and `:1000\r\n` are integer replies (of zero and one thousand, respectively). -Other commands like `SADD`, `SREM`, and `SETNX` will return 1 if the operation -was actually performed and 0 otherwise. +Many Redis commands return RESP integers, including `INCR`, `LLEN`, and `LASTSAVE`. +An integer, by itself, has no special meaning other than in the context of the command that returned it. +For example, it is an incremental number for `INCR`, a UNIX timestamp for `LASTSAVE`, and so forth. +However, the returned integer is guaranteed to be in the range of a signed 64-bit integer. -The following commands will reply with an integer: `SETNX`, `DEL`, -`EXISTS`, `INCR`, `INCRBY`, `DECR`, `DECRBY`, `DBSIZE`, `LASTSAVE`, -`RENAMENX`, `MOVE`, `LLEN`, `SADD`, `SREM`, `SISMEMBER`, `SCARD`. +In some cases, integers can represent true and false Boolean values. +For instance, `SISMEMBER` returns 1 for true and 0 for false. + +Other commands, including `SADD`, `SREM`, and `SETNX`, return 1 when the data changes and 0 otherwise. - -## RESP Bulk Strings +### Bulk strings +A bulk string represents a single binary string. +The string can be of any size, but by default, Redis limits it to 512 MB (see the `proto-max-bulk-len` configuration directive). -Bulk Strings are used in order to represent a single binary-safe -string up to 512 MB in length. +RESP encodes bulk strings in the following way: -Bulk Strings are encoded in the following way: + $\r\n\r\n -* A "$" byte followed by the number of bytes composing the string (a prefixed length), terminated by CRLF. -* The actual string data. +* The dollar sign (`$`) as the first byte. +* One or more decimal digits (`0`..`9`) as the string's length, in bytes, as an unsigned, base-10 value. +* The CRLF terminator. +* The data. * A final CRLF. So the string "hello" is encoded as follows: - "$5\r\nhello\r\n" + $5\r\nhello\r\n -An empty string is encoded as: +The empty string's encoding is: - "$0\r\n\r\n" + $0\r\n\r\n -RESP Bulk Strings can also be used in order to signal non-existence of a value -using a special format to represent a Null value. In this -format, the length is -1, and there is no data. Null is represented as: + + +#### Null bulk strings +Whereas RESP3 has a dedicated data type for [null values](#nulls), RESP2 has no such type. +Instead, due to historical reasons, the representation of null values in RESP2 is via predetermined forms of the [bulk strings](#bulk-strings) and [arrays](#arrays) types. - "$-1\r\n" +The null bulk string represents a non-existing value. +The `GET` command returns the Null Bulk String when the target key doesn't exist. -This is called a **Null Bulk String**. +It is encoded as a bulk string with the length of negative one (-1), like so: + + $-1\r\n -The client library API should not return an empty string, but a nil object, -when the server replies with a Null Bulk String. -For example, a Ruby library should return 'nil' while a C library should -return NULL (or set a special flag in the reply object). +A Redis client should return a nil object when the server replies with a null bulk string rather than the empty string. +For example, a Ruby library should return `nil` while a C library should return `NULL` (or set a special flag in the reply object). -## RESP Arrays +### Arrays +Clients send commands to the Redis server as RESP arrays. +Similarly, some Redis commands that return collections of elements use arrays as their replies. +An example is the `LRANGE` command that returns elements of a list. -Clients send commands to the Redis server using RESP Arrays. Similarly, -certain Redis commands, that return collections of elements to the client, -use RESP Arrays as their replies. An example is the `LRANGE` command that -returns elements of a list. +RESP Arrays' encoding uses the following format: -RESP Arrays are sent using the following format: + *\r\n... -* A `*` character as the first byte, followed by the number of elements in the array as a decimal number, followed by CRLF. -* An additional RESP type for every element of the Array. +* An asterisk (`*`) as the first byte. +* One or more decimal digits (`0`..`9`) as the number of elements in the array as an unsigned, base-10 value. +* The CRLF terminator. +* An additional RESP type for every element of the array. So an empty Array is just the following: - "*0\r\n" + *0\r\n -While an array of two RESP Bulk Strings "hello" and "world" is encoded as: +Whereas the encoding of an array consisting of the two bulk strings "hello" and "world" is: - "*2\r\n$5\r\nhello\r\n$5\r\nworld\r\n" + *2\r\n$5\r\nhello\r\n$5\r\nworld\r\n -As you can see after the `*CRLF` part prefixing the array, the other -data types composing the array are just concatenated one after the other. +As you can see, after the `*CRLF` part prefixing the array, the other data types that compose the array are concatenated one after the other. For example, an Array of three integers is encoded as follows: - "*3\r\n:1\r\n:2\r\n:3\r\n" + *3\r\n:1\r\n:2\r\n:3\r\n -Arrays can contain mixed types, so it's not necessary for the -elements to be of the same type. For instance, a list of four -integers and a bulk string can be encoded as follows: +Arrays can contain mixed data types. +For instance, the following encoding is of a list of four integers and a bulk string: *5\r\n :1\r\n @@ -218,28 +278,14 @@ integers and a bulk string can be encoded as follows: $5\r\n hello\r\n -(The reply was split into multiple lines for clarity). +(The raw RESP encoding is split into multiple lines for readability). -The first line the server sent is `*5\r\n` in order to specify that five -replies will follow. Then every reply constituting the items of the -Multi Bulk reply are transmitted. +The first line the server sent is `*5\r\n`. +This numeric value tells the client that five reply types are about to follow it. +Then, every successive reply constitutes an element in the array. -Null Arrays exist as well and are an alternative way to -specify a Null value (usually the Null Bulk String is used, but for historical -reasons we have two formats). - -For instance, when the `BLPOP` command times out, it returns a Null Array -that has a count of `-1` as in the following example: - - "*-1\r\n" - -A client library API should return a null object and not an empty Array when -Redis replies with a Null Array. This is necessary to distinguish -between an empty list and a different condition (for instance the timeout -condition of the `BLPOP` command). - -Nested arrays are possible in RESP. For example a nested array of two arrays -is encoded as follows: +All of the aggregate RESP types support nesting. +For example, a nested array of two arrays is encoded as follows: *2\r\n *3\r\n @@ -250,16 +296,38 @@ is encoded as follows: +Hello\r\n -World\r\n -(The format was split into multiple lines to make it easier to read). +(The raw RESP encoding is split into multiple lines for readability). + +The above encodes a two-elements array. +The first element is an array that, in turn, contains three integers (1, 2, 3). +The second element is another array containing a simple string and an error. + +{{% alert title="Multi bulk reply" color="info" %}} +In some places, the RESP Array type may be referred to as _multi bulk_. +The two are the same. +{{% /alert %}} + + + +#### Null arrays +Whereas RESP3 has a dedicated data type for [null values](#nulls), RESP2 has no such type. Instead, due to historical reasons, the representation of null values in RESP2 is via predetermined forms of the [Bulk Strings](#bulk-strings) and [arrays](#arrays) types. -The above RESP data type encodes a two-element Array consisting of an Array that contains three Integers (1, 2, 3) and an array of a Simple String and an Error. +Null arrays exist as an alternative way of representing a null value. +For instance, when the `BLPOP` command times out, it returns a null array. -## Null elements in Arrays +The encoding of a null array is that of an array with the length of -1, i.e.: -Single elements of an Array may be Null. This is used in Redis replies to signal that these elements are missing and not empty strings. This -can happen with the SORT command when used with the GET _pattern_ option -if the specified key is missing. Example of an Array reply containing a -Null element: + *-1\r\n + +When Redis replies with a null array, the client should return a null object rather than an empty array. +This is necessary to distinguish between an empty list and a different condition (for instance, the timeout condition of the `BLPOP` command). + +#### Null elements in arrays +Single elements of an array may be [null bulk string](#null-bulk-strings). +This is used in Redis replies to signal that these elements are missing and not empty strings. This can happen, for example, with the `SORT` command when used with the `GET pattern` option +if the specified key is missing. + +Here's an example of an array reply containing a null element: *3\r\n $5\r\n @@ -268,25 +336,287 @@ Null element: $5\r\n world\r\n -The second element is a Null. The client library should return something -like this: +Above, the second element is null. +The client library should return to its caller something like this: ["hello",nil,"world"] -Note that this is not an exception to what was said in the previous sections, but -an example to further specify the protocol. + + +### Nulls +The null data type represents non-existent values. + +Nulls' encoding is the underscore (`_`) character, followed by the CRLF terminator (`\r\n`). +Here's Null's raw RESP encoding: + + _\r\n + +{{% alert title="Null Bulk String, Null Arrays and Nulls" color="info" %}} +Due to historical reasons, RESP2 features two specially crafted values for representing null values of bulk strings and arrays. +This duality has always been a redundancy that added zero semantical value to the protocol itself. + +The null type, introduced in RESP3, aims to fix this wrong. +{{% /alert %}}}} + + + +### Booleans +RESP booleans are encoded as follows: + + #\r\n + +* The octothorpe character (`#`) as the first byte. +* A `t` character for true values, or an `f` character for false ones. +* The CRLF terminator. + + + +### Doubles +The Double RESP type encodes a double-precision floating point value. +Doubles are encoded as follows: + + ,[<+|->][.][[sign]]\r\n + +* The comma character (`,`) as the first byte. +* An optional plus (`+`) or minus (`-`) as the sign. +* One or more decimal digits (`0`..`9`) as an unsigned, base-10 integral value. +* An optional dot (`.`), followed by one or more decimal digits (`0`..`9`) as an unsigned, base-10 fractional value. +* An optional capital or lowercase letter E (`E` or `e`), followed by an optional plus (`+`) or minus (`-`) as the exponent's sign, ending with one or more decimal digits (`0`..`9`) as an unsigned, base-10 exponent value. +* The CRLF terminator. + +Here's the encoding of the number 1.23: + + ,1.23\r\n + +Because the fractional part is optional, the integer value of ten (10) can, therefore, be RESP-encoded both as an integer as well as a double: + + :10\r\n + ,10\r\n + +In such cases, the Redis client should return native integer and double values, respectively, providing that these types are supported by the language of its implementation. + +The positive infinity, negative infinity and NaN values are encoded as follows: + + ,inf\r\n + ,-inf\r\n + ,nan\r\n + + + +### Big numbers +This type can encode integer values outside the range of signed 64-bit integers. + +Big numbers use the following encoding: + + ([+|-]\r\n + +* The left parenthesis character (`(`) as the first byte. +* An optional plus (`+`) or minus (`-`) as the sign. +* One or more decimal digits (`0`..`9`) as an unsigned, base-10 value. +* The CRLF terminator. + +Example: + + (3492890328409238509324850943850943825024385\r\n + +Big numbers can be positive or negative but can't include fractionals. +Client libraries written in languages with a big number type should return a big number. +When big numbers aren't supported, the client should return a string and, when possible, signal to the caller that the reply is a big integer (depending on the API used by the client library). + + + +### Bulk errors +This type combines the purpose of [simple errors](#simple-errors) with the expressive power of [bulk strings](#bulk-strings). + +It is encoded as: + + !\r\n\r\n + +* An exclamation mark (`!`) as the first byte. +* One or more decimal digits (`0`..`9`) as the error's length, in bytes, as an unsigned, base-10 value. +* The CRLF terminator. +* The error itself. +* A final CRLF. + +As a convention, the error begins with an uppercase (space-delimited) word that conveys the error message. + +For instance, the error "SYNTAX invalid syntax" is represented by the following protocol encoding: -## Send commands to a Redis server + !21\r\n + SYNTAX invalid syntax\r\n -Now that you are familiar with the RESP serialization format, you can use it to help write a Redis client library. We can further specify -how the interaction between the client and the server works: +(The raw RESP encoding is split into multiple lines for readability). -* A client sends the Redis server a RESP Array consisting of only Bulk Strings. + + +### Verbatim strings +This type is similar to the [bulk string](#bulk-strings), with the addition of providing a hint about the data's encoding. + +A verbatim string's RESP encoding is as follows: + + =\r\n:\r\n + +* An equal sign (`=`) as the first byte. +* One or more decimal digits (`0`..`9`) as the string's total length, in bytes, as an unsigned, base-10 value. +* The CRLF terminator. +* Exactly three (3) bytes represent the data's encoding. +* The colon (`:`) character separates the encoding and data. +* The data. +* A final CRLF. + +Example: + + =15\r\n + txt:Some string\r\n + +(The raw RESP encoding is split into multiple lines for readability). + +Some client libraries may ignore the difference between this type and the string type and return a native string in both cases. +However, interactive clients, such as command line interfaces (e.g., [`redis-cli`](/docs/manual/cli)), can use this type and know that their output should be presented to the human user as is and without quoting the string. + +For example, the Redis command `INFO` outputs a report that includes newlines. +When using RESP3, `redis-cli` displays it correctly because it is sent as a Verbatim String reply (with its three bytes being "txt"). +When using RESP2, however, the `redis-cli` is hard-coded to look for the `INFO` command to ensure its correct display to the user. + + + +### Maps +The RESP map encodes a collection of key-value tuples, i.e., a dictionary or a hash. + +It is encoded as follows: + + %\r\n... + +* A percent character (`%`) as the first byte. +* One or more decimal digits (`0`..`9`) as the number of entries, or key-value tuples, in the map as an unsigned, base-10 value. +* The CRLF terminator. +* Two additional RESP types for every key and value in the map. + +For example, the following JSON object: + + { + "first": 1, + "second": 2 + } + +Can be encoded in RESP like so: + + %2\r\n + +first\r\n + :1\r\n + +second\r\n + :2\r\n + +(The raw RESP encoding is split into multiple lines for readability). + +Both map keys and values can be any of RESP's types. + +Redis clients should return the idiomatic dictionary type that their language provides. +However, low-level programming languages (such as C, for example) will likely return an array along with type information that indicates to the caller that it is a dictionary. + +{{% alert title="Map pattern in RESP2" color="info" %}} +RESP2 doesn't have a map type. +Maps in RESP2 are represented by arrays, in which each element is a key-value tuple. +Each tuple is an array with two elements, these being the key and the value. +{{% /alert %}} + + + +### Sets +Sets are somewhat like [Arrays](#arrays) but are unordered and should only contain unique elements. + +RESP set's encoding is: + + ~\r\n... + +* A tilde (`~`) as the first byte. +* One or more decimal digits (`0`..`9`) as the number of elements in the set as an unsigned, base-10 value. +* The CRLF terminator. +* An additional RESP type for every element of the Set. + +Clients should return the native set type if it is available in their programming language. +Alternatively, in the absence of a native set type, an array coupled with type information can be used (in C, for example). + + + +### Pushes +RESP's pushes contain out-of-band data. +They are an exception to the protocol's request-response model and provide a generic _push mode_ for connections. + +Push events are encoded similarly to [arrays](#arrays), differing only in their first byte: + + >\r\n... + +* A greater-than sign (`>`) as the first byte. +* One or more decimal digits (`0`..`9`) as the number of elements in the message as an unsigned, base-10 value. +* The CRLF terminator. +* An additional RESP type for every element of the push event. + +Pushed data may precede or follow any of RESP's data types but never inside them. +That means a client won't find push data in the middle of a map reply, for example. +It also means that pushed data may appear before or after a command's reply, as well as by itself (without calling any command). + +Clients should react to pushes by invoking a callback that implements their handling of the pushed data. + +## Client handshake +New RESP connections should begin the session by calling the `HELLO` command. +This practice accomplishes two things: + +1. It allows servers to be backward compatible with RESP2 versions. + This is needed in Redis to make the transition to version 3 of the protocol gentler. +2. The `HELLO` command returns information about the server and the protocol that the client can use for different goals. + +The `HELLO` command has the following high-level syntax: + + HELLO [optional-arguments] + +The first argument of the command is the protocol version we want the connection to be set. +By default, the connection starts in RESP2 mode. +If we specify a connection version that is too big and unsupported by the server, it should reply with a `-NOPROTO` error. Example: + + Client: HELLO 4 + Server: -NOPROTO sorry, this protocol version is not supported. + +At that point, the client may retry with a lower protocol version. + +Similarly, the client can easily detect a server that is only able to speak RESP2: + + Client: HELLO 3 + Server: -ERR unknown command 'HELLO' + +The client can then proceed and use RESP2 to communicate with the server. + +Note that even if the protocol's version is supported, the `HELLO` command may return an error, perform no action and remain in RESP2 mode. +For example, when used with invalid authentication credentials in the command's optional `!AUTH` clause: + + Client: HELLO 3 AUTH default mypassword + Server: -ERR invalid password + (the connection remains in RESP2 mode) + +A successful reply to the `HELLO` command is a map reply. +The information in the reply is partly server-dependent, but certain fields are mandatory for all the RESP3 implementations: +* **server**: "redis" (or other software name). +* **version**: the server's version. +* **proto**: the highest supported version of the RESP protocol. + +In Redis' RESP3 implementation, the following fields are also emitted: + +* **id**: the connection's identifier (ID). +* **mode**: "standalone", "sentinel" or "cluster". +* **role**: "master" or "replica". +* **modules**: list of loaded modules as an Array of Bulk Strings. + +## Sending commands to a Redis server +Now that you are familiar with the RESP serialization format, you can use it to help write a Redis client library. +We can further specify how the interaction between the client and the server works: + +* A client sends the Redis server an [array](#arrays) consisting of only bulk strings. * A Redis server replies to clients, sending any valid RESP data type as a reply. -So for example a typical interaction could be the following. +So, for example, a typical interaction could be the following. -The client sends the command **LLEN mylist** in order to get the length of the list stored at key *mylist*. Then the server replies with an Integer reply as in the following example (C: is the client, S: the server). +The client sends the command `LLEN mylist` to get the length of the list stored at the key _mylist_. +Then the server replies with an [integer](#integers) reply as in the following example (`C:` is the client, `S:` the server). C: *2\r\n C: $4\r\n @@ -299,51 +629,44 @@ The client sends the command **LLEN mylist** in order to get the length of the l As usual, we separate different parts of the protocol with newlines for simplicity, but the actual interaction is the client sending `*2\r\n$4\r\nLLEN\r\n$6\r\nmylist\r\n` as a whole. ## Multiple commands and pipelining - -A client can use the same connection in order to issue multiple commands. -Pipelining is supported so multiple commands can be sent with a single -write operation by the client, without the need to read the server reply -of the previous command before issuing the next one. +A client can use the same connection to issue multiple commands. +Pipelining is supported, so multiple commands can be sent with a single write operation by the client. +The client can skip reading replies and continue to send the commands one after the other. All the replies can be read at the end. For more information, see [Pipelining](/topics/pipelining). ## Inline commands +Sometimes you may need to send a command to the Redis server but only have `telnet` available. +While the Redis protocol is simple to implement, it is not ideal for interactive sessions, and `redis-cli` may not always be available. +For this reason, Redis also accepts commands in the _inline command_ format. -Sometimes you may need to send a command -to the Redis server but only have `telnet` available. While the Redis protocol is simple to implement, it is -not ideal to use in interactive sessions, and `redis-cli` may not always be -available. For this reason, Redis also accepts commands in the **inline command** format. - -The following is an example of a server/client chat using an inline command -(the server chat starts with S:, the client chat with C:) +The following example demonstrates a server/client exchange using an inline command (the server chat starts with `S:`, the client chat with `C:`): C: PING S: +PONG -The following is an example of an inline command that returns an integer: +Here's another example of an inline command where the server returns an integer: C: EXISTS somekey S: :0 -Basically, you write space-separated arguments in a telnet session. -Since no command starts with `*` that is instead used in the unified request -protocol, Redis is able to detect this condition and parse your command. +Basically, to issue an inline command, you write space-separated arguments in a telnet session. +Since no command starts with `*` (the identifying byte of RESP Arrays), Redis detects this condition and parses your command inline. -## High performance parser for the Redis protocol +## High-performance parser for the Redis protocol -While the Redis protocol is human readable and easy to implement, it can -be implemented with a performance similar to that of a binary protocol. +While the Redis protocol is human-readable and easy to implement, its implementation can exhibit performance similar to that of a binary protocol. -RESP uses prefixed lengths to transfer bulk data, so there is -never a need to scan the payload for special characters, like with JSON, nor to quote the payload that needs to be sent to the -server. +RESP uses prefixed lengths to transfer bulk data. +That makes scanning the payload for special characters unnecessary (unlike parsing JSON, for example). +For the same reason, quoting and escaping the payload isn't needed. -The Bulk and Multi Bulk lengths can be processed with code that performs -a single operation per character while at the same time scanning for the -CR character, like the following C code: +Reading the length of aggregate types (for example, bulk strings or arrays) can be processed with code that performs a single operation per character while at the same time scanning for the CR character. -``` +Example (in C): + +```c #include int main(void) { @@ -362,11 +685,17 @@ int main(void) { } ``` -After the first CR is identified, it can be skipped along with the following -LF without any processing. Then the bulk data can be read using a single -read operation that does not inspect the payload in any way. Finally, -the remaining CR and LF characters are discarded without any processing. +After the first CR is identified, it can be skipped along with the following LF without further processing. +Then, the bulk data can be read with a single read operation that doesn't inspect the payload in any way. +Finally, the remaining CR and LF characters are discarded without additional processing. + +While comparable in performance to a binary protocol, the Redis protocol is significantly more straightforward to implement in most high-level languages, reducing the number of bugs in client software. + +## Tips for Redis client authors + +* For testing purposes, use [Lua's type conversions](/topics/lua-api#lua-to-resp3-type-conversion) to have Redis reply with any RESP2/RESP3 needed. + As an example, a RESP3 double can be generated like so: + ``` + EVAL "return { double = tonumber(ARGV[1]) }" 0 1e0 + ``` -While comparable in performance to a binary protocol, the Redis protocol is -significantly simpler to implement in most high-level languages, -reducing the number of bugs in client software. diff --git a/wordlist b/wordlist index 504bc19b16..60fe619c87 100644 --- a/wordlist +++ b/wordlist @@ -70,6 +70,7 @@ BigNumber BitOp Bitfields Bitwise +Booleans brpop C1 C2 @@ -271,6 +272,7 @@ NTP NUMA NX NaN +NaNs Nehalem node-redis NoSQL @@ -532,6 +534,7 @@ bitop bitwise bitwise bool +booleans breakpoint broadcasted bt @@ -655,6 +658,7 @@ foo0 foo1 foo2 formatter +fractionals frequencyonly fsSL fsync @@ -794,6 +798,7 @@ node-redlock noeviction non-TCP non-TLS +non-loopback non-reachability non-virtualized nonprintable @@ -807,6 +812,7 @@ numkeys nullarray nx observability +octothorpe odown ok oldval @@ -984,6 +990,7 @@ suboptimal subsequence substring sudo +superset swapdb swappability syncd @@ -998,6 +1005,7 @@ tmp tmux toolkits topologies +tonumber tradeoff tradeoffs transactional @@ -1024,6 +1032,7 @@ unregisters untrusted untuned unwatches +uppercased urandom used_memory_scripts_eval userSession From 62dd1132514c4c25a5d039b5cc703b8d0f32543b Mon Sep 17 00:00:00 2001 From: savynorem Date: Tue, 15 Aug 2023 10:26:02 -0400 Subject: [PATCH 267/377] wordlist update with commands --- wordlist | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/wordlist b/wordlist index 257e9657de..8298ab47fd 100644 --- a/wordlist +++ b/wordlist @@ -151,6 +151,7 @@ cardinality CAS CAs casted +Castilla cd CentOS CFIELD @@ -332,6 +333,7 @@ foo0 foo1 foo2 formatter +france_location FreeBSD FreeString frequencyonly @@ -380,6 +382,7 @@ HashSets Haversine Healthcheck healthchecks +Henshaw Hexastore hexastore hget @@ -438,6 +441,7 @@ IPv4 IPv6 IS-MASTER-DOWN-BY-ADDR Istio +italy_racers Itamar iterable iteratively @@ -458,6 +462,7 @@ jpeg js JSON JSON-encoded +JUSTID kB keepalive keylen @@ -555,6 +560,8 @@ malloc MASTERDOWN Matteo matteocollina +maxlen +MAXLEN Maxmemory maxmemory Memcache @@ -567,9 +574,11 @@ MessagePack metatag mget middleware +MINID miranda misconfiguration misconfigured +MKSTREAM modules-api-ref moduleType Movablekeys @@ -580,6 +589,7 @@ multisets mutex mylist mymaster +mystream myuser myzset namespace @@ -608,6 +618,7 @@ nonprintable NOOP Noordhuis nopass +Norem NoSQL notify-keyspace-events notifyKeyspaceEvent @@ -689,6 +700,7 @@ preprocessing prerequesits Prev prev +Prickett printf printf-alike Prioglio @@ -714,6 +726,9 @@ queueing quickstarts R1 R2 +race:france +race:italy +race:usa radix rc RC1 @@ -857,6 +872,7 @@ S4 SaaS sadd sadd_smembers +Sam-Bodden Sandboxed sandboxed Sanfilippo @@ -930,6 +946,7 @@ status2 stdin storepass strace +stream_toturial StringDMA struct struct-encoded @@ -1047,12 +1064,59 @@ whos-using-redis WRONGTYPE WSL WSL2 +xack +XACK +xadd +XADD +xadd_2 +xadd_7 +xadd_bad_id +xadd_id +xautoclaim +XAUTOCLAIM +xautoclaim_cursor +xclaim +XCLAIM +xdel +XDEL Xen Xen-specific Xeon xff +XGROUP +xgroup_create +xgroup_create_mkstream +xgroup_read +xgroup_read_bob +xinfo +XINFO +xinfo_consumers +xinfo_groups +xlen +XLEN XMODEM +xpending +XPENDING +xpending_plus_minus +xrange +XRANGE +xrange_all +xrange_empty +xrange_pending +xrange_step_1 +xrange_step_2 +xrange_time +xread +XREAD +XREADGROUP +xgroup_read_id +xread_block +xrevrange +XREVRANGE XSCAN +xtrim +XTRIM +xtrim2 XYZ xzvf YCSB From 51d8fa50f6342a9bba7d5ed274d2f919d35e2db8 Mon Sep 17 00:00:00 2001 From: savynorem Date: Tue, 15 Aug 2023 10:32:47 -0400 Subject: [PATCH 268/377] streams_tutorial -> stream_tutorial --- docs/data-types/streams.md | 52 +++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/data-types/streams.md b/docs/data-types/streams.md index 60d691ce92..d260ffbe63 100644 --- a/docs/data-types/streams.md +++ b/docs/data-types/streams.md @@ -45,7 +45,7 @@ See the [complete list of stream commands](https://redis.io/commands/?group=stre {{< /clients-example >}} * Read two stream entries starting at ID `1691765278160-0`: -{{< clients-example streams_tutorial xrange >}} +{{< clients-example stream_tutorial xrange >}} > XRANGE race:france 1691765278160-0 + COUNT 2 1) 1) "1691765278160-0" 2) 1) "rider" @@ -118,7 +118,7 @@ The format of such IDs may look strange at first, and the gentle reader may wond If for some reason the user needs incremental IDs that are not related to time but are actually associated to another external system ID, as previously mentioned, the `XADD` command can take an explicit ID instead of the `*` wildcard ID that triggers auto-generation, like in the following examples: -{{< clients-example streams_toturial xadd_id >}} +{{< clients-example stream_toturial xadd_id >}} > XADD race:usa 0-1 racer Castilla 0-1 > XADD race:usa 0-2 racer Norem @@ -127,14 +127,14 @@ If for some reason the user needs incremental IDs that are not related to time b Note that in this case, the minimum ID is 0-1 and that the command will not accept an ID equal or smaller than a previous one: -{{< clients-example streams_toturial xadd_bad_id >}} +{{< clients-example stream_toturial xadd_bad_id >}} > XADD race:usa 0-1 racer Prickett (error) ERR The ID specified in XADD is equal or smaller than the target stream top item {{< /clients-example >}} If you're running Redis 7 or later, you can also provide an explicit ID consisting of the milliseconds part only. In this case, the sequence portion of the ID will be automatically generated. To do this, use the syntax below: -{{< clients-example streams_toturial xadd_7 >}} +{{< clients-example stream_toturial xadd_7 >}} > XADD race:usa 0-* racer Prickett 0-3 {{< /clients-example >}} @@ -153,7 +153,7 @@ Redis Streams support all three of the query modes described above via different To query the stream by range we are only required to specify two IDs, *start* and *end*. The range returned will include the elements having start or end as ID, so the range is inclusive. The two special IDs `-` and `+` respectively mean the smallest and the greatest ID possible. -{{< clients-example streams_toturial xrange_all >}} +{{< clients-example stream_toturial xrange_all >}} > XRANGE race:france - + 1) 1) "1691762745152-0" 2) 1) "rider" @@ -195,7 +195,7 @@ To query the stream by range we are only required to specify two IDs, *start* an Each entry returned is an array of two items: the ID and the list of field-value pairs. We already said that the entry IDs have a relation with the time, because the part at the left of the `-` character is the Unix time in milliseconds of the local node that created the stream entry, at the moment the entry was created (however note that streams are replicated with fully specified `XADD` commands, so the replicas will have identical IDs to the master). This means that I could query a range of time using `XRANGE`. In order to do so, however, I may want to omit the sequence part of the ID: if omitted, in the start of the range it will be assumed to be 0, while in the end part it will be assumed to be the maximum sequence number available. This way, querying using just two milliseconds Unix times, we get all the entries that were generated in that range of time, in an inclusive way. For instance, if I want to query a two milliseconds period I could use: -{{< clients-example streams_toturial xrange_time >}} +{{< clients-example stream_toturial xrange_time >}} > XRANGE race:france 1691765375864 1691765375866 1) 1) "1691765375865-0" 2) 1) "rider" @@ -210,7 +210,7 @@ Each entry returned is an array of two items: the ID and the list of field-value I have only a single entry in this range, however in real data sets, I could query for ranges of hours, or there could be many items in just two milliseconds, and the result returned could be huge. For this reason, `XRANGE` supports an optional **COUNT** option at the end. By specifying a count, I can just get the first *N* items. If I want more, I can get the last ID returned, increment the sequence part by one, and query again. Let's see this in the following example. Let's assume that the stream `race:france` was populated with 4 items. To start my iteration, getting 2 items per command, I start with the full range, but with a count of 2. -{{< clients-example streams_toturial xrange_step_1 >}} +{{< clients-example stream_toturial xrange_step_1 >}} > XRANGE race:france - + COUNT 2 1) 1) "1691762745152-0" 2) 1) "rider" @@ -234,7 +234,7 @@ I have only a single entry in this range, however in real data sets, I could que In order to continue the iteration with the next two items, I have to pick the last ID returned, that is `1691765278160-0` and add the prefix `(` to it. The resulting exclusive range interval, that is `(1691765278160-0` in this case, can now be used as the new *start* argument for the next `XRANGE` call: -{{< clients-example streams_toturial xrange_step_2 >}} +{{< clients-example stream_toturial xrange_step_2 >}} > XRANGE race:france (1691765278160-0 + COUNT 2 1) 1) "1691765289770-0" 2) 1) "rider" @@ -258,7 +258,7 @@ In order to continue the iteration with the next two items, I have to pick the l Now that we've gotten 4 items out of a stream that only had 4 things in it, if we try to get more items, we'll get an empty array: -{{< clients-example streams_toturial xrange_empty >}} +{{< clients-example stream_toturial xrange_empty >}} > XRANGE race:france (1691765375865-0 + COUNT 2 (empty array) {{< /clients-example >}} @@ -267,7 +267,7 @@ Since `XRANGE` complexity is *O(log(N))* to seek, and then *O(M)* to return M el The command `XREVRANGE` is the equivalent of `XRANGE` but returning the elements in inverted order, so a practical use for `XREVRANGE` is to check what is the last item in a Stream: -{{< clients-example streams_toturial xrevrange >}} +{{< clients-example stream_toturial xrevrange >}} > XREVRANGE race:france + - COUNT 1 1) 1) "1691765375865-0" 2) 1) "rider" @@ -292,7 +292,7 @@ When we do not want to access items by a range in a stream, usually what we want The command that provides the ability to listen for new messages arriving into a stream is called `XREAD`. It's a bit more complex than `XRANGE`, so we'll start showing simple forms, and later the whole command layout will be provided. -{{< clients-example streams_toturial xread >}} +{{< clients-example stream_toturial xread >}} > XREAD COUNT 2 STREAMS race:france 0 1) 1) "race:france" 2) 1) 1) "1691762745152-0" @@ -391,7 +391,7 @@ Now it's time to zoom in to see the fundamental consumer group commands. They ar Assuming I have a key `race:france` of type stream already existing, in order to create a consumer group I just need to do the following: -{{< clients-example streams_toturial xgroup_create >}} +{{< clients-example stream_toturial xgroup_create >}} > XGROUP CREATE race:france france_location $ OK {{< /clients-example >}} @@ -400,7 +400,7 @@ As you can see in the command above when creating the consumer group we have to `XGROUP CREATE` also supports creating the stream automatically, if it doesn't exist, using the optional `MKSTREAM` subcommand as the last argument: -{{< clients-example streams_toturial xgroup_create_mkstream >}} +{{< clients-example stream_toturial xgroup_create_mkstream >}} > XGROUP CREATE race:italy italy_racers $ MKSTREAM OK {{< /clients-example >}} @@ -412,7 +412,7 @@ Now that the consumer group is created we can immediately try to read messages v We'll add racers to the race:italy stream and try reading something using the consumer group: Note: *here racer is the field name, and the name is the associated value, remember that stream items are small dictionaries.* -{{< clients-example streams_toturial xgroup_read >}} +{{< clients-example stream_toturial xgroup_read >}} > XADD race:italy * racer Castilla "1691766245113-0" > XADD race:italy * racer Royce @@ -441,7 +441,7 @@ This is almost always what you want, however it is also possible to specify a re We can test this behavior immediately specifying an ID of 0, without any **COUNT** option: we'll just see the only pending message, that is, the one about apples: -{{< clients-example streams_toturial xgroup_read_id >}} +{{< clients-example stream_toturial xgroup_read_id >}} > XREADGROUP GROUP italy_racers Alice STREAMS race:italy 0 1) 1) "race:italy" 2) 1) 1) "1691766245113-0" @@ -451,7 +451,7 @@ We can test this behavior immediately specifying an ID of 0, without any **COUNT However, if we acknowledge the message as processed, it will no longer be part of the pending messages history, so the system will no longer report anything: -{{< clients-example streams_toturial xack >}} +{{< clients-example stream_toturial xack >}} > XACK race:italy italy_racers 1691766245113-0 (integer) 1 > XREADGROUP GROUP italy_racers Alice STREAMS race:italy 0 @@ -463,7 +463,7 @@ Don't worry if you yet don't know how `XACK` works, the idea is just that proces Now it's Bob's turn to read something: -{{< clients-example streams_toturial xgroup_read_bob >}} +{{< clients-example stream_toturial xgroup_read_bob >}} > XREADGROUP GROUP italy_racers Bob COUNT 2 STREAMS race:italy > 1) 1) "race:italy" 2) 1) 1) "1691766256307-0" @@ -555,7 +555,7 @@ The first step of this process is just a command that provides observability of This is a read-only command which is always safe to call and will not change ownership of any message. In its simplest form, the command is called with two arguments, which are the name of the stream and the name of the consumer group. -{{< clients-example streams_toturial xpending >}} +{{< clients-example stream_toturial xpending >}} > XPENDING race:italy italy_racers 1) (integer) 2 2) "1691766256307-0" @@ -575,7 +575,7 @@ XPENDING [[IDLE ] [ By providing a start and end ID (that can be just `-` and `+` as in `XRANGE`) and a count to control the amount of information returned by the command, we are able to know more about the pending messages. The optional final argument, the consumer name, is used if we want to limit the output to just messages pending for a given consumer, but won't use this feature in the following example. -{{< clients-example streams_toturial xpending_plus_minus >}} +{{< clients-example stream_toturial xpending_plus_minus >}} > XPENDING race:italy italy_racers - + 10 1) 1) "1691766256307-0" 2) "Bob" @@ -592,7 +592,7 @@ We have two messages from Bob, and they are idle for 60000+ milliseconds, about Note that nobody prevents us from checking what the first message content was by just using `XRANGE`. -{{< clients-example streams_toturial xrange_pending >}} +{{< clients-example stream_toturial xrange_pending >}} > XRANGE race:italy 1691766256307-0 1691766256307-0 1) 1) "1691766256307-0" 2) 1) "racer" @@ -618,7 +618,7 @@ However, as a side effect, claiming a message will reset its idle time and will This is the result of the command execution: -{{< clients-example streams_toturial xclaim >}} +{{< clients-example stream_toturial xclaim >}} > XCLAIM race:italy italy_racers Alice 60000 1691766256307-0 1) 1) "1691766256307-0" 2) 1) "racer" @@ -646,7 +646,7 @@ XAUTOCLAIM [COUNT count] [JUSTI So, in the example above, I could have used automatic claiming to claim a single message like this: -{{< clients-example streams_toturial xautoclaim >}} +{{< clients-example stream_toturial xautoclaim >}} > XAUTOCLAIM race:italy italy_racers Alice 60000 0-0 COUNT 1 1) "1691766261145-0" 2) 1) 1) "1691766256307-0" @@ -657,7 +657,7 @@ So, in the example above, I could have used automatic claiming to claim a single Like `XCLAIM`, the command replies with an array of the claimed messages, but it also returns a stream ID that allows iterating the pending entries. The stream ID is a cursor, and I can use it in my next call to continue in claiming idle pending messages: -{{< clients-example streams_toturial xautoclaim_cursor >}} +{{< clients-example stream_toturial xautoclaim_cursor >}} > XAUTOCLAIM race:italy italy_racers Lora 60000 1526569498055-0 COUNT 1 1) "0-0" 2) 1) 1) "1691766261145-0" @@ -682,7 +682,7 @@ However we may want to do more than that, and the `XINFO` command is an observab This command uses subcommands in order to show different information about the status of the stream and its consumer groups. For instance **XINFO STREAM ** reports information about the stream itself. -{{< clients-example streams_toturial xinfo >}} +{{< clients-example stream_toturial xinfo >}} > XINFO STREAM race:italy 1) "length" 2) (integer) 5 @@ -706,7 +706,7 @@ This command uses subcommands in order to show different information about the s The output shows information about how the stream is encoded internally, and also shows the first and last message in the stream. Another piece of information available is the number of consumer groups associated with this stream. We can dig further asking for more information about the consumer groups. -{{< clients-example streams_toturial xinfo_groups >}} +{{< clients-example stream_toturial xinfo_groups >}} > XINFO GROUPS race:italy 1) 1) "name" 2) "italy_racers" @@ -722,7 +722,7 @@ As you can see in this and in the previous output, the `XINFO` command outputs a The output of the example above, where the **GROUPS** subcommand is used, should be clear observing the field names. We can check in more detail the state of a specific consumer group by checking the consumers that are registered in the group. -{{< clients-example streams_toturial xinfo_consumers >}}} +{{< clients-example stream_toturial xinfo_consumers >}} > XINFO CONSUMERS race:italy italy_racers 1) 1) "name" 2) "Alice" From e627742daf779425fef136fc59aeb0ce4af15cef Mon Sep 17 00:00:00 2001 From: savynorem Date: Tue, 15 Aug 2023 10:34:31 -0400 Subject: [PATCH 269/377] wordlist fix --- wordlist | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wordlist b/wordlist index 8298ab47fd..e3ceda78e5 100644 --- a/wordlist +++ b/wordlist @@ -17,6 +17,7 @@ 1s 1th 2GB +3am 300ms 30ms 32bit @@ -25,11 +26,14 @@ 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 3GB 3MB +4am 4GB 4k +5am 500MB 512MB 5GB +6am 60s 6sync 80ms @@ -131,6 +135,7 @@ Bitwise bitwise bitwise bool +Booleans BPF BPF-optimized BPF's From 96614a800854d72bd22fc0966cbfb0960983e8e7 Mon Sep 17 00:00:00 2001 From: Savannah Date: Tue, 15 Aug 2023 10:38:50 -0400 Subject: [PATCH 270/377] hopefully the last wordlist fix --- wordlist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wordlist b/wordlist index 4639e02bee..c1aaf85ed6 100644 --- a/wordlist +++ b/wordlist @@ -974,7 +974,7 @@ suboptimal subsequence substring sudo -SVGsSVGs +SVGs superset swapdb swappability @@ -1142,4 +1142,4 @@ ziplists ZMODEM ZPOP ZSET -zset \ No newline at end of file +zset From 6fb437644f617be3807e755e7e0c868f87735f08 Mon Sep 17 00:00:00 2001 From: "David W. Dougherty" Date: Mon, 21 Aug 2023 06:33:19 -0700 Subject: [PATCH 271/377] DOC-2586: add RC as a get started method --- docs/getting-started/installation/_index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/getting-started/installation/_index.md b/docs/getting-started/installation/_index.md index 4a8845d356..c9b9fc0c17 100644 --- a/docs/getting-started/installation/_index.md +++ b/docs/getting-started/installation/_index.md @@ -5,3 +5,5 @@ weight: 1 description: > Install Redis on Linux, macOS, and Windows --- + +While you can install Redis on any of the platforms listed below, you might also consider using Redis Cloud by creating a [free account](https://docs.redis.com/latest/rc/rc-quickstart/). \ No newline at end of file From caa1987e56efc20feef359a8a0f7ff01c85782c3 Mon Sep 17 00:00:00 2001 From: Savannah Date: Mon, 21 Aug 2023 11:59:35 -0400 Subject: [PATCH 272/377] update stream IDs to be more consistent, add caveat about various implementations of max length approximation --- docs/data-types/streams.md | 232 +++++++++++++++++++------------------ 1 file changed, 117 insertions(+), 115 deletions(-) diff --git a/docs/data-types/streams.md b/docs/data-types/streams.md index d260ffbe63..9371f5cabb 100644 --- a/docs/data-types/streams.md +++ b/docs/data-types/streams.md @@ -37,32 +37,32 @@ See the [complete list of stream commands](https://redis.io/commands/?group=stre * When our racers pass a checkpoint, we add a stream entry for each racer that includes the racer's name, speed, position, and location ID: {{< clients-example stream_tutorial xadd >}} > XADD race:france * rider Castilla speed 30.2 position 1 location_id 1 -"1691762745152-0" +"1692632086370-0" > XADD race:france * rider Norem speed 28.8 position 3 location_id 1 -"1691765278160-0" +"1692632094485-0" > XADD race:france * rider Prickett speed 29.7 position 2 location_id 1 -"1691765289770-0" +"1692632102976-0" {{< /clients-example >}} -* Read two stream entries starting at ID `1691765278160-0`: +* Read two stream entries starting at ID `1692632086370-0`: {{< clients-example stream_tutorial xrange >}} -> XRANGE race:france 1691765278160-0 + COUNT 2 -1) 1) "1691765278160-0" +> XRANGE race:france 1692632086370-0 + COUNT 2 +1) 1) "1692632086370-0" 2) 1) "rider" - 2) "Norem" + 2) "Castilla" 3) "speed" - 4) "28.8" + 4) "30.2" 5) "position" - 6) "3" + 6) "1" 7) "location_id" 8) "1" -2) 1) "1691765289770-0" +2) 1) "1692632094485-0" 2) 1) "rider" - 2) "Prickett" + 2) "Norem" 3) "speed" - 4) "29.7" + 4) "28.8" 5) "position" - 6) "2" + 6) "3" 7) "location_id" 8) "1" {{< /clients-example >}} @@ -92,10 +92,10 @@ Each stream entry consists of one or more field-value pairs, somewhat like a dic {{< clients-example stream_tutorial xadd_2 >}} > XADD race:france * rider Castilla speed 29.9 position 1 location_id 2 -"1691765375865-0" +"1692632147973-0" {{< /clients-example >}} -The above call to the `XADD` command adds an entry `rider: Castilla, speed: 29.9, position: 1, location_id: 2` to the stream at key `race:france`, using an auto-generated entry ID, which is the one returned by the command, specifically `1691762745152-0`. It gets as its first argument the key name `race:france`, the second argument is the entry ID that identifies every entry inside a stream. However, in this case, we passed `*` because we want the server to generate a new ID for us. Every new ID will be monotonically increasing, so in more simple terms, every new entry added will have a higher ID compared to all the past entries. Auto-generation of IDs by the server is almost always what you want, and the reasons for specifying an ID explicitly are very rare. We'll talk more about this later. The fact that each Stream entry has an ID is another similarity with log files, where line numbers, or the byte offset inside the file, can be used in order to identify a given entry. Returning back at our `XADD` example, after the key name and ID, the next arguments are the field-value pairs composing our stream entry. +The above call to the `XADD` command adds an entry `rider: Castilla, speed: 29.9, position: 1, location_id: 2` to the stream at key `race:france`, using an auto-generated entry ID, which is the one returned by the command, specifically `1692632147973-0`. It gets as its first argument the key name `race:france`, the second argument is the entry ID that identifies every entry inside a stream. However, in this case, we passed `*` because we want the server to generate a new ID for us. Every new ID will be monotonically increasing, so in more simple terms, every new entry added will have a higher ID compared to all the past entries. Auto-generation of IDs by the server is almost always what you want, and the reasons for specifying an ID explicitly are very rare. We'll talk more about this later. The fact that each Stream entry has an ID is another similarity with log files, where line numbers, or the byte offset inside the file, can be used in order to identify a given entry. Returning back at our `XADD` example, after the key name and ID, the next arguments are the field-value pairs composing our stream entry. It is possible to get the number of items inside a Stream just using the `XLEN` command: @@ -155,7 +155,7 @@ To query the stream by range we are only required to specify two IDs, *start* an {{< clients-example stream_toturial xrange_all >}} > XRANGE race:france - + -1) 1) "1691762745152-0" +1) 1) "1692632086370-0" 2) 1) "rider" 2) "Castilla" 3) "speed" @@ -164,7 +164,7 @@ To query the stream by range we are only required to specify two IDs, *start* an 6) "1" 7) "location_id" 8) "1" -2) 1) "1691765278160-0" +2) 1) "1692632094485-0" 2) 1) "rider" 2) "Norem" 3) "speed" @@ -173,7 +173,7 @@ To query the stream by range we are only required to specify two IDs, *start* an 6) "3" 7) "location_id" 8) "1" -3) 1) "1691765289770-0" +3) 1) "1692632102976-0" 2) 1) "rider" 2) "Prickett" 3) "speed" @@ -182,7 +182,7 @@ To query the stream by range we are only required to specify two IDs, *start* an 6) "2" 7) "location_id" 8) "1" -4) 1) "1691765375865-0" +4) 1) "1692632147973-0" 2) 1) "rider" 2) "Castilla" 3) "speed" @@ -196,23 +196,23 @@ To query the stream by range we are only required to specify two IDs, *start* an Each entry returned is an array of two items: the ID and the list of field-value pairs. We already said that the entry IDs have a relation with the time, because the part at the left of the `-` character is the Unix time in milliseconds of the local node that created the stream entry, at the moment the entry was created (however note that streams are replicated with fully specified `XADD` commands, so the replicas will have identical IDs to the master). This means that I could query a range of time using `XRANGE`. In order to do so, however, I may want to omit the sequence part of the ID: if omitted, in the start of the range it will be assumed to be 0, while in the end part it will be assumed to be the maximum sequence number available. This way, querying using just two milliseconds Unix times, we get all the entries that were generated in that range of time, in an inclusive way. For instance, if I want to query a two milliseconds period I could use: {{< clients-example stream_toturial xrange_time >}} -> XRANGE race:france 1691765375864 1691765375866 -1) 1) "1691765375865-0" +> XRANGE race:france 1692632086369 1692632086371 +1) 1) "1692632086370-0" 2) 1) "rider" 2) "Castilla" 3) "speed" - 4) "29.9" + 4) "30.2" 5) "position" 6) "1" 7) "location_id" - 8) "2" + 8) "1" {{< /clients-example >}} I have only a single entry in this range, however in real data sets, I could query for ranges of hours, or there could be many items in just two milliseconds, and the result returned could be huge. For this reason, `XRANGE` supports an optional **COUNT** option at the end. By specifying a count, I can just get the first *N* items. If I want more, I can get the last ID returned, increment the sequence part by one, and query again. Let's see this in the following example. Let's assume that the stream `race:france` was populated with 4 items. To start my iteration, getting 2 items per command, I start with the full range, but with a count of 2. {{< clients-example stream_toturial xrange_step_1 >}} > XRANGE race:france - + COUNT 2 -1) 1) "1691762745152-0" +1) 1) "1692632086370-0" 2) 1) "rider" 2) "Castilla" 3) "speed" @@ -221,7 +221,7 @@ I have only a single entry in this range, however in real data sets, I could que 6) "1" 7) "location_id" 8) "1" -2) 1) "1691765278160-0" +2) 1) "1692632094485-0" 2) 1) "rider" 2) "Norem" 3) "speed" @@ -232,11 +232,11 @@ I have only a single entry in this range, however in real data sets, I could que 8) "1" {{< /clients-example >}} -In order to continue the iteration with the next two items, I have to pick the last ID returned, that is `1691765278160-0` and add the prefix `(` to it. The resulting exclusive range interval, that is `(1691765278160-0` in this case, can now be used as the new *start* argument for the next `XRANGE` call: +In order to continue the iteration with the next two items, I have to pick the last ID returned, that is `1692632094485-0` and add the prefix `(` to it. The resulting exclusive range interval, that is `(1692632094485-0` in this case, can now be used as the new *start* argument for the next `XRANGE` call: {{< clients-example stream_toturial xrange_step_2 >}} -> XRANGE race:france (1691765278160-0 + COUNT 2 -1) 1) "1691765289770-0" +> XRANGE race:france (1692632094485-0 + COUNT 2 +1) 1) "1692632102976-0" 2) 1) "rider" 2) "Prickett" 3) "speed" @@ -245,7 +245,7 @@ In order to continue the iteration with the next two items, I have to pick the l 6) "2" 7) "location_id" 8) "1" -2) 1) "1691765375865-0" +2) 1) "1692632147973-0" 2) 1) "rider" 2) "Castilla" 3) "speed" @@ -259,7 +259,7 @@ In order to continue the iteration with the next two items, I have to pick the l Now that we've gotten 4 items out of a stream that only had 4 things in it, if we try to get more items, we'll get an empty array: {{< clients-example stream_toturial xrange_empty >}} -> XRANGE race:france (1691765375865-0 + COUNT 2 +> XRANGE race:france (1692632147973-0 + COUNT 2 (empty array) {{< /clients-example >}} @@ -269,7 +269,7 @@ The command `XREVRANGE` is the equivalent of `XRANGE` but returning the elements {{< clients-example stream_toturial xrevrange >}} > XREVRANGE race:france + - COUNT 1 -1) 1) "1691765375865-0" +1) 1) "1692632147973-0" 2) 1) "rider" 2) "Castilla" 3) "speed" @@ -295,7 +295,7 @@ The command that provides the ability to listen for new messages arriving into a {{< clients-example stream_toturial xread >}} > XREAD COUNT 2 STREAMS race:france 0 1) 1) "race:france" - 2) 1) 1) "1691762745152-0" + 2) 1) 1) "1692632086370-0" 2) 1) "rider" 2) "Castilla" 3) "speed" @@ -304,7 +304,7 @@ The command that provides the ability to listen for new messages arriving into a 6) "1" 7) "location_id" 8) "1" - 2) 1) "1691765278160-0" + 2) 1) "1692632094485-0" 2) 1) "rider" 2) "Norem" 3) "speed" @@ -392,7 +392,7 @@ Now it's time to zoom in to see the fundamental consumer group commands. They ar Assuming I have a key `race:france` of type stream already existing, in order to create a consumer group I just need to do the following: {{< clients-example stream_toturial xgroup_create >}} -> XGROUP CREATE race:france france_location $ +> XGROUP CREATE race:france france_riders $ OK {{< /clients-example >}} @@ -401,7 +401,7 @@ As you can see in the command above when creating the consumer group we have to `XGROUP CREATE` also supports creating the stream automatically, if it doesn't exist, using the optional `MKSTREAM` subcommand as the last argument: {{< clients-example stream_toturial xgroup_create_mkstream >}} -> XGROUP CREATE race:italy italy_racers $ MKSTREAM +> XGROUP CREATE race:italy italy_riders $ MKSTREAM OK {{< /clients-example >}} @@ -409,24 +409,24 @@ Now that the consumer group is created we can immediately try to read messages v `XREADGROUP` is very similar to `XREAD` and provides the same **BLOCK** option, otherwise it is a synchronous command. However there is a *mandatory* option that must be always specified, which is **GROUP** and has two arguments: the name of the consumer group, and the name of the consumer that is attempting to read. The option **COUNT** is also supported and is identical to the one in `XREAD`. -We'll add racers to the race:italy stream and try reading something using the consumer group: -Note: *here racer is the field name, and the name is the associated value, remember that stream items are small dictionaries.* +We'll add riders to the race:italy stream and try reading something using the consumer group: +Note: *here rider is the field name, and the name is the associated value, remember that stream items are small dictionaries.* {{< clients-example stream_toturial xgroup_read >}} -> XADD race:italy * racer Castilla -"1691766245113-0" -> XADD race:italy * racer Royce -"1691766256307-0" -> XADD race:italy * racer Sam-Bodden -"1691766261145-0" -> XADD race:italy * racer Prickett -"1691766685178-0" -> XADD race:italy * racer Norem -"1691766698493-0" -> XREADGROUP GROUP italy_racers Alice COUNT 1 STREAMS race:italy > +> XADD race:italy * rider Castilla +"1692632639151-0" +> XADD race:italy * rider Royce +"1692632647899-0" +> XADD race:italy * rider Sam-Bodden +"1692632662819-0" +> XADD race:italy * rider Prickett +"1692632670501-0" +> XADD race:italy * rider Norem +"1692632678249-0" +> XREADGROUP GROUP italy_riders Alice COUNT 1 STREAMS race:italy > 1) 1) "race:italy" - 2) 1) 1) "1691766245113-0" - 2) 1) "racer" + 2) 1) 1) "1692632639151-0" + 2) 1) "rider" 2) "Castilla" {{< /clients-example >}} @@ -442,19 +442,19 @@ This is almost always what you want, however it is also possible to specify a re We can test this behavior immediately specifying an ID of 0, without any **COUNT** option: we'll just see the only pending message, that is, the one about apples: {{< clients-example stream_toturial xgroup_read_id >}} -> XREADGROUP GROUP italy_racers Alice STREAMS race:italy 0 +> XREADGROUP GROUP italy_riders Alice STREAMS race:italy 0 1) 1) "race:italy" - 2) 1) 1) "1691766245113-0" - 2) 1) "racer" + 2) 1) 1) "1692632639151-0" + 2) 1) "rider" 2) "Castilla" {{< /clients-example >}} However, if we acknowledge the message as processed, it will no longer be part of the pending messages history, so the system will no longer report anything: {{< clients-example stream_toturial xack >}} -> XACK race:italy italy_racers 1691766245113-0 +> XACK race:italy italy_riders 1692632639151-0 (integer) 1 -> XREADGROUP GROUP italy_racers Alice STREAMS race:italy 0 +> XREADGROUP GROUP italy_riders Alice STREAMS race:italy 0 1) 1) "race:italy" 2) (empty array) {{< /clients-example >}} @@ -464,13 +464,13 @@ Don't worry if you yet don't know how `XACK` works, the idea is just that proces Now it's Bob's turn to read something: {{< clients-example stream_toturial xgroup_read_bob >}} -> XREADGROUP GROUP italy_racers Bob COUNT 2 STREAMS race:italy > +> XREADGROUP GROUP italy_riders Bob COUNT 2 STREAMS race:italy > 1) 1) "race:italy" - 2) 1) 1) "1691766256307-0" - 2) 1) "racer" + 2) 1) 1) "1692632647899-0" + 2) 1) "rider" 2) "Royce" - 2) 1) "1691766261145-0" - 2) 1) "racer" + 2) 1) "1692632662819-0" + 2) 1) "rider" 2) "Sam-Bodden" {{< /clients-example >}} @@ -556,10 +556,10 @@ This is a read-only command which is always safe to call and will not change own In its simplest form, the command is called with two arguments, which are the name of the stream and the name of the consumer group. {{< clients-example stream_toturial xpending >}} -> XPENDING race:italy italy_racers +> XPENDING race:italy italy_riders 1) (integer) 2 -2) "1691766256307-0" -3) "1691766261145-0" +2) "1692632647899-0" +3) "1692632662819-0" 4) 1) 1) "Bob" 2) "2" {{< /clients-example >}} @@ -576,14 +576,14 @@ XPENDING [[IDLE ] [ By providing a start and end ID (that can be just `-` and `+` as in `XRANGE`) and a count to control the amount of information returned by the command, we are able to know more about the pending messages. The optional final argument, the consumer name, is used if we want to limit the output to just messages pending for a given consumer, but won't use this feature in the following example. {{< clients-example stream_toturial xpending_plus_minus >}} -> XPENDING race:italy italy_racers - + 10 -1) 1) "1691766256307-0" +> XPENDING race:italy italy_riders - + 10 +1) 1) "1692632647899-0" 2) "Bob" - 3) (integer) 60644 + 3) (integer) 74642 4) (integer) 1 -2) 1) "1691766261145-0" +2) 1) "1692632662819-0" 2) "Bob" - 3) (integer) 60644 + 3) (integer) 74642 4) (integer) 1 {{< /clients-example >}} @@ -593,9 +593,9 @@ We have two messages from Bob, and they are idle for 60000+ milliseconds, about Note that nobody prevents us from checking what the first message content was by just using `XRANGE`. {{< clients-example stream_toturial xrange_pending >}} -> XRANGE race:italy 1691766256307-0 1691766256307-0 -1) 1) "1691766256307-0" - 2) 1) "racer" +> XRANGE race:italy 1692632647899-0 1692632647899-0 +1) 1) "1692632647899-0" + 2) 1) "rider" 2) "Royce" {{< /clients-example >}} @@ -610,8 +610,8 @@ XCLAIM ... Basically we say, for this specific key and group, I want that the message IDs specified will change ownership, and will be assigned to the specified consumer name ``. However, we also provide a minimum idle time, so that the operation will only work if the idle time of the mentioned messages is greater than the specified idle time. This is useful because maybe two clients are retrying to claim a message at the same time: ``` -Client 1: XCLAIM race:italy italy_racers Alice 60000 1691766256307-0 -Client 2: XCLAIM race:italy italy_racers Lora 60000 1691766256307-0 +Client 1: XCLAIM race:italy italy_riders Alice 60000 1692632647899-0 +Client 2: XCLAIM race:italy italy_riders Lora 60000 1692632647899-0 ``` However, as a side effect, claiming a message will reset its idle time and will increment its number of deliveries counter, so the second client will fail claiming it. In this way we avoid trivial re-processing of messages (even if in the general case you cannot obtain exactly once processing). @@ -619,9 +619,9 @@ However, as a side effect, claiming a message will reset its idle time and will This is the result of the command execution: {{< clients-example stream_toturial xclaim >}} -> XCLAIM race:italy italy_racers Alice 60000 1691766256307-0 -1) 1) "1691766256307-0" - 2) 1) "racer" +> XCLAIM race:italy italy_riders Alice 60000 1692632647899-0 +1) 1) "1692632647899-0" + 2) 1) "rider" 2) "Royce" {{< /clients-example >}} @@ -647,22 +647,22 @@ XAUTOCLAIM [COUNT count] [JUSTI So, in the example above, I could have used automatic claiming to claim a single message like this: {{< clients-example stream_toturial xautoclaim >}} -> XAUTOCLAIM race:italy italy_racers Alice 60000 0-0 COUNT 1 -1) "1691766261145-0" -2) 1) 1) "1691766256307-0" - 2) 1) "racer" - 2) "Royce" +> XAUTOCLAIM race:italy italy_riders Alice 60000 0-0 COUNT 1 +1) "0-0" +2) 1) 1) "1692632662819-0" + 2) 1) "rider" + 2) "Sam-Bodden" {{< /clients-example >}} Like `XCLAIM`, the command replies with an array of the claimed messages, but it also returns a stream ID that allows iterating the pending entries. The stream ID is a cursor, and I can use it in my next call to continue in claiming idle pending messages: {{< clients-example stream_toturial xautoclaim_cursor >}} -> XAUTOCLAIM race:italy italy_racers Lora 60000 1526569498055-0 COUNT 1 -1) "0-0" -2) 1) 1) "1691766261145-0" - 2) 1) "racer" - 2) "Sam-Bodden" +> XAUTOCLAIM race:italy italy_riders Lora 60000 (1692632662819-0 COUNT 1 +1) "1692632662819-0" +2) 1) 1) "1692632647899-0" + 2) 1) "rider" + 2) "Royce" {{< /clients-example >}} When `XAUTOCLAIM` returns the "0-0" stream ID as a cursor, that means that it reached the end of the consumer group pending entries list. @@ -691,16 +691,16 @@ This command uses subcommands in order to show different information about the s 5) "radix-tree-nodes" 6) (integer) 2 7) "last-generated-id" - 8) "1691766698493-0" + 8) "1692632678249-0" 9) "groups" 10) (integer) 1 11) "first-entry" -12) 1) "1691766245113-0" - 2) 1) "racer" +12) 1) "1692632639151-0" + 2) 1) "rider" 2) "Castilla" 13) "last-entry" -14) 1) "1691766698493-0" - 2) 1) "racer" +14) 1) "1692632678249-0" + 2) 1) "rider" 2) "Norem" {{< /clients-example >}} @@ -709,13 +709,13 @@ The output shows information about how the stream is encoded internally, and als {{< clients-example stream_toturial xinfo_groups >}} > XINFO GROUPS race:italy 1) 1) "name" - 2) "italy_racers" + 2) "italy_riders" 3) "consumers" 4) (integer) 3 5) "pending" 6) (integer) 2 7) "last-delivered-id" - 8) "1691766261145-0" + 8) "1692632662819-0" {{< /clients-example >}} As you can see in this and in the previous output, the `XINFO` command outputs a sequence of field-value items. Because it is an observability command this allows the human user to immediately understand what information is reported, and allows the command to report more information in the future by adding more fields without breaking compatibility with older clients. Other commands that must be more bandwidth efficient, like `XPENDING`, just report the information without the field names. @@ -723,25 +723,25 @@ As you can see in this and in the previous output, the `XINFO` command outputs a The output of the example above, where the **GROUPS** subcommand is used, should be clear observing the field names. We can check in more detail the state of a specific consumer group by checking the consumers that are registered in the group. {{< clients-example stream_toturial xinfo_consumers >}} -> XINFO CONSUMERS race:italy italy_racers +> XINFO CONSUMERS race:italy italy_riders 1) 1) "name" 2) "Alice" 3) "pending" 4) (integer) 1 5) "idle" - 6) (integer) 130215 + 6) (integer) 177546 2) 1) "name" 2) "Bob" 3) "pending" 4) (integer) 0 5) "idle" - 6) (integer) 2581506 + 6) (integer) 424686 3) 1) "name" 2) "Lora" 3) "pending" 4) (integer) 1 5) "idle" - 6) (integer) 102218 + 6) (integer) 72241 {{< /clients-example >}} In case you do not remember the syntax of the command, just ask the command itself for help: @@ -780,20 +780,20 @@ So basically Kafka partitions are more similar to using N different Redis keys, Many applications do not want to collect data into a stream forever. Sometimes it is useful to have at maximum a given number of items inside a stream, other times once a given size is reached, it is useful to move data from Redis to a storage which is not in memory and not as fast but suited to store the history for, potentially, decades to come. Redis streams have some support for this. One is the **MAXLEN** option of the `XADD` command. This option is very simple to use: {{< clients-example stream_tutorial maxlen >}} -> XADD race:italy MAXLEN 2 * racer Jones -"1691769379388-0" -> XADD race:italy MAXLEN 2 * racer Wood -"1691769438199-0" -> XADD race:italy MAXLEN 2 * racer Henshaw -"1691769502417-0" +> XADD race:italy MAXLEN 2 * rider Jones +"1692633189161-0" +> XADD race:italy MAXLEN 2 * rider Wood +"1692633198206-0" +> XADD race:italy MAXLEN 2 * rider Henshaw +"1692633208557-0" > XLEN race:italy (integer) 2 > XRANGE race:italy - + -1) 1) "1691769438199-0" - 2) 1) "racer" +1) 1) "1692633198206-0" + 2) 1) "rider" 2) "Wood" -2) 1) "1691769502417-0" - 2) 1) "racer" +2) 1) "1692633208557-0" + 2) 1) "rider" 2) "Henshaw" {{< /clients-example >}} @@ -805,18 +805,20 @@ However trimming with **MAXLEN** can be expensive: streams are represented by ma XADD race:italy MAXLEN ~ 1000 * ... entry fields here ... ``` -The `~` argument between the **MAXLEN** option and the actual count means, I don't really need this to be exactly 1000 items. It can be 1000 or 1010 or 1030, just make sure to save at least 1000 items. With this argument, the trimming is performed only when we can remove a whole node. This makes it much more efficient, and it is usually what you want. +The `~` argument between the **MAXLEN** option and the actual count means, I don't really need this to be exactly 1000 items. It can be 1000 or 1010 or 1030, just make sure to save at least 1000 items. With this argument, the trimming is performed only when we can remove a whole node. This makes it much more efficient, and it is usually what you want. You'll note here that the client libraries have various implementations of this; for example the Python client defaults to approximate and has to explicitly be set to a true length. There is also the `XTRIM` command, which performs something very similar to what the **MAXLEN** option does above, except that it can be run by itself: {{< clients-example stream_tutorial xtrim >}} > XTRIM race:italy MAXLEN 10 +(integer) 0 {{< /clients-example >}} Or, as for the `XADD` option: {{< clients-example stream_tutorial xtrim2 >}} > XTRIM mystream MAXLEN ~ 10 +(integer) 0 {{< /clients-example >}} However, `XTRIM` is designed to accept different trimming strategies. Another trimming strategy is **MINID**, that evicts entries with IDs lower than the one specified. @@ -859,17 +861,17 @@ Streams also have a special command for removing items from the middle of a stre {{< clients-example stream_tutorial xdel >}} > XRANGE race:italy - + COUNT 2 -1) 1) "1691769438199-0" - 2) 1) "racer" +1) 1) "1692633198206-0" + 2) 1) "rider" 2) "Wood" -2) 1) "1691769502417-0" - 2) 1) "racer" +2) 1) "1692633208557-0" + 2) 1) "rider" 2) "Henshaw" -> XDEL race:italy 1691769502417-0 +> XDEL race:italy 1692633208557-0 (integer) 1 > XRANGE race:italy - + COUNT 2 -1) 1) "1691769438199-0" - 2) 1) "racer" +1) 1) "1692633198206-0" + 2) 1) "rider" 2) "Wood" {{< /clients-example >}} From 4ee5a0c12cb424d7c1083fb4bd6d3b2fdb0d91cc Mon Sep 17 00:00:00 2001 From: Savannah Date: Tue, 22 Aug 2023 10:30:26 -0400 Subject: [PATCH 273/377] address feedback from PR + spelling tutorial correctly --- docs/data-types/streams.md | 60 +++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/data-types/streams.md b/docs/data-types/streams.md index 9371f5cabb..9ca9041527 100644 --- a/docs/data-types/streams.md +++ b/docs/data-types/streams.md @@ -118,7 +118,7 @@ The format of such IDs may look strange at first, and the gentle reader may wond If for some reason the user needs incremental IDs that are not related to time but are actually associated to another external system ID, as previously mentioned, the `XADD` command can take an explicit ID instead of the `*` wildcard ID that triggers auto-generation, like in the following examples: -{{< clients-example stream_toturial xadd_id >}} +{{< clients-example stream_tutorial xadd_id >}} > XADD race:usa 0-1 racer Castilla 0-1 > XADD race:usa 0-2 racer Norem @@ -127,14 +127,14 @@ If for some reason the user needs incremental IDs that are not related to time b Note that in this case, the minimum ID is 0-1 and that the command will not accept an ID equal or smaller than a previous one: -{{< clients-example stream_toturial xadd_bad_id >}} +{{< clients-example stream_tutorial xadd_bad_id >}} > XADD race:usa 0-1 racer Prickett (error) ERR The ID specified in XADD is equal or smaller than the target stream top item {{< /clients-example >}} If you're running Redis 7 or later, you can also provide an explicit ID consisting of the milliseconds part only. In this case, the sequence portion of the ID will be automatically generated. To do this, use the syntax below: -{{< clients-example stream_toturial xadd_7 >}} +{{< clients-example stream_tutorial xadd_7 >}} > XADD race:usa 0-* racer Prickett 0-3 {{< /clients-example >}} @@ -153,7 +153,7 @@ Redis Streams support all three of the query modes described above via different To query the stream by range we are only required to specify two IDs, *start* and *end*. The range returned will include the elements having start or end as ID, so the range is inclusive. The two special IDs `-` and `+` respectively mean the smallest and the greatest ID possible. -{{< clients-example stream_toturial xrange_all >}} +{{< clients-example stream_tutorial xrange_all >}} > XRANGE race:france - + 1) 1) "1692632086370-0" 2) 1) "rider" @@ -195,7 +195,7 @@ To query the stream by range we are only required to specify two IDs, *start* an Each entry returned is an array of two items: the ID and the list of field-value pairs. We already said that the entry IDs have a relation with the time, because the part at the left of the `-` character is the Unix time in milliseconds of the local node that created the stream entry, at the moment the entry was created (however note that streams are replicated with fully specified `XADD` commands, so the replicas will have identical IDs to the master). This means that I could query a range of time using `XRANGE`. In order to do so, however, I may want to omit the sequence part of the ID: if omitted, in the start of the range it will be assumed to be 0, while in the end part it will be assumed to be the maximum sequence number available. This way, querying using just two milliseconds Unix times, we get all the entries that were generated in that range of time, in an inclusive way. For instance, if I want to query a two milliseconds period I could use: -{{< clients-example stream_toturial xrange_time >}} +{{< clients-example stream_tutorial xrange_time >}} > XRANGE race:france 1692632086369 1692632086371 1) 1) "1692632086370-0" 2) 1) "rider" @@ -208,9 +208,9 @@ Each entry returned is an array of two items: the ID and the list of field-value 8) "1" {{< /clients-example >}} -I have only a single entry in this range, however in real data sets, I could query for ranges of hours, or there could be many items in just two milliseconds, and the result returned could be huge. For this reason, `XRANGE` supports an optional **COUNT** option at the end. By specifying a count, I can just get the first *N* items. If I want more, I can get the last ID returned, increment the sequence part by one, and query again. Let's see this in the following example. Let's assume that the stream `race:france` was populated with 4 items. To start my iteration, getting 2 items per command, I start with the full range, but with a count of 2. +I have only a single entry in this range. However in real data sets, I could query for ranges of hours, or there could be many items in just two milliseconds, and the result returned could be huge. For this reason, `XRANGE` supports an optional **COUNT** option at the end. By specifying a count, I can just get the first *N* items. If I want more, I can get the last ID returned, increment the sequence part by one, and query again. Let's see this in the following example. Let's assume that the stream `race:france` was populated with 4 items. To start my iteration, getting 2 items per command, I start with the full range, but with a count of 2. -{{< clients-example stream_toturial xrange_step_1 >}} +{{< clients-example stream_tutorial xrange_step_1 >}} > XRANGE race:france - + COUNT 2 1) 1) "1692632086370-0" 2) 1) "rider" @@ -232,9 +232,9 @@ I have only a single entry in this range, however in real data sets, I could que 8) "1" {{< /clients-example >}} -In order to continue the iteration with the next two items, I have to pick the last ID returned, that is `1692632094485-0` and add the prefix `(` to it. The resulting exclusive range interval, that is `(1692632094485-0` in this case, can now be used as the new *start* argument for the next `XRANGE` call: +To continue the iteration with the next two items, I have to pick the last ID returned, that is `1692632094485-0`, and add the prefix `(` to it. The resulting exclusive range interval, that is `(1692632094485-0` in this case, can now be used as the new *start* argument for the next `XRANGE` call: -{{< clients-example stream_toturial xrange_step_2 >}} +{{< clients-example stream_tutorial xrange_step_2 >}} > XRANGE race:france (1692632094485-0 + COUNT 2 1) 1) "1692632102976-0" 2) 1) "rider" @@ -256,9 +256,9 @@ In order to continue the iteration with the next two items, I have to pick the l 8) "2" {{< /clients-example >}} -Now that we've gotten 4 items out of a stream that only had 4 things in it, if we try to get more items, we'll get an empty array: +Now that we've retrieved 4 items out of a stream that only had 4 entries in it, if we try to retrieve more items, we'll get an empty array: -{{< clients-example stream_toturial xrange_empty >}} +{{< clients-example stream_tutorial xrange_empty >}} > XRANGE race:france (1692632147973-0 + COUNT 2 (empty array) {{< /clients-example >}} @@ -267,7 +267,7 @@ Since `XRANGE` complexity is *O(log(N))* to seek, and then *O(M)* to return M el The command `XREVRANGE` is the equivalent of `XRANGE` but returning the elements in inverted order, so a practical use for `XREVRANGE` is to check what is the last item in a Stream: -{{< clients-example stream_toturial xrevrange >}} +{{< clients-example stream_tutorial xrevrange >}} > XREVRANGE race:france + - COUNT 1 1) 1) "1692632147973-0" 2) 1) "rider" @@ -292,7 +292,7 @@ When we do not want to access items by a range in a stream, usually what we want The command that provides the ability to listen for new messages arriving into a stream is called `XREAD`. It's a bit more complex than `XRANGE`, so we'll start showing simple forms, and later the whole command layout will be provided. -{{< clients-example stream_toturial xread >}} +{{< clients-example stream_tutorial xread >}} > XREAD COUNT 2 STREAMS race:france 0 1) 1) "race:france" 2) 1) 1) "1692632086370-0" @@ -391,7 +391,7 @@ Now it's time to zoom in to see the fundamental consumer group commands. They ar Assuming I have a key `race:france` of type stream already existing, in order to create a consumer group I just need to do the following: -{{< clients-example stream_toturial xgroup_create >}} +{{< clients-example stream_tutorial xgroup_create >}} > XGROUP CREATE race:france france_riders $ OK {{< /clients-example >}} @@ -400,7 +400,7 @@ As you can see in the command above when creating the consumer group we have to `XGROUP CREATE` also supports creating the stream automatically, if it doesn't exist, using the optional `MKSTREAM` subcommand as the last argument: -{{< clients-example stream_toturial xgroup_create_mkstream >}} +{{< clients-example stream_tutorial xgroup_create_mkstream >}} > XGROUP CREATE race:italy italy_riders $ MKSTREAM OK {{< /clients-example >}} @@ -410,9 +410,9 @@ Now that the consumer group is created we can immediately try to read messages v `XREADGROUP` is very similar to `XREAD` and provides the same **BLOCK** option, otherwise it is a synchronous command. However there is a *mandatory* option that must be always specified, which is **GROUP** and has two arguments: the name of the consumer group, and the name of the consumer that is attempting to read. The option **COUNT** is also supported and is identical to the one in `XREAD`. We'll add riders to the race:italy stream and try reading something using the consumer group: -Note: *here rider is the field name, and the name is the associated value, remember that stream items are small dictionaries.* +Note: *here rider is the field name, and the name is the associated value. Remember that stream items are small dictionaries.* -{{< clients-example stream_toturial xgroup_read >}} +{{< clients-example stream_tutorial xgroup_read >}} > XADD race:italy * rider Castilla "1692632639151-0" > XADD race:italy * rider Royce @@ -441,7 +441,7 @@ This is almost always what you want, however it is also possible to specify a re We can test this behavior immediately specifying an ID of 0, without any **COUNT** option: we'll just see the only pending message, that is, the one about apples: -{{< clients-example stream_toturial xgroup_read_id >}} +{{< clients-example stream_tutorial xgroup_read_id >}} > XREADGROUP GROUP italy_riders Alice STREAMS race:italy 0 1) 1) "race:italy" 2) 1) 1) "1692632639151-0" @@ -451,7 +451,7 @@ We can test this behavior immediately specifying an ID of 0, without any **COUNT However, if we acknowledge the message as processed, it will no longer be part of the pending messages history, so the system will no longer report anything: -{{< clients-example stream_toturial xack >}} +{{< clients-example stream_tutorial xack >}} > XACK race:italy italy_riders 1692632639151-0 (integer) 1 > XREADGROUP GROUP italy_riders Alice STREAMS race:italy 0 @@ -463,7 +463,7 @@ Don't worry if you yet don't know how `XACK` works, the idea is just that proces Now it's Bob's turn to read something: -{{< clients-example stream_toturial xgroup_read_bob >}} +{{< clients-example stream_tutorial xgroup_read_bob >}} > XREADGROUP GROUP italy_riders Bob COUNT 2 STREAMS race:italy > 1) 1) "race:italy" 2) 1) 1) "1692632647899-0" @@ -555,7 +555,7 @@ The first step of this process is just a command that provides observability of This is a read-only command which is always safe to call and will not change ownership of any message. In its simplest form, the command is called with two arguments, which are the name of the stream and the name of the consumer group. -{{< clients-example stream_toturial xpending >}} +{{< clients-example stream_tutorial xpending >}} > XPENDING race:italy italy_riders 1) (integer) 2 2) "1692632647899-0" @@ -575,7 +575,7 @@ XPENDING [[IDLE ] [ By providing a start and end ID (that can be just `-` and `+` as in `XRANGE`) and a count to control the amount of information returned by the command, we are able to know more about the pending messages. The optional final argument, the consumer name, is used if we want to limit the output to just messages pending for a given consumer, but won't use this feature in the following example. -{{< clients-example stream_toturial xpending_plus_minus >}} +{{< clients-example stream_tutorial xpending_plus_minus >}} > XPENDING race:italy italy_riders - + 10 1) 1) "1692632647899-0" 2) "Bob" @@ -592,7 +592,7 @@ We have two messages from Bob, and they are idle for 60000+ milliseconds, about Note that nobody prevents us from checking what the first message content was by just using `XRANGE`. -{{< clients-example stream_toturial xrange_pending >}} +{{< clients-example stream_tutorial xrange_pending >}} > XRANGE race:italy 1692632647899-0 1692632647899-0 1) 1) "1692632647899-0" 2) 1) "rider" @@ -618,7 +618,7 @@ However, as a side effect, claiming a message will reset its idle time and will This is the result of the command execution: -{{< clients-example stream_toturial xclaim >}} +{{< clients-example stream_tutorial xclaim >}} > XCLAIM race:italy italy_riders Alice 60000 1692632647899-0 1) 1) "1692632647899-0" 2) 1) "rider" @@ -646,7 +646,7 @@ XAUTOCLAIM [COUNT count] [JUSTI So, in the example above, I could have used automatic claiming to claim a single message like this: -{{< clients-example stream_toturial xautoclaim >}} +{{< clients-example stream_tutorial xautoclaim >}} > XAUTOCLAIM race:italy italy_riders Alice 60000 0-0 COUNT 1 1) "0-0" 2) 1) 1) "1692632662819-0" @@ -657,7 +657,7 @@ So, in the example above, I could have used automatic claiming to claim a single Like `XCLAIM`, the command replies with an array of the claimed messages, but it also returns a stream ID that allows iterating the pending entries. The stream ID is a cursor, and I can use it in my next call to continue in claiming idle pending messages: -{{< clients-example stream_toturial xautoclaim_cursor >}} +{{< clients-example stream_tutorial xautoclaim_cursor >}} > XAUTOCLAIM race:italy italy_riders Lora 60000 (1692632662819-0 COUNT 1 1) "1692632662819-0" 2) 1) 1) "1692632647899-0" @@ -682,7 +682,7 @@ However we may want to do more than that, and the `XINFO` command is an observab This command uses subcommands in order to show different information about the status of the stream and its consumer groups. For instance **XINFO STREAM ** reports information about the stream itself. -{{< clients-example stream_toturial xinfo >}} +{{< clients-example stream_tutorial xinfo >}} > XINFO STREAM race:italy 1) "length" 2) (integer) 5 @@ -706,7 +706,7 @@ This command uses subcommands in order to show different information about the s The output shows information about how the stream is encoded internally, and also shows the first and last message in the stream. Another piece of information available is the number of consumer groups associated with this stream. We can dig further asking for more information about the consumer groups. -{{< clients-example stream_toturial xinfo_groups >}} +{{< clients-example stream_tutorial xinfo_groups >}} > XINFO GROUPS race:italy 1) 1) "name" 2) "italy_riders" @@ -722,7 +722,7 @@ As you can see in this and in the previous output, the `XINFO` command outputs a The output of the example above, where the **GROUPS** subcommand is used, should be clear observing the field names. We can check in more detail the state of a specific consumer group by checking the consumers that are registered in the group. -{{< clients-example stream_toturial xinfo_consumers >}} +{{< clients-example stream_tutorial xinfo_consumers >}} > XINFO CONSUMERS race:italy italy_riders 1) 1) "name" 2) "Alice" @@ -805,7 +805,7 @@ However trimming with **MAXLEN** can be expensive: streams are represented by ma XADD race:italy MAXLEN ~ 1000 * ... entry fields here ... ``` -The `~` argument between the **MAXLEN** option and the actual count means, I don't really need this to be exactly 1000 items. It can be 1000 or 1010 or 1030, just make sure to save at least 1000 items. With this argument, the trimming is performed only when we can remove a whole node. This makes it much more efficient, and it is usually what you want. You'll note here that the client libraries have various implementations of this; for example the Python client defaults to approximate and has to explicitly be set to a true length. +The `~` argument between the **MAXLEN** option and the actual count means, I don't really need this to be exactly 1000 items. It can be 1000 or 1010 or 1030, just make sure to save at least 1000 items. With this argument, the trimming is performed only when we can remove a whole node. This makes it much more efficient, and it is usually what you want. You'll note here that the client libraries have various implementations of this, For example, the Python client defaults to approximate and has to be explicitly set to a true length. There is also the `XTRIM` command, which performs something very similar to what the **MAXLEN** option does above, except that it can be run by itself: From cd2e477991f98ddf47a65947298fb609407015d7 Mon Sep 17 00:00:00 2001 From: Savannah Date: Tue, 22 Aug 2023 10:39:35 -0400 Subject: [PATCH 274/377] Update docs/data-types/streams.md Co-authored-by: David Dougherty --- docs/data-types/streams.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/streams.md b/docs/data-types/streams.md index 9ca9041527..378c99cd76 100644 --- a/docs/data-types/streams.md +++ b/docs/data-types/streams.md @@ -805,7 +805,7 @@ However trimming with **MAXLEN** can be expensive: streams are represented by ma XADD race:italy MAXLEN ~ 1000 * ... entry fields here ... ``` -The `~` argument between the **MAXLEN** option and the actual count means, I don't really need this to be exactly 1000 items. It can be 1000 or 1010 or 1030, just make sure to save at least 1000 items. With this argument, the trimming is performed only when we can remove a whole node. This makes it much more efficient, and it is usually what you want. You'll note here that the client libraries have various implementations of this, For example, the Python client defaults to approximate and has to be explicitly set to a true length. +The `~` argument between the **MAXLEN** option and the actual count means, I don't really need this to be exactly 1000 items. It can be 1000 or 1010 or 1030, just make sure to save at least 1000 items. With this argument, the trimming is performed only when we can remove a whole node. This makes it much more efficient, and it is usually what you want. You'll note here that the client libraries have various implementations of this. For example, the Python client defaults to approximate and has to be explicitly set to a true length. There is also the `XTRIM` command, which performs something very similar to what the **MAXLEN** option does above, except that it can be run by itself: From 56bcaac7d7b3a18e9b669095673250d7641a2dba Mon Sep 17 00:00:00 2001 From: Rajiv Harlalka Date: Wed, 6 Sep 2023 21:26:01 +0530 Subject: [PATCH 275/377] Remove extra closing braces on protocol spec page (#2526) --- docs/reference/protocol-spec.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/protocol-spec.md b/docs/reference/protocol-spec.md index bbb9f331cc..bd4b6d1dff 100644 --- a/docs/reference/protocol-spec.md +++ b/docs/reference/protocol-spec.md @@ -356,7 +356,7 @@ Due to historical reasons, RESP2 features two specially crafted values for repre This duality has always been a redundancy that added zero semantical value to the protocol itself. The null type, introduced in RESP3, aims to fix this wrong. -{{% /alert %}}}} +{{% /alert %}} From b91cd8b4a3c979e21ae0b1502c80543713a470ea Mon Sep 17 00:00:00 2001 From: Oran Agra Date: Wed, 6 Sep 2023 21:09:54 +0300 Subject: [PATCH 276/377] update commands.json from redis 7.2.1 --- commands.json | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/commands.json b/commands.json index 268c9bfd5c..aca624b567 100644 --- a/commands.json +++ b/commands.json @@ -56,6 +56,10 @@ "noscript", "loading", "stale" + ], + "hints": [ + "request_policy:all_nodes", + "response_policy:all_succeeded" ] }, "ACL DRYRUN": { @@ -263,6 +267,10 @@ "noscript", "loading", "stale" + ], + "hints": [ + "request_policy:all_nodes", + "response_policy:all_succeeded" ] }, "ACL SETUSER": { @@ -305,6 +313,10 @@ "noscript", "loading", "stale" + ], + "hints": [ + "request_policy:all_nodes", + "response_policy:all_succeeded" ] }, "ACL USERS": { @@ -2169,6 +2181,10 @@ "noscript", "loading", "stale" + ], + "hints": [ + "request_policy:all_nodes", + "response_policy:all_succeeded" ] }, "CLIENT SETNAME": { @@ -2192,6 +2208,10 @@ "noscript", "loading", "stale" + ], + "hints": [ + "request_policy:all_nodes", + "response_policy:all_succeeded" ] }, "CLIENT TRACKING": { @@ -3359,6 +3379,10 @@ "noscript", "loading", "stale" + ], + "hints": [ + "request_policy:all_nodes", + "response_policy:all_succeeded" ] }, "CONFIG REWRITE": { @@ -3377,6 +3401,10 @@ "noscript", "loading", "stale" + ], + "hints": [ + "request_policy:all_nodes", + "response_policy:all_succeeded" ] }, "CONFIG SET": { @@ -8088,7 +8116,7 @@ ], "hints": [ "request_policy:all_nodes", - "response_policy:all_succeeded" + "response_policy:agg_sum" ] }, "LCS": { From 22c3609f955b147b87b5d8f4d9f869fe73d96d02 Mon Sep 17 00:00:00 2001 From: "David W. Dougherty" Date: Wed, 13 Sep 2023 08:05:28 -0700 Subject: [PATCH 277/377] Add RC as option in main get started page + minor title fix --- docs/getting-started/_index.md | 4 +++- docs/management/scaling.md | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/getting-started/_index.md b/docs/getting-started/_index.md index 8a97629bcc..910ba89353 100644 --- a/docs/getting-started/_index.md +++ b/docs/getting-started/_index.md @@ -12,6 +12,8 @@ aliases: This is a guide to getting started with Redis. You'll learn how to install, run, and experiment with the Redis server process. +While you can install Redis on any of the platforms listed below, you might also consider using Redis Cloud by creating a [free account](https://docs.redis.com/latest/rc/rc-quickstart/). + ## Install Redis How you install Redis depends on your operating system and whether you'd like to install it bundled with Redis Stack and Redis UI. See the guide below that best fits your needs: @@ -139,4 +141,4 @@ Make sure that everything is working as expected: Note: The above instructions don't include all of the Redis configuration parameters that you could change, for instance, to use AOF persistence instead of RDB persistence, or to set up replication, and so forth. Make sure to read the example [`redis.conf`](https://github.com/redis/redis/blob/6.2/redis.conf) file (that is heavily commented). -
\ No newline at end of file +
diff --git a/docs/management/scaling.md b/docs/management/scaling.md index bb47574241..f847ab78f2 100644 --- a/docs/management/scaling.md +++ b/docs/management/scaling.md @@ -1,6 +1,6 @@ --- -title: Scaling with Redis Cluster -linkTitle: Scaling +title: Scale with Redis Cluster +linkTitle: Scale with Redis Cluster weight: 6 description: Horizontal scaling with Redis Cluster aliases: [ From 06107e844ab7d24d9093ba695d38cc601b88019f Mon Sep 17 00:00:00 2001 From: Savannah Date: Fri, 15 Sep 2023 13:51:32 -0400 Subject: [PATCH 278/377] Update sorted-sets.md to use bike racing story and hugo short codes --- docs/data-types/sorted-sets.md | 241 ++++++++++++++------------------- 1 file changed, 102 insertions(+), 139 deletions(-) diff --git a/docs/data-types/sorted-sets.md b/docs/data-types/sorted-sets.md index a43fdbb0b8..156480c5d9 100644 --- a/docs/data-types/sorted-sets.md +++ b/docs/data-types/sorted-sets.md @@ -1,4 +1,4 @@ ---- +--- title: "Redis sorted sets" linkTitle: "Sorted sets" weight: 50 @@ -29,27 +29,16 @@ represent sorted sets). They are ordered according to the following rule: * If B and A are two elements with a different score, then A > B if A.score is > B.score. * If B and A have exactly the same score, then A > B if the A string is lexicographically greater than the B string. B and A strings can't be equal since sorted sets only have unique elements. -Let's start with a simple example, adding a few selected hackers names as -sorted set elements, with their year of birth as "score". - - > zadd hackers 1940 "Alan Kay" - (integer) 1 - > zadd hackers 1957 "Sophie Wilson" - (integer) 1 - > zadd hackers 1953 "Richard Stallman" - (integer) 1 - > zadd hackers 1949 "Anita Borg" - (integer) 1 - > zadd hackers 1965 "Yukihiro Matsumoto" - (integer) 1 - > zadd hackers 1914 "Hedy Lamarr" - (integer) 1 - > zadd hackers 1916 "Claude Shannon" - (integer) 1 - > zadd hackers 1969 "Linus Torvalds" - (integer) 1 - > zadd hackers 1912 "Alan Turing" - (integer) 1 +Let's start with a simple example, we'll add all our racers and the score they got in the first race: + +{{< clients-example ss_tutorial zadd >}} +> ZADD racer_scores 10 "Norem" +(integer) 1 +> ZADD racer_scores 12 "Castilla" +(integer) 1 +> ZADD racer_scores 8 "Sam-Bodden" 10 "Royce" 6 "Ford" 14 "Prickett" +(integer) 4 +{{ /clients-example> }} As you can see `ZADD` is similar to `SADD`, but takes one additional argument @@ -64,93 +53,94 @@ Implementation note: Sorted sets are implemented via a dual-ported data structure containing both a skip list and a hash table, so every time we add an element Redis performs an O(log(N)) operation. That's good, but when we ask for sorted elements Redis does not have to do any work at -all, it's already all sorted: - - > zrange hackers 0 -1 - 1) "Alan Turing" - 2) "Hedy Lamarr" - 3) "Claude Shannon" - 4) "Alan Kay" - 5) "Anita Borg" - 6) "Richard Stallman" - 7) "Sophie Wilson" - 8) "Yukihiro Matsumoto" - 9) "Linus Torvalds" +all, it's already all sorted. Note that the `ZRANGE` order is low to high, while the `ZREVRANGE` order is high to low: + +{{< clients-example ss_tutorial zrange >}} +> ZRANGE racer_scores 0 -1 +1) "Ford" +2) "Sam-Bodden" +3) "Norem" +4) "Royce" +5) "Castilla" +6) "Prickett" +> ZREVRANGE racer_scores 0 -1 +1) "Prickett" +2) "Castilla" +3) "Royce" +4) "Norem" +5) "Sam-Bodden" +6) "Ford" +{{ /clients-example> }} Note: 0 and -1 means from element index 0 to the last element (-1 works here just as it does in the case of the `LRANGE` command). -What if I want to order them the opposite way, youngest to oldest? -Use `ZREVRANGE` instead of `ZRANGE`: - - > zrevrange hackers 0 -1 - 1) "Linus Torvalds" - 2) "Yukihiro Matsumoto" - 3) "Sophie Wilson" - 4) "Richard Stallman" - 5) "Anita Borg" - 6) "Alan Kay" - 7) "Claude Shannon" - 8) "Hedy Lamarr" - 9) "Alan Turing" - It is possible to return scores as well, using the `WITHSCORES` argument: - > zrange hackers 0 -1 withscores - 1) "Alan Turing" - 2) "1912" - 3) "Hedy Lamarr" - 4) "1914" - 5) "Claude Shannon" - 6) "1916" - 7) "Alan Kay" - 8) "1940" - 9) "Anita Borg" - 10) "1949" - 11) "Richard Stallman" - 12) "1953" - 13) "Sophie Wilson" - 14) "1957" - 15) "Yukihiro Matsumoto" - 16) "1965" - 17) "Linus Torvalds" - 18) "1969" +{{< clients-example ss_tutorial zrange_withscores >}} +> ZRANGE racer_scores 0 -1 withscores + 1) "Ford" + 2) "6" + 3) "Sam-Bodden" + 4) "8" + 5) "Norem" + 6) "10" + 7) "Royce" + 8) "10" + 9) "Castilla" +10) "12" +11) "Prickett" +12) "14" +{{ /clients-example> }} ### Operating on ranges Sorted sets are more powerful than this. They can operate on ranges. -Let's get all the individuals that were born up to 1950 inclusive. We +Let's get all the racers with 10 or fewer points. We use the `ZRANGEBYSCORE` command to do it: - > zrangebyscore hackers -inf 1950 - 1) "Alan Turing" - 2) "Hedy Lamarr" - 3) "Claude Shannon" - 4) "Alan Kay" - 5) "Anita Borg" +{{< clients-example ss_tutorial zrangebyscore >}} +> ZRANGEBYSCORE racer_scores -inf 10 +1) "Ford" +2) "Sam-Bodden" +3) "Norem" +4) "Royce" +{{ /clients-example> }} We asked Redis to return all the elements with a score between negative -infinity and 1950 (both extremes are included). +infinity and 10 (both extremes are included). -It's also possible to remove ranges of elements. Let's remove all -the hackers born between 1940 and 1960 from the sorted set: +To remove an element we'd simply call `ZREM` with the racers name. +It's also possible to remove ranges of elements. Let's remove racer Castilla along with all +the racers with strictly fewer than 10 points: - > zremrangebyscore hackers 1940 1960 - (integer) 4 +{{< clients-example ss_tutorial zremrangebyscore >}} +> ZREM racer_scores "Castilla" +(integer) 1 +> ZREMRANGEBYSCORE racer_scores -inf 9 +(integer) 2 +> ZRANGE racer_scores 0 -1 +1) "Norem" +2) "Royce" +3) "Prickett" +{{ /clients-example> }} `ZREMRANGEBYSCORE` is perhaps not the best command name, but it can be very useful, and returns the number of removed elements. Another extremely useful operation defined for sorted set elements is the get-rank operation. It is possible to ask what is the -position of an element in the set of the ordered elements. - - > zrank hackers "Anita Borg" - (integer) 4 - +position of an element in the set of the ordered elements. The `ZREVRANK` command is also available in order to get the rank, considering the elements sorted a descending way. +{{< clients-example ss_tutorial zrank >}} +> ZRANK racer_scores "Norem" +(integer) 0 +> ZREVRANK racer_scores "Norem" +(integer) 3 +{{ /clients-example> }} + ### Lexicographical scores In version Redis 2.8, a new feature was introduced that allows @@ -163,32 +153,22 @@ The main commands to operate with lexicographical ranges are `ZRANGEBYLEX`, `ZREVRANGEBYLEX`, `ZREMRANGEBYLEX` and `ZLEXCOUNT`. For example, let's add again our list of famous hackers, but this time -use a score of zero for all the elements: - - > zadd hackers 0 "Alan Kay" 0 "Sophie Wilson" 0 "Richard Stallman" 0 - "Anita Borg" 0 "Yukihiro Matsumoto" 0 "Hedy Lamarr" 0 "Claude Shannon" - 0 "Linus Torvalds" 0 "Alan Turing" - -Because of the sorted sets ordering rules, they are already sorted -lexicographically: - - > zrange hackers 0 -1 - 1) "Alan Kay" - 2) "Alan Turing" - 3) "Anita Borg" - 4) "Claude Shannon" - 5) "Hedy Lamarr" - 6) "Linus Torvalds" - 7) "Richard Stallman" - 8) "Sophie Wilson" - 9) "Yukihiro Matsumoto" - -Using `ZRANGEBYLEX` we can ask for lexicographical ranges: - - > zrangebylex hackers [B [P - 1) "Claude Shannon" - 2) "Hedy Lamarr" - 3) "Linus Torvalds" +use a score of zero for all the elements. We'll see that because of the sorted sets ordering rules, they are already sorted lexicographically. Using `ZRANGEBYLEX` we can ask for lexicographical ranges: + +{{< clients-example ss_tutorial zadd_lex >}} +> ZADD racer_scores 0 "Norem" 0 "Sam-Bodden" 0 "Royce" 0 "Castilla" 0 "Prickett" 0 "Ford" +(integer) 3 +> ZRANGE racer_scores 0 -1 +1) "Castilla" +2) "Ford" +3) "Norem" +4) "Prickett" +5) "Royce" +6) "Sam-Bodden" +> ZRANGEBYLEX racer_scores [A [L +1) "Castilla" +2) "Ford" +{{ /clients-example> }} Ranges can be inclusive or exclusive (depending on the first character), also string infinite and minus infinite are specified respectively with @@ -223,38 +203,21 @@ the #4932 best score here"). ## Examples -* Update a real-time leaderboard as players' scores change: -``` -> ZADD leaderboard:455 100 user:1 -(integer) 1 -> ZADD leaderboard:455 75 user:2 -(integer) 1 -> ZADD leaderboard:455 101 user:3 +* There are two ways we can use a sorted set to represent a leaderbaord. If we know a racers new score, we can update it directly via the `ZADD` command. However if we want to add points to an existing score, we can use the `ZINCRBY` command. +{{< clients-example ss_tutorial leaderboard >}} +> ZADD racer_scores 100 "Wood" (integer) 1 -> ZADD leaderboard:455 15 user:4 +> ZADD racer_scores 100 "Henshaw" (integer) 1 -> ZADD leaderboard:455 275 user:2 +> ZADD racer_scores 150 "Henshaw" (integer) 0 -``` - -Notice that `user:2`'s score is updated in the final `ZADD` call. - -* Get the top 3 players' scores: -``` -> ZRANGE leaderboard:455 0 2 REV WITHSCORES -1) "user:2" -2) "275" -3) "user:3" -4) "101" -5) "user:1" -6) "100" -``` - -* What's the rank of user 2? -``` -> ZREVRANK leaderboard:455 user:2 -(integer) 0 -``` +> ZINCRBY racer_scores 50 "Wood" +"150" +> ZINCRBY racer_scores 50 "Henshaw" +"200" +{{ /clients-example> }} + +You'll see that `ZADD` returns 0 when the member already exists, and the score is updated while `ZINCRBY` returns the new score. The score for racer Henshaw went from 100, was changed to 150 with no regard for what score was there before, and then was incremented by 50 to 200. ## Basic commands From 8224b5d1fd50329607819b45c34a03fcc30c712a Mon Sep 17 00:00:00 2001 From: Savannah Date: Mon, 18 Sep 2023 08:52:27 -0400 Subject: [PATCH 279/377] address feedback in PR correct closing hugo short codes, grammar fixes --- docs/data-types/sorted-sets.md | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/docs/data-types/sorted-sets.md b/docs/data-types/sorted-sets.md index 156480c5d9..680100fc1b 100644 --- a/docs/data-types/sorted-sets.md +++ b/docs/data-types/sorted-sets.md @@ -38,7 +38,7 @@ Let's start with a simple example, we'll add all our racers and the score they g (integer) 1 > ZADD racer_scores 8 "Sam-Bodden" 10 "Royce" 6 "Ford" 14 "Prickett" (integer) 4 -{{ /clients-example> }} +{{< /clients-example >}} As you can see `ZADD` is similar to `SADD`, but takes one additional argument @@ -53,7 +53,7 @@ Implementation note: Sorted sets are implemented via a dual-ported data structure containing both a skip list and a hash table, so every time we add an element Redis performs an O(log(N)) operation. That's good, but when we ask for sorted elements Redis does not have to do any work at -all, it's already all sorted. Note that the `ZRANGE` order is low to high, while the `ZREVRANGE` order is high to low: +all, it's already sorted. Note that the `ZRANGE` order is low to high, while the `ZREVRANGE` order is high to low: {{< clients-example ss_tutorial zrange >}} > ZRANGE racer_scores 0 -1 @@ -70,7 +70,7 @@ all, it's already all sorted. Note that the `ZRANGE` order is low to high, while 4) "Norem" 5) "Sam-Bodden" 6) "Ford" -{{ /clients-example> }} +{{< /clients-example >}} Note: 0 and -1 means from element index 0 to the last element (-1 works here just as it does in the case of the `LRANGE` command). @@ -91,7 +91,7 @@ It is possible to return scores as well, using the `WITHSCORES` argument: 10) "12" 11) "Prickett" 12) "14" -{{ /clients-example> }} +{{< /clients-example >}} ### Operating on ranges @@ -105,12 +105,12 @@ use the `ZRANGEBYSCORE` command to do it: 2) "Sam-Bodden" 3) "Norem" 4) "Royce" -{{ /clients-example> }} +{{< /clients-example >}} We asked Redis to return all the elements with a score between negative infinity and 10 (both extremes are included). -To remove an element we'd simply call `ZREM` with the racers name. +To remove an element we'd simply call `ZREM` with the racer's name. It's also possible to remove ranges of elements. Let's remove racer Castilla along with all the racers with strictly fewer than 10 points: @@ -123,14 +123,14 @@ the racers with strictly fewer than 10 points: 1) "Norem" 2) "Royce" 3) "Prickett" -{{ /clients-example> }} +{{< /clients-example >}} `ZREMRANGEBYSCORE` is perhaps not the best command name, but it can be very useful, and returns the number of removed elements. Another extremely useful operation defined for sorted set elements is the get-rank operation. It is possible to ask what is the -position of an element in the set of the ordered elements. +position of an element in the set of ordered elements. The `ZREVRANK` command is also available in order to get the rank, considering the elements sorted a descending way. @@ -139,7 +139,7 @@ the elements sorted a descending way. (integer) 0 > ZREVRANK racer_scores "Norem" (integer) 3 -{{ /clients-example> }} +{{< /clients-example >}} ### Lexicographical scores @@ -153,7 +153,7 @@ The main commands to operate with lexicographical ranges are `ZRANGEBYLEX`, `ZREVRANGEBYLEX`, `ZREMRANGEBYLEX` and `ZLEXCOUNT`. For example, let's add again our list of famous hackers, but this time -use a score of zero for all the elements. We'll see that because of the sorted sets ordering rules, they are already sorted lexicographically. Using `ZRANGEBYLEX` we can ask for lexicographical ranges: +using a score of zero for all the elements. We'll see that because of the sorted sets ordering rules, they are already sorted lexicographically. Using `ZRANGEBYLEX` we can ask for lexicographical ranges: {{< clients-example ss_tutorial zadd_lex >}} > ZADD racer_scores 0 "Norem" 0 "Sam-Bodden" 0 "Royce" 0 "Castilla" 0 "Prickett" 0 "Ford" @@ -168,7 +168,7 @@ use a score of zero for all the elements. We'll see that because of the sorted s > ZRANGEBYLEX racer_scores [A [L 1) "Castilla" 2) "Ford" -{{ /clients-example> }} +{{< /clients-example >}} Ranges can be inclusive or exclusive (depending on the first character), also string infinite and minus infinite are specified respectively with @@ -203,7 +203,7 @@ the #4932 best score here"). ## Examples -* There are two ways we can use a sorted set to represent a leaderbaord. If we know a racers new score, we can update it directly via the `ZADD` command. However if we want to add points to an existing score, we can use the `ZINCRBY` command. +* There are two ways we can use a sorted set to represent a leaderbaord. If we know a racer's new score, we can update it directly via the `ZADD` command. However, if we want to add points to an existing score, we can use the `ZINCRBY` command. {{< clients-example ss_tutorial leaderboard >}} > ZADD racer_scores 100 "Wood" (integer) 1 @@ -215,9 +215,9 @@ the #4932 best score here"). "150" > ZINCRBY racer_scores 50 "Henshaw" "200" -{{ /clients-example> }} +{{< /clients-example >}} -You'll see that `ZADD` returns 0 when the member already exists, and the score is updated while `ZINCRBY` returns the new score. The score for racer Henshaw went from 100, was changed to 150 with no regard for what score was there before, and then was incremented by 50 to 200. +You'll see that `ZADD` returns 0 when the member already exists (the score is updated), while `ZINCRBY` returns the new score. The score for racer Henshaw went from 100, was changed to 150 with no regard for what score was there before, and then was incremented by 50 to 200. ## Basic commands @@ -244,3 +244,7 @@ If you need to index and query your data, consider the [JSON](/docs/stack/json) * [Redis Sorted Sets Explained](https://www.youtube.com/watch?v=MUKlxdBQZ7g) is an entertaining introduction to sorted sets in Redis. * [Redis University's RU101](https://university.redis.com/courses/ru101/) explores Redis sorted sets in detail. + + +* [Redis Sorted Sets Explained](https://www.youtube.com/watch?v=MUKlxdBQZ7g) is an entertaining introduction to sorted sets in Redis. +* [Redis University's RU101](https://university.redis.com/courses/ru101/) explores Redis sorted sets in detail. From 783763b8f05ec427acdcf5a365f5410b04ee87a4 Mon Sep 17 00:00:00 2001 From: Savannah Date: Wed, 20 Sep 2023 11:25:54 -0400 Subject: [PATCH 280/377] Update hyperloglogs.md with hugo short codes added a pfmerge example - condensed to one more robust example --- docs/data-types/probabilistic/hyperloglogs.md | 42 ++++++++----------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/docs/data-types/probabilistic/hyperloglogs.md b/docs/data-types/probabilistic/hyperloglogs.md index 1f00455e74..e78f1dd47a 100644 --- a/docs/data-types/probabilistic/hyperloglogs.md +++ b/docs/data-types/probabilistic/hyperloglogs.md @@ -1,4 +1,4 @@ ---- +--- title: "HyperLogLog" linkTitle: "HyperLogLog" weight: 1 @@ -37,12 +37,22 @@ only contains a state that does not include actual elements, the API is the same: * Every time you see a new element, you add it to the count with `PFADD`. -* Every time you want to retrieve the current approximation of the unique elements *added* with `PFADD` so far, you use the `PFCOUNT`. +* Every time you want to retrieve the current approximation of the unique elements *added* with `PFADD` so far, you use the `PFCOUNT`. Two different HLLs can be merged into a single one using `PFMERGE` and since HLLs approximate unique elements, the result of the merge is the approximated number of unique elements in the union of the source HLLs. + +{{< clients-example hll_tutorial pfadd >}} - > pfadd hll a b c d - (integer) 1 - > pfcount hll - (integer) 4 +{{< clients-example hll_tutorial pfadd >}} +> PFADD bikes Hyperion Deimos Phoebe Quaoar +(integer) 1 +> PFCOUNT bikes +(integer) 4 +> PFADD commuter_bikes Salacia Mimas Quaoar +(integer) 1 +> PFMERGE all_bikes bikes commuter_bikes +OK +> PFCOUNT all_bikes +(integer) 6 +{{< /clients-example >}} Some examples of use cases for this data structure is counting unique queries performed by users in a search form every day, number of unique visitors to a web page and other similar cases. @@ -68,25 +78,6 @@ Storing the IP address or any other kind of personal identifier is against the l One HyperLogLog is created per page (video/song) per period, and every IP/identifier is added to it on every visit. - -## Examples - -* Add some items to the HyperLogLog: -``` -> PFADD members 123 -(integer) 1 -> PFADD members 500 -(integer) 1 -> PFADD members 12 -(integer) 1 -``` - -* Estimate the number of members in the set: -``` -> PFCOUNT members -(integer) 3 -``` - ## Basic commands * `PFADD` adds an item to a HyperLogLog. @@ -108,3 +99,4 @@ The HyperLogLog can estimate the cardinality of sets with up to 18,446,744,073,7 * [Redis new data structure: the HyperLogLog](http://antirez.com/news/75) has a lot of details about the data structure and its implementation in Redis. * [Redis HyperLogLog Explained](https://www.youtube.com/watch?v=MunL8nnwscQ) shows you how to use Redis HyperLogLog data structures to build a traffic heat map. + From 671d0524f41b4e3926be22b8617f2a5f0b9f2ff9 Mon Sep 17 00:00:00 2001 From: "David W. Dougherty" Date: Wed, 27 Sep 2023 13:11:21 -0700 Subject: [PATCH 281/377] DOC-2743: add UTM parms to RC links --- docs/getting-started/_index.md | 2 +- docs/getting-started/installation/_index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/getting-started/_index.md b/docs/getting-started/_index.md index 910ba89353..53900dcdf4 100644 --- a/docs/getting-started/_index.md +++ b/docs/getting-started/_index.md @@ -12,7 +12,7 @@ aliases: This is a guide to getting started with Redis. You'll learn how to install, run, and experiment with the Redis server process. -While you can install Redis on any of the platforms listed below, you might also consider using Redis Cloud by creating a [free account](https://docs.redis.com/latest/rc/rc-quickstart/). +While you can install Redis on any of the platforms listed below, you might also consider using Redis Cloud by creating a [free account](https://redis.com/try-free?utm_source=redisio&utm_medium=referral&utm_campaign=2023-09-try_free&utm_content=cu-redis_cloud_users). ## Install Redis diff --git a/docs/getting-started/installation/_index.md b/docs/getting-started/installation/_index.md index c9b9fc0c17..0c5358a33f 100644 --- a/docs/getting-started/installation/_index.md +++ b/docs/getting-started/installation/_index.md @@ -6,4 +6,4 @@ description: > Install Redis on Linux, macOS, and Windows --- -While you can install Redis on any of the platforms listed below, you might also consider using Redis Cloud by creating a [free account](https://docs.redis.com/latest/rc/rc-quickstart/). \ No newline at end of file +While you can install Redis on any of the platforms listed below, you might also consider using Redis Cloud by creating a [free account](https://redis.com/try-free/?utm_source=redisio&utm_medium=referral&utm_campaign=2023-09-try_free&utm_content=cu-redis_cloud_users). \ No newline at end of file From d1eb2e71634ba60bc6f4cb780600bbb4e5b1b22c Mon Sep 17 00:00:00 2001 From: "David W. Dougherty" Date: Fri, 29 Sep 2023 10:17:12 -0700 Subject: [PATCH 282/377] DOC-2755: update get started for clarity --- docs/getting-started/_index.md | 35 ++++++++++--------- .../installation/install-redis-from-source.md | 4 ++- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/docs/getting-started/_index.md b/docs/getting-started/_index.md index 910ba89353..b4001ae755 100644 --- a/docs/getting-started/_index.md +++ b/docs/getting-started/_index.md @@ -87,17 +87,20 @@ Running Redis from the command line is fine just to hack a bit or for developmen * Run Redis using screen. * Install Redis in your Linux box in a proper way using an init script, so that after a restart everything will start again properly. -A proper install using an init script is strongly suggested. -The following instructions can be used to perform a proper installation using the init script shipped with Redis version 2.4 or higher in a Debian or Ubuntu based distribution. +A proper install using an init script is strongly recommended. Note: the available packages for supported Linux distributions already include the capability of starting the Redis server from `/etc/init`. -We assume you already copied **redis-server** and **redis-cli** executables under /usr/local/bin. +**Note**: the remainder of this section assumes you've [installed Redis from its source code](/docs/getting-started/installation/install-redis-from-source/). If instead you have installed Redis Stack, you will need to download a [basic init script](https://raw.githubusercontent.com/redis/redis/7.2/utils/redis_init_script) and then modify both it and the following instructions to conform to the way Redis Stack was installed on your platform. For example, on Ubuntu 20.04 LTS, Redis Stack is installed in `/opt/redis-stack`, not `/usr/local`, so you'll need to adjust accordingly. + +The following instructions can be used to perform a proper installation using the init script shipped with the Redis source code, `/path/to/redis-stable/utils/redis_init_script`. + +If you have not yet run `make install` after building the Redis source, you will need to do so before continuing. By default, `make install` will copy the `redis-server` and `redis-cli` binaries to `/usr/local/bin`. * Create a directory in which to store your Redis config files and your data: sudo mkdir /etc/redis sudo mkdir /var/redis -* Copy the init script that you'll find in the Redis distribution under the **utils** directory into `/etc/init.d`. We suggest calling it with the name of the port where you are running this instance of Redis. For example: +* Copy the init script that you'll find in the Redis distribution under the **utils** directory into `/etc/init.d`. We suggest calling it with the name of the port where you are running this instance of Redis. Make sure the resulting file has `0755` permissions. sudo cp utils/redis_init_script /etc/init.d/redis_6379 @@ -105,25 +108,25 @@ We assume you already copied **redis-server** and **redis-cli** executables unde sudo vi /etc/init.d/redis_6379 -Make sure to modify **REDISPORT** accordingly to the port you are using. +Make sure to set the **REDISPORT** variable to the port you are using. Both the pid file path and the configuration file name depend on the port number. -* Copy the template configuration file you'll find in the root directory of the Redis distribution into `/etc/redis/` using the port number as name, for instance: +* Copy the template configuration file you'll find in the root directory of the Redis distribution into `/etc/redis/` using the port number as the name, for instance: sudo cp redis.conf /etc/redis/6379.conf -* Create a directory inside `/var/redis` that will work as data and working directory for this Redis instance: +* Create a directory inside `/var/redis` that will work as both data and working directory for this Redis instance: sudo mkdir /var/redis/6379 * Edit the configuration file, making sure to perform the following changes: * Set **daemonize** to yes (by default it is set to no). - * Set the **pidfile** to `/var/run/redis_6379.pid` (modify the port if needed). - * Change the **port** accordingly. In our example it is not needed as the default port is already 6379. + * Set the **pidfile** to `/var/run/redis_6379.pid`, modifying the port as necessary. + * Change the **port** accordingly. In our example it is not needed as the default port is already `6379`. * Set your preferred **loglevel**. * Set the **logfile** to `/var/log/redis_6379.log` * Set the **dir** to `/var/redis/6379` (very important step!) -* Finally add the new Redis init script to all the default runlevels using the following command: +* Finally, add the new Redis init script to all the default runlevels using the following command: sudo update-rc.d redis_6379 defaults @@ -133,12 +136,12 @@ You are done! Now you can try running your instance with: Make sure that everything is working as expected: -* Try pinging your instance with redis-cli. -* Do a test save with `redis-cli save` and check that the dump file is correctly stored into `/var/redis/6379/` (you should find a file called `dump.rdb`). -* Check that your Redis instance is correctly logging in the log file. -* If it's a new machine where you can try it without problems make sure that after a reboot everything is still working. +* Try pinging your instance within a `redis-cli` session using the `PING` command. +* Do a test save with `redis-cli save` and check that a dump file is correctly saved to `/var/redis/6379/dump.rdb`. +* Check that your Redis instance is logging to the `/var/log/redis_6379.log` file. +* If it's a new machine where you can try it without problems, make sure that after a reboot everything is still working. -Note: The above instructions don't include all of the Redis configuration parameters that you could change, for instance, to use AOF persistence instead of RDB persistence, or to set up replication, and so forth. -Make sure to read the example [`redis.conf`](https://github.com/redis/redis/blob/6.2/redis.conf) file (that is heavily commented). +Note: The above instructions don't include all of the Redis configuration parameters that you could change. For example, to use AOF persistence instead of RDB persistence, or to set up replication, and so forth. +Make sure to read the example [redis.conf](/docs/management/config-file/) file, which is heavily annotated to help guide you on making changes, and also the [configuration article on this site](/docs/management/config/).
diff --git a/docs/getting-started/installation/install-redis-from-source.md b/docs/getting-started/installation/install-redis-from-source.md index d885bca190..c44164f50b 100644 --- a/docs/getting-started/installation/install-redis-from-source.md +++ b/docs/getting-started/installation/install-redis-from-source.md @@ -36,7 +36,7 @@ If the compile succeeds, you'll find several Redis binaries in the `src` directo To install these binaries in `/usr/local/bin`, run: {{< highlight bash >}} -make install +sudo make install {{< / highlight >}} ### Starting and stopping Redis in the foreground @@ -50,3 +50,5 @@ redis-server If successful, you'll see the startup logs for Redis, and Redis will be running in the foreground. To stop Redis, enter `Ctrl-C`. + +For a more complete installation, continue with [these instructions](/docs/getting-started/#install-redis-more-properly). \ No newline at end of file From f7c7152a29a6e84ea33b5ca3e2a8dc475adc9b0e Mon Sep 17 00:00:00 2001 From: Savannah Date: Mon, 2 Oct 2023 09:08:51 -0400 Subject: [PATCH 283/377] Update docs/data-types/probabilistic/hyperloglogs.md address feedback on PR Co-authored-by: David Dougherty --- docs/data-types/probabilistic/hyperloglogs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/probabilistic/hyperloglogs.md b/docs/data-types/probabilistic/hyperloglogs.md index e78f1dd47a..7e2b6b241c 100644 --- a/docs/data-types/probabilistic/hyperloglogs.md +++ b/docs/data-types/probabilistic/hyperloglogs.md @@ -37,7 +37,7 @@ only contains a state that does not include actual elements, the API is the same: * Every time you see a new element, you add it to the count with `PFADD`. -* Every time you want to retrieve the current approximation of the unique elements *added* with `PFADD` so far, you use the `PFCOUNT`. Two different HLLs can be merged into a single one using `PFMERGE` and since HLLs approximate unique elements, the result of the merge is the approximated number of unique elements in the union of the source HLLs. +* When you want to retrieve the current approximation of unique elements added using the `PFADD` command, you can use the `PFCOUNT` command. If you need to merge two different HLLs, the `PFMERGE` command is available. Since HLLs provide approximate counts of unique elements, the result of the merge will give you an approximation of the number of unique elements across both source HLLs. {{< clients-example hll_tutorial pfadd >}} From 93e8a50552ccf3e35d83eb0a5415c1c6c1eed366 Mon Sep 17 00:00:00 2001 From: Savannah Date: Mon, 2 Oct 2023 09:40:15 -0400 Subject: [PATCH 284/377] remove superfluous short code --- docs/data-types/probabilistic/hyperloglogs.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/data-types/probabilistic/hyperloglogs.md b/docs/data-types/probabilistic/hyperloglogs.md index 7e2b6b241c..89bbd11a38 100644 --- a/docs/data-types/probabilistic/hyperloglogs.md +++ b/docs/data-types/probabilistic/hyperloglogs.md @@ -39,8 +39,6 @@ same: * Every time you see a new element, you add it to the count with `PFADD`. * When you want to retrieve the current approximation of unique elements added using the `PFADD` command, you can use the `PFCOUNT` command. If you need to merge two different HLLs, the `PFMERGE` command is available. Since HLLs provide approximate counts of unique elements, the result of the merge will give you an approximation of the number of unique elements across both source HLLs. -{{< clients-example hll_tutorial pfadd >}} - {{< clients-example hll_tutorial pfadd >}} > PFADD bikes Hyperion Deimos Phoebe Quaoar (integer) 1 From 4d345ac90a0c8dbf759238478b38829e2c5e807e Mon Sep 17 00:00:00 2001 From: Oran Agra Date: Thu, 12 Oct 2023 13:51:52 +0300 Subject: [PATCH 285/377] fix swapped vars in memory-stats, and minor wording (#2557) --- commands/memory-stats.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/commands/memory-stats.md b/commands/memory-stats.md index 39cd68e9f8..21a99d32da 100644 --- a/commands/memory-stats.md +++ b/commands/memory-stats.md @@ -33,10 +33,10 @@ values. The following metrics are reported: minus `startup.allocated`) and `keys.count` * `dataset.bytes`: The size in bytes of the dataset, i.e. `overhead.total` subtracted from `total.allocated` (see `INFO`'s `used_memory_dataset`) -* `dataset.percentage`: The percentage of `dataset.bytes` out of the net +* `dataset.percentage`: The percentage of `dataset.bytes` out of the total memory usage -* `peak.percentage`: The percentage of `peak.allocated` out of - `total.allocated` +* `peak.percentage`: The percentage of `total.allocated` out of + `peak.allocated` * `fragmentation`: See `INFO`'s `mem_fragmentation_ratio` @return From d3a0400c69f86ab1eca9f137de4e216f4cba485e Mon Sep 17 00:00:00 2001 From: Matthias Berndt Date: Sun, 22 Oct 2023 13:56:07 +0200 Subject: [PATCH 286/377] fix inconsistency in docs (#2559) The examples don't mention apples, strawberries or oranges, so let's change the text to match the examples. --- docs/data-types/streams.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data-types/streams.md b/docs/data-types/streams.md index 378c99cd76..86152a6b82 100644 --- a/docs/data-types/streams.md +++ b/docs/data-types/streams.md @@ -439,7 +439,7 @@ This is almost always what you want, however it is also possible to specify a re * If the ID is the special ID `>` then the command will return only new messages never delivered to other consumers so far, and as a side effect, will update the consumer group's *last ID*. * If the ID is any other valid numerical ID, then the command will let us access our *history of pending messages*. That is, the set of messages that were delivered to this specified consumer (identified by the provided name), and never acknowledged so far with `XACK`. -We can test this behavior immediately specifying an ID of 0, without any **COUNT** option: we'll just see the only pending message, that is, the one about apples: +We can test this behavior immediately specifying an ID of 0, without any **COUNT** option: we'll just see the only pending message, that is, the one about Castilla: {{< clients-example stream_tutorial xgroup_read_id >}} > XREADGROUP GROUP italy_riders Alice STREAMS race:italy 0 @@ -474,7 +474,7 @@ Now it's Bob's turn to read something: 2) "Sam-Bodden" {{< /clients-example >}} -Bob asked for a maximum of two messages and is reading via the same group `mygroup`. So what happens is that Redis reports just *new* messages. As you can see the "apple" message is not delivered, since it was already delivered to Alice, so Bob gets orange and strawberry, and so forth. +Bob asked for a maximum of two messages and is reading via the same group `mygroup`. So what happens is that Redis reports just *new* messages. As you can see the "Castilla" message is not delivered, since it was already delivered to Alice, so Bob gets Royce and Sam-Bodden and so forth. This way Alice, Bob, and any other consumer in the group, are able to read different messages from the same stream, to read their history of yet to process messages, or to mark messages as processed. This allows creating different topologies and semantics for consuming messages from a stream. From e56123dd2e917d4608998d5e82bb2896c85cac4c Mon Sep 17 00:00:00 2001 From: David Maier <60782329+dmaier-redislabs@users.noreply.github.com> Date: Mon, 23 Oct 2023 20:58:57 +0200 Subject: [PATCH 287/377] Improved quick start guides (#2574) * Moved the old quick start guide to the install section * Added al iases for the old pages * Added the new getting started intro article * Added an empty getting started guide to test if the restructuring works * Minor fix * Fixed the install Redis section * Minor changes * Moved the UI section to a Connect section to comply with the new task-driven approach of the site * Moved the client quick starts under Connect because they would be confused with the new quick start section * Fixed the order * Renamed the menu item Data types to Understand data types to reflect the activity-driven user flow better * Added a new quick start guide for Redis as an in-memory data store * Cosmetical change * Cosmetic changes * Cosmetical changes * The SCAN command exammple referenced the wrong code example * Trying to fix a broken SCAN example * Cloud databases need a user name and password * Cloud databases need a user name and password * Cosmetic changes * 32 bit machines are not state of the art anymore. * Aligned the menu names more * Added the demo data for the quick start guides * Fixed a broken link * Hide the auto-generated index for short pages * Updated the get and set example * Modified title of the datatypes section * Added a reference to the keyspace article * Fixes old client links * Allow to do one quick start guide after another * Renamed data store to data structure store --------- Co-authored-by: David Maier --- docs/connect/_index.md | 39 ++++++ docs/{ui => connect}/cli.md | 1 + docs/{ => connect}/clients/_index.md | 7 +- docs/{ => connect}/clients/dotnet.md | 4 +- docs/{ => connect}/clients/go.md | 3 +- docs/{ => connect}/clients/java.md | 4 +- docs/{ => connect}/clients/nodejs.md | 4 +- docs/{ => connect}/clients/python.md | 4 +- docs/data-types/_index.md | 4 +- docs/data-types/hashes.md | 14 +- docs/data-types/strings.md | 4 +- docs/get-started/_index.md | 20 +++ docs/get-started/data-store.md | 88 ++++++++++++ docs/get-started/data/bikes.json | 127 +++++++++++++++++ docs/{getting-started => get-started}/faq.md | 7 +- docs/get-started/img/free-cloud-db.png | Bin 0 -> 713343 bytes docs/getting-started/installation/_index.md | 9 -- docs/install/_index.md | 18 +++ .../install-redis}/_index.md | 132 ++++++++++-------- .../install-redis-from-source.md | 6 +- .../install-redis}/install-redis-on-linux.md | 4 +- .../install-redis}/install-redis-on-mac-os.md | 6 +- .../install-redis-on-windows.md | 6 +- docs/ui/_index.md | 9 -- 24 files changed, 415 insertions(+), 105 deletions(-) create mode 100644 docs/connect/_index.md rename docs/{ui => connect}/cli.md (99%) rename docs/{ => connect}/clients/_index.md (82%) rename docs/{ => connect}/clients/dotnet.md (99%) rename docs/{ => connect}/clients/go.md (99%) rename docs/{ => connect}/clients/java.md (96%) rename docs/{ => connect}/clients/nodejs.md (94%) rename docs/{ => connect}/clients/python.md (95%) create mode 100644 docs/get-started/_index.md create mode 100644 docs/get-started/data-store.md create mode 100644 docs/get-started/data/bikes.json rename docs/{getting-started => get-started}/faq.md (96%) create mode 100644 docs/get-started/img/free-cloud-db.png delete mode 100644 docs/getting-started/installation/_index.md create mode 100644 docs/install/_index.md rename docs/{getting-started => install/install-redis}/_index.md (52%) rename docs/{getting-started/installation => install/install-redis}/install-redis-from-source.md (91%) rename docs/{getting-started/installation => install/install-redis}/install-redis-on-linux.md (94%) rename docs/{getting-started/installation => install/install-redis}/install-redis-on-mac-os.md (93%) rename docs/{getting-started/installation => install/install-redis}/install-redis-on-windows.md (84%) delete mode 100644 docs/ui/_index.md diff --git a/docs/connect/_index.md b/docs/connect/_index.md new file mode 100644 index 0000000000..a53d05d406 --- /dev/null +++ b/docs/connect/_index.md @@ -0,0 +1,39 @@ +--- +title: Connect to Redis +linkTitle: Connect +description: Learn how to use user interfaces and client libraries +weight: 35 +aliases: + - /docs/ui +--- + +You can connect to Redis in the following ways: + +* With the `redis-cli` command line tool +* Use RedisInsight as a graphical user interface +* Via a client library for your programming language + +## Redis command line interface + +The [Redis command line interface](/docs/connect/cli) (also known as `redis-cli`) is a terminal program that sends commands to and reads replies from the Redis server. It has the following two main modes: + +1. An interactive Read Eval Print Loop (REPL) mode where the user types Redis commands and receives replies. +2. A command mode where `redis-cli` is executed with additional arguments, and the reply is printed to the standard output. + +## RedisInsight + +[RedisInsight](/docs/connect/insight) combines a graphical user interface with Redis CLI to let you work with any Redis deployment. You can visually browse and interact with data, take advantage of diagnostic tools, learn by example, and much more. Best of all, RedisInsight is free. + +## Client libraries + +It's easy to connect your application to a Redis database. The official client libraries cover the following languages: + +* [C#/.NET](/docs/connect/clients/dotnet) +* [Go](/docs/connect/clients/go) +* [Java](/docs/connect/clients/java) +* [Node.js](/docs/connect/clients/nodejs) +* [Python](/docs/connect/clients/python) + +You can find a complete list of all client libraries, including the community-maintained ones, on the [clients page](/resources/clients/). + +
diff --git a/docs/ui/cli.md b/docs/connect/cli.md similarity index 99% rename from docs/ui/cli.md rename to docs/connect/cli.md index 936c0ec2e5..70f3e71f7f 100644 --- a/docs/ui/cli.md +++ b/docs/connect/cli.md @@ -7,6 +7,7 @@ description: > aliases: - /docs/manual/cli - /docs/management/cli + - /docs/ui/cli --- In interactive mode, `redis-cli` has basic line editing capabilities to provide a familiar typing experience. diff --git a/docs/clients/_index.md b/docs/connect/clients/_index.md similarity index 82% rename from docs/clients/_index.md rename to docs/connect/clients/_index.md index a5d1b09dd0..d6e8fcff39 100644 --- a/docs/clients/_index.md +++ b/docs/connect/clients/_index.md @@ -1,11 +1,12 @@ --- -title: "Get started using Redis clients" -linkTitle: "Client quickstarts" -description: Get started using Redis clients. Select your library and connect your application to a Redis database. Then, try an example. +title: "Connect with Redis clients" +linkTitle: "Clients" +description: Connect your application to a Redis database and try an example weight: 45 aliases: - /docs/redis-clients - /docs/stack/get-started/clients/ + - /docs/clients/ --- Here, you will learn how to connect your application to a Redis database. If you're new to Redis, you might first want to [install Redis with Redis Stack and RedisInsight](/docs/getting-started/install-stack/). diff --git a/docs/clients/dotnet.md b/docs/connect/clients/dotnet.md similarity index 99% rename from docs/clients/dotnet.md rename to docs/connect/clients/dotnet.md index 4f62fd34b5..c38c7e3f3b 100644 --- a/docs/clients/dotnet.md +++ b/docs/connect/clients/dotnet.md @@ -3,7 +3,9 @@ title: "C#/.NET guide" linkTitle: "C#/.NET" description: Connect your .NET application to a Redis database weight: 1 - +aliases: + - /docs/clients/dotnet/ + - /docs/redis-clients/dotnet/ --- Install Redis and the Redis client, then connect your .NET application to a Redis database. diff --git a/docs/clients/go.md b/docs/connect/clients/go.md similarity index 99% rename from docs/clients/go.md rename to docs/connect/clients/go.md index cbbefe2b42..2b57e381a5 100644 --- a/docs/clients/go.md +++ b/docs/connect/clients/go.md @@ -3,7 +3,8 @@ title: "Go guide" linkTitle: "Go" description: Connect your Go application to a Redis database weight: 2 - +aliases: + - /docs/clients/go/ --- Install Redis and the Redis client, then connect your Go application to a Redis database. diff --git a/docs/clients/java.md b/docs/connect/clients/java.md similarity index 96% rename from docs/clients/java.md rename to docs/connect/clients/java.md index ccde8b5b7e..1258b9817c 100644 --- a/docs/clients/java.md +++ b/docs/connect/clients/java.md @@ -3,7 +3,9 @@ title: "Java guide" linkTitle: "Java" description: Connect your Java application to a Redis database weight: 3 - +aliases: + - /docs/clients/java/ + - /docs/redis-clients/java/ --- Install Redis and the Redis client, then connect your Java application to a Redis database. diff --git a/docs/clients/nodejs.md b/docs/connect/clients/nodejs.md similarity index 94% rename from docs/clients/nodejs.md rename to docs/connect/clients/nodejs.md index 17faa6d7d1..24b4824051 100644 --- a/docs/clients/nodejs.md +++ b/docs/connect/clients/nodejs.md @@ -3,7 +3,9 @@ title: "Node.js guide" linkTitle: "Node.js" description: Connect your Node.js application to a Redis database weight: 4 - +aliases: + - /docs/clients/nodejs/ + - /docs/redis-clients/nodejs/ --- Install Redis and the Redis client, then connect your Node.js application to a Redis database. diff --git a/docs/clients/python.md b/docs/connect/clients/python.md similarity index 95% rename from docs/clients/python.md rename to docs/connect/clients/python.md index 1a7610e3b6..6563f0ad84 100644 --- a/docs/clients/python.md +++ b/docs/connect/clients/python.md @@ -3,7 +3,9 @@ title: "Python guide" linkTitle: "Python" description: Connect your Python application to a Redis database weight: 5 - +aliases: + - /docs/clients/python/ + - /docs/redis-clients/python/ --- Install Redis and the Redis client, then connect your Python application to a Redis database. diff --git a/docs/data-types/_index.md b/docs/data-types/_index.md index 0d31ff18e3..ca95521d16 100644 --- a/docs/data-types/_index.md +++ b/docs/data-types/_index.md @@ -1,6 +1,6 @@ --- -title: "Redis data types" -linkTitle: "Data types" +title: "Understand Redis data types" +linkTitle: "Understand data types" description: Overview of data types supported by Redis weight: 35 aliases: diff --git a/docs/data-types/hashes.md b/docs/data-types/hashes.md index 2409955a13..68f9825e9d 100644 --- a/docs/data-types/hashes.md +++ b/docs/data-types/hashes.md @@ -10,13 +10,13 @@ Redis hashes are record types structured as collections of field-value pairs. You can use hashes to represent basic objects and to store groupings of counters, among other things. {{< clients-example hash_tutorial set_get_all >}} -> hset bike:1 model Deimos brand Ergonom type 'Enduro bikes' price 4972 +> HSET bike:1 model Deimos brand Ergonom type 'Enduro bikes' price 4972 (integer) 4 -> hget bike:1 model +> HGET bike:1 model "Deimos" -> hget bike:1 price +> HGET bike:1 price "4972" -> hgetall bike:1 +> HGETALL bike:1 1) "model" 2) "Deimos" 3) "brand" @@ -36,7 +36,7 @@ The command `HSET` sets multiple fields of the hash, while `HGET` retrieves a single field. `HMGET` is similar to `HGET` but returns an array of values: {{< clients-example hash_tutorial hmget >}} -> hmget bike:1 model price no-such-field +> HMGET bike:1 model price no-such-field 1) "Deimos" 2) "4972" 3) (nil) @@ -46,9 +46,9 @@ There are commands that are able to perform operations on individual fields as well, like `HINCRBY`: {{< clients-example hash_tutorial hincrby >}} -> hincrby bike:1 price 100 +> HINCRBY bike:1 price 100 (integer) 5072 -> hincrby bike:1 price -100 +> HINCRBY bike:1 price -100 (integer) 4972 {{< /clients-example >}} diff --git a/docs/data-types/strings.md b/docs/data-types/strings.md index 55909e3185..52348dcf59 100644 --- a/docs/data-types/strings.md +++ b/docs/data-types/strings.md @@ -16,9 +16,9 @@ we are mapping a string to another string. The string data type is useful for a number of use cases, like caching HTML fragments or pages. {{< clients-example set_tutorial set_get >}} - > set bike:1 Deimos + > SET bike:1 Deimos OK - > get bike:1 + > GET bike:1 "Deimos" {{< /clients-example >}} diff --git a/docs/get-started/_index.md b/docs/get-started/_index.md new file mode 100644 index 0000000000..e94be52b99 --- /dev/null +++ b/docs/get-started/_index.md @@ -0,0 +1,20 @@ +--- +title: "Quick starts" +linkTitle: "Quick starts" +hideListLinks: true +weight: 20 +description: > + Redis quick start guides +aliases: + - /docs/getting-started/ +--- + +Redis can be used as a database, cache, streaming engine, message broker, and more. The following quick start guides will show you how to use Redis for the following specific purposes: + +1. [Data structure store](/docs/get-started/data-store) +2. [Document database](/docs/get-started/document-database) +3. [Vector database](/docs/get-started/vector-database) + +Please select the guide that aligns best with your specific usage scenario. + +You can find answers to frequently asked questions in the [FAQ](/docs/get-started/faq/). diff --git a/docs/get-started/data-store.md b/docs/get-started/data-store.md new file mode 100644 index 0000000000..79b657798e --- /dev/null +++ b/docs/get-started/data-store.md @@ -0,0 +1,88 @@ +--- +title: "Redis as an in-memory data structure store quick start guide" +linkTitle: "Data structure store" +weight: 1 +description: Understand how to use basic Redis data types +--- + +This quick start guide shows you how to: + +1. Get started with Redis +2. Store data under a key in Redis +3. Retrieve data with a key from Redis +4. Scan the keyspace for keys that match a specific pattern + +The examples in this article refer to a simple bicycle inventory. + +## Setup + +The easiest way to get started with Redis is to use Redis Cloud: + +1. Create a [free account](https://redis.com/try-free?utm_source=redisio&utm_medium=referral&utm_campaign=2023-09-try_free&utm_content=cu-redis_cloud_users). +2. Follow the instructions to create a free database. + + + +You can alternatively follow the [installation guides](/docs/install/install-stack/) to install Redis on your local machine. + +## Connect + +The first step is to connect to Redis. You can find further details about the connection options in this documentation site's [connection section](/docs/connect). The following example shows how to connect to a Redis server that runs on localhost (`-h 127.0.0.1`) and listens on the default port (`-p 6379`): + +{{< clients-example search_quickstart connect >}} +> redis-cli -h 127.0.0.1 -p 6379 +{{< /clients-example>}} +
+{{% alert title="Tip" color="warning" %}} +You can copy and paste the connection details from the Redis Cloud database configuration page. Here is an example connection string of a Cloud database that is hosted in the AWS region `us-east-1` and listens on port 16379: `redis-16379.c283.us-east-1-4.ec2.cloud.redislabs.com:16379`. The connection string has the format `host:port`. You must also copy and paste the username and password of your Cloud database and then either pass the credentials to your client or use the [AUTH command](/commands/auth/) after the connection is established. +{{% /alert %}} + +## Store and retrieve data + +Redis stands for Remote Dictionary Server. You can use the same data types as in your local programming environment but on the server side within Redis. + +Similar to byte arrays, Redis strings store sequences of bytes, including text, serialized objects, counter values, and binary arrays. The following example shows you how to set and get a string value: + +{{< clients-example set_and_get >}} +SET bike:1 "Process 134" +GET bike:1 +{{< /clients-example >}} + +Hashes are the equivalent of dictionaries (dicts or hash maps). Among other things, you can use hashes to represent plain objects and to store groupings of counters. The following example explains how to set and access field values of an object: + +{{< clients-example hash_tutorial set_get_all >}} +> HSET bike:1 model Deimos brand Ergonom type 'Enduro bikes' price 4972 +(integer) 4 +> HGET bike:1 model +"Deimos" +> HGET bike:1 price +"4972" +> HGETALL bike:1 +1) "model" +2) "Deimos" +3) "brand" +4) "Ergonom" +5) "type" +6) "Enduro bikes" +7) "price" +8) "4972" +{{< /clients-example >}} + +You can get a complete overview of available data types in this documentation site's [data types section](/docs/data-types/). Each data type has commands allowing you to manipulate or retrieve data. The [commands reference](/commands/) provides a sophisticated explanation. + +## Scan the keyspace + +Each item within Redis has a unique key. All items live within the Redis [keyspace](/docs/manual/keyspace/). You can scan the Redis keyspace via the [SCAN command](/commands/scan/). Here is an example that scans for the first 100 keys that have the prefix `bike:`: + +{{< clients-example scan_example >}} +SCAN 0 MATCH "bike:*" COUNT 100 +{{< /clients-example >}} + +[SCAN](/commands/scan/) returns a cursor position, allowing you to scan iteratively for the next batch of keys until you reach the cursor value 0. + +## Next steps + +You can address more use cases with Redis by learning about Redis Stack. Here are two additional quick start guides: + +* [Redis as a document database](/docs/get-started/document-database/) +* [Redis as a vector database](/docs/get-started/vector-database/) \ No newline at end of file diff --git a/docs/get-started/data/bikes.json b/docs/get-started/data/bikes.json new file mode 100644 index 0000000000..f8186ec93c --- /dev/null +++ b/docs/get-started/data/bikes.json @@ -0,0 +1,127 @@ +[ + { + "model": "Jigger", + "brand": "Velorim", + "price": 270, + "type": "Kids bikes", + "specs": { + "material": "aluminium", + "weight": "10" + }, + "description": "Small and powerful, the Jigger is the best ride for the smallest of tikes! This is the tiniest kids’ pedal bike on the market available without a coaster brake, the Jigger is the vehicle of choice for the rare tenacious little rider raring to go. We say rare because this smokin’ little bike is not ideal for a nervous first-time rider, but it’s a true giddy up for a true speedster. The Jigger is a 12 inch lightweight kids bicycle and it will meet your little one’s need for speed. It’s a single speed bike that makes learning to pump pedals simple and intuitive. It even has a handle in the bottom of the saddle so you can easily help your child during training! The Jigger is among the most lightweight children’s bikes on the planet. It is designed so that 2-3 year-olds fit comfortably in a molded ride position that allows for efficient riding, balanced handling and agility. The Jigger’s frame design and gears work together so your buddingbiker can stand up out of the seat, stop rapidly, rip over trails and pump tracks. The Jigger’s is amazing on dirt or pavement. Your tike will speed down the bike path in no time. The Jigger will ship with a coaster brake. A freewheel kit is provided at no cost. " + }, + { + "model": "Hillcraft", + "brand": "Bicyk", + "price": 1200, + "type": "Kids Mountain Bikes", + "specs": { + "material": "carbon", + "weight": "11" + }, + "description": "Kids want to ride with as little weight as possible. Especially on an incline! They may be at the age when a 27.5\" wheel bike is just too clumsy coming off a 24\" bike. The Hillcraft 26 is just the solution they need! Imagine 120mm travel. Boost front/rear. You have NOTHING to tweak because it is easy to assemble right out of the box. The Hillcraft 26 is an efficient trail trekking machine. Up or down does not matter - dominate the trails going both down and up with this amazing bike. The name Monarch comes from Monarch trail in Colorado where we love to ride. It’s a highly technical, steep and rocky trail but the rip on the waydown is so fulfilling. Don’t ride the trail on a hardtail! It is so much more fun on the full suspension Hillcraft! Hit your local trail with the Hillcraft Monarch 26 to get to where you want to go. " + }, + { + "model": "Chook air 5", + "brand": "Nord", + "price": 815, + "type": "Kids Mountain Bikes", + "specs": { + "material": "alloy", + "weight": "9.1" + }, + "description": "The Chook Air 5 gives kids aged six years and older a durable and uberlight mountain bike for their first experience on tracks and easy cruising through forests and fields. The lower top tube makes it easy to mount and dismount in any situation, giving your kids greater safety on the trails. The Chook Air 5 is the perfect intro to mountain biking." + }, + { + "model": "Eva 291", + "brand": "Eva", + "price": 3400, + "type": "Mountain Bikes", + "specs": { + "material": "carbon", + "weight": "9.1" + }, + "description": "The sister company to Nord, Eva launched in 2005 as the first and only women-dedicated bicycle brand. Designed by women for women, allEva bikes are optimized for the feminine physique using analytics from a body metrics database. If you like 29ers, try the Eva 291. It’s a brand new bike for 2022.. This full-suspension, cross-country ride has been designed for velocity. The 291 has 100mm of front and rear travel, a superlight aluminum frame and fast-rolling 29-inch wheels. Yippee!" + }, + { + "model": "Kahuna", + "brand": "Noka Bikes", + "price": 3200, + "type": "Mountain Bikes", + "specs": { + "material": "alloy", + "weight": "9.8" + }, + "description": "Whether you want to try your hand at XC racing or are looking for a lively trail bike that's just as inspiring on the climbs as it is over rougher ground, the Wilder is one heck of a bike built specifically for short women. Both the frames and components have been tweaked to include a women’s saddle, different bars and unique colourway." + }, + { + "model": "XBN 2.1 Alloy", + "brand": "Breakout", + "price": 810, + "type": "Road Bikes", + "specs": { + "material": "alloy", + "weight": "7.2" + }, + "description": "The XBN 2.1 Alloy is our entry-level road bike – but that’s not to say that it’s a basic machine. With an internal weld aluminium frame, a full carbon fork, and the slick-shifting Claris gears from Shimano’s, this is a bike which doesn’t break the bank and delivers craved performance. The 6061 alloy frame is triple-butted which ensures a lighter weight and smoother ride. And it’s comfortable with dropped seat stays and the carbon fork. The carefully crafted 50-34 tooth chainset and 11-32 tooth cassette give an easy-on-the-legs bottom gear for climbing, and the high-quality Vittoria Zaffiro tires balance grip, rolling friction and puncture protection when coasting down the other side. " + }, + { + "model": "WattBike", + "brand": "ScramBikes", + "price": 2300, + "type": "eBikes", + "specs": { + "material": "alloy", + "weight": "15" + }, + "description": "The WattBike is the best e-bike for people who still feel young at heart. It has a Bafang 500 watt geared hub motor that can reach 20 miles per hour on both steep inclines and city streets. The lithium-ion battery, which gets nearly 40 miles per charge, has a lightweight form factor, making it easier for seniors to use. It comes fully assembled (no convoluted instructions!) and includes a sturdy helmet at no cost. The Plush saddle softens over time with use. The included Seatpost, however, is easily adjustable and adds to this bike’s fantastic rating for seniors, as do the hydraulic disc brakes from Tektro. " + }, + { + "model": "Soothe Electric bike", + "brand": "Peaknetic", + "price": 1950, + "type": "eBikes", + "specs": { + "material": "alloy", + "weight": "14.7" + }, + "description": "The Soothe is an everyday electric bike, from the makers of Exercycle bikes, that conveys style while you get around the city. The Soothe lives up to its name by keeping your posture upright and relaxed for the ride ahead, keeping those aches and pains from riding at bay. It includes a low-step frame , our memory foam seat, bump-resistant shocks and conveniently placed thumb throttle. " + }, + { + "model": "Secto", + "brand": "Peaknetic", + "price": 430, + "type": "Commuter bikes", + "specs": { + "material": "aluminium", + "weight": "10.0" + }, + "description": "If you struggle with stiff fingers or a kinked neck or back after a few minutes on the road, this lightweight, aluminum bike alleviates those issues and allows you to enjoy the ride. From the ergonomic grips to the lumbar-supporting seat position, the Roll Low-Entry offers incredible comfort. The rear-inclined seat tube facilitates stability by allowing you to put a foot on the ground to balance at a stop, and the low step-over frame makes it accessible for all ability and mobility levels. The saddle is very soft, with a wide back to support your hip joints and a cutout in the center to redistribute that pressure. Rim brakes deliver satisfactory braking control, and the wide tires provide a smooth, stable ride on paved roads and gravel. Rack and fender mounts facilitate setting up the Roll Low-Entry as your preferred commuter, and the BMX-like handlebar offers space for mounting a flashlight, bell, or phone holder." + }, + { + "model": "Summit", + "brand": "nHill", + "price": 1200, + "type": "Mountain Bike", + "specs": { + "material": "alloy", + "weight": "11.3" + }, + "description": "This budget mountain bike from nHill performs well both on bike paths and on the trail. The fork with 100mm of travel absorbs rough terrain. Fat Kenda Booster tires give you grip in corners and on wet trails. The Shimano Tourney drivetrain offered enough gears for finding a comfortable pace to ride uphill, and the Tektro hydraulic disc brakes break smoothly. Whether you want an affordable bike that you can take to work, but also take trail riding on the weekends or you’re just after a stable, comfortable ride for the bike path, the Summit gives a good value for money." + }, + { + "model": "ThrillCycle", + "brand": "BikeShind", + "price": 815, + "type": "Commuter Bikes", + "specs": { + "material": "alloy", + "weight": "12.7" + }, + "description": "An artsy, retro-inspired bicycle that’s as functional as it is pretty: The ThrillCycle steel frame offers a smooth ride. A 9-speed drivetrain has enough gears for coasting in the city, but we wouldn’t suggest taking it to the mountains. Fenders protect you from mud, and a rear basket lets you transport groceries, flowers and books. The ThrillCycle comes with a limited lifetime warranty, so this little guy will last you long past graduation." + } + + + + +] diff --git a/docs/getting-started/faq.md b/docs/get-started/faq.md similarity index 96% rename from docs/getting-started/faq.md rename to docs/get-started/faq.md index 9ee1d55c83..0c8531ac97 100644 --- a/docs/getting-started/faq.md +++ b/docs/get-started/faq.md @@ -63,10 +63,9 @@ and not refreshed on cache misses. ## How can I reduce Redis' overall memory usage? -If you can, use Redis 32 bit instances. Also make good use of small hashes, -lists, sorted sets, and sets of integers, since Redis is able to represent -those data types in the special case of a few elements in a much more compact -way. There is more info in the [Memory Optimization page](/topics/memory-optimization). +A good practice is to consider memory consumption when mapping your logical data model to the physical data model within Redis. These considerations include using specific data types, key patterns, and normalization. + +Beyond data modeling, there is more info in the [Memory Optimization page](/topics/memory-optimization). ## What happens if Redis runs out of memory? diff --git a/docs/get-started/img/free-cloud-db.png b/docs/get-started/img/free-cloud-db.png new file mode 100644 index 0000000000000000000000000000000000000000..d4bc935230be2b2bcf6a50f458525ee69697d3cf GIT binary patch literal 713343 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
u+14y1! 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≷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%0A8)8)f6{p7$SO;K6Z8&Gh{KH?Y$%e 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 z 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

!( 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�wf%Auxc0?PULK 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 acjtQh*7@+6#p8bv{wc_+K0w|xdHR2sE@HO; literal 0 HcmV?d00001 diff --git a/docs/getting-started/installation/_index.md b/docs/getting-started/installation/_index.md deleted file mode 100644 index 0c5358a33f..0000000000 --- a/docs/getting-started/installation/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Installing Redis" -linkTitle: "Install Redis" -weight: 1 -description: > - Install Redis on Linux, macOS, and Windows ---- - -While you can install Redis on any of the platforms listed below, you might also consider using Redis Cloud by creating a [free account](https://redis.com/try-free/?utm_source=redisio&utm_medium=referral&utm_campaign=2023-09-try_free&utm_content=cu-redis_cloud_users). \ No newline at end of file diff --git a/docs/install/_index.md b/docs/install/_index.md new file mode 100644 index 0000000000..807a7596ae --- /dev/null +++ b/docs/install/_index.md @@ -0,0 +1,18 @@ +--- +title: "Install Redis or Redis Stack" +linkTitle: "Install" +weight: 30 +hideListLinks: true +description: How to install your preferred Redis flavor on your target platform +aliases: + - /docs/getting-started +--- + +You can install both [Redis](https://redis.io/docs/about/) or [Redis Stack](/docs/about/about-stack) locally on your machine. Redis and Redis Stack are available on Linux, macOS, and Windows. + +Here are the installation instructions: + +* [Install Redis](/docs/install/install-redis) +* [Install Redis Stack](/docs/install/install-stack) + +While you can install Redis (Stack) locally, you might also consider using Redis Cloud by creating a [free account](https://redis.com/try-free/?utm_source=redisio&utm_medium=referral&utm_campaign=2023-09-try_free&utm_content=cu-redis_cloud_users). \ No newline at end of file diff --git a/docs/getting-started/_index.md b/docs/install/install-redis/_index.md similarity index 52% rename from docs/getting-started/_index.md rename to docs/install/install-redis/_index.md index 237d1f476d..a72112717d 100644 --- a/docs/getting-started/_index.md +++ b/docs/install/install-redis/_index.md @@ -1,16 +1,15 @@ ---- -title: "Get started with Redis" -linkTitle: "Get started" - -weight: 20 - +--- +title: "Install Redis" +linkTitle: "Install Redis" +weight: 1 description: > - How to get up and running with Redis + Install Redis on Linux, macOS, and Windows aliases: - - /docs/getting-started/tutorial +- /docs/getting-started/installation +- /docs/getting-started/tutorial --- -This is a guide to getting started with Redis. You'll learn how to install, run, and experiment with the Redis server process. +This is a an installation guide. You'll learn how to install, run, and experiment with the Redis server process. While you can install Redis on any of the platforms listed below, you might also consider using Redis Cloud by creating a [free account](https://redis.com/try-free?utm_source=redisio&utm_medium=referral&utm_campaign=2023-09-try_free&utm_content=cu-redis_cloud_users). @@ -18,43 +17,39 @@ While you can install Redis on any of the platforms listed below, you might also How you install Redis depends on your operating system and whether you'd like to install it bundled with Redis Stack and Redis UI. See the guide below that best fits your needs: -* [Install Redis from Source](/docs/getting-started/installation/install-redis-from-source) -* [Install Redis on Linux](/docs/getting-started/installation/install-redis-on-linux) -* [Install Redis on macOS](/docs/getting-started/installation/install-redis-on-mac-os) -* [Install Redis on Windows](/docs/getting-started/installation/install-redis-on-windows) -* [Install Redis with Redis Stack and RedisInsight](/docs/getting-started/install-stack/) +* [Install Redis from Source](/docs/install/install-redis-from-source) +* [Install Redis on Linux](/docs/install/install-redis-on-linux) +* [Install Redis on macOS](/docs/install/install-redis-on-mac-os) +* [Install Redis on Windows](/docs/install/install-redis-on-windows) +* [Install Redis with Redis Stack and RedisInsight](/docs/install/install-stack/) -Once you have Redis up and running, and can connect using `redis-cli`, you can continue with the steps below. -## Explore Redis using the CLI +## Test if you can connect using the CLI + +Once you have Redis up and running, you can connect using `redis-cli`. External programs talk to Redis using a TCP socket and a Redis specific protocol. This protocol is implemented in the Redis client libraries for the different programming languages. However to make hacking with Redis simpler Redis provides a command line utility that can be used to send commands to Redis. This program is called **redis-cli**. The first thing to do in order to check if Redis is working properly is sending a **PING** command using redis-cli: - $ redis-cli ping - PONG +``` +$ redis-cli ping +PONG +``` Running **redis-cli** followed by a command name and its arguments will send this command to the Redis instance running on localhost at port 6379. You can change the host and port used by `redis-cli` - just try the `--help` option to check the usage information. Another interesting way to run `redis-cli` is without arguments: the program will start in interactive mode. You can type different commands and see their replies. - $ redis-cli - redis 127.0.0.1:6379> ping - PONG - redis 127.0.0.1:6379> set mykey somevalue - OK - redis 127.0.0.1:6379> get mykey - "somevalue" - -At this point you are able to talk with Redis. It is the right time to pause a bit with this tutorial and start the [fifteen minutes introduction to Redis data types](https://redis.io/topics/data-types-intro) in order to learn a few Redis commands. Otherwise if you already know a few basic Redis commands you can keep reading. +``` +$ redis-cli +redis 127.0.0.1:6379> ping +PONG +``` ## Securing Redis -By default Redis binds to **all the interfaces** and has no authentication at -all. If you use Redis in a very controlled environment, separated from the -external internet and in general from attackers, that's fine. However if an unhardened Redis -is exposed to the internet, it is a big security concern. If you are not 100% sure your environment is secured properly, please check the following steps in order to make Redis more secure, which are enlisted in order of increased security. +By default Redis binds to **all the interfaces** and has no authentication at all. If you use Redis in a very controlled environment, separated from the external internet and in general from attackers, that's fine. However if an unhardened Redis is exposed to the internet, it is a big security concern. If you are not 100% sure your environment is secured properly, please check the following steps in order to make Redis more secure: 1. Make sure the port Redis uses to listen for connections (by default 6379 and additionally 16379 if you run Redis in cluster mode, plus 26379 for Sentinel) is firewalled, so that it is not possible to contact Redis from the outside world. 2. Use a configuration file where the `bind` directive is set in order to guarantee that Redis listens on only the network interfaces you are using. For example only the loopback interface (127.0.0.1) if you are accessing Redis just locally from the same computer, and so forth. @@ -65,20 +60,20 @@ Note that a Redis instance exposed to the internet without any security [is very ## Use Redis from your application -Of course using Redis just from the command line interface is not enough as -the goal is to use it from your application. In order to do so you need to -download and install a Redis client library for your programming language. -You'll find a [full list of clients for different languages in this page](https://redis.io/clients). +Of course using Redis just from the command line interface is not enough as the goal is to use it from your application. In order to do so you need to download and install a Redis client library for your programming language. + +You'll find a [full list of clients for different languages in this page](/clients). ## Redis persistence -You can learn [how Redis persistence works on this page](https://redis.io/topics/persistence), however what is important to understand for a quick start is that by default, if you start Redis with the default configuration, Redis will spontaneously save the dataset only from time to time (for instance after at least five minutes if you have at least 100 changes in your data), so if you want your database to persist and be reloaded after a restart make sure to call the **SAVE** command manually every time you want to force a data set snapshot. Otherwise make sure to shutdown the database using the **SHUTDOWN** command: +You can learn [how Redis persistence works on this page](/docs/management/persistence/), however what is important to understand for a quick start is that by default, if you start Redis with the default configuration, Redis will spontaneously save the dataset only from time to time (for instance after at least five minutes if you have at least 100 changes in your data), so if you want your database to persist and be reloaded after a restart make sure to call the **SAVE** command manually every time you want to force a data set snapshot. Otherwise make sure to shutdown the database using the **SHUTDOWN** command: - $ redis-cli shutdown +``` +$ redis-cli shutdown +``` -This way Redis will make sure to save the data on disk before quitting. -Reading the [persistence page](https://redis.io/topics/persistence) is strongly suggested in order to better understand how Redis persistence works. +This way Redis will make sure to save the data on disk before quitting. Reading the [persistence page](/docs/management/persistence/) is strongly suggested in order to better understand how Redis persistence works. ## Install Redis more properly @@ -87,9 +82,15 @@ Running Redis from the command line is fine just to hack a bit or for developmen * Run Redis using screen. * Install Redis in your Linux box in a proper way using an init script, so that after a restart everything will start again properly. -A proper install using an init script is strongly recommended. Note: the available packages for supported Linux distributions already include the capability of starting the Redis server from `/etc/init`. +A proper install using an init script is strongly recommended. + +{{% alert title="Note" color="warning" %}} +The available packages for supported Linux distributions already include the capability of starting the Redis server from `/etc/init`. +{{% /alert %}} -**Note**: the remainder of this section assumes you've [installed Redis from its source code](/docs/getting-started/installation/install-redis-from-source/). If instead you have installed Redis Stack, you will need to download a [basic init script](https://raw.githubusercontent.com/redis/redis/7.2/utils/redis_init_script) and then modify both it and the following instructions to conform to the way Redis Stack was installed on your platform. For example, on Ubuntu 20.04 LTS, Redis Stack is installed in `/opt/redis-stack`, not `/usr/local`, so you'll need to adjust accordingly. +{{% alert title="Note" color="warning" %}} +The remainder of this section assumes you've [installed Redis from its source code](/docs/install/install-redis-from-source/). If instead you have installed Redis Stack, you will need to download a [basic init script](https://raw.githubusercontent.com/redis/redis/7.2/utils/redis_init_script) and then modify both it and the following instructions to conform to the way Redis Stack was installed on your platform. For example, on Ubuntu 20.04 LTS, Redis Stack is installed in `/opt/redis-stack`, not `/usr/local`, so you'll need to adjust accordingly. +{{% /alert %}} The following instructions can be used to perform a proper installation using the init script shipped with the Redis source code, `/path/to/redis-stable/utils/redis_init_script`. @@ -97,27 +98,37 @@ If you have not yet run `make install` after building the Redis source, you will * Create a directory in which to store your Redis config files and your data: - sudo mkdir /etc/redis - sudo mkdir /var/redis + ``` + sudo mkdir /etc/redis + sudo mkdir /var/redis + ``` * Copy the init script that you'll find in the Redis distribution under the **utils** directory into `/etc/init.d`. We suggest calling it with the name of the port where you are running this instance of Redis. Make sure the resulting file has `0755` permissions. - - sudo cp utils/redis_init_script /etc/init.d/redis_6379 + + ``` + sudo cp utils/redis_init_script /etc/init.d/redis_6379 + ``` * Edit the init script. - sudo vi /etc/init.d/redis_6379 + ``` + sudo vi /etc/init.d/redis_6379 + ``` Make sure to set the **REDISPORT** variable to the port you are using. Both the pid file path and the configuration file name depend on the port number. * Copy the template configuration file you'll find in the root directory of the Redis distribution into `/etc/redis/` using the port number as the name, for instance: - sudo cp redis.conf /etc/redis/6379.conf + ``` + sudo cp redis.conf /etc/redis/6379.conf + ``` * Create a directory inside `/var/redis` that will work as both data and working directory for this Redis instance: - sudo mkdir /var/redis/6379 + ``` + sudo mkdir /var/redis/6379 + ``` * Edit the configuration file, making sure to perform the following changes: * Set **daemonize** to yes (by default it is set to no). @@ -128,20 +139,27 @@ Both the pid file path and the configuration file name depend on the port number * Set the **dir** to `/var/redis/6379` (very important step!) * Finally, add the new Redis init script to all the default runlevels using the following command: - sudo update-rc.d redis_6379 defaults + ``` + sudo update-rc.d redis_6379 defaults + ``` You are done! Now you can try running your instance with: - sudo /etc/init.d/redis_6379 start +``` +sudo /etc/init.d/redis_6379 start +``` Make sure that everything is working as expected: -* Try pinging your instance within a `redis-cli` session using the `PING` command. -* Do a test save with `redis-cli save` and check that a dump file is correctly saved to `/var/redis/6379/dump.rdb`. -* Check that your Redis instance is logging to the `/var/log/redis_6379.log` file. -* If it's a new machine where you can try it without problems, make sure that after a reboot everything is still working. +1. Try pinging your instance within a `redis-cli` session using the `PING` command. +2. Do a test save with `redis-cli save` and check that a dump file is correctly saved to `/var/redis/6379/dump.rdb`. +3. Check that your Redis instance is logging to the `/var/log/redis_6379.log` file. +4. If it's a new machine where you can try it without problems, make sure that after a reboot everything is still working. + +{{% alert title="Note" color="warning" %}} +The above instructions don't include all of the Redis configuration parameters that you could change. For example, to use AOF persistence instead of RDB persistence, or to set up replication, and so forth. +{{% /alert %}} -Note: The above instructions don't include all of the Redis configuration parameters that you could change. For example, to use AOF persistence instead of RDB persistence, or to set up replication, and so forth. -Make sure to read the example [redis.conf](/docs/management/config-file/) file, which is heavily annotated to help guide you on making changes, and also the [configuration article on this site](/docs/management/config/). +You should also read the example [redis.conf](/docs/management/config-file/) file, which is heavily annotated to help guide you on making changes. Further details can also be found in the [configuration article on this site](/docs/management/config/). -


+
\ No newline at end of file diff --git a/docs/getting-started/installation/install-redis-from-source.md b/docs/install/install-redis/install-redis-from-source.md similarity index 91% rename from docs/getting-started/installation/install-redis-from-source.md rename to docs/install/install-redis/install-redis-from-source.md index c44164f50b..2d8e2623cd 100644 --- a/docs/getting-started/installation/install-redis-from-source.md +++ b/docs/install/install-redis/install-redis-from-source.md @@ -1,9 +1,11 @@ --- title: "Install Redis from Source" -linkTitle: "Install from Source" +linkTitle: "Source code" weight: 5 description: > Compile and install Redis from source +aliases: +- /docs/getting-started/installation/install-redis-from-source --- You can compile and install Redis from source on variety of platforms and operating systems including Linux and macOS. Redis has no dependencies other than a C compiler and `libc`. @@ -51,4 +53,4 @@ If successful, you'll see the startup logs for Redis, and Redis will be running To stop Redis, enter `Ctrl-C`. -For a more complete installation, continue with [these instructions](/docs/getting-started/#install-redis-more-properly). \ No newline at end of file +For a more complete installation, continue with [these instructions](/docs/install/#install-redis-more-properly). \ No newline at end of file diff --git a/docs/getting-started/installation/install-redis-on-linux.md b/docs/install/install-redis/install-redis-on-linux.md similarity index 94% rename from docs/getting-started/installation/install-redis-on-linux.md rename to docs/install/install-redis/install-redis-on-linux.md index 41b0041351..2e47efe945 100644 --- a/docs/getting-started/installation/install-redis-on-linux.md +++ b/docs/install/install-redis/install-redis-on-linux.md @@ -1,9 +1,11 @@ --- title: "Install Redis on Linux" -linkTitle: "Install on Linux" +linkTitle: "Linux" weight: 1 description: > How to install Redis on Linux +aliases: +- /docs/getting-started/installation/install-redis-on-linux --- Most major Linux distributions provide packages for Redis. diff --git a/docs/getting-started/installation/install-redis-on-mac-os.md b/docs/install/install-redis/install-redis-on-mac-os.md similarity index 93% rename from docs/getting-started/installation/install-redis-on-mac-os.md rename to docs/install/install-redis/install-redis-on-mac-os.md index cb838e5ae2..5f82311575 100644 --- a/docs/getting-started/installation/install-redis-on-mac-os.md +++ b/docs/install/install-redis/install-redis-on-mac-os.md @@ -1,11 +1,13 @@ --- title: "Install Redis on macOS" -linkTitle: "Install on macOS" +linkTitle: "MacOS" weight: 1 description: Use Homebrew to install and start Redis on macOS +aliases: +- /docs/getting-started/installation/install-redis-on-mac-os --- -This guide shows you how to install Redis on macOS using Homebrew. Homebrew is the easiest way to install Redis on macOS. If you'd prefer to build Redis from the source files on macOS, see [Installing Redis from Source](../install-redis-from-source). +This guide shows you how to install Redis on macOS using Homebrew. Homebrew is the easiest way to install Redis on macOS. If you'd prefer to build Redis from the source files on macOS, see [Installing Redis from Source](/docs/install/install-redis-from-source). ## Prerequisites diff --git a/docs/getting-started/installation/install-redis-on-windows.md b/docs/install/install-redis/install-redis-on-windows.md similarity index 84% rename from docs/getting-started/installation/install-redis-on-windows.md rename to docs/install/install-redis/install-redis-on-windows.md index 3ce2d367d0..6b5e6bd465 100644 --- a/docs/getting-started/installation/install-redis-on-windows.md +++ b/docs/install/install-redis/install-redis-on-windows.md @@ -1,8 +1,10 @@ --- title: "Install Redis on Windows" -linkTitle: "Install on Windows" +linkTitle: "Windows" weight: 1 description: Use Redis on Windows for development +aliases: +- /docs/getting-started/installation/install-redis-on-windows/ --- Redis is not officially supported on Windows. However, you can install Redis on Windows for development by following the instructions below. @@ -15,7 +17,7 @@ Microsoft provides [detailed instructions for installing WSL](https://docs.micro ## Install Redis -Once you're running Ubuntu on Windows, you can follow the steps detailed at [Install on Ubuntu/Debian](../install-redis-on-linux#install-on-ubuntu-debian) to install recent stable versions of Redis from the official `packages.redis.io` APT repository. +Once you're running Ubuntu on Windows, you can follow the steps detailed at [Install on Ubuntu/Debian](/docs/install/install-redis-on-linux#install-on-ubuntu-debian) to install recent stable versions of Redis from the official `packages.redis.io` APT repository. Add the repository to the apt index, update it, and then install: {{< highlight bash >}} diff --git a/docs/ui/_index.md b/docs/ui/_index.md deleted file mode 100644 index a7e27b13f5..0000000000 --- a/docs/ui/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: User interfaces -linkTitle: User interfaces -description: Learn how to use Redis interfaces -weight: 30 ---- -The Redis command line interface (redis-cli) is a terminal program used to send commands to and read replies from the Redis server. It has two main modes: an interactive Read Eval Print Loop (REPL) mode where the user types Redis commands and receives replies, and a command mode where redis-cli is executed with additional arguments and the reply is printed to the standard output. - -RedisInsight combines a graphical user interface with Redis CLI to let you work with any Redis deployment. You can visually browse and interact with data, take advantage of diagnostic tools, learn by example, and much more. Best of all, RedisInsight is free. From f5514bfa0dd0752bff99e9b9ec2266f9f6e34833 Mon Sep 17 00:00:00 2001 From: Binbin Date: Tue, 24 Oct 2023 03:37:42 -0500 Subject: [PATCH 288/377] update client list fields: no-evict and no-touch (#2572) no-evict added in redis/redis#8687 no-touch added in redis/redis#11483 Co-authored-by: Binbin --- commands/client-list.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/commands/client-list.md b/commands/client-list.md index 6241425ba7..e24c7e1e2e 100644 --- a/commands/client-list.md +++ b/commands/client-list.md @@ -49,6 +49,7 @@ A: connection to be closed ASAP b: the client is waiting in a blocking operation c: connection to be closed after writing entire reply d: a watched keys has been modified - EXEC will fail +e: the client is excluded from the client eviction mechanism i: the client is waiting for a VM I/O (deprecated) M: the client is a master N: no specific flag set @@ -60,6 +61,7 @@ u: the client is unblocked U: the client is connected via a Unix domain socket x: the client is in a MULTI/EXEC context t: the client enabled keys tracking in order to perform client side caching +T: the client will not touch the LRU/LFU of the keys it accesses R: the client tracking target client is invalid B: the client enabled broadcast tracking mode ``` From 928bf6ed9848b76b53429adf81f96f9db3b06800 Mon Sep 17 00:00:00 2001 From: Oran Agra Date: Tue, 24 Oct 2023 11:39:06 +0300 Subject: [PATCH 289/377] update commands spec (args) from 7.2.2 (#2570) see redis/redis#12633 --- commands.json | 92 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 16 deletions(-) diff --git a/commands.json b/commands.json index aca624b567..63637edabd 100644 --- a/commands.json +++ b/commands.json @@ -11073,14 +11073,44 @@ "arity": 3, "arguments": [ { - "name": "host", - "type": "string", - "display_text": "host" - }, - { - "name": "port", - "type": "integer", - "display_text": "port" + "name": "args", + "type": "oneof", + "arguments": [ + { + "name": "host-port", + "type": "block", + "arguments": [ + { + "name": "host", + "type": "string", + "display_text": "host" + }, + { + "name": "port", + "type": "integer", + "display_text": "port" + } + ] + }, + { + "name": "no-one", + "type": "block", + "arguments": [ + { + "name": "no", + "type": "pure-token", + "display_text": "no", + "token": "NO" + }, + { + "name": "one", + "type": "pure-token", + "display_text": "one", + "token": "ONE" + } + ] + } + ] } ], "command_flags": [ @@ -12743,14 +12773,44 @@ "arity": 3, "arguments": [ { - "name": "host", - "type": "string", - "display_text": "host" - }, - { - "name": "port", - "type": "integer", - "display_text": "port" + "name": "args", + "type": "oneof", + "arguments": [ + { + "name": "host-port", + "type": "block", + "arguments": [ + { + "name": "host", + "type": "string", + "display_text": "host" + }, + { + "name": "port", + "type": "integer", + "display_text": "port" + } + ] + }, + { + "name": "no-one", + "type": "block", + "arguments": [ + { + "name": "no", + "type": "pure-token", + "display_text": "no", + "token": "NO" + }, + { + "name": "one", + "type": "pure-token", + "display_text": "one", + "token": "ONE" + } + ] + } + ] } ], "command_flags": [ From 309eb4b603e8cd711a92a47ca8cb1c6e62707893 Mon Sep 17 00:00:00 2001 From: David Maier <60782329+dmaier-redislabs@users.noreply.github.com> Date: Tue, 24 Oct 2023 15:36:49 +0200 Subject: [PATCH 290/377] Update _index.md Fixed some broken links --- docs/install/install-redis/_index.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/install/install-redis/_index.md b/docs/install/install-redis/_index.md index a72112717d..d3892b4bff 100644 --- a/docs/install/install-redis/_index.md +++ b/docs/install/install-redis/_index.md @@ -17,10 +17,10 @@ While you can install Redis on any of the platforms listed below, you might also How you install Redis depends on your operating system and whether you'd like to install it bundled with Redis Stack and Redis UI. See the guide below that best fits your needs: -* [Install Redis from Source](/docs/install/install-redis-from-source) -* [Install Redis on Linux](/docs/install/install-redis-on-linux) -* [Install Redis on macOS](/docs/install/install-redis-on-mac-os) -* [Install Redis on Windows](/docs/install/install-redis-on-windows) +* [Install Redis from Source](/docs/install/install-redis/install-redis-from-source) +* [Install Redis on Linux](/docs/install/install-redis/install-redis-on-linux) +* [Install Redis on macOS](/docs/install/install-redis/install-redis-on-mac-os) +* [Install Redis on Windows](/docs/install/install-redis/install-redis-on-windows) * [Install Redis with Redis Stack and RedisInsight](/docs/install/install-stack/) @@ -162,4 +162,4 @@ The above instructions don't include all of the Redis configuration parameters t You should also read the example [redis.conf](/docs/management/config-file/) file, which is heavily annotated to help guide you on making changes. Further details can also be found in the [configuration article on this site](/docs/management/config/). -
\ No newline at end of file +
From ee17d7ace3ca560682cd680dffbf768b72897461 Mon Sep 17 00:00:00 2001 From: Felipe Cury <26260549+flpcury@users.noreply.github.com> Date: Tue, 24 Oct 2023 00:42:22 +0900 Subject: [PATCH 291/377] Fix typos in protocol-spec.md --- docs/reference/protocol-spec.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference/protocol-spec.md b/docs/reference/protocol-spec.md index bd4b6d1dff..a9893c8a5b 100644 --- a/docs/reference/protocol-spec.md +++ b/docs/reference/protocol-spec.md @@ -67,7 +67,7 @@ This is the simplest model possible; however, there are some exceptions: The protocol of this mode is not specified but is obvious to parse. * [Protected mode](/docs/management/security/#protected-mode). Connections opened from a non-loopback address to a Redis while in protected mode are denied and terminated by the server. - Before terminating the connection, Redis unconditionally sends `-DENIED` reply, irregardless of whether the client writes to the socket. + Before terminating the connection, Redis unconditionally sends a `-DENIED` reply, regardless of whether the client writes to the socket. * The [RESP3 Push type](#resp3-pushes). As the name suggests, a push type allows the server to send out-of-band data to the connection. The server may push data at any time, and the data isn't necessarily related to specific commands executed by the client. @@ -298,7 +298,7 @@ For example, a nested array of two arrays is encoded as follows: (The raw RESP encoding is split into multiple lines for readability). -The above encodes a two-elements array. +The above encodes a two-element array. The first element is an array that, in turn, contains three integers (1, 2, 3). The second element is another array containing a simple string and an error. From 17ae2f70090434259ef1968e493aa0ce8c673931 Mon Sep 17 00:00:00 2001 From: "David W. Dougherty" Date: Wed, 25 Oct 2023 06:57:15 -0700 Subject: [PATCH 292/377] Minor correction to list data type page --- docs/data-types/lists.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/lists.md b/docs/data-types/lists.md index a91cd40c40..46715c9202 100644 --- a/docs/data-types/lists.md +++ b/docs/data-types/lists.md @@ -305,7 +305,7 @@ This is an example of a `BRPOP` call we could use in the worker: (2.01s) {{< /clients-example >}} -It means: "wait for elements in the list `tasks`, but return if after 5 seconds +It means: "wait for elements in the list `bikes:repairs`, but return if after 5 seconds no element is available". Note that you can use 0 as timeout to wait for elements forever, and you can From 9d29e0cb21826fc44d4afe1b7aae5c31bc1038c4 Mon Sep 17 00:00:00 2001 From: "David W. Dougherty" Date: Tue, 31 Oct 2023 08:25:58 -0700 Subject: [PATCH 293/377] Add RESP3 reply schemas to commands --- README.md | 45 +- commands/acl-cat.md | 4 - commands/acl-deluser.md | 4 - commands/acl-dryrun.md | 5 - commands/acl-genpass.md | 4 - commands/acl-getuser.md | 4 - commands/acl-help.md | 3 - commands/acl-list.md | 4 - commands/acl-load.md | 6 - commands/acl-log.md | 10 - commands/acl-save.md | 6 - commands/acl-setuser.md | 6 - commands/acl-users.md | 4 - commands/acl-whoami.md | 4 - commands/append.md | 4 - commands/asking.md | 4 - commands/auth.md | 4 - commands/bgrewriteaof.md | 5 - commands/bgsave.md | 3 - commands/bitcount.md | 6 - commands/bitfield.md | 6 - commands/bitfield_ro.md | 4 - commands/bitop.md | 7 - commands/bitpos.md | 14 - commands/blmove.md | 5 - commands/blmpop.md | 7 - commands/blpop.md | 9 - commands/brpop.md | 9 - commands/brpoplpush.md | 5 - commands/bzmpop.md | 8 - commands/bzpopmax.md | 9 - commands/bzpopmin.md | 9 - commands/client-caching.md | 4 - commands/client-getname.md | 4 - commands/client-getredir.md | 4 - commands/client-help.md | 4 - commands/client-id.md | 6 - commands/client-info.md | 4 - commands/client-kill.md | 10 - commands/client-list.md | 8 - commands/client-no-evict.md | 4 - commands/client-no-touch.md | 4 - commands/client-pause.md | 4 - commands/client-reply.md | 6 - commands/client-setinfo.md | 4 - commands/client-setname.md | 4 - commands/client-tracking.md | 4 - commands/client-trackinginfo.md | 4 +- commands/client-unblock.md | 7 - commands/client-unpause.md | 4 - commands/cluster-addslots.md | 4 - commands/cluster-addslotsrange.md | 4 - commands/cluster-bumpepoch.md | 4 - commands/cluster-count-failure-reports.md | 4 - commands/cluster-countkeysinslot.md | 4 - commands/cluster-delslots.md | 5 - commands/cluster-delslotsrange.md | 5 - commands/cluster-failover.md | 4 - commands/cluster-flushslots.md | 4 - commands/cluster-forget.md | 4 - commands/cluster-getkeysinslot.md | 4 - commands/cluster-help.md | 4 - commands/cluster-info.md | 4 - commands/cluster-keyslot.md | 4 - commands/cluster-links.md | 4 - commands/cluster-meet.md | 4 - commands/cluster-myid.md | 4 - commands/cluster-myshardid.md | 4 - commands/cluster-nodes.md | 4 - commands/cluster-replicas.md | 4 - commands/cluster-replicate.md | 4 - commands/cluster-reset.md | 4 - commands/cluster-saveconfig.md | 4 - commands/cluster-set-config-epoch.md | 4 - commands/cluster-setslot.md | 4 - commands/cluster-shards.md | 4 - commands/cluster-slaves.md | 4 - commands/cluster-slots.md | 6 - commands/command-count.md | 4 - commands/command-docs.md | 4 - commands/command-getkeys.md | 5 - commands/command-getkeysandflags.md | 5 - commands/command-help.md | 4 - commands/command-info.md | 5 - commands/command-list.md | 4 - commands/command.md | 6 - commands/config-get.md | 5 - commands/config-help.md | 4 - commands/config-resetstat.md | 4 - commands/config-rewrite.md | 5 - commands/config-set.md | 5 - commands/copy.md | 7 - commands/dbsize.md | 4 - commands/decr.md | 4 - commands/decrby.md | 4 - commands/del.md | 4 - commands/discard.md | 4 - commands/dump.md | 4 - commands/echo.md | 4 - commands/exec.md | 7 - commands/exists.md | 4 - commands/expire.md | 7 - commands/expireat.md | 7 - commands/expiretime.md | 7 - commands/failover.md | 4 - commands/flushall.md | 4 - commands/flushdb.md | 4 - commands/function-delete.md | 4 - commands/function-dump.md | 4 - commands/function-flush.md | 4 - commands/function-help.md | 4 - commands/function-kill.md | 4 - commands/function-list.md | 4 - commands/function-load.md | 4 - commands/function-restore.md | 4 - commands/function-stats.md | 4 - commands/geoadd.md | 7 - commands/geodist.md | 7 - commands/geohash.md | 7 - commands/geopos.md | 10 - commands/georadius.md | 17 - commands/georadius_ro.md | 4 - commands/geosearch.md | 13 - commands/geosearchstore.md | 4 - commands/get.md | 4 - commands/getbit.md | 4 - commands/getdel.md | 4 - commands/getex.md | 4 - commands/getrange.md | 4 - commands/getset.md | 4 - commands/hdel.md | 5 - commands/hello.md | 4 - commands/hexists.md | 7 - commands/hget.md | 5 - commands/hgetall.md | 5 - commands/hincrby.md | 4 - commands/hincrbyfloat.md | 4 - commands/hkeys.md | 5 - commands/hlen.md | 4 - commands/hmget.md | 5 - commands/hmset.md | 4 - commands/hrandfield.md | 7 - commands/hset.md | 4 - commands/hsetnx.md | 7 - commands/hstrlen.md | 4 - commands/hvals.md | 5 - commands/incr.md | 4 - commands/incrby.md | 4 - commands/incrbyfloat.md | 4 - commands/info.md | 7 - commands/keys.md | 4 - commands/lastsave.md | 4 - commands/latency-doctor.md | 4 - commands/latency-graph.md | 4 - commands/latency-help.md | 4 - commands/latency-histogram.md | 7 - commands/latency-history.md | 7 - commands/latency-latest.md | 7 - commands/latency-reset.md | 4 - commands/lcs.md | 7 - commands/lindex.md | 4 - commands/linsert.md | 4 - commands/llen.md | 4 - commands/lmove.md | 4 - commands/lmpop.md | 7 - commands/lolwut.md | 4 - commands/lpop.md | 10 - commands/lpos.md | 4 - commands/lpush.md | 4 - commands/lpushx.md | 4 - commands/lrange.md | 4 - commands/lrem.md | 4 - commands/lset.md | 4 - commands/ltrim.md | 4 - commands/memory-doctor.md | 4 - commands/memory-help.md | 4 - commands/memory-malloc-stats.md | 4 - commands/memory-purge.md | 4 - commands/memory-stats.md | 4 - commands/memory-usage.md | 4 - commands/mget.md | 4 - commands/migrate.md | 5 - commands/module-help.md | 4 - commands/module-list.md | 9 - commands/module-load.md | 4 - commands/module-loadex.md | 4 - commands/module-unload.md | 4 - commands/monitor.md | 5 - commands/move.md | 7 - commands/mset.md | 4 - commands/msetnx.md | 7 - commands/multi.md | 4 - commands/object-encoding.md | 4 - commands/object-freq.md | 6 - commands/object-help.md | 4 - commands/object-idletime.md | 6 - commands/object-refcount.md | 6 - commands/persist.md | 7 - commands/pexpire.md | 7 - commands/pexpireat.md | 7 - commands/pexpiretime.md | 7 - commands/pfadd.md | 6 - commands/pfcount.md | 6 - commands/pfmerge.md | 4 - commands/ping.md | 6 - commands/psubscribe.md | 5 - commands/psync.md | 4 - commands/pttl.md | 4 - commands/publish.md | 6 - commands/pubsub-channels.md | 4 - commands/pubsub-help.md | 4 - commands/pubsub-numpat.md | 4 - commands/pubsub-numsub.md | 6 - commands/pubsub-shardchannels.md | 4 - commands/pubsub-shardnumsub.md | 6 - commands/punsubscribe.md | 5 - commands/quit.md | 4 - commands/randomkey.md | 4 - commands/readonly.md | 4 - commands/readwrite.md | 4 - commands/rename.md | 4 - commands/renamenx.md | 7 - commands/replicaof.md | 4 - commands/reset.md | 4 - commands/restore.md | 4 - commands/role.md | 4 - commands/rpop.md | 10 - commands/rpoplpush.md | 4 - commands/rpush.md | 4 - commands/rpushx.md | 4 - commands/sadd.md | 5 - commands/save.md | 4 - commands/scard.md | 5 - commands/script-debug.md | 5 - commands/script-exists.md | 7 - commands/script-flush.md | 4 - commands/script-help.md | 4 - commands/script-kill.md | 4 - commands/script-load.md | 5 - commands/sdiff.md | 4 - commands/sdiffstore.md | 4 - commands/select.md | 4 - commands/set.md | 12 - commands/setbit.md | 4 - commands/setex.md | 5 - commands/setnx.md | 7 - commands/setrange.md | 4 - commands/shutdown.md | 6 - commands/sinter.md | 4 - commands/sintercard.md | 4 - commands/sinterstore.md | 4 - commands/sismember.md | 7 - commands/slaveof.md | 4 - commands/slowlog-get.md | 4 - commands/slowlog-help.md | 4 - commands/slowlog-len.md | 6 - commands/slowlog-reset.md | 4 - commands/smembers.md | 4 - commands/smismember.md | 5 - commands/smove.md | 7 - commands/sort.md | 5 - commands/sort_ro.md | 4 - commands/spop.md | 10 - commands/spublish.md | 5 - commands/srandmember.md | 6 - commands/srem.md | 5 - commands/ssubscribe.md | 6 - commands/strlen.md | 5 - commands/subscribe.md | 5 - commands/substr.md | 4 - commands/sunion.md | 4 - commands/sunionstore.md | 4 - commands/sunsubscribe.md | 5 - commands/swapdb.md | 4 - commands/sync.md | 4 - commands/time.md | 9 - commands/touch.md | 4 - commands/ttl.md | 4 - commands/type.md | 4 - commands/unlink.md | 4 - commands/unsubscribe.md | 5 - commands/unwatch.md | 4 - commands/wait.md | 4 - commands/waitaof.md | 4 - commands/watch.md | 4 - commands/xack.md | 9 - commands/xadd.md | 11 - commands/xautoclaim.md | 10 - commands/xclaim.md | 8 - commands/xdel.md | 4 - commands/xgroup-create.md | 4 - commands/xgroup-createconsumer.md | 4 - commands/xgroup-delconsumer.md | 4 - commands/xgroup-destroy.md | 4 - commands/xgroup-help.md | 4 - commands/xgroup-setid.md | 4 - commands/xinfo-consumers.md | 4 - commands/xinfo-groups.md | 4 - commands/xinfo-help.md | 4 - commands/xinfo-stream.md | 4 - commands/xlen.md | 4 - commands/xpending.md | 8 - commands/xrange.md | 9 - commands/xread.md | 15 +- commands/xreadgroup.md | 13 - commands/xrevrange.md | 10 - commands/xtrim.md | 4 - commands/zadd.md | 11 - commands/zcard.md | 5 - commands/zcount.md | 4 - commands/zdiff.md | 5 - commands/zdiffstore.md | 5 - commands/zincrby.md | 5 - commands/zinter.md | 5 - commands/zintercard.md | 4 - commands/zinterstore.md | 5 - commands/zlexcount.md | 4 - commands/zmpop.md | 7 - commands/zmscore.md | 5 - commands/zpopmax.md | 4 - commands/zpopmin.md | 4 - commands/zrandmember.md | 7 - commands/zrange.md | 5 - commands/zrangebylex.md | 4 - commands/zrangebyscore.md | 5 - commands/zrangestore.md | 4 - commands/zrank.md | 11 - commands/zrem.md | 7 - commands/zremrangebylex.md | 4 - commands/zremrangebyrank.md | 4 - commands/zremrangebyscore.md | 4 - commands/zrevrange.md | 5 - commands/zrevrangebylex.md | 4 - commands/zrevrangebyscore.md | 5 - commands/zrevrank.md | 11 - commands/zscore.md | 5 - commands/zunion.md | 5 - commands/zunionstore.md | 5 - resp2_replies.json | 1318 ++++++++++++++++++++ resp3_replies.json | 1383 +++++++++++++++++++++ 340 files changed, 2742 insertions(+), 1737 deletions(-) create mode 100644 resp2_replies.json create mode 100644 resp3_replies.json diff --git a/README.md b/README.md index 0913ee1140..a9401a1c9b 100644 --- a/README.md +++ b/README.md @@ -41,16 +41,49 @@ into account: These keywords will get expanded and auto-linked to relevant parts of the documentation. -There should be at least two predefined sections: description and return value. -The return value section is marked using the @return keyword: +Each command will have a description and both RESP2 and RESP3 return values. +Regarding the return values, these are contained in the files: -``` -Returns all keys matching the given pattern. +* `resp2_replies.json` +* `resp3_replies.json` -@return +Each file is a dictionary with a matching set of keys. Each key is an array of strings that, +when processed, produce Markdown content. Here's an example: -@multi-bulk-reply: all the keys that matched the pattern. ``` +{ + ... + "ACL CAT": [ + "One of the following:", + "* [Array reply](/docs/reference/protocol-spec#arrays): an array of [Bulk string reply](/docs/reference/protocol-spec#bulk-strings) elements representing ACL categories or commands in a given category.", + "* [Simple error reply](/docs/reference/protocol-spec#simple-errors): the command returns an error if an invalid category name is given." + ], + ... +} +``` + +**Important**: when adding or editing return values, be sure to edit both files. Use the following +links for the reply type. Note: do not use `@reply-type` specifiers; use only the Markdown link. + +```md +@simple-string-reply: [Simple string reply](https://redis.io/docs/reference/protocol-spec#simple-strings) +@simple-error-reply: [Simple error reply](https://redis.io/docs/reference/protocol-spec#simple-errors) +@integer-reply: [Integer reply](https://redis.io/docs/reference/protocol-spec#integers) +@bulk-string-reply: [Bulk string reply](https://redis.io/docs/reference/protocol-spec#bulk-strings) +@array-reply: [Array reply](https://redis.io/docs/reference/protocol-spec#arrays) +@nil-reply: [Nil reply](https://redis.io/docs/reference/protocol-spec#bulk-strings) +@null-reply: [Null reply](https://redis.io/docs/reference/protocol-spec#nulls) +@boolean-reply: [Boolean reply](https://redis.io/docs/reference/protocol-spec#booleans) +@double-reply: [Double reply](https://redis.io/docs/reference/protocol-spec#doubles) +@big-number-reply: [Big number reply](https://redis.io/docs/reference/protocol-spec#big-numbers) +@bulk-error-reply: [Bulk error reply](https://redis.io/docs/reference/protocol-spec#bulk-errors) +@verbatim-string-reply: [Verbatim string reply](https://redis.io/docs/reference/protocol-spec#verbatim-strings) +@map-reply: [Map reply](https://redis.io/docs/reference/protocol-spec#maps) +@set-reply: [Set reply](https://redis.io/docs/reference/protocol-spec#sets) +@push-reply: [Push reply](https://redis.io/docs/reference/protocol-spec#pushes) +``` + +**Note:** RESP3 return schemas are not currently included in the `resp2/resp3_replies.json` files for Redis Stack modules. ## Styling guidelines diff --git a/commands/acl-cat.md b/commands/acl-cat.md index 0eb256fab8..97e35d16fa 100644 --- a/commands/acl-cat.md +++ b/commands/acl-cat.md @@ -76,7 +76,3 @@ Then we may want to know what commands are part of a given category: 30) "psync" 31) "sort" ``` - -@return - -@array-reply: a list of ACL categories or a list of commands inside a given category. The command may return an error if an invalid category name is given as argument. diff --git a/commands/acl-deluser.md b/commands/acl-deluser.md index e3f443e4d7..620183db8f 100644 --- a/commands/acl-deluser.md +++ b/commands/acl-deluser.md @@ -4,10 +4,6 @@ removed from the system, this is the default user that every new connection is authenticated with. The list of users may include usernames that do not exist, in such case no operation is performed for the non existing users. -@return - -@integer-reply: The number of users that were deleted. This number will not always match the number of arguments since certain users may not exist. - @examples ``` diff --git a/commands/acl-dryrun.md b/commands/acl-dryrun.md index 4afb3cd1de..4a2006979b 100644 --- a/commands/acl-dryrun.md +++ b/commands/acl-dryrun.md @@ -1,11 +1,6 @@ Simulate the execution of a given command by a given user. This command can be used to test the permissions of a given user without having to enable the user or cause the side effects of running the command. -@return - -@simple-string-reply: `OK` on success. -@bulk-string-reply: An error describing why the user can't execute the command. - @examples ``` diff --git a/commands/acl-genpass.md b/commands/acl-genpass.md index 2afbaecf5e..0b7a274334 100644 --- a/commands/acl-genpass.md +++ b/commands/acl-genpass.md @@ -25,10 +25,6 @@ rounded to the next multiple of 4. So for instance asking for just 1 bit password will result in 4 bits to be emitted, in the form of a single hex character. -@return - -@bulk-string-reply: by default 64 bytes string representing 256 bits of pseudorandom data. Otherwise if an argument if needed, the output string length is the number of specified bits (rounded to the next multiple of 4) divided by 4. - @examples ``` diff --git a/commands/acl-getuser.md b/commands/acl-getuser.md index 6c2eeedb07..c952e6483a 100644 --- a/commands/acl-getuser.md +++ b/commands/acl-getuser.md @@ -9,10 +9,6 @@ Note: This description of command rules reflects the user's effective permission Selectors are listed in the order they were applied to the user, and include information about commands, key patterns, and channel patterns. -@array-reply: a list of ACL rule definitions for the user. - -If `user` does not exist a @nil-reply is returned. - @examples Here's an example configuration for a user diff --git a/commands/acl-help.md b/commands/acl-help.md index ddb9432f3c..bccd37b243 100644 --- a/commands/acl-help.md +++ b/commands/acl-help.md @@ -1,5 +1,2 @@ The `ACL HELP` command returns a helpful text describing the different subcommands. -@return - -@array-reply: a list of subcommands and their descriptions diff --git a/commands/acl-list.md b/commands/acl-list.md index e21e710437..df7cecde26 100644 --- a/commands/acl-list.md +++ b/commands/acl-list.md @@ -4,10 +4,6 @@ same used in the redis.conf file or the external ACL file, so you can cut and paste what is returned by the ACL LIST command directly inside a configuration file if you wish (but make sure to check `ACL SAVE`). -@return - -An array of strings. - @examples ``` diff --git a/commands/acl-load.md b/commands/acl-load.md index 521c1a6594..f425937ef5 100644 --- a/commands/acl-load.md +++ b/commands/acl-load.md @@ -6,12 +6,6 @@ sure to have an *all or nothing* behavior, that is: * If every line in the file is valid, all the ACLs are loaded. * If one or more line in the file is not valid, nothing is loaded, and the old ACL rules defined in the server memory continue to be used. -@return - -@simple-string-reply: `OK` on success. - -The command may fail with an error for several reasons: if the file is not readable, if there is an error inside the file, and in such case the error will be reported to the user in the error. Finally the command will fail if the server is not configured to use an external ACL file. - @examples ``` diff --git a/commands/acl-log.md b/commands/acl-log.md index c29ce2877d..eb102f66a6 100644 --- a/commands/acl-log.md +++ b/commands/acl-log.md @@ -8,16 +8,6 @@ The optional argument specifies how many entries to show. By default up to ten failures are returned. The special `RESET` argument clears the log. Entries are displayed starting from the most recent. -@return - -When called to show security events: - -@array-reply: a list of ACL security events. - -When called with `RESET`: - -@simple-string-reply: `OK` if the security log was cleared. - @examples ``` diff --git a/commands/acl-save.md b/commands/acl-save.md index 57badc8b78..bfa59a5969 100644 --- a/commands/acl-save.md +++ b/commands/acl-save.md @@ -1,12 +1,6 @@ When Redis is configured to use an ACL file (with the `aclfile` configuration option), this command will save the currently defined ACLs from the server memory to the ACL file. -@return - -@simple-string-reply: `OK` on success. - -The command may fail with an error for several reasons: if the file cannot be written or if the server is not configured to use an external ACL file. - @examples ``` diff --git a/commands/acl-setuser.md b/commands/acl-setuser.md index 15e872c124..3bc31cc0ee 100644 --- a/commands/acl-setuser.md +++ b/commands/acl-setuser.md @@ -84,12 +84,6 @@ This is a list of all the supported Redis ACL rules: * `clearselectors`: (Available in Redis 7.0 and later) Deletes all of the selectors attached to the user. * `reset`: Removes any capability from the user. They are set to off, without passwords, unable to execute any command, unable to access any key. -@return - -@simple-string-reply: `OK` on success. - -If the rules contain errors, the error is returned. - @examples ``` diff --git a/commands/acl-users.md b/commands/acl-users.md index 9b0fe1bf38..b8a40c4c16 100644 --- a/commands/acl-users.md +++ b/commands/acl-users.md @@ -1,10 +1,6 @@ The command shows a list of all the usernames of the currently configured users in the Redis ACL system. -@return - -An array of strings. - @examples ``` diff --git a/commands/acl-whoami.md b/commands/acl-whoami.md index 5ec7b8485b..04a759477b 100644 --- a/commands/acl-whoami.md +++ b/commands/acl-whoami.md @@ -2,10 +2,6 @@ Return the username the current connection is authenticated with. New connections are authenticated with the "default" user. They can change user using `AUTH`. -@return - -@bulk-string-reply: the username of the current connection. - @examples ``` diff --git a/commands/append.md b/commands/append.md index 2c8bd7432f..2f10c8c1e8 100644 --- a/commands/append.md +++ b/commands/append.md @@ -3,10 +3,6 @@ end of the string. If `key` does not exist it is created and set as an empty string, so `APPEND` will be similar to `SET` in this special case. -@return - -@integer-reply: the length of the string after the append operation. - @examples ```cli diff --git a/commands/asking.md b/commands/asking.md index d98643c25c..39b0acb72b 100644 --- a/commands/asking.md +++ b/commands/asking.md @@ -4,7 +4,3 @@ This is normally done automatically by cluster clients. If an `-ASK` redirect is received during a transaction, only one ASKING command needs to be sent to the target node before sending the complete transaction to the target node. See [ASK redirection in the Redis Cluster Specification](/topics/cluster-spec#ask-redirection) for details. - -@return - -@simple-string-reply: `OK`. diff --git a/commands/auth.md b/commands/auth.md index 5062718f69..144aec9a21 100644 --- a/commands/auth.md +++ b/commands/auth.md @@ -30,7 +30,3 @@ Because of the high performance nature of Redis, it is possible to try a lot of passwords in parallel in very short time, so make sure to generate a strong and very long password so that this attack is infeasible. A good way to generate strong passwords is via the `ACL GENPASS` command. - -@return - -@simple-string-reply or an error if the password, or username/password pair, is invalid. diff --git a/commands/bgrewriteaof.md b/commands/bgrewriteaof.md index 85f52040b4..2424a8631f 100644 --- a/commands/bgrewriteaof.md +++ b/commands/bgrewriteaof.md @@ -23,8 +23,3 @@ Please refer to the [persistence documentation][tp] for detailed information. [tp]: /topics/persistence -@return - -@simple-string-reply: A simple string reply indicating that the rewriting started or is about to start ASAP, when the call is executed with success. - -The command may reply with an error in certain cases, as documented above. diff --git a/commands/bgsave.md b/commands/bgsave.md index 714d960716..f6f676326e 100644 --- a/commands/bgsave.md +++ b/commands/bgsave.md @@ -19,6 +19,3 @@ Please refer to the [persistence documentation][tp] for detailed information. [tp]: /topics/persistence -@return - -@simple-string-reply: `Background saving started` if `BGSAVE` started correctly or `Background saving scheduled` when used with the `SCHEDULE` subcommand. diff --git a/commands/bitcount.md b/commands/bitcount.md index 95bd3a3882..3b33703751 100644 --- a/commands/bitcount.md +++ b/commands/bitcount.md @@ -15,12 +15,6 @@ We can use an additional argument `BIT` to specify a bit index. So 0 is the first bit, 1 is the second bit, and so forth. For negative values, -1 is the last bit, -2 is the penultimate, and so forth. -@return - -@integer-reply - -The number of bits set to 1. - @examples ```cli diff --git a/commands/bitfield.md b/commands/bitfield.md index 6609c85b13..0a549acff9 100644 --- a/commands/bitfield.md +++ b/commands/bitfield.md @@ -78,12 +78,6 @@ By default, **WRAP** is used if not otherwise specified. 1) (integer) 0 2) (integer) 3 -## Return value - -The command returns an array with each entry being the corresponding result of -the sub command given at the same position. `OVERFLOW` subcommands don't count -as generating a reply. - The following is an example of `OVERFLOW FAIL` returning NULL. > BITFIELD mykey OVERFLOW FAIL incrby u2 102 1 diff --git a/commands/bitfield_ro.md b/commands/bitfield_ro.md index 94057a1183..26ec064ded 100644 --- a/commands/bitfield_ro.md +++ b/commands/bitfield_ro.md @@ -13,7 +13,3 @@ See original `BITFIELD` for more details. ``` BITFIELD_RO hello GET i8 16 ``` - -@return - -@array-reply: An array with each entry being the corresponding result of the subcommand given at the same position. diff --git a/commands/bitop.md b/commands/bitop.md index fd5aca9b17..e679b449bf 100644 --- a/commands/bitop.md +++ b/commands/bitop.md @@ -24,13 +24,6 @@ zero-padded up to the length of the longest string. The same holds true for non-existent keys, that are considered as a stream of zero bytes up to the length of the longest string. -@return - -@integer-reply - -The size of the string stored in the destination key, that is equal to the -size of the longest input string. - @examples ```cli diff --git a/commands/bitpos.md b/commands/bitpos.md index 1016941418..689926dbc0 100644 --- a/commands/bitpos.md +++ b/commands/bitpos.md @@ -22,20 +22,6 @@ bit, -2 is the penultimate, and so forth. Non-existent keys are treated as empty strings. -@return - -@integer-reply - -The command returns the position of the first bit set to 1 or 0 according to the request. - -If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is returned. - -If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns the first bit not part of the string on the right. So if the string is three bytes set to the value `0xff` the command `BITPOS key 0` will return 24, since up to bit 23 all the bits are 1. - -Basically, the function considers the right of the string as padded with zeros if you look for clear bits and specify no range or the _start_ argument **only**. - -However, this behavior changes if you are looking for clear bits and specify a range with both __start__ and __end__. If no clear bit is found in the specified range, the function returns -1 as the user specified a clear range and there are no 0 bits in that range. - @examples ```cli diff --git a/commands/blmove.md b/commands/blmove.md index 463a2dca28..7a45b13e89 100644 --- a/commands/blmove.md +++ b/commands/blmove.md @@ -10,11 +10,6 @@ This command comes in place of the now deprecated `BRPOPLPUSH`. Doing See `LMOVE` for more information. -@return - -@bulk-string-reply: the element being popped from `source` and pushed to `destination`. -If `timeout` is reached, a @nil-reply is returned. - ## Pattern: Reliable queue Please see the pattern description in the `LMOVE` documentation. diff --git a/commands/blmpop.md b/commands/blmpop.md index 262713ef31..73bac9d284 100644 --- a/commands/blmpop.md +++ b/commands/blmpop.md @@ -6,10 +6,3 @@ When all lists are empty, Redis will block the connection until another client p A `timeout` of zero can be used to block indefinitely. See `LMPOP` for more information. - -@return - -@array-reply: specifically: - -* A `nil` when no element could be popped, and timeout is reached. -* A two-element array with the first element being the name of the key from which elements were popped, and the second element is an array of elements. diff --git a/commands/blpop.md b/commands/blpop.md index 1d73fff19d..5ce6ffb447 100644 --- a/commands/blpop.md +++ b/commands/blpop.md @@ -82,15 +82,6 @@ thing that happens when the timeout is reached. If you like science fiction, think of time flowing at infinite speed inside a `MULTI` / `EXEC` block... -@return - -@array-reply: specifically: - -* A `nil` multi-bulk when no element could be popped and the timeout expired. -* A two-element multi-bulk with the first element being the name of the key - where an element was popped and the second element being the value of the - popped element. - @examples ``` diff --git a/commands/brpop.md b/commands/brpop.md index dfa2b91cac..08806cff53 100644 --- a/commands/brpop.md +++ b/commands/brpop.md @@ -10,15 +10,6 @@ the tail of a list instead of popping from the head. [cb]: /commands/blpop -@return - -@array-reply: specifically: - -* A `nil` multi-bulk when no element could be popped and the timeout expired. -* A two-element multi-bulk with the first element being the name of the key - where an element was popped and the second element being the value of the - popped element. - @examples ``` diff --git a/commands/brpoplpush.md b/commands/brpoplpush.md index 9a6fe376d9..3989fd67fe 100644 --- a/commands/brpoplpush.md +++ b/commands/brpoplpush.md @@ -7,11 +7,6 @@ A `timeout` of zero can be used to block indefinitely. See `RPOPLPUSH` for more information. -@return - -@bulk-string-reply: the element being popped from `source` and pushed to `destination`. -If `timeout` is reached, a @nil-reply is returned. - ## Pattern: Reliable queue Please see the pattern description in the `RPOPLPUSH` documentation. diff --git a/commands/bzmpop.md b/commands/bzmpop.md index dc0c077d96..50c25709c0 100644 --- a/commands/bzmpop.md +++ b/commands/bzmpop.md @@ -6,11 +6,3 @@ When all sorted sets are empty, Redis will block the connection until another cl A `timeout` of zero can be used to block indefinitely. See `ZMPOP` for more information. - -@return - -@array-reply: specifically: - -* A `nil` when no element could be popped. -* A two-element array with the first element being the name of the key from which elements were popped, and the second element is an array of the popped elements. Every entry in the elements array is also an array that contains the member and its score. - diff --git a/commands/bzpopmax.md b/commands/bzpopmax.md index 8155ed8b99..c6d726f4db 100644 --- a/commands/bzpopmax.md +++ b/commands/bzpopmax.md @@ -14,15 +14,6 @@ with the highest scores instead of popping the ones with the lowest scores. [cb]: /commands/bzpopmin -@return - -@array-reply: specifically: - -* A `nil` multi-bulk when no element could be popped and the timeout expired. -* A three-element multi-bulk with the first element being the name of the key - where a member was popped, the second element is the popped member itself, - and the third element is the score of the popped element. - @examples ``` diff --git a/commands/bzpopmin.md b/commands/bzpopmin.md index b48a4fb759..936154d051 100644 --- a/commands/bzpopmin.md +++ b/commands/bzpopmin.md @@ -14,15 +14,6 @@ popped from. [cl]: /commands/blpop -@return - -@array-reply: specifically: - -* A `nil` multi-bulk when no element could be popped and the timeout expired. -* A three-element multi-bulk with the first element being the name of the key - where a member was popped, the second element is the popped member itself, - and the third element is the score of the popped element. - @examples ``` diff --git a/commands/client-caching.md b/commands/client-caching.md index 1f4b8b8a3e..e3bf90ee86 100644 --- a/commands/client-caching.md +++ b/commands/client-caching.md @@ -16,7 +16,3 @@ tracked using `CLIENT CACHING no`. Basically the command sets a state in the connection, that is valid only for the next command execution, that will modify the behavior of client tracking. - -@return - -@simple-string-reply: `OK` or an error if the argument is not yes or no. diff --git a/commands/client-getname.md b/commands/client-getname.md index f60539dd02..0991c6eea9 100644 --- a/commands/client-getname.md +++ b/commands/client-getname.md @@ -1,5 +1 @@ The `CLIENT GETNAME` returns the name of the current connection as set by `CLIENT SETNAME`. Since every new connection starts without an associated name, if no name was assigned a null bulk reply is returned. - -@return - -@bulk-string-reply: The connection name, or a null bulk reply if no name is set. diff --git a/commands/client-getredir.md b/commands/client-getredir.md index 2cc326957f..dcc623c1a8 100644 --- a/commands/client-getredir.md +++ b/commands/client-getredir.md @@ -5,7 +5,3 @@ order to avoid forcing client libraries implementations to remember the ID notifications are redirected to, this command exists in order to improve introspection and allow clients to check later if redirection is active and towards which client ID. - -@return - -@integer-reply: the ID of the client we are redirecting the notifications to. The command returns `-1` if client tracking is not enabled, or `0` if client tracking is enabled but we are not redirecting the notifications to any client. diff --git a/commands/client-help.md b/commands/client-help.md index 964a625740..6745f6cf24 100644 --- a/commands/client-help.md +++ b/commands/client-help.md @@ -1,5 +1 @@ The `CLIENT HELP` command returns a helpful text describing the different subcommands. - -@return - -@array-reply: a list of subcommands and their descriptions diff --git a/commands/client-id.md b/commands/client-id.md index fe6723c513..53fcac5016 100644 --- a/commands/client-id.md +++ b/commands/client-id.md @@ -12,9 +12,3 @@ introduced also in Redis 5 together with `CLIENT ID`. Check the `CLIENT UNBLOCK` ```cli CLIENT ID ``` - -@return - -@integer-reply - -The id of the client. diff --git a/commands/client-info.md b/commands/client-info.md index f60592e175..5eea826ba8 100644 --- a/commands/client-info.md +++ b/commands/client-info.md @@ -7,7 +7,3 @@ The reply format is identical to that of `CLIENT LIST`, and the content consists ```cli CLIENT INFO ``` - -@return - -@bulk-string-reply: a unique string, as described at the `CLIENT LIST` page, for the current client. diff --git a/commands/client-kill.md b/commands/client-kill.md index ea65aaf3ea..a8f02c65a2 100644 --- a/commands/client-kill.md +++ b/commands/client-kill.md @@ -41,13 +41,3 @@ the client point of view, the connection can never be closed in the middle of the execution of a command. However, the client will notice the connection has been closed only when the next command is sent (and results in network error). - -@return - -When called with the three arguments format: - -@simple-string-reply: `OK` if the connection exists and has been closed - -When called with the filter / value format: - -@integer-reply: the number of clients killed. diff --git a/commands/client-list.md b/commands/client-list.md index e24c7e1e2e..0eb1c735d8 100644 --- a/commands/client-list.md +++ b/commands/client-list.md @@ -5,14 +5,6 @@ You can use one of the optional subcommands to filter the list. The `TYPE type` The `ID` filter only returns entries for clients with IDs matching the `client-id` arguments. -@return - -@bulk-string-reply: a unique string, formatted as follows: - -* One client connection per line (separated by LF) -* Each line is composed of a succession of `property=value` fields separated - by a space character. - Here is the meaning of the fields: * `id`: a unique 64-bit client ID diff --git a/commands/client-no-evict.md b/commands/client-no-evict.md index 70070a6abb..2a18898e41 100644 --- a/commands/client-no-evict.md +++ b/commands/client-no-evict.md @@ -5,7 +5,3 @@ When turned on and client eviction is configured, the current connection will be When turned off, the current client will be re-included in the pool of potential clients to be evicted (and evicted if needed). See [client eviction](/topics/clients#client-eviction) for more details. - -@return - -@simple-string-reply: `OK`. diff --git a/commands/client-no-touch.md b/commands/client-no-touch.md index 36e69dec77..da723058bc 100644 --- a/commands/client-no-touch.md +++ b/commands/client-no-touch.md @@ -3,7 +3,3 @@ The `CLIENT NO-TOUCH` command controls whether commands sent by the client will When turned on, the current client will not change LFU/LRU stats, unless it sends the `TOUCH` command. When turned off, the client touches LFU/LRU stats just as a normal client. - -@return - -@simple-string-reply: `OK`. diff --git a/commands/client-pause.md b/commands/client-pause.md index 6f778da1e7..d7c381f9c0 100644 --- a/commands/client-pause.md +++ b/commands/client-pause.md @@ -35,10 +35,6 @@ Since Redis 3.2.10 / 4.0.0, this command also prevents keys to be evicted or expired during the time clients are paused. This way the dataset is guaranteed to be static not just from the point of view of clients not being able to write, but also from the point of view of internal operations. -@return - -@simple-string-reply: The command returns OK or an error if the timeout is invalid. - ## Behavior change history * `>= 3.2.0`: Client pause prevents client pause and key eviction as well. \ No newline at end of file diff --git a/commands/client-reply.md b/commands/client-reply.md index f2c3ed8b42..63608e60a9 100644 --- a/commands/client-reply.md +++ b/commands/client-reply.md @@ -5,9 +5,3 @@ The `CLIENT REPLY` command controls whether the server will reply the client's c * `ON`. This is the default mode in which the server returns a reply to every command. * `OFF`. In this mode the server will not reply to client commands. * `SKIP`. This mode skips the reply of command immediately after it. - -@return - -When called with either `OFF` or `SKIP` subcommands, no reply is made. When called with `ON`: - -@simple-string-reply: `OK`. diff --git a/commands/client-setinfo.md b/commands/client-setinfo.md index b6ff217411..64a66f3734 100644 --- a/commands/client-setinfo.md +++ b/commands/client-setinfo.md @@ -10,7 +10,3 @@ Currently the supported attributes are: There is no limit to the length of these attributes. However it is not possible to use spaces, newlines, or other non-printable characters that would violate the format of the `CLIENT LIST` reply. Note that these attributes are **not** cleared by the RESET command. - -@return - -@simple-string-reply: `OK` if the attribute name was successfully set. diff --git a/commands/client-setname.md b/commands/client-setname.md index c1e70af259..f0a147921b 100644 --- a/commands/client-setname.md +++ b/commands/client-setname.md @@ -13,7 +13,3 @@ The connection name can be inspected using `CLIENT GETNAME`. Every new connection starts without an assigned name. Tip: setting names to connections is a good way to debug connection leaks due to bugs in the application using Redis. - -@return - -@simple-string-reply: `OK` if the connection name was successfully set. diff --git a/commands/client-tracking.md b/commands/client-tracking.md index e77f7d907e..503d4dca62 100644 --- a/commands/client-tracking.md +++ b/commands/client-tracking.md @@ -27,7 +27,3 @@ command when enabling tracking: * `OPTIN`: when broadcasting is NOT active, normally don't track keys in read only commands, unless they are called immediately after a `CLIENT CACHING yes` command. * `OPTOUT`: when broadcasting is NOT active, normally track keys in read only commands, unless they are called immediately after a `CLIENT CACHING no` command. * `NOLOOP`: don't send notifications about keys modified by this connection itself. - -@return - -@simple-string-reply: `OK` if the connection was successfully put in tracking mode or if the tracking mode was successfully disabled. Otherwise an error is returned. diff --git a/commands/client-trackinginfo.md b/commands/client-trackinginfo.md index 82de43e255..6cc0df14ab 100644 --- a/commands/client-trackinginfo.md +++ b/commands/client-trackinginfo.md @@ -1,8 +1,6 @@ The command returns information about the current client connection's use of the [server assisted client side caching](/topics/client-side-caching) feature. -@return - -@array-reply: a list of tracking information sections and their respective values, specifically: +Here's the list of tracking information sections and their respective values: * **flags**: A list of tracking flags used by the connection. The flags and their meanings are as follows: * `off`: The connection isn't using server assisted client side caching. diff --git a/commands/client-unblock.md b/commands/client-unblock.md index 11dff98ce7..36e70b2924 100644 --- a/commands/client-unblock.md +++ b/commands/client-unblock.md @@ -49,10 +49,3 @@ NULL > BRPOP key1 key2 key3 key4 0 (client is blocked again) ``` - -@return - -@integer-reply, specifically: - -* `1` if the client was unblocked successfully. -* `0` if the client wasn't unblocked. diff --git a/commands/client-unpause.md b/commands/client-unpause.md index c43848522f..9878ee1b3c 100644 --- a/commands/client-unpause.md +++ b/commands/client-unpause.md @@ -1,5 +1 @@ `CLIENT UNPAUSE` is used to resume command processing for all clients that were paused by `CLIENT PAUSE`. - -@return - -@simple-string-reply: The command returns `OK` diff --git a/commands/cluster-addslots.md b/commands/cluster-addslots.md index 9c9a8c012e..101f671506 100644 --- a/commands/cluster-addslots.md +++ b/commands/cluster-addslots.md @@ -45,7 +45,3 @@ This means that this command should be used with care only by applications orchestrating Redis Cluster, like `redis-cli`, and the command if used out of the right context can leave the cluster in a wrong state or cause data loss. - -@return - -@simple-string-reply: `OK` if the command was successful. Otherwise an error is returned. diff --git a/commands/cluster-addslotsrange.md b/commands/cluster-addslotsrange.md index 6e7c545fc1..1fc1cd3d8b 100644 --- a/commands/cluster-addslotsrange.md +++ b/commands/cluster-addslotsrange.md @@ -21,7 +21,3 @@ This command only works in cluster mode and is useful in the following Redis Clu 1. To create a new cluster, `CLUSTER ADDSLOTSRANGE` is used to initially set up master nodes splitting the available hash slots among them. 2. In order to fix a broken cluster where certain slots are unassigned. - -@return - -@simple-string-reply: `OK` if the command was successful. Otherwise an error is returned. diff --git a/commands/cluster-bumpepoch.md b/commands/cluster-bumpepoch.md index b05694a442..68bce48797 100644 --- a/commands/cluster-bumpepoch.md +++ b/commands/cluster-bumpepoch.md @@ -3,7 +3,3 @@ Advances the cluster config epoch. The `CLUSTER BUMPEPOCH` command triggers an increment to the cluster's config epoch from the connected node. The epoch will be incremented if the node's config epoch is zero, or if it is less than the cluster's greatest epoch. **Note:** config epoch management is performed internally by the cluster, and relies on obtaining a consensus of nodes. The `CLUSTER BUMPEPOCH` attempts to increment the config epoch **WITHOUT** getting the consensus, so using it may violate the "last failover wins" rule. Use it with caution. - -@return - -@simple-string-reply: `BUMPED` if the epoch was incremented, or `STILL` if the node already has the greatest config epoch in the cluster. diff --git a/commands/cluster-count-failure-reports.md b/commands/cluster-count-failure-reports.md index ac1ef71c0e..399a6bc000 100644 --- a/commands/cluster-count-failure-reports.md +++ b/commands/cluster-count-failure-reports.md @@ -16,7 +16,3 @@ This command returns the number of failure reports for the current node which ar This command is mainly useful for debugging, when the failure detector of Redis Cluster is not operating as we believe it should. - -@return - -@integer-reply: the number of active failure reports for the node. diff --git a/commands/cluster-countkeysinslot.md b/commands/cluster-countkeysinslot.md index 0bffec84b5..2a6e6af4f8 100644 --- a/commands/cluster-countkeysinslot.md +++ b/commands/cluster-countkeysinslot.md @@ -7,7 +7,3 @@ zero being returned. > CLUSTER COUNTKEYSINSLOT 7000 (integer) 50341 ``` - -@return - -@integer-reply: The number of keys in the specified hash slot, or an error if the hash slot is invalid. diff --git a/commands/cluster-delslots.md b/commands/cluster-delslots.md index 77204e1e95..4fdb4a5180 100644 --- a/commands/cluster-delslots.md +++ b/commands/cluster-delslots.md @@ -41,8 +41,3 @@ This command only works in cluster mode and may be useful for debugging and in order to manually orchestrate a cluster configuration when a new cluster is created. It is currently not used by `redis-cli`, and mainly exists for API completeness. - -@return - -@simple-string-reply: `OK` if the command was successful. Otherwise -an error is returned. diff --git a/commands/cluster-delslotsrange.md b/commands/cluster-delslotsrange.md index e4c1f2b89d..af902ff586 100644 --- a/commands/cluster-delslotsrange.md +++ b/commands/cluster-delslotsrange.md @@ -25,8 +25,3 @@ This command only works in cluster mode and may be useful for debugging and in order to manually orchestrate a cluster configuration when a new cluster is created. It is currently not used by `redis-cli`, and mainly exists for API completeness. - -@return - -@simple-string-reply: `OK` if the command was successful. Otherwise -an error is returned. diff --git a/commands/cluster-failover.md b/commands/cluster-failover.md index 911eaea894..85834cba67 100644 --- a/commands/cluster-failover.md +++ b/commands/cluster-failover.md @@ -61,7 +61,3 @@ Because of this the **TAKEOVER** option should be used with care. To check that the masters are aware of a new replica, you can send `CLUSTER NODES` or `CLUSTER REPLICAS` to each of the master nodes and check that it appears as a replica, before sending `CLUSTER FAILOVER` to the replica. * To check that the failover has actually happened you can use `ROLE`, `INFO REPLICATION` (which indicates "role:master" after successful failover), or `CLUSTER NODES` to verify that the state of the cluster has changed sometime after the command was sent. * To check if the failover has failed, check the replica's log for "Manual failover timed out", which is logged if the replica has given up after a few seconds. - -@return - -@simple-string-reply: `OK` if the command was accepted and a manual failover is going to be attempted. An error if the operation cannot be executed, for example if we are talking with a node which is already a master. diff --git a/commands/cluster-flushslots.md b/commands/cluster-flushslots.md index b0b3fdfba6..0c8984ff23 100644 --- a/commands/cluster-flushslots.md +++ b/commands/cluster-flushslots.md @@ -1,7 +1,3 @@ Deletes all slots from a node. The `CLUSTER FLUSHSLOTS` deletes all information about slots from the connected node. It can only be called when the database is empty. - -@return - -@simple-string-reply: `OK` diff --git a/commands/cluster-forget.md b/commands/cluster-forget.md index 6bff5061fe..afc06414df 100644 --- a/commands/cluster-forget.md +++ b/commands/cluster-forget.md @@ -51,7 +51,3 @@ The command does not succeed and returns an error in the following cases: 1. The specified node ID is not found in the nodes table. 2. The node receiving the command is a replica, and the specified node ID identifies its current master. 3. The node ID identifies the same node we are sending the command to. - -@return - -@simple-string-reply: `OK` if the command was executed successfully, otherwise an error is returned. diff --git a/commands/cluster-getkeysinslot.md b/commands/cluster-getkeysinslot.md index 120bf4412d..dec113df05 100644 --- a/commands/cluster-getkeysinslot.md +++ b/commands/cluster-getkeysinslot.md @@ -14,7 +14,3 @@ of the `CLUSTER SETSLOT` command documentation. 2) "key_89793" 3) "key_92937" ``` - -@return - -@array-reply: From 0 to *count* key names in a Redis array reply. diff --git a/commands/cluster-help.md b/commands/cluster-help.md index 3b1e159006..85579bd446 100644 --- a/commands/cluster-help.md +++ b/commands/cluster-help.md @@ -1,5 +1 @@ The `CLUSTER HELP` command returns a helpful text describing the different subcommands. - -@return - -@array-reply: a list of subcommands and their descriptions diff --git a/commands/cluster-info.md b/commands/cluster-info.md index 372cc73906..3f49280aca 100644 --- a/commands/cluster-info.md +++ b/commands/cluster-info.md @@ -46,7 +46,3 @@ Here are the explanation of these fields: * `cluster_stats_messages_publishshard_sent` and `cluster_stats_messages_publishshard_received`: Pub/Sub Publish shard propagation, see [Sharded Pubsub](/topics/pubsub#sharded-pubsub). More information about the Current Epoch and Config Epoch variables are available in the [Redis Cluster specification document](/topics/cluster-spec#cluster-current-epoch). - -@return - -@bulk-string-reply: A map between named fields and values in the form of `:` lines separated by newlines composed by the two bytes `CRLF`. diff --git a/commands/cluster-keyslot.md b/commands/cluster-keyslot.md index 7e0358785c..1556874255 100644 --- a/commands/cluster-keyslot.md +++ b/commands/cluster-keyslot.md @@ -18,7 +18,3 @@ Example use cases for this command: ``` Note that the command implements the full hashing algorithm, including support for **hash tags**, that is the special property of Redis Cluster key hashing algorithm, of hashing just what is between `{` and `}` if such a pattern is found inside the key name, in order to force multiple keys to be handled by the same node. - -@return - -@integer-reply: The hash slot number. diff --git a/commands/cluster-links.md b/commands/cluster-links.md index 7b3376298c..12e7630e68 100644 --- a/commands/cluster-links.md +++ b/commands/cluster-links.md @@ -42,7 +42,3 @@ Each map is composed of the following attributes of the corresponding cluster li 4. `events`: Events currently registered for the link. `r` means readable event, `w` means writable event. 5. `send-buffer-allocated`: Allocated size of the link's send buffer, which is used to buffer outgoing messages toward the peer. 6. `send-buffer-used`: Size of the portion of the link's send buffer that is currently holding data(messages). - -@return - -@array-reply: An array of maps where each map contains various attributes and their values of a cluster link. diff --git a/commands/cluster-meet.md b/commands/cluster-meet.md index b33c9fb749..0ce7c212f6 100644 --- a/commands/cluster-meet.md +++ b/commands/cluster-meet.md @@ -36,7 +36,3 @@ the node to force the receiver to accept it as a trusted node, it sends a `MEET` packet instead of a `PING` packet. The two packets have exactly the same format, but the former forces the receiver to acknowledge the node as trusted. - -@return - -@simple-string-reply: `OK` if the command was successful. If the address or port specified are invalid an error is returned. diff --git a/commands/cluster-myid.md b/commands/cluster-myid.md index 02e8b1d3b6..594c28b3f4 100644 --- a/commands/cluster-myid.md +++ b/commands/cluster-myid.md @@ -1,7 +1,3 @@ Returns the node's id. The `CLUSTER MYID` command returns the unique, auto-generated identifier that is associated with the connected cluster node. - -@return - -@bulk-string-reply: The node id. \ No newline at end of file diff --git a/commands/cluster-myshardid.md b/commands/cluster-myshardid.md index 4334b150a0..6ffb3c5b9b 100644 --- a/commands/cluster-myshardid.md +++ b/commands/cluster-myshardid.md @@ -1,7 +1,3 @@ Returns the node's shard id. The `CLUSTER MYSHARDID` command returns the unique, auto-generated identifier that is associated with the shard to which the connected cluster node belongs. - -@return - -@bulk-string-reply: The node's shard id. diff --git a/commands/cluster-nodes.md b/commands/cluster-nodes.md index e5bfb7bc95..3f5499ca0e 100644 --- a/commands/cluster-nodes.md +++ b/commands/cluster-nodes.md @@ -104,8 +104,4 @@ Note that: 1. Migration and importing slots are only added to the node flagged as `myself`. This information is local to a node, for its own slots. 2. Importing and migrating slots are provided as **additional info**. If the node has a given hash slot assigned, it will be also a plain number in the list of hash slots, so clients that don't have a clue about hash slots migrations can just skip this special fields. -@return - -@bulk-string-reply: The serialized cluster configuration. - **A note about the word slave used in this man page and command name**: Starting with Redis 5, if not for backward compatibility, the Redis project no longer uses the word slave. Unfortunately in this command the word slave is part of the protocol, so we'll be able to remove such occurrences only when this API will be naturally deprecated. diff --git a/commands/cluster-replicas.md b/commands/cluster-replicas.md index 4e6192e117..6d0e63708e 100644 --- a/commands/cluster-replicas.md +++ b/commands/cluster-replicas.md @@ -9,7 +9,3 @@ and we ask `CLUSTER REPLICAS` to a node that has not yet received the configuration update, it may show stale information. However eventually (in a matter of seconds if there are no network partitions) all the nodes will agree about the set of nodes associated with a given master. - -@return - -The command returns data in the same format as `CLUSTER NODES`. diff --git a/commands/cluster-replicate.md b/commands/cluster-replicate.md index 5b403aaa8b..9d3c36d280 100644 --- a/commands/cluster-replicate.md +++ b/commands/cluster-replicate.md @@ -20,7 +20,3 @@ only if the following additional conditions are met: 2. The node is empty, no keys are stored at all in the key space. If the command succeeds the new replica will immediately try to contact its master in order to replicate from it. - -@return - -@simple-string-reply: `OK` if the command was executed successfully, otherwise an error is returned. diff --git a/commands/cluster-reset.md b/commands/cluster-reset.md index 02ffe9eb95..1d76229342 100644 --- a/commands/cluster-reset.md +++ b/commands/cluster-reset.md @@ -19,7 +19,3 @@ is also extensively used by the Redis Cluster testing framework in order to reset the state of the cluster every time a new test unit is executed. If no reset type is specified, the default is **soft**. - -@return - -@simple-string-reply: `OK` if the command was successful. Otherwise an error is returned. diff --git a/commands/cluster-saveconfig.md b/commands/cluster-saveconfig.md index 31308c2028..3f23701963 100644 --- a/commands/cluster-saveconfig.md +++ b/commands/cluster-saveconfig.md @@ -9,7 +9,3 @@ configuration via the `CLUSTER` command in order to ensure the new configuration is persisted on disk, however all the commands should normally be able to auto schedule to persist the configuration on disk when it is important to do so for the correctness of the system in the event of a restart. - -@return - -@simple-string-reply: `OK` or an error if the operation fails. diff --git a/commands/cluster-set-config-epoch.md b/commands/cluster-set-config-epoch.md index 71f458f33e..5eb7fca262 100644 --- a/commands/cluster-set-config-epoch.md +++ b/commands/cluster-set-config-epoch.md @@ -19,7 +19,3 @@ configuration epoch. So, using `CLUSTER SET-CONFIG-EPOCH`, when a new cluster is created, we can assign a different progressive configuration epoch to each node before joining the cluster together. - -@return - -@simple-string-reply: `OK` if the command was executed successfully, otherwise an error is returned. diff --git a/commands/cluster-setslot.md b/commands/cluster-setslot.md index e712d36ba6..ab32c6772c 100644 --- a/commands/cluster-setslot.md +++ b/commands/cluster-setslot.md @@ -60,10 +60,6 @@ command: It is important to note that step 3 is the only time when a Redis Cluster node will create a new config epoch without agreement from other nodes. This only happens when a manual configuration is operated. However it is impossible that this creates a non-transient setup where two nodes have the same config epoch, since Redis Cluster uses a config epoch collision resolution algorithm. -@return - -@simple-string-reply: All the subcommands return `OK` if the command was successful. Otherwise an error is returned. - ## Redis Cluster live resharding explained The `CLUSTER SETSLOT` command is an important piece used by Redis Cluster in order to migrate all the keys contained in one hash slot from one node to another. This is how the migration is orchestrated, with the help of other commands as well. We'll call the node that has the current ownership of the hash slot the `source` node, and the node where we want to migrate the `destination` node. diff --git a/commands/cluster-shards.md b/commands/cluster-shards.md index 8d5c8fd4cc..a6989a3910 100644 --- a/commands/cluster-shards.md +++ b/commands/cluster-shards.md @@ -50,10 +50,6 @@ This can happen in a cluster that consists of only one node or the node has not The value `?` is displayed if the node is incorrectly configured to use announced hostnames but no hostname is configured using `cluster-announce-hostname`. Clients may treat the empty string in the same way as NULL, that is the same endpoint it used to send the current command to, while `"?"` should be treated as an unknown node, not necessarily the same node as the one serving the current command. -@return - -@array-reply: nested list of a map of hash ranges and shard nodes. - @examples ``` diff --git a/commands/cluster-slaves.md b/commands/cluster-slaves.md index d90eaf38c5..2f4f9628af 100644 --- a/commands/cluster-slaves.md +++ b/commands/cluster-slaves.md @@ -11,7 +11,3 @@ and we ask `CLUSTER SLAVES` to a node that has not yet received the configuration update, it may show stale information. However eventually (in a matter of seconds if there are no network partitions) all the nodes will agree about the set of nodes associated with a given master. - -@return - -The command returns data in the same format as `CLUSTER NODES`. diff --git a/commands/cluster-slots.md b/commands/cluster-slots.md index b3166bbf28..be07af62e8 100644 --- a/commands/cluster-slots.md +++ b/commands/cluster-slots.md @@ -41,12 +41,6 @@ All networking information after the third nested reply are replicas of the mast If a cluster instance has non-contiguous slots (e.g. 1-400,900,1800-6000) then master and replica networking information results will be duplicated for each top-level slot range reply. -@return - -@array-reply: nested list of slot ranges with networking information. - -@examples - ``` > CLUSTER SLOTS 1) 1) (integer) 0 diff --git a/commands/command-count.md b/commands/command-count.md index a198dd35ac..2eee36f22e 100644 --- a/commands/command-count.md +++ b/commands/command-count.md @@ -1,9 +1,5 @@ Returns @integer-reply of number of total commands in this Redis server. -@return - -@integer-reply: number of commands returned by `COMMAND` - @examples ```cli diff --git a/commands/command-docs.md b/commands/command-docs.md index 35ea017f2a..99e431b177 100644 --- a/commands/command-docs.md +++ b/commands/command-docs.md @@ -44,10 +44,6 @@ The following keys may be included in the mapped reply: [td]: /topics/command-arguments -@return - -@array-reply: a map as a flattened array as described above. - @examples ```cli diff --git a/commands/command-getkeys.md b/commands/command-getkeys.md index 6b8f300253..6e9b756adf 100644 --- a/commands/command-getkeys.md +++ b/commands/command-getkeys.md @@ -7,11 +7,6 @@ from a full Redis command. but in some cases it's not possible to find keys of certain commands and then the entire command must be parsed to discover some / all key names. You can use `COMMAND GETKEYS` or `COMMAND GETKEYSANDFLAGS` to discover key names directly from how Redis parses the commands. - -@return - -@array-reply: list of keys from your command. - @examples ```cli diff --git a/commands/command-getkeysandflags.md b/commands/command-getkeysandflags.md index 3fa479d02d..0f83afa7db 100644 --- a/commands/command-getkeysandflags.md +++ b/commands/command-getkeysandflags.md @@ -8,11 +8,6 @@ You can use `COMMAND GETKEYS` or `COMMAND GETKEYSANDFLAGS` to discover key names Refer to [key specifications](/topics/key-specs#logical-operation-flags) for information about the meaning of the key flags. -@return - -@array-reply: list of keys from your command. -Each element of the array is an array containing key name in the first entry, and flags in the second. - @examples ```cli diff --git a/commands/command-help.md b/commands/command-help.md index 73d4cc4812..80aa033dea 100644 --- a/commands/command-help.md +++ b/commands/command-help.md @@ -1,5 +1 @@ The `COMMAND HELP` command returns a helpful text describing the different subcommands. - -@return - -@array-reply: a list of subcommands and their descriptions diff --git a/commands/command-info.md b/commands/command-info.md index e16a5550c7..568f70a47b 100644 --- a/commands/command-info.md +++ b/commands/command-info.md @@ -6,11 +6,6 @@ get returned. If you request details about non-existing commands, their return position will be nil. - -@return - -@array-reply: nested list of command details. - @examples ```cli diff --git a/commands/command-list.md b/commands/command-list.md index 85cc453afb..60b6981b43 100644 --- a/commands/command-list.md +++ b/commands/command-list.md @@ -5,7 +5,3 @@ You can use the optional _FILTERBY_ modifier to apply one of the following filte - **MODULE module-name**: get the commands that belong to the module specified by _module-name_. - **ACLCAT category**: get the commands in the [ACL category](/docs/management/security/acl/#command-categories) specified by _category_. - **PATTERN pattern**: get the commands that match the given glob-like _pattern_. - -@return - -@array-reply: a list of command names. diff --git a/commands/command.md b/commands/command.md index 37545f9bd9..9a66f6cd07 100644 --- a/commands/command.md +++ b/commands/command.md @@ -196,12 +196,6 @@ Each element in the array represents one subcommand and follows the same specifi [td]: /topics/key-specs [tr]: /topics/key-specs -@return - -@array-reply: a nested list of command details. - -The order of commands in the array is random. - @examples The following is `COMMAND`'s output for the `GET` command: diff --git a/commands/config-get.md b/commands/config-get.md index d2e85a38c7..312abd4137 100644 --- a/commands/config-get.md +++ b/commands/config-get.md @@ -38,8 +38,3 @@ configuration parameter used in the [redis.conf][hgcarr22rc] file: Note that you should look at the redis.conf file relevant to the version you're working with as configuration options might change between versions. The link above is to the latest development version. - - -@return - -The return type of the command is a @array-reply. diff --git a/commands/config-help.md b/commands/config-help.md index 5f8bc48248..b45bebd154 100644 --- a/commands/config-help.md +++ b/commands/config-help.md @@ -1,5 +1 @@ The `CONFIG HELP` command returns a helpful text describing the different subcommands. - -@return - -@array-reply: a list of subcommands and their descriptions diff --git a/commands/config-resetstat.md b/commands/config-resetstat.md index be5dee9ebc..0c8789e7d0 100644 --- a/commands/config-resetstat.md +++ b/commands/config-resetstat.md @@ -8,7 +8,3 @@ The following is a non-exhaustive list of values that are reset: * Connections received, rejected and evicted * Persistence statistics * Active defragmentation statistics - -@return - -@simple-string-reply: always `OK`. diff --git a/commands/config-rewrite.md b/commands/config-rewrite.md index c1031561bf..f4714975fd 100644 --- a/commands/config-rewrite.md +++ b/commands/config-rewrite.md @@ -13,8 +13,3 @@ CONFIG REWRITE is also able to rewrite the configuration file from scratch if th ## Atomic rewrite process In order to make sure the redis.conf file is always consistent, that is, on errors or crashes you always end with the old file, or the new one, the rewrite is performed with a single `write(2)` call that has enough content to be at least as big as the old file. Sometimes additional padding in the form of comments is added in order to make sure the resulting file is big enough, and later the file gets truncated to remove the padding at the end. - -@return - -@simple-string-reply: `OK` when the configuration was rewritten properly. -Otherwise an error is returned. diff --git a/commands/config-set.md b/commands/config-set.md index 4b0841e049..02576fadc4 100644 --- a/commands/config-set.md +++ b/commands/config-set.md @@ -34,8 +34,3 @@ Redis server that started with AOF turned on since the start. You can have both the AOF enabled with RDB snapshotting if you want, the two options are not mutually exclusive. - -@return - -@simple-string-reply: `OK` when the configuration was set properly. -Otherwise an error is returned. diff --git a/commands/copy.md b/commands/copy.md index 62b04fc651..247c6c6478 100644 --- a/commands/copy.md +++ b/commands/copy.md @@ -8,13 +8,6 @@ index for the destination key. The command returns zero when the `destination` key already exists. The `REPLACE` option removes the `destination` key before copying the value to it. -@return - -@integer-reply, specifically: - -* `1` if `source` was copied. -* `0` if `source` was not copied. - @examples ``` diff --git a/commands/dbsize.md b/commands/dbsize.md index fe82aa78cb..7aa2fb857e 100644 --- a/commands/dbsize.md +++ b/commands/dbsize.md @@ -1,5 +1 @@ Return the number of keys in the currently-selected database. - -@return - -@integer-reply diff --git a/commands/decr.md b/commands/decr.md index cda121a932..ca6150a40e 100644 --- a/commands/decr.md +++ b/commands/decr.md @@ -6,10 +6,6 @@ This operation is limited to **64 bit signed integers**. See `INCR` for extra information on increment/decrement operations. -@return - -@integer-reply: the value of `key` after the decrement - @examples ```cli diff --git a/commands/decrby.md b/commands/decrby.md index b2e823b7e6..b0b4ebadb3 100644 --- a/commands/decrby.md +++ b/commands/decrby.md @@ -6,10 +6,6 @@ This operation is limited to 64 bit signed integers. See `INCR` for extra information on increment/decrement operations. -@return - -@integer-reply: the value of `key` after the decrement - @examples ```cli diff --git a/commands/del.md b/commands/del.md index d5fcbaced5..b20b1e863f 100644 --- a/commands/del.md +++ b/commands/del.md @@ -1,10 +1,6 @@ Removes the specified keys. A key is ignored if it does not exist. -@return - -@integer-reply: The number of keys that were removed. - @examples ```cli diff --git a/commands/discard.md b/commands/discard.md index d84b50331c..a4064ddd74 100644 --- a/commands/discard.md +++ b/commands/discard.md @@ -4,7 +4,3 @@ connection state to normal. [tt]: /topics/transactions If `WATCH` was used, `DISCARD` unwatches all keys watched by the connection. - -@return - -@simple-string-reply: always `OK`. diff --git a/commands/dump.md b/commands/dump.md index 0446386cc1..e06b501911 100644 --- a/commands/dump.md +++ b/commands/dump.md @@ -21,10 +21,6 @@ should be used. If `key` does not exist a nil bulk reply is returned. -@return - -@bulk-string-reply: the serialized value. - @examples ``` diff --git a/commands/echo.md b/commands/echo.md index 642d0f3a1d..e158e8910d 100644 --- a/commands/echo.md +++ b/commands/echo.md @@ -1,9 +1,5 @@ Returns `message`. -@return - -@bulk-string-reply - @examples ```cli diff --git a/commands/exec.md b/commands/exec.md index b2f58fef8b..2dada72b72 100644 --- a/commands/exec.md +++ b/commands/exec.md @@ -7,10 +7,3 @@ When using `WATCH`, `EXEC` will execute commands only if the watched keys were not modified, allowing for a [check-and-set mechanism][ttc]. [ttc]: /topics/transactions#cas - -@return - -@array-reply: each element being the reply to each of the commands in the -atomic transaction. - -When using `WATCH`, `EXEC` can return a @nil-reply if the execution was aborted. diff --git a/commands/exists.md b/commands/exists.md index a9a89afbad..c8a20239d7 100644 --- a/commands/exists.md +++ b/commands/exists.md @@ -2,10 +2,6 @@ Returns if `key` exists. The user should be aware that if the same existing key is mentioned in the arguments multiple times, it will be counted multiple times. So if `somekey` exists, `EXISTS somekey somekey` will return 2. -@return - -@integer-reply, specifically the number of keys that exist from those specified as arguments. - @examples ```cli diff --git a/commands/expire.md b/commands/expire.md index ddb4c9ad12..7aca62f81f 100644 --- a/commands/expire.md +++ b/commands/expire.md @@ -60,13 +60,6 @@ are now fixed. `EXPIRE` would return 0 and not alter the timeout for a key with a timeout set. -@return - -@integer-reply, specifically: - -* `1` if the timeout was set. -* `0` if the timeout was not set. e.g. key doesn't exist, or operation skipped due to the provided arguments. - @examples ```cli diff --git a/commands/expireat.md b/commands/expireat.md index cbc10c6770..fed6bff7a8 100644 --- a/commands/expireat.md +++ b/commands/expireat.md @@ -27,13 +27,6 @@ The `EXPIREAT` command supports a set of options: A non-volatile key is treated as an infinite TTL for the purpose of `GT` and `LT`. The `GT`, `LT` and `NX` options are mutually exclusive. -@return - -@integer-reply, specifically: - -* `1` if the timeout was set. -* `0` if the timeout was not set. e.g. key doesn't exist, or operation skipped due to the provided arguments. - @examples ```cli diff --git a/commands/expiretime.md b/commands/expiretime.md index b524dcc34f..afcd37b8b9 100644 --- a/commands/expiretime.md +++ b/commands/expiretime.md @@ -2,13 +2,6 @@ Returns the absolute Unix timestamp (since January 1, 1970) in seconds at which See also the `PEXPIRETIME` command which returns the same information with milliseconds resolution. -@return - -@integer-reply: Expiration Unix timestamp in seconds, or a negative value in order to signal an error (see the description below). - -* The command returns `-1` if the key exists but has no associated expiration time. -* The command returns `-2` if the key does not exist. - @examples ```cli diff --git a/commands/failover.md b/commands/failover.md index 719d19943b..dd4ce43399 100644 --- a/commands/failover.md +++ b/commands/failover.md @@ -42,7 +42,3 @@ The command has no side effects if issued in the `waiting-for-sync` state but ca If a multi-master scenario is encountered, you will need to manually identify which master has the latest data and designate it as the master and have the other replicas. NOTE: `REPLICAOF` is disabled while a failover is in progress, this is to prevent unintended interactions with the failover that might cause data loss. - -@return - -@simple-string-reply: `OK` if the command was accepted and a coordinated failover is in progress. An error if the operation cannot be executed. diff --git a/commands/flushall.md b/commands/flushall.md index 5a562d0cf4..68ec53c0b5 100644 --- a/commands/flushall.md +++ b/commands/flushall.md @@ -11,10 +11,6 @@ It is possible to use one of the following modifiers to dictate the flushing mod Note: an asynchronous `FLUSHALL` command only deletes keys that were present at the time the command was invoked. Keys created during an asynchronous flush will be unaffected. -@return - -@simple-string-reply - ## Behavior change history * `>= 6.2.0`: Default flush behavior now configurable by the **lazyfree-lazy-user-flush** configuration directive. \ No newline at end of file diff --git a/commands/flushdb.md b/commands/flushdb.md index f8235639b2..112a9db3eb 100644 --- a/commands/flushdb.md +++ b/commands/flushdb.md @@ -11,10 +11,6 @@ It is possible to use one of the following modifiers to dictate the flushing mod Note: an asynchronous `FLUSHDB` command only deletes keys that were present at the time the command was invoked. Keys created during an asynchronous flush will be unaffected. -@return - -@simple-string-reply - ## Behavior change history * `>= 6.2.0`: Default flush behavior now configurable by the **lazyfree-lazy-user-flush** configuration directive. \ No newline at end of file diff --git a/commands/function-delete.md b/commands/function-delete.md index 5b90f81733..f2c8e1439b 100644 --- a/commands/function-delete.md +++ b/commands/function-delete.md @@ -5,10 +5,6 @@ If the library doesn't exist, the server returns an error. For more information please refer to [Introduction to Redis Functions](/topics/functions-intro). -@return - -@simple-string-reply - @examples ``` diff --git a/commands/function-dump.md b/commands/function-dump.md index cf144bc0ad..3636957f75 100644 --- a/commands/function-dump.md +++ b/commands/function-dump.md @@ -3,10 +3,6 @@ You can restore the serialized payload later with the `FUNCTION RESTORE` command For more information please refer to [Introduction to Redis Functions](/topics/functions-intro). -@return - -@bulk-string-reply: the serialized payload - @examples The following example shows how to dump loaded libraries using `FUNCTION DUMP` and then it calls `FUNCTION FLUSH` deletes all the libraries. diff --git a/commands/function-flush.md b/commands/function-flush.md index 38c412a19a..7d9a2836a0 100644 --- a/commands/function-flush.md +++ b/commands/function-flush.md @@ -6,7 +6,3 @@ Unless called with the optional mode argument, the `lazyfree-lazy-user-flush` co * `!SYNC`: Synchronously flush the libraries. For more information please refer to [Introduction to Redis Functions](/topics/functions-intro). - -@return - -@simple-string-reply diff --git a/commands/function-help.md b/commands/function-help.md index 38c300d590..9190a9b082 100644 --- a/commands/function-help.md +++ b/commands/function-help.md @@ -1,5 +1 @@ The `FUNCTION HELP` command returns a helpful text describing the different subcommands. - -@return - -@array-reply: a list of subcommands and their descriptions diff --git a/commands/function-kill.md b/commands/function-kill.md index 2db5ea58bc..1a61c9eb91 100644 --- a/commands/function-kill.md +++ b/commands/function-kill.md @@ -4,7 +4,3 @@ Kill a function that is currently executing. The `FUNCTION KILL` command can be used only on functions that did not modify the dataset during their execution (since stopping a read-only function does not violate the scripting engine's guaranteed atomicity). For more information please refer to [Introduction to Redis Functions](/topics/functions-intro). - -@return - -@simple-string-reply diff --git a/commands/function-list.md b/commands/function-list.md index bb66dba4ed..7cd3853d7f 100644 --- a/commands/function-list.md +++ b/commands/function-list.md @@ -15,7 +15,3 @@ The following information is provided for each of the libraries in the response: * **library_code:** the library's source code (when given the `WITHCODE` modifier). For more information please refer to [Introduction to Redis Functions](/topics/functions-intro). - -@return - -@array-reply diff --git a/commands/function-load.md b/commands/function-load.md index 16f125baff..2bb36d3e71 100644 --- a/commands/function-load.md +++ b/commands/function-load.md @@ -20,10 +20,6 @@ The command will return an error in the following circumstances: For more information please refer to [Introduction to Redis Functions](/topics/functions-intro). -@return - -@string - the library name that was loaded - @examples The following example will create a library named `mylib` with a single function, `myfunc`, that returns the first argument it gets. diff --git a/commands/function-restore.md b/commands/function-restore.md index 2868d160b6..f50edda58f 100644 --- a/commands/function-restore.md +++ b/commands/function-restore.md @@ -9,7 +9,3 @@ The following policies are allowed: * **REPLACE:** appends the restored libraries to the existing libraries, replacing any existing ones in case of name collisions. Note that this policy doesn't prevent function name collisions, only libraries. For more information please refer to [Introduction to Redis Functions](/topics/functions-intro). - -@return - -@simple-string-reply diff --git a/commands/function-stats.md b/commands/function-stats.md index 005b47b912..1746d0e0e7 100644 --- a/commands/function-stats.md +++ b/commands/function-stats.md @@ -15,7 +15,3 @@ The reply is map with two keys: You can use this command to inspect the invocation of a long-running function and decide whether kill it with the `FUNCTION KILL` command. For more information please refer to [Introduction to Redis Functions](/topics/functions-intro). - -@return - -@array-reply \ No newline at end of file diff --git a/commands/geoadd.md b/commands/geoadd.md index ecdd6e877b..fdc696d277 100644 --- a/commands/geoadd.md +++ b/commands/geoadd.md @@ -39,13 +39,6 @@ The model assumes that the Earth is a sphere since it uses the Haversine formula The introduced errors are not an issue when used, for example, by social networks and similar applications requiring this type of querying. However, in the worst case, the error may be up to 0.5%, so you may want to consider other systems for error-critical applications. -@return - -@integer-reply, specifically: - -* When used without optional arguments, the number of elements added to the sorted set (excluding score updates). -* If the `CH` option is specified, the number of elements that were changed (added or updated). - @examples ```cli diff --git a/commands/geodist.md b/commands/geodist.md index af78cdff71..257d97f7f3 100644 --- a/commands/geodist.md +++ b/commands/geodist.md @@ -13,13 +13,6 @@ The unit must be one of the following, and defaults to meters: The distance is computed assuming that the Earth is a perfect sphere, so errors up to 0.5% are possible in edge cases. -@return - -@bulk-string-reply, specifically: - -The command returns the distance as a double (represented as a string) -in the specified unit, or NULL if one or both the elements are missing. - @examples ```cli diff --git a/commands/geohash.md b/commands/geohash.md index a99ade2f43..0d43056747 100644 --- a/commands/geohash.md +++ b/commands/geohash.md @@ -18,13 +18,6 @@ have the following properties: 2. It is possible to use them in `geohash.org` URLs such as `http://geohash.org/`. This is an [example of such URL](http://geohash.org/sqdtr74hyu0). 3. Strings with a similar prefix are nearby, but the contrary is not true, it is possible that strings with different prefixes are nearby too. -@return - -@array-reply, specifically: - -The command returns an array where each element is the Geohash corresponding to -each member name passed as argument to the command. - @examples ```cli diff --git a/commands/geopos.md b/commands/geopos.md index 19dd377f1c..c23a879978 100644 --- a/commands/geopos.md +++ b/commands/geopos.md @@ -4,16 +4,6 @@ Given a sorted set representing a geospatial index, populated using the `GEOADD` The command can accept a variable number of arguments so it always returns an array of positions even when a single element is specified. -@return - -@array-reply, specifically: - -The command returns an array where each element is a two elements array -representing longitude and latitude (x,y) of each member name passed as -argument to the command. - -Non existing elements are reported as NULL elements of the array. - @examples ```cli diff --git a/commands/georadius.md b/commands/georadius.md index 3d0bba4688..27e9fdc78b 100644 --- a/commands/georadius.md +++ b/commands/georadius.md @@ -33,23 +33,6 @@ By default the command returns the items to the client. It is possible to store * `!STORE`: Store the items in a sorted set populated with their geospatial information. * `!STOREDIST`: Store the items in a sorted set populated with their distance from the center as a floating point number, in the same unit specified in the radius. -@return - -@array-reply, specifically: - -* Without any `WITH` option specified, the command just returns a linear array like ["New York","Milan","Paris"]. -* If `WITHCOORD`, `WITHDIST` or `WITHHASH` options are specified, the command returns an array of arrays, where each sub-array represents a single item. - -When additional information is returned as an array of arrays for each item, the first item in the sub-array is always the name of the returned item. The other information is returned in the following order as successive elements of the sub-array. - -1. The distance from the center as a floating point number, in the same unit specified in the radius. -2. The geohash integer. -3. The coordinates as a two items x,y array (longitude,latitude). - -So for example the command `GEORADIUS Sicily 15 37 200 km WITHCOORD WITHDIST` will return each item in the following way: - - ["Palermo","190.4424",["13.361389338970184","38.115556395496299"]] - ## Read-only variants Since `GEORADIUS` and `GEORADIUSBYMEMBER` have a `STORE` and `STOREDIST` option they are technically flagged as writing commands in the Redis command table. For this reason read-only replicas will flag them, and Redis Cluster replicas will redirect them to the master instance even if the connection is in read-only mode (see the `READONLY` command of Redis Cluster). diff --git a/commands/georadius_ro.md b/commands/georadius_ro.md index d2e3399b9c..df6c42b147 100644 --- a/commands/georadius_ro.md +++ b/commands/georadius_ro.md @@ -1,7 +1,3 @@ Read-only variant of the `GEORADIUS` command. This command is identical to the `GEORADIUS` command, except that it doesn't support the optional `STORE` and `STOREDIST` parameters. - -@return - -@array-reply: An array with each entry being the corresponding result of the subcommand given at the same position. diff --git a/commands/geosearch.md b/commands/geosearch.md index 972c1c984d..b094a93bce 100644 --- a/commands/geosearch.md +++ b/commands/geosearch.md @@ -28,19 +28,6 @@ When the `ANY` option is used, the command returns as soon as enough matches are When `ANY` is not provided, the command will perform an effort that is proportional to the number of items matching the specified area and sort them, so to query very large areas with a very small `COUNT` option may be slow even if just a few results are returned. -@return - -@array-reply, specifically: - -* Without any `WITH` option specified, the command just returns a linear array like ["New York","Milan","Paris"]. -* If `WITHCOORD`, `WITHDIST` or `WITHHASH` options are specified, the command returns an array of arrays, where each sub-array represents a single item. - -When additional information is returned as an array of arrays for each item, the first item in the sub-array is always the name of the returned item. The other information is returned in the following order as successive elements of the sub-array. - -1. The distance from the center as a floating point number, in the same unit specified in the shape. -2. The geohash integer. -3. The coordinates as a two items x,y array (longitude,latitude). - @examples ```cli diff --git a/commands/geosearchstore.md b/commands/geosearchstore.md index 53e5ebe603..b27d40125a 100644 --- a/commands/geosearchstore.md +++ b/commands/geosearchstore.md @@ -6,10 +6,6 @@ By default, it stores the results in the `destination` sorted set with their geo When using the `STOREDIST` option, the command stores the items in a sorted set populated with their distance from the center of the circle or box, as a floating-point number, in the same unit specified for that shape. -@return - -@integer-reply: the number of elements in the resulting set. - @examples ```cli diff --git a/commands/get.md b/commands/get.md index 2e1517afb7..2706dec616 100644 --- a/commands/get.md +++ b/commands/get.md @@ -3,10 +3,6 @@ If the key does not exist the special value `nil` is returned. An error is returned if the value stored at `key` is not a string, because `GET` only handles string values. -@return - -@bulk-string-reply: the value of `key`, or `nil` when `key` does not exist. - @examples ```cli diff --git a/commands/getbit.md b/commands/getbit.md index 1506af304a..ec0d7414cd 100644 --- a/commands/getbit.md +++ b/commands/getbit.md @@ -6,10 +6,6 @@ When _key_ does not exist it is assumed to be an empty string, so _offset_ is always out of range and the value is also assumed to be a contiguous space with 0 bits. -@return - -@integer-reply: the bit value stored at _offset_. - @examples ```cli diff --git a/commands/getdel.md b/commands/getdel.md index 8474e93105..68867d3490 100644 --- a/commands/getdel.md +++ b/commands/getdel.md @@ -1,10 +1,6 @@ Get the value of `key` and delete the key. This command is similar to `GET`, except for the fact that it also deletes the key on success (if and only if the key's value type is a string). -@return - -@bulk-string-reply: the value of `key`, `nil` when `key` does not exist, or an error if the key's value type isn't a string. - @examples ```cli diff --git a/commands/getex.md b/commands/getex.md index 89ce809de6..4b11b47384 100644 --- a/commands/getex.md +++ b/commands/getex.md @@ -11,10 +11,6 @@ The `GETEX` command supports a set of options that modify its behavior: * `PXAT` *timestamp-milliseconds* -- Set the specified Unix time at which the key will expire, in milliseconds. * `PERSIST` -- Remove the time to live associated with the key. -@return - -@bulk-string-reply: the value of `key`, or `nil` when `key` does not exist. - @examples ```cli diff --git a/commands/getrange.md b/commands/getrange.md index 7283defc49..c188f95494 100644 --- a/commands/getrange.md +++ b/commands/getrange.md @@ -7,10 +7,6 @@ So -1 means the last character, -2 the penultimate and so forth. The function handles out of range requests by limiting the resulting range to the actual length of the string. -@return - -@bulk-string-reply - @examples ```cli diff --git a/commands/getset.md b/commands/getset.md index dd7aee765c..ba3f82ac51 100644 --- a/commands/getset.md +++ b/commands/getset.md @@ -17,10 +17,6 @@ GETSET mycounter "0" GET mycounter ``` -@return - -@bulk-string-reply: the old value stored at `key`, or `nil` when `key` did not exist. - @examples ```cli diff --git a/commands/hdel.md b/commands/hdel.md index ab6874e1ef..b0dceb2baf 100644 --- a/commands/hdel.md +++ b/commands/hdel.md @@ -3,11 +3,6 @@ Specified fields that do not exist within this hash are ignored. If `key` does not exist, it is treated as an empty hash and this command returns `0`. -@return - -@integer-reply: the number of fields that were removed from the hash, not -including specified but non existing fields. - @examples ```cli diff --git a/commands/hello.md b/commands/hello.md index 776fd814f3..92c6604214 100644 --- a/commands/hello.md +++ b/commands/hello.md @@ -55,7 +55,3 @@ protocol to the specified version and also accepts the following options: * `AUTH `: directly authenticate the connection in addition to switching to the specified protocol version. This makes calling `AUTH` before `HELLO` unnecessary when setting up a new connection. Note that the `username` can be set to "default" to authenticate against a server that does not use ACLs, but rather the simpler `requirepass` mechanism of Redis prior to version 6. * `SETNAME `: this is the equivalent of calling `CLIENT SETNAME`. - -@return - -@array-reply: a list of server properties. The reply is a map instead of an array when RESP3 is selected. The command returns an error if the `protover` requested does not exist. diff --git a/commands/hexists.md b/commands/hexists.md index f27678a67a..b63b63f443 100644 --- a/commands/hexists.md +++ b/commands/hexists.md @@ -1,12 +1,5 @@ Returns if `field` is an existing field in the hash stored at `key`. -@return - -@integer-reply, specifically: - -* `1` if the hash contains `field`. -* `0` if the hash does not contain `field`, or `key` does not exist. - @examples ```cli diff --git a/commands/hget.md b/commands/hget.md index b8d91016eb..d6bef72f81 100644 --- a/commands/hget.md +++ b/commands/hget.md @@ -1,10 +1,5 @@ Returns the value associated with `field` in the hash stored at `key`. -@return - -@bulk-string-reply: the value associated with `field`, or `nil` when `field` is not -present in the hash or `key` does not exist. - @examples ```cli diff --git a/commands/hgetall.md b/commands/hgetall.md index 3717f001db..4fbd625f84 100644 --- a/commands/hgetall.md +++ b/commands/hgetall.md @@ -2,11 +2,6 @@ Returns all fields and values of the hash stored at `key`. In the returned value, every field name is followed by its value, so the length of the reply is twice the size of the hash. -@return - -@array-reply: list of fields and their values stored in the hash, or an -empty list when `key` does not exist. - @examples ```cli diff --git a/commands/hincrby.md b/commands/hincrby.md index 3d24c254d8..c2f1b63960 100644 --- a/commands/hincrby.md +++ b/commands/hincrby.md @@ -6,10 +6,6 @@ performed. The range of values supported by `HINCRBY` is limited to 64 bit signed integers. -@return - -@integer-reply: the value at `field` after the increment operation. - @examples Since the `increment` argument is signed, both increment and decrement diff --git a/commands/hincrbyfloat.md b/commands/hincrbyfloat.md index d6eb472597..46794de151 100644 --- a/commands/hincrbyfloat.md +++ b/commands/hincrbyfloat.md @@ -12,10 +12,6 @@ The exact behavior of this command is identical to the one of the `INCRBYFLOAT` command, please refer to the documentation of `INCRBYFLOAT` for further information. -@return - -@bulk-string-reply: the value of `field` after the increment. - @examples ```cli diff --git a/commands/hkeys.md b/commands/hkeys.md index c74b01e0f6..945b8f6204 100644 --- a/commands/hkeys.md +++ b/commands/hkeys.md @@ -1,10 +1,5 @@ Returns all field names in the hash stored at `key`. -@return - -@array-reply: list of fields in the hash, or an empty list when `key` does -not exist. - @examples ```cli diff --git a/commands/hlen.md b/commands/hlen.md index 2c18193435..ab19a35656 100644 --- a/commands/hlen.md +++ b/commands/hlen.md @@ -1,9 +1,5 @@ Returns the number of fields contained in the hash stored at `key`. -@return - -@integer-reply: number of fields in the hash, or `0` when `key` does not exist. - @examples ```cli diff --git a/commands/hmget.md b/commands/hmget.md index b10c43b3fa..ff322a15d8 100644 --- a/commands/hmget.md +++ b/commands/hmget.md @@ -5,11 +5,6 @@ For every `field` that does not exist in the hash, a `nil` value is returned. Because non-existing keys are treated as empty hashes, running `HMGET` against a non-existing `key` will return a list of `nil` values. -@return - -@array-reply: list of values associated with the given fields, in the same -order as they are requested. - ```cli HSET myhash field1 "Hello" HSET myhash field2 "World" diff --git a/commands/hmset.md b/commands/hmset.md index 8cec77585e..b89a13fc5e 100644 --- a/commands/hmset.md +++ b/commands/hmset.md @@ -3,10 +3,6 @@ Sets the specified fields to their respective values in the hash stored at This command overwrites any specified fields already existing in the hash. If `key` does not exist, a new key holding a hash is created. -@return - -@simple-string-reply - @examples ```cli diff --git a/commands/hrandfield.md b/commands/hrandfield.md index 389a1095ff..df6e2e5a31 100644 --- a/commands/hrandfield.md +++ b/commands/hrandfield.md @@ -8,13 +8,6 @@ In this case, the number of returned fields is the absolute value of the specifi The optional `WITHVALUES` modifier changes the reply so it includes the respective values of the randomly selected hash fields. -@return - -@bulk-string-reply: without the additional `count` argument, the command returns a Bulk Reply with the randomly selected field, or `nil` when `key` does not exist. - -@array-reply: when the additional `count` argument is passed, the command returns an array of fields, or an empty array when `key` does not exist. -If the `WITHVALUES` modifier is used, the reply is a list fields and their values from the hash. - @examples ```cli diff --git a/commands/hset.md b/commands/hset.md index 0572b01cf5..92c34f3d30 100644 --- a/commands/hset.md +++ b/commands/hset.md @@ -3,10 +3,6 @@ Sets the specified fields to their respective values in the hash stored at `key` This command overwrites the values of specified fields that exist in the hash. If `key` doesn't exist, a new key holding a hash is created. -@return - -@integer-reply: The number of fields that were added. - @examples ```cli diff --git a/commands/hsetnx.md b/commands/hsetnx.md index c60eaa071b..cc2dbdc020 100644 --- a/commands/hsetnx.md +++ b/commands/hsetnx.md @@ -3,13 +3,6 @@ yet exist. If `key` does not exist, a new key holding a hash is created. If `field` already exists, this operation has no effect. -@return - -@integer-reply, specifically: - -* `1` if `field` is a new field in the hash and `value` was set. -* `0` if `field` already exists in the hash and no operation was performed. - @examples ```cli diff --git a/commands/hstrlen.md b/commands/hstrlen.md index b187f75fb7..f32b1d8882 100644 --- a/commands/hstrlen.md +++ b/commands/hstrlen.md @@ -1,9 +1,5 @@ Returns the string length of the value associated with `field` in the hash stored at `key`. If the `key` or the `field` do not exist, 0 is returned. -@return - -@integer-reply: the string length of the value associated with `field`, or zero when `field` is not present in the hash or `key` does not exist at all. - @examples ```cli diff --git a/commands/hvals.md b/commands/hvals.md index 5526959276..f54f780519 100644 --- a/commands/hvals.md +++ b/commands/hvals.md @@ -1,10 +1,5 @@ Returns all values in the hash stored at `key`. -@return - -@array-reply: list of values in the hash, or an empty list when `key` does -not exist. - @examples ```cli diff --git a/commands/incr.md b/commands/incr.md index 6abee168b4..b87897233e 100644 --- a/commands/incr.md +++ b/commands/incr.md @@ -13,10 +13,6 @@ Redis stores integers in their integer representation, so for string values that actually hold an integer, there is no overhead for storing the string representation of the integer. -@return - -@integer-reply: the value of `key` after the increment - @examples ```cli diff --git a/commands/incrby.md b/commands/incrby.md index 9734351e80..d67a2dae54 100644 --- a/commands/incrby.md +++ b/commands/incrby.md @@ -6,10 +6,6 @@ This operation is limited to 64 bit signed integers. See `INCR` for extra information on increment/decrement operations. -@return - -@integer-reply: the value of `key` after the increment - @examples ```cli diff --git a/commands/incrbyfloat.md b/commands/incrbyfloat.md index 9efca1d9f7..d44bec435d 100644 --- a/commands/incrbyfloat.md +++ b/commands/incrbyfloat.md @@ -23,10 +23,6 @@ Trailing zeroes are always removed. The precision of the output is fixed at 17 digits after the decimal point regardless of the actual internal precision of the computation. -@return - -@bulk-string-reply: the value of `key` after the increment. - @examples ```cli diff --git a/commands/info.md b/commands/info.md index 0ea28bd41b..eecacc5f54 100644 --- a/commands/info.md +++ b/commands/info.md @@ -26,13 +26,6 @@ It can also take the following values: When no parameter is provided, the `default` option is assumed. -@return - -@bulk-string-reply: as a collection of text lines. - -Lines can contain a section name (starting with a # character) or a property. -All the properties are in the form of `field:value` terminated by `\r\n`. - ```cli INFO ``` diff --git a/commands/keys.md b/commands/keys.md index 186caca66c..766299da39 100644 --- a/commands/keys.md +++ b/commands/keys.md @@ -26,10 +26,6 @@ Supported glob-style patterns: Use `\` to escape special characters if you want to match them verbatim. -@return - -@array-reply: list of keys matching `pattern`. - @examples ```cli diff --git a/commands/lastsave.md b/commands/lastsave.md index eec80e5b67..1e38f6f626 100644 --- a/commands/lastsave.md +++ b/commands/lastsave.md @@ -2,7 +2,3 @@ Return the UNIX TIME of the last DB save executed with success. A client may check if a `BGSAVE` command succeeded reading the `LASTSAVE` value, then issuing a `BGSAVE` command and checking at regular intervals every N seconds if `LASTSAVE` changed. Redis considers the database saved successfully at startup. - -@return - -@integer-reply: an UNIX time stamp. diff --git a/commands/latency-doctor.md b/commands/latency-doctor.md index 8f493aaa55..6693eff2f5 100644 --- a/commands/latency-doctor.md +++ b/commands/latency-doctor.md @@ -39,7 +39,3 @@ I have a few advices for you: For more information refer to the [Latency Monitoring Framework page][lm]. [lm]: /topics/latency-monitor - -@return - -@bulk-string-reply diff --git a/commands/latency-graph.md b/commands/latency-graph.md index f1cfa5e996..285b2488ea 100644 --- a/commands/latency-graph.md +++ b/commands/latency-graph.md @@ -58,7 +58,3 @@ in the lower row) is the minimum, and a # in the higher row is the maximum. For more information refer to the [Latency Monitoring Framework page][lm]. [lm]: /topics/latency-monitor - -@return - -@bulk-string-reply \ No newline at end of file diff --git a/commands/latency-help.md b/commands/latency-help.md index 8077bf07d9..59f3999370 100644 --- a/commands/latency-help.md +++ b/commands/latency-help.md @@ -4,7 +4,3 @@ subcommands. For more information refer to the [Latency Monitoring Framework page][lm]. [lm]: /topics/latency-monitor - -@return - -@array-reply: a list of subcommands and their descriptions diff --git a/commands/latency-histogram.md b/commands/latency-histogram.md index 02496acf31..9d984bc9e4 100644 --- a/commands/latency-histogram.md +++ b/commands/latency-histogram.md @@ -34,10 +34,3 @@ To delete the latency histograms' data use the `CONFIG RESETSTAT` command. 5# (integer) 16 => (integer) 99968 6# (integer) 33 => (integer) 100000 ``` - -@return - -@array-reply: specifically: - -The command returns a map where each key is a command name. -The value is a map with a key for the total calls, and a map of the histogram time buckets. diff --git a/commands/latency-history.md b/commands/latency-history.md index 815e644fff..4207727a1a 100644 --- a/commands/latency-history.md +++ b/commands/latency-history.md @@ -35,10 +35,3 @@ Valid values for `event` are: For more information refer to the [Latency Monitoring Framework page][lm]. [lm]: /topics/latency-monitor - -@return - -@array-reply: specifically: - -The command returns an array where each element is a two elements array -representing the timestamp and the latency of the event. \ No newline at end of file diff --git a/commands/latency-latest.md b/commands/latency-latest.md index 918435b8d8..26a1e4d4ed 100644 --- a/commands/latency-latest.md +++ b/commands/latency-latest.md @@ -28,10 +28,3 @@ OK For more information refer to the [Latency Monitoring Framework page][lm]. [lm]: /topics/latency-monitor - -@return - -@array-reply: specifically: - -The command returns an array where each element is a four elements array -representing the event's name, timestamp, latest and all-time latency measurements. diff --git a/commands/latency-reset.md b/commands/latency-reset.md index 9762869b9f..f2d87cc121 100644 --- a/commands/latency-reset.md +++ b/commands/latency-reset.md @@ -28,7 +28,3 @@ Valid values for `event` are: For more information refer to the [Latency Monitoring Framework page][lm]. [lm]: /topics/latency-monitor - -@return - -@integer-reply: the number of event time series that were reset. diff --git a/commands/lcs.md b/commands/lcs.md index b554686263..09e9048534 100644 --- a/commands/lcs.md +++ b/commands/lcs.md @@ -70,10 +70,3 @@ Finally to also have the match len: 3) "len" 4) (integer) 6 ``` - -@return - -* Without modifiers the string representing the longest common substring is returned. -* When `LEN` is given the command returns the length of the longest common substring. -* When `IDX` is given the command returns an array with the LCS length and all the ranges in both the strings, start and end offset for each string, where there are matches. When `WITHMATCHLEN` is given each array representing a match will also have the length of the match (see examples). - diff --git a/commands/lindex.md b/commands/lindex.md index 229c63deab..0f6438e42e 100644 --- a/commands/lindex.md +++ b/commands/lindex.md @@ -7,10 +7,6 @@ Here, `-1` means the last element, `-2` means the penultimate and so forth. When the value at `key` is not a list, an error is returned. -@return - -@bulk-string-reply: the requested element, or `nil` when `index` is out of range. - @examples ```cli diff --git a/commands/linsert.md b/commands/linsert.md index df80725136..fdbdaf9c8c 100644 --- a/commands/linsert.md +++ b/commands/linsert.md @@ -6,10 +6,6 @@ performed. An error is returned when `key` exists but does not hold a list value. -@return - -@integer-reply: the list length after a successful insert operation, `0` if the `key` doesn't exist, and `-1` when the `pivot` wasn't found. - @examples ```cli diff --git a/commands/llen.md b/commands/llen.md index 8c7c70fac1..4c9a7862ee 100644 --- a/commands/llen.md +++ b/commands/llen.md @@ -2,10 +2,6 @@ Returns the length of the list stored at `key`. If `key` does not exist, it is interpreted as an empty list and `0` is returned. An error is returned when the value stored at `key` is not a list. -@return - -@integer-reply: the length of the list at `key`. - @examples ```cli diff --git a/commands/lmove.md b/commands/lmove.md index a35f177685..7dd02fa4e2 100644 --- a/commands/lmove.md +++ b/commands/lmove.md @@ -18,10 +18,6 @@ no-op if `wherefrom` is the same as `whereto`). This command comes in place of the now deprecated `RPOPLPUSH`. Doing `LMOVE RIGHT LEFT` is equivalent. -@return - -@bulk-string-reply: the element being popped and pushed. - @examples ```cli diff --git a/commands/lmpop.md b/commands/lmpop.md index aad5b6a3e6..ee053e2378 100644 --- a/commands/lmpop.md +++ b/commands/lmpop.md @@ -10,13 +10,6 @@ See `BLMPOP` for the blocking variant of this command. Elements are popped from either the left or right of the first non-empty list based on the passed argument. The number of returned elements is limited to the lower between the non-empty list's length, and the count argument (which defaults to 1). -@return - -@array-reply: specifically: - -* A `nil` when no element could be popped. -* A two-element array with the first element being the name of the key from which elements were popped, and the second element is an array of elements. - @examples ```cli diff --git a/commands/lolwut.md b/commands/lolwut.md index a767a381ea..027c9b177e 100644 --- a/commands/lolwut.md +++ b/commands/lolwut.md @@ -23,7 +23,3 @@ LOLWUT version should have the following properties: 3. LOLWUT output should be fast to generate so that the command can be called in production instances without issues. It should remain fast even when the user experiments with odd parameters. 4. LOLWUT implementations should be safe and carefully checked for security, and resist to untrusted inputs if they take arguments. 5. LOLWUT must always display the Redis version at the end. - -@return - -@bulk-string-reply (or verbatim reply when using the RESP3 protocol): the string containing the generative computer art, and a text with the Redis version. diff --git a/commands/lpop.md b/commands/lpop.md index c6e77c2d97..ed7dc9cf4e 100644 --- a/commands/lpop.md +++ b/commands/lpop.md @@ -4,16 +4,6 @@ By default, the command pops a single element from the beginning of the list. When provided with the optional `count` argument, the reply will consist of up to `count` elements, depending on the list's length. -@return - -When called without the `count` argument: - -@bulk-string-reply: the value of the first element, or `nil` when `key` does not exist. - -When called with the `count` argument: - -@array-reply: list of popped elements, or `nil` when `key` does not exist. - @examples ```cli diff --git a/commands/lpos.md b/commands/lpos.md index 93fe579447..b4485acb56 100644 --- a/commands/lpos.md +++ b/commands/lpos.md @@ -57,10 +57,6 @@ Finally, the `MAXLEN` option tells the command to compare the provided element o When `MAXLEN` is used, it is possible to specify 0 as the maximum number of comparisons, as a way to tell the command we want unlimited comparisons. This is better than giving a very large `MAXLEN` option because it is more general. -@return - -The command returns the integer representing the matching element, or `nil` if there is no match. However, if the `COUNT` option is given the command returns an array (empty if there are no matches). - @examples ```cli diff --git a/commands/lpush.md b/commands/lpush.md index e8b97203db..c1d198bad9 100644 --- a/commands/lpush.md +++ b/commands/lpush.md @@ -10,10 +10,6 @@ leftmost element to the rightmost element. So for instance the command `LPUSH mylist a b c` will result into a list containing `c` as first element, `b` as second element and `a` as third element. -@return - -@integer-reply: the length of the list after the push operations. - @examples ```cli diff --git a/commands/lpushx.md b/commands/lpushx.md index e98c9037d7..69182df8a8 100644 --- a/commands/lpushx.md +++ b/commands/lpushx.md @@ -3,10 +3,6 @@ already exists and holds a list. In contrary to `LPUSH`, no operation will be performed when `key` does not yet exist. -@return - -@integer-reply: the length of the list after the push operation. - @examples ```cli diff --git a/commands/lrange.md b/commands/lrange.md index 7634f3e6c3..c59de57e1b 100644 --- a/commands/lrange.md +++ b/commands/lrange.md @@ -23,10 +23,6 @@ If `start` is larger than the end of the list, an empty list is returned. If `stop` is larger than the actual end of the list, Redis will treat it like the last element of the list. -@return - -@array-reply: list of elements in the specified range. - @examples ```cli diff --git a/commands/lrem.md b/commands/lrem.md index 36c0c7df00..dd2f7e7fbc 100644 --- a/commands/lrem.md +++ b/commands/lrem.md @@ -12,10 +12,6 @@ For example, `LREM list -2 "hello"` will remove the last two occurrences of Note that non-existing keys are treated like empty lists, so when `key` does not exist, the command will always return `0`. -@return - -@integer-reply: the number of removed elements. - @examples ```cli diff --git a/commands/lset.md b/commands/lset.md index 8f1c391594..c6fb635758 100644 --- a/commands/lset.md +++ b/commands/lset.md @@ -3,10 +3,6 @@ For more information on the `index` argument, see `LINDEX`. An error is returned for out of range indexes. -@return - -@simple-string-reply - @examples ```cli diff --git a/commands/ltrim.md b/commands/ltrim.md index 7cae0c7caf..61ae3f6e26 100644 --- a/commands/ltrim.md +++ b/commands/ltrim.md @@ -31,10 +31,6 @@ It is important to note that when used in this way `LTRIM` is an O(1) operation because in the average case just one element is removed from the tail of the list. -@return - -@simple-string-reply - @examples ```cli diff --git a/commands/memory-doctor.md b/commands/memory-doctor.md index dbb9db3e33..8a61604542 100644 --- a/commands/memory-doctor.md +++ b/commands/memory-doctor.md @@ -1,6 +1,2 @@ The `MEMORY DOCTOR` command reports about different memory-related issues that the Redis server experiences, and advises about possible remedies. - -@return - -@bulk-string-reply \ No newline at end of file diff --git a/commands/memory-help.md b/commands/memory-help.md index c0f4086f53..1b86c43a32 100644 --- a/commands/memory-help.md +++ b/commands/memory-help.md @@ -1,6 +1,2 @@ The `MEMORY HELP` command returns a helpful text describing the different subcommands. - -@return - -@array-reply: a list of subcommands and their descriptions diff --git a/commands/memory-malloc-stats.md b/commands/memory-malloc-stats.md index 8da8e72e96..f0b645ca38 100644 --- a/commands/memory-malloc-stats.md +++ b/commands/memory-malloc-stats.md @@ -3,7 +3,3 @@ the memory allocator. This command is currently implemented only when using **jemalloc** as an allocator, and evaluates to a benign NOOP for all others. - -@return - -@bulk-string-reply: the memory allocator's internal statistics report diff --git a/commands/memory-purge.md b/commands/memory-purge.md index 5ebe43356d..947a4fea45 100644 --- a/commands/memory-purge.md +++ b/commands/memory-purge.md @@ -3,7 +3,3 @@ reclaimed by the allocator. This command is currently implemented only when using **jemalloc** as an allocator, and evaluates to a benign NOOP for all others. - -@return - -@simple-string-reply diff --git a/commands/memory-stats.md b/commands/memory-stats.md index 21a99d32da..99ff8ca01d 100644 --- a/commands/memory-stats.md +++ b/commands/memory-stats.md @@ -39,8 +39,4 @@ values. The following metrics are reported: `peak.allocated` * `fragmentation`: See `INFO`'s `mem_fragmentation_ratio` -@return - -@array-reply: nested list of memory usage metrics and their values - **A note about the word slave used in this man page**: Starting with Redis 5, if not for backward compatibility, the Redis project no longer uses the word slave. Unfortunately in this command the word slave is part of the protocol, so we'll be able to remove such occurrences only when this API will be naturally deprecated. diff --git a/commands/memory-usage.md b/commands/memory-usage.md index 68b23aec1b..54b17e7d74 100644 --- a/commands/memory-usage.md +++ b/commands/memory-usage.md @@ -37,7 +37,3 @@ OK > MEMORY USAGE foo3 (integer) 160 ``` - -@return - -@integer-reply: the memory usage in bytes, or `nil` when the key does not exist. diff --git a/commands/mget.md b/commands/mget.md index 8bca6ca81a..97de1cc61d 100644 --- a/commands/mget.md +++ b/commands/mget.md @@ -3,10 +3,6 @@ For every key that does not hold a string value or does not exist, the special value `nil` is returned. Because of this, the operation never fails. -@return - -@array-reply: list of values at the specified keys. - @examples ```cli diff --git a/commands/migrate.md b/commands/migrate.md index 318e0e253f..1bc5913302 100644 --- a/commands/migrate.md +++ b/commands/migrate.md @@ -65,8 +65,3 @@ just a single key exists. * `!KEYS` -- If the key argument is an empty string, the command will instead migrate all the keys that follow the `!KEYS` option (see the above section for more info). * `!AUTH` -- Authenticate with the given password to the remote instance. * `AUTH2` -- Authenticate with the given username and password pair (Redis 6 or greater ACL auth style). - -@return - -@simple-string-reply: The command returns OK on success, or `NOKEY` if no keys were -found in the source instance. diff --git a/commands/module-help.md b/commands/module-help.md index a05bf1e965..6759bfe0fe 100644 --- a/commands/module-help.md +++ b/commands/module-help.md @@ -1,5 +1 @@ The `MODULE HELP` command returns a helpful text describing the different subcommands. - -@return - -@array-reply: a list of subcommands and their descriptions diff --git a/commands/module-list.md b/commands/module-list.md index 1bfa3e232b..3f91414b05 100644 --- a/commands/module-list.md +++ b/commands/module-list.md @@ -1,10 +1 @@ Returns information about the modules loaded to the server. - -@return - -@array-reply: list of loaded modules. Each element in the list represents a -module, and is in itself a list of property names and their values. The -following properties is reported for each loaded module: - -* `name`: Name of the module -* `ver`: Version of the module diff --git a/commands/module-load.md b/commands/module-load.md index 99777c3886..7232257a1d 100644 --- a/commands/module-load.md +++ b/commands/module-load.md @@ -7,7 +7,3 @@ unmodified to the module. **Note**: modules can also be loaded at server startup with `loadmodule` configuration directive in `redis.conf`. - -@return - -@simple-string-reply: `OK` if module was loaded. diff --git a/commands/module-loadex.md b/commands/module-loadex.md index f7a55dbd51..a863aae32c 100644 --- a/commands/module-loadex.md +++ b/commands/module-loadex.md @@ -9,7 +9,3 @@ Any additional arguments that follow the `ARGS` keyword are passed unmodified to **Note**: modules can also be loaded at server startup with `loadmodule` configuration directive in `redis.conf`. - -@return - -@simple-string-reply: `OK` if module was loaded. diff --git a/commands/module-unload.md b/commands/module-unload.md index 84ebebf010..4214e750f0 100644 --- a/commands/module-unload.md +++ b/commands/module-unload.md @@ -7,7 +7,3 @@ library's filename. Known limitations: * Modules that register custom data types can not be unloaded. - -@return - -@simple-string-reply: `OK` if module was unloaded. diff --git a/commands/monitor.md b/commands/monitor.md index 2622cdd53a..5a7a70c575 100644 --- a/commands/monitor.md +++ b/commands/monitor.md @@ -80,11 +80,6 @@ In this particular case, running a single `MONITOR` client can reduce the throughput by more than 50%. Running more `MONITOR` clients will reduce throughput even more. -@return - -**Non standard return value**, just dumps the received commands in an infinite -flow. - ## Behavior change history * `>= 6.0.0`: `AUTH` excluded from the command's output. diff --git a/commands/move.md b/commands/move.md index ceb212caac..1e9f6cdbf9 100644 --- a/commands/move.md +++ b/commands/move.md @@ -3,10 +3,3 @@ destination database. When `key` already exists in the destination database, or it does not exist in the source database, it does nothing. It is possible to use `MOVE` as a locking primitive because of this. - -@return - -@integer-reply, specifically: - -* `1` if `key` was moved. -* `0` if `key` was not moved. diff --git a/commands/mset.md b/commands/mset.md index f070d29329..d22b0de5da 100644 --- a/commands/mset.md +++ b/commands/mset.md @@ -6,10 +6,6 @@ See `MSETNX` if you don't want to overwrite existing values. It is not possible for clients to see that some of the keys were updated while others are unchanged. -@return - -@simple-string-reply: always `OK` since `MSET` can't fail. - @examples ```cli diff --git a/commands/msetnx.md b/commands/msetnx.md index 795bfc9812..71b4117c30 100644 --- a/commands/msetnx.md +++ b/commands/msetnx.md @@ -10,13 +10,6 @@ that either all the fields or none at all are set. It is not possible for clients to see that some of the keys were updated while others are unchanged. -@return - -@integer-reply, specifically: - -* `1` if the all the keys were set. -* `0` if no key was set (at least one key already existed). - @examples ```cli diff --git a/commands/multi.md b/commands/multi.md index dc8789249d..1b2ba22659 100644 --- a/commands/multi.md +++ b/commands/multi.md @@ -2,7 +2,3 @@ Marks the start of a [transaction][tt] block. Subsequent commands will be queued for atomic execution using `EXEC`. [tt]: /topics/transactions - -@return - -@simple-string-reply: always `OK`. diff --git a/commands/object-encoding.md b/commands/object-encoding.md index 3a9583d0d9..b09dc0bef2 100644 --- a/commands/object-encoding.md +++ b/commands/object-encoding.md @@ -15,7 +15,3 @@ Redis objects can be encoded in different ways: * Sorted Sets can be encoded as `ziplist` or `skiplist` format. As for the List type small sorted sets can be specially encoded using `ziplist`, while the `skiplist` encoding is the one that works with sorted sets of any size. All the specially encoded types are automatically converted to the general type once you perform an operation that makes it impossible for Redis to retain the space saving encoding. - -@return - -@bulk-string-reply: the encoding of the object, or `nil` if the key doesn't exist diff --git a/commands/object-freq.md b/commands/object-freq.md index fdf891e83d..5c75bfb787 100644 --- a/commands/object-freq.md +++ b/commands/object-freq.md @@ -1,9 +1,3 @@ This command returns the logarithmic access frequency counter of a Redis object stored at ``. The command is only available when the `maxmemory-policy` configuration directive is set to one of the LFU policies. - -@return - -@integer-reply - -The counter's value. \ No newline at end of file diff --git a/commands/object-help.md b/commands/object-help.md index f98196c5e1..d528d40751 100644 --- a/commands/object-help.md +++ b/commands/object-help.md @@ -1,5 +1 @@ The `OBJECT HELP` command returns a helpful text describing the different subcommands. - -@return - -@array-reply: a list of subcommands and their descriptions diff --git a/commands/object-idletime.md b/commands/object-idletime.md index 2a89641746..791d8fb00a 100644 --- a/commands/object-idletime.md +++ b/commands/object-idletime.md @@ -1,9 +1,3 @@ This command returns the time in seconds since the last access to the value stored at ``. The command is only available when the `maxmemory-policy` configuration directive is not set to one of the LFU policies. - -@return - -@integer-reply - -The idle time in seconds. \ No newline at end of file diff --git a/commands/object-refcount.md b/commands/object-refcount.md index 639c899dbd..e526681640 100644 --- a/commands/object-refcount.md +++ b/commands/object-refcount.md @@ -1,7 +1 @@ This command returns the reference count of the stored at ``. - -@return - -@integer-reply - -The number of references. \ No newline at end of file diff --git a/commands/persist.md b/commands/persist.md index 67a00147da..44f067d7d8 100644 --- a/commands/persist.md +++ b/commands/persist.md @@ -2,13 +2,6 @@ Remove the existing timeout on `key`, turning the key from _volatile_ (a key with an expire set) to _persistent_ (a key that will never expire as no timeout is associated). -@return - -@integer-reply, specifically: - -* `1` if the timeout was removed. -* `0` if `key` does not exist or does not have an associated timeout. - @examples ```cli diff --git a/commands/pexpire.md b/commands/pexpire.md index bc2e6f109e..2e0df07063 100644 --- a/commands/pexpire.md +++ b/commands/pexpire.md @@ -13,13 +13,6 @@ The `PEXPIRE` command supports a set of options since Redis 7.0: A non-volatile key is treated as an infinite TTL for the purpose of `GT` and `LT`. The `GT`, `LT` and `NX` options are mutually exclusive. -@return - -@integer-reply, specifically: - -* `1` if the timeout was set. -* `0` if the timeout was not set. e.g. key doesn't exist, or operation skipped due to the provided arguments. - @examples ```cli diff --git a/commands/pexpireat.md b/commands/pexpireat.md index 21e2853e39..748d491a72 100644 --- a/commands/pexpireat.md +++ b/commands/pexpireat.md @@ -13,13 +13,6 @@ The `PEXPIREAT` command supports a set of options since Redis 7.0: A non-volatile key is treated as an infinite TTL for the purpose of `GT` and `LT`. The `GT`, `LT` and `NX` options are mutually exclusive. -@return - -@integer-reply, specifically: - -* `1` if the timeout was set. -* `0` if the timeout was not set. e.g. key doesn't exist, or operation skipped due to the provided arguments. - @examples ```cli diff --git a/commands/pexpiretime.md b/commands/pexpiretime.md index 9fcda95507..ffde6be48b 100644 --- a/commands/pexpiretime.md +++ b/commands/pexpiretime.md @@ -1,12 +1,5 @@ `PEXPIRETIME` has the same semantic as `EXPIRETIME`, but returns the absolute Unix expiration timestamp in milliseconds instead of seconds. -@return - -@integer-reply: Expiration Unix timestamp in milliseconds, or a negative value in order to signal an error (see the description below). - -* The command returns `-1` if the key exists but has no associated expiration time. -* The command returns `-2` if the key does not exist. - @examples ```cli diff --git a/commands/pfadd.md b/commands/pfadd.md index 5d0128b1a0..f621a00d4e 100644 --- a/commands/pfadd.md +++ b/commands/pfadd.md @@ -8,12 +8,6 @@ To call the command without elements but just the variable name is valid, this w For an introduction to HyperLogLog data structure check the `PFCOUNT` command page. -@return - -@integer-reply, specifically: - -* 1 if at least 1 HyperLogLog internal register was altered. 0 otherwise. - @examples ```cli diff --git a/commands/pfcount.md b/commands/pfcount.md index 71d10930c0..ac6f712a6a 100644 --- a/commands/pfcount.md +++ b/commands/pfcount.md @@ -11,12 +11,6 @@ For example in order to take the count of all the unique search queries performe Note: as a side effect of calling this function, it is possible that the HyperLogLog is modified, since the last 8 bytes encode the latest computed cardinality for caching purposes. So `PFCOUNT` is technically a write command. -@return - -@integer-reply, specifically: - -* The approximated number of unique elements observed via `PFADD`. - @examples ```cli diff --git a/commands/pfmerge.md b/commands/pfmerge.md index c59c930182..4eb1b90966 100644 --- a/commands/pfmerge.md +++ b/commands/pfmerge.md @@ -9,10 +9,6 @@ If the destination variable exists, it is treated as one of the source sets and its cardinality will be included in the cardinality of the computed HyperLogLog. -@return - -@simple-string-reply: The command just returns `OK`. - @examples ```cli diff --git a/commands/ping.md b/commands/ping.md index 1667e1eab5..f1631d4a2c 100644 --- a/commands/ping.md +++ b/commands/ping.md @@ -10,12 +10,6 @@ multi-bulk with a "pong" in the first position and an empty bulk in the second position, unless an argument is provided in which case it returns a copy of the argument. -@return - -@simple-string-reply, and specifically `PONG`, when no argument is provided. - -@bulk-string-reply the argument provided, when applicable. - @examples ```cli diff --git a/commands/psubscribe.md b/commands/psubscribe.md index c5936489f2..abb80b9975 100644 --- a/commands/psubscribe.md +++ b/commands/psubscribe.md @@ -13,11 +13,6 @@ However, if RESP3 is used (see `HELLO`) it is possible for a client to issue any For more information, see [Pub/sub](/docs/interact/pubsub/). -@return - -When successful, this command doesn't return anything. -Instead, for each pattern, one message with the first element being the string "psubscribe" is pushed as a confirmation that the command succeeded. - ## Behavior change history * `>= 6.2.0`: `RESET` can be called to exit subscribed state. diff --git a/commands/psync.md b/commands/psync.md index 8cbacf2fa6..d9eac2ab9a 100644 --- a/commands/psync.md +++ b/commands/psync.md @@ -7,7 +7,3 @@ For more information about replication in Redis please check the [replication page][tr]. [tr]: /topics/replication - -@return - -**Non standard return value**, a bulk transfer of the data followed by `PING` and write requests from the master. diff --git a/commands/pttl.md b/commands/pttl.md index 4e0807971b..302194b46a 100644 --- a/commands/pttl.md +++ b/commands/pttl.md @@ -9,10 +9,6 @@ Starting with Redis 2.8 the return value in case of error changed: * The command returns `-2` if the key does not exist. * The command returns `-1` if the key exists but has no associated expire. -@return - -@integer-reply: TTL in milliseconds, or a negative value in order to signal an error (see the description above). - @examples ```cli diff --git a/commands/publish.md b/commands/publish.md index 62283f8dc1..cd61d04678 100644 --- a/commands/publish.md +++ b/commands/publish.md @@ -3,9 +3,3 @@ Posts a message to the given channel. In a Redis Cluster clients can publish to every node. The cluster makes sure that published messages are forwarded as needed, so clients can subscribe to any channel by connecting to any one of the nodes. - -@return - -@integer-reply: the number of clients that received the message. Note that in a -Redis Cluster, only clients that are connected to the same node as the -publishing client are included in the count. diff --git a/commands/pubsub-channels.md b/commands/pubsub-channels.md index 8b9a06eefd..8e0b3e36fd 100644 --- a/commands/pubsub-channels.md +++ b/commands/pubsub-channels.md @@ -5,7 +5,3 @@ An active channel is a Pub/Sub channel with one or more subscribers (excluding c If no `pattern` is specified, all the channels are listed, otherwise if pattern is specified only channels matching the specified glob-style pattern are listed. Cluster note: in a Redis Cluster clients can subscribe to every node, and can also publish to every other node. The cluster will make sure that published messages are forwarded as needed. That said, `PUBSUB`'s replies in a cluster only report information from the node's Pub/Sub context, rather than the entire cluster. - -@return - -@array-reply: a list of active channels, optionally matching the specified pattern. diff --git a/commands/pubsub-help.md b/commands/pubsub-help.md index a7ab2a359f..f711c27db2 100644 --- a/commands/pubsub-help.md +++ b/commands/pubsub-help.md @@ -1,5 +1 @@ The `PUBSUB HELP` command returns a helpful text describing the different subcommands. - -@return - -@array-reply: a list of subcommands and their descriptions diff --git a/commands/pubsub-numpat.md b/commands/pubsub-numpat.md index 6f3a7c9e14..2a3282c5c6 100644 --- a/commands/pubsub-numpat.md +++ b/commands/pubsub-numpat.md @@ -3,7 +3,3 @@ Returns the number of unique patterns that are subscribed to by clients (that ar Note that this isn't the count of clients subscribed to patterns, but the total number of unique patterns all the clients are subscribed to. Cluster note: in a Redis Cluster clients can subscribe to every node, and can also publish to every other node. The cluster will make sure that published messages are forwarded as needed. That said, `PUBSUB`'s replies in a cluster only report information from the node's Pub/Sub context, rather than the entire cluster. - -@return - -@integer-reply: the number of patterns all the clients are subscribed to. diff --git a/commands/pubsub-numsub.md b/commands/pubsub-numsub.md index d4d6b85e7b..604c317900 100644 --- a/commands/pubsub-numsub.md +++ b/commands/pubsub-numsub.md @@ -3,9 +3,3 @@ Returns the number of subscribers (exclusive of clients subscribed to patterns) Note that it is valid to call this command without channels. In this case it will just return an empty list. Cluster note: in a Redis Cluster clients can subscribe to every node, and can also publish to every other node. The cluster will make sure that published messages are forwarded as needed. That said, `PUBSUB`'s replies in a cluster only report information from the node's Pub/Sub context, rather than the entire cluster. - -@return - -@array-reply: a list of channels and number of subscribers for every channel. - -The format is channel, count, channel, count, ..., so the list is flat. The order in which the channels are listed is the same as the order of the channels specified in the command call. diff --git a/commands/pubsub-shardchannels.md b/commands/pubsub-shardchannels.md index b2b5da3355..c6c460bd79 100644 --- a/commands/pubsub-shardchannels.md +++ b/commands/pubsub-shardchannels.md @@ -6,10 +6,6 @@ If no `pattern` is specified, all the channels are listed, otherwise if pattern The information returned about the active shard channels are at the shard level and not at the cluster level. -@return - -@array-reply: a list of active channels, optionally matching the specified pattern. - @examples ``` diff --git a/commands/pubsub-shardnumsub.md b/commands/pubsub-shardnumsub.md index 8d09d4381f..8119fe9b56 100644 --- a/commands/pubsub-shardnumsub.md +++ b/commands/pubsub-shardnumsub.md @@ -4,12 +4,6 @@ Note that it is valid to call this command without channels, in this case it wil Cluster note: in a Redis Cluster, `PUBSUB`'s replies in a cluster only report information from the node's Pub/Sub context, rather than the entire cluster. -@return - -@array-reply: a list of channels and number of subscribers for every channel. - -The format is channel, count, channel, count, ..., so the list is flat. The order in which the channels are listed is the same as the order of the shard channels specified in the command call. - @examples ``` diff --git a/commands/punsubscribe.md b/commands/punsubscribe.md index 65045f60e2..af8ee7e021 100644 --- a/commands/punsubscribe.md +++ b/commands/punsubscribe.md @@ -5,8 +5,3 @@ When no patterns are specified, the client is unsubscribed from all the previously subscribed patterns. In this case, a message for every unsubscribed pattern will be sent to the client. - -@return - -When successful, this command doesn't return anything. -Instead, for each pattern, one message with the first element being the string "punsubscribe" is pushed as a confirmation that the command succeeded. diff --git a/commands/quit.md b/commands/quit.md index b4cf337338..e0507d43d2 100644 --- a/commands/quit.md +++ b/commands/quit.md @@ -5,7 +5,3 @@ client. **Note:** Clients should not use this command. Instead, clients should simply close the connection when they're not used anymore. Terminating a connection on the client side is preferable, as it eliminates `TIME_WAIT` lingering sockets on the server side. - -@return - -@simple-string-reply: always OK. diff --git a/commands/randomkey.md b/commands/randomkey.md index d8233224ff..37a2d759ab 100644 --- a/commands/randomkey.md +++ b/commands/randomkey.md @@ -1,5 +1 @@ Return a random key from the currently selected database. - -@return - -@bulk-string-reply: the random key, or `nil` when the database is empty. diff --git a/commands/readonly.md b/commands/readonly.md index bc73b9b980..9bd4f96a7e 100644 --- a/commands/readonly.md +++ b/commands/readonly.md @@ -13,7 +13,3 @@ master node. This may happen because: 1. The client sent a command about hash slots never served by the master of this replica. 2. The cluster was reconfigured (for example resharded) and the replica is no longer able to serve commands for a given hash slot. - -@return - -@simple-string-reply diff --git a/commands/readwrite.md b/commands/readwrite.md index d6d7089be4..9b50eefd80 100644 --- a/commands/readwrite.md +++ b/commands/readwrite.md @@ -4,7 +4,3 @@ Read queries against a Redis Cluster replica node are disabled by default, but you can use the `READONLY` command to change this behavior on a per- connection basis. The `READWRITE` command resets the readonly mode flag of a connection back to readwrite. - -@return - -@simple-string-reply diff --git a/commands/rename.md b/commands/rename.md index 471ecf4187..82c503c219 100644 --- a/commands/rename.md +++ b/commands/rename.md @@ -4,10 +4,6 @@ If `newkey` already exists it is overwritten, when this happens `RENAME` execute In Cluster mode, both `key` and `newkey` must be in the same **hash slot**, meaning that in practice only keys that have the same hash tag can be reliably renamed in cluster. -@return - -@simple-string-reply - @examples ```cli diff --git a/commands/renamenx.md b/commands/renamenx.md index c132af4a73..15b951e4ca 100644 --- a/commands/renamenx.md +++ b/commands/renamenx.md @@ -3,13 +3,6 @@ It returns an error when `key` does not exist. In Cluster mode, both `key` and `newkey` must be in the same **hash slot**, meaning that in practice only keys that have the same hash tag can be reliably renamed in cluster. -@return - -@integer-reply, specifically: - -* `1` if `key` was renamed to `newkey`. -* `0` if `newkey` already exists. - @examples ```cli diff --git a/commands/replicaof.md b/commands/replicaof.md index 1c3ec93dce..8351f1453e 100644 --- a/commands/replicaof.md +++ b/commands/replicaof.md @@ -6,10 +6,6 @@ If a server is already a replica of some master, `REPLICAOF` hostname port will The form `REPLICAOF` NO ONE will stop replication, turning the server into a MASTER, but will not discard the replication. So, if the old master stops working, it is possible to turn the replica into a master and set the application to use this new master in read/write. Later when the other Redis server is fixed, it can be reconfigured to work as a replica. -@return - -@simple-string-reply - @examples ``` diff --git a/commands/reset.md b/commands/reset.md index e6bbc1ace6..78434755a4 100644 --- a/commands/reset.md +++ b/commands/reset.md @@ -19,7 +19,3 @@ following: authentication is enabled. * Turns off `NO-EVICT` mode. * Turns off `NO-TOUCH` mode. - -@return - -@simple-string-reply: always 'RESET'. diff --git a/commands/restore.md b/commands/restore.md index eb605be703..d756a33bb4 100644 --- a/commands/restore.md +++ b/commands/restore.md @@ -18,10 +18,6 @@ exists unless you use the `REPLACE` modifier. `!RESTORE` checks the RDB version and data checksum. If they don't match an error is returned. -@return - -@simple-string-reply: The command returns OK on success. - @examples ``` diff --git a/commands/role.md b/commands/role.md index c308c934f4..08bf21df1f 100644 --- a/commands/role.md +++ b/commands/role.md @@ -69,10 +69,6 @@ The sentinel output is composed of the following parts: 1. The string `sentinel`. 2. An array of master names monitored by this Sentinel instance. -@return - -@array-reply: where the first element is one of `master`, `slave`, `sentinel` and the additional elements are role-specific as illustrated above. - @examples ```cli diff --git a/commands/rpop.md b/commands/rpop.md index 99c863cd23..1f66fe2711 100644 --- a/commands/rpop.md +++ b/commands/rpop.md @@ -4,16 +4,6 @@ By default, the command pops a single element from the end of the list. When provided with the optional `count` argument, the reply will consist of up to `count` elements, depending on the list's length. -@return - -When called without the `count` argument: - -@bulk-string-reply: the value of the last element, or `nil` when `key` does not exist. - -When called with the `count` argument: - -@array-reply: list of popped elements, or `nil` when `key` does not exist. - @examples ```cli diff --git a/commands/rpoplpush.md b/commands/rpoplpush.md index d00e8c99c5..55f38bb555 100644 --- a/commands/rpoplpush.md +++ b/commands/rpoplpush.md @@ -13,10 +13,6 @@ If `source` and `destination` are the same, the operation is equivalent to removing the last element from the list and pushing it as first element of the list, so it can be considered as a list rotation command. -@return - -@bulk-string-reply: the element being popped and pushed. - @examples ```cli diff --git a/commands/rpush.md b/commands/rpush.md index def4ee10cf..9b50a44450 100644 --- a/commands/rpush.md +++ b/commands/rpush.md @@ -10,10 +10,6 @@ leftmost element to the rightmost element. So for instance the command `RPUSH mylist a b c` will result into a list containing `a` as first element, `b` as second element and `c` as third element. -@return - -@integer-reply: the length of the list after the push operation. - @examples ```cli diff --git a/commands/rpushx.md b/commands/rpushx.md index daab019a7e..88e0da657e 100644 --- a/commands/rpushx.md +++ b/commands/rpushx.md @@ -3,10 +3,6 @@ already exists and holds a list. In contrary to `RPUSH`, no operation will be performed when `key` does not yet exist. -@return - -@integer-reply: the length of the list after the push operation. - @examples ```cli diff --git a/commands/sadd.md b/commands/sadd.md index f8232bb220..93ad38d388 100644 --- a/commands/sadd.md +++ b/commands/sadd.md @@ -5,11 +5,6 @@ members. An error is returned when the value stored at `key` is not a set. -@return - -@integer-reply: the number of elements that were added to the set, not including -all the elements already present in the set. - @examples ```cli diff --git a/commands/save.md b/commands/save.md index c66c5e90a7..e2f32aa4d8 100644 --- a/commands/save.md +++ b/commands/save.md @@ -12,7 +12,3 @@ good last resort to perform the dump of the latest dataset. Please refer to the [persistence documentation][tp] for detailed information. [tp]: /topics/persistence - -@return - -@simple-string-reply: The commands returns OK on success. diff --git a/commands/scard.md b/commands/scard.md index 85d3c01059..1bbbc0c8bd 100644 --- a/commands/scard.md +++ b/commands/scard.md @@ -1,10 +1,5 @@ Returns the set cardinality (number of elements) of the set stored at `key`. -@return - -@integer-reply: the cardinality (number of elements) of the set, or `0` if `key` -does not exist. - @examples ```cli diff --git a/commands/script-debug.md b/commands/script-debug.md index 3779ed5e47..5a2e845f69 100644 --- a/commands/script-debug.md +++ b/commands/script-debug.md @@ -20,8 +20,3 @@ is active and retains all changes to the data set once it ends. * `NO`. Disables scripts debug mode. For more information about `EVAL` scripts please refer to [Introduction to Eval Scripts](/topics/eval-intro). - -@return - -@simple-string-reply: `OK`. - diff --git a/commands/script-exists.md b/commands/script-exists.md index 758660cf9b..5681628f25 100644 --- a/commands/script-exists.md +++ b/commands/script-exists.md @@ -9,10 +9,3 @@ operation can be performed solely using `EVALSHA` instead of `EVAL` to save bandwidth. For more information about `EVAL` scripts please refer to [Introduction to Eval Scripts](/topics/eval-intro). - -@return - -@array-reply The command returns an array of integers that correspond to -the specified SHA1 digest arguments. -For every corresponding SHA1 digest of a script that actually exists in the -script cache, a 1 is returned, otherwise 0 is returned. diff --git a/commands/script-flush.md b/commands/script-flush.md index 705d0142d4..d1e65a109d 100644 --- a/commands/script-flush.md +++ b/commands/script-flush.md @@ -10,10 +10,6 @@ It is possible to use one of the following modifiers to dictate the flushing mod For more information about `EVAL` scripts please refer to [Introduction to Eval Scripts](/topics/eval-intro). -@return - -@simple-string-reply - ## Behavior change history * `>= 6.2.0`: Default flush behavior now configurable by the **lazyfree-lazy-user-flush** configuration directive. \ No newline at end of file diff --git a/commands/script-help.md b/commands/script-help.md index 02b716326f..ed745e1389 100644 --- a/commands/script-help.md +++ b/commands/script-help.md @@ -1,5 +1 @@ The `SCRIPT HELP` command returns a helpful text describing the different subcommands. - -@return - -@array-reply: a list of subcommands and their descriptions diff --git a/commands/script-kill.md b/commands/script-kill.md index 5b4c646edb..b6dae1486e 100644 --- a/commands/script-kill.md +++ b/commands/script-kill.md @@ -13,7 +13,3 @@ the Redis process in a hard way and preventing it from persisting with half-writ information. For more information about `EVAL` scripts please refer to [Introduction to Eval Scripts](/topics/eval-intro). - -@return - -@simple-string-reply diff --git a/commands/script-load.md b/commands/script-load.md index ed5ab2dbc1..e85c6de628 100644 --- a/commands/script-load.md +++ b/commands/script-load.md @@ -10,8 +10,3 @@ The command works in the same way even if the script was already present in the script cache. For more information about `EVAL` scripts please refer to [Introduction to Eval Scripts](/topics/eval-intro). - -@return - -@bulk-string-reply This command returns the SHA1 digest of the script added into the -script cache. diff --git a/commands/sdiff.md b/commands/sdiff.md index 5d458eca34..7815877126 100644 --- a/commands/sdiff.md +++ b/commands/sdiff.md @@ -12,10 +12,6 @@ SDIFF key1 key2 key3 = {b,d} Keys that do not exist are considered to be empty sets. -@return - -@array-reply: list with members of the resulting set. - @examples ```cli diff --git a/commands/sdiffstore.md b/commands/sdiffstore.md index e941016742..23cd591532 100644 --- a/commands/sdiffstore.md +++ b/commands/sdiffstore.md @@ -3,10 +3,6 @@ is stored in `destination`. If `destination` already exists, it is overwritten. -@return - -@integer-reply: the number of elements in the resulting set. - @examples ```cli diff --git a/commands/select.md b/commands/select.md index 9ebc04e969..5f76dedbab 100644 --- a/commands/select.md +++ b/commands/select.md @@ -8,7 +8,3 @@ In practical terms, Redis databases should be used to separate different keys be When using Redis Cluster, the `SELECT` command cannot be used, since Redis Cluster only supports database zero. In the case of a Redis Cluster, having multiple databases would be useless and an unnecessary source of complexity. Commands operating atomically on a single database would not be possible with the Redis Cluster design and goals. Since the currently selected database is a property of the connection, clients should track the currently selected database and re-select it on reconnection. While there is no command in order to query the selected database in the current connection, the `CLIENT LIST` output shows, for each client, the currently selected database. - -@return - -@simple-string-reply diff --git a/commands/set.md b/commands/set.md index 2d8f626eed..5674b0765d 100644 --- a/commands/set.md +++ b/commands/set.md @@ -17,18 +17,6 @@ The `SET` command supports a set of options that modify its behavior: Note: Since the `SET` command options can replace `SETNX`, `SETEX`, `PSETEX`, `GETSET`, it is possible that in future versions of Redis these commands will be deprecated and finally removed. -@return - -@simple-string-reply: `OK` if `SET` was executed correctly. - -@nil-reply: `(nil)` if the `SET` operation was not performed because the user specified the `NX` or `XX` option but the condition was not met. - -If the command is issued with the `!GET` option, the above does not apply. It will instead reply as follows, regardless if the `SET` was actually performed: - -@bulk-string-reply: the old string value stored at key. - -@nil-reply: `(nil)` if the key did not exist. - @examples ```cli diff --git a/commands/setbit.md b/commands/setbit.md index e0b440b56c..a2e27ae840 100644 --- a/commands/setbit.md +++ b/commands/setbit.md @@ -20,10 +20,6 @@ allocation) takes ~8ms. Note that once this first allocation is done, subsequent calls to `SETBIT` for the same _key_ will not have the allocation overhead. -@return - -@integer-reply: the original bit value stored at _offset_. - @examples ```cli diff --git a/commands/setex.md b/commands/setex.md index f0d89d8b6d..c56718a11a 100644 --- a/commands/setex.md +++ b/commands/setex.md @@ -6,13 +6,8 @@ This command is equivalent to: SET key value EX seconds ``` - An error is returned when `seconds` is invalid. -@return - -@simple-string-reply - @examples ```cli diff --git a/commands/setnx.md b/commands/setnx.md index 833573c45e..72f5ac6a63 100644 --- a/commands/setnx.md +++ b/commands/setnx.md @@ -3,13 +3,6 @@ In that case, it is equal to `SET`. When `key` already holds a value, no operation is performed. `SETNX` is short for "**SET** if **N**ot e**X**ists". -@return - -@integer-reply, specifically: - -* `1` if the key was set -* `0` if the key was not set - @examples ```cli diff --git a/commands/setrange.md b/commands/setrange.md index 617e3d5dc3..3c7aa05b01 100644 --- a/commands/setrange.md +++ b/commands/setrange.md @@ -26,10 +26,6 @@ Thanks to `SETRANGE` and the analogous `GETRANGE` commands, you can use Redis strings as a linear array with O(1) random access. This is a very fast and efficient storage in many real world use cases. -@return - -@integer-reply: the length of the string after it was modified by the command. - @examples Basic usage: diff --git a/commands/shutdown.md b/commands/shutdown.md index 5dca6dec25..8bef39752d 100644 --- a/commands/shutdown.md +++ b/commands/shutdown.md @@ -62,12 +62,6 @@ This provides a best effort minimizing the risk of data loss in a situation wher Before version 7.0, shutting down a heavily loaded master node in a diskless setup was more likely to result in data loss. To minimize the risk of data loss in such setups, it's advised to trigger a manual `FAILOVER` (or `CLUSTER FAILOVER`) to demote the master to a replica and promote one of the replicas to be the new master, before shutting down a master node. -@return - -@simple-string-reply: `OK` if `ABORT` was specified and shutdown was aborted. -On successful shutdown, nothing is returned since the server quits and the connection is closed. -On failure, an error is returned. - ## Behavior change history * `>= 7.0.0`: Introduced waiting for lagging replicas before exiting. \ No newline at end of file diff --git a/commands/sinter.md b/commands/sinter.md index 465b3d73f7..e0b665b8a3 100644 --- a/commands/sinter.md +++ b/commands/sinter.md @@ -14,10 +14,6 @@ Keys that do not exist are considered to be empty sets. With one of the keys being an empty set, the resulting set is also empty (since set intersection with an empty set always results in an empty set). -@return - -@array-reply: list with members of the resulting set. - @examples ```cli diff --git a/commands/sintercard.md b/commands/sintercard.md index 24473e50b5..464e7bded5 100644 --- a/commands/sintercard.md +++ b/commands/sintercard.md @@ -8,10 +8,6 @@ By default, the command calculates the cardinality of the intersection of all gi When provided with the optional `LIMIT` argument (which defaults to 0 and means unlimited), if the intersection cardinality reaches limit partway through the computation, the algorithm will exit and yield limit as the cardinality. Such implementation ensures a significant speedup for queries where the limit is lower than the actual intersection cardinality. -@return - -@integer-reply: the number of elements in the resulting intersection. - @examples ```cli diff --git a/commands/sinterstore.md b/commands/sinterstore.md index 17dd0bf0b4..e3e712f036 100644 --- a/commands/sinterstore.md +++ b/commands/sinterstore.md @@ -3,10 +3,6 @@ it is stored in `destination`. If `destination` already exists, it is overwritten. -@return - -@integer-reply: the number of elements in the resulting set. - @examples ```cli diff --git a/commands/sismember.md b/commands/sismember.md index 219cd6e3e0..08b1c6c51f 100644 --- a/commands/sismember.md +++ b/commands/sismember.md @@ -1,12 +1,5 @@ Returns if `member` is a member of the set stored at `key`. -@return - -@integer-reply, specifically: - -* `1` if the element is a member of the set. -* `0` if the element is not a member of the set, or if `key` does not exist. - @examples ```cli diff --git a/commands/slaveof.md b/commands/slaveof.md index 34b95741ed..b42dc06160 100644 --- a/commands/slaveof.md +++ b/commands/slaveof.md @@ -16,7 +16,3 @@ So, if the old master stops working, it is possible to turn the replica into a master and set the application to use this new master in read/write. Later when the other Redis server is fixed, it can be reconfigured to work as a replica. - -@return - -@simple-string-reply diff --git a/commands/slowlog-get.md b/commands/slowlog-get.md index 3773cfbcd3..4b8f0c58d5 100644 --- a/commands/slowlog-get.md +++ b/commands/slowlog-get.md @@ -20,7 +20,3 @@ Each entry from the slow log is comprised of the following six values: The entry's unique ID can be used in order to avoid processing slow log entries multiple times (for instance you may have a script sending you an email alert for every new slow log entry). The ID is never reset in the course of the Redis server execution, only a server restart will reset it. - -@return - -@array-reply: a list of slow log entries. diff --git a/commands/slowlog-help.md b/commands/slowlog-help.md index a70f3a5d4e..86bf5b39a2 100644 --- a/commands/slowlog-help.md +++ b/commands/slowlog-help.md @@ -1,5 +1 @@ The `SLOWLOG HELP` command returns a helpful text describing the different subcommands. - -@return - -@array-reply: a list of subcommands and their descriptions diff --git a/commands/slowlog-len.md b/commands/slowlog-len.md index 6cc062f2a1..9515bb9473 100644 --- a/commands/slowlog-len.md +++ b/commands/slowlog-len.md @@ -4,9 +4,3 @@ A new entry is added to the slow log whenever a command exceeds the execution ti The maximum number of entries in the slow log is governed by the `slowlog-max-len` configuration directive. Once the slog log reaches its maximal size, the oldest entry is removed whenever a new entry is created. The slow log can be cleared with the `SLOWLOG RESET` command. - -@return - -@integer-reply - -The number of entries in the slow log. diff --git a/commands/slowlog-reset.md b/commands/slowlog-reset.md index 2b6d436aaf..a860f4433f 100644 --- a/commands/slowlog-reset.md +++ b/commands/slowlog-reset.md @@ -1,7 +1,3 @@ This command resets the slow log, clearing all entries in it. Once deleted the information is lost forever. - -@return - -@simple-string-reply: `OK` diff --git a/commands/smembers.md b/commands/smembers.md index 2272859352..20a8e23872 100644 --- a/commands/smembers.md +++ b/commands/smembers.md @@ -2,10 +2,6 @@ Returns all the members of the set value stored at `key`. This has the same effect as running `SINTER` with one argument `key`. -@return - -@array-reply: all elements of the set. - @examples ```cli diff --git a/commands/smismember.md b/commands/smismember.md index c4cec64a6b..4b8885996c 100644 --- a/commands/smismember.md +++ b/commands/smismember.md @@ -2,11 +2,6 @@ Returns whether each `member` is a member of the set stored at `key`. For every `member`, `1` is returned if the value is a member of the set, or `0` if the element is not a member of the set or if `key` does not exist. -@return - -@array-reply: list representing the membership of the given elements, in the same -order as they are requested. - @examples ```cli diff --git a/commands/smove.md b/commands/smove.md index 6b2400b6b0..241125cd2b 100644 --- a/commands/smove.md +++ b/commands/smove.md @@ -12,13 +12,6 @@ removed from the source set. An error is returned if `source` or `destination` does not hold a set value. -@return - -@integer-reply, specifically: - -* `1` if the element is moved. -* `0` if the element is not a member of `source` and no operation was performed. - @examples ```cli diff --git a/commands/sort.md b/commands/sort.md index 2a091db48c..ca06ed5bd6 100644 --- a/commands/sort.md +++ b/commands/sort.md @@ -147,8 +147,3 @@ SORT mylist BY weight_*->fieldname GET object_*->fieldname The string `->` is used to separate the key name from the hash field name. The key is substituted as documented above, and the hash stored at the resulting key is accessed to retrieve the specified hash field. - -@return - -@array-reply: without passing the `store` option the command returns a list of sorted elements. -@integer-reply: when the `store` option is specified the command returns the number of sorted elements in the destination list. diff --git a/commands/sort_ro.md b/commands/sort_ro.md index 66223a32e5..82dc85ee8d 100644 --- a/commands/sort_ro.md +++ b/commands/sort_ro.md @@ -11,7 +11,3 @@ See original `SORT` for more details. ``` SORT_RO mylist BY weight_*->fieldname GET object_*->fieldname ``` - -@return - -@array-reply: a list of sorted elements. diff --git a/commands/spop.md b/commands/spop.md index 8c86a9ab36..5ebfaed881 100644 --- a/commands/spop.md +++ b/commands/spop.md @@ -6,16 +6,6 @@ By default, the command pops a single member from the set. When provided with the optional `count` argument, the reply will consist of up to `count` members, depending on the set's cardinality. -@return - -When called without the `count` argument: - -@bulk-string-reply: the removed member, or `nil` when `key` does not exist. - -When called with the `count` argument: - -@array-reply: the removed members, or an empty array when `key` does not exist. - @examples ```cli diff --git a/commands/spublish.md b/commands/spublish.md index 762ff8ed75..0b8e65d09a 100644 --- a/commands/spublish.md +++ b/commands/spublish.md @@ -6,11 +6,6 @@ The cluster makes sure that published shard messages are forwarded to all the no For more information about sharded pubsub, see [Sharded Pubsub](/topics/pubsub#sharded-pubsub). -@return - -@integer-reply: the number of clients that received the message. -Note that in a Redis Cluster, only clients that are connected to the same node as the publishing client are included in the count. - @examples For example the following command publish to channel `orders` with a subscriber already waiting for message(s). diff --git a/commands/srandmember.md b/commands/srandmember.md index dd2d4a837d..b90dd23b7b 100644 --- a/commands/srandmember.md +++ b/commands/srandmember.md @@ -6,12 +6,6 @@ The array's length is either `count` or the set's cardinality (`SCARD`), whichev If called with a negative `count`, the behavior changes and the command is allowed to return the **same element multiple times**. In this case, the number of returned elements is the absolute value of the specified `count`. -@return - -@bulk-string-reply: without the additional `count` argument, the command returns a Bulk Reply with the randomly selected element, or `nil` when `key` does not exist. - -@array-reply: when the additional `count` argument is passed, the command returns an array of elements, or an empty array when `key` does not exist. - @examples ```cli diff --git a/commands/srem.md b/commands/srem.md index fca5b75d3c..2a85a99e6b 100644 --- a/commands/srem.md +++ b/commands/srem.md @@ -5,11 +5,6 @@ If `key` does not exist, it is treated as an empty set and this command returns An error is returned when the value stored at `key` is not a set. -@return - -@integer-reply: the number of members that were removed from the set, not -including non existing members. - @examples ```cli diff --git a/commands/ssubscribe.md b/commands/ssubscribe.md index 71c975cb7e..bf7d30e859 100644 --- a/commands/ssubscribe.md +++ b/commands/ssubscribe.md @@ -7,12 +7,6 @@ A client can subscribe to channels across different slots over separate `SSUBSCR For more information about sharded Pub/Sub, see [Sharded Pub/Sub](/topics/pubsub#sharded-pubsub). -@return - -When successful, this command doesn't return anything. -Instead, for each shard channel, one message with the first element being the string "ssubscribe" is pushed as a confirmation that the command succeeded. -Note that this command can also return a -MOVED redirect. - @examples ``` diff --git a/commands/strlen.md b/commands/strlen.md index e504180f01..f4b1fee52d 100644 --- a/commands/strlen.md +++ b/commands/strlen.md @@ -1,11 +1,6 @@ Returns the length of the string value stored at `key`. An error is returned when `key` holds a non-string value. -@return - -@integer-reply: the length of the string at `key`, or `0` when `key` does not -exist. - @examples ```cli diff --git a/commands/subscribe.md b/commands/subscribe.md index b9b4682775..1bde8ebe9c 100644 --- a/commands/subscribe.md +++ b/commands/subscribe.md @@ -7,11 +7,6 @@ However, if RESP3 is used (see `HELLO`) it is possible for a client to issue any For more information, see [Pub/sub](/docs/interact/pubsub/). -@return - -When successful, this command doesn't return anything. -Instead, for each channel, one message with the first element being the string "subscribe" is pushed as a confirmation that the command succeeded. - ## Behavior change history * `>= 6.2.0`: `RESET` can be called to exit subscribed state. diff --git a/commands/substr.md b/commands/substr.md index 7283defc49..c188f95494 100644 --- a/commands/substr.md +++ b/commands/substr.md @@ -7,10 +7,6 @@ So -1 means the last character, -2 the penultimate and so forth. The function handles out of range requests by limiting the resulting range to the actual length of the string. -@return - -@bulk-string-reply - @examples ```cli diff --git a/commands/sunion.md b/commands/sunion.md index 205646893a..31315484b6 100644 --- a/commands/sunion.md +++ b/commands/sunion.md @@ -11,10 +11,6 @@ SUNION key1 key2 key3 = {a,b,c,d,e} Keys that do not exist are considered to be empty sets. -@return - -@array-reply: list with members of the resulting set. - @examples ```cli diff --git a/commands/sunionstore.md b/commands/sunionstore.md index 716caf13f0..28b752640a 100644 --- a/commands/sunionstore.md +++ b/commands/sunionstore.md @@ -3,10 +3,6 @@ it is stored in `destination`. If `destination` already exists, it is overwritten. -@return - -@integer-reply: the number of elements in the resulting set. - @examples ```cli diff --git a/commands/sunsubscribe.md b/commands/sunsubscribe.md index 36dc8d9a40..7ce76c333e 100644 --- a/commands/sunsubscribe.md +++ b/commands/sunsubscribe.md @@ -6,8 +6,3 @@ In this case a message for every unsubscribed shard channel will be sent to the Note: The global channels and shard channels needs to be unsubscribed from separately. For more information about sharded Pub/Sub, see [Sharded Pub/Sub](/topics/pubsub#sharded-pubsub). - -@return - -When successful, this command doesn't return anything. -Instead, for each shard channel, one message with the first element being the string "sunsubscribe" is pushed as a confirmation that the command succeeded. diff --git a/commands/swapdb.md b/commands/swapdb.md index ead2db07c0..7037f477f0 100644 --- a/commands/swapdb.md +++ b/commands/swapdb.md @@ -6,10 +6,6 @@ the other way around. Example: This will swap database 0 with database 1. All the clients connected with database 0 will immediately see the new data, exactly like all the clients connected with database 1 will see the data that was formerly of database 0. -@return - -@simple-string-reply: `OK` if `SWAPDB` was executed correctly. - @examples ``` diff --git a/commands/sync.md b/commands/sync.md index cb958479ca..5d9ad047f9 100644 --- a/commands/sync.md +++ b/commands/sync.md @@ -8,7 +8,3 @@ For more information about replication in Redis please check the [replication page][tr]. [tr]: /topics/replication - -@return - -**Non standard return value**, a bulk transfer of the data followed by `PING` and write requests from the master. diff --git a/commands/time.md b/commands/time.md index 2cf1af6828..b7adb8f164 100644 --- a/commands/time.md +++ b/commands/time.md @@ -3,15 +3,6 @@ timestamp and the amount of microseconds already elapsed in the current second. Basically the interface is very similar to the one of the `gettimeofday` system call. -@return - -@array-reply, specifically: - -A multi bulk reply containing two elements: - -* unix time in seconds. -* microseconds. - @examples ```cli diff --git a/commands/touch.md b/commands/touch.md index a369354503..ba5bc9b0db 100644 --- a/commands/touch.md +++ b/commands/touch.md @@ -1,10 +1,6 @@ Alters the last access time of a key(s). A key is ignored if it does not exist. -@return - -@integer-reply: The number of keys that were touched. - @examples ```cli diff --git a/commands/ttl.md b/commands/ttl.md index 15821e1140..1cc0a86f90 100644 --- a/commands/ttl.md +++ b/commands/ttl.md @@ -11,10 +11,6 @@ Starting with Redis 2.8 the return value in case of error changed: See also the `PTTL` command that returns the same information with milliseconds resolution (Only available in Redis 2.6 or greater). -@return - -@integer-reply: TTL in seconds, or a negative value in order to signal an error (see the description above). - @examples ```cli diff --git a/commands/type.md b/commands/type.md index 8a818e0544..7bdd48407d 100644 --- a/commands/type.md +++ b/commands/type.md @@ -2,10 +2,6 @@ Returns the string representation of the type of the value stored at `key`. The different types that can be returned are: `string`, `list`, `set`, `zset`, `hash` and `stream`. -@return - -@simple-string-reply: type of `key`, or `none` when `key` does not exist. - @examples ```cli diff --git a/commands/unlink.md b/commands/unlink.md index c91dd664de..0d5ade0217 100644 --- a/commands/unlink.md +++ b/commands/unlink.md @@ -5,10 +5,6 @@ blocking, while `DEL` is. This is where the command name comes from: the command just **unlinks** the keys from the keyspace. The actual removal will happen later asynchronously. -@return - -@integer-reply: The number of keys that were unlinked. - @examples ```cli diff --git a/commands/unsubscribe.md b/commands/unsubscribe.md index e5f53a0e9c..7bdf1d15e5 100644 --- a/commands/unsubscribe.md +++ b/commands/unsubscribe.md @@ -5,8 +5,3 @@ When no channels are specified, the client is unsubscribed from all the previously subscribed channels. In this case, a message for every unsubscribed channel will be sent to the client. - -@return - -When successful, this command doesn't return anything. -Instead, for each channel, one message with the first element being the string "unsubscribe" is pushed as a confirmation that the command succeeded. diff --git a/commands/unwatch.md b/commands/unwatch.md index b60bcb8040..dcdda08dab 100644 --- a/commands/unwatch.md +++ b/commands/unwatch.md @@ -3,7 +3,3 @@ Flushes all the previously watched keys for a [transaction][tt]. [tt]: /topics/transactions If you call `EXEC` or `DISCARD`, there's no need to manually call `UNWATCH`. - -@return - -@simple-string-reply: always `OK`. diff --git a/commands/wait.md b/commands/wait.md index a76f644784..b671faff4e 100644 --- a/commands/wait.md +++ b/commands/wait.md @@ -37,10 +37,6 @@ write command was executed in the context of a given client. When `WAIT` is called Redis checks if the specified number of replicas already acknowledged this offset or a greater one. -@return - -@integer-reply: The command returns the number of replicas reached by all the writes performed in the context of the current connection. - @examples ``` diff --git a/commands/waitaof.md b/commands/waitaof.md index 58b4c7abab..5b824342a5 100644 --- a/commands/waitaof.md +++ b/commands/waitaof.md @@ -35,10 +35,6 @@ In addition, Redis replicas asynchronously ping their master with two replicatio Redis remembers, for each client, the replication offset of the produced replication stream when the last write command was executed in the context of that client. When `WAITAOF` is called, Redis checks if the local Redis and/or the specified number of replicas have confirmed fsyncing this offset or a greater one to their AOF. -@return - -@array-reply: The command returns an array of two integers: The first is the number of local Redises (0 or 1) that have fsynced to AOF all writes performed in the context of the current connection; The second is the number of replicas that have acknowledged doing the same. - @examples ``` diff --git a/commands/watch.md b/commands/watch.md index 08f823ff7f..2121bd5cb5 100644 --- a/commands/watch.md +++ b/commands/watch.md @@ -2,7 +2,3 @@ Marks the given keys to be watched for conditional execution of a [transaction][tt]. [tt]: /topics/transactions - -@return - -@simple-string-reply: always `OK`. diff --git a/commands/xack.md b/commands/xack.md index aae2db5586..daeb7c21c8 100644 --- a/commands/xack.md +++ b/commands/xack.md @@ -14,15 +14,6 @@ so that such message does not get processed again, and as a side effect, the PEL entry about this message is also purged, releasing memory from the Redis server. -@return - -@integer-reply, specifically: - -The command returns the number of messages successfully acknowledged. -Certain message IDs may no longer be part of the PEL (for example because -they have already been acknowledged), and XACK will not count them as -successfully acknowledged. - @examples ``` diff --git a/commands/xadd.md b/commands/xadd.md index d651a6858c..3f431a133b 100644 --- a/commands/xadd.md +++ b/commands/xadd.md @@ -72,17 +72,6 @@ Will add a new entry but will also evict old entries so that the stream will con For further information about Redis streams please check our [introduction to Redis Streams document](/topics/streams-intro). -@return - -@bulk-string-reply, specifically: - -The command returns the ID of the added entry. The ID is the one auto-generated -if `*` is passed as ID argument, otherwise the command just returns the same ID -specified by the user during insertion. - -The command returns a @nil-reply when used with the `NOMKSTREAM` option and the -key doesn't exist. - @examples ```cli diff --git a/commands/xautoclaim.md b/commands/xautoclaim.md index 5ff44f2fd2..4b65eba3ae 100644 --- a/commands/xautoclaim.md +++ b/commands/xautoclaim.md @@ -25,16 +25,6 @@ These message IDs are returned to the caller as a part of `XAUTOCLAIM`s reply. Lastly, claiming a message with `XAUTOCLAIM` also increments the attempted deliveries count for that message, unless the `JUSTID` option has been specified (which only delivers the message ID, not the message itself). Messages that cannot be processed for some reason - for example, because consumers systematically crash when processing them - will exhibit high attempted delivery counts that can be detected by monitoring. -@return - -@array-reply, specifically: - -An array with three elements: - -1. A stream ID to be used as the `` argument for the next call to `XAUTOCLAIM`. -2. An array containing all the successfully claimed messages in the same format as `XRANGE`. -3. An array containing message IDs that no longer exist in the stream, and were deleted from the PEL in which they were found. - @examples ``` diff --git a/commands/xclaim.md b/commands/xclaim.md index bc7b7be3a6..50fd8d23c2 100644 --- a/commands/xclaim.md +++ b/commands/xclaim.md @@ -35,14 +35,6 @@ useful to normal users: 4. `FORCE`: Creates the pending message entry in the PEL even if certain specified IDs are not already in the PEL assigned to a different client. However the message must be exist in the stream, otherwise the IDs of non existing messages are ignored. 5. `JUSTID`: Return just an array of IDs of messages successfully claimed, without returning the actual message. Using this option means the retry counter is not incremented. -@return - -@array-reply, specifically: - -The command returns all the messages successfully claimed, in the same format -as `XRANGE`. However if the `JUSTID` option was specified, only the message -IDs are reported, without including the actual message. - @examples ``` diff --git a/commands/xdel.md b/commands/xdel.md index 3ee4a3d067..57b9a8ba47 100644 --- a/commands/xdel.md +++ b/commands/xdel.md @@ -26,10 +26,6 @@ collection in case a given macro-node reaches a given amount of deleted entries. Currently with the usage we anticipate for this data structure, it is not a good idea to add such complexity. -@return - -@integer-reply: the number of entries actually deleted. - @examples ``` diff --git a/commands/xgroup-create.md b/commands/xgroup-create.md index 4fdc149f61..124a8a14f4 100644 --- a/commands/xgroup-create.md +++ b/commands/xgroup-create.md @@ -19,7 +19,3 @@ To enable consumer group lag tracking, specify the optional `entries_read` named An arbitrary ID is any ID that isn't the ID of the stream's first entry, last entry, or zero ("0-0") ID. Use it to find out how many entries are between the arbitrary ID (excluding it) and the stream's last entry. Set the `entries_read` the stream's `entries_added` subtracted by the number of entries. - -@return - -@simple-string-reply: `OK` on success. diff --git a/commands/xgroup-createconsumer.md b/commands/xgroup-createconsumer.md index 3b27b1d123..f81d468a02 100644 --- a/commands/xgroup-createconsumer.md +++ b/commands/xgroup-createconsumer.md @@ -2,7 +2,3 @@ Create a consumer named `` in the consumer group `` of Consumers are also created automatically whenever an operation, such as `XREADGROUP`, references a consumer that doesn't exist. This is valid for `XREADGROUP` only when there is data in the stream. - -@return - -@integer-reply: the number of created consumers (0 or 1) \ No newline at end of file diff --git a/commands/xgroup-delconsumer.md b/commands/xgroup-delconsumer.md index 9e73da8922..57c71adb12 100644 --- a/commands/xgroup-delconsumer.md +++ b/commands/xgroup-delconsumer.md @@ -4,7 +4,3 @@ Sometimes it may be useful to remove old consumers since they are no longer used Note, however, that any pending messages that the consumer had will become unclaimable after it was deleted. It is strongly recommended, therefore, that any pending messages are claimed or acknowledged prior to deleting the consumer from the group. - -@return - -@integer-reply: the number of pending messages that the consumer had before it was deleted diff --git a/commands/xgroup-destroy.md b/commands/xgroup-destroy.md index 448468ba14..29af5f73cb 100644 --- a/commands/xgroup-destroy.md +++ b/commands/xgroup-destroy.md @@ -1,7 +1,3 @@ The `XGROUP DESTROY` command completely destroys a consumer group. The consumer group will be destroyed even if there are active consumers, and pending messages, so make sure to call this command only when really needed. - -@return - -@integer-reply: the number of destroyed consumer groups (0 or 1) \ No newline at end of file diff --git a/commands/xgroup-help.md b/commands/xgroup-help.md index 1eb1a7bb34..405008ac80 100644 --- a/commands/xgroup-help.md +++ b/commands/xgroup-help.md @@ -1,5 +1 @@ The `XGROUP HELP` command returns a helpful text describing the different subcommands. - -@return - -@array-reply: a list of subcommands and their descriptions diff --git a/commands/xgroup-setid.md b/commands/xgroup-setid.md index 0808404f25..5ea91accdc 100644 --- a/commands/xgroup-setid.md +++ b/commands/xgroup-setid.md @@ -10,7 +10,3 @@ The optional `entries_read` argument can be specified to enable consumer group l An arbitrary ID is any ID that isn't the ID of the stream's first entry, its last entry or the zero ("0-0") ID. This can be useful you know exactly how many entries are between the arbitrary ID (excluding it) and the stream's last entry. In such cases, the `entries_read` can be set to the stream's `entries_added` subtracted with the number of entries. - -@return - -@simple-string-reply: `OK` on success. diff --git a/commands/xinfo-consumers.md b/commands/xinfo-consumers.md index d4bb878b8e..f50c8ac34e 100644 --- a/commands/xinfo-consumers.md +++ b/commands/xinfo-consumers.md @@ -7,10 +7,6 @@ The following information is provided for each consumer in the group: * **idle**: the number of milliseconds that have passed since the consumer's last attempted interaction (Examples: `XREADGROUP`, `XCLAIM`, `XAUTOCLAIM`) * **inactive**: the number of milliseconds that have passed since the consumer's last successful interaction (Examples: `XREADGROUP` that actually read some entries into the PEL, `XCLAIM`/`XAUTOCLAIM` that actually claimed some entries) -@return - -@array-reply: a list of consumers. - @examples ``` diff --git a/commands/xinfo-groups.md b/commands/xinfo-groups.md index 08af1c9ae1..3074725158 100644 --- a/commands/xinfo-groups.md +++ b/commands/xinfo-groups.md @@ -39,10 +39,6 @@ However, the lag is only temporarily unavailable. It is restored automatically during regular operation as consumers keep processing messages. Once the consumer group delivers the last message in the stream to its members, it will be set with the correct logical read counter, and tracking its lag can be resumed. -@return - -@array-reply: a list of consumer groups. - @examples ``` diff --git a/commands/xinfo-help.md b/commands/xinfo-help.md index 293892fd8f..34ad659b9c 100644 --- a/commands/xinfo-help.md +++ b/commands/xinfo-help.md @@ -1,5 +1 @@ The `XINFO HELP` command returns a helpful text describing the different subcommands. - -@return - -@array-reply: a list of subcommands and their descriptions diff --git a/commands/xinfo-stream.md b/commands/xinfo-stream.md index beba33e18e..64a68949f2 100644 --- a/commands/xinfo-stream.md +++ b/commands/xinfo-stream.md @@ -19,10 +19,6 @@ Furthermore, **groups** is also an array, and for each of the consumer groups it The `COUNT` option can be used to limit the number of stream and PEL entries that are returned (The first `` entries are returned). The default `COUNT` is 10 and a `COUNT` of 0 means that all entries will be returned (execution time may be long if the stream has a lot of entries). -@return - -@array-reply: a list of informational bits - @examples Default reply: diff --git a/commands/xlen.md b/commands/xlen.md index 41c2010e7f..e996f7ee18 100644 --- a/commands/xlen.md +++ b/commands/xlen.md @@ -8,10 +8,6 @@ Streams are not auto-deleted once they have no entries inside (for instance after an `XDEL` call), because the stream may have consumer groups associated with it. -@return - -@integer-reply: the number of entries of the stream at `key`. - @examples ```cli diff --git a/commands/xpending.md b/commands/xpending.md index 48840aaa38..c22ae8e38d 100644 --- a/commands/xpending.md +++ b/commands/xpending.md @@ -127,11 +127,3 @@ The `XPENDING` command allows iterating over the pending entries just like prefixing the ID of the last-read pending entry with the `(` character that denotes an open (exclusive) range, and proving it to the subsequent call to the command. - -@return - -@array-reply, specifically: - -The command returns data in different format depending on the way it is -called, as previously explained in this page. However the reply is always -an array of items. diff --git a/commands/xrange.md b/commands/xrange.md index fa81b316a5..a8d4e89b67 100644 --- a/commands/xrange.md +++ b/commands/xrange.md @@ -200,15 +200,6 @@ of XRANGE: For further information about Redis streams please check our [introduction to Redis Streams document](/topics/streams-intro). -@return - -@array-reply, specifically: - -The command returns the entries with IDs matching the specified range. -The returned entries are complete, that means that the ID and all the fields -they are composed are returned. Moreover, the entries are returned with -their fields and values in the exact same order as `XADD` added them. - @examples ```cli diff --git a/commands/xread.md b/commands/xread.md index ea0f311ecc..0a6741519f 100644 --- a/commands/xread.md +++ b/commands/xread.md @@ -197,19 +197,6 @@ are not removed from the stream when clients are served, so every client waiting will be served as soon as an `XADD` command provides data to the stream. -@return - -@array-reply, specifically: - -The command returns an array of results: each element of the returned -array is an array composed of a two element containing the key name and -the entries reported for that key. The entries reported are full stream -entries, having IDs and the list of all the fields and values. Field and -values are guaranteed to be reported in the same order they were added -by `XADD`. - -When **BLOCK** is used, on timeout a null reply is returned. - Reading the [Redis Streams introduction](/topics/streams-intro) is highly suggested in order to understand more about the streams overall behavior -and semantics. +and semantics. \ No newline at end of file diff --git a/commands/xreadgroup.md b/commands/xreadgroup.md index 2e20d415f2..e94d2bb619 100644 --- a/commands/xreadgroup.md +++ b/commands/xreadgroup.md @@ -129,19 +129,6 @@ OK 2) (nil) ``` -@return - -@array-reply, specifically: - -The command returns an array of results: each element of the returned -array is an array composed of a two element containing the key name and -the entries reported for that key. The entries reported are full stream -entries, having IDs and the list of all the fields and values. Field and -values are guaranteed to be reported in the same order they were added -by `XADD`. - -When **BLOCK** is used, on timeout a null reply is returned. - Reading the [Redis Streams introduction](/topics/streams-intro) is highly suggested in order to understand more about the streams overall behavior and semantics. diff --git a/commands/xrevrange.md b/commands/xrevrange.md index d61b3f5073..ab10209082 100644 --- a/commands/xrevrange.md +++ b/commands/xrevrange.md @@ -14,16 +14,6 @@ enough to send: XREVRANGE somestream + - COUNT 1 -@return - -@array-reply, specifically: - -The command returns the entries with IDs matching the specified range, -from the higher ID to the lower ID matching. -The returned entries are complete, that means that the ID and all the fields -they are composed are returned. Moreover the entries are returned with -their fields and values in the exact same order as `XADD` added them. - @examples ```cli diff --git a/commands/xtrim.md b/commands/xtrim.md index 08d55d5a9e..b26fec018e 100644 --- a/commands/xtrim.md +++ b/commands/xtrim.md @@ -44,10 +44,6 @@ When used, it specifies the maximal `count` of entries that will be evicted. When `LIMIT` and `count` aren't specified, the default value of 100 * the number of entries in a macro node will be implicitly used as the `count`. Specifying the value 0 as `count` disables the limiting mechanism entirely. -@return - -@integer-reply: The number of entries deleted from the stream. - @examples ```cli diff --git a/commands/zadd.md b/commands/zadd.md index eb77de6790..1f11c6ed28 100644 --- a/commands/zadd.md +++ b/commands/zadd.md @@ -58,17 +58,6 @@ The lexicographic ordering used is binary, it compares strings as array of bytes If the user inserts all the elements in a sorted set with the same score (for example 0), all the elements of the sorted set are sorted lexicographically, and range queries on elements are possible using the command `ZRANGEBYLEX` (Note: it is also possible to query sorted sets by range of scores using `ZRANGEBYSCORE`). -@return - -@integer-reply, specifically: - -* When used without optional arguments, the number of elements added to the sorted set (excluding score updates). -* If the `CH` option is specified, the number of elements that were changed (added or updated). - -If the `INCR` option is specified, the return value will be @bulk-string-reply: - -* The new score of `member` (a double precision floating point number) represented as string, or `nil` if the operation was aborted (when called with either the `XX` or the `NX` option). - @examples ```cli diff --git a/commands/zcard.md b/commands/zcard.md index 5ad504335d..bacabd2883 100644 --- a/commands/zcard.md +++ b/commands/zcard.md @@ -1,11 +1,6 @@ Returns the sorted set cardinality (number of elements) of the sorted set stored at `key`. -@return - -@integer-reply: the cardinality (number of elements) of the sorted set, or `0` -if `key` does not exist. - @examples ```cli diff --git a/commands/zcount.md b/commands/zcount.md index 82ce39b81c..a90d7c4b37 100644 --- a/commands/zcount.md +++ b/commands/zcount.md @@ -6,10 +6,6 @@ The `min` and `max` arguments have the same semantic as described for Note: the command has a complexity of just O(log(N)) because it uses elements ranks (see `ZRANK`) to get an idea of the range. Because of this there is no need to do a work proportional to the size of the range. -@return - -@integer-reply: the number of elements in the specified score range. - @examples ```cli diff --git a/commands/zdiff.md b/commands/zdiff.md index d9449b7ef5..e2df52e424 100644 --- a/commands/zdiff.md +++ b/commands/zdiff.md @@ -1,11 +1,6 @@ This command is similar to `ZDIFFSTORE`, but instead of storing the resulting sorted set, it is returned to the client. -@return - -@array-reply: the result of the difference (optionally with their scores, in case -the `WITHSCORES` option is given). - @examples ```cli diff --git a/commands/zdiffstore.md b/commands/zdiffstore.md index abe3ba7e73..d9d2e2cac3 100644 --- a/commands/zdiffstore.md +++ b/commands/zdiffstore.md @@ -6,11 +6,6 @@ Keys that do not exist are considered to be empty sets. If `destination` already exists, it is overwritten. -@return - -@integer-reply: the number of elements in the resulting sorted set at -`destination`. - @examples ```cli diff --git a/commands/zincrby.md b/commands/zincrby.md index 0b8ccf0985..bbf48716b8 100644 --- a/commands/zincrby.md +++ b/commands/zincrby.md @@ -11,11 +11,6 @@ The `score` value should be the string representation of a numeric value, and accepts double precision floating point numbers. It is possible to provide a negative value to decrement the score. -@return - -@bulk-string-reply: the new score of `member` (a double precision floating point -number), represented as string. - @examples ```cli diff --git a/commands/zinter.md b/commands/zinter.md index 5a7adccd79..b796517797 100644 --- a/commands/zinter.md +++ b/commands/zinter.md @@ -3,11 +3,6 @@ sorted set, it is returned to the client. For a description of the `WEIGHTS` and `AGGREGATE` options, see `ZUNIONSTORE`. -@return - -@array-reply: the result of intersection (optionally with their scores, in case -the `WITHSCORES` option is given). - @examples ```cli diff --git a/commands/zintercard.md b/commands/zintercard.md index 613849fc2d..7ee7d1edeb 100644 --- a/commands/zintercard.md +++ b/commands/zintercard.md @@ -7,10 +7,6 @@ By default, the command calculates the cardinality of the intersection of all gi When provided with the optional `LIMIT` argument (which defaults to 0 and means unlimited), if the intersection cardinality reaches limit partway through the computation, the algorithm will exit and yield limit as the cardinality. Such implementation ensures a significant speedup for queries where the limit is lower than the actual intersection cardinality. -@return - -@integer-reply: the number of elements in the resulting intersection. - @examples ```cli diff --git a/commands/zinterstore.md b/commands/zinterstore.md index 0ecda0ddd7..1d386aa3a4 100644 --- a/commands/zinterstore.md +++ b/commands/zinterstore.md @@ -13,11 +13,6 @@ For a description of the `WEIGHTS` and `AGGREGATE` options, see `ZUNIONSTORE`. If `destination` already exists, it is overwritten. -@return - -@integer-reply: the number of elements in the resulting sorted set at -`destination`. - @examples ```cli diff --git a/commands/zlexcount.md b/commands/zlexcount.md index 15484f7973..2eeed5c27d 100644 --- a/commands/zlexcount.md +++ b/commands/zlexcount.md @@ -5,10 +5,6 @@ The `min` and `max` arguments have the same meaning as described for Note: the command has a complexity of just O(log(N)) because it uses elements ranks (see `ZRANK`) to get an idea of the range. Because of this there is no need to do a work proportional to the size of the range. -@return - -@integer-reply: the number of elements in the specified score range. - @examples ```cli diff --git a/commands/zmpop.md b/commands/zmpop.md index 16848a0e08..e3fd6944b3 100644 --- a/commands/zmpop.md +++ b/commands/zmpop.md @@ -12,13 +12,6 @@ The optional `COUNT` can be used to specify the number of elements to pop, and i The number of popped elements is the minimum from the sorted set's cardinality and `COUNT`'s value. -@return - -@array-reply: specifically: - -* A `nil` when no element could be popped. -* A two-element array with the first element being the name of the key from which elements were popped, and the second element is an array of the popped elements. Every entry in the elements array is also an array that contains the member and its score. - @examples ```cli diff --git a/commands/zmscore.md b/commands/zmscore.md index c2317e90b8..0111a4a01b 100644 --- a/commands/zmscore.md +++ b/commands/zmscore.md @@ -2,11 +2,6 @@ Returns the scores associated with the specified `members` in the sorted set sto For every `member` that does not exist in the sorted set, a `nil` value is returned. -@return - -@array-reply: list of scores or `nil` associated with the specified `member` values (a double precision floating point number), -represented as strings. - @examples ```cli diff --git a/commands/zpopmax.md b/commands/zpopmax.md index 8f6750a75d..c0245f28b6 100644 --- a/commands/zpopmax.md +++ b/commands/zpopmax.md @@ -6,10 +6,6 @@ value that is higher than the sorted set's cardinality will not produce an error. When returning multiple elements, the one with the highest score will be the first, followed by the elements with lower scores. -@return - -@array-reply: list of popped elements and scores. - @examples ```cli diff --git a/commands/zpopmin.md b/commands/zpopmin.md index 16f7c97ac1..2214e57dd6 100644 --- a/commands/zpopmin.md +++ b/commands/zpopmin.md @@ -6,10 +6,6 @@ value that is higher than the sorted set's cardinality will not produce an error. When returning multiple elements, the one with the lowest score will be the first, followed by the elements with greater scores. -@return - -@array-reply: list of popped elements and scores. - @examples ```cli diff --git a/commands/zrandmember.md b/commands/zrandmember.md index aae0b25434..d1f6ed983e 100644 --- a/commands/zrandmember.md +++ b/commands/zrandmember.md @@ -8,13 +8,6 @@ In this case, the number of returned elements is the absolute value of the speci The optional `WITHSCORES` modifier changes the reply so it includes the respective scores of the randomly selected elements from the sorted set. -@return - -@bulk-string-reply: without the additional `count` argument, the command returns a Bulk Reply with the randomly selected element, or `nil` when `key` does not exist. - -@array-reply: when the additional `count` argument is passed, the command returns an array of elements, or an empty array when `key` does not exist. -If the `WITHSCORES` modifier is used, the reply is a list elements and their scores from the sorted set. - @examples ```cli diff --git a/commands/zrange.md b/commands/zrange.md index e28d5c3994..a928689d71 100644 --- a/commands/zrange.md +++ b/commands/zrange.md @@ -100,11 +100,6 @@ Because of the first *normalized* part in every element (before the colon charac The binary nature of the comparison allows to use sorted sets as a general purpose index, for example, the first part of the element can be a 64-bit big-endian number. Since big-endian numbers have the most significant bytes in the initial positions, the binary comparison will match the numerical comparison of the numbers. This can be used in order to implement range queries on 64-bit values. As in the example below, after the first 8 bytes, we can store the value of the element we are indexing. -@return - -@array-reply: list of elements in the specified range (optionally with -their scores, in case the `WITHSCORES` option is given). - @examples ```cli diff --git a/commands/zrangebylex.md b/commands/zrangebylex.md index 4eefffc05a..b4663f674b 100644 --- a/commands/zrangebylex.md +++ b/commands/zrangebylex.md @@ -47,10 +47,6 @@ comparison of the numbers. This can be used in order to implement range queries on 64 bit values. As in the example below, after the first 8 bytes we can store the value of the element we are actually indexing. -@return - -@array-reply: list of elements in the specified score range. - @examples ```cli diff --git a/commands/zrangebyscore.md b/commands/zrangebyscore.md index bc81708533..5c4ea3a9fc 100644 --- a/commands/zrangebyscore.md +++ b/commands/zrangebyscore.md @@ -40,11 +40,6 @@ ZRANGEBYSCORE zset (5 (10 Will return all the elements with `5 < score < 10` (5 and 10 excluded). -@return - -@array-reply: list of elements in the specified score range (optionally -with their scores). - @examples ```cli diff --git a/commands/zrangestore.md b/commands/zrangestore.md index 8dc744c3e3..2a0bbfc9d9 100644 --- a/commands/zrangestore.md +++ b/commands/zrangestore.md @@ -1,9 +1,5 @@ This command is like `ZRANGE`, but stores the result in the `` destination key. -@return - -@integer-reply: the number of elements in the resulting sorted set. - @examples ```cli diff --git a/commands/zrank.md b/commands/zrank.md index f458f298da..8436883cd0 100644 --- a/commands/zrank.md +++ b/commands/zrank.md @@ -8,17 +8,6 @@ The optional `WITHSCORE` argument supplements the command's reply with the score Use `ZREVRANK` to get the rank of an element with the scores ordered from high to low. -@return - -* If `member` exists in the sorted set: - * using `WITHSCORE`, @array-reply: an array containing the rank and score of `member`. - * without using `WITHSCORE`, @integer-reply: the rank of `member`. -* If `member` does not exist in the sorted set or `key` does not exist: - * using `WITHSCORE`, @array-reply: `nil`. - * without using `WITHSCORE`, @bulk-string-reply: `nil`. - -Note that in RESP3 null and nullarray are the same, but in RESP2 they are not. - @examples ```cli diff --git a/commands/zrem.md b/commands/zrem.md index d97fd4ba94..642e2874bc 100644 --- a/commands/zrem.md +++ b/commands/zrem.md @@ -3,13 +3,6 @@ Non existing members are ignored. An error is returned when `key` exists and does not hold a sorted set. -@return - -@integer-reply, specifically: - -* The number of members removed from the sorted set, not including non existing - members. - @examples ```cli diff --git a/commands/zremrangebylex.md b/commands/zremrangebylex.md index 4264f1b072..83df974cdd 100644 --- a/commands/zremrangebylex.md +++ b/commands/zremrangebylex.md @@ -2,10 +2,6 @@ When all the elements in a sorted set are inserted with the same score, in order The meaning of `min` and `max` are the same of the `ZRANGEBYLEX` command. Similarly, this command actually removes the same elements that `ZRANGEBYLEX` would return if called with the same `min` and `max` arguments. -@return - -@integer-reply: the number of elements removed. - @examples ```cli diff --git a/commands/zremrangebyrank.md b/commands/zremrangebyrank.md index edd3cf39a5..30a068b673 100644 --- a/commands/zremrangebyrank.md +++ b/commands/zremrangebyrank.md @@ -7,10 +7,6 @@ the element with the highest score. For example: `-1` is the element with the highest score, `-2` the element with the second highest score and so forth. -@return - -@integer-reply: the number of elements removed. - @examples ```cli diff --git a/commands/zremrangebyscore.md b/commands/zremrangebyscore.md index fdf9a9869c..839b17b3c7 100644 --- a/commands/zremrangebyscore.md +++ b/commands/zremrangebyscore.md @@ -1,10 +1,6 @@ Removes all elements in the sorted set stored at `key` with a score between `min` and `max` (inclusive). -@return - -@integer-reply: the number of elements removed. - @examples ```cli diff --git a/commands/zrevrange.md b/commands/zrevrange.md index 3a19810c94..2a36390456 100644 --- a/commands/zrevrange.md +++ b/commands/zrevrange.md @@ -4,11 +4,6 @@ Descending lexicographical order is used for elements with equal score. Apart from the reversed ordering, `ZREVRANGE` is similar to `ZRANGE`. -@return - -@array-reply: list of elements in the specified range (optionally with -their scores). - @examples ```cli diff --git a/commands/zrevrangebylex.md b/commands/zrevrangebylex.md index c6772c9128..eb9ad8f436 100644 --- a/commands/zrevrangebylex.md +++ b/commands/zrevrangebylex.md @@ -2,10 +2,6 @@ When all the elements in a sorted set are inserted with the same score, in order Apart from the reversed ordering, `ZREVRANGEBYLEX` is similar to `ZRANGEBYLEX`. -@return - -@array-reply: list of elements in the specified score range. - @examples ```cli diff --git a/commands/zrevrangebyscore.md b/commands/zrevrangebyscore.md index e95d771bb3..c6e2e3e537 100644 --- a/commands/zrevrangebyscore.md +++ b/commands/zrevrangebyscore.md @@ -9,11 +9,6 @@ order. Apart from the reversed ordering, `ZREVRANGEBYSCORE` is similar to `ZRANGEBYSCORE`. -@return - -@array-reply: list of elements in the specified score range (optionally -with their scores). - @examples ```cli diff --git a/commands/zrevrank.md b/commands/zrevrank.md index 11aad62bbe..c79868920b 100644 --- a/commands/zrevrank.md +++ b/commands/zrevrank.md @@ -8,17 +8,6 @@ The optional `WITHSCORE` argument supplements the command's reply with the score Use `ZRANK` to get the rank of an element with the scores ordered from low to high. -@return - -* If `member` exists in the sorted set: - * using `WITHSCORE`, @array-reply: an array containing the rank and score of `member`. - * without using `WITHSCORE`, @integer-reply: the rank of `member`. -* If `member` does not exist in the sorted set or `key` does not exist: - * using `WITHSCORE`, @array-reply: `nil`. - * without using `WITHSCORE`, @bulk-string-reply: `nil`. - -Note that in RESP3 null and nullarray are the same, but in RESP2 they are not. - @examples ```cli diff --git a/commands/zscore.md b/commands/zscore.md index 8b1e74dd88..324019d940 100644 --- a/commands/zscore.md +++ b/commands/zscore.md @@ -3,11 +3,6 @@ Returns the score of `member` in the sorted set at `key`. If `member` does not exist in the sorted set, or `key` does not exist, `nil` is returned. -@return - -@bulk-string-reply: the score of `member` (a double precision floating point number), -represented as string. - @examples ```cli diff --git a/commands/zunion.md b/commands/zunion.md index d77d81f47c..f85bfd821a 100644 --- a/commands/zunion.md +++ b/commands/zunion.md @@ -3,11 +3,6 @@ sorted set, it is returned to the client. For a description of the `WEIGHTS` and `AGGREGATE` options, see `ZUNIONSTORE`. -@return - -@array-reply: the result of union (optionally with their scores, in case -the `WITHSCORES` option is given). - @examples ```cli diff --git a/commands/zunionstore.md b/commands/zunionstore.md index 49e2d506e9..efa2fbba55 100644 --- a/commands/zunionstore.md +++ b/commands/zunionstore.md @@ -21,11 +21,6 @@ the minimum or maximum score of an element across the inputs where it exists. If `destination` already exists, it is overwritten. -@return - -@integer-reply: the number of elements in the resulting sorted set at -`destination`. - @examples ```cli diff --git a/resp2_replies.json b/resp2_replies.json new file mode 100644 index 0000000000..cf187b833e --- /dev/null +++ b/resp2_replies.json @@ -0,0 +1,1318 @@ +{ + "ACL": [], + "ACL CAT": [ + "One of the following:", + "* [Array reply](/docs/reference/protocol-spec#arrays): an array of [Bulk string reply](/docs/reference/protocol-spec#bulk-strings) elements representing ACL categories or commands in a given category.", + "* [Simple error reply](/docs/reference/protocol-spec#simple-errors): the command returns an error if an invalid category name is given." + ], + "ACL DELUSER": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of users that were deleted. This number will not always match the number of arguments since certain users may not exist." + ], + "ACL DRYRUN": [ + "Any of the following:", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` on success.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): an error describing why the user can't execute the command." + ], + "ACL GENPASS": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): pseudorandom data. By default it contains 64 bytes, representing 256 bits of data. If `bits` was given, the output string length is the number of specified bits (rounded to the next multiple of 4) divided by 4." + ], + "ACL GETUSER": [ + "One of the following:", + "* [Array reply](/docs/reference/protocol-spec#arrays): a list of ACL rule definitions for the user.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if user does not exist." + ], + "ACL HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of subcommands and their descriptions." + ], + "ACL LIST": [ + "[Array reply](/docs/reference/protocol-spec#arrays): an array of [Bulk string reply](/docs/reference/protocol-spec#bulk-strings) elements." + ], + "ACL LOG": [ + "When called to show security events:", + "* [Array reply](/docs/reference/protocol-spec#arrays): an array of [Bulk string reply](/docs/reference/protocol-spec#bulk-strings) elements representing ACL security events.", + "When called with `RESET`:", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the security log was cleared." + ], + "ACL SAVE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`.", + "The command may fail with an error for several reasons: if the file cannot be written or if the server is not configured to use an external ACL file." + ], + "ACL SETUSER": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`.", + "If the rules contain errors, the error is returned." + ], + "ACL USERS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): list of existing ACL users." + ], + "ACL WHOAMI": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the username of the current connection." + ], + "ACL-LOAD": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` on success.", + "", + "The command may fail with an error for several reasons: if the file is not readable, if there is an error inside the file, and in such cases, the error will be reported to the user in the error.", + "Finally, the command will fail if the server is not configured to use an external ACL file." + ], + "APPEND": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the length of the string after the append operation." + ], + "ASKING": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "AUTH": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`, or an error if the password, or username/password pair, is invalid." + ], + "BGREWRITEAOF": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): a simple string reply indicating that the rewriting started or is about to start ASAP when the call is executed with success.", + "", + "The command may reply with an error in certain cases, as documented above." + ], + "BGSAVE": [ + "One of the following:", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `Background saving started`.", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `Background saving scheduled`." + ], + "BITCOUNT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of bits set to 1." + ], + "BITFIELD": [ + "One of the following:", + "* [Array reply](/docs/reference/protocol-spec#arrays): each entry being the corresponding result of the sub-command given at the same position.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if OVERFLOW FAIL was given and overflows or underflows are detected." + ], + "BITFIELD_RO": [ + "[Array reply](/docs/reference/protocol-spec#arrays): each entry being the corresponding result of the sub-command given at the same position." + ], + "BITOP": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the size of the string stored in the destination key is equal to the size of the longest input string." + ], + "BITPOS": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): the position of the first bit set to 1 or 0 according to the request", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-1`. In case the `bit` argument is 1 and the string is empty or composed of just zero bytes", + "", + "If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is returned.", + "", + "If we look for clear bits (the bit argument is 0) and the string only contains bits set to 1, the function returns the first bit not part of the string on the right. So if the string is three bytes set to the value `0xff` the command `BITPOS key 0` will return 24, since up to bit 23 all the bits are 1.", + "", + "The function considers the right of the string as padded with zeros if you look for clear bits and specify no range or the _start_ argument **only**.", + "", + "However, this behavior changes if you are looking for clear bits and specify a range with both _start_ and _end_.", + "If a clear bit isn't found in the specified range, the function returns -1 as the user specified a clear range and there are no 0 bits in that range." + ], + "BLMOVE": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the element being popped from the _source_ and pushed to the _destination_.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): the operation timed-out" + ], + "BLMPOP": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): when no element could be popped and the _timeout_ is reached.", + "* [Array reply](/docs/reference/protocol-spec#arrays): a two-element array with the first element being the name of the key from which elements were popped, and the second element being an array of the popped elements." + ], + "BLPOP": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): no element could be popped and the timeout expired", + "* [Array reply](/docs/reference/protocol-spec#arrays): the key from which the element was popped and the value of the popped element." + ], + "BRPOP": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): no element could be popped and the timeout expired.", + "* [Array reply](/docs/reference/protocol-spec#arrays): the key from which the element was popped and the value of the popped element" + ], + "BRPOPLPUSH": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the element being popped from _source_ and pushed to _destination_.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): the timeout is reached." + ], + "BZMPOP": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): when no element could be popped.", + "* [Array reply](/docs/reference/protocol-spec#arrays): a two-element array with the first element being the name of the key from which elements were popped, and the second element is an array of the popped elements. Every entry in the elements array is also an array that contains the member and its score." + ], + "BZPOPMAX": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): when no element could be popped and the _timeout_ expired.", + "* [Array reply](/docs/reference/protocol-spec#arrays): the keyname, popped member, and its score." + ], + "BZPOPMIN": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): when no element could be popped and the _timeout_ expired.", + "* [Array reply](/docs/reference/protocol-spec#arrays): the keyname, popped member, and its score." + ], + "CLIENT": [], + "CLIENT CACHING": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` or an error if the argument is not \"yes\" or \"no\"." + ], + "CLIENT GETNAME": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the connection name of the current connection.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): the connection name was not set." + ], + "CLIENT GETREDIR": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` when not redirecting notifications to any client.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-1` if client tracking is not enabled.", + "* [Integer reply](/docs/reference/protocol-spec#integers): the ID of the client to which notification are being redirected." + ], + "CLIENT HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of subcommands and their descriptions." + ], + "CLIENT ID": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the ID of the client." + ], + "CLIENT INFO": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): a unique string for the current client, as described at the `CLIENT LIST` page." + ], + "CLIENT KILL": [ + "One of the following:", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` when called in 3 argument format and the connection has been closed.", + "* [Integer reply](/docs/reference/protocol-spec#integers): when called in filter/value format, the number of clients killed." + ], + "CLIENT LIST": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): information and statistics about client connections." + ], + "CLIENT NO-EVICT": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "CLIENT NO-TOUCH": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "CLIENT PAUSE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` or an error if the timeout is invalid." + ], + "CLIENT REPLY": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` when called with `ON`. When called with either `OFF` or `SKIP` sub-commands, no reply is made." + ], + "CLIENT SETINFO": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the attribute name was successfully set." + ], + "CLIENT SETNAME": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the connection name was successfully set." + ], + "CLIENT TRACKING": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the connection was successfully put in tracking mode or if the tracking mode was successfully disabled. Otherwise, an error is returned." + ], + "CLIENT TRACKINGINFO": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of tracking information sections and their respective values." + ], + "CLIENT UNBLOCK": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the client was unblocked successfully.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the client wasn't unblocked." + ], + "CLIENT UNPAUSE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "CLUSTER": [], + "CLUSTER ADDSLOTS": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER ADDSLOTSRANGE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER BUMPEPOCH": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): `BUMPED` if the epoch was incremented.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): `STILL` if the node already has the greatest configured epoch in the cluster." + ], + "CLUSTER COUNT-FAILURE-REPORTS": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of active failure reports for the node." + ], + "CLUSTER COUNTKEYSINSLOT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): The number of keys in the specified hash slot, or an error if the hash slot is invalid." + ], + "CLUSTER DELSLOTS": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER DELSLOTSRANGE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER FAILOVER": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was accepted and a manual failover is going to be attempted. An error if the operation cannot be executed, for example if the client is connected to a node that is already a master." + ], + "CLUSTER FLUSHSLOTS": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`" + ], + "CLUSTER FORGET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was executed successfully. Otherwise an error is returned." + ], + "CLUSTER GETKEYSINSLOT": [ + "[Array reply](/docs/reference/protocol-spec#arrays): an array with up to count elements." + ], + "CLUSTER HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of subcommands and their descriptions." + ], + "CLUSTER INFO": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): A map between named fields and values in the form of `:` lines separated by newlines composed by the two bytes `CRLF`." + ], + "CLUSTER KEYSLOT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): The hash slot number for the specified key" + ], + "CLUSTER LINKS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): an array of maps where each map contains various attributes and their values of a cluster link." + ], + "CLUSTER MEET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. If the address or port specified are invalid an error is returned." + ], + "CLUSTER MYID": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the node ID." + ], + "CLUSTER MYSHARDID": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the node's shard ID." + ], + "CLUSTER NODES": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the serialized cluster configuration." + ], + "CLUSTER REPLICAS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of replica nodes replicating from the specified master node provided in the same format used by `CLUSTER NODES`." + ], + "CLUSTER REPLICATE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER RESET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER SAVECONFIG": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER SET-CONFIG-EPOCH": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER SETSLOT": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): all the sub-commands return `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER SHARDS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a nested list of a map of hash ranges and shard nodes describing individual shards." + ], + "CLUSTER SLAVES": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of replica nodes replicating from the specified master node provided in the same format used by `CLUSTER NODES`." + ], + "CLUSTER SLOTS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): nested list of slot ranges with networking information." + ], + "COMMAND": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a nested list of command details. The order of the commands in the array is random." + ], + "COMMAND COUNT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of commands returned by `COMMAND`." + ], + "COMMAND DOCS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a map, as a flattened array, where each key is a command name, and each value is the documentary information." + ], + "COMMAND GETKEYS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): list of keys from the given command." + ], + "COMMAND GETKEYSANDFLAGS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of keys from the given command and their usage flags." + ], + "COMMAND HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "COMMAND INFO": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a nested list of command details." + ], + "COMMAND LIST": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of command names." + ], + "CONFIG": [], + "CONFIG GET": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of configuration parameters matching the provided arguments." + ], + "CONFIG HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "CONFIG RESETSTAT": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "CONFIG REWRITE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` when the configuration was rewritten properly. Otherwise an error is returned." + ], + "CONFIG SET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` when the configuration was set properly. Otherwise an error is returned." + ], + "COPY": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if _source_ was copied.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if _source_ was not copied." + ], + "DBSIZE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of keys in the currently-selected database." + ], + "DEBUG": [], + "DECR": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the value of the key after decrementing it." + ], + "DECRBY": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the value of the key after decrementing it." + ], + "DEL": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of keys that were removed." + ], + "DISCARD": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "DUMP": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): The serialized value of the key.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): the key does not exist." + ], + "ECHO": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the given string." + ], + "EVAL": [ + "The return value depends on the script that was executed." + ], + "EVALSHA": [ + "The return value depends on the script that was executed." + ], + "EVALSHA_RO": [ + "The return value depends on the script that was executed." + ], + "EVAL_RO": [ + "The return value depends on the script that was executed." + ], + "EXEC": [ + "One of the following:", + "* [Array reply](/docs/reference/protocol-spec#arrays): each element being the reply to each of the commands in the atomic transaction.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): the transaction was aborted because a `WATCH`ed key was touched." + ], + "EXISTS": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of keys that exist from those specified as arguments." + ], + "EXPIRE": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the timeout was not set; for example, the key doesn't exist, or the operation was skipped because of the provided arguments.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the timeout was set." + ], + "EXPIREAT": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the timeout was not set; for example, the key doesn't exist, or the operation was skipped because of the provided arguments.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the timeout was set." + ], + "EXPIRETIME": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): the expiration Unix timestamp in seconds.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-1` if the key exists but has no associated expiration time.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-2` if the key does not exist." + ], + "FAILOVER": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was accepted and a coordinated failover is in progress. An error if the operation cannot be executed." + ], + "FCALL": [ + "The return value depends on the function that was executed." + ], + "FCALL_RO": [ + "The return value depends on the function that was executed." + ], + "FLUSHALL": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "FLUSHDB": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "FUNCTION": [], + "FUNCTION DELETE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "FUNCTION DUMP": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the serialized payload" + ], + "FUNCTION FLUSH": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "FUNCTION HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions" + ], + "FUNCTION KILL": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "FUNCTION LIST": [ + "[Array reply](/docs/reference/protocol-spec#arrays): information about functions and libraries." + ], + "FUNCTION LOAD": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the library name that was loaded." + ], + "FUNCTION RESTORE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "FUNCTION STATS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): information about the function that's currently running and information about the available execution engines." + ], + "GEOADD": [ + "[Integer reply](/docs/reference/protocol-spec#integers): When used without optional arguments, the number of elements added to the sorted set (excluding score updates). If the CH option is specified, the number of elements that were changed (added or updated)." + ], + "GEODIST": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): one or both of the elements are missing.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): distance as a double (represented as a string) in the specified units." + ], + "GEOHASH": [ + "[Array reply](/docs/reference/protocol-spec#arrays): an array where each element is the Geohash corresponding to each member name passed as an argument to the command." + ], + "GEOPOS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): An array where each element is a two elements array representing longitude and latitude (x,y) of each member name passed as argument to the command. Non-existing elements are reported as [Nil reply](/docs/reference/protocol-spec#bulk-strings) elements of the array." + ], + "GEORADIUS": [ + "One of the following:", + "* If no `WITH*` option is specified, an [Array reply](/docs/reference/protocol-spec#arrays) of matched member names", + "* If `WITHCOORD`, `WITHDIST`, or `WITHHASH` options are specified, the command returns an [Array reply](/docs/reference/protocol-spec#arrays) of arrays, where each sub-array represents a single item:", + " 1. The distance from the center as a floating point number, in the same unit specified in the radius.", + " 1. The Geohash integer.", + " 1. The coordinates as a two items x,y array (longitude,latitude).", + "", + "For example, the command `GEORADIUS Sicily 15 37 200 km WITHCOORD WITHDIST` will return each item in the following way:", + "", + "`[\"Palermo\",\"190.4424\",[\"13.361389338970184\",\"38.115556395496299\"]]`" + ], + "GEORADIUSBYMEMBER": [ + "One of the following:", + "* If no `WITH*` option is specified, an [Array reply](/docs/reference/protocol-spec#arrays) of matched member names", + "* If `WITHCOORD`, `WITHDIST`, or `WITHHASH` options are specified, the command returns an [Array reply](/docs/reference/protocol-spec#arrays) of arrays, where each sub-array represents a single item:", + " * The distance from the center as a floating point number, in the same unit specified in the radius.", + " * The Geohash integer.", + " * The coordinates as a two items x,y array (longitude,latitude)." + ], + "GEORADIUSBYMEMBER_RO": [ + "One of the following:", + "* If no `WITH*` option is specified, an [Array reply](/docs/reference/protocol-spec#arrays) of matched member names", + "* If `WITHCOORD`, `WITHDIST`, or `WITHHASH` options are specified, the command returns an [Array reply](/docs/reference/protocol-spec#arrays) of arrays, where each sub-array represents a single item:", + " * The distance from the center as a floating point number, in the same unit specified in the radius.", + " * The Geohash integer.", + " * The coordinates as a two items x,y array (longitude,latitude)." + ], + "GEORADIUS_RO": [ + "One of the following:", + "* If no `WITH*` option is specified, an [Array reply](/docs/reference/protocol-spec#arrays) of matched member names", + "* If `WITHCOORD`, `WITHDIST`, or `WITHHASH` options are specified, the command returns an [Array reply](/docs/reference/protocol-spec#arrays) of arrays, where each sub-array represents a single item:", + " * The distance from the center as a floating point number, in the same unit specified in the radius.", + " * The Geohash integer.", + " * The coordinates as a two items x,y array (longitude,latitude)." + ], + "GEOSEARCH": [ + "One of the following:", + "* If no `WITH*` option is specified, an [Array reply](/docs/reference/protocol-spec#arrays) of matched member names", + "* If `WITHCOORD`, `WITHDIST`, or `WITHHASH` options are specified, the command returns an [Array reply](/docs/reference/protocol-spec#arrays) of arrays, where each sub-array represents a single item:", + " * The distance from the center as a floating point number, in the same unit specified in the radius.", + " * The Geohash integer.", + " * The coordinates as a two items x,y array (longitude,latitude)." + ], + "GEOSEARCHSTORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of elements in the resulting set" + ], + "GET": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the value of the key.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the key does not exist." + ], + "GETBIT": [ + "The bit value stored at _offset_, one of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0`.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1`." + ], + "GETDEL": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the value of the key.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the key does not exist or if the key's value type is not a string." + ], + "GETEX": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the value of `key`", + "[Nil reply](/docs/reference/protocol-spec#bulk-strings): if `key` does not exist." + ], + "GETRANGE": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): The substring of the string value stored at key, determined by the offsets start and end (both are inclusive)." + ], + "GETSET": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the old value stored at the key.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the key does not exist." + ], + "HDEL": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of fields that were removed from the hash, excluding any specified but non-existing fields." + ], + "HELLO": [ + "[Map reply](/docs/reference/protocol-spec#maps): a list of server properties.", + "[Simple error reply](/docs/reference/protocol-spec#simple-errors): if the `protover` requested does not exist." + ], + "HEXISTS": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the hash does not contain the field, or the key does not exist.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the hash contains the field." + ], + "HGET": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): The value associated with the field.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): If the field is not present in the hash or key does not exist." + ], + "HGETALL": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of fields and their values stored in the hash, or an empty list when key does not exist." + ], + "HINCRBY": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the value of the field after the increment operation." + ], + "HINCRBYFLOAT": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the value of the field after the increment operation." + ], + "HKEYS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of fields in the hash, or an empty list when the key does not exist" + ], + "HLEN": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of fields in the hash, or 0 when the key does not exist." + ], + "HMGET": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of values associated with the given fields, in the same order as they are requested." + ], + "HMSET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "HRANDFIELD": [ + "Any of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the key doesn't exist", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): a single, randomly selected field when the `count` option is not used", + "* [Array reply](/docs/reference/protocol-spec#arrays): a list containing `count` fields when the `count` option is used, or an empty array if the key does not exists.", + "* [Array reply](/docs/reference/protocol-spec#arrays): a list of fields and their values when `count` and `WITHVALUES` were both used." + ], + "HSCAN": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a two-element array.", + "* The first element is a [Bulk string reply](/docs/reference/protocol-spec#bulk-strings) that represents an unsigned 64-bit number, the cursor.", + "* The second element is an [Array reply](/docs/reference/protocol-spec#arrays) of field/value pairs that were scanned." + ], + "HSET": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of fields that were added." + ], + "HSETNX": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the field already exists in the hash and no operation was performed.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the field is a new field in the hash and the value was set." + ], + "HSTRLEN": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the string length of the value associated with the _field_, or zero when the _field_ isn't present in the hash or the _key_ doesn't exist at all." + ], + "HVALS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of values in the hash, or an empty list when the key does not exist" + ], + "INCR": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the value of the key after the increment." + ], + "INCRBY": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the value of the key after the increment." + ], + "INCRBYFLOAT": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the value of the key after the increment." + ], + "INFO": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): a map of info fields, one field per line in the form of : where the value can be a comma separated map like =. Also contains section header lines starting with `#` and blank lines.", + "", + "Lines can contain a section name (starting with a # character) or a property. All the properties are in the form of `field:value` terminated by `\r\n`." + ], + "KEYS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of keys matching _pattern_." + ], + "LASTSAVE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): UNIX TIME of the last DB save executed with success." + ], + "LATENCY": [], + "LATENCY DOCTOR": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): a human readable latency analysis report." + ], + "LATENCY GRAPH": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): Latency graph" + ], + "LATENCY HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "LATENCY HISTOGRAM": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a map where each key is a command name, and each value is a map with the total calls, and an inner map of the histogram time buckets." + ], + "LATENCY HISTORY": [ + "[Array reply](/docs/reference/protocol-spec#arrays): an array where each element is a two elements array representing the timestamp and the latency of the event." + ], + "LATENCY LATEST": [ + "[Array reply](/docs/reference/protocol-spec#arrays): an array where each element is a four elements array representing the event's name, timestamp, latest and all-time latency measurements." + ], + "LATENCY RESET": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of event time series that were reset." + ], + "LCS": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the longest common subsequence.", + "* [Integer reply](/docs/reference/protocol-spec#integers): the length of the longest common subsequence when _LEN_ is given.", + "* [Array reply](/docs/reference/protocol-spec#arrays): an array with the LCS length and all the ranges in both the strings when _IDX_ is given." + ], + "LINDEX": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): when _index_ is out of range.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the requested element." + ], + "LINSERT": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): the list length after a successful insert operation.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` when the key doesn't exist.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-1` when the pivot wasn't found." + ], + "LLEN": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the length of the list." + ], + "LMOVE": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the element being popped and pushed." + ], + "LMPOP": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if no element could be popped.", + "* [Array reply](/docs/reference/protocol-spec#arrays): a two-element array with the first element being the name of the key from which elements were popped and the second element being an array of elements." + ], + "LOLWUT": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): a string containing generative computer art and the Redis version." + ], + "LPOP": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the key does not exist.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): when called without the _count_ argument, the value of the first element.", + "* [Array reply](/docs/reference/protocol-spec#arrays): when called with the _count_ argument, a list of popped elements." + ], + "LPOS": [ + "Any of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if there is no matching element.", + "* [Integer reply](/docs/reference/protocol-spec#integers): an integer representing the matching element.", + "* [Array reply](/docs/reference/protocol-spec#arrays): If the COUNT option is given, an array of integers representing the matching elements (or an empty array if there are no matches)." + ], + "LPUSH": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the length of the list after the push operation." + ], + "LPUSHX": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the length of the list after the push operation." + ], + "LRANGE": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of elements in the specified range, or an empty array if the key doesn't exist." + ], + "LREM": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of removed elements." + ], + "LSET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "LTRIM": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "MEMORY": [], + "MEMORY DOCTOR": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): a memory problems report." + ], + "MEMORY HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions" + ], + "MEMORY MALLOC-STATS": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the memory allocator's internal statistics report" + ], + "MEMORY PURGE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "MEMORY STATS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a nested list of memory usage metrics and their values." + ], + "MEMORY USAGE": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): the memory usage in bytes.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the key does not exist." + ], + "MGET": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of values at the specified keys." + ], + "MIGRATE": [ + "One of the following:", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` on success.", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `NOKEY` when no keys were found in the source instance." + ], + "MODULE": [], + "MODULE HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "MODULE LIST": [ + "[Array reply](/docs/reference/protocol-spec#arrays): list of loaded modules. Each element in the list represents a represents a module, and is in itself a list of property names and their values. The following properties is reported for each loaded module:", + "* name: the name of the module.", + "* ver: the version of the module." + ], + "MODULE LOAD": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the module was loaded." + ], + "MODULE LOADEX": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the module was loaded." + ], + "MODULE UNLOAD": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the module was unloaded." + ], + "MONITOR": [ + "**Non-standard return value**. Dumps the received commands in an infinite flow." + ], + "MOVE": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if _key_ was moved.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if _key_ wasn't moved." + ], + "MSET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): always `OK` because `MSET` can't fail." + ], + "MSETNX": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if no key was set (at least one key already existed).", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if all the keys were set." + ], + "MULTI": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "OBJECT": [], + "OBJECT ENCODING": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the key doesn't exist.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the encoding of the object." + ], + "OBJECT FREQ": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the counter's value." + ], + "OBJECT HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions" + ], + "OBJECT IDLETIME": [ + "One of the following:", + "[Integer reply](/docs/reference/protocol-spec#integers): the idle time in seconds.", + "[Nil reply](/docs/reference/protocol-spec#bulk-strings): if _key_ doesn't exist." + ], + "OBJECT REFCOUNT": [ + "One of the following:", + "[Integer reply](/docs/reference/protocol-spec#integers): the number of references.", + "[Nil reply](/docs/reference/protocol-spec#bulk-strings): if _key_ doesn't exist." + ], + "PERSIST": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if _key_ does not exist or does not have an associated timeout.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the timeout has been removed." + ], + "PEXPIRE": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0`if the timeout was not set. For example, if the key doesn't exist, or the operation skipped because of the provided arguments.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the timeout was set." + ], + "PEXPIREAT": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the timeout was set.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the timeout was not set. For example, if the key doesn't exist, or the operation was skipped due to the provided arguments." + ], + "PEXPIRETIME": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): Expiration Unix timestamp in milliseconds.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-1` if the key exists but has no associated expiration time.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-2` if the key does not exist." + ], + "PFADD": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if at least one HyperLogLog internal register was altered.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if no HyperLogLog internal registers were altered." + ], + "PFCOUNT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the approximated number of unique elements observed via `PFADD`." + ], + "PFDEBUG": [], + "PFMERGE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "PFSELFTEST": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "PING": [ + "Any of the following:", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `PONG` when no argument is provided.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the provided argument." + ], + "PSETEX": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "PSUBSCRIBE": [ + "When successful, this command doesn't return anything. Instead, for each pattern, one message with the first element being the string `psubscribe` is pushed as a confirmation that the command succeeded." + ], + "PSYNC": [ + "**Non-standard return value**, a bulk transfer of the data followed by `PING` and write requests from the master." + ], + "PTTL": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): TTL in milliseconds.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-1` if the key exists but has no associated expiration.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-2` if the key does not exist." + ], + "PUBLISH": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of clients that received the message. Note that in a Redis Cluster, only clients that are connected to the same node as the publishing client are included in the count." + ], + "PUBSUB": [], + "PUBSUB CHANNELS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of active channels, optionally matching the specified pattern." + ], + "PUBSUB HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "PUBSUB NUMPAT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of patterns all the clients are subscribed to." + ], + "PUBSUB NUMSUB": [ + "[Array reply](/docs/reference/protocol-spec#arrays): the number of subscribers per channel, each even element (including the 0th) is channel name, each odd element is the number of subscribers" + ], + "PUBSUB SHARDCHANNELS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of active channels, optionally matching the specified pattern." + ], + "PUBSUB SHARDNUMSUB": [ + "[Array reply](/docs/reference/protocol-spec#arrays): the number of subscribers per shard channel, each even element (including the 0th) is channel name, each odd element is the number of subscribers." + ], + "PUNSUBSCRIBE": [ + "When successful, this command doesn't return anything. Instead, for each pattern, one message with the first element being the string `punsubscribe` is pushed as a confirmation that the command succeeded." + ], + "QUIT": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): OK." + ], + "RANDOMKEY": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): when the database is empty.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): a random key in database." + ], + "READONLY": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "READWRITE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "RENAME": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "RENAMENX": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if _key_ was renamed to _newkey_.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if _newkey_ already exists." + ], + "REPLCONF": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "REPLICAOF": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "RESET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `RESET`." + ], + "RESTORE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "RESTORE-ASKING": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "ROLE": [ + "[Array reply](/docs/reference/protocol-spec#arrays): where the first element is one of `master`, `slave`, or `sentinel`, and the additional elements are role-specific as illustrated above." + ], + "RPOP": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the key does not exist.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): when called without the _count_ argument, the value of the last element.", + "* [Array reply](/docs/reference/protocol-spec#arrays): when called with the _count_ argument, a list of popped elements." + ], + "RPOPLPUSH": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the element being popped and pushed.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the source list is empty." + ], + "RPUSH": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the length of the list after the push operation." + ], + "RPUSHX": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the length of the list after the push operation." + ], + "SADD": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of elements that were added to the set, not including all the elements already present in the set." + ], + "SAVE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SCAN": [ + "[Array reply](/docs/reference/protocol-spec#arrays): specifically, an array with two elements.", + "* The first element is a [Bulk string reply](/docs/reference/protocol-spec#bulk-strings) that represents an unsigned 64-bit number, the cursor.", + "* The second element is an [Array reply](/docs/reference/protocol-spec#arrays) with the names of scanned keys." + ], + "SCARD": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the cardinality (number of elements) of the set, or `0` if the key does not exist." + ], + "SCRIPT": [], + "SCRIPT DEBUG": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SCRIPT EXISTS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): an array of integers that correspond to the specified SHA1 digest arguments." + ], + "SCRIPT FLUSH": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SCRIPT HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "SCRIPT KILL": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SCRIPT LOAD": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the SHA1 digest of the script added into the script cache." + ], + "SDIFF": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list with members of the resulting set." + ], + "SDIFFSTORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of elements in the resulting set." + ], + "SELECT": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SET": [ + "Any of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): `GET` not given: Operation was aborted (conflict with one of the `XX`/`NX` options).", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`. `GET` not given: The key was set.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): `GET` given: The key didn't exist before the `SET`.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): `GET` given: The previous value of the key." + ], + "SETBIT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the original bit value stored at _offset_." + ], + "SETEX": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SETNX": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the key was not set.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the key was set." + ], + "SETRANGE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the length of the string after it was modified by the command." + ], + "SHUTDOWN": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if _ABORT_ was specified and shutdown was aborted. On successful shutdown, nothing is returned because the server quits and the connection is closed. On failure, an error is returned." + ], + "SINTER": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list with the members of the resulting set." + ], + "SINTERCARD": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of elements in the resulting intersection." + ], + "SINTERSTORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of elements in the resulting set." + ], + "SISMEMBER": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the element is not a member of the set, or when the key does not exist.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the element is a member of the set." + ], + "SLAVEOF": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SLOWLOG": [], + "SLOWLOG GET": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of slow log entries per the above format." + ], + "SLOWLOG HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "SLOWLOG LEN": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of entries in the slow log." + ], + "SLOWLOG RESET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SMEMBERS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): all members of the set." + ], + "SMISMEMBER": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list representing the membership of the given elements, in the same order as they are requested." + ], + "SMOVE": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the element is moved.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the element is not a member of _source_ and no operation was performed." + ], + "SORT": [ + "[Array reply](/docs/reference/protocol-spec#arrays): without passing the _STORE_ option, the command returns a list of sorted elements.", + "[Integer reply](/docs/reference/protocol-spec#integers): when the _STORE_ option is specified, the command returns the number of sorted elements in the destination list." + ], + "SORT_RO": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sorted elements." + ], + "SPOP": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the key does not exist.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): when called without the _count_ argument, the removed member.", + "* [Array reply](/docs/reference/protocol-spec#arrays): when called with the _count_ argument, a aist of the removed members." + ], + "SPUBLISH": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of clients that received the message. Note that in a Redis Cluster, only clients that are connected to the same node as the publishing client are included in the count" + ], + "SRANDMEMBER": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): without the additional _count_ argument, the command returns a randomly selected member, or a [Nil reply](/docs/reference/protocol-spec#bulk-strings) when _key_ doesn't exist.", + "* [Array reply](/docs/reference/protocol-spec#arrays): when the optional _count_ argument is passed, the command returns an array of members, or an empty array when _key_ doesn't exist." + ], + "SREM": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of members that were removed from the set, not including non existing members." + ], + "SSCAN": [ + "[Array reply](/docs/reference/protocol-spec#arrays): specifically, an array with two elements:", + "* The first element is a [Bulk string reply](/docs/reference/protocol-spec#bulk-strings) that represents an unsigned 64-bit number, the cursor.", + "* The second element is an [Array reply](/docs/reference/protocol-spec#arrays) with the names of scanned members." + ], + "SSUBSCRIBE": [ + "When successful, this command doesn't return anything. Instead, for each shard channel, one message with the first element being the string `ssubscribe` is pushed as a confirmation that the command succeeded. Note that this command can also return a -MOVED redirect." + ], + "STRLEN": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the length of the string stored at key, or 0 when the key does not exist." + ], + "SUBSCRIBE": [ + "When successful, this command doesn't return anything. Instead, for each channel, one message with the first element being the string `subscribe` is pushed as a confirmation that the command succeeded." + ], + "SUBSTR": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the substring of the string value stored at key, determined by the offsets start and end (both are inclusive)." + ], + "SUNION": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list with members of the resulting set." + ], + "SUNIONSTORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of elements in the resulting set." + ], + "SUNSUBSCRIBE": [ + "When successful, this command doesn't return anything. Instead, for each shard channel, one message with the first element being the string `sunsubscribe` is pushed as a confirmation that the command succeeded." + ], + "SWAPDB": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SYNC": [ + "**Non-standard return value**, a bulk transfer of the data followed by `PING` and write requests from the master." + ], + "TIME": [ + "[Array reply](/docs/reference/protocol-spec#arrays): specifically, a two-element array consisting of the Unix timestamp in seconds and the microseconds' count." + ], + "TOUCH": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of touched keys." + ], + "TTL": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): TTL in seconds.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-1` if the key exists but has no associated expiration.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-2` if the key does not exist." + ], + "TYPE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): the type of _key_, or `none` when _key_ doesn't exist." + ], + "UNLINK": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of keys that were unlinked." + ], + "UNSUBSCRIBE": [ + "When successful, this command doesn't return anything. Instead, for each channel, one message with the first element being the string `unsubscribe` is pushed as a confirmation that the command succeeded." + ], + "UNWATCH": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "WAIT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the command returns the number of replicas reached by all the writes performed in the context of the current connection." + ], + "WAITAOF": [ + "[Array reply](/docs/reference/protocol-spec#arrays): The command returns an array of two integers:", + "1. The first is the number of local Redises (0 or 1) that have fsynced to AOF all writes performed in the context of the current connection", + "2. The second is the number of replicas that have acknowledged doing the same." + ], + "WATCH": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "XACK": [ + "[Integer reply](/docs/reference/protocol-spec#integers): The command returns the number of messages successfully acknowledged. Certain message IDs may no longer be part of the PEL (for example because they have already been acknowledged), and XACK will not count them as successfully acknowledged." + ], + "XADD": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): The ID of the added entry. The ID is the one automatically generated if an asterisk (`*`) is passed as the _id_ argument, otherwise the command just returns the same ID specified by the user during insertion.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the NOMKSTREAM option is given and the key doesn't exist." + ], + "XAUTOCLAIM": [ + "[Array reply](/docs/reference/protocol-spec#arrays), specifically, an array with three elements:", + "1. A stream ID to be used as the _start_ argument for the next call to XAUTOCLAIM.", + "2. An [Array reply](/docs/reference/protocol-spec#arrays) containing all the successfully claimed messages in the same format as `XRANGE`.", + "3. An [Array reply](/docs/reference/protocol-spec#arrays) containing message IDs that no longer exist in the stream, and were deleted from the PEL in which they were found." + ], + "XCLAIM": [ + "Any of the following:", + "* [Array reply](/docs/reference/protocol-spec#arrays): when the _JUSTID_ option is specified, an array of IDs of messages successfully claimed.", + "* [Array reply](/docs/reference/protocol-spec#arrays): an array of stream entries, each of which contains an array of two elements, the entry ID and the entry data itself." + ], + "XDEL": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of entries that were deleted." + ], + "XGROUP": [], + "XGROUP CREATE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "XGROUP CREATECONSUMER": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of created consumers, either 0 or 1." + ], + "XGROUP DELCONSUMER": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of pending messages the consumer had before it was deleted." + ], + "XGROUP DESTROY": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of destroyed consumer groups, either 0 or 1." + ], + "XGROUP HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "XGROUP SETID": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "XINFO": [], + "XINFO CONSUMERS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of consumers and their attributes." + ], + "XINFO GROUPS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of consumer groups." + ], + "XINFO HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "XINFO STREAM": [ + "One of the following:", + "* [Array reply](/docs/reference/protocol-spec#arrays): when the _FULL_ argument is used, a list of information about a stream in summary form.", + "* [Array reply](/docs/reference/protocol-spec#arrays): when the _FULL_ argument is used, a list of information about a stream in extended form." + ], + "XLEN": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of entries of the stream at _key_." + ], + "XPENDING": [ + "* [Array reply](/docs/reference/protocol-spec#arrays): different data depending on the way XPENDING is called, as explained on this page." + ], + "XRANGE": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of stream entries with IDs matching the specified range." + ], + "XREAD": [ + "One of the following:", + "* [Array reply](/docs/reference/protocol-spec#arrays): an array where each element is an array composed of a two elements containing the key name and the entries reported for that key. The entries reported are full stream entries, having IDs and the list of all the fields and values. Field and values are guaranteed to be reported in the same order they were added by `XADD`.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the _BLOCK_ option is given and a timeout occurs, or if there is no stream that can be served." + ], + "XREADGROUP": [ + "One of the following:", + "* [Array reply](/docs/reference/protocol-spec#arrays): an array where each element is an array composed of a two elements containing the key name and the entries reported for that key. The entries reported are full stream entries, having IDs and the list of all the fields and values. Field and values are guaranteed to be reported in the same order they were added by `XADD`.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the _BLOCK_ option is given and a timeout occurs, or if there is no stream that can be served." + ], + "XREVRANGE": [ + "[Array reply](/docs/reference/protocol-spec#arrays): The command returns the entries with IDs matching the specified range. The returned entries are complete, which means that the ID and all the fields they are composed of are returned. Moreover, the entries are returned with their fields and values in the same order as `XADD` added them." + ], + "XSETID": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "XTRIM": [ + "[Integer reply](/docs/reference/protocol-spec#integers): The number of entries deleted from the stream." + ], + "ZADD": [ + "Any of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the operation was aborted because of a conflict with one of the _XX/NX/LT/GT_ options.", + "* [Integer reply](/docs/reference/protocol-spec#integers): the number of new members when the _CH_ option is not used.", + "* [Integer reply](/docs/reference/protocol-spec#integers): the number of new or updated members when the _CH_ option is used.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the updated score of the member when the _INCR_ option is used." + ], + "ZCARD": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the cardinality (number of members) of the sorted set, or 0 if the key doesn't exist." + ], + "ZCOUNT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of members in the specified score range." + ], + "ZDIFF": [ + "* [Array reply](/docs/reference/protocol-spec#arrays): the result of the difference including, optionally, scores when the _WITHSCORES_ option is used." + ], + "ZDIFFSTORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of members in the resulting sorted set at _destination_." + ], + "ZINCRBY": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the new score of _member_ as a double precision floating point number." + ], + "ZINTER": [ + "* [Array reply](/docs/reference/protocol-spec#arrays): the result of the intersection including, optionally, scores when the _WITHSCORES_ option is used." + ], + "ZINTERCARD": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of members in the resulting intersection." + ], + "ZINTERSTORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of members in the resulting sorted set at the _destination_." + ], + "ZLEXCOUNT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of members in the specified score range." + ], + "ZMPOP": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): when no element could be popped.", + "* [Array reply](/docs/reference/protocol-spec#arrays): A two-element array with the first element being the name of the key from which elements were popped, and the second element is an array of the popped elements. Every entry in the elements array is also an array that contains the member and its score." + ], + "ZMSCORE": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the member does not exist in the sorted set.", + "* [Array reply](/docs/reference/protocol-spec#arrays): a list of [Bulk string reply](/docs/reference/protocol-spec#bulk-strings) _member_ scores as double-precision floating point numbers." + ], + "ZPOPMAX": [ + "* [Array reply](/docs/reference/protocol-spec#arrays): a list of popped elements and scores." + ], + "ZPOPMIN": [ + "* [Array reply](/docs/reference/protocol-spec#arrays): a list of popped elements and scores." + ], + "ZRANDMEMBER": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): without the additional _count_ argument, the command returns a randomly selected member, or [Nil reply](/docs/reference/protocol-spec#bulk-strings) when _key_ doesn't exist.", + "[Array reply](/docs/reference/protocol-spec#arrays): when the additional _count_ argument is passed, the command returns an array of members, or an empty array when _key_ doesn't exist. If the _WITHSCORES_ modifier is used, the reply is a list of members and their scores from the sorted set." + ], + "ZRANGE": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of members in the specified range with, optionally, their scores when the _WITHSCORES_ option is given." + ], + "ZRANGEBYLEX": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of elements in the specified score range." + ], + "ZRANGEBYSCORE": [ + "* [Array reply](/docs/reference/protocol-spec#arrays): a list of the members with, optionally, their scores in the specified score range." + ], + "ZRANGESTORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of elements in the resulting sorted set." + ], + "ZRANK": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the key does not exist or the member does not exist in the sorted set.", + "* [Integer reply](/docs/reference/protocol-spec#integers): the rank of the member when _WITHSCORES_ is not used.", + "* [Array reply](/docs/reference/protocol-spec#arrays): the rank and score of the member when _WITHSCORES_ is used." + ], + "ZREM": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of members removed from the sorted set, not including non-existing members." + ], + "ZREMRANGEBYLEX": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of members removed." + ], + "ZREMRANGEBYRANK": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of members removed." + ], + "ZREMRANGEBYSCORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of members removed." + ], + "ZREVRANGE": [ + "* [Array reply](/docs/reference/protocol-spec#arrays): a list of members in the specified range, optionally with their scores if _WITHSCORE_ was used." + ], + "ZREVRANGEBYLEX": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of members in the specified score range." + ], + "ZREVRANGEBYSCORE": [ + "* [Array reply](/docs/reference/protocol-spec#arrays): a list of the members and, optionally, their scores in the specified score range." + ], + "ZREVRANK": [ + "One of the following:", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the key does not exist or the member does not exist in the sorted set.", + "* [Integer reply](/docs/reference/protocol-spec#integers): The rank of the member when _WITHSCORE_ is not used.", + "* [Array reply](/docs/reference/protocol-spec#arrays): The rank and score of the member when _WITHSCORE_ is used." + ], + "ZSCAN": [ + "[Array reply](/docs/reference/protocol-spec#arrays): cursor and scan response in array form." + ], + "ZSCORE": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the score of the member (a double-precision floating point number), represented as a string.", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if _member_ does not exist in the sorted set, or the key does not exist." + ], + "ZUNION": [ + "[Array reply](/docs/reference/protocol-spec#arrays): the result of the union with, optionally, their scores when _WITHSCORES_ is used." + ], + "ZUNIONSTORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of elements in the resulting sorted set." + ] +} \ No newline at end of file diff --git a/resp3_replies.json b/resp3_replies.json new file mode 100644 index 0000000000..cb8da478bc --- /dev/null +++ b/resp3_replies.json @@ -0,0 +1,1383 @@ +{ + "ACL": [], + "ACL CAT": [ + "One of the following:", + "* [Array reply](/docs/reference/protocol-spec#arrays): an array of [Bulk string reply](/docs/reference/protocol-spec#bulk-strings) elements representing ACL categories or commands in a given category.", + "* [Simple error reply](/docs/reference/protocol-spec#simple-errors): the command returns an error if an invalid category name is given." + ], + "ACL DELUSER": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of users that were deleted. This number will not always match the number of arguments since certain users may not exist." + ], + "ACL DRYRUN": [ + "Any of the following:", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` on success.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): an error describing why the user can't execute the command." + ], + "ACL GENPASS": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): pseudorandom data. By default it contains 64 bytes, representing 256 bits of data. If `bits` was given, the output string length is the number of specified bits (rounded to the next multiple of 4) divided by 4." + ], + "ACL GETUSER": [ + "One of the following:", + "* [Map reply](/docs/reference/protocol-spec#maps): a set of ACL rule definitions for the user", + "* [Null reply](/docs/reference/protocol-spec#nulls): if user does not exist." + ], + "ACL HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of subcommands and their descriptions." + ], + "ACL LIST": [ + "[Array reply](/docs/reference/protocol-spec#arrays): an array of [Bulk string reply](/docs/reference/protocol-spec#bulk-strings) elements." + ], + "ACL LOAD": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` on success.", + "", + "The command may fail with an error for several reasons: if the file is not readable, if there is an error inside the file, and in such cases, the error will be reported to the user in the error.", + "Finally, the command will fail if the server is not configured to use an external ACL file." + ], + "ACL LOG": [ + "When called to show security events:", + "* [Array reply](/docs/reference/protocol-spec#arrays): an array of [Bulk string reply](/docs/reference/protocol-spec#bulk-strings) elements representing ACL security events.", + "When called with `RESET`:", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the security log was cleared." + ], + "ACL SAVE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`.", + "The command may fail with an error for several reasons: if the file cannot be written or if the server is not configured to use an external ACL file." + ], + "ACL SETUSER": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`.", + "If the rules contain errors, the error is returned." + ], + "ACL USERS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): list of existing ACL users." + ], + "ACL WHOAMI": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the username of the current connection." + ], + "APPEND": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the length of the string after the append operation." + ], + "ASKING": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "AUTH": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`, or an error if the password, or username/password pair, is invalid." + ], + "BGREWRITEAOF": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): a simple string reply indicating that the rewriting started or is about to start ASAP when the call is executed with success.", + "", + "The command may reply with an error in certain cases, as documented above." + ], + "BGSAVE": [ + "One of the following:", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `Background saving started`.", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `Background saving scheduled`." + ], + "BITCOUNT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of bits set to 1." + ], + "BITFIELD": [ + "One of the following:", + "* [Array reply](/docs/reference/protocol-spec#arrays): each entry being the corresponding result of the sub-command given at the same position.", + "* [Null reply](/docs/reference/protocol-spec#nulls): if OVERFLOW FAIL was given and overflows or underflows are detected." + ], + "BITFIELD_RO": [ + "[Array reply](/docs/reference/protocol-spec#arrays): each entry being the corresponding result of the sub-command given at the same position." + ], + "BITOP": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the size of the string stored in the destination key is equal to the size of the longest input string." + ], + "BITPOS": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): the position of the first bit set to 1 or 0 according to the request", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-1`. In case the `bit` argument is 1 and the string is empty or composed of just zero bytes", + "", + "If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is returned.", + "", + "If we look for clear bits (the bit argument is 0) and the string only contains bits set to 1, the function returns the first bit not part of the string on the right. So if the string is three bytes set to the value `0xff` the command `BITPOS key 0` will return 24, since up to bit 23 all the bits are 1.", + "", + "The function considers the right of the string as padded with zeros if you look for clear bits and specify no range or the _start_ argument **only**.", + "", + "However, this behavior changes if you are looking for clear bits and specify a range with both _start_ and _end_.", + "If a clear bit isn't found in the specified range, the function returns -1 as the user specified a clear range and there are no 0 bits in that range." + ], + "BLMOVE": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the element being popped from the _source_ and pushed to the _destination_.", + "* [Null reply](/docs/reference/protocol-spec#nulls): the operation timed-out" + ], + "BLMPOP": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): when no element could be popped and the _timeout_ is reached.", + "* [Array reply](/docs/reference/protocol-spec#arrays): a two-element array with the first element being the name of the key from which elements were popped, and the second element being an array of the popped elements." + ], + "BLPOP": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): no element could be popped and the timeout expired", + "* [Array reply](/docs/reference/protocol-spec#arrays): the key from which the element was popped and the value of the popped element." + ], + "BRPOP": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): no element could be popped and the timeout expired.", + "* [Array reply](/docs/reference/protocol-spec#arrays): the key from which the element was popped and the value of the popped element" + ], + "BRPOPLPUSH": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the element being popped from _source_ and pushed to _destination_.", + "* [Null reply](/docs/reference/protocol-spec#nulls): the timeout is reached." + ], + "BZMPOP": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): when no element could be popped.", + "* [Array reply](/docs/reference/protocol-spec#arrays): a two-element array with the first element being the name of the key from which elements were popped, and the second element is an array of the popped elements. Every entry in the elements array is also an array that contains the member and its score." + ], + "BZPOPMAX": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): when no element could be popped and the _timeout_ expired.", + "* [Array reply](/docs/reference/protocol-spec#arrays): the keyname, popped member, and its score." + ], + "BZPOPMIN": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): when no element could be popped and the _timeout_ expired.", + "* [Array reply](/docs/reference/protocol-spec#arrays): the keyname, popped member, and its score." + ], + "CLIENT": [], + "CLIENT CACHING": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` or an error if the argument is not \"yes\" or \"no\"." + ], + "CLIENT GETNAME": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the connection name of the current connection.", + "* [Null reply](/docs/reference/protocol-spec#nulls): the connection name was not set." + ], + "CLIENT GETREDIR": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` when not redirecting notifications to any client.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-1` if client tracking is not enabled.", + "* [Integer reply](/docs/reference/protocol-spec#integers): the ID of the client to which notification are being redirected." + ], + "CLIENT HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of subcommands and their descriptions." + ], + "CLIENT ID": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the ID of the client." + ], + "CLIENT INFO": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): a unique string for the current client, as described at the `CLIENT LIST` page." + ], + "CLIENT KILL": [ + "One of the following:", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` when called in 3 argument format and the connection has been closed.", + "* [Integer reply](/docs/reference/protocol-spec#integers): when called in filter/value format, the number of clients killed." + ], + "CLIENT LIST": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): information and statistics about client connections." + ], + "CLIENT NO-EVICT": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "CLIENT NO-TOUCH": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "CLIENT PAUSE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` or an error if the timeout is invalid." + ], + "CLIENT REPLY": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` when called with `ON`. When called with either `OFF` or `SKIP` sub-commands, no reply is made." + ], + "CLIENT SETINFO": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the attribute name was successfully set." + ], + "CLIENT SETNAME": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the connection name was successfully set." + ], + "CLIENT TRACKING": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the connection was successfully put in tracking mode or if the tracking mode was successfully disabled. Otherwise, an error is returned." + ], + "CLIENT TRACKINGINFO": [ + "[Map reply](/docs/reference/protocol-spec#maps): a list of tracking information sections and their respective values." + ], + "CLIENT UNBLOCK": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the client was unblocked successfully.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the client wasn't unblocked." + ], + "CLIENT UNPAUSE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "CLUSTER": [], + "CLUSTER ADDSLOTS": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER ADDSLOTSRANGE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER BUMPEPOCH": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): `BUMPED` if the epoch was incremented.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): `STILL` if the node already has the greatest configured epoch in the cluster." + ], + "CLUSTER COUNT-FAILURE-REPORTS": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of active failure reports for the node." + ], + "CLUSTER COUNTKEYSINSLOT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): The number of keys in the specified hash slot, or an error if the hash slot is invalid." + ], + "CLUSTER DELSLOTS": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER DELSLOTSRANGE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER FAILOVER": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was accepted and a manual failover is going to be attempted. An error if the operation cannot be executed, for example if the client is connected to a node that is already a master." + ], + "CLUSTER FLUSHSLOTS": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "CLUSTER FORGET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was executed successfully. Otherwise an error is returned." + ], + "CLUSTER GETKEYSINSLOT": [ + "[Array reply](/docs/reference/protocol-spec#arrays): an array with up to count elements." + ], + "CLUSTER HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of subcommands and their descriptions." + ], + "CLUSTER INFO": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): A map between named fields and values in the form of : lines separated by newlines composed by the two bytes CRLF" + ], + "CLUSTER KEYSLOT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): The hash slot number for the specified key" + ], + "CLUSTER LINKS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): an array of [Map reply](/docs/reference/protocol-spec#maps) where each map contains various attributes and their values of a cluster link." + ], + "CLUSTER MEET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. If the address or port specified are invalid an error is returned." + ], + "CLUSTER MYID": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the node ID." + ], + "CLUSTER MYSHARDID": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the node's shard ID." + ], + "CLUSTER NODES": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the serialized cluster configuration." + ], + "CLUSTER REPLICAS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of replica nodes replicating from the specified master node provided in the same format used by `CLUSTER NODES`." + ], + "CLUSTER REPLICATE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER RESET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER SAVECONFIG": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER SET-CONFIG-EPOCH": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER SETSLOT": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): all the sub-commands return `OK` if the command was successful. Otherwise an error is returned." + ], + "CLUSTER SHARDS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a nested list of [Map reply](/docs/reference/protocol-spec#maps) of hash ranges and shard nodes describing individual shards." + ], + "CLUSTER SLAVES": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of replica nodes replicating from the specified master node provided in the same format used by `CLUSTER NODES`." + ], + "CLUSTER SLOTS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): nested list of slot ranges with networking information." + ], + "COMMAND": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a nested list of command details. The order of the commands in the array is random." + ], + "COMMAND COUNT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of commands returned by `COMMAND`." + ], + "COMMAND DOCS": [ + "[Map reply](/docs/reference/protocol-spec#maps): a map where each key is a command name, and each value is the documentary information." + ], + "COMMAND GETKEYS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of keys from the given command." + ], + "COMMAND GETKEYSANDFLAGS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of keys from the given command and their usage flags." + ], + "COMMAND HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "COMMAND INFO": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a nested list of command details." + ], + "COMMAND LIST": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of command names." + ], + "CONFIG": [], + "CONFIG GET": [ + "[Map reply](/docs/reference/protocol-spec#maps): a list of configuration parameters matching the provided arguments." + ], + "CONFIG HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "CONFIG RESETSTAT": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "CONFIG REWRITE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` when the configuration was rewritten properly. Otherwise an error is returned." + ], + "CONFIG SET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` when the configuration was set properly. Otherwise an error is returned." + ], + "COPY": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if _source_ was copied.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if _source_ was not copied." + ], + "DBSIZE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of keys in the currently-selected database." + ], + "DEBUG": [], + "DECR": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the value of the key after decrementing it." + ], + "DECRBY": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the value of the key after decrementing it." + ], + "DEL": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of keys that were removed." + ], + "DISCARD": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "DUMP": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the serialized value of the key.", + "* [Null reply](/docs/reference/protocol-spec#nulls): the key does not exist." + ], + "ECHO": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the given string." + ], + "EVAL": [ + "The return value depends on the script that was executed." + ], + "EVALSHA": [ + "The return value depends on the script that was executed." + ], + "EVALSHA_RO": [ + "The return value depends on the script that was executed." + ], + "EVAL_RO": [ + "The return value depends on the script that was executed." + ], + "EXEC": [ + "One of the following:", + "* [Array reply](/docs/reference/protocol-spec#arrays): each element being the reply to each of the commands in the atomic transaction.", + "* [Null reply](/docs/reference/protocol-spec#nulls): the transaction was aborted because a `WATCH`ed key was touched." + ], + "EXISTS": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of keys that exist from those specified as arguments." + ], + "EXPIRE": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the timeout was not set; for example, the key doesn't exist, or the operation was skipped because of the provided arguments.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the timeout was set." + ], + "EXPIREAT": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the timeout was not set; for example, the key doesn't exist, or the operation was skipped because of the provided arguments.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the timeout was set." + ], + "EXPIRETIME": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): the expiration Unix timestamp in seconds.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-1` if the key exists but has no associated expiration time.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-2` if the key does not exist." + ], + "FAILOVER": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the command was accepted and a coordinated failover is in progress. An error if the operation cannot be executed." + ], + "FCALL": [ + "The return value depends on the function that was executed." + ], + "FCALL_RO": [ + "The return value depends on the function that was executed." + ], + "FLUSHALL": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "FLUSHDB": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "FUNCTION": [], + "FUNCTION DELETE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "FUNCTION DUMP": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the serialized payload" + ], + "FUNCTION FLUSH": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "FUNCTION HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "FUNCTION KILL": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "FUNCTION LIST": [ + "[Array reply](/docs/reference/protocol-spec#arrays): information about functions and libraries." + ], + "FUNCTION LOAD": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the library name that was loaded." + ], + "FUNCTION RESTORE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "FUNCTION STATS": [ + "[Map reply](/docs/reference/protocol-spec#maps): information about the function that's currently running and information about the available execution engines." + ], + "GEOADD": [ + "[Integer reply](/docs/reference/protocol-spec#integers): When used without optional arguments, the number of elements added to the sorted set (excluding score updates). If the CH option is specified, the number of elements that were changed (added or updated)." + ], + "GEODIST": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): one or both of the elements are missing.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): distance as a double (represented as a string) in the specified units." + ], + "GEOHASH": [ + "[Array reply](/docs/reference/protocol-spec#arrays): An array where each element is the Geohash corresponding to each member name passed as an argument to the command." + ], + "GEOPOS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): An array where each element is a two elements array representing longitude and latitude (x,y) of each member name passed as argument to the command. Non-existing elements are reported as [Null reply](/docs/reference/protocol-spec#nulls) elements of the array." + ], + "GEORADIUS": [ + "One of the following:", + "* If no `WITH*` option is specified, an [Array reply](/docs/reference/protocol-spec#arrays) of matched member names", + "* If `WITHCOORD`, `WITHDIST`, or `WITHHASH` options are specified, the command returns an [Array reply](/docs/reference/protocol-spec#arrays) of arrays, where each sub-array represents a single item:", + " 1. The distance from the center as a floating point number, in the same unit specified in the radius.", + " 1. The Geohash integer.", + " 1. The coordinates as a two items x,y array (longitude,latitude).", + "", + "For example, the command `GEORADIUS Sicily 15 37 200 km WITHCOORD WITHDIST` will return each item in the following way:", + "", + "`[\"Palermo\",\"190.4424\",[\"13.361389338970184\",\"38.115556395496299\"]]`" + ], + "GEORADIUSBYMEMBER": [ + "One of the following:", + "* If no `WITH*` option is specified, an [Array reply](/docs/reference/protocol-spec#arrays) of matched member names", + "* If `WITHCOORD`, `WITHDIST`, or `WITHHASH` options are specified, the command returns an [Array reply](/docs/reference/protocol-spec#arrays) of arrays, where each sub-array represents a single item:", + " * The distance from the center as a floating point number, in the same unit specified in the radius.", + " * The Geohash integer.", + " * The coordinates as a two items x,y array (longitude,latitude)." + ], + "GEORADIUSBYMEMBER_RO": [ + "One of the following:", + "* If no `WITH*` option is specified, an [Array reply](/docs/reference/protocol-spec#arrays) of matched member names", + "* If `WITHCOORD`, `WITHDIST`, or `WITHHASH` options are specified, the command returns an [Array reply](/docs/reference/protocol-spec#arrays) of arrays, where each sub-array represents a single item:", + " * The distance from the center as a floating point number, in the same unit specified in the radius.", + " * The Geohash integer.", + " * The coordinates as a two items x,y array (longitude,latitude)." + ], + "GEORADIUS_RO": [ + "One of the following:", + "* If no `WITH*` option is specified, an [Array reply](/docs/reference/protocol-spec#arrays) of matched member names", + "* If `WITHCOORD`, `WITHDIST`, or `WITHHASH` options are specified, the command returns an [Array reply](/docs/reference/protocol-spec#arrays) of arrays, where each sub-array represents a single item:", + " * The distance from the center as a floating point number, in the same unit specified in the radius.", + " * The Geohash integer.", + " * The coordinates as a two items x,y array (longitude,latitude)." + ], + "GEOSEARCH": [ + "One of the following:", + "* If no `WITH*` option is specified, an [Array reply](/docs/reference/protocol-spec#arrays) of matched member names", + "* If `WITHCOORD`, `WITHDIST`, or `WITHHASH` options are specified, the command returns an [Array reply](/docs/reference/protocol-spec#arrays) of arrays, where each sub-array represents a single item:", + " * The distance from the center as a floating point number, in the same unit specified in the radius.", + " * The Geohash integer.", + " * The coordinates as a two items x,y array (longitude,latitude)." + ], + "GEOSEARCHSTORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of elements in the resulting set" + ], + "GET": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the value of the key.", + "* [Null reply](/docs/reference/protocol-spec#nulls): key does not exist." + ], + "GETBIT": [ + "The bit value stored at _offset_, one of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0`.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1`." + ], + "GETDEL": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the value of the key.", + "* [Null reply](/docs/reference/protocol-spec#nulls): if the key does not exist or if the key's value type is not a string." + ], + "GETEX": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the value of `key`", + "[Null reply](/docs/reference/protocol-spec#nulls): if `key` does not exist." + ], + "GETRANGE": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): The substring of the string value stored at key, determined by the offsets start and end (both are inclusive)." + ], + "GETSET": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the old value stored at the key.", + "* [Null reply](/docs/reference/protocol-spec#nulls): if the key does not exist." + ], + "HDEL": [ + "[Integer reply](/docs/reference/protocol-spec#integers): The number of fields that were removed from the hash, excluding any specified but non-existing fields." + ], + "HELLO": [ + "[Map reply](/docs/reference/protocol-spec#maps): a list of server properties.", + "[Simple error reply](/docs/reference/protocol-spec#simple-errors): if the `protover` requested does not exist." + ], + "HEXISTS": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the hash does not contain the field, or the key does not exist.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the hash contains the field." + ], + "HGET": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): The value associated with the field.", + "* [Null reply](/docs/reference/protocol-spec#nulls): If the field is not present in the hash or key does not exist." + ], + "HGETALL": [ + "[Map reply](/docs/reference/protocol-spec#maps): a map of fields and their values stored in the hash, or an empty list when key does not exist." + ], + "HINCRBY": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the value of the field after the increment operation." + ], + "HINCRBYFLOAT": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): The value of the field after the increment operation." + ], + "HKEYS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of fields in the hash, or an empty list when the key does not exist." + ], + "HLEN": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of the fields in the hash, or 0 when the key does not exist." + ], + "HMGET": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of values associated with the given fields, in the same order as they are requested." + ], + "HMSET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "HRANDFIELD": [ + "Any of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): if the key doesn't exist", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): a single, randomly selected field when the `count` option is not used", + "* [Array reply](/docs/reference/protocol-spec#arrays): a list containing `count` fields when the `count` option is used, or an empty array if the key does not exists.", + "* [Array reply](/docs/reference/protocol-spec#arrays): a list of fields and their values when `count` and `WITHVALUES` were both used." + ], + "HSCAN": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a two-element array.", + "* The first element is a [Bulk string reply](/docs/reference/protocol-spec#bulk-strings) that represents an unsigned 64-bit number, the cursor.", + "* The second element is an [Array reply](/docs/reference/protocol-spec#arrays) of field/value pairs that were scanned." + ], + "HSET": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of fields that were added." + ], + "HSETNX": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the field already exists in the hash and no operation was performed.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the field is a new field in the hash and the value was set." + ], + "HSTRLEN": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the string length of the value associated with the _field_, or zero when the _field_ isn't present in the hash or the _key_ doesn't exist at all." + ], + "HVALS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of values in the hash, or an empty list when the key does not exist." + ], + "INCR": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the value of the key after the increment." + ], + "INCRBY": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the value of the key after the increment." + ], + "INCRBYFLOAT": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the value of the key after the increment." + ], + "INFO": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): a map of info fields, one field per line in the form of : where the value can be a comma separated map like =. Also contains section header lines starting with `#` and blank lines.", + "", + "Lines can contain a section name (starting with a # character) or a property. All the properties are in the form of `field:value` terminated by `\r\n`." + ], + "KEYS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of keys matching _pattern_." + ], + "LASTSAVE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): UNIX TIME of the last DB save executed with success." + ], + "LATENCY": [], + "LATENCY DOCTOR": [ + "[Verbatim string reply](/docs/reference/protocol-spec#verbatim-strings): a human readable latency analysis report." + ], + "LATENCY GRAPH": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): Latency graph" + ], + "LATENCY HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "LATENCY HISTOGRAM": [ + "[Map reply](/docs/reference/protocol-spec#maps): a map where each key is a command name, and each value is a map with the total calls, and an inner map of the histogram time buckets." + ], + "LATENCY HISTORY": [ + "[Array reply](/docs/reference/protocol-spec#arrays): an array where each element is a two elements array representing the timestamp and the latency of the event." + ], + "LATENCY LATEST": [ + "[Array reply](/docs/reference/protocol-spec#arrays): an array where each element is a four elements array representing the event's name, timestamp, latest and all-time latency measurements." + ], + "LATENCY RESET": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of event time series that were reset." + ], + "LCS": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the longest common subsequence.", + "* [Integer reply](/docs/reference/protocol-spec#integers): the length of the longest common subsequence when _LEN_ is given.", + "* [Map reply](/docs/reference/protocol-spec#maps): a map with the LCS length and all the ranges in both the strings when _IDX_ is given." + ], + "LINDEX": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): when _index_ is out of range.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the requested element." + ], + "LINSERT": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): the list length after a successful insert operation.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` when the key doesn't exist.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-1` when the pivot wasn't found." + ], + "LLEN": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the length of the list." + ], + "LMOVE": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the element being popped and pushed." + ], + "LMPOP": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): if no element could be popped.", + "* [Array reply](/docs/reference/protocol-spec#arrays): a two-element array with the first element being the name of the key from which elements were popped and the second element being an array of elements." + ], + "LOLWUT": [ + "[Verbatim string reply](/docs/reference/protocol-spec#verbatim-strings): a string containing generative computer art and the Redis version." + ], + "LPOP": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): if the key does not exist.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): when called without the _count_ argument, the value of the first element.", + "* [Array reply](/docs/reference/protocol-spec#arrays): when called with the _count_ argument, a list of popped elements." + ], + "LPOS": [ + "Any of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): if there is no matching element.", + "* [Integer reply](/docs/reference/protocol-spec#integers): an integer representing the matching element.", + "* [Array reply](/docs/reference/protocol-spec#arrays): If the COUNT option is given, an array of integers representing the matching elements (or an empty array if there are no matches)." + ], + "LPUSH": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the length of the list after the push operation." + ], + "LPUSHX": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the length of the list after the push operation." + ], + "LRANGE": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of elements in the specified range, or an empty array if the key doesn't exist." + ], + "LREM": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of removed elements." + ], + "LSET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "LTRIM": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "MEMORY": [], + "MEMORY DOCTOR": [ + "[Verbatim string reply](/docs/reference/protocol-spec#verbatim-strings): a memory problems report." + ], + "MEMORY HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "MEMORY MALLOC-STATS": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): The memory allocator's internal statistics report." + ], + "MEMORY PURGE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "MEMORY STATS": [ + "[Map reply](/docs/reference/protocol-spec#maps): memory usage metrics and their values." + ], + "MEMORY USAGE": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): the memory usage in bytes.", + "* [Null reply](/docs/reference/protocol-spec#nulls): if the key does not exist." + ], + "MGET": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of values at the specified keys." + ], + "MIGRATE": [ + "One of the following:", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` on success.", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `NOKEY` when no keys were found in the source instance." + ], + "MODULE": [], + "MODULE HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions" + ], + "MODULE LIST": [ + "[Array reply](/docs/reference/protocol-spec#arrays): list of loaded modules. Each element in the list represents a represents a module, and is a [Map reply](/docs/reference/protocol-spec#maps) of property names and their values. The following properties is reported for each loaded module:", + "* name: the name of the module.", + "* ver: the version of the module." + ], + "MODULE LOAD": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the module was loaded." + ], + "MODULE LOADEX": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the module was loaded." + ], + "MODULE UNLOAD": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if the module was unloaded." + ], + "MONITOR": [ + "**Non-standard return value**. Dumps the received commands in an infinite flow." + ], + "MOVE": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if _key_ was moved.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if _key_ wasn't moved." + ], + "MSET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): always `OK` because `MSET` can't fail." + ], + "MSETNX": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if no key was set (at least one key already existed).", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if all the keys were set." + ], + "MULTI": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "OBJECT": [], + "OBJECT ENCODING": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): if the key doesn't exist.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the encoding of the object." + ], + "OBJECT FREQ": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the counter's value." + ], + "OBJECT HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "OBJECT IDLETIME": [ + "One of the following:", + "[Integer reply](/docs/reference/protocol-spec#integers): the idle time in seconds.", + "[Null reply](/docs/reference/protocol-spec#nulls): if _key_ doesn't exist." + ], + "OBJECT REFCOUNT": [ + "One of the following:", + "[Integer reply](/docs/reference/protocol-spec#integers): the number of references.", + "[Null reply](/docs/reference/protocol-spec#nulls): if _key_ doesn't exist." + ], + "PERSIST": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if _key_ does not exist or does not have an associated timeout.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the timeout has been removed." + ], + "PEXPIRE": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0`if the timeout was not set. For example, if the key doesn't exist, or the operation skipped because of the provided arguments.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the timeout was set." + ], + "PEXPIREAT": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the timeout was set.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the timeout was not set. For example, if the key doesn't exist, or the operation was skipped due to the provided arguments." + ], + "PEXPIRETIME": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): Expiration Unix timestamp in milliseconds.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-1` if the key exists but has no associated expiration time.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-2` if the key does not exist." + ], + "PFADD": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if at least one HyperLogLog internal register was altered.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if no HyperLogLog internal registers were altered." + ], + "PFCOUNT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the approximated number of unique elements observed via `PFADD`" + ], + "PFDEBUG": [], + "PFMERGE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "PFSELFTEST": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "PING": [ + "Any of the following:", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `PONG` when no argument is provided.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the provided argument." + ], + "PSETEX": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "PSUBSCRIBE": [ + "When successful, this command doesn't return anything. Instead, for each pattern, one message with the first element being the string `psubscribe` is pushed as a confirmation that the command succeeded." + ], + "PSYNC": [ + "**Non-standard return value**, a bulk transfer of the data followed by `PING` and write requests from the master." + ], + "PTTL": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): TTL in milliseconds.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-1` if the key exists but has no associated expiration.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-2` if the key does not exist." + ], + "PUBLISH": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of clients that received the message. Note that in a Redis Cluster, only clients that are connected to the same node as the publishing client are included in the count." + ], + "PUBSUB": [], + "PUBSUB CHANNELS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of active channels, optionally matching the specified pattern." + ], + "PUBSUB HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "PUBSUB NUMPAT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of patterns all the clients are subscribed to." + ], + "PUBSUB NUMSUB": [ + "[Array reply](/docs/reference/protocol-spec#arrays): the number of subscribers per channel, each even element (including the 0th) is channel name, each odd element is the number of subscribers" + ], + "PUBSUB SHARDCHANNELS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of active channels, optionally matching the specified pattern." + ], + "PUBSUB SHARDNUMSUB": [ + "[Array reply](/docs/reference/protocol-spec#arrays): the number of subscribers per shard channel, each even element (including the 0th) is channel name, each odd element is the number of subscribers." + ], + "PUNSUBSCRIBE": [ + "When successful, this command doesn't return anything. Instead, for each pattern, one message with the first element being the string `punsubscribe` is pushed as a confirmation that the command succeeded." + ], + "QUIT": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "RANDOMKEY": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): when the database is empty.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): a random key in the database." + ], + "READONLY": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "READWRITE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "RENAME": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "RENAMENX": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if _key_ was renamed to _newkey_.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if _newkey_ already exists." + ], + "REPLCONF": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "REPLICAOF": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "RESET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `RESET`." + ], + "RESTORE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "RESTORE-ASKING": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "ROLE": [ + "[Array reply](/docs/reference/protocol-spec#arrays): where the first element is one of `master`, `slave`, or `sentinel`, and the additional elements are role-specific as illustrated above." + ], + "RPOP": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): if the key does not exist.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): when called without the _count_ argument, the value of the last element.", + "* [Array reply](/docs/reference/protocol-spec#arrays): when called with the _count_ argument, a list of popped elements." + ], + "RPOPLPUSH": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the element being popped and pushed.", + "* [Null reply](/docs/reference/protocol-spec#nulls): if the source list is empty." + ], + "RPUSH": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the length of the list after the push operation." + ], + "RPUSHX": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the length of the list after the push operation." + ], + "SADD": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of elements that were added to the set, not including all the elements already present in the set." + ], + "SAVE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SCAN": [ + "[Array reply](/docs/reference/protocol-spec#arrays): specifically, an array with two elements.", + "* The first element is a [Bulk string reply](/docs/reference/protocol-spec#bulk-strings) that represents an unsigned 64-bit number, the cursor.", + "* The second element is an [Array reply](/docs/reference/protocol-spec#arrays) with the names of scanned keys." + ], + "SCARD": [ + "[Integer reply](/docs/reference/protocol-spec#integers): The cardinality (number of elements) of the set, or 0 if the key does not exist." + ], + "SCRIPT": [], + "SCRIPT DEBUG": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SCRIPT EXISTS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): an array of integers that correspond to the specified SHA1 digest arguments." + ], + "SCRIPT FLUSH": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SCRIPT HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "SCRIPT KILL": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SCRIPT LOAD": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the SHA1 digest of the script added into the script cache." + ], + "SDIFF": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list with the members of the resulting set." + ], + "SDIFFSTORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of elements in the resulting set." + ], + "SELECT": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SENTINEL CKQUORUM": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): Returns OK if the current Sentinel configuration is able to reach the quorum needed to failover a master, and the majority needed to authorize the failover." + ], + "SENTINEL CONFIG": [ + "One of the following:", + "* [Map reply](/docs/reference/protocol-spec#maps): When 'SENTINEL-CONFIG GET' is called, returns a map.", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`. When 'SENTINEL-CONFIG SET' is called, returns OK on success." + ], + "SENTINEL DEBUG": [ + "One of the following:", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`. The configuration update was successful.", + "* [Map reply](/docs/reference/protocol-spec#maps): List of configurable time parameters and their values (milliseconds)." + ], + "SENTINEL FAILOVER": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`. Force a fail over as if the master was not reachable, and without asking for agreement to other Sentinels." + ], + "SENTINEL FLUSHCONFIG": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`. Force Sentinel to rewrite its configuration on disk, including the current Sentinel state." + ], + "SENTINEL GET MASTER-ADDR-BY-NAME": [], + "SENTINEL HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): Helpful text about subcommands." + ], + "SENTINEL INFO CACHE": [ + "[Array reply](/docs/reference/protocol-spec#arrays): This is actually a map, the odd entries are a master name, and the even entries are the last cached INFO output from that master and all its replicas." + ], + "SENTINEL IS MASTER-DOWN-BY-ADDR": [], + "SENTINEL MASTER": [ + "[Map reply](/docs/reference/protocol-spec#maps): The state and info of the specified master." + ], + "SENTINEL MASTERS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): List of monitored Redis masters, and their state." + ], + "SENTINEL MONITOR": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SENTINEL MYID": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): Node ID of the sentinel instance." + ], + "SENTINEL PENDING SCRIPTS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): List of pending scripts." + ], + "SENTINEL REMOVE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SENTINEL REPLICAS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): List of replicas for this master, and their state." + ], + "SENTINEL RESET": [ + "[Integer reply](/docs/reference/protocol-spec#integers): The number of masters that were reset." + ], + "SENTINEL SENTINELS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): List of sentinel instances, and their state." + ], + "SENTINEL SET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SENTINEL SIMULATE FAILURE": [ + "One of the following:", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`. The simulated flag was set.", + "* [Array reply](/docs/reference/protocol-spec#arrays): Supported simulates flags. Returned in case `HELP` was used." + ], + "SENTINEL SLAVES": [ + "[Array reply](/docs/reference/protocol-spec#arrays): List of monitored replicas, and their state." + ], + "SET": [ + "Any of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): `GET` not given: Operation was aborted (conflict with one of the `XX`/`NX` options).", + "* [Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`. `GET` not given: The key was set.", + "* [Null reply](/docs/reference/protocol-spec#nulls): `GET` given: The key didn't exist before the `SET`.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): `GET` given: The previous value of the key." + ], + "SETBIT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the original bit value stored at _offset_." + ], + "SETEX": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SETNX": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the key was not set.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the key was set." + ], + "SETRANGE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the length of the string after it was modified by the command." + ], + "SHUTDOWN": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK` if _ABORT_ was specified and shutdown was aborted. On successful shutdown, nothing is returned because the server quits and the connection is closed. On failure, an error is returned." + ], + "SINTER": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list with the members of the resulting set." + ], + "SINTERCARD": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of the elements in the resulting intersection." + ], + "SINTERSTORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of the elements in the result set." + ], + "SISMEMBER": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the element is not a member of the set, or when the key does not exist.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the element is a member of the set." + ], + "SLAVEOF": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SLOWLOG": [], + "SLOWLOG GET": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of slow log entries per the above format." + ], + "SLOWLOG HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "SLOWLOG LEN": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of entries in the slow log." + ], + "SLOWLOG RESET": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SMEMBERS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): all members of the set." + ], + "SMISMEMBER": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list representing the membership of the given elements, in the same order as they are requested." + ], + "SMOVE": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): `1` if the element is moved.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `0` if the element is not a member of _source_ and no operation was performed." + ], + "SORT": [ + "[Array reply](/docs/reference/protocol-spec#arrays): without passing the _STORE_ option, the command returns a list of sorted elements.", + "[Integer reply](/docs/reference/protocol-spec#integers): when the _STORE_ option is specified, the command returns the number of sorted elements in the destination list." + ], + "SORT_RO": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sorted elements." + ], + "SPOP": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): if the key does not exist.", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): when called without the _count_ argument, the removed member.", + "* [Array reply](/docs/reference/protocol-spec#arrays): when called with the _count_ argument, a aist of the removed members." + ], + "SPUBLISH": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of clients that received the message. Note that in a Redis Cluster, only clients that are connected to the same node as the publishing client are included in the count" + ], + "SRANDMEMBER": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): without the additional _count_ argument, the command returns a randomly selected member, or a [Null reply](/docs/reference/protocol-spec#nulls) when _key_ doesn't exist.", + "* [Array reply](/docs/reference/protocol-spec#arrays): when the optional _count_ argument is passed, the command returns an array of members, or an empty array when _key_ doesn't exist." + ], + "SREM": [ + "[Integer reply](/docs/reference/protocol-spec#integers): Number of members that were removed from the set, not including non existing members." + ], + "SSCAN": [ + "[Array reply](/docs/reference/protocol-spec#arrays): specifically, an array with two elements:", + "* The first element is a [Bulk string reply](/docs/reference/protocol-spec#bulk-strings) that represents an unsigned 64-bit number, the cursor.", + "* The second element is an [Array reply](/docs/reference/protocol-spec#arrays) with the names of scanned members." + ], + "SSUBSCRIBE": [ + "When successful, this command doesn't return anything. Instead, for each shard channel, one message with the first element being the string 'ssubscribe' is pushed as a confirmation that the command succeeded. Note that this command can also return a -MOVED redirect." + ], + "STRLEN": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the length of the string stored at key, or 0 when the key does not exist." + ], + "SUBSCRIBE": [ + "When successful, this command doesn't return anything. Instead, for each channel, one message with the first element being the string `subscribe` is pushed as a confirmation that the command succeeded." + ], + "SUBSTR": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the substring of the string value stored at key, determined by the offsets start and end (both are inclusive)." + ], + "SUNION": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list with the members of the resulting set." + ], + "SUNIONSTORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): Number of the elements in the resulting set." + ], + "SUNSUBSCRIBE": [ + "When successful, this command doesn't return anything. Instead, for each shard channel, one message with the first element being the string `sunsubscribe` is pushed as a confirmation that the command succeeded." + ], + "SWAPDB": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "SYNC": [ + "**Non-standard return value**, a bulk transfer of the data followed by `PING` and write requests from the master." + ], + "TIME": [ + "[Array reply](/docs/reference/protocol-spec#arrays): specifically, a two-element array consisting of the Unix timestamp in seconds and the microseconds' count." + ], + "TOUCH": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of touched keys." + ], + "TTL": [ + "One of the following:", + "* [Integer reply](/docs/reference/protocol-spec#integers): TTL in seconds.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-1` if the key exists but has no associated expiration.", + "* [Integer reply](/docs/reference/protocol-spec#integers): `-2` if the key does not exist." + ], + "TYPE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): the type of _key_, or `none` when _key_ doesn't exist." + ], + "UNLINK": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of keys that were unlinked." + ], + "UNSUBSCRIBE": [ + "When successful, this command doesn't return anything. Instead, for each channel, one message with the first element being the string `unsubscribe` is pushed as a confirmation that the command succeeded." + ], + "UNWATCH": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "WAIT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of replicas reached by all the writes performed in the context of the current connection." + ], + "WAITAOF": [ + "[Array reply](/docs/reference/protocol-spec#arrays): The command returns an array of two integers:", + "1. The first is the number of local Redises (0 or 1) that have fsynced to AOF all writes performed in the context of the current connection", + "2. The second is the number of replicas that have acknowledged doing the same." + ], + "WATCH": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "XACK": [ + "[Integer reply](/docs/reference/protocol-spec#integers): The command returns the number of messages successfully acknowledged. Certain message IDs may no longer be part of the PEL (for example because they have already been acknowledged), and XACK will not count them as successfully acknowledged." + ], + "XADD": [ + "One of the following:", + "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): The ID of the added entry. The ID is the one automatically generated if an asterisk (`*`) is passed as the _id_ argument, otherwise the command just returns the same ID specified by the user during insertion.", + "* [Null reply](/docs/reference/protocol-spec#nulls): if the NOMKSTREAM option is given and the key doesn't exist." + ], + "XAUTOCLAIM": [ + "[Array reply](/docs/reference/protocol-spec#arrays), specifically, an array with three elements:", + "1. A stream ID to be used as the _start_ argument for the next call to XAUTOCLAIM.", + "2. An [Array reply](/docs/reference/protocol-spec#arrays) containing all the successfully claimed messages in the same format as `XRANGE`.", + "3. An [Array reply](/docs/reference/protocol-spec#arrays) containing message IDs that no longer exist in the stream, and were deleted from the PEL in which they were found." + ], + "XCLAIM": [ + "Any of the following:", + "* [Array reply](/docs/reference/protocol-spec#arrays): when the _JUSTID_ option is specified, an array of IDs of messages successfully claimed.", + "* [Array reply](/docs/reference/protocol-spec#arrays): an array of stream entries, each of which contains an array of two elements, the entry ID and the entry data itself." + ], + "XDEL": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of entries that were deleted." + ], + "XGROUP": [], + "XGROUP CREATE": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "XGROUP CREATECONSUMER": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of created consumers, either 0 or 1." + ], + "XGROUP DELCONSUMER": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of pending messages the consumer had before it was deleted." + ], + "XGROUP DESTROY": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of destroyed consumer groups, either 0 or 1." + ], + "XGROUP HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "XGROUP SETID": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "XINFO": [], + "XINFO CONSUMERS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of consumers and their attributes." + ], + "XINFO GROUPS": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of consumer groups." + ], + "XINFO HELP": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." + ], + "XINFO STREAM": [ + "One of the following:", + "* [Map reply](/docs/reference/protocol-spec#maps): when the _FULL_ argument was not given, a list of information about a stream in summary form.", + "* [Map reply](/docs/reference/protocol-spec#maps): when the _FULL_ argument was given, a list of information about a stream in extended form." + ], + "XLEN": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of entries of the stream at _key_." + ], + "XPENDING": [ + "* [Array reply](/docs/reference/protocol-spec#arrays): different data depending on the way XPENDING is called, as explained on this page." + ], + "XRANGE": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of stream entries with IDs matching the specified range." + ], + "XREAD": [ + "One of the following:", + "* [Map reply](/docs/reference/protocol-spec#maps): A map of key-value elements where each element is composed of the key name and the entries reported for that key. The entries reported are full stream entries, having IDs and the list of all the fields and values. Field and values are guaranteed to be reported in the same order they were added by `XADD`.", + "* [Null reply](/docs/reference/protocol-spec#nulls): if the _BLOCK_ option is given and a timeout occurs, or if there is no stream that can be served." + ], + "XREADGROUP": [ + "One of the following:", + "* [Map reply](/docs/reference/protocol-spec#maps): A map of key-value elements where each element is composed of the key name and the entries reported for that key. The entries reported are full stream entries, having IDs and the list of all the fields and values. Field and values are guaranteed to be reported in the same order they were added by `XADD`.", + "* [Null reply](/docs/reference/protocol-spec#nulls): if the _BLOCK_ option is given and a timeout occurs, or if there is no stream that can be served." + ], + "XREVRANGE": [ + "[Array reply](/docs/reference/protocol-spec#arrays): The command returns the entries with IDs matching the specified range. The returned entries are complete, which means that the ID and all the fields they are composed of are returned. Moreover, the entries are returned with their fields and values in the same order as `XADD` added them." + ], + "XSETID": [ + "[Simple string reply](/docs/reference/protocol-spec#simple-strings): `OK`." + ], + "XTRIM": [ + "[Integer reply](/docs/reference/protocol-spec#integers): The number of entries deleted from the stream." + ], + "ZADD": [ + "Any of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): if the operation was aborted because of a conflict with one of the _XX/NX/LT/GT_ options.", + "* [Integer reply](/docs/reference/protocol-spec#integers): the number of new members when the _CH_ option is not used.", + "* [Integer reply](/docs/reference/protocol-spec#integers): the number of new or updated members when the _CH_ option is used.", + "* [Double reply](/docs/reference/protocol-spec#doubles): the updated score of the member when the _INCR_ option is used." + ], + "ZCARD": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the cardinality (number of members) of the sorted set, or 0 if the key doesn't exist." + ], + "ZCOUNT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of members in the specified score range." + ], + "ZDIFF": [ + "* [Array reply](/docs/reference/protocol-spec#arrays): the result of the difference including, optionally, scores when the _WITHSCORES_ option is used." + ], + "ZDIFFSTORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of members in the resulting sorted set at _destination_." + ], + "ZINCRBY": [ + "[Double reply](/docs/reference/protocol-spec#doubles): the new score of _member_." + ], + "ZINTER": [ + "* [Array reply](/docs/reference/protocol-spec#arrays): the result of the intersection including, optionally, scores when the _WITHSCORES_ option is used." + ], + "ZINTERCARD": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of members in the resulting intersection." + ], + "ZINTERSTORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of members in the resulting sorted set at the _destination_." + ], + "ZLEXCOUNT": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of members in the specified score range." + ], + "ZMPOP": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): when no element could be popped.", + "* [Array reply](/docs/reference/protocol-spec#arrays): A two-element array with the first element being the name of the key from which elements were popped, and the second element is an array of the popped elements. Every entry in the elements array is also an array that contains the member and its score." + ], + "ZMSCORE": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): if the member does not exist in the sorted set.", + "* [Array reply](/docs/reference/protocol-spec#arrays): a list of [Double reply](/docs/reference/protocol-spec#doubles) _member_ scores as double-precision floating point numbers." + ], + "ZPOPMAX": [ + "* [Array reply](/docs/reference/protocol-spec#arrays): a list of popped elements and scores." + ], + "ZPOPMIN": [ + "* [Array reply](/docs/reference/protocol-spec#arrays): a list of popped elements and scores." + ], + "ZRANDMEMBER": [ + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): without the additional _count_ argument, the command returns a randomly selected member, or [Null reply](/docs/reference/protocol-spec#nulls) when _key_ doesn't exist.", + "[Array reply](/docs/reference/protocol-spec#arrays): when the additional _count_ argument is passed, the command returns an array of members, or an empty array when _key_ doesn't exist. If the _WITHSCORES_ modifier is used, the reply is a list of members and their scores from the sorted set." + ], + "ZRANGE": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of members in the specified range with, optionally, their scores when the _WITHSCORES_ option is given." + ], + "ZRANGEBYLEX": [ + "[Array reply](/docs/reference/protocol-spec#arrays): a list of elements in the specified score range." + ], + "ZRANGEBYSCORE": [ + "* [Array reply](/docs/reference/protocol-spec#arrays): a list of the members with, optionally, their scores in the specified score range." + ], + "ZRANGESTORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of elements in the resulting sorted set." + ], + "ZRANK": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): if the key does not exist or the member does not exist in the sorted set.", + "* [Integer reply](/docs/reference/protocol-spec#integers): the rank of the member when _WITHSCORES_ is not used.", + "* [Array reply](/docs/reference/protocol-spec#arrays): the rank and score of the member when _WITHSCORES_ is used." + ], + "ZREM": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of members removed from the sorted set, not including non-existing members." + ], + "ZREMRANGEBYLEX": [ + "[Integer reply](/docs/reference/protocol-spec#integers): Number of members removed." + ], + "ZREMRANGEBYRANK": [ + "[Integer reply](/docs/reference/protocol-spec#integers): Number of members removed." + ], + "ZREMRANGEBYSCORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): Number of members removed." + ], + "ZREVRANGE": [ + "* [Array reply](/docs/reference/protocol-spec#arrays): a list of members in the specified range, optionally with their scores if _WITHSCORE_ was used." + ], + "ZREVRANGEBYLEX": [ + "[Array reply](/docs/reference/protocol-spec#arrays): List of the elements in the specified score range." + ], + "ZREVRANGEBYSCORE": [ + "* [Array reply](/docs/reference/protocol-spec#arrays): a list of the members and, optionally, their scores in the specified score range." + ], + "ZREVRANK": [ + "One of the following:", + "* [Null reply](/docs/reference/protocol-spec#nulls): if the key does not exist or the member does not exist in the sorted set.", + "* [Integer reply](/docs/reference/protocol-spec#integers): The rank of the member when _WITHSCORE_ is not used.", + "* [Array reply](/docs/reference/protocol-spec#arrays): The rank and score of the member when _WITHSCORE_ is used." + ], + "ZSCAN": [ + "[Array reply](/docs/reference/protocol-spec#arrays): cursor and scan response in array form." + ], + "ZSCORE": [ + "One of the following:", + "* [Double reply](/docs/reference/protocol-spec#doubles): the score of the member (a double-precision floating point number).", + "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if _member_ does not exist in the sorted set, or the key does not exist." + ], + "ZUNION": [ + "[Array reply](/docs/reference/protocol-spec#arrays): the result of the union with, optionally, their scores when _WITHSCORES_ is used." + ], + "ZUNIONSTORE": [ + "[Integer reply](/docs/reference/protocol-spec#integers): the number of elements in the resulting sorted set." + ] +} \ No newline at end of file From 9ecb2d92ced0820269712da36ba866f644ac2983 Mon Sep 17 00:00:00 2001 From: ajatkj Date: Wed, 1 Nov 2023 19:51:38 +0530 Subject: [PATCH 294/377] Update install-redis-on-mac-os.md Fix link for "Installing Redis from Source." --- docs/install/install-redis/install-redis-on-mac-os.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install/install-redis/install-redis-on-mac-os.md b/docs/install/install-redis/install-redis-on-mac-os.md index 5f82311575..f2bd70cfab 100644 --- a/docs/install/install-redis/install-redis-on-mac-os.md +++ b/docs/install/install-redis/install-redis-on-mac-os.md @@ -7,7 +7,7 @@ aliases: - /docs/getting-started/installation/install-redis-on-mac-os --- -This guide shows you how to install Redis on macOS using Homebrew. Homebrew is the easiest way to install Redis on macOS. If you'd prefer to build Redis from the source files on macOS, see [Installing Redis from Source](/docs/install/install-redis-from-source). +This guide shows you how to install Redis on macOS using Homebrew. Homebrew is the easiest way to install Redis on macOS. If you'd prefer to build Redis from the source files on macOS, see [Installing Redis from Source](/docs/install/install-redis/install-redis-from-source). ## Prerequisites From 0374f59379f45cffaa1715a865c449df3f5b30b3 Mon Sep 17 00:00:00 2001 From: BharadwajDivate <56808783+BharadwajDivate@users.noreply.github.com> Date: Sun, 5 Nov 2023 14:25:10 +0530 Subject: [PATCH 295/377] Update install-redis-on-windows.md fixed a broken link to install on linux page --- docs/install/install-redis/install-redis-on-windows.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install/install-redis/install-redis-on-windows.md b/docs/install/install-redis/install-redis-on-windows.md index 6b5e6bd465..087f3ba119 100644 --- a/docs/install/install-redis/install-redis-on-windows.md +++ b/docs/install/install-redis/install-redis-on-windows.md @@ -17,7 +17,7 @@ Microsoft provides [detailed instructions for installing WSL](https://docs.micro ## Install Redis -Once you're running Ubuntu on Windows, you can follow the steps detailed at [Install on Ubuntu/Debian](/docs/install/install-redis-on-linux#install-on-ubuntu-debian) to install recent stable versions of Redis from the official `packages.redis.io` APT repository. +Once you're running Ubuntu on Windows, you can follow the steps detailed at [Install on Ubuntu/Debian](/docs/install/install-redis/install-redis-on-linux#install-on-ubuntu-debian) to install recent stable versions of Redis from the official `packages.redis.io` APT repository. Add the repository to the apt index, update it, and then install: {{< highlight bash >}} From d780e33f944071e00223df97aa4d37636d2e856e Mon Sep 17 00:00:00 2001 From: Elias Obeid Date: Tue, 7 Nov 2023 11:47:11 +0100 Subject: [PATCH 296/377] Update ZRANK WITHSCORE resp2 & resp3_replies.json --- resp2_replies.json | 6 +++--- resp3_replies.json | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/resp2_replies.json b/resp2_replies.json index cf187b833e..fb590709cc 100644 --- a/resp2_replies.json +++ b/resp2_replies.json @@ -1271,8 +1271,8 @@ "ZRANK": [ "One of the following:", "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the key does not exist or the member does not exist in the sorted set.", - "* [Integer reply](/docs/reference/protocol-spec#integers): the rank of the member when _WITHSCORES_ is not used.", - "* [Array reply](/docs/reference/protocol-spec#arrays): the rank and score of the member when _WITHSCORES_ is used." + "* [Integer reply](/docs/reference/protocol-spec#integers): the rank of the member when _WITHSCORE_ is not used.", + "* [Array reply](/docs/reference/protocol-spec#arrays): the rank and score of the member when _WITHSCORE_ is used." ], "ZREM": [ "[Integer reply](/docs/reference/protocol-spec#integers): the number of members removed from the sorted set, not including non-existing members." @@ -1315,4 +1315,4 @@ "ZUNIONSTORE": [ "[Integer reply](/docs/reference/protocol-spec#integers): the number of elements in the resulting sorted set." ] -} \ No newline at end of file +} diff --git a/resp3_replies.json b/resp3_replies.json index cb8da478bc..addd0867dc 100644 --- a/resp3_replies.json +++ b/resp3_replies.json @@ -1336,8 +1336,8 @@ "ZRANK": [ "One of the following:", "* [Null reply](/docs/reference/protocol-spec#nulls): if the key does not exist or the member does not exist in the sorted set.", - "* [Integer reply](/docs/reference/protocol-spec#integers): the rank of the member when _WITHSCORES_ is not used.", - "* [Array reply](/docs/reference/protocol-spec#arrays): the rank and score of the member when _WITHSCORES_ is used." + "* [Integer reply](/docs/reference/protocol-spec#integers): the rank of the member when _WITHSCORE_ is not used.", + "* [Array reply](/docs/reference/protocol-spec#arrays): the rank and score of the member when _WITHSCORE_ is used." ], "ZREM": [ "[Integer reply](/docs/reference/protocol-spec#integers): the number of members removed from the sorted set, not including non-existing members." @@ -1380,4 +1380,4 @@ "ZUNIONSTORE": [ "[Integer reply](/docs/reference/protocol-spec#integers): the number of elements in the resulting sorted set." ] -} \ No newline at end of file +} From 0dbba45128c2f072d42ef6e4e7969bd2ba89b5bf Mon Sep 17 00:00:00 2001 From: shayan javani <25373436+massivefermion@users.noreply.github.com> Date: Fri, 10 Nov 2023 19:45:27 +0330 Subject: [PATCH 297/377] Add radish, the gleam client (#2598) --- clients/gleam/github.com/massivefermion/radish.json | 8 ++++++++ languages.json | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 clients/gleam/github.com/massivefermion/radish.json diff --git a/clients/gleam/github.com/massivefermion/radish.json b/clients/gleam/github.com/massivefermion/radish.json new file mode 100644 index 0000000000..519ed4bf82 --- /dev/null +++ b/clients/gleam/github.com/massivefermion/radish.json @@ -0,0 +1,8 @@ +{ + "name": "Radish", + "description": "Simple and Fast Redis client written in and for Gleam", + "homepage": "https://hexdocs.pm/radish", + "twitter": [ + "massivefermion" + ] +} \ No newline at end of file diff --git a/languages.json b/languages.json index b201a3bbca..5d6dfda9ab 100644 --- a/languages.json +++ b/languages.json @@ -18,6 +18,7 @@ "Erlang": "erlang", "Fancy": "fancy", "gawk": "gawk", + "Gleam": "gleam", "GNU Prolog": "gnu-prolog", "Go": "go", "Haskell": "haskell", @@ -60,4 +61,4 @@ "VCL": "vcl", "Xojo": "xojo", "Zig": "zig" -} +} \ No newline at end of file From 852466779eba5de5672195e453a415f5d45fa5ec Mon Sep 17 00:00:00 2001 From: synix Date: Fri, 10 Nov 2023 10:54:53 -0600 Subject: [PATCH 298/377] Correction of examples for lists (#2530) --- docs/data-types/lists.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data-types/lists.md b/docs/data-types/lists.md index 46715c9202..fccdf3913e 100644 --- a/docs/data-types/lists.md +++ b/docs/data-types/lists.md @@ -293,7 +293,7 @@ This is an example of a `BRPOP` call we could use in the worker: {{< clients-example list_tutorial brpop >}} > RPUSH bikes:repairs bike:1 bike:2 -(integer) 5 +(integer) 2 > BRPOP bikes:repairs 1 1) "bikes:repairs" 2) "bike:2" @@ -346,7 +346,7 @@ Examples of rule 1: {{< clients-example list_tutorial rule_1 >}} > DEL new_bikes -(integer) 1 +(integer) 0 > LPUSH new_bikes bike:1 bike:2 bike:3 (integer) 3 {{< /clients-example >}} From 14154f27876b9d40a679d5ab826a00d2bddb2884 Mon Sep 17 00:00:00 2001 From: synix Date: Fri, 10 Nov 2023 10:56:19 -0600 Subject: [PATCH 299/377] Correction of examples for sets datatype (#2531) --- docs/data-types/sets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/sets.md b/docs/data-types/sets.md index 6a71637983..f4f51f5e2f 100644 --- a/docs/data-types/sets.md +++ b/docs/data-types/sets.md @@ -141,7 +141,7 @@ set without removing it using the `SRANDMEMBER` command: {{< clients-example sets_tutorial srem >}} > SADD bikes:racing:france bike:1 bike:2 bike:3 bike:4 bike:5 -(integer) 3 +(integer) 5 > SREM bikes:racing:france bike:1 (integer) 1 > SPOP bikes:racing:france From 4a13bd56abd92ba2157299601a64301dd93a6cff Mon Sep 17 00:00:00 2001 From: Renato Monteiro <45536168+monteiro-renato@users.noreply.github.com> Date: Fri, 10 Nov 2023 16:57:50 +0000 Subject: [PATCH 300/377] Grammar correction in sorted-sets.md (#2547) --- docs/data-types/sorted-sets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/sorted-sets.md b/docs/data-types/sorted-sets.md index 680100fc1b..34738b13b0 100644 --- a/docs/data-types/sorted-sets.md +++ b/docs/data-types/sorted-sets.md @@ -132,7 +132,7 @@ Another extremely useful operation defined for sorted set elements is the get-rank operation. It is possible to ask what is the position of an element in the set of ordered elements. The `ZREVRANK` command is also available in order to get the rank, considering -the elements sorted a descending way. +the elements sorted in a descending way. {{< clients-example ss_tutorial zrank >}} > ZRANK racer_scores "Norem" From 32b7378fb63b3d47f4a714b27fdf37f35d75e41d Mon Sep 17 00:00:00 2001 From: Chayim Date: Wed, 15 Nov 2023 12:21:34 +0200 Subject: [PATCH 301/377] Change examples using HMSET to HSET as the former is deprecated (#2569) HMSET is deprecated as of Redis 4.0.0, and HSET is the preferred method for this interaction. This PR updates the examples where we were referring to the deprecated command. --- commands/hrandfield.md | 2 +- commands/hstrlen.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/hrandfield.md b/commands/hrandfield.md index df6e2e5a31..e019e8a946 100644 --- a/commands/hrandfield.md +++ b/commands/hrandfield.md @@ -11,7 +11,7 @@ The optional `WITHVALUES` modifier changes the reply so it includes the respecti @examples ```cli -HMSET coin heads obverse tails reverse edge null +HSET coin heads obverse tails reverse edge null HRANDFIELD coin HRANDFIELD coin HRANDFIELD coin -5 WITHVALUES diff --git a/commands/hstrlen.md b/commands/hstrlen.md index f32b1d8882..e473ecffeb 100644 --- a/commands/hstrlen.md +++ b/commands/hstrlen.md @@ -3,7 +3,7 @@ Returns the string length of the value associated with `field` in the hash store @examples ```cli -HMSET myhash f1 HelloWorld f2 99 f3 -256 +HSET myhash f1 HelloWorld f2 99 f3 -256 HSTRLEN myhash f1 HSTRLEN myhash f2 HSTRLEN myhash f3 From a242d79d8627f554690b62ce3724554f1a3af43e Mon Sep 17 00:00:00 2001 From: portman xu Date: Wed, 15 Nov 2023 04:38:08 -0600 Subject: [PATCH 302/377] Change 'this counters' to 'these counters' (#2540) --- commands/incr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/incr.md b/commands/incr.md index b87897233e..e8aae005d0 100644 --- a/commands/incr.md +++ b/commands/incr.md @@ -78,7 +78,7 @@ END ``` Basically we have a counter for every IP, for every different second. -But this counters are always incremented setting an expire of 10 seconds so that +But these counters are always incremented setting an expire of 10 seconds so that they'll be removed by Redis automatically when the current second is a different one. From b4980035940e341c83be356afeb14cae71ebb958 Mon Sep 17 00:00:00 2001 From: Guy Korland Date: Wed, 15 Nov 2023 12:48:29 +0200 Subject: [PATCH 303/377] Add FalkorDB under modules (#2545) --- modules/community/github.com/FalkorDB/FalkorDB.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 modules/community/github.com/FalkorDB/FalkorDB.json diff --git a/modules/community/github.com/FalkorDB/FalkorDB.json b/modules/community/github.com/FalkorDB/FalkorDB.json new file mode 100644 index 0000000000..dac23f5ead --- /dev/null +++ b/modules/community/github.com/FalkorDB/FalkorDB.json @@ -0,0 +1,8 @@ +{ + "name": "FalkorDB", + "license": "SSPL", + "description": "A graph database with a Cypher-based querying language using sparse adjacency matrices", + "github": [ + "FalkorDB" + ] +} From e83b601af68fa64bf0f552f2963d7468b6846844 Mon Sep 17 00:00:00 2001 From: Renato Monteiro <45536168+monteiro-renato@users.noreply.github.com> Date: Wed, 15 Nov 2023 12:32:09 +0000 Subject: [PATCH 304/377] Fix wording in cli.md (#2600) --- docs/connect/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/connect/cli.md b/docs/connect/cli.md index 70f3e71f7f..d5eb11f103 100644 --- a/docs/connect/cli.md +++ b/docs/connect/cli.md @@ -603,7 +603,7 @@ once you use the `MONITOR` command. All commands received by the active Redis in 1460100081.165665 [0 127.0.0.1:51706] "set" "shipment:8000736522714:status" "sorting" 1460100083.053365 [0 127.0.0.1:51707] "get" "shipment:8000736522714:status" -Note that it is possible to use to pipe the output, so you can monitor +Note that it is possible to pipe the output, so you can monitor for specific patterns using tools such as `grep`. ## Monitoring the latency of Redis instances From 9698b8ba81cae1c2251ca035598a9a1dcc3db120 Mon Sep 17 00:00:00 2001 From: Renato Monteiro <45536168+monteiro-renato@users.noreply.github.com> Date: Wed, 15 Nov 2023 12:33:28 +0000 Subject: [PATCH 305/377] Fix discrepancy in lists.md (#2546) The line I've updated made sense with the previous code snippet. The commit af1734cafec11cd9bb67afc9f48fa876a66f7465 changed the code snippets but looks like this line was missed. --- docs/data-types/lists.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/lists.md b/docs/data-types/lists.md index fccdf3913e..f2275e2332 100644 --- a/docs/data-types/lists.md +++ b/docs/data-types/lists.md @@ -305,7 +305,7 @@ This is an example of a `BRPOP` call we could use in the worker: (2.01s) {{< /clients-example >}} -It means: "wait for elements in the list `bikes:repairs`, but return if after 5 seconds +It means: "wait for elements in the list `bikes:repairs`, but return if after 1 second no element is available". Note that you can use 0 as timeout to wait for elements forever, and you can From ce712a989185fe91f6177106dc70b5b56684bcd2 Mon Sep 17 00:00:00 2001 From: Simon Prickett Date: Wed, 15 Nov 2023 13:59:21 +0000 Subject: [PATCH 306/377] Put SCAN details back to SCAN page (#2535) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moving the text back from Keyspace Tutorial to where it was moved in an earlier change. Co-authored-by: Viktor Söderqvist --- commands/scan.md | 192 +++++++++++++++++++++++++++++++++++++++- docs/manual/keyspace.md | 186 +------------------------------------- 2 files changed, 190 insertions(+), 188 deletions(-) diff --git a/commands/scan.md b/commands/scan.md index 5a10ec6e8b..09c52efe6c 100644 --- a/commands/scan.md +++ b/commands/scan.md @@ -9,19 +9,203 @@ Since these commands allow for incremental iteration, returning only a small num However while blocking commands like `SMEMBERS` are able to provide all the elements that are part of a Set in a given moment, The SCAN family of commands only offer limited guarantees about the returned elements since the collection that we incrementally iterate can change during the iteration process. -Note that `SCAN`, `SSCAN`, `HSCAN` and `ZSCAN` all work very similarly, so this documentation covers all the four commands. However an obvious difference is that in the case of `SSCAN`, `HSCAN` and `ZSCAN` the first argument is the name of the key holding the Set, Hash or Sorted Set value. The `SCAN` command does not need any key name argument as it iterates keys in the current database, so the iterated object is the database itself. +Note that `SCAN`, `SSCAN`, `HSCAN` and `ZSCAN` all work very similarly, so this documentation covers all four commands. However an obvious difference is that in the case of `SSCAN`, `HSCAN` and `ZSCAN` the first argument is the name of the key holding the Set, Hash or Sorted Set value. The `SCAN` command does not need any key name argument as it iterates keys in the current database, so the iterated object is the database itself. +## SCAN basic usage -For more information on `SCAN` please refer to the [The Redis Keyspace](/docs/manual/keyspace) tutorial. +SCAN is a cursor based iterator. This means that at every call of the command, the server returns an updated cursor that the user needs to use as the cursor argument in the next call. + +An iteration starts when the cursor is set to 0, and terminates when the cursor returned by the server is 0. The following is an example of SCAN iteration: + +``` +redis 127.0.0.1:6379> scan 0 +1) "17" +2) 1) "key:12" + 2) "key:8" + 3) "key:4" + 4) "key:14" + 5) "key:16" + 6) "key:17" + 7) "key:15" + 8) "key:10" + 9) "key:3" + 10) "key:7" + 11) "key:1" +redis 127.0.0.1:6379> scan 17 +1) "0" +2) 1) "key:5" + 2) "key:18" + 3) "key:0" + 4) "key:2" + 5) "key:19" + 6) "key:13" + 7) "key:6" + 8) "key:9" + 9) "key:11" +``` + +In the example above, the first call uses zero as a cursor, to start the iteration. The second call uses the cursor returned by the previous call as the first element of the reply, that is, 17. + +As you can see the **SCAN return value** is an array of two values: the first value is the new cursor to use in the next call, the second value is an array of elements. + +Since in the second call the returned cursor is 0, the server signaled to the caller that the iteration finished, and the collection was completely explored. Starting an iteration with a cursor value of 0, and calling `SCAN` until the returned cursor is 0 again is called a **full iteration**. ## Return value -`SCAN`, `SSCAN`, `HSCAN` and `ZSCAN` return a two elements multi-bulk reply, where the first element is a string representing an unsigned 64 bit number (the cursor), and the second element is a multi-bulk with an array of elements. +`SCAN`, `SSCAN`, `HSCAN` and `ZSCAN` return a two element multi-bulk reply, where the first element is a string representing an unsigned 64 bit number (the cursor), and the second element is a multi-bulk with an array of elements. * `SCAN` array of elements is a list of keys. * `SSCAN` array of elements is a list of Set members. * `HSCAN` array of elements contain two elements, a field and a value, for every returned element of the Hash. -* `ZSCAN` array of elements contain two elements, a member and its associated score, for every returned element of the sorted set. +* `ZSCAN` array of elements contain two elements, a member and its associated score, for every returned element of the Sorted Set. + +## Scan guarantees + +The `SCAN` command, and the other commands in the `SCAN` family, are able to provide to the user a set of guarantees associated to full iterations. + +* A full iteration always retrieves all the elements that were present in the collection from the start to the end of a full iteration. This means that if a given element is inside the collection when an iteration is started, and is still there when an iteration terminates, then at some point `SCAN` returned it to the user. +* A full iteration never returns any element that was NOT present in the collection from the start to the end of a full iteration. So if an element was removed before the start of an iteration, and is never added back to the collection for all the time an iteration lasts, `SCAN` ensures that this element will never be returned. + +However because `SCAN` has very little state associated (just the cursor) it has the following drawbacks: + +* A given element may be returned multiple times. It is up to the application to handle the case of duplicated elements, for example only using the returned elements in order to perform operations that are safe when re-applied multiple times. +* Elements that were not constantly present in the collection during a full iteration, may be returned or not: it is undefined. + +## Number of elements returned at every SCAN call + +`SCAN` family functions do not guarantee that the number of elements returned per call are in a given range. The commands are also allowed to return zero elements, and the client should not consider the iteration complete as long as the returned cursor is not zero. + +However the number of returned elements is reasonable, that is, in practical terms `SCAN` may return a maximum number of elements in the order of a few tens of elements when iterating a large collection, or may return all the elements of the collection in a single call when the iterated collection is small enough to be internally represented as an encoded data structure (this happens for small Sets, Hashes and Sorted Sets). + +However there is a way for the user to tune the order of magnitude of the number of returned elements per call using the **COUNT** option. + +## The COUNT option + +While `SCAN` does not provide guarantees about the number of elements returned at every iteration, it is possible to empirically adjust the behavior of `SCAN` using the **COUNT** option. Basically with COUNT the user specifies the *amount of work that should be done at every call in order to retrieve elements from the collection*. This is **just a hint** for the implementation, however generally speaking this is what you could expect most of the times from the implementation. + +* The default `COUNT` value is 10. +* When iterating the key space, or a Set, Hash or Sorted Set that is big enough to be represented by a hash table, assuming no **MATCH** option is used, the server will usually return *count* or a few more than *count* elements per call. Please check the *why SCAN may return all the elements at once* section later in this document. +* When iterating Sets encoded as intsets (small sets composed of just integers), or Hashes and Sorted Sets encoded as ziplists (small hashes and sets composed of small individual values), usually all the elements are returned in the first `SCAN` call regardless of the `COUNT` value. + +Important: **there is no need to use the same COUNT value** for every iteration. The caller is free to change the count from one iteration to the other as required, as long as the cursor passed in the next call is the one obtained in the previous call to the command. + +## The MATCH option + +It is possible to only iterate elements matching a given glob-style pattern, similarly to the behavior of the `KEYS` command that takes a pattern as its only argument. + +To do so, just append the `MATCH ` arguments at the end of the `SCAN` command (it works with all the `SCAN` family commands). + +This is an example of iteration using **MATCH**: + +``` +redis 127.0.0.1:6379> sadd myset 1 2 3 foo foobar feelsgood +(integer) 6 +redis 127.0.0.1:6379> sscan myset 0 match f* +1) "0" +2) 1) "foo" + 2) "feelsgood" + 3) "foobar" +redis 127.0.0.1:6379> +``` + +It is important to note that the **MATCH** filter is applied after elements are retrieved from the collection, just before returning data to the client. This means that if the pattern matches very little elements inside the collection, `SCAN` will likely return no elements in most iterations. An example is shown below: + +``` +redis 127.0.0.1:6379> scan 0 MATCH *11* +1) "288" +2) 1) "key:911" +redis 127.0.0.1:6379> scan 288 MATCH *11* +1) "224" +2) (empty list or set) +redis 127.0.0.1:6379> scan 224 MATCH *11* +1) "80" +2) (empty list or set) +redis 127.0.0.1:6379> scan 80 MATCH *11* +1) "176" +2) (empty list or set) +redis 127.0.0.1:6379> scan 176 MATCH *11* COUNT 1000 +1) "0" +2) 1) "key:611" + 2) "key:711" + 3) "key:118" + 4) "key:117" + 5) "key:311" + 6) "key:112" + 7) "key:111" + 8) "key:110" + 9) "key:113" + 10) "key:211" + 11) "key:411" + 12) "key:115" + 13) "key:116" + 14) "key:114" + 15) "key:119" + 16) "key:811" + 17) "key:511" + 18) "key:11" +redis 127.0.0.1:6379> +``` + +As you can see most of the calls returned zero elements, but the last call where a `COUNT` of 1000 was used in order to force the command to do more scanning for that iteration. + + +## The TYPE option + +You can use the `!TYPE` option to ask `SCAN` to only return objects that match a given `type`, allowing you to iterate through the database looking for keys of a specific type. The **TYPE** option is only available on the whole-database `SCAN`, not `HSCAN` or `ZSCAN` etc. + +The `type` argument is the same string name that the `TYPE` command returns. Note a quirk where some Redis types, such as GeoHashes, HyperLogLogs, Bitmaps, and Bitfields, may internally be implemented using other Redis types, such as a string or zset, so can't be distinguished from other keys of that same type by `SCAN`. For example, a ZSET and GEOHASH: + +``` +redis 127.0.0.1:6379> GEOADD geokey 0 0 value +(integer) 1 +redis 127.0.0.1:6379> ZADD zkey 1000 value +(integer) 1 +redis 127.0.0.1:6379> TYPE geokey +zset +redis 127.0.0.1:6379> TYPE zkey +zset +redis 127.0.0.1:6379> SCAN 0 TYPE zset +1) "0" +2) 1) "geokey" + 2) "zkey" +``` + +It is important to note that the **TYPE** filter is also applied after elements are retrieved from the database, so the option does not reduce the amount of work the server has to do to complete a full iteration, and for rare types you may receive no elements in many iterations. + +## Multiple parallel iterations + +It is possible for an infinite number of clients to iterate the same collection at the same time, as the full state of the iterator is in the cursor, that is obtained and returned to the client at every call. No server side state is taken at all. + +## Terminating iterations in the middle + +Since there is no state server side, but the full state is captured by the cursor, the caller is free to terminate an iteration half-way without signaling this to the server in any way. An infinite number of iterations can be started and never terminated without any issue. + +## Calling SCAN with a corrupted cursor + +Calling `SCAN` with a broken, negative, out of range, or otherwise invalid cursor, will result in undefined behavior but never in a crash. What will be undefined is that the guarantees about the returned elements can no longer be ensured by the `SCAN` implementation. + +The only valid cursors to use are: + +* The cursor value of 0 when starting an iteration. +* The cursor returned by the previous call to SCAN in order to continue the iteration. + +## Guarantee of termination + +The `SCAN` algorithm is guaranteed to terminate only if the size of the iterated collection remains bounded to a given maximum size, otherwise iterating a collection that always grows may result into `SCAN` to never terminate a full iteration. + +This is easy to see intuitively: if the collection grows there is more and more work to do in order to visit all the possible elements, and the ability to terminate the iteration depends on the number of calls to `SCAN` and its COUNT option value compared with the rate at which the collection grows. + +## Why SCAN may return all the items of an aggregate data type in a single call? + +In the `COUNT` option documentation, we state that sometimes this family of commands may return all the elements of a Set, Hash or Sorted Set at once in a single call, regardless of the `COUNT` option value. The reason why this happens is that the cursor-based iterator can be implemented, and is useful, only when the aggregate data type that we are scanning is represented as a hash table. However Redis uses a [memory optimization](/topics/memory-optimization) where small aggregate data types, until they reach a given amount of items or a given max size of single elements, are represented using a compact single-allocation packed encoding. When this is the case, `SCAN` has no meaningful cursor to return, and must iterate the whole data structure at once, so the only sane behavior it has is to return everything in a call. + +However once the data structures are bigger and are promoted to use real hash tables, the `SCAN` family of commands will resort to the normal behavior. Note that since this special behavior of returning all the elements is true only for small aggregates, it has no effects on the command complexity or latency. However the exact limits to get converted into real hash tables are [user configurable](/topics/memory-optimization), so the maximum number of elements you can see returned in a single call depends on how big an aggregate data type could be and still use the packed representation. + +Also note that this behavior is specific of `SSCAN`, `HSCAN` and `ZSCAN`. `SCAN` itself never shows this behavior because the key space is always represented by hash tables. + +## Further reading + +For more information about managing keys, please refer to the [The Redis Keyspace](/docs/manual/keyspace) tutorial. ## Additional examples diff --git a/docs/manual/keyspace.md b/docs/manual/keyspace.md index 5e37c2bf1f..f6f443f64d 100644 --- a/docs/manual/keyspace.md +++ b/docs/manual/keyspace.md @@ -114,190 +114,8 @@ To incrementally iterate over the keys in a Redis database in an efficient mann Since `SCAN` allows for incremental iteration, returning only a small number of elements per call, it can be used in production without the downside of commands like `KEYS` or `SMEMBERS` that may block the server for a long time (even several seconds) when called against big collections of keys or elements. -However while blocking commands like `SMEMBERS` are able to provide all the elements that are part of a Set in a given moment, The SCAN family of commands only offer limited guarantees about the returned elements since the collection that we incrementally iterate can change during the iteration process. - -#### SCAN basic usage - -SCAN is a cursor based iterator. This means that at every call of the command, the server returns an updated cursor that the user needs to use as the cursor argument in the next call. - -An iteration starts when the cursor is set to 0, and terminates when the cursor returned by the server is 0. The following is an example of SCAN iteration: - -``` -redis 127.0.0.1:6379> scan 0 -1) "17" -2) 1) "key:12" - 2) "key:8" - 3) "key:4" - 4) "key:14" - 5) "key:16" - 6) "key:17" - 7) "key:15" - 8) "key:10" - 9) "key:3" - 10) "key:7" - 11) "key:1" -redis 127.0.0.1:6379> scan 17 -1) "0" -2) 1) "key:5" - 2) "key:18" - 3) "key:0" - 4) "key:2" - 5) "key:19" - 6) "key:13" - 7) "key:6" - 8) "key:9" - 9) "key:11" -``` - -In the example above, the first call uses zero as a cursor, to start the iteration. The second call uses the cursor returned by the previous call as the first element of the reply, that is, 17. - -As you can see the **SCAN return value** is an array of two values: the first value is the new cursor to use in the next call, the second value is an array of elements. - -Since in the second call the returned cursor is 0, the server signaled to the caller that the iteration finished, and the collection was completely explored. Starting an iteration with a cursor value of 0, and calling `SCAN` until the returned cursor is 0 again is called a **full iteration**. - -#### Scan guarantees - -The `SCAN` command, and the other commands in the `SCAN` family, are able to provide to the user a set of guarantees associated to full iterations. - -* A full iteration always retrieves all the elements that were present in the collection from the start to the end of a full iteration. This means that if a given element is inside the collection when an iteration is started, and is still there when an iteration terminates, then at some point `SCAN` returned it to the user. -* A full iteration never returns any element that was NOT present in the collection from the start to the end of a full iteration. So if an element was removed before the start of an iteration, and is never added back to the collection for all the time an iteration lasts, `SCAN` ensures that this element will never be returned. - -However because `SCAN` has very little state associated (just the cursor) it has the following drawbacks: - -* A given element may be returned multiple times. It is up to the application to handle the case of duplicated elements, for example only using the returned elements in order to perform operations that are safe when re-applied multiple times. -* Elements that were not constantly present in the collection during a full iteration, may be returned or not: it is undefined. - -#### Number of elements returned at every SCAN call - -`SCAN` family functions do not guarantee that the number of elements returned per call are in a given range. The commands are also allowed to return zero elements, and the client should not consider the iteration complete as long as the returned cursor is not zero. - -However the number of returned elements is reasonable, that is, in practical terms SCAN may return a maximum number of elements in the order of a few tens of elements when iterating a large collection, or may return all the elements of the collection in a single call when the iterated collection is small enough to be internally represented as an encoded data structure (this happens for small sets, hashes and sorted sets). - -However there is a way for the user to tune the order of magnitude of the number of returned elements per call using the **COUNT** option. - -#### The COUNT option - -While `SCAN` does not provide guarantees about the number of elements returned at every iteration, it is possible to empirically adjust the behavior of `SCAN` using the **COUNT** option. Basically with COUNT the user specified the *amount of work that should be done at every call in order to retrieve elements from the collection*. This is **just a hint** for the implementation, however generally speaking this is what you could expect most of the times from the implementation. - -* The default COUNT value is 10. -* When iterating the key space, or a Set, Hash or Sorted Set that is big enough to be represented by a hash table, assuming no **MATCH** option is used, the server will usually return *count* or a bit more than *count* elements per call. Please check the *why SCAN may return all the elements at once* section later in this document. -* When iterating Sets encoded as intsets (small sets composed of just integers), or Hashes and Sorted Sets encoded as ziplists (small hashes and sets composed of small individual values), usually all the elements are returned in the first `SCAN` call regardless of the COUNT value. - -Important: **there is no need to use the same COUNT value** for every iteration. The caller is free to change the count from one iteration to the other as required, as long as the cursor passed in the next call is the one obtained in the previous call to the command. - -#### The MATCH option - -It is possible to only iterate elements matching a given glob-style pattern, similarly to the behavior of the `KEYS` command that takes a pattern as its only argument. - -To do so, just append the `MATCH ` arguments at the end of the `SCAN` command (it works with all the SCAN family commands). - -This is an example of iteration using **MATCH**: - -``` -redis 127.0.0.1:6379> sadd myset 1 2 3 foo foobar feelsgood -(integer) 6 -redis 127.0.0.1:6379> sscan myset 0 match f* -1) "0" -2) 1) "foo" - 2) "feelsgood" - 3) "foobar" -redis 127.0.0.1:6379> -``` - -It is important to note that the **MATCH** filter is applied after elements are retrieved from the collection, just before returning data to the client. This means that if the pattern matches very little elements inside the collection, `SCAN` will likely return no elements in most iterations. An example is shown below: - -``` -redis 127.0.0.1:6379> scan 0 MATCH *11* -1) "288" -2) 1) "key:911" -redis 127.0.0.1:6379> scan 288 MATCH *11* -1) "224" -2) (empty list or set) -redis 127.0.0.1:6379> scan 224 MATCH *11* -1) "80" -2) (empty list or set) -redis 127.0.0.1:6379> scan 80 MATCH *11* -1) "176" -2) (empty list or set) -redis 127.0.0.1:6379> scan 176 MATCH *11* COUNT 1000 -1) "0" -2) 1) "key:611" - 2) "key:711" - 3) "key:118" - 4) "key:117" - 5) "key:311" - 6) "key:112" - 7) "key:111" - 8) "key:110" - 9) "key:113" - 10) "key:211" - 11) "key:411" - 12) "key:115" - 13) "key:116" - 14) "key:114" - 15) "key:119" - 16) "key:811" - 17) "key:511" - 18) "key:11" -redis 127.0.0.1:6379> -``` - -As you can see most of the calls returned zero elements, but the last call where a COUNT of 1000 was used in order to force the command to do more scanning for that iteration. - - -#### The TYPE option - -You can use the `!TYPE` option to ask `SCAN` to only return objects that match a given `type`, allowing you to iterate through the database looking for keys of a specific type. The **TYPE** option is only available on the whole-database `SCAN`, not `HSCAN` or `ZSCAN` etc. - -The `type` argument is the same string name that the `TYPE` command returns. Note a quirk where some Redis types, such as GeoHashes, HyperLogLogs, Bitmaps, and Bitfields, may internally be implemented using other Redis types, such as a string or zset, so can't be distinguished from other keys of that same type by `SCAN`. For example, a ZSET and GEOHASH: - -``` -redis 127.0.0.1:6379> GEOADD geokey 0 0 value -(integer) 1 -redis 127.0.0.1:6379> ZADD zkey 1000 value -(integer) 1 -redis 127.0.0.1:6379> TYPE geokey -zset -redis 127.0.0.1:6379> TYPE zkey -zset -redis 127.0.0.1:6379> SCAN 0 TYPE zset -1) "0" -2) 1) "geokey" - 2) "zkey" -``` - -It is important to note that the **TYPE** filter is also applied after elements are retrieved from the database, so the option does not reduce the amount of work the server has to do to complete a full iteration, and for rare types you may receive no elements in many iterations. - -#### Multiple parallel iterations - -It is possible for an infinite number of clients to iterate the same collection at the same time, as the full state of the iterator is in the cursor, that is obtained and returned to the client at every call. No server side state is taken at all. - -#### Terminating iterations in the middle - -Since there is no state server side, but the full state is captured by the cursor, the caller is free to terminate an iteration half-way without signaling this to the server in any way. An infinite number of iterations can be started and never terminated without any issue. - -#### Calling SCAN with a corrupted cursor - -Calling `SCAN` with a broken, negative, out of range, or otherwise invalid cursor, will result in undefined behavior but never in a crash. What will be undefined is that the guarantees about the returned elements can no longer be ensured by the `SCAN` implementation. - -The only valid cursors to use are: - -* The cursor value of 0 when starting an iteration. -* The cursor returned by the previous call to SCAN in order to continue the iteration. - -#### Guarantee of termination - -The `SCAN` algorithm is guaranteed to terminate only if the size of the iterated collection remains bounded to a given maximum size, otherwise iterating a collection that always grows may result into `SCAN` to never terminate a full iteration. - -This is easy to see intuitively: if the collection grows there is more and more work to do in order to visit all the possible elements, and the ability to terminate the iteration depends on the number of calls to `SCAN` and its COUNT option value compared with the rate at which the collection grows. - -#### Why SCAN may return all the items of an aggregate data type in a single call? - -In the `COUNT` option documentation, we state that sometimes this family of commands may return all the elements of a Set, Hash or Sorted Set at once in a single call, regardless of the `COUNT` option value. The reason why this happens is that the cursor-based iterator can be implemented, and is useful, only when the aggregate data type that we are scanning is represented as a hash table. However Redis uses a [memory optimization](/topics/memory-optimization) where small aggregate data types, until they reach a given amount of items or a given max size of single elements, are represented using a compact single-allocation packed encoding. When this is the case, `SCAN` has no meaningful cursor to return, and must iterate the whole data structure at once, so the only sane behavior it has is to return everything in a call. - -However once the data structures are bigger and are promoted to use real hash tables, the `SCAN` family of commands will resort to the normal behavior. Note that since this special behavior of returning all the elements is true only for small aggregates, it has no effects on the command complexity or latency. However the exact limits to get converted into real hash tables are [user configurable](/topics/memory-optimization), so the maximum number of elements you can see returned in a single call depends on how big an aggregate data type could be and still use the packed representation. - -Also note that this behavior is specific of `SSCAN`, `HSCAN` and `ZSCAN`. `SCAN` itself never shows this behavior because the key space is always represented by hash tables. +However while blocking commands like `SMEMBERS` are able to provide all the elements that are part of a Set in a given moment. +The `SCAN` family of commands only offer limited guarantees about the returned elements since the collection that we incrementally iterate can change during the iteration process. ### Keys From 072898399523843e4abb6c50e9e9a2ac1935910e Mon Sep 17 00:00:00 2001 From: heyone-top <979034501@qq.com> Date: Wed, 22 Nov 2023 20:27:53 +0800 Subject: [PATCH 307/377] Correction of map representation in RESP2 (#2587) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the protocol spec, the description of how maps are represented in RESP2 is incorrect. "Maps in RESP2 are represented by arrays, in which each element is a key-value tuple. Each tuple is an array with two elements, these being the key and the value." This is not true. A map in RESP2 is represented as a flat array containing the keys and values, not nested arrays. The description is updated. Co-authored-by: Viktor Söderqvist --- docs/reference/protocol-spec.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/reference/protocol-spec.md b/docs/reference/protocol-spec.md index a9893c8a5b..c5ace66fd8 100644 --- a/docs/reference/protocol-spec.md +++ b/docs/reference/protocol-spec.md @@ -516,8 +516,9 @@ However, low-level programming languages (such as C, for example) will likely re {{% alert title="Map pattern in RESP2" color="info" %}} RESP2 doesn't have a map type. -Maps in RESP2 are represented by arrays, in which each element is a key-value tuple. -Each tuple is an array with two elements, these being the key and the value. +A map in RESP2 is represented by a flat array containing the keys and the values. +The first element is a key, followed by the corresponding value, then the next key and so on, like this: +`key1, value1, key2, value2, ...`. {{% /alert %}}
From c2d73cd8d9c9a461bf18651287357caf23653bfa Mon Sep 17 00:00:00 2001 From: Hwang Si Yeon <46290941+lowgiant@users.noreply.github.com> Date: Thu, 23 Nov 2023 02:59:26 +0900 Subject: [PATCH 308/377] Add an explanation for URI with -u in redis-cli (#2604) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's good for users to know that they need to specify "default" as the username when authenticating without a username. Other details of the URI format are described too, like scheme and dbnum. Related to https://github.com/redis/redis/pull/12751 Co-authored-by: Viktor Söderqvist --- docs/connect/cli.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/connect/cli.md b/docs/connect/cli.md index d5eb11f103..4a9a4b2e97 100644 --- a/docs/connect/cli.md +++ b/docs/connect/cli.md @@ -122,6 +122,11 @@ option and the URI pattern `redis://user:password@host:port/dbnum`: $ redis-cli -u redis://LJenkins:p%40ssw0rd@redis-16379.hosted.com:16379/0 PING PONG +**NOTE:** +User, password and dbnum are optional. +For authentication without a username, use username `default`. +For TLS, use the scheme `rediss`. + ## SSL/TLS By default, `redis-cli` uses a plain TCP connection to connect to Redis. From 5d48ad73b5650c5a78a7d98d7df6693e33d763c5 Mon Sep 17 00:00:00 2001 From: "David W. Dougherty" Date: Mon, 27 Nov 2023 09:04:21 -0800 Subject: [PATCH 309/377] DOC-3075: update Python connection section re. distutils removal in Python 3.12+ --- docs/connect/clients/python.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/connect/clients/python.md b/docs/connect/clients/python.md index 6563f0ad84..7c0e5e87aa 100644 --- a/docs/connect/clients/python.md +++ b/docs/connect/clients/python.md @@ -26,6 +26,10 @@ pip install redis For faster performance, install Redis with [`hiredis`](https://github.com/redis/hiredis) support. This provides a compiled response parser, and for most cases requires zero code changes. By default, if `hiredis` >= 1.0 is available, `redis-py` attempts to use it for response parsing. +{{% alert title="Note" %}} +The Python `distutils` packaging scheme is no longer part of Python 3.12 and greater. If you're having difficulties getting `redis-py` installed in a Python 3.12 environment, consider updating to a recent release of `redis-py`. +{{% /alert %}} + ```bash pip install redis[hiredis] ``` From c9e3055dc8d77af0e79a27c1b8263a41d7dbb3f1 Mon Sep 17 00:00:00 2001 From: Arnaud Rebillout Date: Wed, 1 Nov 2023 09:15:28 +0700 Subject: [PATCH 310/377] Update getting-started/faq to get-started/faq getting-started/faq redirects to get-started/faq. As a result, this link is not fully functional (the part after the hashtag is lost after redirection): https://redis.io/docs/getting-started/faq/#background-saving-fails-with-a-fork-error-on-linux --- docs/management/admin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/management/admin.md b/docs/management/admin.md index 8d31b9a14d..116b3aca21 100644 --- a/docs/management/admin.md +++ b/docs/management/admin.md @@ -17,7 +17,7 @@ aliases: [ * Deploy Redis using the Linux operating system. Redis is also tested on OS X, and from time to time on FreeBSD and OpenBSD systems. However, Linux is where most of the stress testing is performed, and where most production deployments are run. -* Set the Linux kernel overcommit memory setting to 1. Add `vm.overcommit_memory = 1` to `/etc/sysctl.conf`. Then, reboot or run the command `sysctl vm.overcommit_memory=1` to activate the setting. See [FAQ: Background saving fails with a fork() error on Linux?](https://redis.io/docs/getting-started/faq/#background-saving-fails-with-a-fork-error-on-linux) for details. +* Set the Linux kernel overcommit memory setting to 1. Add `vm.overcommit_memory = 1` to `/etc/sysctl.conf`. Then, reboot or run the command `sysctl vm.overcommit_memory=1` to activate the setting. See [FAQ: Background saving fails with a fork() error on Linux?](https://redis.io/docs/get-started/faq/#background-saving-fails-with-a-fork-error-on-linux) for details. * To ensure the Linux kernel feature Transparent Huge Pages does not impact Redis memory usage and latency, run the command: `echo never > /sys/kernel/mm/transparent_hugepage/enabled` to disable it. See [Latency Diagnosis - Latency induced by transparent huge pages](https://redis.io/docs/management/optimization/latency/#latency-induced-by-transparent-huge-pages) for additional context. From 6defa01cb82ba743a02c96b062ffa67222ab7b70 Mon Sep 17 00:00:00 2001 From: Zhiyuan Zheng Date: Wed, 29 Nov 2023 10:33:07 +0800 Subject: [PATCH 311/377] Remove the duplicated entiry in sorted-sets.md --- docs/data-types/sorted-sets.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/data-types/sorted-sets.md b/docs/data-types/sorted-sets.md index 34738b13b0..4a03f445b2 100644 --- a/docs/data-types/sorted-sets.md +++ b/docs/data-types/sorted-sets.md @@ -244,7 +244,3 @@ If you need to index and query your data, consider the [JSON](/docs/stack/json) * [Redis Sorted Sets Explained](https://www.youtube.com/watch?v=MUKlxdBQZ7g) is an entertaining introduction to sorted sets in Redis. * [Redis University's RU101](https://university.redis.com/courses/ru101/) explores Redis sorted sets in detail. - - -* [Redis Sorted Sets Explained](https://www.youtube.com/watch?v=MUKlxdBQZ7g) is an entertaining introduction to sorted sets in Redis. -* [Redis University's RU101](https://university.redis.com/courses/ru101/) explores Redis sorted sets in detail. From 5b4c923f4ac069593f02b52d92693364089a5df3 Mon Sep 17 00:00:00 2001 From: moznion Date: Wed, 29 Nov 2023 23:40:41 -0800 Subject: [PATCH 312/377] Revise the response description of `OBJECT FREQ` command `OBJECT FREQ` would return the nil/null response if the target key doesn't exist. Signed-off-by: moznion --- resp2_replies.json | 4 +++- resp3_replies.json | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/resp2_replies.json b/resp2_replies.json index fb590709cc..ce2f6efa9b 100644 --- a/resp2_replies.json +++ b/resp2_replies.json @@ -767,7 +767,9 @@ "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the encoding of the object." ], "OBJECT FREQ": [ - "[Integer reply](/docs/reference/protocol-spec#integers): the counter's value." + "One of the following:", + "[Integer reply](/docs/reference/protocol-spec#integers): the counter's value.", + "[Nil reply](/docs/reference/protocol-spec#bulk-strings): if _key_ doesn't exist." ], "OBJECT HELP": [ "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions" diff --git a/resp3_replies.json b/resp3_replies.json index addd0867dc..31f3f1fb18 100644 --- a/resp3_replies.json +++ b/resp3_replies.json @@ -767,7 +767,9 @@ "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the encoding of the object." ], "OBJECT FREQ": [ - "[Integer reply](/docs/reference/protocol-spec#integers): the counter's value." + "One of the following:", + "[Integer reply](/docs/reference/protocol-spec#integers): the counter's value.", + "[Null reply](/docs/reference/protocol-spec#nulls): if _key_ doesn't exist." ], "OBJECT HELP": [ "[Array reply](/docs/reference/protocol-spec#arrays): a list of sub-commands and their descriptions." From 8251f69cd068c93fed9d010a5ffb0ca16ad72438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=87a=C4=9Fda=C5=9F=20Kurultay=20Kalkan?= Date: Sat, 9 Dec 2023 02:53:33 +0300 Subject: [PATCH 313/377] Update resp2_replies.json fix aist to list --- resp2_replies.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resp2_replies.json b/resp2_replies.json index ce2f6efa9b..074363f755 100644 --- a/resp2_replies.json +++ b/resp2_replies.json @@ -1040,7 +1040,7 @@ "One of the following:", "* [Nil reply](/docs/reference/protocol-spec#bulk-strings): if the key does not exist.", "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): when called without the _count_ argument, the removed member.", - "* [Array reply](/docs/reference/protocol-spec#arrays): when called with the _count_ argument, a aist of the removed members." + "* [Array reply](/docs/reference/protocol-spec#arrays): when called with the _count_ argument, a list of the removed members." ], "SPUBLISH": [ "[Integer reply](/docs/reference/protocol-spec#integers): the number of clients that received the message. Note that in a Redis Cluster, only clients that are connected to the same node as the publishing client are included in the count" From 2a06c5fd2c82b285f991f1f14086ade3147cbc91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=87a=C4=9Fda=C5=9F=20Kurultay=20Kalkan?= Date: Sat, 9 Dec 2023 02:54:32 +0300 Subject: [PATCH 314/377] Update resp3_replies.json fix aist to list --- resp3_replies.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resp3_replies.json b/resp3_replies.json index 31f3f1fb18..5b8226f871 100644 --- a/resp3_replies.json +++ b/resp3_replies.json @@ -1105,7 +1105,7 @@ "One of the following:", "* [Null reply](/docs/reference/protocol-spec#nulls): if the key does not exist.", "* [Bulk string reply](/docs/reference/protocol-spec#bulk-strings): when called without the _count_ argument, the removed member.", - "* [Array reply](/docs/reference/protocol-spec#arrays): when called with the _count_ argument, a aist of the removed members." + "* [Array reply](/docs/reference/protocol-spec#arrays): when called with the _count_ argument, a list of the removed members." ], "SPUBLISH": [ "[Integer reply](/docs/reference/protocol-spec#integers): the number of clients that received the message. Note that in a Redis Cluster, only clients that are connected to the same node as the publishing client are included in the count" From b260429d01c85c64d7d0ea185929d92c85bba022 Mon Sep 17 00:00:00 2001 From: jiangyunpeng Date: Fri, 15 Dec 2023 17:08:24 +0800 Subject: [PATCH 315/377] Explain how to remove failed cluster node (#2427) (#2434) `redis-cli --cluster del-node` doesn't work since it tries to connect to all nodes. `--cluster call CLUSTER FORGET` works though. --- docs/management/scaling.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/management/scaling.md b/docs/management/scaling.md index f847ab78f2..11de8eaafe 100644 --- a/docs/management/scaling.md +++ b/docs/management/scaling.md @@ -875,6 +875,14 @@ over one of its replicas and remove the node after it turned into a replica of t new master. Obviously this does not help when you want to reduce the actual number of masters in your cluster, in that case, a resharding is needed. +There is a special scenario where you want to remove a failed node. +You should not use the `del-node` command because it tries to connect to all nodes and you will encounter a "connection refused" error. +Instead, you can use the `call` command: + + redis-cli --cluster call 127.0.0.1:7000 cluster forget `` + +This command will execute `CLUSTER FORGET` command on every node. + #### Replica migration In Redis Cluster, you can reconfigure a replica to replicate with a From f996053ed5b05a69ddda21e1ab58af8a6d1368b3 Mon Sep 17 00:00:00 2001 From: Lior Kogan Date: Tue, 19 Dec 2023 11:14:11 +0200 Subject: [PATCH 316/377] Update hincrbyfloat.md (#2626) WRONGTYPE is about the key type, not the field type. looks like a copy paste issue from INCRBYFLOAT --- commands/hincrbyfloat.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/hincrbyfloat.md b/commands/hincrbyfloat.md index 46794de151..f83d7d124d 100644 --- a/commands/hincrbyfloat.md +++ b/commands/hincrbyfloat.md @@ -4,7 +4,7 @@ is negative, the result is to have the hash field value **decremented** instead If the field does not exist, it is set to `0` before performing the operation. An error is returned if one of the following conditions occur: -* The field contains a value of the wrong type (not a string). +* The key contains a value of the wrong type (not a hash). * The current field content or the specified increment are not parsable as a double precision floating point number. From b4eac7e09c0e7b071363c054bb463c4a2b97b313 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Tue, 19 Dec 2023 13:45:53 +0100 Subject: [PATCH 317/377] Improve RDB to AOF conversion docs (#2521) Add warning about RDB to AOF conversion and some other improvements to that documentation section. Removed section for Redis < 2.2. Related to redis/redis#12484. --- docs/management/persistence.md | 29 ++++++++++++++++------------- wordlist | 1 + 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/docs/management/persistence.md b/docs/management/persistence.md index e2e4be102b..4328c1b849 100644 --- a/docs/management/persistence.md +++ b/docs/management/persistence.md @@ -259,26 +259,30 @@ and starts appending new data into the new file. ### How I can switch to AOF, if I'm currently using dump.rdb snapshots? -There is a different procedure to do this in version 2.0 and later versions, as you -can guess it's simpler since Redis 2.2 and does not require a restart at all. +If you want to enable AOF in a server that is currently using RDB snapshots, you need to convert the data by enabling AOF via CONFIG command on the live server first. + +**IMPORTANT:** not following this procedure (e.g. just changing the config and restarting the server) can result in data loss! **Redis >= 2.2** +Preparations: + * Make a backup of your latest dump.rdb file. * Transfer this backup to a safe place. -* Issue the following two commands: -* `redis-cli config set appendonly yes` -* `redis-cli config set save ""` -* Make sure your database contains the same number of keys it contained. -* Make sure writes are appended to the append only file correctly. -The first CONFIG command enables the Append Only File persistence. +Switch to AOF on live database: -The second CONFIG command is used to turn off snapshotting persistence. This is optional, if you wish you can take both the persistence methods enabled. +* Enable AOF: `redis-cli config set appendonly yes` +* Optionally disable RDB: `redis-cli config set save ""` +* Make sure writes are appended to the append only file correctly. +* **IMPORTANT:** Update your `redis.conf` (potentially through `CONFIG REWRITE`) and ensure that it matches the configuration above. + If you forget this step, when you restart the server, the configuration changes will be lost and the server will start again with the old configuration, resulting in a loss of your data. + +Next time you restart the server: -**IMPORTANT:** remember to edit your redis.conf to turn on the AOF, otherwise -when you restart the server the configuration changes will be lost and the -server will start again with the old configuration. +* Before restarting the server, wait for AOF rewrite to finish persisting the data. + You can do that by watching `INFO persistence`, waiting for `aof_rewrite_in_progress` and `aof_rewrite_scheduled` to be `0`, and validating that `aof_last_bgrewrite_status` is `ok`. +* After restarting the server, check that your database contains the same number of keys it contained previously. **Redis 2.0** @@ -294,7 +298,6 @@ server will start again with the old configuration. ## Interactions between AOF and RDB persistence - Redis >= 2.4 makes sure to avoid triggering an AOF rewrite when an RDB snapshotting operation is already in progress, or allowing a `BGSAVE` while the AOF rewrite is in progress. This prevents two Redis background processes diff --git a/wordlist b/wordlist index c1aaf85ed6..d222fcd152 100644 --- a/wordlist +++ b/wordlist @@ -183,6 +183,7 @@ codenamed Collina's commandstats commnad +CONFIG Config config config-file From f411cc56b36704ceae2f03808bfe53add1e30fa9 Mon Sep 17 00:00:00 2001 From: Enoch Isaac <94745584+21stPhenom@users.noreply.github.com> Date: Tue, 19 Dec 2023 15:53:12 +0100 Subject: [PATCH 318/377] Fixed grammar in _index.md (#2627) * Fixed grammar in _index.md * Update docs/install/_index.md Co-authored-by: David Dougherty --------- Co-authored-by: David Dougherty --- docs/install/_index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/install/_index.md b/docs/install/_index.md index 807a7596ae..4685cefe7e 100644 --- a/docs/install/_index.md +++ b/docs/install/_index.md @@ -8,11 +8,11 @@ aliases: - /docs/getting-started --- -You can install both [Redis](https://redis.io/docs/about/) or [Redis Stack](/docs/about/about-stack) locally on your machine. Redis and Redis Stack are available on Linux, macOS, and Windows. +You can install [Redis](https://redis.io/docs/about/) or [Redis Stack](/docs/about/about-stack) locally on your machine. Redis and Redis Stack are available on Linux, macOS, and Windows. Here are the installation instructions: * [Install Redis](/docs/install/install-redis) * [Install Redis Stack](/docs/install/install-stack) -While you can install Redis (Stack) locally, you might also consider using Redis Cloud by creating a [free account](https://redis.com/try-free/?utm_source=redisio&utm_medium=referral&utm_campaign=2023-09-try_free&utm_content=cu-redis_cloud_users). \ No newline at end of file +While you can install Redis (Stack) locally, you might also consider using Redis Cloud by creating a [free account](https://redis.com/try-free/?utm_source=redisio&utm_medium=referral&utm_campaign=2023-09-try_free&utm_content=cu-redis_cloud_users). From 95cb44d7fdf54cad2eb6f30f31cc4e38158d7f91 Mon Sep 17 00:00:00 2001 From: Cameron Beck <94604154+cbkinase@users.noreply.github.com> Date: Thu, 21 Dec 2023 09:25:27 -0500 Subject: [PATCH 319/377] Update index.md (#2628) --- docs/reference/eviction/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/eviction/index.md b/docs/reference/eviction/index.md index 4874a82bb2..0cf1b5be97 100644 --- a/docs/reference/eviction/index.md +++ b/docs/reference/eviction/index.md @@ -158,7 +158,7 @@ By default Redis is configured to: * Saturate the counter at, around, one million requests. * Decay the counter every one minute. -Those should be reasonable values and were tested experimental, but the user may want to play with these configuration settings to pick optimal values. +Those should be reasonable values and were tested experimentally, but the user may want to play with these configuration settings to pick optimal values. Instructions about how to tune these parameters can be found inside the example `redis.conf` file in the source distribution. Briefly, they are: From c8258cfa67c4532bda205ee5a0938cb146ee62fb Mon Sep 17 00:00:00 2001 From: mich-elle-luna <153109578+mich-elle-luna@users.noreply.github.com> Date: Fri, 22 Dec 2023 11:58:16 -0800 Subject: [PATCH 320/377] add link and fix a bit of language to address issue #885 (#2629) * Update _index.md to fix #885 fixes #885 and removes a bit of language for clarity * Update _index.md #885 --- docs/install/install-redis/_index.md | 29 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/docs/install/install-redis/_index.md b/docs/install/install-redis/_index.md index d3892b4bff..149e137b96 100644 --- a/docs/install/install-redis/_index.md +++ b/docs/install/install-redis/_index.md @@ -23,14 +23,15 @@ How you install Redis depends on your operating system and whether you'd like to * [Install Redis on Windows](/docs/install/install-redis/install-redis-on-windows) * [Install Redis with Redis Stack and RedisInsight](/docs/install/install-stack/) +Refer to [Redis Administration](/docs/management/admin/) for detailed setup tips. ## Test if you can connect using the CLI -Once you have Redis up and running, you can connect using `redis-cli`. +After you have Redis up and running, you can connect using `redis-cli`. -External programs talk to Redis using a TCP socket and a Redis specific protocol. This protocol is implemented in the Redis client libraries for the different programming languages. However to make hacking with Redis simpler Redis provides a command line utility that can be used to send commands to Redis. This program is called **redis-cli**. +External programs talk to Redis using a TCP socket and a Redis specific protocol. This protocol is implemented in the Redis client libraries for the different programming languages. However, to make hacking with Redis simpler, Redis provides a command line utility that can be used to send commands to Redis. This program is called **redis-cli**. -The first thing to do in order to check if Redis is working properly is sending a **PING** command using redis-cli: +The first thing to do to check if Redis is working properly is sending a **PING** command using redis-cli: ``` $ redis-cli ping @@ -49,33 +50,33 @@ PONG ## Securing Redis -By default Redis binds to **all the interfaces** and has no authentication at all. If you use Redis in a very controlled environment, separated from the external internet and in general from attackers, that's fine. However if an unhardened Redis is exposed to the internet, it is a big security concern. If you are not 100% sure your environment is secured properly, please check the following steps in order to make Redis more secure: +By default Redis binds to **all the interfaces** and has no authentication at all. If you use Redis in a very controlled environment, separated from the external internet and in general from attackers, that's fine. However, if an unhardened Redis is exposed to the internet, it is a big security concern. If you are not 100% sure your environment is secured properly, please check the following steps in order to make Redis more secure: 1. Make sure the port Redis uses to listen for connections (by default 6379 and additionally 16379 if you run Redis in cluster mode, plus 26379 for Sentinel) is firewalled, so that it is not possible to contact Redis from the outside world. -2. Use a configuration file where the `bind` directive is set in order to guarantee that Redis listens on only the network interfaces you are using. For example only the loopback interface (127.0.0.1) if you are accessing Redis just locally from the same computer, and so forth. -3. Use the `requirepass` option in order to add an additional layer of security so that clients will require to authenticate using the `AUTH` command. -4. Use [spiped](http://www.tarsnap.com/spiped.html) or another SSL tunneling software in order to encrypt traffic between Redis servers and Redis clients if your environment requires encryption. +2. Use a configuration file where the `bind` directive is set in order to guarantee that Redis listens on only the network interfaces you are using. For example, only the loopback interface (127.0.0.1) if you are accessing Redis locally from the same computer. +3. Use the `requirepass` option to add an additional layer of security so that clients will be required to authenticate using the `AUTH` command. +4. Use [spiped](http://www.tarsnap.com/spiped.html) or another SSL tunneling software to encrypt traffic between Redis servers and Redis clients if your environment requires encryption. -Note that a Redis instance exposed to the internet without any security [is very simple to exploit](http://antirez.com/news/96), so make sure you understand the above and apply **at least** a firewall layer. After the firewall is in place, try to connect with `redis-cli` from an external host in order to prove yourself the instance is actually not reachable. +Note that a Redis instance exposed to the internet without any security [is very simple to exploit](http://antirez.com/news/96), so make sure you understand the above and apply **at least** a firewall layer. After the firewall is in place, try to connect with `redis-cli` from an external host to confirm that the instance is not reachable. ## Use Redis from your application -Of course using Redis just from the command line interface is not enough as the goal is to use it from your application. In order to do so you need to download and install a Redis client library for your programming language. +Of course using Redis just from the command line interface is not enough as the goal is to use it from your application. To do so, you need to download and install a Redis client library for your programming language. You'll find a [full list of clients for different languages in this page](/clients). ## Redis persistence -You can learn [how Redis persistence works on this page](/docs/management/persistence/), however what is important to understand for a quick start is that by default, if you start Redis with the default configuration, Redis will spontaneously save the dataset only from time to time (for instance after at least five minutes if you have at least 100 changes in your data), so if you want your database to persist and be reloaded after a restart make sure to call the **SAVE** command manually every time you want to force a data set snapshot. Otherwise make sure to shutdown the database using the **SHUTDOWN** command: +You can learn [how Redis persistence works on this page](/docs/management/persistence/). It is important to understand that, if you start Redis with the default configuration, Redis will spontaneously save the dataset only from time to time. For example, after at least five minutes if you have at least 100 changes in your data. If you want your database to persist and be reloaded after a restart make sure to call the **SAVE** command manually every time you want to force a data set snapshot. Alternatively, you can save the data on disk before quitting by using the **SHUTDOWN** command: ``` $ redis-cli shutdown ``` -This way Redis will make sure to save the data on disk before quitting. Reading the [persistence page](/docs/management/persistence/) is strongly suggested in order to better understand how Redis persistence works. +This way, Redis will save the data on disk before quitting. Reading the [persistence page](/docs/management/persistence/) is strongly suggested to better understand how Redis persistence works. -## Install Redis more properly +## Install Redis properly Running Redis from the command line is fine just to hack a bit or for development. However, at some point you'll have some actual application to run on a real server. For this kind of usage you have two different choices: @@ -135,8 +136,8 @@ Both the pid file path and the configuration file name depend on the port number * Set the **pidfile** to `/var/run/redis_6379.pid`, modifying the port as necessary. * Change the **port** accordingly. In our example it is not needed as the default port is already `6379`. * Set your preferred **loglevel**. - * Set the **logfile** to `/var/log/redis_6379.log` - * Set the **dir** to `/var/redis/6379` (very important step!) + * Set the **logfile** to `/var/log/redis_6379.log`. + * Set the **dir** to `/var/redis/6379` (very important step!). * Finally, add the new Redis init script to all the default runlevels using the following command: ``` From 908c77de8a95a11cef3dcf4ec4965815d5a0118e Mon Sep 17 00:00:00 2001 From: Binbin Date: Wed, 27 Dec 2023 19:45:55 +0800 Subject: [PATCH 321/377] Fix incorrect output of example in ACL DRYRUN (#2633) In redis/redis#10405, we will check arity first, so the example output is wrong. And in redis/redis#11160, we changed the text. --- commands/acl-dryrun.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/acl-dryrun.md b/commands/acl-dryrun.md index 4a2006979b..78cca1e76d 100644 --- a/commands/acl-dryrun.md +++ b/commands/acl-dryrun.md @@ -8,6 +8,6 @@ This command can be used to test the permissions of a given user without having "OK" > ACL DRYRUN VIRGINIA SET foo bar "OK" -> ACL DRYRUN VIRGINIA GET foo bar -"This user has no permissions to run the 'GET' command" +> ACL DRYRUN VIRGINIA GET foo +"User VIRGINIA has no permissions to run the 'get' command" ``` From a8751ba708ab9237b14af185054f98a961979757 Mon Sep 17 00:00:00 2001 From: Binbin Date: Wed, 27 Dec 2023 19:48:34 +0800 Subject: [PATCH 322/377] Add new pubsub_clients field in INFO (#2624) Added in redis/redis#12849 --- commands/info.md | 1 + 1 file changed, 1 insertion(+) diff --git a/commands/info.md b/commands/info.md index eecacc5f54..856c637a09 100644 --- a/commands/info.md +++ b/commands/info.md @@ -83,6 +83,7 @@ Here is the meaning of all fields in the **clients** section: * `blocked_clients`: Number of clients pending on a blocking call (`BLPOP`, `BRPOP`, `BRPOPLPUSH`, `BLMOVE`, `BZPOPMIN`, `BZPOPMAX`) * `tracking_clients`: Number of clients being tracked (`CLIENT TRACKING`) +* `pubsub_clients`: Number of clients in pubsub mode (`SUBSCRIBE`, `PSUBSCRIBE`, `SSUBSCRIBE`). Added in Redis 8.0 * `clients_in_timeout_table`: Number of clients in the clients timeout table * `total_blocking_keys`: Number of blocking keys. Added in Redis 7.2. * `total_blocking_keys_on_nokey`: Number of blocking keys that one or more clients that would like to be unblocked when the key is deleted. Added in Redis 7.2. From d3fdeb6732779e01175014a5f928ebd843f2fc79 Mon Sep 17 00:00:00 2001 From: Lior Kogan Date: Wed, 27 Dec 2023 23:01:18 +0200 Subject: [PATCH 323/377] SET options EX, PX, EXAT, PXAT take positive integer argument (#2617) Clarify that argument is a positive integer, unlike EXPIRE which accepts zero and negative numbers too. --- commands/set.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/commands/set.md b/commands/set.md index 5674b0765d..1dc7322e96 100644 --- a/commands/set.md +++ b/commands/set.md @@ -6,10 +6,10 @@ Any previous time to live associated with the key is discarded on successful `SE The `SET` command supports a set of options that modify its behavior: -* `EX` *seconds* -- Set the specified expire time, in seconds. -* `PX` *milliseconds* -- Set the specified expire time, in milliseconds. -* `EXAT` *timestamp-seconds* -- Set the specified Unix time at which the key will expire, in seconds. -* `PXAT` *timestamp-milliseconds* -- Set the specified Unix time at which the key will expire, in milliseconds. +* `EX` *seconds* -- Set the specified expire time, in seconds (a positive integer). +* `PX` *milliseconds* -- Set the specified expire time, in milliseconds (a positive integer). +* `EXAT` *timestamp-seconds* -- Set the specified Unix time at which the key will expire, in seconds (a positive integer). +* `PXAT` *timestamp-milliseconds* -- Set the specified Unix time at which the key will expire, in milliseconds (a positive integer). * `NX` -- Only set the key if it does not already exist. * `XX` -- Only set the key if it already exists. * `KEEPTTL` -- Retain the time to live associated with the key. From 98dd3843f3e3cb1baa2796fe38f5fa2746c35417 Mon Sep 17 00:00:00 2001 From: Binbin Date: Sun, 31 Dec 2023 14:21:11 +0800 Subject: [PATCH 324/377] Add some missing INFO fields about FUNCTION (#2599) Info fields from the rearrangement of scripts when functions were introduced. see redis/redis#9780 --------- Co-authored-by: Oran Agra --- commands/info.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/commands/info.md b/commands/info.md index 856c637a09..27dd23fb31 100644 --- a/commands/info.md +++ b/commands/info.md @@ -112,9 +112,18 @@ Here is the meaning of all fields in the **memory** section: the net memory usage (`used_memory` minus `used_memory_startup`) * `total_system_memory`: The total amount of memory that the Redis host has * `total_system_memory_human`: Human readable representation of previous value -* `used_memory_lua`: Number of bytes used by the Lua engine -* `used_memory_lua_human`: Human readable representation of previous value -* `used_memory_scripts`: Number of bytes used by cached Lua scripts +* `used_memory_lua`: Number of bytes used by the Lua engine for EVAL scripts. Deprecated in Redis 7.0, renamed to `used_memory_vm_eval` +* `used_memory_vm_eval`: Number of bytes used by the script VM engines for EVAL framework (not part of used_memory). Added in Redis 7.0 +* `used_memory_lua_human`: Human readable representation of previous value. Deprecated in Redis 7.0 +* `used_memory_scripts_eval`: Number of bytes overhead by the EVAL scripts (part of used_memory). Added in Redis 7.0 +* `number_of_cached_scripts`: The number of EVAL scripts cached by the server. Added in Redis 7.0 +* `number_of_functions`: The number of functions. Added in Redis 7.0 +* `number_of_libraries`: The number of libraries. Added in Redis 7.0 +* `used_memory_vm_functions`: Number of bytes used by the script VM engines for Functions framework (not part of used_memory). Added in Redis 7.0 +* `used_memory_vm_total`: `used_memory_vm_eval` + `used_memory_vm_functions` (not part of used_memory). Added in Redis 7.0 +* `used_memory_vm_total_human`: Human readable representation of previous value. +* `used_memory_functions`: Number of bytes overhead by Function scripts (part of used_memory). Added in Redis 7.0 +* `used_memory_scripts`: `used_memory_scripts_eval` + `used_memory_functions` (part of used_memory). Added in Redis 7.0 * `used_memory_scripts_human`: Human readable representation of previous value * `maxmemory`: The value of the `maxmemory` configuration directive * `maxmemory_human`: Human readable representation of previous value From 7c5a901414c5af4aefd2c1b1761a496b9c796677 Mon Sep 17 00:00:00 2001 From: Lukasz Dobrzanski Date: Tue, 2 Jan 2024 15:49:22 +0000 Subject: [PATCH 325/377] Update `maxclients` directive in `redis.conf` info/wording (#2631) * Update `maxclients` directive in `redis.conf` info/wording. * Update redis.conf:`maxclients` directive docs/reference/clients.md Co-authored-by: David Dougherty * Update docs/reference/clients.md --------- Co-authored-by: David Dougherty --- docs/reference/clients.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/reference/clients.md b/docs/reference/clients.md index b71007c3f2..45dbcb1608 100644 --- a/docs/reference/clients.md +++ b/docs/reference/clients.md @@ -47,8 +47,7 @@ However, Redis does the following two things when serving clients: In Redis 2.4 there was a hard-coded limit for the maximum number of clients that could be handled simultaneously. -In Redis 2.6 and newer, this limit is dynamic: by default it is set to 10000 clients, unless -otherwise stated by the `maxclients` directive in `redis.conf`. +In Redis 2.6 and newer, this limit is configurable using the `maxclients` directive in `redis.conf`. The default is 10,000 clients. However, Redis checks with the kernel what the maximum number of file descriptors that we are able to open is (the *soft limit* is checked). If the From b990e9f27e4a64bcbee6b77b7d3f25ca1fc6ac63 Mon Sep 17 00:00:00 2001 From: nihohit Date: Fri, 5 Jan 2024 12:04:53 +0200 Subject: [PATCH 326/377] Expand docs about multi-shard (#2493) Add example and more details about multi-shard request policy in command tips page. --- docs/reference/command-tips.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/reference/command-tips.md b/docs/reference/command-tips.md index 090c1e7e0b..5a373624d7 100644 --- a/docs/reference/command-tips.md +++ b/docs/reference/command-tips.md @@ -50,7 +50,9 @@ In cases where the client should adopt a behavior different than the default, th This tip is in-use by commands that don't accept key name arguments. The command operates atomically per shard. - **multi_shard:** the client should execute the command on several shards. - The shards that execute the command are determined by the hash slots of its input key name arguments. + The client should split the inputs according to the hash slots of its input key name arguments. + For example, the command `DEL {foo} {foo}1 bar` should be split to `DEL {foo} {foo}1` and `DEL bar`. + If the keys are hashed to more than a single slot, the command must be split even if all the slots are managed by the same shard. Examples for such commands include `MSET`, `MGET` and `DEL`. However, note that `SUNIONSTORE` isn't considered as _multi_shard_ because all of its keys must belong to the same hash slot. - **special:** indicates a non-trivial form of the client's request policy, such as the `SCAN` command. From 77e0025e4a2d1fb4580a600c9d4ad1dc6f9c3113 Mon Sep 17 00:00:00 2001 From: Jamie Snell Date: Fri, 5 Jan 2024 04:12:31 -0600 Subject: [PATCH 327/377] Grammar - Add missing 'and' (#2491) --- commands/memory-usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/memory-usage.md b/commands/memory-usage.md index 54b17e7d74..b436292373 100644 --- a/commands/memory-usage.md +++ b/commands/memory-usage.md @@ -2,7 +2,7 @@ The `MEMORY USAGE` command reports the number of bytes that a key and its value require to be stored in RAM. The reported usage is the total of memory allocations for data and -administrative overheads that a key its value require. +administrative overheads that a key and its value require. For nested data types, the optional `SAMPLES` option can be provided, where `count` is the number of sampled nested values. The samples are averaged to estimate the total size. From 8663f15b294e87f41b7d42d05fee1ec2f1714443 Mon Sep 17 00:00:00 2001 From: Igor Malinovskiy Date: Fri, 5 Jan 2024 11:21:24 +0100 Subject: [PATCH 328/377] Clarify meaning of numlocal param in WAITAOF command (#2446) --- commands/waitaof.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/commands/waitaof.md b/commands/waitaof.md index 5b824342a5..a6269e2375 100644 --- a/commands/waitaof.md +++ b/commands/waitaof.md @@ -1,4 +1,9 @@ This command blocks the current client until all previous write commands by that client are acknowledged as having been fsynced to the AOF of the local Redis and/or at least the specified number of replicas. + +`numlocal` represents the number of local fsyncs required to be confirmed before proceeding. +When `numlocal` is set to 1, the command blocks until the data written to the Redis instance is confirmed to be persisted to the local AOF file. +The value 0 disables this check. + If the timeout, specified in milliseconds, is reached, the command returns even if the specified number of acknowledgments has not been met. The command **will always return** the number of masters and replicas that have fsynced all write commands sent by the current client before the `WAITAOF` command, both in the case where the specified thresholds were met, and when the timeout is reached. From c582783b304d8d08827c5906aaab7586f2bab5f1 Mon Sep 17 00:00:00 2001 From: Binbin Date: Wed, 10 Jan 2024 20:39:44 +0800 Subject: [PATCH 329/377] Update FUNCTION LIST example to mention output has flags (#2642) --- docs/interact/programmability/functions-intro.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/interact/programmability/functions-intro.md b/docs/interact/programmability/functions-intro.md index b4dc77033c..7d7d8e2543 100644 --- a/docs/interact/programmability/functions-intro.md +++ b/docs/interact/programmability/functions-intro.md @@ -272,14 +272,20 @@ redis> FUNCTION LIST 2) "my_hset" 3) "description" 4) (nil) + 5) "flags" + 6) (empty array) 2) 1) "name" 2) "my_hgetall" 3) "description" 4) (nil) + 5) "flags" + 6) (empty array) 3) 1) "name" 2) "my_hlastmodified" 3) "description" 4) (nil) + 5) "flags" + 6) (empty array) ``` You can see that it is easy to update our library with new capabilities. From dfac80808209feb5da70b3024ab495c673d743d1 Mon Sep 17 00:00:00 2001 From: Binbin Date: Thu, 11 Jan 2024 21:41:08 +0800 Subject: [PATCH 330/377] Fix outdated incorrect example in function delete (#2644) The command format is using the old one and it is outdated. Shebank is added and FUNCTION LOAD returns the lib name. --- commands/function-delete.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/function-delete.md b/commands/function-delete.md index f2c8e1439b..557ce4d1c3 100644 --- a/commands/function-delete.md +++ b/commands/function-delete.md @@ -8,8 +8,8 @@ For more information please refer to [Introduction to Redis Functions](/topics/f @examples ``` -redis> FUNCTION LOAD Lua mylib "redis.register_function('myfunc', function(keys, args) return 'hello' end)" -OK +redis> FUNCTION LOAD "#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return 'hello' end)" +"mylib" redis> FCALL myfunc 0 "hello" redis> FUNCTION DELETE mylib From 4f0fcdb5096ba964f2b7d9f3a2996c06d00de339 Mon Sep 17 00:00:00 2001 From: Chen Tianjie Date: Fri, 12 Jan 2024 11:59:13 +0800 Subject: [PATCH 331/377] Update keys.bytes-per-key. (#2638) --- commands/memory-stats.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/commands/memory-stats.md b/commands/memory-stats.md index 99ff8ca01d..f058696645 100644 --- a/commands/memory-stats.md +++ b/commands/memory-stats.md @@ -29,8 +29,7 @@ values. The following metrics are reported: Redis keyspace (see `INFO`'s `used_memory_overhead`) * `keys.count`: The total number of keys stored across all databases in the server -* `keys.bytes-per-key`: The ratio between **net memory usage** (`total.allocated` - minus `startup.allocated`) and `keys.count` +* `keys.bytes-per-key`: The ratio between `dataset.bytes` and `keys.count` * `dataset.bytes`: The size in bytes of the dataset, i.e. `overhead.total` subtracted from `total.allocated` (see `INFO`'s `used_memory_dataset`) * `dataset.percentage`: The percentage of `dataset.bytes` out of the total From 12c4317d5e18977553a0971515eb601496e7928e Mon Sep 17 00:00:00 2001 From: Valentino Geron Date: Tue, 16 Jan 2024 16:33:56 +0200 Subject: [PATCH 332/377] Add note for building redis with TLS support (#2641) * Add note for building redis with TLS support * Update docs/install/install-redis/install-redis-from-source.md Co-authored-by: David Dougherty --------- Co-authored-by: David Dougherty --- docs/install/install-redis/install-redis-from-source.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/install/install-redis/install-redis-from-source.md b/docs/install/install-redis/install-redis-from-source.md index 2d8e2623cd..b782f6e450 100644 --- a/docs/install/install-redis/install-redis-from-source.md +++ b/docs/install/install-redis/install-redis-from-source.md @@ -30,6 +30,12 @@ cd redis-stable make {{< / highlight >}} +To build with TLS support, you'll need to install OpenSSL development libraries (e.g., libssl-dev on Debian/Ubuntu) and then run: + +{{< highlight bash >}} +make BUILD_TLS=yes +{{< / highlight >}} + If the compile succeeds, you'll find several Redis binaries in the `src` directory, including: * **redis-server**: the Redis Server itself @@ -53,4 +59,4 @@ If successful, you'll see the startup logs for Redis, and Redis will be running To stop Redis, enter `Ctrl-C`. -For a more complete installation, continue with [these instructions](/docs/install/#install-redis-more-properly). \ No newline at end of file +For a more complete installation, continue with [these instructions](/docs/install/#install-redis-more-properly). From 00cdad86d2249f08f5d54f098cdc427c60f302af Mon Sep 17 00:00:00 2001 From: Savannah Date: Tue, 16 Jan 2024 10:33:54 -0500 Subject: [PATCH 333/377] Update bitmaps.md (#2561) * Update bitmaps.md update bitmaps data type page to include hugo short code - condensed example and added relevant context * Update bitmaps.md to incorporate feedback from PR * fixing hugo short codes * add clarity around sensors on bikes --- docs/data-types/bitmaps.md | 49 ++++++++++++-------------------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/docs/data-types/bitmaps.md b/docs/data-types/bitmaps.md index 0d45d4fc67..d71ea742f1 100644 --- a/docs/data-types/bitmaps.md +++ b/docs/data-types/bitmaps.md @@ -1,4 +1,4 @@ ---- +--- title: "Redis bitmaps" linkTitle: "Bitmaps" weight: 120 @@ -21,37 +21,30 @@ Some examples of bitmap use cases include: * `SETBIT` sets a bit at the provided offset to 0 or 1. * `GETBIT` returns the value of a bit at a given offset. -* `BITOP` lets you perform bitwise operations against one or more strings. See the [complete list of bitmap commands](https://redis.io/commands/?group=bitmap). -## Examples +## Example -Suppose you have 1000 sensors deployed in the field, labeled 0-999. -You want to quickly determine whether a given sensor has pinged the server within the hour. +Suppose you have 1000 cyclists racing through the country-side, with sensors on their bikes labeled 0-999. +You want to quickly determine whether a given sensor has pinged a tracking server within the hour to check in on a rider. You can represent this scenario using a bitmap whose key references the current hour. -* Sensor 123 pings the server on January 1, 2024 within the 00:00 hour. -``` +* Rider 123 pings the server on January 1, 2024 within the 00:00 hour. You can then confirm that rider 123 pinged the server. You can also check to see if rider 456 has pinged the server for that same hour. + +{{< clients-example bitmap_tutorial ping >}} > SETBIT pings:2024-01-01-00:00 123 1 (integer) 0 -``` - -* Did sensor 123 ping the server on January 1, 2024 within the 00:00 hour? -``` > GETBIT pings:2024-01-01-00:00 123 1 -``` - -* What about sensor 456? -``` > GETBIT pings:2024-01-01-00:00 456 0 -``` +{{< /clients-example >}} +## Bit Operations Bit operations are divided into two groups: constant-time single bit operations, like setting a bit to 1 or 0, or getting its value, and @@ -64,15 +57,6 @@ where different users are represented by incremental user IDs, it is possible to remember a single bit information (for example, knowing whether a user wants to receive a newsletter) of 4 billion users using just 512 MB of memory. -Bits are set and retrieved using the `SETBIT` and `GETBIT` commands: - - > setbit key 10 1 - (integer) 0 - > getbit key 10 - (integer) 1 - > getbit key 11 - (integer) 0 - The `SETBIT` command takes as its first argument the bit number, and as its second argument the value to set the bit to, which is 1 or 0. The command automatically enlarges the string if the addressed bit is outside the @@ -89,15 +73,12 @@ There are three commands operating on group of bits: 3. `BITPOS` finds the first bit having the specified value of 0 or 1. Both `BITPOS` and `BITCOUNT` are able to operate with byte ranges of the -string, instead of running for the whole length of the string. The following -is a trivial example of `BITCOUNT` call: - - > setbit key 0 1 - (integer) 0 - > setbit key 100 1 - (integer) 0 - > bitcount key - (integer) 2 +string, instead of running for the whole length of the string. We can trivially see the number of bits that have been set in a bitmap. + +{{< clients-example bitmap_tutorial bitcount >}} +> BITCOUNT pings:2024-01-01-00:00 +(integer) 1 +{{< /clients-example >}} For example imagine you want to know the longest streak of daily visits of your web site users. You start counting days starting from zero, that is the From ab5db30ca9d0d5f4dea83b16fbea80d931e5fd38 Mon Sep 17 00:00:00 2001 From: Savannah Date: Tue, 16 Jan 2024 10:40:27 -0500 Subject: [PATCH 334/377] Update bitfields.md (#2560) * Update bitfields.md update bitfields data type page to include hugo short code - condense example and add relevant context * Update bitfields.md to incorporate feedback on PR * Update docs/data-types/bitfields.md Co-authored-by: David Dougherty --------- Co-authored-by: David Dougherty --- docs/data-types/bitfields.md | 42 +++++++++++++----------------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/docs/data-types/bitfields.md b/docs/data-types/bitfields.md index fb74fc5d1f..0f693c2277 100644 --- a/docs/data-types/bitfields.md +++ b/docs/data-types/bitfields.md @@ -21,37 +21,25 @@ Bitfields support atomic read, write and increment operations, making them a goo ## Examples -Suppose you're keeping track of activity in an online game. -You want to maintain two crucial metrics for each player: the total amount of gold and the number of monsters slain. -Because your game is highly addictive, these counters should be at least 32 bits wide. +## Example -You can represent these counters with one bitfield per player. +Suppose you want to maintain two metrics for various bicycles: the current price and the number of owners over time. You can represent these counters with a 32-bit wide bitfield per for each bike. -* New players start the tutorial with 1000 gold (counter in offset 0). -``` -> BITFIELD player:1:stats SET u32 #0 1000 -1) (integer) 0 -``` +* Bike 1 initially costs 1,000 (counter in offset 0) and has never had an owner. After being sold, it's now considered used and the price instantly drops to reflect its new condition, and it now has an owner (offset 1). After quite some time, the bike becomes a classic. The original owner sells it for a profit, so the price goes up and the number of owners does as well.Finally, you can look at the bike's current price and number of owners. -* After killing the goblin holding the prince captive, add the 50 gold earned and increment the "slain" counter (offset 1). -``` -> BITFIELD player:1:stats INCRBY u32 #0 50 INCRBY u32 #1 1 -1) (integer) 1050 -2) (integer) 1 -``` - -* Pay the blacksmith 999 gold to buy a legendary rusty dagger. -``` -> BITFIELD player:1:stats INCRBY u32 #0 -999 -1) (integer) 51 -``` - -* Read the player's stats: -``` -> BITFIELD player:1:stats GET u32 #0 GET u32 #1 -1) (integer) 51 +{{< clients-example bitfield_tutorial bf >}} +> BITFIELD bike:1:stats SET u32 #0 1000 +1) (integer) 0 +> BITFIELD bike:1:stats INCRBY u32 #0 -50 INCRBY u32 #1 1 +1) (integer) 950 2) (integer) 1 -``` +> BITFIELD bike:1:stats INCRBY u32 #0 500 INCRBY u32 #1 1 +1) (integer) 1450 +2) (integer) 2 +> BITFIELD bike:1:stats GET u32 #0 GET u32 #1 +1) (integer) 1450 +2) (integer) 2 +{{< /clients-example >}} ## Performance From e54befcd8fc3fd6930bbf93bff45913d0c2da853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Svensson?= Date: Tue, 16 Jan 2024 17:49:14 +0100 Subject: [PATCH 335/377] Add notes of `:0@0` addresses in `CLUSTER NODES` (#2643) --- commands/cluster-nodes.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/commands/cluster-nodes.md b/commands/cluster-nodes.md index 3f5499ca0e..a802fe7cff 100644 --- a/commands/cluster-nodes.md +++ b/commands/cluster-nodes.md @@ -38,7 +38,8 @@ Each line is composed of the following fields: The meaning of each field is the following: 1. `id`: The node ID, a 40-character globally unique string generated when a node is created and never changed again (unless `CLUSTER RESET HARD` is used). -2. `ip:port@cport`: The node address that clients should contact to run queries. +2. `ip:port@cport`: The node address that clients should contact to run queries, along with the used cluster bus port. + `:0@0` can be expected when the address is no longer known for this node ID, hence flagged with `noaddr`. 3. `hostname`: A human readable string that can be configured via the `cluster-annouce-hostname` setting. The max length of the string is 256 characters, excluding the null terminator. The name can contain ASCII alphanumeric characters, '-', and '.' only. 5. `flags`: A list of comma separated flags: `myself`, `master`, `slave`, `fail?`, `fail`, `handshake`, `noaddr`, `nofailover`, `noflags`. Flags are explained below. 6. `master`: If the node is a replica, and the primary is known, the primary node ID, otherwise the "-" character. From 59db4e32546857f3f82597ca929088bc494c934e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20S=C3=B6derqvist?= Date: Thu, 18 Jan 2024 09:43:44 +0100 Subject: [PATCH 336/377] Explain patterns with hash tags in cluster spec (#2646) Adding to the cluster spec documentation of the following Redis features: redis/redis#12754 (SCAN) redis/redis#12536 (KEYS) redis/redis#12728 (SORT, SORT_RO) --- docs/reference/cluster-spec.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/reference/cluster-spec.md b/docs/reference/cluster-spec.md index 64c8016980..6a1eb47cc4 100644 --- a/docs/reference/cluster-spec.md +++ b/docs/reference/cluster-spec.md @@ -199,6 +199,23 @@ Examples: * For the key `foo{bar}{zap}` the substring `bar` will be hashed, since the algorithm stops at the first valid or invalid (without bytes inside) match of `{` and `}`. * What follows from the algorithm is that if the key starts with `{}`, it is guaranteed to be hashed as a whole. This is useful when using binary data as key names. +#### Glob-style patterns + +Commands accepting a glob-style pattern, including `KEYS`, `SCAN` and `SORT`, are optimized for patterns that imply a single slot. +This means that if all keys that can match a pattern must belong to a specific slot, only this slot is searched for keys matching the pattern. +The pattern slot optimization is introduced in Redis 8.0. + +The optimization kicks in when the pattern meets the following conditions: + +* the pattern contains a hashtag, +* there are no wildcards or escape characters before the hashtag, and +* the hashtag within curly braces doesn't contain any wildcards or escape characters. + +For example, `SCAN 0 MATCH {abc}*` can successfully recognize the hashtag and scans only the slot corresponding to `abc`. +However, the patterns `*{abc}`, `{a*c}`, or `{a\*bc}` cannot recognize the hashtag, so all slots need to be scanned. + +#### Hash slot example code + Adding the hash tags exception, the following is an implementation of the `HASH_SLOT` function in Ruby and C language. Ruby example code: From 68992d7653d34ac83969339c774cf1922143897b Mon Sep 17 00:00:00 2001 From: Igor Malinovskiy Date: Mon, 22 Jan 2024 12:27:09 +0100 Subject: [PATCH 337/377] Add "Production usage" section to Jedis quick start (#2636) --- docs/connect/clients/java.md | 164 ++++++++++++++++++++--------------- 1 file changed, 92 insertions(+), 72 deletions(-) diff --git a/docs/connect/clients/java.md b/docs/connect/clients/java.md index 1258b9817c..abe3b13d71 100644 --- a/docs/connect/clients/java.md +++ b/docs/connect/clients/java.md @@ -187,104 +187,124 @@ public class Main { } ``` -### Example: Indexing and querying JSON documents +### Production usage -Make sure that you have Redis Stack and `Jedis` installed. +### Configuring Connection pool +As mentioned in the previous section, use `JedisPool` or `JedisPooled` to create a connection pool. +`JedisPooled`, added in Jedis version 4.0.0, provides capabilities similar to `JedisPool` but with a more straightforward API. +A connection pool holds a specified number of connections, creates more connections when necessary, and terminates them when they are no longer needed. -Import dependencies and add a sample `User` class: +Here is a simplified connection lifecycle in a pool: -```java -import redis.clients.jedis.JedisPooled; -import redis.clients.jedis.search.*; -import redis.clients.jedis.search.aggr.*; -import redis.clients.jedis.search.schemafields.*; - -class User { - private String name; - private String email; - private int age; - private String city; - - public User(String name, String email, int age, String city) { - this.name = name; - this.email = email; - this.age = age; - this.city = city; - } - - //... -} -``` +1. A connection is requested from the pool. +2. A connection is served: + - An idle connection is served when non-active connections are available, or + - A new connection is created when the number of connections is under `maxTotal`. +3. The connection becomes active. +4. The connection is released back to the pool. +5. The connection is marked as stale. +6. The connection is kept idle for `minEvictableIdleTime`. +7. The connection becomes evictable if the number of connections is greater than `minIdle`. +8. The connection is ready to be closed. -Connect to your Redis database with `JedisPooled`. +It's important to configure the connection pool correctly. +Use `GenericObjectPoolConfig` from [Apache Commons Pool2](https://commons.apache.org/proper/commons-pool/apidocs/org/apache/commons/pool2/impl/GenericObjectPoolConfig.html). ```java -JedisPooled jedis = new JedisPooled("localhost", 6379); +ConnectionPoolConfig poolConfig = new ConnectionPoolConfig(); +// maximum active connections in the pool, +// tune this according to your needs and application type +// default is 8 +poolConfig.setMaxTotal(8); + +// maximum idle connections in the pool, default is 8 +poolConfig.setMaxIdle(8); +// minimum idle connections in the pool, default 0 +poolConfig.setMinIdle(0); + +// Enables waiting for a connection to become available. +poolConfig.setBlockWhenExhausted(true); +// The maximum number of seconds to wait for a connection to become available +poolConfig.setMaxWait(Duration.ofSeconds(1)); + +// Enables sending a PING command periodically while the connection is idle. +poolConfig.setTestWhileIdle(true); +// controls the period between checks for idle connections in the pool +poolConfig.setTimeBetweenEvictionRuns(Duration.ofSeconds(1)); + +// JedisPooled does all hard work on fetching and releasing connection to the pool +// to prevent connection starvation +JedisPooled jedis = new JedisPooled(poolConfig, "localhost", 6379); ``` -Let's create some test data to add to your database. - -```java -User user1 = new User("Paul John", "paul.john@example.com", 42, "London"); -User user2 = new User("Eden Zamir", "eden.zamir@example.com", 29, "Tel Aviv"); -User user3 = new User("Paul Zamir", "paul.zamir@example.com", 35, "Tel Aviv"); -``` +### Timeout -Create an index. In this example, all JSON documents with the key prefix `user:` are indexed. For more information, see [Query syntax](/docs/interact/search-and-query/query/). +To set a timeout for a connection, use the `JedisPooled` or `JedisPool` constructor with the `timeout` parameter, or use `JedisClientConfig` with the `socketTimeout` and `connectionTimeout` parameters: ```java -jedis.ftCreate("idx:users", - FTCreateParams.createParams() - .on(IndexDataType.JSON) - .addPrefix("user:"), - TextField.of("$.name").as("name"), - TagField.of("$.city").as("city"), - NumericField.of("$.age").as("age") +HostAndPort hostAndPort = new HostAndPort("localhost", 6379); + +JedisPooled jedisWithTimeout = new JedisPooled(hostAndPort, + DefaultJedisClientConfig.builder() + .socketTimeoutMillis(5000) // set timeout to 5 seconds + .connectionTimeoutMillis(5000) // set connection timeout to 5 seconds + .build(), + poolConfig ); ``` -Use `JSON.SET` to set each user value at the specified path. +### Exception handling +The Jedis Exception Hierarchy is rooted on `JedisException`, which implements `RuntimeException`, and are therefore all unchecked exceptions. -```java -jedis.jsonSetWithEscape("user:1", user1); -jedis.jsonSetWithEscape("user:2", user2); -jedis.jsonSetWithEscape("user:3", user3); +``` +JedisException +├── JedisDataException +│ ├── JedisRedirectionException +│ │ ├── JedisMovedDataException +│ │ └── JedisAskDataException +│ ├── AbortedTransactionException +│ ├── JedisAccessControlException +│ └── JedisNoScriptException +├── JedisClusterException +│ ├── JedisClusterOperationException +│ ├── JedisConnectionException +│ └── JedisValidationException +└── InvalidURIException ``` -Let's find user `Paul` and filter the results by age. +#### General Exceptions +In general, Jedis can throw the following exceptions while executing commands: -```java -var query = new Query("Paul @age:[30 40]"); -var result = jedis.ftSearch("idx:users", query).getDocuments(); -System.out.println(result); -// Prints: [id:user:3, score: 1.0, payload:null, properties:[$={"name":"Paul Zamir","email":"paul.zamir@example.com","age":35,"city":"Tel Aviv"}]] -``` +- `JedisConnectionException` - when the connection to Redis is lost or closed unexpectedly. Configure failover to handle this exception automatically with Resilience4J and the built-in Jedis failover mechanism. +- `JedisAccessControlException` - when the user does not have the permission to execute the command or the user ID and/or password are incorrect. +- `JedisDataException` - when there is a problem with the data being sent to or received from the Redis server. Usually, the error message will contain more information about the failed command. +- `JedisException` - this exception is a catch-all exception that can be thrown for any other unexpected errors. -Return only the `city` field. +Conditions when `JedisException` can be thrown: +- Bad return from a health check with the `PING` command +- Failure during SHUTDOWN +- Pub/Sub failure when issuing commands (disconnect) +- Any unknown server messages +- Sentinel: can connect to sentinel but master is not monitored or all Sentinels are down. +- MULTI or DISCARD command failed +- Shard commands key hash check failed or no Reachable Shards +- Retry deadline exceeded/number of attempts (Retry Command Executor) +- POOL - pool exhausted, error adding idle objects, returning broken resources to the pool -```java -var city_query = new Query("Paul @age:[30 40]"); -var city_result = jedis.ftSearch("idx:users", city_query.returnFields("city")).getDocuments(); -System.out.println(city_result); -// Prints: [id:user:3, score: 1.0, payload:null, properties:[city=Tel Aviv]] -``` +All the Jedis exceptions are runtime exceptions and in most cases irrecoverable, so in general bubble up to the API capturing the error message. -Count all users in the same city. +## DNS cache and Redis -```java -AggregationBuilder ab = new AggregationBuilder("*") - .groupBy("@city", Reducers.count().as("count")); -AggregationResult ar = jedis.ftAggregate("idx:users", ab); +When you connect to a Redis with multiple endpoints, such as [Redis Enterprise Active-Active](https://redis.com/redis-enterprise/technology/active-active-geo-distribution/), it's recommended to disable the JVM's DNS cache to load-balance requests across multiple endpoints. -for (int idx=0; idx < ar.getTotalResults(); idx++) { - System.out.println(ar.getRow(idx).getString("city") + " - " + ar.getRow(idx).getString("count")); -} -// Prints: -// London - 1 -// Tel Aviv - 2 +You can do this in your application's code with the following snippet: +```java +java.security.Security.setProperty("networkaddress.cache.ttl","0"); +java.security.Security.setProperty("networkaddress.cache.negative.ttl", "0"); ``` ### Learn more * [Jedis API reference](https://www.javadoc.io/doc/redis.clients/jedis/latest/index.html) +* [Failover with Jedis](https://github.com/redis/jedis/blob/master/docs/failover.md) * [GitHub](https://github.com/redis/jedis) From 44a5a0f7c64be18ca9435d91a7797e2ccfe69997 Mon Sep 17 00:00:00 2001 From: domgew <44265359+domgew@users.noreply.github.com> Date: Sat, 27 Jan 2024 18:35:25 +0100 Subject: [PATCH 338/377] Add Kedis (Kotlin Multiplatform redis client library) --- clients/kotlin/github.com/domgew/kedis.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 clients/kotlin/github.com/domgew/kedis.json diff --git a/clients/kotlin/github.com/domgew/kedis.json b/clients/kotlin/github.com/domgew/kedis.json new file mode 100644 index 0000000000..1d83baed85 --- /dev/null +++ b/clients/kotlin/github.com/domgew/kedis.json @@ -0,0 +1,4 @@ +{ + "name": "Kedis", + "description": "Redis client library for Kotlin Multiplatform (JVM + Native)" +} \ No newline at end of file From f0fc05d56d2bb85458661e9bab0d2e3ffd7875fd Mon Sep 17 00:00:00 2001 From: Chen Tianjie Date: Mon, 29 Jan 2024 14:20:53 +0800 Subject: [PATCH 339/377] Update info docs with two buffer limit metrics. (#2520) Add explains about "client_query_buffer_limit_disconnections" and "client_output_buffer_limit_disconnections". Correct "reply_buffer_shrinks" and "reply_buffer_expands" name. --- commands/info.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/commands/info.md b/commands/info.md index 27dd23fb31..d216804624 100644 --- a/commands/info.md +++ b/commands/info.md @@ -310,8 +310,10 @@ Here is the meaning of all fields in the **stats** section: * `total_writes_processed`: Total number of write events processed * `io_threaded_reads_processed`: Number of read events processed by the main and I/O threads * `io_threaded_writes_processed`: Number of write events processed by the main and I/O threads -* `stat_reply_buffer_shrinks`: Total number of output buffer shrinks -* `stat_reply_buffer_expands`: Total number of output buffer expands +* `client_query_buffer_limit_disconnections`: Total number of disconnections due to client reaching query buffer limit +* `client_output_buffer_limit_disconnections`: Total number of disconnections due to client reaching output buffer limit +* `reply_buffer_shrinks`: Total number of output buffer shrinks +* `reply_buffer_expands`: Total number of output buffer expands * `eventloop_cycles`: Total number of eventloop cycles * `eventloop_duration_sum`: Total time spent in the eventloop in microseconds (including I/O and command processing) * `eventloop_duration_cmd_sum`: Total time spent on executing commands in microseconds From 6895f84525858aafd0bd76ef35eafd28a01b89e4 Mon Sep 17 00:00:00 2001 From: ViktarStarastsenka <99594890+ViktarStarastsenka@users.noreply.github.com> Date: Wed, 31 Jan 2024 21:20:10 +0100 Subject: [PATCH 340/377] Docker documentation (#2623) * Create install-on-aws * adding description for RedisInsight on Docker * Update configuration.md * Update configuration.md * Update configuration.md * Update install-on-aws.md * Update install-on-aws.md * Update install-on-aws.md * Update install-on-docker.md * Update install-on-aws.md * Update install-on-docker.md * Update install-on-k8s.md * Update configuration.md * Update and rename configuration.md to env_variables.md * Update env_variables.md * Update and rename env_variables.md to env-variables.md * Update env-variables.md * Update install-on-aws.md * Update install-on-docker.md * Update install-on-k8s.md * Update install-on-k8s.md adding the health check * Update install-on-docker.md * Update install-on-aws.md * Update env-variables.md * Update env-variables.md * Update install-on-docker.md * Update install-on-aws.md * Update install-on-docker.md * Update install-on-k8s.md * Update install-on-k8s.md * Updating RedisInsight on Docker * Updating RedisInsight on Docker * Update install-on-aws.md * Update install-on-aws.md * Update install-on-k8s.md * Update env-variables.md * Update install-on-k8s.md * Update env-variables.md * Update install-on-docker.md * Update install-on-aws.md * Update install-on-docker.md * Update install-on-docker.md * Update install-on-aws.md * Update install-on-docker.md * Update env-variables.md --- docs/install/install-redisinsight/_index.md | 9 + .../install-redisinsight/env-variables.md | 19 ++ .../install-redisinsight/install-on-aws.md | 92 ++++++ .../install-redisinsight/install-on-docker.md | 34 +++ .../install-redisinsight/install-on-k8s.md | 267 ++++++++++++++++++ 5 files changed, 421 insertions(+) create mode 100644 docs/install/install-redisinsight/_index.md create mode 100644 docs/install/install-redisinsight/env-variables.md create mode 100644 docs/install/install-redisinsight/install-on-aws.md create mode 100644 docs/install/install-redisinsight/install-on-docker.md create mode 100644 docs/install/install-redisinsight/install-on-k8s.md diff --git a/docs/install/install-redisinsight/_index.md b/docs/install/install-redisinsight/_index.md new file mode 100644 index 0000000000..a45a4defcf --- /dev/null +++ b/docs/install/install-redisinsight/_index.md @@ -0,0 +1,9 @@ +--- +title: "Install RedisInsight" +linkTitle: "Install RedisInsight" +weight: 3 +description: > + Install RedisInsite on AWS, Docker, and Kubernetes +--- + +This is a an installation guide. You'll learn how to install RedisInsight on Amazon Web Services (AWS), Docker, and Kubernetes. \ No newline at end of file diff --git a/docs/install/install-redisinsight/env-variables.md b/docs/install/install-redisinsight/env-variables.md new file mode 100644 index 0000000000..dbf115bcff --- /dev/null +++ b/docs/install/install-redisinsight/env-variables.md @@ -0,0 +1,19 @@ +--- +title: "Environment variables" +linkTitle: "Environment variables" +weight: 1 +description: > + RedisInsight supported environment variables +--- +You can configure RedisInsight with the following environment variables. + +| Variable | Purpose | Default | Additional info | +| --- | --- | --- | --- | +| RI_APP_PORT | The port that RedisInsight listens on |
  • Docker: 5540
  • desktop: 5530
| See [Express Documentation](https://expressjs.com/en/api.html#app.listen)| +| RI_APP_HOST | The host that RedisInsight connects to |
  • Docker: 0.0.0.0
  • desktop: 127.0.0.1
| See [Express Documentation](https://expressjs.com/en/api.html#app.listen)| +| RI_SERVER_TLS_KEY | Private key for HTTPS | n/a | Private key in [PEM format](https://www.ssl.com/guide/pem-der-crt-and-cer-x-509-encodings-and-conversions/#ftoc-heading-3). Can be a path to a file or a string in PEM format.| +| RI_SERVER_TLS_CERT | Certificate for supplied private key | n/a | Public certificate in [PEM format](https://www.ssl.com/guide/pem-der-crt-and-cer-x-509-encodings-and-conversions/#ftoc-heading-3). Can be a path to a file or a string in PEM format.| +| RI_ENCRYPTION_KEY | Key to encrypt data with | n/a | Available only for Docker.
Redisinsight stores sensitive information (database passwords, Workbench history, etc.) locally (using [sqlite3](https://github.com/TryGhost/node-sqlite3)). This variable allows you to store sensitive information encrypted using the specified encryption key.
Note: The same encryption key should be provided for subsequent `docker run` commands with the same volume attached to decrypt the information. | +| RI_LOG_LEVEL | Configures the log level of the application. | `info` | Supported logging levels are prioritized from highest to lowest:
  • error
  • warn
  • info
  • http
  • verbose
  • debug
  • silly
| +| RI_FILES_LOGGER | Log to file | `true` | By default, you can find log files in the following folders:
  • Docker: `/data/logs`
  • desktop: `/.refisinsight-app/logs`
| +| RI_STDOUT_LOGGER | Log to STDOUT | `true` | | diff --git a/docs/install/install-redisinsight/install-on-aws.md b/docs/install/install-redisinsight/install-on-aws.md new file mode 100644 index 0000000000..93fe59299e --- /dev/null +++ b/docs/install/install-redisinsight/install-on-aws.md @@ -0,0 +1,92 @@ +--- +title: "Install on AWS EC2" +linkTitle: "Install on AWS EC2" +weight: 3 +description: > + How to install RedisInsight on AWS EC2 +--- +This tutorial shows you how to install RedisInsight on an AWS EC2 instance and manage ElastiCache Redis instances using RedisInsight. To complete this tutorial you must have access to the AWS Console and permissions to launch EC2 instances. + +Step 1: Create a new IAM Role (optional) +-------------- + +RedisInsight needs read-only access to S3 and ElastiCache APIs. This is an optional step. + +1. Log in to the AWS Console and navigate to the IAM screen. +1. Create a new IAM Role. +1. Under *Select type of trusted entity*, choose EC2. The role is used by an EC2 instance. +1. Assign the following permissions: + * AmazonS3ReadOnlyAccess + * AmazonElastiCacheReadOnlyAccess + +Step 2: Launch EC2 Instance +-------------- + +Next, launch an EC2 instance. + +1. Navigate to EC2 under AWS Console. +1. Click Launch Instance. +1. Choose 64-bit Amazon Linux AMI. +1. Choose at least a t2.medium instance. The size of the instance depends on the memory used by your ElastiCache instance that you want to analyze. +1. Under Configure Instance: + * Choose the VPC that has your ElastiCache instances. + * Choose a subnet that has network access to your ElastiCache instances. + * Ensure that your EC2 instance has a public IP Address. + * Assign the IAM role that you created in Step 1. +1. Under the storage section, allocate at least 100 GiB storage. +1. Under security group, ensure that: + * Incoming traffic is allowed on port 5540 + * Incoming traffic is allowed on port 22 only during installation +1. Review and launch the ec2 instance. + +Step 3: Verify permissions and connectivity +---------- + +Next, verify that the EC2 instance has the required IAM permissions and can connect to ElastiCache Redis instances. + +1. SSH into the newly launched EC2 instance. +1. Open a command prompt. +1. Run the command `aws s3 ls`. This should list all S3 buckets. + 1. If the `aws` command cannot be found, make sure your EC2 instance is based of Amazon Linux. +1. Next, find the hostname of the ElastiCache instance you want to analyze and run the command `echo info | nc 6379`. +1. If you see some details about the ElastiCache Redis instance, you can proceed to the next step. +1. If you cannot connect to redis, you should review your VPC, subnet, and security group settings. + +Step 4: Install Docker on EC2 +------- + +Next, install Docker on the EC2 instance. Run the following commands: + +1. `sudo yum update -y` +1. `sudo yum install -y docker` +1. `sudo service docker start` +1. `sudo usermod -a -G docker ec2-user` +1. Log out and log back in again to pick up the new docker group permissions. +1. To verify, run `docker ps`. You should see some output without having to run `sudo`. + +Step 5: Run RedisInsight in the Docker container +------- + +Finally, install RedisInsight using one of the options described below. + +1. If you do not want to persist your RedisInsight data: + +```bash +docker run -d --name redisinsight -p 5540:5540 redis/redisinsight:latest +``` +2. If you want to persist your RedisInsight data, first attach the Docker volume to the `/data` path and then run the following command: + +```bash +docker run -d --name redisinsight -p 5540:5540 redis/redisinsight:latest -v redisinsight:/data +``` + +If the previous command returns a permission error, ensure that the user with `ID = 1000` has the necessary permission to access the volume provided (`redisinsight` in the command above). + +Find the IP Address of your EC2 instances and launch your browser at `http://:5540`. Accept the EULA and start using RedisInsight. + +RedisInsight also provides a health check endpoint at `http://:5540/api/health/` to monitor the health of the running container. + +Summary +------ + +In this guide, we installed RedisInsight on an AWS EC2 instance running Docker. As a next step, you should add an ElastiCache Redis Instance and then run the memory analysis. diff --git a/docs/install/install-redisinsight/install-on-docker.md b/docs/install/install-redisinsight/install-on-docker.md new file mode 100644 index 0000000000..c73a15ea97 --- /dev/null +++ b/docs/install/install-redisinsight/install-on-docker.md @@ -0,0 +1,34 @@ +--- +title: "Install on Docker" +linkTitle: "Install on Docker" +weight: 2 +description: > + How to install RedisInsight on Docker +--- +This tutorial shows how to install RedisInsight on [Docker](https://www.docker.com/) so you can use RedisInsight in development. +See a separate guide for installing [RedisInsight on AWS](/docs/install/install-redisinsight/install-on-aws/). + +## Install Docker + +The first step is to [install Docker for your operating system](https://docs.docker.com/install/). + +## Run RedisInsight Docker image + +You can install RedisInsight using one of the options described below. + +1. If you do not want to persist your RedisInsight data: + +```bash +docker run -d --name redisinsight -p 5540:5540 redis/redisinsight:latest +``` +2. If you want to persist your RedisInsight data, first attach the Docker volume to the `/data` path and then run the following command: + +```bash +docker run -d --name redisinsight -p 5540:5540 redis/redisinsight:latest -v redisinsight:/data +``` + +If the previous command returns a permission error, ensure that the user with `ID = 1000` has the necessary permissions to access the volume provided (`redisinsight` in the command above). + +Next, point your browser to `http://localhost:5540`. + +RedisInsight also provides a health check endpoint at `http://localhost:5540/api/health/` to monitor the health of the running container. diff --git a/docs/install/install-redisinsight/install-on-k8s.md b/docs/install/install-redisinsight/install-on-k8s.md new file mode 100644 index 0000000000..8a42865fec --- /dev/null +++ b/docs/install/install-redisinsight/install-on-k8s.md @@ -0,0 +1,267 @@ +--- +title: "Install on Kubernetes" +linkTitle: "Install on Kubernetes" +weight: 4 +description: > + How to install RedisInsight on Kubernetes +--- +This tutorial shows how to install RedisInsight on [Kubernetes](https://kubernetes.io/) (K8s). +This is an easy way to use RedisInsight with a [Redis Enterprise K8s deployment](https://redis.io/docs/about/redis-enterprise/#:~:text=and%20Multi%2Dcloud-,Redis%20Enterprise%20Software,-Redis%20Enterprise%20Software). + +## Create the RedisInsight deployment and service + +Below is an annotated YAML file that will create a RedisInsight +deployment and a service in a K8s cluster. + +1. Create a new file named `redisinsight.yaml` with the content below. + +```yaml +# RedisInsight service with name 'redisinsight-service' +apiVersion: v1 +kind: Service +metadata: + name: redisinsight-service # name should not be 'redisinsight' + # since the service creates + # environment variables that + # conflicts with redisinsight + # application's environment + # variables `RI_APP_HOST` and + # `RI_APP_PORT` +spec: + type: LoadBalancer + ports: + - port: 80 + targetPort: 5540 + selector: + app: redisinsight +--- +# RedisInsight deployment with name 'redisinsight' +apiVersion: apps/v1 +kind: Deployment +metadata: + name: redisinsight #deployment name + labels: + app: redisinsight #deployment label +spec: + replicas: 1 #a single replica pod + selector: + matchLabels: + app: redisinsight #which pods is the deployment managing, as defined by the pod template + template: #pod template + metadata: + labels: + app: redisinsight #label for pod/s + spec: + containers: + + - name: redisinsight #Container name (DNS_LABEL, unique) + image: redis/redisinsight:latest #repo/image + imagePullPolicy: IfNotPresent #Installs the latest RedisInsight version + volumeMounts: + - name: redisinsight #Pod volumes to mount into the container's filesystem. Cannot be updated. + mountPath: /data + ports: + - containerPort: 5540 #exposed container port and protocol + protocol: TCP + volumes: + - name: redisinsight + emptyDir: {} # node-ephemeral volume https://kubernetes.io/docs/concepts/storage/volumes/#emptydir +``` + +2. Create the RedisInsight deployment and service: + +```sh +kubectl apply -f redisinsight.yaml +``` + +3. Once the deployment and service are successfully applied and complete, access RedisInsight. This can be accomplished by using the `` of the service we created to reach RedisInsight. + +```sh +$ kubectl get svc redisinsight-service +NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE +redisinsight-service 80:32143/TCP 1m +``` + +4. If you are using minikube, run `minikube list` to list the service and access RedisInsight at `http://:`. +``` +$ minikube list +|-------------|----------------------|--------------|---------------------------------------------| +| NAMESPACE | NAME | TARGET PORT | URL | +|-------------|----------------------|--------------|---------------------------------------------| +| default | kubernetes | No node port | | +| default | redisinsight-service | 80 | http://: | +| kube-system | kube-dns | No node port | | +|-------------|----------------------|--------------|---------------------------------------------| +``` + +## Create the RedisInsight deployment with persistant storage + +Below is an annotated YAML file that will create a RedisInsight +deployment in a K8s cluster. It will assign a peristent volume created from a volume claim template. +Write access to the container is configured in an init container. When using deployments +with persistent writeable volumes, it's best to set the strategy to `Recreate`. Otherwise you may find yourself +with two pods trying to use the same volume. + +1. Create a new file `redisinsight.yaml` with the content below. + +```yaml +# RedisInsight service with name 'redisinsight-service' +apiVersion: v1 +kind: Service +metadata: + name: redisinsight-service # name should not be 'redisinsight' + # since the service creates + # environment variables that + # conflicts with redisinsight + # application's environment + # variables `RI_APP_HOST` and + # `RI_APP_PORT` +spec: + type: LoadBalancer + ports: + - port: 80 + targetPort: 5540 + selector: + app: redisinsight +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: redisinsight-pv-claim + labels: + app: redisinsight +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + storageClassName: default +--- +# RedisInsight deployment with name 'redisinsight' +apiVersion: apps/v1 +kind: Deployment +metadata: + name: redisinsight #deployment name + labels: + app: redisinsight #deployment label +spec: + replicas: 1 #a single replica pod + strategy: + type: Recreate + selector: + matchLabels: + app: redisinsight #which pods is the deployment managing, as defined by the pod template + template: #pod template + metadata: + labels: + app: redisinsight #label for pod/s + spec: + volumes: + - name: redisinsight + persistentVolumeClaim: + claimName: redisinsight-pv-claim + initContainers: + - name: init + image: busybox + command: + - /bin/sh + - '-c' + - | + chown -R 1001 /data + resources: {} + volumeMounts: + - name: redisinsight + mountPath: /data + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + containers: + - name: redisinsight #Container name (DNS_LABEL, unique) + image: redis/redisinsight:latest #repo/image + imagePullPolicy: IfNotPresent #Always pull image + volumeMounts: + - name: redisinsight #Pod volumes to mount into the container's filesystem. Cannot be updated. + mountPath: /data + ports: + - containerPort: 5540 #exposed container port and protocol + protocol: TCP +``` + +2. Create the RedisInsight deployment and service. + +```sh +kubectl apply -f redisinsight.yaml +``` + +## Create the RedisInsight deployment without a service. + +Below is an annotated YAML file that will create a RedisInsight +deployment in a K8s cluster. + +1. Create a new file redisinsight.yaml with the content below + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: redisinsight #deployment name + labels: + app: redisinsight #deployment label +spec: + replicas: 1 #a single replica pod + selector: + matchLabels: + app: redisinsight #which pods is the deployment managing, as defined by the pod template + template: #pod template + metadata: + labels: + app: redisinsight #label for pod/s + spec: + containers: + - name: redisinsight #Container name (DNS_LABEL, unique) + image: redis/redisinsight:latest #repo/image + imagePullPolicy: IfNotPresent #Always pull image + env: + # If there's a service named 'redisinsight' that exposes the + # deployment, we manually set `RI_APP_HOST` and + # `RI_APP_PORT` to override the service environment + # variables. + - name: RI_APP_HOST + value: "0.0.0.0" + - name: RI_APP_PORT + value: "5540" + volumeMounts: + - name: redisinsight #Pod volumes to mount into the container's filesystem. Cannot be updated. + mountPath: /data + ports: + - containerPort: 5540 #exposed container port and protocol + protocol: TCP + livenessProbe: + httpGet: + path : /healthcheck/ # exposed RI endpoint for healthcheck + port: 5540 # exposed container port + initialDelaySeconds: 5 # number of seconds to wait after the container starts to perform liveness probe + periodSeconds: 5 # period in seconds after which liveness probe is performed + failureThreshold: 1 # number of liveness probe failures after which container restarts + volumes: + - name: redisinsight + emptyDir: {} # node-ephemeral volume https://kubernetes.io/docs/concepts/storage/volumes/#emptydir +``` + +2. Create the RedisInsight deployment + +```sh +kubectl apply -f redisinsight.yaml +``` + +{{< alert title="Note" >}} +If the deployment will be exposed by a service whose name is 'redisinsight', set `RI_APP_HOST` and `RI_APP_PORT` environment variables to override the environment variables created by the service. +{{< /alert >}} + +3. Once the deployment has been successfully applied and the deployment is complete, access RedisInsight. This can be accomplished by exposing the deployment as a K8s Service or by using port forwarding, as in the example below: + +```sh +kubectl port-forward deployment/redisinsight 5540 +``` + +Open your browser and point to From 578a29db40c8935343a97b92905c97293b4b249a Mon Sep 17 00:00:00 2001 From: Hieu Do <33567997+minhhieu76qng@users.noreply.github.com> Date: Wed, 7 Feb 2024 21:47:43 +0700 Subject: [PATCH 341/377] Fix sorted set leaderboard typo (#2656) --- docs/data-types/sorted-sets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-types/sorted-sets.md b/docs/data-types/sorted-sets.md index 4a03f445b2..9351e2a09c 100644 --- a/docs/data-types/sorted-sets.md +++ b/docs/data-types/sorted-sets.md @@ -203,7 +203,7 @@ the #4932 best score here"). ## Examples -* There are two ways we can use a sorted set to represent a leaderbaord. If we know a racer's new score, we can update it directly via the `ZADD` command. However, if we want to add points to an existing score, we can use the `ZINCRBY` command. +* There are two ways we can use a sorted set to represent a leaderboard. If we know a racer's new score, we can update it directly via the `ZADD` command. However, if we want to add points to an existing score, we can use the `ZINCRBY` command. {{< clients-example ss_tutorial leaderboard >}} > ZADD racer_scores 100 "Wood" (integer) 1 From 03a860c082606a20050acb4e9044ac2354880806 Mon Sep 17 00:00:00 2001 From: Shachar Langbeheim Date: Mon, 12 Feb 2024 16:55:39 +0200 Subject: [PATCH 342/377] Add GLIDE for Redis to nodejs list of clients. --- clients/nodejs/github.com/AWS/GLIDE-for-Redis.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 clients/nodejs/github.com/AWS/GLIDE-for-Redis.json diff --git a/clients/nodejs/github.com/AWS/GLIDE-for-Redis.json b/clients/nodejs/github.com/AWS/GLIDE-for-Redis.json new file mode 100644 index 0000000000..a21fe4956e --- /dev/null +++ b/clients/nodejs/github.com/AWS/GLIDE-for-Redis.json @@ -0,0 +1,4 @@ +{ + "name": "GLIDE for Redis", + "description": "General Language Independent Driver for the Enterprise (GLIDE) for Redis, is a high throughput Redis client, sponsored by AWS." +} From b4368ea2756f44cda11aefeac635f9bec6283ebf Mon Sep 17 00:00:00 2001 From: Shachar Langbeheim Date: Mon, 12 Feb 2024 16:55:59 +0200 Subject: [PATCH 343/377] Add GLIDE for Redis to Python list of clients. --- clients/python/github.com/AWS/GLIDE-for-Redis.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 clients/python/github.com/AWS/GLIDE-for-Redis.json diff --git a/clients/python/github.com/AWS/GLIDE-for-Redis.json b/clients/python/github.com/AWS/GLIDE-for-Redis.json new file mode 100644 index 0000000000..a21fe4956e --- /dev/null +++ b/clients/python/github.com/AWS/GLIDE-for-Redis.json @@ -0,0 +1,4 @@ +{ + "name": "GLIDE for Redis", + "description": "General Language Independent Driver for the Enterprise (GLIDE) for Redis, is a high throughput Redis client, sponsored by AWS." +} From ba9da8b6beadcdd61aad226a5b35db9ad34c3df5 Mon Sep 17 00:00:00 2001 From: Shachar Langbeheim Date: Mon, 12 Feb 2024 20:31:09 +0200 Subject: [PATCH 344/377] Update clients/python/github.com/AWS/GLIDE-for-Redis.json Co-authored-by: Madelyn Olson <34459052+madolson@users.noreply.github.com> --- clients/python/github.com/AWS/GLIDE-for-Redis.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/python/github.com/AWS/GLIDE-for-Redis.json b/clients/python/github.com/AWS/GLIDE-for-Redis.json index a21fe4956e..cfb35fce02 100644 --- a/clients/python/github.com/AWS/GLIDE-for-Redis.json +++ b/clients/python/github.com/AWS/GLIDE-for-Redis.json @@ -1,4 +1,4 @@ { "name": "GLIDE for Redis", - "description": "General Language Independent Driver for the Enterprise (GLIDE) for Redis, is a high throughput Redis client, sponsored by AWS." + "description": "General Language Independent Driver for the Enterprise (GLIDE) for Redis is an advanced multi-language Redis client that is feature rich, highly performant, and built for reliability and operational stability. GLIDE for Redis is supported by AWS." } From e67c18814854893974c98a73658c7dd727dc61e8 Mon Sep 17 00:00:00 2001 From: Shachar Langbeheim Date: Mon, 12 Feb 2024 20:33:07 +0200 Subject: [PATCH 345/377] Update clients/nodejs/github.com/AWS/GLIDE-for-Redis.json --- clients/nodejs/github.com/AWS/GLIDE-for-Redis.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/nodejs/github.com/AWS/GLIDE-for-Redis.json b/clients/nodejs/github.com/AWS/GLIDE-for-Redis.json index a21fe4956e..cfb35fce02 100644 --- a/clients/nodejs/github.com/AWS/GLIDE-for-Redis.json +++ b/clients/nodejs/github.com/AWS/GLIDE-for-Redis.json @@ -1,4 +1,4 @@ { "name": "GLIDE for Redis", - "description": "General Language Independent Driver for the Enterprise (GLIDE) for Redis, is a high throughput Redis client, sponsored by AWS." + "description": "General Language Independent Driver for the Enterprise (GLIDE) for Redis is an advanced multi-language Redis client that is feature rich, highly performant, and built for reliability and operational stability. GLIDE for Redis is supported by AWS." } From 5aa601fa8dd68d9a26dc737de8c7720657a701ab Mon Sep 17 00:00:00 2001 From: Madelyn Olson <34459052+madolson@users.noreply.github.com> Date: Tue, 13 Feb 2024 17:08:43 -0800 Subject: [PATCH 346/377] Update clients/kotlin/github.com/domgew/kedis.json --- clients/kotlin/github.com/domgew/kedis.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/kotlin/github.com/domgew/kedis.json b/clients/kotlin/github.com/domgew/kedis.json index 1d83baed85..a620f65a5c 100644 --- a/clients/kotlin/github.com/domgew/kedis.json +++ b/clients/kotlin/github.com/domgew/kedis.json @@ -1,4 +1,4 @@ { "name": "Kedis", "description": "Redis client library for Kotlin Multiplatform (JVM + Native)" -} \ No newline at end of file +} From ccd3a13c6bcc7bdf9389daad9244007639feff35 Mon Sep 17 00:00:00 2001 From: guybe7 Date: Mon, 19 Feb 2024 18:05:05 +0700 Subject: [PATCH 347/377] The history section should not contain behavioral changes (#2668) As per https://github.com/redis/redis/pull/10398 --- commands/command-docs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/command-docs.md b/commands/command-docs.md index 99e431b177..98943d73a7 100644 --- a/commands/command-docs.md +++ b/commands/command-docs.md @@ -35,7 +35,7 @@ The following keys may be included in the mapped reply: - _syscmd:_ a system command that isn't meant to be called by users. * **deprecated_since:** the Redis version that deprecated the command (or for module commands, the module version).. * **replaced_by:** the alternative for a deprecated command. -* **history:** an array of historical notes describing changes to the command's behavior or arguments. +* **history:** an array of historical notes describing changes to the command's output or arguments. It should not contain information about behavioral changes. Each entry is an array itself, made up of two elements: 1. The Redis version that the entry applies to. 2. The description of the change. From 7679858b1a19a84fc613ca45fe44d3c25385dc64 Mon Sep 17 00:00:00 2001 From: Binbin Date: Tue, 20 Feb 2024 21:23:24 +0800 Subject: [PATCH 348/377] Fix FUNCTION DUMP outupdated examples (#2670) The old example uses an old format, which is no longer supported, it will return an `ERR Pre-GA function format not supported` error. Also the FUNCTION LIST example is also a bit outdated. --- commands/function-dump.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/commands/function-dump.md b/commands/function-dump.md index 3636957f75..167001c3cb 100644 --- a/commands/function-dump.md +++ b/commands/function-dump.md @@ -9,22 +9,24 @@ The following example shows how to dump loaded libraries using `FUNCTION DUMP` a Then, it restores the original libraries from the serialized payload with `FUNCTION RESTORE`. ``` +redis> FUNCTION LOAD "#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)" +"mylib" redis> FUNCTION DUMP -"\xf6\x05mylib\x03LUA\x00\xc3@D@J\x1aredis.register_function('my@\x0b\x02', @\x06`\x12\x11keys, args) return`\x0c\a[1] end)\n\x00@\n)\x11\xc8|\x9b\xe4" +"\xf5\xc3@X@]\x1f#!lua name=mylib \n redis.registe\rr_function('my@\x0b\x02', @\x06`\x12\nkeys, args) 6\x03turn`\x0c\a[1] end)\x0c\x00\xba\x98\xc2\xa2\x13\x0e$\a" redis> FUNCTION FLUSH OK -redis> FUNCTION RESTORE "\xf6\x05mylib\x03LUA\x00\xc3@D@J\x1aredis.register_function('my@\x0b\x02', @\x06`\x12\x11keys, args) return`\x0c\a[1] end)\n\x00@\n)\x11\xc8|\x9b\xe4" +redis> FUNCTION RESTORE "\xf5\xc3@X@]\x1f#!lua name=mylib \n redis.registe\rr_function('my@\x0b\x02', @\x06`\x12\nkeys, args) 6\x03turn`\x0c\a[1] end)\x0c\x00\xba\x98\xc2\xa2\x13\x0e$\a" OK redis> FUNCTION LIST 1) 1) "library_name" 2) "mylib" 3) "engine" 4) "LUA" - 5) "description" - 6) (nil) - 7) "functions" - 8) 1) 1) "name" + 5) "functions" + 6) 1) 1) "name" 2) "myfunc" 3) "description" 4) (nil) + 5) "flags" + 6) (empty array) ``` From 20ed0317b4739c8034998ea2f5bb622fe33d6fb6 Mon Sep 17 00:00:00 2001 From: Moti Cohen Date: Wed, 28 Feb 2024 16:57:32 +0200 Subject: [PATCH 349/377] Add librdb tool and c-library (#2675) Co-authored-by: moticless --- libraries/c/github.com/redis/librdb.json | 5 +++++ tools/other/github.com/redis/librdb.json | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 libraries/c/github.com/redis/librdb.json create mode 100644 tools/other/github.com/redis/librdb.json diff --git a/libraries/c/github.com/redis/librdb.json b/libraries/c/github.com/redis/librdb.json new file mode 100644 index 0000000000..23818714d8 --- /dev/null +++ b/libraries/c/github.com/redis/librdb.json @@ -0,0 +1,5 @@ +{ + "name": "librdb", + "description": "Redis RDB file parser, with JSON, RESP and RDB-loader extensions", + "recommended": true +} diff --git a/tools/other/github.com/redis/librdb.json b/tools/other/github.com/redis/librdb.json new file mode 100644 index 0000000000..23818714d8 --- /dev/null +++ b/tools/other/github.com/redis/librdb.json @@ -0,0 +1,5 @@ +{ + "name": "librdb", + "description": "Redis RDB file parser, with JSON, RESP and RDB-loader extensions", + "recommended": true +} From aebf9fb3e4ee7258a276c1c670f6132efb561143 Mon Sep 17 00:00:00 2001 From: Chen Tianjie Date: Fri, 1 Mar 2024 13:44:59 +0800 Subject: [PATCH 350/377] Add overhead metrics to info and memory stats. (#2674) The corresponding doc PR of https://github.com/redis/redis/pull/12913 --------- Co-authored-by: Oran Agra --- commands/info.md | 1 + commands/memory-stats.md | 3 +++ 2 files changed, 4 insertions(+) diff --git a/commands/info.md b/commands/info.md index d216804624..c1eb0062fc 100644 --- a/commands/info.md +++ b/commands/info.md @@ -150,6 +150,7 @@ Here is the meaning of all fields in the **memory** section: * `mem_replication_backlog`: Memory used by replication backlog * `mem_total_replication_buffers`: Total memory consumed for replication buffers - Added in Redis 7.0. * `mem_allocator`: Memory allocator, chosen at compile time. +* `mem_overhead_db_hashtable_rehashing`: Temporary memory overhead of database dictionaries currently being rehashed - Added in 8.0. * `active_defrag_running`: When `activedefrag` is enabled, this indicates whether defragmentation is currently active, and the CPU percentage it intends to utilize. * `lazyfree_pending_objects`: The number of objects waiting to be freed (as a result of calling `UNLINK`, or `FLUSHDB` and `FLUSHALL` with the **ASYNC** diff --git a/commands/memory-stats.md b/commands/memory-stats.md index f058696645..b2c5109baa 100644 --- a/commands/memory-stats.md +++ b/commands/memory-stats.md @@ -23,10 +23,13 @@ values. The following metrics are reported: * `dbXXX`: For each of the server's databases, the overheads of the main and expiry dictionaries (`overhead.hashtable.main` and `overhead.hashtable.expires`, respectively) are reported in bytes +* `overhead.db.hashtable.lut`: Total overhead of dictionary buckets in databases (Added in Redis 8.0) +* `overhead.db.hashtable.rehashing`: Temporary memory overhead of database dictionaries currently being rehashed (Added in Redis 8.0) * `overhead.total`: The sum of all overheads, i.e. `startup.allocated`, `replication.backlog`, `clients.slaves`, `clients.normal`, `aof.buffer` and those of the internal data structures that are used in managing the Redis keyspace (see `INFO`'s `used_memory_overhead`) +* `db.dict.rehashing.count`: Number of DB dictionaries currently being rehashed (Added in Redis 8.0) * `keys.count`: The total number of keys stored across all databases in the server * `keys.bytes-per-key`: The ratio between `dataset.bytes` and `keys.count` From 438e8b11f391275d8030ad0f918fd3821bdda9e0 Mon Sep 17 00:00:00 2001 From: Chen Tianjie Date: Fri, 1 Mar 2024 15:32:04 +0800 Subject: [PATCH 351/377] Add novalues option to HSCAN. (#2612) Doc of redis/redis#12765. --------- Co-authored-by: Oran Agra --- commands/scan.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/commands/scan.md b/commands/scan.md index 09c52efe6c..367830455c 100644 --- a/commands/scan.md +++ b/commands/scan.md @@ -172,6 +172,25 @@ redis 127.0.0.1:6379> SCAN 0 TYPE zset It is important to note that the **TYPE** filter is also applied after elements are retrieved from the database, so the option does not reduce the amount of work the server has to do to complete a full iteration, and for rare types you may receive no elements in many iterations. +## The NOVALUES option + +When using `HSCAN`, you can use the `NOVALUES` option to make Redis return only the keys in the hash table without their corresponding values. + +``` +redis 127.0.0.1:6379> HSET myhash a 1 b 2 +OK +redis 127.0.0.1:6379> HSCAN myhash 0 +1) "0" +2) 1) "a" + 2) "1" + 3) "b" + 4) "2" +redis 127.0.0.1:6379> HSCAN myhash 0 NOVALUES +1) "0" +2) 1) "a" + 2) "b" +``` + ## Multiple parallel iterations It is possible for an infinite number of clients to iterate the same collection at the same time, as the full state of the iterator is in the cursor, that is obtained and returned to the client at every call. No server side state is taken at all. From ee795e452d3053d4abbc3872c7a114fab9754264 Mon Sep 17 00:00:00 2001 From: Chen Tianjie Date: Fri, 1 Mar 2024 15:54:31 +0800 Subject: [PATCH 352/377] Allow by/get of sort(ro) in cluster mode. (#2611) --- commands/sort.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/commands/sort.md b/commands/sort.md index ca06ed5bd6..b6340d81e8 100644 --- a/commands/sort.md +++ b/commands/sort.md @@ -105,8 +105,11 @@ SORT mylist BY weight_* GET object_* GET # ## Restrictions for using external keys -When enabling `Redis cluster-mode` there is no way to guarantee the existence of the external keys on the node which the command is processed on. -In this case, any use of `GET` or `BY` which reference external key pattern will cause the command to fail with an error. +Before 8.0, when enabling `Redis cluster-mode` there is no way to guarantee the existence of the external keys on the node which the command is processed on. In this case, any use of `GET` or `BY` which reference external key pattern will cause the command to fail with an error. + +Starting from 8.0, pattern with hash tag can be mapped to a slot, and so in `Redis cluster-mode`, the use of `BY` or `GET` is allowed when pattern contains hash tag and implies a specific slot which the key is also in, which means any key matching this pattern must be in the same slot as the key, and therefore in the same node. For example, in cluster mode, `{mylist}weight_*` is acceptable as a pattern when sorting `mylist`, while pattern `{abc}weight_*` will be denied, causing the command to fail with an error. + +To use pattern with hash tag, see https://redis.io/docs/reference/cluster-spec/#hash-tags for more information. Starting from Redis 7.0, any use of `GET` or `BY` which reference external key pattern will only be allowed in case the current user running the command has full key read permissions. Full key read permissions can be set for the user by, for example, specifying `'%R~*'` or `'~*` with the relevant command access rules. From 9e1530946c25b2e380aaf8780d1b1f08c2f12525 Mon Sep 17 00:00:00 2001 From: "zhaozhao.zz" Date: Fri, 1 Mar 2024 15:55:44 +0800 Subject: [PATCH 353/377] Add WATCH metrics (#2665) --------- Co-authored-by: Oran Agra --- commands/client-list.md | 1 + commands/info.md | 2 ++ 2 files changed, 3 insertions(+) diff --git a/commands/client-list.md b/commands/client-list.md index 0eb1c735d8..653e75a8ef 100644 --- a/commands/client-list.md +++ b/commands/client-list.md @@ -20,6 +20,7 @@ Here is the meaning of the fields: * `psub`: number of pattern matching subscriptions * `ssub`: number of shard channel subscriptions. Added in Redis 7.0.3 * `multi`: number of commands in a MULTI/EXEC context +* `watch`: number of keys this client is currently watching. Added in Redis 8.0 * `qbuf`: query buffer length (0 means no query pending) * `qbuf-free`: free space of the query buffer (0 means the buffer is full) * `argv-mem`: incomplete arguments for the next command (already extracted from query buffer) diff --git a/commands/info.md b/commands/info.md index c1eb0062fc..4e9520754b 100644 --- a/commands/info.md +++ b/commands/info.md @@ -84,7 +84,9 @@ Here is the meaning of all fields in the **clients** section: `BRPOP`, `BRPOPLPUSH`, `BLMOVE`, `BZPOPMIN`, `BZPOPMAX`) * `tracking_clients`: Number of clients being tracked (`CLIENT TRACKING`) * `pubsub_clients`: Number of clients in pubsub mode (`SUBSCRIBE`, `PSUBSCRIBE`, `SSUBSCRIBE`). Added in Redis 8.0 +* `watching_clients`: Number of clients in watching mode (`WATCH`). Added in Redis 8.0 * `clients_in_timeout_table`: Number of clients in the clients timeout table +* `total_watched_keys`: Number of watched keys. Added in Redis 8.0. * `total_blocking_keys`: Number of blocking keys. Added in Redis 7.2. * `total_blocking_keys_on_nokey`: Number of blocking keys that one or more clients that would like to be unblocked when the key is deleted. Added in Redis 7.2. From 66da565f9da37eec69ccf8d8fe18314b703568e7 Mon Sep 17 00:00:00 2001 From: Binbin Date: Tue, 5 Mar 2024 21:03:44 +0800 Subject: [PATCH 354/377] Update object-encoding doc to mention all the encodings (#2677) --- commands/object-encoding.md | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/commands/object-encoding.md b/commands/object-encoding.md index b09dc0bef2..685debf912 100644 --- a/commands/object-encoding.md +++ b/commands/object-encoding.md @@ -9,9 +9,34 @@ Redis objects can be encoded in different ways: - `embstr`, an embedded string, which is an object where the internal simple dynamic string, `sds`, is an unmodifiable string allocated in the same chuck as the object itself. `embstr` can be strings with lengths up to the hardcoded limit of `OBJ_ENCODING_EMBSTR_SIZE_LIMIT` or 44 bytes. -* Lists can be encoded as `ziplist` or `linkedlist`. The `ziplist` is the special representation that is used to save space for small lists. -* Sets can be encoded as `intset` or `hashtable`. The `intset` is a special encoding used for small sets composed solely of integers. -* Hashes can be encoded as `ziplist` or `hashtable`. The `ziplist` is a special encoding used for small hashes. -* Sorted Sets can be encoded as `ziplist` or `skiplist` format. As for the List type small sorted sets can be specially encoded using `ziplist`, while the `skiplist` encoding is the one that works with sorted sets of any size. +* Lists can be encoded as: + + - `linkedlist`, simple list encoding. No longer used, an old list encoding. + - `ziplist`, Redis <= 6.2, a space-efficient encoding used for small lists. + - `listpack`, Redis >= 7.0, a space-efficient encoding used for small lists. + - `quicklist`, encoded as linkedlist of ziplists or listpacks. + +* Sets can be encoded as: + + - `hashtable`, normal set encoding. + - `intset`, a special encoding used for small sets composed solely of integers. + - `listpack`, Redis >= 7.2, a space-efficient encoding used for small sets. + +* Hashes can be encoded as: + + - `zipmap`, no longer used, an old hash encoding. + - `hashtable`, normal hash encoding. + - `ziplist`, Redis <= 6.2, a space-efficient encoding used for small hashes. + - `listpack`, Redis >= 7.0, a space-efficient encoding used for small hashes. + +* Sorted Sets can be encoded as: + + - `skiplist`, normal sorted set encoding. + - `ziplist`, Redis <= 6.2, a space-efficient encoding used for small sorted sets. + - `listpack`, Redis >= 7.0, a space-efficient encoding used for small sorted sets. + +* Streams can be encoded as: + + - `stream`, encoded as a radix tree of listpacks. All the specially encoded types are automatically converted to the general type once you perform an operation that makes it impossible for Redis to retain the space saving encoding. From a1e94d906282d8e601acc80d64317f16b9e274c0 Mon Sep 17 00:00:00 2001 From: Chen Tianjie Date: Thu, 7 Mar 2024 18:33:47 +0800 Subject: [PATCH 355/377] Update KEYS and SCAN page about pattern with hash tag (#2610) The optimization done in redis/redis#12754. --- commands/keys.md | 7 +++++++ commands/scan.md | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/commands/keys.md b/commands/keys.md index 766299da39..f51e0ea51a 100644 --- a/commands/keys.md +++ b/commands/keys.md @@ -26,6 +26,13 @@ Supported glob-style patterns: Use `\` to escape special characters if you want to match them verbatim. +When using [Redis Cluster](/docs/management/scaling/), the search is optimized for patterns that imply a single slot. +If a pattern can only match keys of one slot, +Redis only iterates over keys in that slot, rather than the whole database, +when searching for keys matching the pattern. +For example, with the pattern `{a}h*llo`, Redis would only try to match it with the keys in slot 15495, which hash tag `{a}` implies. +To use pattern with hash tag, see [Hash tags](/docs/reference/cluster-spec/#hash-tags) in the Cluster specification for more information. + @examples ```cli diff --git a/commands/scan.md b/commands/scan.md index 367830455c..7ef81e47e9 100644 --- a/commands/scan.md +++ b/commands/scan.md @@ -148,6 +148,12 @@ redis 127.0.0.1:6379> As you can see most of the calls returned zero elements, but the last call where a `COUNT` of 1000 was used in order to force the command to do more scanning for that iteration. +When using [Redis Cluster](/docs/management/scaling/), the search is optimized for patterns that imply a single slot. +If a pattern can only match keys of one slot, +Redis only iterates over keys in that slot, rather than the whole database, +when searching for keys matching the pattern. +For example, with the pattern `{a}h*llo`, Redis would only try to match it with the keys in slot 15495, which hash tag `{a}` implies. +To use pattern with hash tag, see [Hash tags](/docs/reference/cluster-spec/#hash-tags) in the Cluster specification for more information. ## The TYPE option From 00f9306b6d8b4062ccf78cf9d642e61cb2e5d0a5 Mon Sep 17 00:00:00 2001 From: Kelvin Wong <61614687+im-calvin@users.noreply.github.com> Date: Thu, 7 Mar 2024 04:15:28 -0800 Subject: [PATCH 356/377] Bugfix-install redis broken link (#2680) --- docs/install/install-redis/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install/install-redis/_index.md b/docs/install/install-redis/_index.md index 149e137b96..e316a5565b 100644 --- a/docs/install/install-redis/_index.md +++ b/docs/install/install-redis/_index.md @@ -90,7 +90,7 @@ The available packages for supported Linux distributions already include the cap {{% /alert %}} {{% alert title="Note" color="warning" %}} -The remainder of this section assumes you've [installed Redis from its source code](/docs/install/install-redis-from-source/). If instead you have installed Redis Stack, you will need to download a [basic init script](https://raw.githubusercontent.com/redis/redis/7.2/utils/redis_init_script) and then modify both it and the following instructions to conform to the way Redis Stack was installed on your platform. For example, on Ubuntu 20.04 LTS, Redis Stack is installed in `/opt/redis-stack`, not `/usr/local`, so you'll need to adjust accordingly. +The remainder of this section assumes you've [installed Redis from its source code](/docs/install/install-redis/install-redis-from-source). If instead you have installed Redis Stack, you will need to download a [basic init script](https://raw.githubusercontent.com/redis/redis/7.2/utils/redis_init_script) and then modify both it and the following instructions to conform to the way Redis Stack was installed on your platform. For example, on Ubuntu 20.04 LTS, Redis Stack is installed in `/opt/redis-stack`, not `/usr/local`, so you'll need to adjust accordingly. {{% /alert %}} The following instructions can be used to perform a proper installation using the init script shipped with the Redis source code, `/path/to/redis-stable/utils/redis_init_script`. From 45029753c2c2ace0e19bacd507825cd820d59730 Mon Sep 17 00:00:00 2001 From: Chen Tianjie Date: Thu, 7 Mar 2024 20:17:52 +0800 Subject: [PATCH 357/377] Apply title to raw link (#2678) A link to *hash tags* in the cluster spec --- commands/sort.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/sort.md b/commands/sort.md index b6340d81e8..a5843d86e7 100644 --- a/commands/sort.md +++ b/commands/sort.md @@ -109,7 +109,7 @@ Before 8.0, when enabling `Redis cluster-mode` there is no way to guarantee the Starting from 8.0, pattern with hash tag can be mapped to a slot, and so in `Redis cluster-mode`, the use of `BY` or `GET` is allowed when pattern contains hash tag and implies a specific slot which the key is also in, which means any key matching this pattern must be in the same slot as the key, and therefore in the same node. For example, in cluster mode, `{mylist}weight_*` is acceptable as a pattern when sorting `mylist`, while pattern `{abc}weight_*` will be denied, causing the command to fail with an error. -To use pattern with hash tag, see https://redis.io/docs/reference/cluster-spec/#hash-tags for more information. +To use pattern with hash tag, see [Hash tags](/docs/reference/cluster-spec/#hash-tags) for more information. Starting from Redis 7.0, any use of `GET` or `BY` which reference external key pattern will only be allowed in case the current user running the command has full key read permissions. Full key read permissions can be set for the user by, for example, specifying `'%R~*'` or `'~*` with the relevant command access rules. From c4a2ea11376ced4058db1257d5e24375b9c55979 Mon Sep 17 00:00:00 2001 From: Gaspard van Koningsveld Date: Thu, 7 Mar 2024 04:22:23 -0800 Subject: [PATCH 358/377] Fix the rendering of the RESP documentation for the INFO command (#2676) --- resp2_replies.json | 4 ++-- resp3_replies.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/resp2_replies.json b/resp2_replies.json index 074363f755..33abc6c5cb 100644 --- a/resp2_replies.json +++ b/resp2_replies.json @@ -601,9 +601,9 @@ "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the value of the key after the increment." ], "INFO": [ - "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): a map of info fields, one field per line in the form of : where the value can be a comma separated map like =. Also contains section header lines starting with `#` and blank lines.", + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): a map of info fields, one field per line in the form of `:` where the value can be a comma separated map like `=`. Also contains section header lines starting with `#` and blank lines.", "", - "Lines can contain a section name (starting with a # character) or a property. All the properties are in the form of `field:value` terminated by `\r\n`." + "Lines can contain a section name (starting with a `#` character) or a property. All the properties are in the form of `field:value` terminated by `\\r\\n`." ], "KEYS": [ "[Array reply](/docs/reference/protocol-spec#arrays): a list of keys matching _pattern_." diff --git a/resp3_replies.json b/resp3_replies.json index 5b8226f871..fa7da38383 100644 --- a/resp3_replies.json +++ b/resp3_replies.json @@ -601,9 +601,9 @@ "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): the value of the key after the increment." ], "INFO": [ - "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): a map of info fields, one field per line in the form of : where the value can be a comma separated map like =. Also contains section header lines starting with `#` and blank lines.", + "[Bulk string reply](/docs/reference/protocol-spec#bulk-strings): a map of info fields, one field per line in the form of `:` where the value can be a comma separated map like `=`. Also contains section header lines starting with `#` and blank lines.", "", - "Lines can contain a section name (starting with a # character) or a property. All the properties are in the form of `field:value` terminated by `\r\n`." + "Lines can contain a section name (starting with a `#` character) or a property. All the properties are in the form of `field:value` terminated by `\\r\\n`." ], "KEYS": [ "[Array reply](/docs/reference/protocol-spec#arrays): a list of keys matching _pattern_." From 2dd99c461cc01e8571e56d93a7bfccd8c855dd73 Mon Sep 17 00:00:00 2001 From: guybe7 Date: Fri, 8 Mar 2024 16:03:50 +0700 Subject: [PATCH 359/377] Document XINFO STREAM FULL (#2669) Document all the information returned by XINFO STREAM FULL. Also, document the behavioral change of consumer seen-time/idle since 7.2.0 --- commands/xinfo-consumers.md | 3 +++ commands/xinfo-stream.md | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/commands/xinfo-consumers.md b/commands/xinfo-consumers.md index f50c8ac34e..855a308ced 100644 --- a/commands/xinfo-consumers.md +++ b/commands/xinfo-consumers.md @@ -7,6 +7,9 @@ The following information is provided for each consumer in the group: * **idle**: the number of milliseconds that have passed since the consumer's last attempted interaction (Examples: `XREADGROUP`, `XCLAIM`, `XAUTOCLAIM`) * **inactive**: the number of milliseconds that have passed since the consumer's last successful interaction (Examples: `XREADGROUP` that actually read some entries into the PEL, `XCLAIM`/`XAUTOCLAIM` that actually claimed some entries) +Note that before Redis 7.2.0, **idle** used to denote the time passed since last successful interaction. +In 7.2.0, **inactive** was added and **idle** was changed to denote the time passed since last attempted interaction. + @examples ``` diff --git a/commands/xinfo-stream.md b/commands/xinfo-stream.md index 64a68949f2..4fcbe1e2ee 100644 --- a/commands/xinfo-stream.md +++ b/commands/xinfo-stream.md @@ -12,10 +12,40 @@ The informative details provided by this command are: * **first-entry**: the ID and field-value tuples of the first entry in the stream * **last-entry**: the ID and field-value tuples of the last entry in the stream +### The `FULL` modifier + The optional `FULL` modifier provides a more verbose reply. When provided, the `FULL` reply includes an **entries** array that consists of the stream entries (ID and field-value tuples) in ascending order. Furthermore, **groups** is also an array, and for each of the consumer groups it consists of the information reported by `XINFO GROUPS` and `XINFO CONSUMERS`. +The following information is provided for each of the groups: + +* **name**: the consumer group's name +* **last-delivered-id**: the ID of the last entry delivered to the group's consumers +* **entries-read**: the logical "read counter" of the last entry delivered to the group's consumers +* **lag**: the number of entries in the stream that are still waiting to be delivered to the group's consumers, or a NULL when that number can't be determined. +* **pel-count**: the length of the group's pending entries list (PEL), which are messages that were delivered but are yet to be acknowledged +* **pending**: an array with pending entries information (see below) +* **consumers**: an array with consumers information (see below) + +The following information is provided for each pending entry: + +1. The ID of the message. +2. The name of the consumer that fetched the message and has still to acknowledge it. We call it the current *owner* of the message. +3. The UNIX timestamp of when the message was delivered to this consumer. +4. The number of times this message was delivered. + +The following information is provided for each consumer: + +* **name**: the consumer's name +* **seen-time**: the UNIX timestamp of the last attempted interaction (Examples: `XREADGROUP`, `XCLAIM`, `XAUTOCLAIM`) +* **active-time**: the UNIX timestamp of the last successful interaction (Examples: `XREADGROUP` that actually read some entries into the PEL, `XCLAIM`/`XAUTOCLAIM` that actually claimed some entries) +* **pel-count**: the number of entries in the PEL: pending messages for the consumer, which are messages that were delivered but are yet to be acknowledged +* **pending**: an array with pending entries information, has the same structure as described above, except the consumer name is omitted (redundant, since anyway we are in a specific consumer context) + +Note that before Redis 7.2.0, **seen-time** used to denote the last successful interaction. +In 7.2.0, **active-time** was added and **seen-time** was changed to denote the last attempted interaction. + The `COUNT` option can be used to limit the number of stream and PEL entries that are returned (The first `` entries are returned). The default `COUNT` is 10 and a `COUNT` of 0 means that all entries will be returned (execution time may be long if the stream has a lot of entries). From 9d4eadf0167950726a43dc5433cc2cb6e023446e Mon Sep 17 00:00:00 2001 From: Slava Koyfman Date: Fri, 8 Mar 2024 11:04:49 +0200 Subject: [PATCH 360/377] Document CLIENT KILL MAXAGE filter (#2666) --- commands/client-kill.md | 1 + 1 file changed, 1 insertion(+) diff --git a/commands/client-kill.md b/commands/client-kill.md index a8f02c65a2..e54529a7c8 100644 --- a/commands/client-kill.md +++ b/commands/client-kill.md @@ -17,6 +17,7 @@ instead of killing just by address. The following filters are available: * `CLIENT KILL TYPE type`, where *type* is one of `normal`, `master`, `replica` and `pubsub`. This closes the connections of **all the clients** in the specified class. Note that clients blocked into the `MONITOR` command are considered to belong to the `normal` class. * `CLIENT KILL USER username`. Closes all the connections that are authenticated with the specified [ACL](/topics/acl) username, however it returns an error if the username does not map to an existing ACL user. * `CLIENT KILL SKIPME yes/no`. By default this option is set to `yes`, that is, the client calling the command will not get killed, however setting this option to `no` will have the effect of also killing the client calling the command. +* `CLIENT KILL MAXAGE maxage`. Closes all the connections that are older than the specified age, in seconds. It is possible to provide multiple filters at the same time. The command will handle multiple filters via logical AND. For example: From 7f18c04120c944ed4bea58aed17c1612783ca259 Mon Sep 17 00:00:00 2001 From: "debing.sun" Date: Fri, 8 Mar 2024 18:26:17 +0800 Subject: [PATCH 361/377] Add Lua os library section (#2671) in redis/redis#12971 we expose a new Lua os api os.clock(). --- docs/interact/programmability/lua-api.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/interact/programmability/lua-api.md b/docs/interact/programmability/lua-api.md index f5d6e3e505..3fa62f10c9 100644 --- a/docs/interact/programmability/lua-api.md +++ b/docs/interact/programmability/lua-api.md @@ -670,6 +670,7 @@ The following [standard Lua libraries](https://www.lua.org/manual/5.1/manual.htm * The [_String Manipulation (string)_ library](https://www.lua.org/manual/5.1/manual.html#5.4) * The [_Table Manipulation (table)_ library](https://www.lua.org/manual/5.1/manual.html#5.5) * The [_Mathematical Functions (math)_ library](https://www.lua.org/manual/5.1/manual.html#5.6) +* The [_Operating System Facilities (os)_ library](#os-library) In addition, the following external libraries are loaded and accessible to scripts: @@ -678,6 +679,18 @@ In addition, the following external libraries are loaded and accessible to scrip * The [_cmsgpack_ library](#cmsgpack-library) * The [_bitop_ library](#bitop-library) +### _os_ library + +* Since version: 8.0.0 +* Available in scripts: yes +* Available in functions: yes + +_os_ provides a set of functions for dealing with date, time, and system commands. +More details can be found in the [Operating System Facilities](https://www.lua.org/manual/5.1/manual.html#5.8). +Note that for sandbox security, currently only the following os functions is exposed: + +* `os.clock()` + ### _struct_ library * Since version: 2.6.0 From d74da8f10329433a20dc0471fe1b2bdc6b5b7757 Mon Sep 17 00:00:00 2001 From: "debing.sun" Date: Mon, 11 Mar 2024 15:26:18 +0800 Subject: [PATCH 362/377] Add allocator_muzzy field in INFO MEMORY and MEMORY STATS (#2672) In redis/redis#12996 we add a new `allocator_muzzy` field for `INFO MEMORY` and `MEMORY STATS`. Also update MEMORY-STATS.md for missing fields. --- commands/info.md | 1 + commands/memory-stats.md | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/commands/info.md b/commands/info.md index 4e9520754b..de4d04608a 100644 --- a/commands/info.md +++ b/commands/info.md @@ -144,6 +144,7 @@ Here is the meaning of all fields in the **memory** section: * `allocator_allocated`: Total bytes allocated form the allocator, including internal-fragmentation. Normally the same as `used_memory`. * `allocator_active`: Total bytes in the allocator active pages, this includes external-fragmentation. * `allocator_resident`: Total bytes resident (RSS) in the allocator, this includes pages that can be released to the OS (by `MEMORY PURGE`, or just waiting). +* `allocator_muzzy`: Total bytes of 'muzzy' memory (RSS) in the allocator. Muzzy memory is memory that has been freed, but not yet fully returned to the operating system. It can be reused immediately when needed or reclaimed by the OS when system pressure increases. * `mem_not_counted_for_evict`: Used memory that's not counted for key eviction. This is basically transient replica and AOF buffers. * `mem_clients_slaves`: Memory used by replica clients - Starting Redis 7.0, replica buffers share memory with the replication backlog, so this field can show 0 when replicas don't trigger an increase of memory usage. * `mem_clients_normal`: Memory used by normal clients diff --git a/commands/memory-stats.md b/commands/memory-stats.md index b2c5109baa..3d88350dad 100644 --- a/commands/memory-stats.md +++ b/commands/memory-stats.md @@ -20,6 +20,8 @@ values. The following metrics are reported: * `aof.buffer`: The summed size in bytes of AOF related buffers. * `lua.caches`: the summed size in bytes of the overheads of the Lua scripts' caches +* `functions.caches`: the summed size in bytes of the overheads of the Function scripts' + caches * `dbXXX`: For each of the server's databases, the overheads of the main and expiry dictionaries (`overhead.hashtable.main` and `overhead.hashtable.expires`, respectively) are reported in bytes @@ -39,6 +41,17 @@ values. The following metrics are reported: memory usage * `peak.percentage`: The percentage of `total.allocated` out of `peak.allocated` +* `allocator.allocated`: See `INFO`'s `allocator_allocated` +* `allocator.active`: See `INFO`'s `allocator_active` +* `allocator.resident`: See `INFO`'s `allocator_resident` +* `allocator.muzzy`: See `INFO`'s `allocator_muzzy` +* `allocator-fragmentation.ratio`: See `INFO`'s `allocator_frag_ratio` +* `allocator-fragmentation.bytes`: See `INFO`'s `allocator_frag_bytes` +* `allocator-rss.ratio`: See `INFO`'s `allocator_rss_ratio` +* `allocator-rss.bytes`: See `INFO`'s `allocator_rss_bytes` +* `rss-overhead.ratio`: See `INFO`'s `rss_overhead_ratio` +* `rss-overhead.bytes`: See `INFO`'s `rss_overhead_bytes` * `fragmentation`: See `INFO`'s `mem_fragmentation_ratio` +* `fragmentation.bytes`: See `INFO`'s `mem_fragmentation_bytes` **A note about the word slave used in this man page**: Starting with Redis 5, if not for backward compatibility, the Redis project no longer uses the word slave. Unfortunately in this command the word slave is part of the protocol, so we'll be able to remove such occurrences only when this API will be naturally deprecated. From 34478235ee766a44cf8096e8b5cfc8595d2ef030 Mon Sep 17 00:00:00 2001 From: Brendan Devine <66495727+btdevine@users.noreply.github.com> Date: Mon, 11 Mar 2024 02:29:13 -0500 Subject: [PATCH 363/377] Added in missing word "extract" in install-redis-from-source.md (#2648) --- docs/install/install-redis/install-redis-from-source.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install/install-redis/install-redis-from-source.md b/docs/install/install-redis/install-redis-from-source.md index b782f6e450..f910965350 100644 --- a/docs/install/install-redis/install-redis-from-source.md +++ b/docs/install/install-redis/install-redis-from-source.md @@ -22,7 +22,7 @@ wget https://download.redis.io/redis-stable.tar.gz ## Compiling Redis -To compile Redis, first the tarball, change to the root directory, and then run `make`: +To compile Redis, first extract the tarball, change to the root directory, and then run `make`: {{< highlight bash >}} tar -xzvf redis-stable.tar.gz From 54777055f37b5254045ab4d697b472321e555b89 Mon Sep 17 00:00:00 2001 From: Nipuna Ransinghe Date: Mon, 11 Mar 2024 18:51:18 +0530 Subject: [PATCH 364/377] Add Ballerina Redis client (#2682) This PR adds information on the Official Redis client library for [Ballerina](https://ballerina.io/). This client comes with the support for Redis clusters, connection pooling and secure connections OOTB. ## References - Ballerina Redis Client Package: https://central.ballerina.io/ballerinax/redis/latest - Source Repository: https://github.com/ballerina-platform/module-ballerinax-redis - Client Specification Documentation: https://github.com/ballerina-platform/module-ballerinax-redis/blob/master/docs/spec/spec.md - Ballerina Programming Language Homepage: https://ballerina.io/ --- clients/ballerina/github.com/redis/ballerinax-redis.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 clients/ballerina/github.com/redis/ballerinax-redis.json diff --git a/clients/ballerina/github.com/redis/ballerinax-redis.json b/clients/ballerina/github.com/redis/ballerinax-redis.json new file mode 100644 index 0000000000..6ee431585e --- /dev/null +++ b/clients/ballerina/github.com/redis/ballerinax-redis.json @@ -0,0 +1,7 @@ +{ + "name": "ballerinax-redis", + "description": "Official Redis client for Ballerina language with the support for Redis clusters, connection pooling and secure connections.", + "homepage": "https://central.ballerina.io/ballerinax/redis/latest", + "repository": "https://github.com/ballerina-platform/module-ballerinax-redis", + "recommended": true +} From 7807291f71bb6cd2b2f4ec8f53b2f734dc99912f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20S=C3=B6derqvist?= Date: Tue, 12 Mar 2024 09:19:17 +0100 Subject: [PATCH 365/377] Add Ballerina to the list of languages (#2684) --- languages.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/languages.json b/languages.json index 5d6dfda9ab..45bf6c212d 100644 --- a/languages.json +++ b/languages.json @@ -1,6 +1,7 @@ { "ActionScript": "actionscript", "ActiveX/COM+": "activex-com", + "Ballerina": "ballerina", "Bash": "bash", "Boomi": "boomi", "C": "c", @@ -61,4 +62,4 @@ "VCL": "vcl", "Xojo": "xojo", "Zig": "zig" -} \ No newline at end of file +} From 6c106478cd5314d49cd524e0ae282fb947767453 Mon Sep 17 00:00:00 2001 From: Nipuna Ransinghe Date: Tue, 12 Mar 2024 14:16:14 +0530 Subject: [PATCH 366/377] Fix the directory structure of the Ballerina client (#2685) * Fix the directory structure of the Ballerina client, which generates the link * Change the client name --- .../module-ballerinax-redis.json} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename clients/ballerina/github.com/{redis/ballerinax-redis.json => ballerina-platform/module-ballerinax-redis.json} (89%) diff --git a/clients/ballerina/github.com/redis/ballerinax-redis.json b/clients/ballerina/github.com/ballerina-platform/module-ballerinax-redis.json similarity index 89% rename from clients/ballerina/github.com/redis/ballerinax-redis.json rename to clients/ballerina/github.com/ballerina-platform/module-ballerinax-redis.json index 6ee431585e..49340f841d 100644 --- a/clients/ballerina/github.com/redis/ballerinax-redis.json +++ b/clients/ballerina/github.com/ballerina-platform/module-ballerinax-redis.json @@ -1,5 +1,5 @@ { - "name": "ballerinax-redis", + "name": "Ballerina Redis Client", "description": "Official Redis client for Ballerina language with the support for Redis clusters, connection pooling and secure connections.", "homepage": "https://central.ballerina.io/ballerinax/redis/latest", "repository": "https://github.com/ballerina-platform/module-ballerinax-redis", From 51cd6df160077672a9f0a18d3e85019596bc26ac Mon Sep 17 00:00:00 2001 From: sawasa Date: Wed, 13 Mar 2024 17:05:46 +0900 Subject: [PATCH 367/377] Add client Redis::Cluster::Fast for Perl (#2664) --- .../perl/github.com/plainbanana/Redis-Cluster-Fast.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 clients/perl/github.com/plainbanana/Redis-Cluster-Fast.json diff --git a/clients/perl/github.com/plainbanana/Redis-Cluster-Fast.json b/clients/perl/github.com/plainbanana/Redis-Cluster-Fast.json new file mode 100644 index 0000000000..c23ba9a1a0 --- /dev/null +++ b/clients/perl/github.com/plainbanana/Redis-Cluster-Fast.json @@ -0,0 +1,8 @@ +{ + "name": "Redis::Cluster::Fast", + "description": "A fast Perl binding for Redis Cluster", + "homepage": "http://search.cpan.org/dist/Redis-Cluster-Fast/", + "twitter": [ + "plainbanana" + ] +} \ No newline at end of file From 7dbeb33c0ec969a614f19530036acf526d5551c4 Mon Sep 17 00:00:00 2001 From: Binbin Date: Fri, 15 Mar 2024 00:36:33 +0800 Subject: [PATCH 368/377] Add new INFO evicted_scripts field and eval scripts eviction (#2686) Co-authored-by: Oran Agra --- commands/eval.md | 6 ++++++ commands/info.md | 1 + 2 files changed, 7 insertions(+) diff --git a/commands/eval.md b/commands/eval.md index 079edeb001..4dd5c8f452 100644 --- a/commands/eval.md +++ b/commands/eval.md @@ -12,6 +12,12 @@ to ensure the correct execution of scripts, both in standalone and clustered dep The script **should only** access keys whose names are given as input arguments. Scripts **should never** access keys with programmatically-generated names or based on the contents of data structures stored in the database. +**Note:** +in some cases, users will abuse Lua EVAL by embedding values in the script instead of providing them as argument, and thus generating a different script on each call to EVAL. +These are added to the Lua interpreter and cached to redis-server, consuming a large amount of memory over time. +Starting from Redis 8.0, scripts loaded with `EVAL` or `EVAL_RO` will be deleted from redis after a certain number (least recently used order). +The number of evicted scripts can be viewed through `INFO`'s `evicted_scripts`. + Please refer to the [Redis Programmability](/topics/programmability) and [Introduction to Eval Scripts](/topics/eval-intro) for more information about Lua scripts. @examples diff --git a/commands/info.md b/commands/info.md index de4d04608a..117a5da638 100644 --- a/commands/info.md +++ b/commands/info.md @@ -276,6 +276,7 @@ Here is the meaning of all fields in the **stats** section: * `expire_cycle_cpu_milliseconds`: The cumulative amount of time spent on active expiry cycles * `evicted_keys`: Number of evicted keys due to `maxmemory` limit * `evicted_clients`: Number of evicted clients due to `maxmemory-clients` limit. Added in Redis 7.0. +* `evicted_scripts`: Number of evicted EVAL scripts due to LRU policy, see `EVAL` for more details. Added in Redis 8.0. * `total_eviction_exceeded_time`: Total time `used_memory` was greater than `maxmemory` since server startup, in milliseconds * `current_eviction_exceeded_time`: The time passed since `used_memory` last rose above `maxmemory`, in milliseconds * `keyspace_hits`: Number of successful lookup of keys in the main dictionary From 69921f506c02f65606498cfb4c083c6d8f91f125 Mon Sep 17 00:00:00 2001 From: dmaier-redislabs Date: Wed, 20 Mar 2024 23:54:23 +0200 Subject: [PATCH 369/377] Changes in the context of the Redis license change --- README.md | 2 + community/_index.md | 30 +++---------- docs/about/_index.md | 11 +++-- docs/about/governance.md | 91 ---------------------------------------- docs/about/license.md | 77 ++++++++++------------------------ docs/about/sponsors.md | 43 ------------------- 6 files changed, 37 insertions(+), 217 deletions(-) delete mode 100644 docs/about/governance.md delete mode 100644 docs/about/sponsors.md diff --git a/README.md b/README.md index a9401a1c9b..873edc9a6f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Redis documentation +OPEN SOURCE LICENSE VS. TRADEMARKS. The three-clause BSD license gives you the right to redistribute and use the software in source and binary forms, with or without modification, under certain conditions. However, open source licenses like the three-clause BSD license do not address trademarks. For further details please read the [Redis Trademark Policy](https://www.redis.com/legal/trademark-policy)." + ## Clients All clients are listed under language specific sub-folders of [clients](./clients) diff --git a/community/_index.md b/community/_index.md index 09e6949d5c..b67d2a2aaf 100644 --- a/community/_index.md +++ b/community/_index.md @@ -3,7 +3,7 @@ title: Community linkTitle: Community --- -Since 2009, the Redis open source project has inspired an enthusiastic and active community of users and contributors. We continue to be committed to fostering an open, welcoming, diverse, inclusive, and healthy community. +Since 2009, the Redis project has inspired an enthusiastic and active community of users and contributors. We continue to be committed to fostering an open, welcoming, diverse, inclusive, and healthy community. ## Code of Conduct @@ -29,29 +29,15 @@ For occasional updates on the new Redis releases, you can either [subscribe to t To keep up with the latest from Redis Inc., including news on Redis Cloud and Redis Stack, consider [following the Redis Twitter feed](https://twitter.com/redisinc). -## Project governance - -Redis has adopted a [light governance model](/docs/about/governance) led by individuals who have made significant contributions to Redis and demonstrated a long-term commitment to the project. - -Learn more about the project's governance and the Redis Core Team on the [Redis governance page](/docs/about/governance). - -## Conferences and meetups - -Redis regularly sponsors conferences and meetups. Recent conferences include: - -* [Redis Days 2022](https://redis.com/redisdays/) - -* [RedisConf 2021](https://redis.com/redisconf/) - -* [RedisConf 2020](https://www.youtube.com/c/Redisinc/playlists?view=50&sort=dd&shelf_id=4) - ## Contributing to Redis -There are many ways to contribute to Redis, starting with documentation all the way to changes to the open source Redis server. Here are a few ways you can get involved. +> Future releases of Redis will be dual-licensed under a source-available license. You can choose between the [Redis Source Available License 2.0 (RSALv2)](/docs/about/license) or the Server Side Public License v1 (SSPLv1). + +There are many ways to contribute to Redis, starting with documentation all the way to changes to the Redis server. Here are a few ways you can get involved. ### Contributing to docs -The [Redis docs](https://github.com/redis/redis-doc) are open source, and we'd love to incorporate your contributions. For small changes and typos, we recommend creating a pull request against [redis-doc repo](https://github.com/redis/redis-doc/pulls). +We welcome contributions to the [Redis docs](https://github.com/redis/redis-doc). For small changes and typos, we recommend creating a pull request against [redis-doc repo](https://github.com/redis/redis-doc/pulls). ### Reporting bugs @@ -61,8 +47,4 @@ For larger doc changes, we ask that you first create an issue describing your pr ### Client libraries -The Redis client libraries are nearly always open source and accepting of contributions. Consult the contribution guidelines for the library you're interested in. - -### Hacktoberfest - -Redis is participating in [Hacktoberfest 2022](/community/hacktoberfest/). +The Redis client libraries are nearly always open source and accepting of contributions. Consult the contribution guidelines for the library you're interested in. \ No newline at end of file diff --git a/docs/about/_index.md b/docs/about/_index.md index 4b80f25497..56dc574a12 100644 --- a/docs/about/_index.md +++ b/docs/about/_index.md @@ -2,14 +2,17 @@ title: Introduction to Redis linkTitle: "About" weight: 10 -description: Learn about the Redis open source project +description: Learn about Redis aliases: - /topics/introduction - /buzz --- -Redis is an open source (BSD licensed), in-memory __data structure store__ used as a database, cache, message broker, and streaming engine. Redis provides [data structures](/docs/data-types/) such as -[strings](/docs/data-types/strings/), [hashes](/docs/data-types/hashes/), [lists](/docs/data-types/lists/), [sets](/docs/data-types/sets/), [sorted sets](/docs/data-types/sorted-sets/) with range queries, [bitmaps](/docs/data-types/bitmaps/), [hyperloglogs](/docs/data-types/hyperloglogs/), [geospatial indexes](/docs/data-types/geospatial/), and [streams](/docs/data-types/streams/). Redis has built-in [replication](/topics/replication), [Lua scripting](/commands/eval), [LRU eviction](/docs/reference/eviction/), [transactions](/topics/transactions), and different levels of [on-disk persistence](/topics/persistence), and provides high availability via [Redis Sentinel](/topics/sentinel) and automatic partitioning with [Redis Cluster](/topics/cluster-tutorial). +Redis is an open source (BSD licensed), in-memory __data structure store__ used as a database, cache, message broker, and streaming engine. + +> Future releases of Redis will be dual-licensed under a source-available license. You can choose between the [Redis Source Available License 2.0 (RSALv2)](/docs/about/license) or the Server Side Public License v1 (SSPLv1). + +Redis provides [data structures](/docs/data-types/) such as [strings](/docs/data-types/strings/), [hashes](/docs/data-types/hashes/), [lists](/docs/data-types/lists/), [sets](/docs/data-types/sets/), [sorted sets](/docs/data-types/sorted-sets/) with range queries, [bitmaps](/docs/data-types/bitmaps/), [hyperloglogs](/docs/data-types/hyperloglogs/), [geospatial indexes](/docs/data-types/geospatial/), and [streams](/docs/data-types/streams/). Redis has built-in [replication](/topics/replication), [Lua scripting](/commands/eval), [LRU eviction](/docs/reference/eviction/), [transactions](/topics/transactions), and different levels of [on-disk persistence](/topics/persistence), and provides high availability via [Redis Sentinel](/topics/sentinel) and automatic partitioning with [Redis Cluster](/topics/cluster-tutorial). You can run __atomic operations__ on these types, like [appending to a string](/commands/append); @@ -40,4 +43,4 @@ Redis is written in **ANSI C** and works on most POSIX systems like Linux, \*BSD, and Mac OS X, without external dependencies. Linux and OS X are the two operating systems where Redis is developed and tested the most, and we **recommend using Linux for deployment**. Redis may work in Solaris-derived systems like SmartOS, but support is *best effort*. There is no official support for Windows builds. -
\ No newline at end of file +
diff --git a/docs/about/governance.md b/docs/about/governance.md deleted file mode 100644 index 879f109eb7..0000000000 --- a/docs/about/governance.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -title: "Redis open source governance" -linkTitle: "Governance" -weight: 3 -description: > - Governance model for the Redis open source project -aliases: - - /topics/governance ---- - -From 2009-2020, Salvatore Sanfilippo built, led, and maintained the Redis open source project. During this time, Redis had no formal governance structure, operating primarily as a [BDFL](https://en.wikipedia.org/wiki/Benevolent_dictator_for_life)-style project. - -As Redis grew, matured, and expanded its user base, it became increasingly important to form a sustainable structure for its ongoing development and maintenance. Salvatore and the core Redis contributors wanted to ensure the project’s continuity and reflect its larger community. With this in mind, a new governance structure was adopted. - -## Current governance structure - -Starting on June 30, 2020, Redis adopted a _light governance_ model that matches the current size of the project and minimizes the changes from its earlier model. The governance model is intended to be a meritocracy, aiming to empower individuals who demonstrate a long-term commitment and make significant contributions. - -## The Redis core team - -Salvatore Sanfilippo named two successors to take over and lead the Redis project: Yossi Gottlieb ([yossigo](https://github.com/yossigo)) and Oran Agra ([oranagra](https://github.com/oranagra)) - -With the backing and blessing of Redis Ltd., we took this opportunity to create a more open, scalable, and community-driven “core team” structure to run the project. The core team consists of members selected based on demonstrated, long-term personal involvement and contributions. - -The current core team members are: - -* Project Lead: Yossi Gottlieb ([yossigo](https://github.com/yossigo)) from Redis Ltd. -* Project Lead: Oran Agra ([oranagra](https://github.com/oranagra)) from Redis Ltd. -* Community Lead: Itamar Haber ([itamarhaber](https://github.com/itamarhaber)) from Redis Ltd. -* Member: Zhao Zhao ([soloestoy](https://github.com/soloestoy)) from Alibaba -* Member: Madelyn Olson ([madolson](https://github.com/madolson)) from Amazon Web Services - -The Redis core team members serve the Redis open source project and community. They are expected to set a good example of behavior, culture, and tone in accordance with the adopted [Code of Conduct](https://www.contributor-covenant.org/). They should also consider and act upon the best interests of the project and the community in a way that is free from foreign or conflicting interests. - -The core team will be responsible for the Redis core project, which is the part of Redis that is hosted in the main Redis repository and is BSD licensed. It will also aim to maintain coordination and collaboration with other projects that make up the Redis ecosystem, including Redis clients, satellite projects, major middleware that relies on Redis, etc. - -#### Roles and responsibilities - -The core team has the following remit: - -* Managing the core Redis code and documentation -* Managing new Redis releases -* Maintaining a high-level technical direction/roadmap -* Providing a fast response, including fixes/patches, to address security vulnerabilities and other major issues -* Project governance decisions and changes -* Coordination of Redis core with the rest of the Redis ecosystem -* Managing the membership of the core team - -The core team aims to form and empower a community of contributors by further delegating tasks to individuals who demonstrate commitment, know-how, and skills. In particular, we hope to see greater community involvement in the following areas: - -* Support, troubleshooting, and bug fixes of reported issues -* Triage of contributions/pull requests - -#### Decision making - -* **Normal decisions** will be made by core team members based on a lazy consensus approach: each member may vote +1 (positive) or -1 (negative). A negative vote must include thorough reasoning and better yet, an alternative proposal. The core team will always attempt to reach a full consensus rather than a majority. Examples of normal decisions: - * Day-to-day approval of pull requests and closing issues - * Opening new issues for discussion -* **Major decisions** that have a significant impact on the Redis architecture, design, or philosophy as well as core-team structure or membership changes should preferably be determined by full consensus. If the team is not able to achieve a full consensus, a majority vote is required. Examples of major decisions: - * Fundamental changes to the Redis core - * Adding a new data structure - * Creating a new version of RESP (Redis Serialization Protocol) - * Changes that affect backward compatibility - * Adding or changing core team members -* Project leads have a right to veto major decisions - -#### Core team membership - -* The core team is not expected to serve for life, however, long-term participation is desired to provide stability and consistency in the Redis programming style and the community. -* If a core-team member whose work is funded by Redis Ltd. must be replaced, the replacement will be designated by Redis Ltd. after consultation with the remaining core-team members. -* If a core-team member not funded by Redis Ltd. will no longer participate, for whatever reason, the other team members will select a replacement. - -## Community forums and communications - -We want the Redis community to be as welcoming and inclusive as possible. To that end, we have adopted a [Code of Conduct](https://www.contributor-covenant.org/) that we ask all community members to read and observe. - -We encourage that all significant communications will be public, asynchronous, archived, and open for the community to actively participate in using the channels described [here](https://redis.io/community). The exception to that is sensitive security issues that require resolution prior to public disclosure. - -To contact the core team about sensitive matters, such as misconduct or security issues, please email [redis@redis.io](mailto:redis@redis.io). - -## New Redis repository and commits approval process - -The Redis core source repository is hosted under [https://github.com/redis/redis](https://github.com/redis/redis). Our target is to eventually host everything (the Redis core source and other ecosystem projects) under the Redis GitHub organization ([https://github.com/redis](https://github.com/redis)). Commits to the Redis source repository will require code review, approval of at least one core-team member who is not the author of the commit, and no objections. - -## Project and development updates - -Stay connected to the project and the community! For project and community updates, follow the project [channels](https://redis.io/community). Development announcements will be made via [the Redis mailing list](https://groups.google.com/forum/#!forum/redis-db). - -## Updates to these governance rules - -Any substantial changes to these rules will be treated as a major decision. Minor changes or ministerial corrections will be treated as normal decisions. diff --git a/docs/about/license.md b/docs/about/license.md index 31291c669e..6f78dd1f2a 100644 --- a/docs/about/license.md +++ b/docs/about/license.md @@ -10,76 +10,43 @@ aliases: --- -* Redis is **open source software** released under the terms of the **three clause BSD license**. Most of the Redis source code was written and is copyrighted by Salvatore Sanfilippo and Pieter Noordhuis. A list of other contributors can be found in the git history. +* Redis is source-available software, available under the terms of the RSALv2 and SSPLv1 licenses. Most of the Redis source code was written and is copyrighted by Salvatore Sanfilippo and Pieter Noordhuis. A list of other contributors can be found in the git history. The Redis trademark and logo are owned by Redis Ltd. and can be used in accordance with the [Redis Trademark Guidelines](https://redis.com/legal/trademark-guidelines/). * RedisInsight is licensed under the Server Side Public License (SSPL). -* Redis Stack Server, which combines open source Redis with Search and Query features, JSON, Time Series, and Probabilistic data structures is dual-licensed under the Redis Source Available License (RSALv2), as described below, and the [Server Side Public License](https://en.wikipedia.org/wiki/Server_Side_Public_License) (SSPL). For information about licensing per version, see [Versions and licenses](/docs/about/about-stack/#redis-stack-license). +* Redis Stack Server, which combines open source Redis with Search and Query features, JSON, Time Series, and Probabilistic data structures is dual-licensed under the Redis Source Available License (RSALv2), as described below, and the [Server Side Public License](https://redis.com/legal/server-side-public-license-sspl/) (SSPL). For information about licensing per version, see [Versions and licenses](/docs/about/about-stack/#redis-stack-license). -## Licences: - -### Three clause BSD license - -Every file in the Redis distribution, with the exceptions of third party files specified in the list below, contain the following license: - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -* Neither the name of Redis nor the names of its contributors may be used - to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. +## Licenses: ### REDIS SOURCE AVAILABLE LICENSE (RSAL) 2.0 - -_Last updated: November 15, 2022_ +Last updated: November 15, 2022 #### Acceptance By using the software, you agree to all of the terms and conditions below. - + #### Copyright License The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations and conditions below. #### Limitations -You may not make the functionality of the software or a modified version available to third parties as a service, or distribute the software or a modified version in a manner that makes the functionality of the software available to third parties. -Making the functionality of the software or modified version available to third parties includes, without limitation, enabling third parties to interact with the functionality of the software or modified version in distributed form or remotely through a computer network, offering a product or service the value of which entirely or primarily derives from the value of the software or modified version, or offering a product or service that accomplishes for users the primary purpose of the software or modified version. +You may not make the functionality of the software or a modified version available to third parties as a service, or distribute the software or a modified version in a manner that makes the functionality of the software available to third parties. Making the functionality of the software or modified version available to third parties includes, without limitation, enabling third parties to interact with the functionality of the software or modified version in distributed form or remotely through a computer network, offering a product or service the value of which entirely or primarily derives from the value of the software or modified version, or offering a product or service that accomplishes for users the primary purpose of the software or modified version. You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor’s trademarks is subject to applicable law. - + #### Patents The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company. #### Notices -You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms. -If you modify the software, you must include in any modified copies of the software prominent notices stating that you have modified the software. +You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms. If you modify the software, you must include in any modified copies of the software prominent notices stating that you have modified the software. #### No Other Rights @@ -91,38 +58,38 @@ If you use the software in violation of these terms, such use is not licensed, a #### No Liability -_**As far as the law allows, the **software** comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.**_ +As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim. #### Definitions -The **licensor** is the entity offering these terms, and the software is the software the licensor makes available under these terms, including any portion of it. +The licensor is the entity offering these terms, and the software is the software the licensor makes available under these terms, including any portion of it. -To **modify** a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission other than making an exact copy. The resulting work is called a **modified version** of the earlier work. +To modify a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission other than making an exact copy. The resulting work is called a modified version of the earlier work. **you** refers to the individual or entity agreeing to these terms. -**your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. +**your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. **control** means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect. -**your licenses** are all the licenses granted to you for the software under these terms. -use means anything you do with the software requiring one of your licenses. +**your licenses** are all the licenses granted to you for the software under these terms. -**trademark** means trademarks, service marks, and similar rights. +**use** means anything you do with the software requiring one of your licenses. +**trademark** means trademarks, service marks, and similar rights. -### Third-party files and licenses +#### Third-party files and licenses Redis uses source code from third parties. All this code contains a BSD or BSD-compatible license. The following is a list of third-party files and information about their copyright. -* Redis uses the [LHF compression library](http://oldhome.schmorp.de/marc/liblzf.html). LibLZF is copyright Marc Alexander Lehmann and is released under the terms of the **two-clause BSD license**. +* Redis uses the [LHF compression library](http://oldhome.schmorp.de/marc/liblzf.html). LibLZF is copyright Marc Alexander Lehmann and is released under the terms of the two-clause BSD license. -* Redis uses the `sha1.c` file that is copyright by Steve Reid and released under the **public domain**. This file is extremely popular and used among open source and proprietary code. +* Redis uses the sha1.c file that is copyright by Steve Reid and released under the public domain. This file is extremely popular and used among open source and proprietary code. -* When compiled on Linux, Redis uses the [Jemalloc allocator](https://github.com/jemalloc/jemalloc), which is copyrighted by Jason Evans, Mozilla Foundation, and Facebook, Inc and released under the **two-clause BSD license**. +* When compiled on Linux, Redis uses the [Jemalloc allocator](https://github.com/jemalloc/jemalloc), which is copyrighted by Jason Evans, Mozilla Foundation, and Facebook, Inc and released under the two-clause BSD license. -* Inside Jemalloc, the file `pprof` is copyrighted by Google Inc. and released under the **three-clause BSD license**. +* Inside Jemalloc, the file pprof is copyrighted by Google Inc. and released under the three-clause BSD license. -* Inside Jemalloc the files `inttypes.h`, `stdbool.h`, `stdint.h`, `strings.h` under the `msvc_compat` directory are copyright Alexander Chemeris and released under the **three-clause BSD license**. +* Inside Jemalloc the files inttypes.h, stdbool.h, stdint.h, strings.h under the msvc_compat directory are copyright Alexander Chemeris and released under the three-clause BSD license. -* The libraries **hiredis** and **linenoise** also included inside the Redis distribution are copyright Salvatore Sanfilippo and Pieter Noordhuis and released under the terms respectively of the **three-clause BSD license** and **two-clause BSD license**. \ No newline at end of file +* The libraries hiredis and linenoise also included inside the Redis distribution are copyright Salvatore Sanfilippo and Pieter Noordhuis and released under the terms respectively of the three-clause BSD license and two-clause BSD license. \ No newline at end of file diff --git a/docs/about/sponsors.md b/docs/about/sponsors.md deleted file mode 100644 index 1426a14509..0000000000 --- a/docs/about/sponsors.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: "Redis sponsors" -linkTitle: "Sponsors" -weight: 4 -description: Current and former Redis sponsors -aliases: - - /topics/sponsors ---- - -From 2015 to 2020, Salvatore Sanfilippo's work on Redis was sponsored by [Redis Ltd.](https://redis.com) Since June 2020, Redis Ltd. has sponsored the [governance of Redis](/topics/governance). Redis Ltd. also sponsors the hosting and maintenance of [redis.io](https://redis.io). - -Past sponsorships: - -* The [Shuttleworth Foundation](https://en.wikipedia.org/wiki/Shuttleworth_Foundation) has donated 5000 USD to the Redis project in form of a flash grant. -* From May 2013 to June 2015, the work [Salvatore Sanfilippo](http://twitter.com/antirez) did to develop Redis was sponsored by [Pivotal](http://gopivotal.com). -* Before May 2013, the project was sponsored by VMware with the work of [Salvatore Sanfilippo](http://twitter.com/antirez) and [Pieter Noordhuis](http://twitter.com/pnoordhuis). -* [VMware](http://vmware.com) and later [Pivotal](http://pivotal.io) provided a 24 GB RAM workstation for Salvatore to run the Redis CI test and other long running tests. Later, Salvatore equipped the server with an SSD drive in order to test in the same hardware with rotating and flash drives. -* [Linode](https://linode.com), in January 2010, provided virtual machines for Redis testing in a virtualized environment. -* Slicehost, January 2010, provided Virtual Machines for Redis testing in a virtualized environment. -* [Citrusbyte](http://citrusbyte.com), in December 2009, contributed part of Virtual Memory implementation. -* [Hitmeister](http://www.hitmeister.de/), in December 2009, contributed part of Redis Cluster. -* [Engine Yard](http://engineyard.com), in December 2009, contributed blocking POP (BLPOP) and part of the Virtual Memory implementation. - -Also thanks to the following people or organizations that donated to the Project: - -* Emil Vladev -* [Brad Jasper](http://bradjasper.com/) -* [Mrkris](http://mrkris.com/) - -The Redis community is grateful to [Redis Ltd.](http://redis.com), [Pivotal](http://gopivotal.com), [VMware](http://vmware.com) and to the other companies and people who have donated to the Redis project. Thank you. - -## redis.io - -[Citrusbyte](https://citrusbyte.com) sponsored the creation of the official -Redis logo (designed by Carlos Prioglio) and -transferred its copyright to Salvatore Sanfilippo. - -They also sponsored the initial implementation of this site by -[Damian Janowski](https://twitter.com/djanowski) and [Michel -Martens](https://twitter.com/soveran). - -The `redis.io` domain was donated for a few years to the project by [I Want My -Name](https://iwantmyname.com). From 02d8fcdd47f32b8f234b3c6ce76761e2baac9947 Mon Sep 17 00:00:00 2001 From: David Dougherty Date: Fri, 22 Mar 2024 08:27:00 -0700 Subject: [PATCH 370/377] Add Lettuce quick start guide (#2695) * DOC-3406: add Lettuce quick start guide * Adhere to async and reactive APIs * Apply suggestions from code review Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> * Apply suggestions from code review Thank you, Michelle! Co-authored-by: mich-elle-luna <153109578+mich-elle-luna@users.noreply.github.com> --------- Co-authored-by: Igor Malinovskiy Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Co-authored-by: mich-elle-luna <153109578+mich-elle-luna@users.noreply.github.com> --- docs/connect/clients/lettuce.md | 246 ++++++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 docs/connect/clients/lettuce.md diff --git a/docs/connect/clients/lettuce.md b/docs/connect/clients/lettuce.md new file mode 100644 index 0000000000..5e94ac4497 --- /dev/null +++ b/docs/connect/clients/lettuce.md @@ -0,0 +1,246 @@ +--- +title: "Lettuce guide" +linkTitle: "Lettuce" +description: Connect your Lettuce application to a Redis database +weight: 3 +--- + +Install Redis and the Redis client, then connect your Lettuce application to a Redis database. + +## Lettuce + +Lettuce offers a powerful and efficient way to interact with Redis through its asynchronous and reactive APIs. By leveraging these capabilities, you can build high-performance, scalable Java applications that make optimal use of Redis's capabilities. + +## Install + +To include Lettuce as a dependency in your application, edit the appropriate dependency file as shown below. + +If you use Maven, add the following dependency to your `pom.xml`: + +```xml + + io.lettuce + lettuce-core + 6.3.2.RELEASE + +``` + +If you use Gradle, include this line in your `build.gradle` file: + +``` +dependencies { + compile 'io.lettuce:lettuce-core:6.3.2.RELEASE +} +``` + +If you wish to use the JAR files directly, download the latest Lettuce and, optionally, Apache Commons Pool2 JAR files from Maven Central or any other Maven repository. + +To build from source, see the instructions on the [Lettuce source code GitHub repo](https://github.com/lettuce-io/lettuce-core). + +## Connect + +Start by creating a connection to your Redis server. There are many ways to achieve this using Lettuce. Here are a few. + +### Asynchronous connection + +```java +package org.example; +import java.util.*; +import java.util.concurrent.ExecutionException; + +import io.lettuce.core.*; +import io.lettuce.core.api.async.RedisAsyncCommands; +import io.lettuce.core.api.StatefulRedisConnection; + +public class Async { + public static void main(String[] args) { + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisAsyncCommands asyncCommands = connection.async(); + + // Asynchronously store & retrieve a simple string + asyncCommands.set("foo", "bar").get(); + System.out.println(asyncCommands.get("foo").get()); // prints bar + + // Asynchronously store key-value pairs in a hash directly + Map hash = new HashMap<>(); + hash.put("name", "John"); + hash.put("surname", "Smith"); + hash.put("company", "Redis"); + hash.put("age", "29"); + asyncCommands.hset("user-session:123", hash).get(); + + System.out.println(asyncCommands.hgetall("user-session:123").get()); + // Prints: {name=John, surname=Smith, company=Redis, age=29} + } catch (ExecutionException | InterruptedException e) { + throw new RuntimeException(e); + } finally { + redisClient.shutdown(); + } + } +} +``` + +Learn more about asynchronous Lettuce API in [the reference guide](https://lettuce.io/core/release/reference/index.html#asynchronous-api). + +### Reactive connection + +```java +package org.example; +import java.util.*; +import io.lettuce.core.*; +import io.lettuce.core.api.reactive.RedisReactiveCommands; +import io.lettuce.core.api.StatefulRedisConnection; + +public class Main { + public static void main(String[] args) { + RedisClient redisClient = RedisClient.create("redis://localhost:6379"); + + try (StatefulRedisConnection connection = redisClient.connect()) { + RedisReactiveCommands reactiveCommands = connection.reactive(); + + // Reactively store & retrieve a simple string + reactiveCommands.set("foo", "bar").block(); + reactiveCommands.get("foo").doOnNext(System.out::println).block(); // prints bar + + // Reactively store key-value pairs in a hash directly + Map hash = new HashMap<>(); + hash.put("name", "John"); + hash.put("surname", "Smith"); + hash.put("company", "Redis"); + hash.put("age", "29"); + + reactiveCommands.hset("user-session:124", hash).then( + reactiveCommands.hgetall("user-session:124") + .collectMap(KeyValue::getKey, KeyValue::getValue).doOnNext(System.out::println)) + .block(); + // Prints: {surname=Smith, name=John, company=Redis, age=29} + + } finally { + redisClient.shutdown(); + } + } +} +``` + +Learn more about reactive Lettuce API in [the reference guide](https://lettuce.io/core/release/reference/index.html#reactive-api). + +### Redis Cluster connection + +```java +import io.lettuce.core.RedisURI; +import io.lettuce.core.cluster.RedisClusterClient; +import io.lettuce.core.cluster.api.StatefulRedisClusterConnection; +import io.lettuce.core.cluster.api.async.RedisAdvancedClusterAsyncCommands; + +// ... + +RedisURI redisUri = RedisURI.Builder.redis("localhost").withPassword("authentication").build(); + +RedisClusterClient clusterClient = RedisClusterClient.create(redisUri); +StatefulRedisClusterConnection connection = clusterClient.connect(); +RedisAdvancedClusterAsyncCommands commands = connection.async(); + +// ... + +connection.close(); +clusterClient.shutdown(); +``` + +### TLS connection + +When you deploy your application, use TLS and follow the [Redis security guidelines](/docs/management/security/). + +```java +RedisURI redisUri = RedisURI.Builder.redis("localhost") + .withSsl(true) + .withPassword("secret!") // use your Redis password + .build(); + +RedisClient client = RedisClient.create(redisUri); +``` + + + +## Connection Management in Lettuce + +Lettuce uses `ClientResources` for efficient management of shared resources like event loop groups and thread pools. +For connection pooling, Lettuce leverages `RedisClient` or `RedisClusterClient`, which can handle multiple concurrent connections efficiently. + +A typical approach with Lettuce is to create a single `RedisClient` instance and reuse it to establish connections to your Redis server(s). +These connections are multiplexed; that is, multiple commands can be run concurrently over a single or a small set of connections, making explicit pooling less critical. + +Lettuce provides pool config to be used with Lettuce asynchronous connection methods. + + +```java +package org.example; +import io.lettuce.core.RedisClient; +import io.lettuce.core.RedisURI; +import io.lettuce.core.TransactionResult; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.async.RedisAsyncCommands; +import io.lettuce.core.codec.StringCodec; +import io.lettuce.core.support.*; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +public class Pool { + public static void main(String[] args) { + RedisClient client = RedisClient.create(); + + String host = "localhost"; + int port = 6379; + + CompletionStage>> poolFuture + = AsyncConnectionPoolSupport.createBoundedObjectPoolAsync( + () -> client.connectAsync(StringCodec.UTF8, RedisURI.create(host, port)), + BoundedPoolConfig.create()); + + // await poolFuture initialization to avoid NoSuchElementException: Pool exhausted when starting your application + AsyncPool> pool = poolFuture.toCompletableFuture() + .join(); + + // execute work + CompletableFuture transactionResult = pool.acquire() + .thenCompose(connection -> { + + RedisAsyncCommands async = connection.async(); + + async.multi(); + async.set("key", "value"); + async.set("key2", "value2"); + System.out.println("Executed commands in pipeline"); + return async.exec().whenComplete((s, throwable) -> pool.release(connection)); + }); + transactionResult.join(); + + // terminating + pool.closeAsync(); + + // after pool completion + client.shutdownAsync(); + } +} +``` + +In this setup, `LettuceConnectionFactory` is a custom class you would need to implement, adhering to Apache Commons Pool's `PooledObjectFactory` interface, to manage lifecycle events of pooled `StatefulRedisConnection` objects. + +## DNS cache and Redis + +When you connect to a Redis database with multiple endpoints, such as Redis Enterprise Active-Active, it's recommended to disable the JVM's DNS cache to load-balance requests across multiple endpoints. + +You can do this in your application's code with the following snippet: + +```java +java.security.Security.setProperty("networkaddress.cache.ttl","0"); +java.security.Security.setProperty("networkaddress.cache.negative.ttl", "0"); +``` + +## Learn more + +- [Lettuce reference documentation](https://lettuce.io/docs/) +- [Redis commands](https://redis.io/commands) +- [Project Reactor](https://projectreactor.io/) \ No newline at end of file From c3124c58d3279885e956e27d870432928f358bad Mon Sep 17 00:00:00 2001 From: Igor Malinovskiy Date: Tue, 26 Mar 2024 17:11:13 +0100 Subject: [PATCH 371/377] Add Production usage docs for Node-Redis (#2696) * Add Production usage docs for Node-Redis * Update docs/connect/clients/nodejs.md Co-authored-by: David Dougherty * Update docs/connect/clients/nodejs.md Co-authored-by: David Dougherty * Update docs/connect/clients/nodejs.md Co-authored-by: David Dougherty * Update docs/connect/clients/nodejs.md Co-authored-by: David Dougherty * Update docs/connect/clients/nodejs.md Co-authored-by: David Dougherty * Update docs/connect/clients/nodejs.md Co-authored-by: David Dougherty * Address review suggestions --------- Co-authored-by: David Dougherty --- docs/connect/clients/nodejs.md | 189 +++++++++------------------------ 1 file changed, 50 insertions(+), 139 deletions(-) diff --git a/docs/connect/clients/nodejs.md b/docs/connect/clients/nodejs.md index 24b4824051..4c7aa13c0f 100644 --- a/docs/connect/clients/nodejs.md +++ b/docs/connect/clients/nodejs.md @@ -136,166 +136,77 @@ await client.disconnect(); You can also use discrete parameters and UNIX sockets. Details can be found in the [client configuration guide](https://github.com/redis/node-redis/blob/master/docs/client-configuration.md). -### Example: Indexing and querying JSON documents +### Production usage -Make sure that you have Redis Stack and `node-redis` installed. Import dependencies: +#### Handling errors +Node-Redis provides [multiple events to handle various scenarios](https://github.com/redis/node-redis?tab=readme-ov-file#events), among which the most critical is the `error` event. -```js -import {AggregateSteps, AggregateGroupByReducers, createClient, SchemaFieldTypes} from 'redis'; -const client = createClient(); -await client.connect(); -``` +This event is triggered whenever an error occurs within the client. -Create an index. +It is crucial to listen for error events. -```js -try { - await client.ft.create('idx:users', { - '$.name': { - type: SchemaFieldTypes.TEXT, - SORTABLE: true - }, - '$.city': { - type: SchemaFieldTypes.TEXT, - AS: 'city' - }, - '$.age': { - type: SchemaFieldTypes.NUMERIC, - AS: 'age' - } - }, { - ON: 'JSON', - PREFIX: 'user:' - }); -} catch (e) { - if (e.message === 'Index already exists') { - console.log('Index exists already, skipped creation.'); - } else { - // Something went wrong, perhaps RediSearch isn't installed... - console.error(e); - process.exit(1); - } -} -``` -Create JSON documents to add to your database. +If a client does not register at least one error listener and an error occurs, the system will throw that error, potentially causing the Node.js process to exit unexpectedly. +See [the EventEmitter docs](https://nodejs.org/api/events.html#events_error_events) for more details. -```js -await Promise.all([ - client.json.set('user:1', '$', { - "name": "Paul John", - "email": "paul.john@example.com", - "age": 42, - "city": "London" - }), - client.json.set('user:2', '$', { - "name": "Eden Zamir", - "email": "eden.zamir@example.com", - "age": 29, - "city": "Tel Aviv" - }), - client.json.set('user:3', '$', { - "name": "Paul Zamir", - "email": "paul.zamir@example.com", - "age": 35, - "city": "Tel Aviv" - }), -]); +```typescript +const client = createClient({ + // ... client options +}); +// Always ensure there's a listener for errors in the client to prevent process crashes due to unhandled errors +client.on('error', error => { + console.error(`Redis client error:`, error); +}); ``` -Let's find user 'Paul` and filter the results by age. -```js -let result = await client.ft.search( - 'idx:users', - 'Paul @age:[30 40]' -); -console.log(JSON.stringify(result, null, 2)); -/* -{ - "total": 1, - "documents": [ - { - "id": "user:3", - "value": { - "name": "Paul Zamir", - "email": "paul.zamir@example.com", - "age": 35, - "city": "Tel Aviv" - } - } - ] -} - */ -``` +#### Handling reconnections -Return only the city field. +If network issues or other problems unexpectedly close the socket, the client will reject all commands already sent, since the server might have already executed them. +The rest of the pending commands will remain queued in memory until a new socket is established. +This behaviour is controlled by the `enableOfflineQueue` option, which is enabled by default. -```js -result = await client.ft.search( - 'idx:users', - 'Paul @age:[30 40]', - { - RETURN: ['$.city'] - } -); -console.log(JSON.stringify(result, null, 2)); +The client uses `reconnectStrategy` to decide when to attempt to reconnect. +The default strategy is to calculate the delay before each attempt based on the attempt number `Math.min(retries * 50, 500)`. You can customize this strategy by passing a supported value to `reconnectStrategy` option: -/* -{ - "total": 1, - "documents": [ - { - "id": "user:3", - "value": { - "$.city": "Tel Aviv" - } + +1. Define a callback `(retries: number, cause: Error) => false | number | Error` **(recommended)** +```typescript +const client = createClient({ + socket: { + reconnectStrategy: function(retries) { + if (retries > 20) { + console.log("Too many attempts to reconnect. Redis connection was terminated"); + return new Error("Too many retries."); + } else { + return retries * 500; + } } - ] -} - */ + } +}); +client.on('error', error => console.error('Redis client error:', error)); ``` - -Count all users in the same city. +In the provided reconnection strategy callback, the client attempts to reconnect up to 20 times with a delay of `retries * 500` milliseconds between attempts. +After approximately two minutes, the client logs an error message and terminates the connection if the maximum retry limit is exceeded. -```js -result = await client.ft.aggregate('idx:users', '*', { - STEPS: [ - { - type: AggregateSteps.GROUPBY, - properties: ['@city'], - REDUCE: [ - { - type: AggregateGroupByReducers.COUNT, - AS: 'count' - } - ] - } - ] -}) -console.log(JSON.stringify(result, null, 2)); -/* -{ - "total": 2, - "results": [ - { - "city": "London", - "count": "1" - }, - { - "city": "Tel Aviv", - "count": "2" - } - ] -} - */ +2. Use a numerical value to set a fixed delay in milliseconds. +3. Use `false` to disable reconnection attempts. This option should only be used for testing purposes. + +#### Timeout -await client.quit(); +To set a timeout for a connection, use the `connectTimeout` option: +```typescript +const client = createClient({ + // setting a 10-second timeout + connectTimeout: 10000 // in milliseconds +}); +client.on('error', error => console.error('Redis client error:', error)); ``` ### Learn more +* [Node-Redis Configuration Options](https://github.com/redis/node-redis/blob/master/docs/client-configuration.md) * [Redis commands](https://redis.js.org/#node-redis-usage-redis-commands) * [Programmability](https://redis.js.org/#node-redis-usage-programmability) * [Clustering](https://redis.js.org/#node-redis-usage-clustering) From 17217021cb0d3c1aa2954805b574ba4b2037e95f Mon Sep 17 00:00:00 2001 From: David Dougherty Date: Tue, 26 Mar 2024 13:45:06 -0700 Subject: [PATCH 372/377] DOC-3547: gather Java clients under Java 'folder' (#2700) --- docs/connect/clients/java/_index.md | 11 +++++++++++ docs/connect/clients/{ => java}/java.md | 2 +- docs/connect/clients/{ => java}/lettuce.md | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 docs/connect/clients/java/_index.md rename docs/connect/clients/{ => java}/java.md (97%) rename docs/connect/clients/{ => java}/lettuce.md (99%) diff --git a/docs/connect/clients/java/_index.md b/docs/connect/clients/java/_index.md new file mode 100644 index 0000000000..4c0e6a10f9 --- /dev/null +++ b/docs/connect/clients/java/_index.md @@ -0,0 +1,11 @@ +--- +title: "Connect with Redis Java clients" +linkTitle: "Java clients" +description: Connect your application to a Redis database using Java and try an example +weight: 3 +--- + +You have two choices of Java clients that you can use with Redis: + +- Jedis, for synchronous applications. +- Lettuce, for asynchronous and reactive applications. diff --git a/docs/connect/clients/java.md b/docs/connect/clients/java/java.md similarity index 97% rename from docs/connect/clients/java.md rename to docs/connect/clients/java/java.md index abe3b13d71..0ef99cf034 100644 --- a/docs/connect/clients/java.md +++ b/docs/connect/clients/java/java.md @@ -2,7 +2,7 @@ title: "Java guide" linkTitle: "Java" description: Connect your Java application to a Redis database -weight: 3 +weight: 1 aliases: - /docs/clients/java/ - /docs/redis-clients/java/ diff --git a/docs/connect/clients/lettuce.md b/docs/connect/clients/java/lettuce.md similarity index 99% rename from docs/connect/clients/lettuce.md rename to docs/connect/clients/java/lettuce.md index 5e94ac4497..47b182c5c6 100644 --- a/docs/connect/clients/lettuce.md +++ b/docs/connect/clients/java/lettuce.md @@ -2,7 +2,7 @@ title: "Lettuce guide" linkTitle: "Lettuce" description: Connect your Lettuce application to a Redis database -weight: 3 +weight: 2 --- Install Redis and the Redis client, then connect your Lettuce application to a Redis database. From 5a27794f16ae051b9ccea64ea73214ad04fb2ea2 Mon Sep 17 00:00:00 2001 From: David Dougherty Date: Tue, 26 Mar 2024 13:51:30 -0700 Subject: [PATCH 373/377] DOC-3516: updates to RC try free graphics (#2701) --- docs/get-started/data-store.md | 4 ++-- docs/get-started/img/free-cloud-db.png | Bin 713343 -> 71700 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/get-started/data-store.md b/docs/get-started/data-store.md index 79b657798e..7c9455a620 100644 --- a/docs/get-started/data-store.md +++ b/docs/get-started/data-store.md @@ -19,9 +19,9 @@ The examples in this article refer to a simple bicycle inventory. The easiest way to get started with Redis is to use Redis Cloud: 1. Create a [free account](https://redis.com/try-free?utm_source=redisio&utm_medium=referral&utm_campaign=2023-09-try_free&utm_content=cu-redis_cloud_users). + + 2. Follow the instructions to create a free database. - - You can alternatively follow the [installation guides](/docs/install/install-stack/) to install Redis on your local machine. diff --git a/docs/get-started/img/free-cloud-db.png b/docs/get-started/img/free-cloud-db.png index d4bc935230be2b2bcf6a50f458525ee69697d3cf..3336f3353aa86a997299ac8444bba6c4c6d448d7 100644 GIT binary patch literal 71700 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 Q0t0=d#O1!$h#Ca^FNWPqCIA2c literal 713343 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%0A+WX%cfluYLg_k4^Lu%h@g~IrnH) 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%0A8)8)f6{p7$SO;K6Z8&Gh{KH?Y$%e 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 acjtQh*7@+6#p8bv{wc_+K0w|xdHR2sE@HO; From 18b7b7c949b0276bcc614e88101b411dba6e1f15 Mon Sep 17 00:00:00 2001 From: David Dougherty <david.dougherty@redis.com> Date: Thu, 28 Mar 2024 11:11:54 -0700 Subject: [PATCH 374/377] DOC-3564: fix Java client menu (#2704) --- docs/connect/clients/java/_index.md | 2 +- docs/connect/clients/java/{java.md => jedis.md} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename docs/connect/clients/java/{java.md => jedis.md} (97%) diff --git a/docs/connect/clients/java/_index.md b/docs/connect/clients/java/_index.md index 4c0e6a10f9..21a90ffe4b 100644 --- a/docs/connect/clients/java/_index.md +++ b/docs/connect/clients/java/_index.md @@ -1,6 +1,6 @@ --- title: "Connect with Redis Java clients" -linkTitle: "Java clients" +linkTitle: "Java" description: Connect your application to a Redis database using Java and try an example weight: 3 --- diff --git a/docs/connect/clients/java/java.md b/docs/connect/clients/java/jedis.md similarity index 97% rename from docs/connect/clients/java/java.md rename to docs/connect/clients/java/jedis.md index 0ef99cf034..aea7a8d912 100644 --- a/docs/connect/clients/java/java.md +++ b/docs/connect/clients/java/jedis.md @@ -1,6 +1,6 @@ --- -title: "Java guide" -linkTitle: "Java" +title: "Jedis guide" +linkTitle: "Jedis" description: Connect your Java application to a Redis database weight: 1 aliases: From 414d1860422b44b85274d29ff9ce42de99fc8da6 Mon Sep 17 00:00:00 2001 From: Igor Malinovskiy <igor.malinovskiy@redis.com> Date: Tue, 2 Apr 2024 18:03:35 +0200 Subject: [PATCH 375/377] Bump recommended Jedis version --- docs/connect/clients/java/jedis.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/connect/clients/java/jedis.md b/docs/connect/clients/java/jedis.md index aea7a8d912..7384fa6c77 100644 --- a/docs/connect/clients/java/jedis.md +++ b/docs/connect/clients/java/jedis.md @@ -24,7 +24,7 @@ To include `Jedis` as a dependency in your application, edit the dependency file <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> - <version>4.3.1</version> + <version>5.1.2</version> </dependency> ``` @@ -36,7 +36,7 @@ To include `Jedis` as a dependency in your application, edit the dependency file } //... dependencies { - implementation 'redis.clients:jedis:4.3.1' + implementation 'redis.clients:jedis:5.1.2' //... } ``` From 3541d0e20cc4bb7873bdbf51a7717757b806577f Mon Sep 17 00:00:00 2001 From: David Maier <60782329+dmaier-redislabs@users.noreply.github.com> Date: Tue, 9 Apr 2024 00:16:44 +0200 Subject: [PATCH 376/377] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 873edc9a6f..1a93bea2d1 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # Redis documentation +> **Important**: This repository got replaced by the new [Redis docs](https://github.com/redis/docs) repository and will be archived soon. + + +## License vs Trademarks + OPEN SOURCE LICENSE VS. TRADEMARKS. The three-clause BSD license gives you the right to redistribute and use the software in source and binary forms, with or without modification, under certain conditions. However, open source licenses like the three-clause BSD license do not address trademarks. For further details please read the [Redis Trademark Policy](https://www.redis.com/legal/trademark-policy)." ## Clients From 8b0dfd86fe07e43ac10db1074df978fe28b37269 Mon Sep 17 00:00:00 2001 From: mich-elle-luna <153109578+mich-elle-luna@users.noreply.github.com> Date: Mon, 23 Jun 2025 09:45:57 -0700 Subject: [PATCH 377/377] Update distributed-locks.md remove risky link --- docs/manual/patterns/distributed-locks.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/manual/patterns/distributed-locks.md b/docs/manual/patterns/distributed-locks.md index 603e0e91fc..e4169f8970 100644 --- a/docs/manual/patterns/distributed-locks.md +++ b/docs/manual/patterns/distributed-locks.md @@ -46,7 +46,6 @@ already available that can be used for reference. * [Redis-plus-plus](https://github.com/sewenew/redis-plus-plus/#redlock) (C++ implementation). * [Redlock-cs](https://github.com/kidfashion/redlock-cs) (C#/.NET implementation). * [RedLock.net](https://github.com/samcook/RedLock.net) (C#/.NET implementation). Includes async and lock extension support. -* [ScarletLock](https://github.com/psibernetic/scarletlock) (C# .NET implementation with configurable datastore). * [Redlock4Net](https://github.com/LiZhenNet/Redlock4Net) (C# .NET implementation). * [node-redlock](https://github.com/mike-marcacci/node-redlock) (NodeJS implementation). Includes support for lock extension. * [Deno DLM](https://github.com/oslabs-beta/Deno-Redlock) (Deno implementation)