Skip to content

Commit eb5f009

Browse files
committed
add support for sending commands without key parameter to redis cluster.
1 parent 7c19a8e commit eb5f009

File tree

5 files changed

+31
-2
lines changed

5 files changed

+31
-2
lines changed

README.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,8 @@ auto pipe = redis.pipeline();
919919

920920
When creating a `Pipeline` object, `Redis::pipeline` method creates a new connection to Redis server. This connection is NOT picked from the connection pool, but a newly created connection. This connection has the same `ConnectionOptions` with other connections in the connection pool. `Pipeline` object maintains the new connection, and all piped commands are sent through this connection.
921921

922+
**NOTE**: Creating a `Pipeline` object is NOT cheap, since it creates a new connection. So you'd better reuse the `Pipeline` as much as possible.
923+
922924
#### Send Commands
923925

924926
You can send Redis commands through the `Pipeline` object. Just like the `Redis` class, `Pipeline` has one or more (overloaded) methods for each Redis command. However, you CANNOT get the replies until you call `Pipeline::exec`. So these methods do NOT return the reply, instead they return the `Pipeline` object itself. And you can chain these methods calls.
@@ -1003,6 +1005,8 @@ auto tx = redis.transaction();
10031005

10041006
As the `Pipeline` class, `Transaction` maintains a newly created connection to Redis. This connection has the same `ConnectionOptions` with the `Redis` object.
10051007

1008+
**NOTE**: Creating a `Transaction` object is NOT cheap, since it creates a new connection. So you'd better reuse the `Transaction` as much as possible.
1009+
10061010
Also you don't need to send [MULTI](https://redis.io/commands/multi) command to Redis. `Transaction` will do that for you automatically.
10071011

10081012
#### Send Commands
@@ -1077,7 +1081,7 @@ auto redis = Redis("tcp://127.0.0.1");
10771081
// Create a transaction.
10781082
auto tx = redis.transaction();
10791083
1080-
// Create a Redis object from the Transaction object, which share a single connection.
1084+
// Create a Redis object from the Transaction object. Both objects share the same connection.
10811085
auto r = tx.redis();
10821086
10831087
// If the watched key has been modified by other clients, the transaction might fail.
@@ -1166,7 +1170,10 @@ As we mentioned, `RedisCluster`'s interfaces are similar to `Redis`. It supports
11661170
- Not support commands without key as argument, e.g. [PING](https://redis.io/commands/ping), [INFO](https://redis.io/commands/info).
11671171
- Not support Lua script without key parameters.
11681172

1169-
`RedisCluster` does NOT support these interfaces, because it has no idea to which node these commands should be sent.
1173+
`RedisCluster` does NOT have built-in methods to send these commands or Lua scripts. Since there's no key parameter, `RedisCluster` has no idea to which node these commands should be sent. However there're 2 workarounds for this problem:
1174+
1175+
- If you want to send these commands to a specific node, you can create a `Redis` object with that node's host and port, and use the `Redis` object to do the work.
1176+
- Instead of host and port, you can also call `Redis RedisCluster::redis(const StringView &hash_tag)` to create a `Redis` object with a hash-tag specifying the node. In this case, the returned `Redis` object creates a new connection to Redis server.
11701177

11711178
Also you can use the [hash tags](https://redis.io/topics/cluster-spec#keys-hash-tags) to send multiple-key commands.
11721179

@@ -1218,6 +1225,12 @@ auto replies = pipe.incr("{counter}:1").incr("{counter}:2").exec();
12181225
// Transaction.
12191226
auto tx = redis_cluster.transaction("key");
12201227
replies = tx.incr("key").get("key").exec();
1228+
1229+
// Create a Redis object with hash-tag.
1230+
auto r = redis_cluster.redis("hash-tag");
1231+
1232+
// And send command without key parameter to the server.
1233+
r.command("client", "setname", "connection-name");
12211234
```
12221235

12231236
#### Details

src/sw/redis++/redis.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,6 +1088,8 @@ class Redis {
10881088
template <typename Impl>
10891089
friend class QueuedRedis;
10901090

1091+
friend class RedisCluster;
1092+
10911093
// For internal use.
10921094
explicit Redis(const ConnectionSPtr &connection);
10931095

src/sw/redis++/redis_cluster.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ namespace redis {
2626

2727
RedisCluster::RedisCluster(const std::string &uri) : RedisCluster(ConnectionOptions(uri)) {}
2828

29+
Redis RedisCluster::redis(const StringView &hash_tag) {
30+
auto opts = _pool.connection_options(hash_tag);
31+
return Redis(std::make_shared<Connection>(opts));
32+
}
33+
2934
Pipeline RedisCluster::pipeline(const StringView &hash_tag) {
3035
auto opts = _pool.connection_options(hash_tag);
3136
return Pipeline(std::make_shared<Connection>(opts));

src/sw/redis++/redis_cluster.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "subscriber.h"
2929
#include "pipeline.h"
3030
#include "transaction.h"
31+
#include "redis.h"
3132

3233
namespace sw {
3334

@@ -57,6 +58,8 @@ class RedisCluster {
5758
RedisCluster(RedisCluster &&) = default;
5859
RedisCluster& operator=(RedisCluster &&) = default;
5960

61+
Redis redis(const StringView &hash_tag);
62+
6063
Pipeline pipeline(const StringView &hash_tag);
6164

6265
Transaction transaction(const StringView &hash_tag, bool piped = false);

test/src/sw/redis++/cluster_test.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ void ClusterTest::_test_cluster() {
6666
_redis_cluster.zadd(zset_key, member, score);
6767
auto res = _redis_cluster.zscore(zset_key, member);
6868
REDIS_ASSERT(res && score == *res, "failed to test cluster: zadd/zscore commands");
69+
70+
auto r = _redis_cluster.redis("hash-tag");
71+
r.command("client", "setname", "my-name");
72+
auto reply = r.command("client", "getname");
73+
val = reply::parse<OptionalString>(*reply);
74+
REDIS_ASSERT(val && *val == "my-name", "failed to test cluster");
6975
}
7076

7177
void ClusterTest::_test_hash_tag() {

0 commit comments

Comments
 (0)