pub struct ClusterClient { /* private fields */ }Expand description
One open connection per distinct shard node, with a slot → shard index so a single-key command goes straight to its owner.
Implementations§
Source§impl ClusterClient
impl ClusterClient
Sourcepub fn connect(host: &str, port: u16) -> Result<Self>
pub fn connect(host: &str, port: u16) -> Result<Self>
Connect via a seed node, discover the topology (CLUSTER SLOTS), and
open one connection per shard.
Examples found in repository?
18fn main() -> std::io::Result<()> {
19 let seed: u16 = std::env::args()
20 .nth(1)
21 .and_then(|s| s.parse().ok())
22 .unwrap_or(6005);
23
24 // Connect to a seed shard; the full topology is discovered from it.
25 let mut cc = ClusterClient::connect("127.0.0.1", seed)?;
26 println!("connected — {} shard(s)", cc.shard_count());
27
28 // Each of these keys may live on a different shard; the client routes each
29 // to its owner with no -MOVED and no forwarding hop.
30 cc.set(b"user:1", b"alice")?;
31 cc.set(b"user:2", b"bob")?;
32 cc.set(b"user:3", b"carol")?;
33
34 println!("user:1 = {:?}", cc.get(b"user:1")?.map(String::from_utf8));
35
36 // INCR routes by key like any single-key command.
37 let n = cc.incr(b"counter")?;
38 println!("counter = {n}");
39
40 // DEL/EXISTS take keys that may span shards — routed per key and summed.
41 let exists = cc.exists(&[b"user:1", b"user:2", b"missing"])?;
42 println!("exists(user:1, user:2, missing) = {exists}"); // 2
43
44 let removed = cc.del(&[b"user:1", b"user:2", b"user:3"])?;
45 println!("deleted {removed} keys"); // 3
46
47 // DBSIZE / FLUSHALL are whole-cluster: kevy fans them out server-side, so
48 // one call covers every shard.
49 println!("dbsize (whole cluster) = {}", cc.dbsize()?);
50
51 Ok(())
52}More examples
16fn main() {
17 let a: Vec<String> = std::env::args().collect();
18 let seed: u16 = a.get(1).and_then(|s| s.parse().ok()).unwrap_or(7001);
19 let iters: usize = a.get(2).and_then(|s| s.parse().ok()).unwrap_or(20_000);
20 let keys: usize = a.get(3).and_then(|s| s.parse().ok()).unwrap_or(1000);
21 let conc: usize = a.get(4).and_then(|s| s.parse().ok()).unwrap_or(8);
22
23 // Populate.
24 {
25 let mut cc = ClusterClient::connect("127.0.0.1", seed).unwrap();
26 for k in 0..keys {
27 cc.set(format!("k{k}").as_bytes(), b"v").unwrap();
28 }
29 }
30
31 let t0 = Instant::now();
32 let handles: Vec<_> = (0..conc)
33 .map(|c| {
34 std::thread::spawn(move || {
35 let mut cc = ClusterClient::connect("127.0.0.1", seed).unwrap();
36 let mut lat = Vec::with_capacity(iters);
37 for i in 0..iters {
38 let key = format!("k{}", (i * 7 + c * 131) % keys);
39 let t = Instant::now();
40 let _ = cc.get(key.as_bytes()).unwrap();
41 lat.push(t.elapsed().as_nanos() as u64);
42 }
43 lat
44 })
45 })
46 .collect();
47 let mut all = Vec::new();
48 for h in handles {
49 all.extend(h.join().unwrap());
50 }
51 let wall = t0.elapsed().as_secs_f64();
52 all.sort_unstable();
53 let p = |q: f64| all[((all.len() as f64 * q) as usize).min(all.len() - 1)] as f64 / 1000.0;
54 println!(
55 "ClusterClient conc={conc} n={} ops/s={:.0} p50={:.1}us p99={:.1}us p999={:.1}us",
56 all.len(),
57 all.len() as f64 / wall,
58 p(0.50),
59 p(0.99),
60 p(0.999),
61 );
62}Sourcepub fn request_keyed(&mut self, key: &[u8], args: &[Vec<u8>]) -> Result<Reply>
pub fn request_keyed(&mut self, key: &[u8], args: &[Vec<u8>]) -> Result<Reply>
Route a single-key command (args) to the shard owning key.
Sourcepub fn request_unkeyed(&mut self, args: &[Vec<u8>]) -> Result<Reply>
pub fn request_unkeyed(&mut self, args: &[Vec<u8>]) -> Result<Reply>
A keyless command (PING / etc.) — answered identically by any shard, so send it to the first.
Sourcepub fn shard_count(&self) -> usize
pub fn shard_count(&self) -> usize
Number of distinct shard nodes.
Examples found in repository?
18fn main() -> std::io::Result<()> {
19 let seed: u16 = std::env::args()
20 .nth(1)
21 .and_then(|s| s.parse().ok())
22 .unwrap_or(6005);
23
24 // Connect to a seed shard; the full topology is discovered from it.
25 let mut cc = ClusterClient::connect("127.0.0.1", seed)?;
26 println!("connected — {} shard(s)", cc.shard_count());
27
28 // Each of these keys may live on a different shard; the client routes each
29 // to its owner with no -MOVED and no forwarding hop.
30 cc.set(b"user:1", b"alice")?;
31 cc.set(b"user:2", b"bob")?;
32 cc.set(b"user:3", b"carol")?;
33
34 println!("user:1 = {:?}", cc.get(b"user:1")?.map(String::from_utf8));
35
36 // INCR routes by key like any single-key command.
37 let n = cc.incr(b"counter")?;
38 println!("counter = {n}");
39
40 // DEL/EXISTS take keys that may span shards — routed per key and summed.
41 let exists = cc.exists(&[b"user:1", b"user:2", b"missing"])?;
42 println!("exists(user:1, user:2, missing) = {exists}"); // 2
43
44 let removed = cc.del(&[b"user:1", b"user:2", b"user:3"])?;
45 println!("deleted {removed} keys"); // 3
46
47 // DBSIZE / FLUSHALL are whole-cluster: kevy fans them out server-side, so
48 // one call covers every shard.
49 println!("dbsize (whole cluster) = {}", cc.dbsize()?);
50
51 Ok(())
52}Source§impl ClusterClient
impl ClusterClient
Sourcepub fn publish(&mut self, channel: &[u8], message: &[u8]) -> Result<usize>
pub fn publish(&mut self, channel: &[u8], message: &[u8]) -> Result<usize>
PUBLISH channel message — returns the number of subscribers reached.
kevy’s pub/sub is process-global (delivered to subscribers on every
core), so a cluster PUBLISH goes to any one shard.
Sourcepub fn set(&mut self, key: &[u8], value: &[u8]) -> Result<()>
pub fn set(&mut self, key: &[u8], value: &[u8]) -> Result<()>
SET key value.
Examples found in repository?
18fn main() -> std::io::Result<()> {
19 let seed: u16 = std::env::args()
20 .nth(1)
21 .and_then(|s| s.parse().ok())
22 .unwrap_or(6005);
23
24 // Connect to a seed shard; the full topology is discovered from it.
25 let mut cc = ClusterClient::connect("127.0.0.1", seed)?;
26 println!("connected — {} shard(s)", cc.shard_count());
27
28 // Each of these keys may live on a different shard; the client routes each
29 // to its owner with no -MOVED and no forwarding hop.
30 cc.set(b"user:1", b"alice")?;
31 cc.set(b"user:2", b"bob")?;
32 cc.set(b"user:3", b"carol")?;
33
34 println!("user:1 = {:?}", cc.get(b"user:1")?.map(String::from_utf8));
35
36 // INCR routes by key like any single-key command.
37 let n = cc.incr(b"counter")?;
38 println!("counter = {n}");
39
40 // DEL/EXISTS take keys that may span shards — routed per key and summed.
41 let exists = cc.exists(&[b"user:1", b"user:2", b"missing"])?;
42 println!("exists(user:1, user:2, missing) = {exists}"); // 2
43
44 let removed = cc.del(&[b"user:1", b"user:2", b"user:3"])?;
45 println!("deleted {removed} keys"); // 3
46
47 // DBSIZE / FLUSHALL are whole-cluster: kevy fans them out server-side, so
48 // one call covers every shard.
49 println!("dbsize (whole cluster) = {}", cc.dbsize()?);
50
51 Ok(())
52}More examples
16fn main() {
17 let a: Vec<String> = std::env::args().collect();
18 let seed: u16 = a.get(1).and_then(|s| s.parse().ok()).unwrap_or(7001);
19 let iters: usize = a.get(2).and_then(|s| s.parse().ok()).unwrap_or(20_000);
20 let keys: usize = a.get(3).and_then(|s| s.parse().ok()).unwrap_or(1000);
21 let conc: usize = a.get(4).and_then(|s| s.parse().ok()).unwrap_or(8);
22
23 // Populate.
24 {
25 let mut cc = ClusterClient::connect("127.0.0.1", seed).unwrap();
26 for k in 0..keys {
27 cc.set(format!("k{k}").as_bytes(), b"v").unwrap();
28 }
29 }
30
31 let t0 = Instant::now();
32 let handles: Vec<_> = (0..conc)
33 .map(|c| {
34 std::thread::spawn(move || {
35 let mut cc = ClusterClient::connect("127.0.0.1", seed).unwrap();
36 let mut lat = Vec::with_capacity(iters);
37 for i in 0..iters {
38 let key = format!("k{}", (i * 7 + c * 131) % keys);
39 let t = Instant::now();
40 let _ = cc.get(key.as_bytes()).unwrap();
41 lat.push(t.elapsed().as_nanos() as u64);
42 }
43 lat
44 })
45 })
46 .collect();
47 let mut all = Vec::new();
48 for h in handles {
49 all.extend(h.join().unwrap());
50 }
51 let wall = t0.elapsed().as_secs_f64();
52 all.sort_unstable();
53 let p = |q: f64| all[((all.len() as f64 * q) as usize).min(all.len() - 1)] as f64 / 1000.0;
54 println!(
55 "ClusterClient conc={conc} n={} ops/s={:.0} p50={:.1}us p99={:.1}us p999={:.1}us",
56 all.len(),
57 all.len() as f64 / wall,
58 p(0.50),
59 p(0.99),
60 p(0.999),
61 );
62}Sourcepub fn set_with_ttl(
&mut self,
key: &[u8],
value: &[u8],
ttl: Duration,
) -> Result<()>
pub fn set_with_ttl( &mut self, key: &[u8], value: &[u8], ttl: Duration, ) -> Result<()>
SET key value PX ttl_ms — value with an expiry.
Sourcepub fn get(&mut self, key: &[u8]) -> Result<Option<Vec<u8>>>
pub fn get(&mut self, key: &[u8]) -> Result<Option<Vec<u8>>>
GET key. None if absent or expired.
Examples found in repository?
18fn main() -> std::io::Result<()> {
19 let seed: u16 = std::env::args()
20 .nth(1)
21 .and_then(|s| s.parse().ok())
22 .unwrap_or(6005);
23
24 // Connect to a seed shard; the full topology is discovered from it.
25 let mut cc = ClusterClient::connect("127.0.0.1", seed)?;
26 println!("connected — {} shard(s)", cc.shard_count());
27
28 // Each of these keys may live on a different shard; the client routes each
29 // to its owner with no -MOVED and no forwarding hop.
30 cc.set(b"user:1", b"alice")?;
31 cc.set(b"user:2", b"bob")?;
32 cc.set(b"user:3", b"carol")?;
33
34 println!("user:1 = {:?}", cc.get(b"user:1")?.map(String::from_utf8));
35
36 // INCR routes by key like any single-key command.
37 let n = cc.incr(b"counter")?;
38 println!("counter = {n}");
39
40 // DEL/EXISTS take keys that may span shards — routed per key and summed.
41 let exists = cc.exists(&[b"user:1", b"user:2", b"missing"])?;
42 println!("exists(user:1, user:2, missing) = {exists}"); // 2
43
44 let removed = cc.del(&[b"user:1", b"user:2", b"user:3"])?;
45 println!("deleted {removed} keys"); // 3
46
47 // DBSIZE / FLUSHALL are whole-cluster: kevy fans them out server-side, so
48 // one call covers every shard.
49 println!("dbsize (whole cluster) = {}", cc.dbsize()?);
50
51 Ok(())
52}More examples
16fn main() {
17 let a: Vec<String> = std::env::args().collect();
18 let seed: u16 = a.get(1).and_then(|s| s.parse().ok()).unwrap_or(7001);
19 let iters: usize = a.get(2).and_then(|s| s.parse().ok()).unwrap_or(20_000);
20 let keys: usize = a.get(3).and_then(|s| s.parse().ok()).unwrap_or(1000);
21 let conc: usize = a.get(4).and_then(|s| s.parse().ok()).unwrap_or(8);
22
23 // Populate.
24 {
25 let mut cc = ClusterClient::connect("127.0.0.1", seed).unwrap();
26 for k in 0..keys {
27 cc.set(format!("k{k}").as_bytes(), b"v").unwrap();
28 }
29 }
30
31 let t0 = Instant::now();
32 let handles: Vec<_> = (0..conc)
33 .map(|c| {
34 std::thread::spawn(move || {
35 let mut cc = ClusterClient::connect("127.0.0.1", seed).unwrap();
36 let mut lat = Vec::with_capacity(iters);
37 for i in 0..iters {
38 let key = format!("k{}", (i * 7 + c * 131) % keys);
39 let t = Instant::now();
40 let _ = cc.get(key.as_bytes()).unwrap();
41 lat.push(t.elapsed().as_nanos() as u64);
42 }
43 lat
44 })
45 })
46 .collect();
47 let mut all = Vec::new();
48 for h in handles {
49 all.extend(h.join().unwrap());
50 }
51 let wall = t0.elapsed().as_secs_f64();
52 all.sort_unstable();
53 let p = |q: f64| all[((all.len() as f64 * q) as usize).min(all.len() - 1)] as f64 / 1000.0;
54 println!(
55 "ClusterClient conc={conc} n={} ops/s={:.0} p50={:.1}us p99={:.1}us p999={:.1}us",
56 all.len(),
57 all.len() as f64 / wall,
58 p(0.50),
59 p(0.99),
60 p(0.999),
61 );
62}Sourcepub fn incr(&mut self, key: &[u8]) -> Result<i64>
pub fn incr(&mut self, key: &[u8]) -> Result<i64>
INCR key. Returns the post-increment value.
Examples found in repository?
18fn main() -> std::io::Result<()> {
19 let seed: u16 = std::env::args()
20 .nth(1)
21 .and_then(|s| s.parse().ok())
22 .unwrap_or(6005);
23
24 // Connect to a seed shard; the full topology is discovered from it.
25 let mut cc = ClusterClient::connect("127.0.0.1", seed)?;
26 println!("connected — {} shard(s)", cc.shard_count());
27
28 // Each of these keys may live on a different shard; the client routes each
29 // to its owner with no -MOVED and no forwarding hop.
30 cc.set(b"user:1", b"alice")?;
31 cc.set(b"user:2", b"bob")?;
32 cc.set(b"user:3", b"carol")?;
33
34 println!("user:1 = {:?}", cc.get(b"user:1")?.map(String::from_utf8));
35
36 // INCR routes by key like any single-key command.
37 let n = cc.incr(b"counter")?;
38 println!("counter = {n}");
39
40 // DEL/EXISTS take keys that may span shards — routed per key and summed.
41 let exists = cc.exists(&[b"user:1", b"user:2", b"missing"])?;
42 println!("exists(user:1, user:2, missing) = {exists}"); // 2
43
44 let removed = cc.del(&[b"user:1", b"user:2", b"user:3"])?;
45 println!("deleted {removed} keys"); // 3
46
47 // DBSIZE / FLUSHALL are whole-cluster: kevy fans them out server-side, so
48 // one call covers every shard.
49 println!("dbsize (whole cluster) = {}", cc.dbsize()?);
50
51 Ok(())
52}Sourcepub fn expire(&mut self, key: &[u8], ttl: Duration) -> Result<bool>
pub fn expire(&mut self, key: &[u8], ttl: Duration) -> Result<bool>
PEXPIRE key ttl_ms. Whether the key existed and got a TTL.
Sourcepub fn ttl_ms(&mut self, key: &[u8]) -> Result<i64>
pub fn ttl_ms(&mut self, key: &[u8]) -> Result<i64>
PTTL key. ms remaining, -2 no key, -1 no TTL.
Sourcepub fn del(&mut self, keys: &[&[u8]]) -> Result<usize>
pub fn del(&mut self, keys: &[&[u8]]) -> Result<usize>
DEL key [key ...] — routed per key (each to its owner) and summed, so
keys spanning shards work without a same-slot constraint.
Examples found in repository?
18fn main() -> std::io::Result<()> {
19 let seed: u16 = std::env::args()
20 .nth(1)
21 .and_then(|s| s.parse().ok())
22 .unwrap_or(6005);
23
24 // Connect to a seed shard; the full topology is discovered from it.
25 let mut cc = ClusterClient::connect("127.0.0.1", seed)?;
26 println!("connected — {} shard(s)", cc.shard_count());
27
28 // Each of these keys may live on a different shard; the client routes each
29 // to its owner with no -MOVED and no forwarding hop.
30 cc.set(b"user:1", b"alice")?;
31 cc.set(b"user:2", b"bob")?;
32 cc.set(b"user:3", b"carol")?;
33
34 println!("user:1 = {:?}", cc.get(b"user:1")?.map(String::from_utf8));
35
36 // INCR routes by key like any single-key command.
37 let n = cc.incr(b"counter")?;
38 println!("counter = {n}");
39
40 // DEL/EXISTS take keys that may span shards — routed per key and summed.
41 let exists = cc.exists(&[b"user:1", b"user:2", b"missing"])?;
42 println!("exists(user:1, user:2, missing) = {exists}"); // 2
43
44 let removed = cc.del(&[b"user:1", b"user:2", b"user:3"])?;
45 println!("deleted {removed} keys"); // 3
46
47 // DBSIZE / FLUSHALL are whole-cluster: kevy fans them out server-side, so
48 // one call covers every shard.
49 println!("dbsize (whole cluster) = {}", cc.dbsize()?);
50
51 Ok(())
52}Sourcepub fn exists(&mut self, keys: &[&[u8]]) -> Result<usize>
pub fn exists(&mut self, keys: &[&[u8]]) -> Result<usize>
EXISTS key [key ...] — routed per key and summed (a repeated key
counts each time, matching Redis).
Examples found in repository?
18fn main() -> std::io::Result<()> {
19 let seed: u16 = std::env::args()
20 .nth(1)
21 .and_then(|s| s.parse().ok())
22 .unwrap_or(6005);
23
24 // Connect to a seed shard; the full topology is discovered from it.
25 let mut cc = ClusterClient::connect("127.0.0.1", seed)?;
26 println!("connected — {} shard(s)", cc.shard_count());
27
28 // Each of these keys may live on a different shard; the client routes each
29 // to its owner with no -MOVED and no forwarding hop.
30 cc.set(b"user:1", b"alice")?;
31 cc.set(b"user:2", b"bob")?;
32 cc.set(b"user:3", b"carol")?;
33
34 println!("user:1 = {:?}", cc.get(b"user:1")?.map(String::from_utf8));
35
36 // INCR routes by key like any single-key command.
37 let n = cc.incr(b"counter")?;
38 println!("counter = {n}");
39
40 // DEL/EXISTS take keys that may span shards — routed per key and summed.
41 let exists = cc.exists(&[b"user:1", b"user:2", b"missing"])?;
42 println!("exists(user:1, user:2, missing) = {exists}"); // 2
43
44 let removed = cc.del(&[b"user:1", b"user:2", b"user:3"])?;
45 println!("deleted {removed} keys"); // 3
46
47 // DBSIZE / FLUSHALL are whole-cluster: kevy fans them out server-side, so
48 // one call covers every shard.
49 println!("dbsize (whole cluster) = {}", cc.dbsize()?);
50
51 Ok(())
52}Sourcepub fn dbsize(&mut self) -> Result<usize>
pub fn dbsize(&mut self) -> Result<usize>
DBSIZE — the cluster-wide total. kevy answers DBSIZE by fanning out
across shards internally (Route::Dbsize), so a single shard already
reports the whole-cluster count; no client-side summing.
Examples found in repository?
18fn main() -> std::io::Result<()> {
19 let seed: u16 = std::env::args()
20 .nth(1)
21 .and_then(|s| s.parse().ok())
22 .unwrap_or(6005);
23
24 // Connect to a seed shard; the full topology is discovered from it.
25 let mut cc = ClusterClient::connect("127.0.0.1", seed)?;
26 println!("connected — {} shard(s)", cc.shard_count());
27
28 // Each of these keys may live on a different shard; the client routes each
29 // to its owner with no -MOVED and no forwarding hop.
30 cc.set(b"user:1", b"alice")?;
31 cc.set(b"user:2", b"bob")?;
32 cc.set(b"user:3", b"carol")?;
33
34 println!("user:1 = {:?}", cc.get(b"user:1")?.map(String::from_utf8));
35
36 // INCR routes by key like any single-key command.
37 let n = cc.incr(b"counter")?;
38 println!("counter = {n}");
39
40 // DEL/EXISTS take keys that may span shards — routed per key and summed.
41 let exists = cc.exists(&[b"user:1", b"user:2", b"missing"])?;
42 println!("exists(user:1, user:2, missing) = {exists}"); // 2
43
44 let removed = cc.del(&[b"user:1", b"user:2", b"user:3"])?;
45 println!("deleted {removed} keys"); // 3
46
47 // DBSIZE / FLUSHALL are whole-cluster: kevy fans them out server-side, so
48 // one call covers every shard.
49 println!("dbsize (whole cluster) = {}", cc.dbsize()?);
50
51 Ok(())
52}Source§impl ClusterClient
impl ClusterClient
Sourcepub fn hset(&mut self, key: &[u8], pairs: &[(&[u8], &[u8])]) -> Result<usize>
pub fn hset(&mut self, key: &[u8], pairs: &[(&[u8], &[u8])]) -> Result<usize>
HSET key field value [field value ...] — count of newly added fields.
Sourcepub fn hget(&mut self, key: &[u8], field: &[u8]) -> Result<Option<Vec<u8>>>
pub fn hget(&mut self, key: &[u8], field: &[u8]) -> Result<Option<Vec<u8>>>
HGET key field. None when key or field absent.
Sourcepub fn hdel(&mut self, key: &[u8], fields: &[&[u8]]) -> Result<usize>
pub fn hdel(&mut self, key: &[u8], fields: &[&[u8]]) -> Result<usize>
HDEL key field [field ...] — count of fields removed.
Sourcepub fn hgetall(&mut self, key: &[u8]) -> Result<Vec<Vec<u8>>>
pub fn hgetall(&mut self, key: &[u8]) -> Result<Vec<Vec<u8>>>
HGETALL key — flat [f0, v0, f1, v1, …].
Sourcepub fn lpush(&mut self, key: &[u8], values: &[&[u8]]) -> Result<usize>
pub fn lpush(&mut self, key: &[u8], values: &[&[u8]]) -> Result<usize>
LPUSH key value [value ...] — new list length.
Sourcepub fn rpush(&mut self, key: &[u8], values: &[&[u8]]) -> Result<usize>
pub fn rpush(&mut self, key: &[u8], values: &[&[u8]]) -> Result<usize>
RPUSH key value [value ...] — new list length.
Sourcepub fn lrange(
&mut self,
key: &[u8],
start: i64,
stop: i64,
) -> Result<Vec<Vec<u8>>>
pub fn lrange( &mut self, key: &[u8], start: i64, stop: i64, ) -> Result<Vec<Vec<u8>>>
LRANGE key start stop (Redis-style negative indices).
Sourcepub fn sadd(&mut self, key: &[u8], members: &[&[u8]]) -> Result<usize>
pub fn sadd(&mut self, key: &[u8], members: &[&[u8]]) -> Result<usize>
SADD key member [member ...] — count newly added.
Sourcepub fn srem(&mut self, key: &[u8], members: &[&[u8]]) -> Result<usize>
pub fn srem(&mut self, key: &[u8], members: &[&[u8]]) -> Result<usize>
SREM key member [member ...] — count removed.
Sourcepub fn sinter(&mut self, keys: &[&[u8]]) -> Result<Vec<Vec<u8>>>
pub fn sinter(&mut self, keys: &[&[u8]]) -> Result<Vec<Vec<u8>>>
SINTER key [key ...] — all keys must share a slot (route by the first).
Sourcepub fn sunion(&mut self, keys: &[&[u8]]) -> Result<Vec<Vec<u8>>>
pub fn sunion(&mut self, keys: &[&[u8]]) -> Result<Vec<Vec<u8>>>
SUNION key [key ...] — same-slot.
Sourcepub fn sdiff(&mut self, keys: &[&[u8]]) -> Result<Vec<Vec<u8>>>
pub fn sdiff(&mut self, keys: &[&[u8]]) -> Result<Vec<Vec<u8>>>
SDIFF key [key ...] — same-slot.
Sourcepub fn zadd(&mut self, key: &[u8], pairs: &[(f64, &[u8])]) -> Result<usize>
pub fn zadd(&mut self, key: &[u8], pairs: &[(f64, &[u8])]) -> Result<usize>
ZADD key score member [score member ...] — count newly added.
Sourcepub fn zrem(&mut self, key: &[u8], members: &[&[u8]]) -> Result<usize>
pub fn zrem(&mut self, key: &[u8], members: &[&[u8]]) -> Result<usize>
ZREM key member [member ...] — count removed.