redis 3.2.0 → 4.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +278 -15
- data/README.md +260 -76
- data/lib/redis/client.rb +239 -115
- data/lib/redis/cluster/command.rb +79 -0
- data/lib/redis/cluster/command_loader.rb +33 -0
- data/lib/redis/cluster/key_slot_converter.rb +72 -0
- data/lib/redis/cluster/node.rb +120 -0
- data/lib/redis/cluster/node_key.rb +31 -0
- data/lib/redis/cluster/node_loader.rb +37 -0
- data/lib/redis/cluster/option.rb +93 -0
- data/lib/redis/cluster/slot.rb +86 -0
- data/lib/redis/cluster/slot_loader.rb +49 -0
- data/lib/redis/cluster.rb +315 -0
- data/lib/redis/commands/bitmaps.rb +63 -0
- data/lib/redis/commands/cluster.rb +45 -0
- data/lib/redis/commands/connection.rb +58 -0
- data/lib/redis/commands/geo.rb +84 -0
- data/lib/redis/commands/hashes.rb +251 -0
- data/lib/redis/commands/hyper_log_log.rb +37 -0
- data/lib/redis/commands/keys.rb +411 -0
- data/lib/redis/commands/lists.rb +289 -0
- data/lib/redis/commands/pubsub.rb +72 -0
- data/lib/redis/commands/scripting.rb +114 -0
- data/lib/redis/commands/server.rb +188 -0
- data/lib/redis/commands/sets.rb +207 -0
- data/lib/redis/commands/sorted_sets.rb +804 -0
- data/lib/redis/commands/streams.rb +382 -0
- data/lib/redis/commands/strings.rb +313 -0
- data/lib/redis/commands/transactions.rb +92 -0
- data/lib/redis/commands.rb +242 -0
- data/lib/redis/connection/command_helper.rb +7 -10
- data/lib/redis/connection/hiredis.rb +11 -6
- data/lib/redis/connection/registry.rb +2 -1
- data/lib/redis/connection/ruby.rb +173 -64
- data/lib/redis/connection/synchrony.rb +32 -8
- data/lib/redis/connection.rb +3 -1
- data/lib/redis/distributed.rb +233 -74
- data/lib/redis/errors.rb +48 -0
- data/lib/redis/hash_ring.rb +30 -72
- data/lib/redis/pipeline.rb +145 -12
- data/lib/redis/subscribe.rb +20 -13
- data/lib/redis/version.rb +3 -1
- data/lib/redis.rb +171 -2476
- metadata +71 -165
- data/.gitignore +0 -15
- data/.travis/Gemfile +0 -11
- data/.travis.yml +0 -54
- data/.yardopts +0 -3
- data/Gemfile +0 -4
- data/Rakefile +0 -68
- data/benchmarking/logging.rb +0 -71
- data/benchmarking/pipeline.rb +0 -51
- data/benchmarking/speed.rb +0 -21
- data/benchmarking/suite.rb +0 -24
- data/benchmarking/worker.rb +0 -71
- data/examples/basic.rb +0 -15
- data/examples/consistency.rb +0 -114
- data/examples/dist_redis.rb +0 -43
- data/examples/incr-decr.rb +0 -17
- data/examples/list.rb +0 -26
- data/examples/pubsub.rb +0 -37
- data/examples/sentinel/sentinel.conf +0 -9
- data/examples/sentinel/start +0 -49
- data/examples/sentinel.rb +0 -41
- data/examples/sets.rb +0 -36
- data/examples/unicorn/config.ru +0 -3
- data/examples/unicorn/unicorn.rb +0 -20
- data/redis.gemspec +0 -43
- data/test/bitpos_test.rb +0 -69
- data/test/blocking_commands_test.rb +0 -42
- data/test/command_map_test.rb +0 -30
- data/test/commands_on_hashes_test.rb +0 -21
- data/test/commands_on_hyper_log_log_test.rb +0 -21
- data/test/commands_on_lists_test.rb +0 -20
- data/test/commands_on_sets_test.rb +0 -77
- data/test/commands_on_sorted_sets_test.rb +0 -123
- data/test/commands_on_strings_test.rb +0 -101
- data/test/commands_on_value_types_test.rb +0 -131
- data/test/connection_handling_test.rb +0 -189
- data/test/db/.gitkeep +0 -0
- data/test/distributed_blocking_commands_test.rb +0 -46
- data/test/distributed_commands_on_hashes_test.rb +0 -10
- data/test/distributed_commands_on_hyper_log_log_test.rb +0 -33
- data/test/distributed_commands_on_lists_test.rb +0 -22
- data/test/distributed_commands_on_sets_test.rb +0 -83
- data/test/distributed_commands_on_sorted_sets_test.rb +0 -18
- data/test/distributed_commands_on_strings_test.rb +0 -59
- data/test/distributed_commands_on_value_types_test.rb +0 -95
- data/test/distributed_commands_requiring_clustering_test.rb +0 -164
- data/test/distributed_connection_handling_test.rb +0 -23
- data/test/distributed_internals_test.rb +0 -70
- data/test/distributed_key_tags_test.rb +0 -52
- data/test/distributed_persistence_control_commands_test.rb +0 -26
- data/test/distributed_publish_subscribe_test.rb +0 -92
- data/test/distributed_remote_server_control_commands_test.rb +0 -66
- data/test/distributed_scripting_test.rb +0 -102
- data/test/distributed_sorting_test.rb +0 -20
- data/test/distributed_test.rb +0 -58
- data/test/distributed_transactions_test.rb +0 -32
- data/test/encoding_test.rb +0 -18
- data/test/error_replies_test.rb +0 -59
- data/test/fork_safety_test.rb +0 -65
- data/test/helper.rb +0 -232
- data/test/helper_test.rb +0 -24
- data/test/internals_test.rb +0 -434
- data/test/lint/blocking_commands.rb +0 -150
- data/test/lint/hashes.rb +0 -162
- data/test/lint/hyper_log_log.rb +0 -60
- data/test/lint/lists.rb +0 -143
- data/test/lint/sets.rb +0 -125
- data/test/lint/sorted_sets.rb +0 -238
- data/test/lint/strings.rb +0 -260
- data/test/lint/value_types.rb +0 -122
- data/test/persistence_control_commands_test.rb +0 -26
- data/test/pipelining_commands_test.rb +0 -242
- data/test/publish_subscribe_test.rb +0 -210
- data/test/remote_server_control_commands_test.rb +0 -117
- data/test/scanning_test.rb +0 -413
- data/test/scripting_test.rb +0 -78
- data/test/sorting_test.rb +0 -59
- data/test/support/connection/hiredis.rb +0 -1
- data/test/support/connection/ruby.rb +0 -1
- data/test/support/connection/synchrony.rb +0 -17
- data/test/support/redis_mock.rb +0 -115
- data/test/support/wire/synchrony.rb +0 -24
- data/test/support/wire/thread.rb +0 -5
- data/test/synchrony_driver.rb +0 -88
- data/test/test.conf +0 -9
- data/test/thread_safety_test.rb +0 -32
- data/test/transactions_test.rb +0 -264
- data/test/unknown_commands_test.rb +0 -14
- data/test/url_param_test.rb +0 -132
data/lib/redis.rb
CHANGED
@@ -1,2106 +1,175 @@
|
|
1
|
-
|
2
|
-
require "redis/errors"
|
3
|
-
|
4
|
-
class Redis
|
5
|
-
|
6
|
-
def self.deprecate(message, trace = caller[0])
|
7
|
-
$stderr.puts "\n#{message} (in #{trace})"
|
8
|
-
end
|
9
|
-
|
10
|
-
attr :client
|
11
|
-
|
12
|
-
# @deprecated The preferred way to create a new client object is using `#new`.
|
13
|
-
# This method does not actually establish a connection to Redis,
|
14
|
-
# in contrary to what you might expect.
|
15
|
-
def self.connect(options = {})
|
16
|
-
new(options)
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.current
|
20
|
-
@current ||= Redis.new
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.current=(redis)
|
24
|
-
@current = redis
|
25
|
-
end
|
26
|
-
|
27
|
-
include MonitorMixin
|
28
|
-
|
29
|
-
def initialize(options = {})
|
30
|
-
@options = options.dup
|
31
|
-
@original_client = @client = Client.new(options)
|
32
|
-
|
33
|
-
super() # Monitor#initialize
|
34
|
-
end
|
35
|
-
|
36
|
-
def synchronize
|
37
|
-
mon_synchronize { yield(@client) }
|
38
|
-
end
|
39
|
-
|
40
|
-
# Run code with the client reconnecting
|
41
|
-
def with_reconnect(val=true, &blk)
|
42
|
-
synchronize do |client|
|
43
|
-
client.with_reconnect(val, &blk)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# Run code without the client reconnecting
|
48
|
-
def without_reconnect(&blk)
|
49
|
-
with_reconnect(false, &blk)
|
50
|
-
end
|
51
|
-
|
52
|
-
# Test whether or not the client is connected
|
53
|
-
def connected?
|
54
|
-
@original_client.connected?
|
55
|
-
end
|
56
|
-
|
57
|
-
# Authenticate to the server.
|
58
|
-
#
|
59
|
-
# @param [String] password must match the password specified in the
|
60
|
-
# `requirepass` directive in the configuration file
|
61
|
-
# @return [String] `OK`
|
62
|
-
def auth(password)
|
63
|
-
synchronize do |client|
|
64
|
-
client.call([:auth, password])
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
# Change the selected database for the current connection.
|
69
|
-
#
|
70
|
-
# @param [Fixnum] db zero-based index of the DB to use (0 to 15)
|
71
|
-
# @return [String] `OK`
|
72
|
-
def select(db)
|
73
|
-
synchronize do |client|
|
74
|
-
client.db = db
|
75
|
-
client.call([:select, db])
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# Ping the server.
|
80
|
-
#
|
81
|
-
# @return [String] `PONG`
|
82
|
-
def ping
|
83
|
-
synchronize do |client|
|
84
|
-
client.call([:ping])
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
# Echo the given string.
|
89
|
-
#
|
90
|
-
# @param [String] value
|
91
|
-
# @return [String]
|
92
|
-
def echo(value)
|
93
|
-
synchronize do |client|
|
94
|
-
client.call([:echo, value])
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# Close the connection.
|
99
|
-
#
|
100
|
-
# @return [String] `OK`
|
101
|
-
def quit
|
102
|
-
synchronize do |client|
|
103
|
-
begin
|
104
|
-
client.call([:quit])
|
105
|
-
rescue ConnectionError
|
106
|
-
ensure
|
107
|
-
client.disconnect
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
# Asynchronously rewrite the append-only file.
|
113
|
-
#
|
114
|
-
# @return [String] `OK`
|
115
|
-
def bgrewriteaof
|
116
|
-
synchronize do |client|
|
117
|
-
client.call([:bgrewriteaof])
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
# Asynchronously save the dataset to disk.
|
122
|
-
#
|
123
|
-
# @return [String] `OK`
|
124
|
-
def bgsave
|
125
|
-
synchronize do |client|
|
126
|
-
client.call([:bgsave])
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
# Get or set server configuration parameters.
|
131
|
-
#
|
132
|
-
# @param [Symbol] action e.g. `:get`, `:set`, `:resetstat`
|
133
|
-
# @return [String, Hash] string reply, or hash when retrieving more than one
|
134
|
-
# property with `CONFIG GET`
|
135
|
-
def config(action, *args)
|
136
|
-
synchronize do |client|
|
137
|
-
client.call([:config, action] + args) do |reply|
|
138
|
-
if reply.kind_of?(Array) && action == :get
|
139
|
-
Hash[_pairify(reply)]
|
140
|
-
else
|
141
|
-
reply
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
# Return the number of keys in the selected database.
|
148
|
-
#
|
149
|
-
# @return [Fixnum]
|
150
|
-
def dbsize
|
151
|
-
synchronize do |client|
|
152
|
-
client.call([:dbsize])
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
def debug(*args)
|
157
|
-
synchronize do |client|
|
158
|
-
client.call([:debug] + args)
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
# Remove all keys from all databases.
|
163
|
-
#
|
164
|
-
# @return [String] `OK`
|
165
|
-
def flushall
|
166
|
-
synchronize do |client|
|
167
|
-
client.call([:flushall])
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
# Remove all keys from the current database.
|
172
|
-
#
|
173
|
-
# @return [String] `OK`
|
174
|
-
def flushdb
|
175
|
-
synchronize do |client|
|
176
|
-
client.call([:flushdb])
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
# Get information and statistics about the server.
|
181
|
-
#
|
182
|
-
# @param [String, Symbol] cmd e.g. "commandstats"
|
183
|
-
# @return [Hash<String, String>]
|
184
|
-
def info(cmd = nil)
|
185
|
-
synchronize do |client|
|
186
|
-
client.call([:info, cmd].compact) do |reply|
|
187
|
-
if reply.kind_of?(String)
|
188
|
-
reply = Hash[reply.split("\r\n").map do |line|
|
189
|
-
line.split(":", 2) unless line =~ /^(#|$)/
|
190
|
-
end.compact]
|
191
|
-
|
192
|
-
if cmd && cmd.to_s == "commandstats"
|
193
|
-
# Extract nested hashes for INFO COMMANDSTATS
|
194
|
-
reply = Hash[reply.map do |k, v|
|
195
|
-
v = v.split(",").map { |e| e.split("=") }
|
196
|
-
[k[/^cmdstat_(.*)$/, 1], Hash[v]]
|
197
|
-
end]
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
reply
|
202
|
-
end
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
# Get the UNIX time stamp of the last successful save to disk.
|
207
|
-
#
|
208
|
-
# @return [Fixnum]
|
209
|
-
def lastsave
|
210
|
-
synchronize do |client|
|
211
|
-
client.call([:lastsave])
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
# Listen for all requests received by the server in real time.
|
216
|
-
#
|
217
|
-
# There is no way to interrupt this command.
|
218
|
-
#
|
219
|
-
# @yield a block to be called for every line of output
|
220
|
-
# @yieldparam [String] line timestamp and command that was executed
|
221
|
-
def monitor(&block)
|
222
|
-
synchronize do |client|
|
223
|
-
client.call_loop([:monitor], &block)
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
# Synchronously save the dataset to disk.
|
228
|
-
#
|
229
|
-
# @return [String]
|
230
|
-
def save
|
231
|
-
synchronize do |client|
|
232
|
-
client.call([:save])
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
# Synchronously save the dataset to disk and then shut down the server.
|
237
|
-
def shutdown
|
238
|
-
synchronize do |client|
|
239
|
-
client.with_reconnect(false) do
|
240
|
-
begin
|
241
|
-
client.call([:shutdown])
|
242
|
-
rescue ConnectionError
|
243
|
-
# This means Redis has probably exited.
|
244
|
-
nil
|
245
|
-
end
|
246
|
-
end
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
# Make the server a slave of another instance, or promote it as master.
|
251
|
-
def slaveof(host, port)
|
252
|
-
synchronize do |client|
|
253
|
-
client.call([:slaveof, host, port])
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
# Interact with the slowlog (get, len, reset)
|
258
|
-
#
|
259
|
-
# @param [String] subcommand e.g. `get`, `len`, `reset`
|
260
|
-
# @param [Fixnum] length maximum number of entries to return
|
261
|
-
# @return [Array<String>, Fixnum, String] depends on subcommand
|
262
|
-
def slowlog(subcommand, length=nil)
|
263
|
-
synchronize do |client|
|
264
|
-
args = [:slowlog, subcommand]
|
265
|
-
args << length if length
|
266
|
-
client.call args
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
# Internal command used for replication.
|
271
|
-
def sync
|
272
|
-
synchronize do |client|
|
273
|
-
client.call([:sync])
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
|
-
# Return the server time.
|
278
|
-
#
|
279
|
-
# @example
|
280
|
-
# r.time # => [ 1333093196, 606806 ]
|
281
|
-
#
|
282
|
-
# @return [Array<Fixnum>] tuple of seconds since UNIX epoch and
|
283
|
-
# microseconds in the current second
|
284
|
-
def time
|
285
|
-
synchronize do |client|
|
286
|
-
client.call([:time]) do |reply|
|
287
|
-
reply.map(&:to_i) if reply
|
288
|
-
end
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
# Remove the expiration from a key.
|
293
|
-
#
|
294
|
-
# @param [String] key
|
295
|
-
# @return [Boolean] whether the timeout was removed or not
|
296
|
-
def persist(key)
|
297
|
-
synchronize do |client|
|
298
|
-
client.call([:persist, key], &_boolify)
|
299
|
-
end
|
300
|
-
end
|
301
|
-
|
302
|
-
# Set a key's time to live in seconds.
|
303
|
-
#
|
304
|
-
# @param [String] key
|
305
|
-
# @param [Fixnum] seconds time to live
|
306
|
-
# @return [Boolean] whether the timeout was set or not
|
307
|
-
def expire(key, seconds)
|
308
|
-
synchronize do |client|
|
309
|
-
client.call([:expire, key, seconds], &_boolify)
|
310
|
-
end
|
311
|
-
end
|
312
|
-
|
313
|
-
# Set the expiration for a key as a UNIX timestamp.
|
314
|
-
#
|
315
|
-
# @param [String] key
|
316
|
-
# @param [Fixnum] unix_time expiry time specified as a UNIX timestamp
|
317
|
-
# @return [Boolean] whether the timeout was set or not
|
318
|
-
def expireat(key, unix_time)
|
319
|
-
synchronize do |client|
|
320
|
-
client.call([:expireat, key, unix_time], &_boolify)
|
321
|
-
end
|
322
|
-
end
|
323
|
-
|
324
|
-
# Get the time to live (in seconds) for a key.
|
325
|
-
#
|
326
|
-
# @param [String] key
|
327
|
-
# @return [Fixnum] remaining time to live in seconds, or -1 if the
|
328
|
-
# key does not exist or does not have a timeout
|
329
|
-
def ttl(key)
|
330
|
-
synchronize do |client|
|
331
|
-
client.call([:ttl, key])
|
332
|
-
end
|
333
|
-
end
|
334
|
-
|
335
|
-
# Set a key's time to live in milliseconds.
|
336
|
-
#
|
337
|
-
# @param [String] key
|
338
|
-
# @param [Fixnum] milliseconds time to live
|
339
|
-
# @return [Boolean] whether the timeout was set or not
|
340
|
-
def pexpire(key, milliseconds)
|
341
|
-
synchronize do |client|
|
342
|
-
client.call([:pexpire, key, milliseconds], &_boolify)
|
343
|
-
end
|
344
|
-
end
|
345
|
-
|
346
|
-
# Set the expiration for a key as number of milliseconds from UNIX Epoch.
|
347
|
-
#
|
348
|
-
# @param [String] key
|
349
|
-
# @param [Fixnum] ms_unix_time expiry time specified as number of milliseconds from UNIX Epoch.
|
350
|
-
# @return [Boolean] whether the timeout was set or not
|
351
|
-
def pexpireat(key, ms_unix_time)
|
352
|
-
synchronize do |client|
|
353
|
-
client.call([:pexpireat, key, ms_unix_time], &_boolify)
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
# Get the time to live (in milliseconds) for a key.
|
358
|
-
#
|
359
|
-
# @param [String] key
|
360
|
-
# @return [Fixnum] remaining time to live in milliseconds, or -1 if the
|
361
|
-
# key does not exist or does not have a timeout
|
362
|
-
def pttl(key)
|
363
|
-
synchronize do |client|
|
364
|
-
client.call([:pttl, key])
|
365
|
-
end
|
366
|
-
end
|
367
|
-
|
368
|
-
# Return a serialized version of the value stored at a key.
|
369
|
-
#
|
370
|
-
# @param [String] key
|
371
|
-
# @return [String] serialized_value
|
372
|
-
def dump(key)
|
373
|
-
synchronize do |client|
|
374
|
-
client.call([:dump, key])
|
375
|
-
end
|
376
|
-
end
|
377
|
-
|
378
|
-
# Create a key using the serialized value, previously obtained using DUMP.
|
379
|
-
#
|
380
|
-
# @param [String] key
|
381
|
-
# @param [String] ttl
|
382
|
-
# @param [String] serialized_value
|
383
|
-
# @return `"OK"`
|
384
|
-
def restore(key, ttl, serialized_value)
|
385
|
-
synchronize do |client|
|
386
|
-
client.call([:restore, key, ttl, serialized_value])
|
387
|
-
end
|
388
|
-
end
|
389
|
-
|
390
|
-
# Transfer a key from the connected instance to another instance.
|
391
|
-
#
|
392
|
-
# @param [String] key
|
393
|
-
# @param [Hash] options
|
394
|
-
# - `:host => String`: host of instance to migrate to
|
395
|
-
# - `:port => Integer`: port of instance to migrate to
|
396
|
-
# - `:db => Integer`: database to migrate to (default: same as source)
|
397
|
-
# - `:timeout => Integer`: timeout (default: same as connection timeout)
|
398
|
-
# @return [String] `"OK"`
|
399
|
-
def migrate(key, options)
|
400
|
-
host = options[:host] || raise(RuntimeError, ":host not specified")
|
401
|
-
port = options[:port] || raise(RuntimeError, ":port not specified")
|
402
|
-
db = (options[:db] || client.db).to_i
|
403
|
-
timeout = (options[:timeout] || client.timeout).to_i
|
404
|
-
|
405
|
-
synchronize do |client|
|
406
|
-
client.call([:migrate, host, port, key, db, timeout])
|
407
|
-
end
|
408
|
-
end
|
409
|
-
|
410
|
-
# Delete one or more keys.
|
411
|
-
#
|
412
|
-
# @param [String, Array<String>] keys
|
413
|
-
# @return [Fixnum] number of keys that were deleted
|
414
|
-
def del(*keys)
|
415
|
-
synchronize do |client|
|
416
|
-
client.call([:del] + keys)
|
417
|
-
end
|
418
|
-
end
|
419
|
-
|
420
|
-
# Determine if a key exists.
|
421
|
-
#
|
422
|
-
# @param [String] key
|
423
|
-
# @return [Boolean]
|
424
|
-
def exists(key)
|
425
|
-
synchronize do |client|
|
426
|
-
client.call([:exists, key], &_boolify)
|
427
|
-
end
|
428
|
-
end
|
429
|
-
|
430
|
-
# Find all keys matching the given pattern.
|
431
|
-
#
|
432
|
-
# @param [String] pattern
|
433
|
-
# @return [Array<String>]
|
434
|
-
def keys(pattern = "*")
|
435
|
-
synchronize do |client|
|
436
|
-
client.call([:keys, pattern]) do |reply|
|
437
|
-
if reply.kind_of?(String)
|
438
|
-
reply.split(" ")
|
439
|
-
else
|
440
|
-
reply
|
441
|
-
end
|
442
|
-
end
|
443
|
-
end
|
444
|
-
end
|
445
|
-
|
446
|
-
# Move a key to another database.
|
447
|
-
#
|
448
|
-
# @example Move a key to another database
|
449
|
-
# redis.set "foo", "bar"
|
450
|
-
# # => "OK"
|
451
|
-
# redis.move "foo", 2
|
452
|
-
# # => true
|
453
|
-
# redis.exists "foo"
|
454
|
-
# # => false
|
455
|
-
# redis.select 2
|
456
|
-
# # => "OK"
|
457
|
-
# redis.exists "foo"
|
458
|
-
# # => true
|
459
|
-
# redis.get "foo"
|
460
|
-
# # => "bar"
|
461
|
-
#
|
462
|
-
# @param [String] key
|
463
|
-
# @param [Fixnum] db
|
464
|
-
# @return [Boolean] whether the key was moved or not
|
465
|
-
def move(key, db)
|
466
|
-
synchronize do |client|
|
467
|
-
client.call([:move, key, db], &_boolify)
|
468
|
-
end
|
469
|
-
end
|
470
|
-
|
471
|
-
def object(*args)
|
472
|
-
synchronize do |client|
|
473
|
-
client.call([:object] + args)
|
474
|
-
end
|
475
|
-
end
|
476
|
-
|
477
|
-
# Return a random key from the keyspace.
|
478
|
-
#
|
479
|
-
# @return [String]
|
480
|
-
def randomkey
|
481
|
-
synchronize do |client|
|
482
|
-
client.call([:randomkey])
|
483
|
-
end
|
484
|
-
end
|
485
|
-
|
486
|
-
# Rename a key. If the new key already exists it is overwritten.
|
487
|
-
#
|
488
|
-
# @param [String] old_name
|
489
|
-
# @param [String] new_name
|
490
|
-
# @return [String] `OK`
|
491
|
-
def rename(old_name, new_name)
|
492
|
-
synchronize do |client|
|
493
|
-
client.call([:rename, old_name, new_name])
|
494
|
-
end
|
495
|
-
end
|
496
|
-
|
497
|
-
# Rename a key, only if the new key does not exist.
|
498
|
-
#
|
499
|
-
# @param [String] old_name
|
500
|
-
# @param [String] new_name
|
501
|
-
# @return [Boolean] whether the key was renamed or not
|
502
|
-
def renamenx(old_name, new_name)
|
503
|
-
synchronize do |client|
|
504
|
-
client.call([:renamenx, old_name, new_name], &_boolify)
|
505
|
-
end
|
506
|
-
end
|
507
|
-
|
508
|
-
# Sort the elements in a list, set or sorted set.
|
509
|
-
#
|
510
|
-
# @example Retrieve the first 2 elements from an alphabetically sorted "list"
|
511
|
-
# redis.sort("list", :order => "alpha", :limit => [0, 2])
|
512
|
-
# # => ["a", "b"]
|
513
|
-
# @example Store an alphabetically descending list in "target"
|
514
|
-
# redis.sort("list", :order => "desc alpha", :store => "target")
|
515
|
-
# # => 26
|
516
|
-
#
|
517
|
-
# @param [String] key
|
518
|
-
# @param [Hash] options
|
519
|
-
# - `:by => String`: use external key to sort elements by
|
520
|
-
# - `:limit => [offset, count]`: skip `offset` elements, return a maximum
|
521
|
-
# of `count` elements
|
522
|
-
# - `:get => [String, Array<String>]`: single key or array of keys to
|
523
|
-
# retrieve per element in the result
|
524
|
-
# - `:order => String`: combination of `ASC`, `DESC` and optionally `ALPHA`
|
525
|
-
# - `:store => String`: key to store the result at
|
526
|
-
#
|
527
|
-
# @return [Array<String>, Array<Array<String>>, Fixnum]
|
528
|
-
# - when `:get` is not specified, or holds a single element, an array of elements
|
529
|
-
# - when `:get` is specified, and holds more than one element, an array of
|
530
|
-
# elements where every element is an array with the result for every
|
531
|
-
# element specified in `:get`
|
532
|
-
# - when `:store` is specified, the number of elements in the stored result
|
533
|
-
def sort(key, options = {})
|
534
|
-
args = []
|
535
|
-
|
536
|
-
by = options[:by]
|
537
|
-
args.concat(["BY", by]) if by
|
538
|
-
|
539
|
-
limit = options[:limit]
|
540
|
-
args.concat(["LIMIT"] + limit) if limit
|
541
|
-
|
542
|
-
get = Array(options[:get])
|
543
|
-
args.concat(["GET"].product(get).flatten) unless get.empty?
|
544
|
-
|
545
|
-
order = options[:order]
|
546
|
-
args.concat(order.split(" ")) if order
|
547
|
-
|
548
|
-
store = options[:store]
|
549
|
-
args.concat(["STORE", store]) if store
|
550
|
-
|
551
|
-
synchronize do |client|
|
552
|
-
client.call([:sort, key] + args) do |reply|
|
553
|
-
if get.size > 1 && !store
|
554
|
-
if reply
|
555
|
-
reply.each_slice(get.size).to_a
|
556
|
-
end
|
557
|
-
else
|
558
|
-
reply
|
559
|
-
end
|
560
|
-
end
|
561
|
-
end
|
562
|
-
end
|
563
|
-
|
564
|
-
# Determine the type stored at key.
|
565
|
-
#
|
566
|
-
# @param [String] key
|
567
|
-
# @return [String] `string`, `list`, `set`, `zset`, `hash` or `none`
|
568
|
-
def type(key)
|
569
|
-
synchronize do |client|
|
570
|
-
client.call([:type, key])
|
571
|
-
end
|
572
|
-
end
|
573
|
-
|
574
|
-
# Decrement the integer value of a key by one.
|
575
|
-
#
|
576
|
-
# @example
|
577
|
-
# redis.decr("value")
|
578
|
-
# # => 4
|
579
|
-
#
|
580
|
-
# @param [String] key
|
581
|
-
# @return [Fixnum] value after decrementing it
|
582
|
-
def decr(key)
|
583
|
-
synchronize do |client|
|
584
|
-
client.call([:decr, key])
|
585
|
-
end
|
586
|
-
end
|
587
|
-
|
588
|
-
# Decrement the integer value of a key by the given number.
|
589
|
-
#
|
590
|
-
# @example
|
591
|
-
# redis.decrby("value", 5)
|
592
|
-
# # => 0
|
593
|
-
#
|
594
|
-
# @param [String] key
|
595
|
-
# @param [Fixnum] decrement
|
596
|
-
# @return [Fixnum] value after decrementing it
|
597
|
-
def decrby(key, decrement)
|
598
|
-
synchronize do |client|
|
599
|
-
client.call([:decrby, key, decrement])
|
600
|
-
end
|
601
|
-
end
|
602
|
-
|
603
|
-
# Increment the integer value of a key by one.
|
604
|
-
#
|
605
|
-
# @example
|
606
|
-
# redis.incr("value")
|
607
|
-
# # => 6
|
608
|
-
#
|
609
|
-
# @param [String] key
|
610
|
-
# @return [Fixnum] value after incrementing it
|
611
|
-
def incr(key)
|
612
|
-
synchronize do |client|
|
613
|
-
client.call([:incr, key])
|
614
|
-
end
|
615
|
-
end
|
616
|
-
|
617
|
-
# Increment the integer value of a key by the given integer number.
|
618
|
-
#
|
619
|
-
# @example
|
620
|
-
# redis.incrby("value", 5)
|
621
|
-
# # => 10
|
622
|
-
#
|
623
|
-
# @param [String] key
|
624
|
-
# @param [Fixnum] increment
|
625
|
-
# @return [Fixnum] value after incrementing it
|
626
|
-
def incrby(key, increment)
|
627
|
-
synchronize do |client|
|
628
|
-
client.call([:incrby, key, increment])
|
629
|
-
end
|
630
|
-
end
|
631
|
-
|
632
|
-
# Increment the numeric value of a key by the given float number.
|
633
|
-
#
|
634
|
-
# @example
|
635
|
-
# redis.incrbyfloat("value", 1.23)
|
636
|
-
# # => 1.23
|
637
|
-
#
|
638
|
-
# @param [String] key
|
639
|
-
# @param [Float] increment
|
640
|
-
# @return [Float] value after incrementing it
|
641
|
-
def incrbyfloat(key, increment)
|
642
|
-
synchronize do |client|
|
643
|
-
client.call([:incrbyfloat, key, increment], &_floatify)
|
644
|
-
end
|
645
|
-
end
|
646
|
-
|
647
|
-
# Set the string value of a key.
|
648
|
-
#
|
649
|
-
# @param [String] key
|
650
|
-
# @param [String] value
|
651
|
-
# @param [Hash] options
|
652
|
-
# - `:ex => Fixnum`: Set the specified expire time, in seconds.
|
653
|
-
# - `:px => Fixnum`: Set the specified expire time, in milliseconds.
|
654
|
-
# - `:nx => true`: Only set the key if it does not already exist.
|
655
|
-
# - `:xx => true`: Only set the key if it already exist.
|
656
|
-
# @return [String, Boolean] `"OK"` or true, false if `:nx => true` or `:xx => true`
|
657
|
-
def set(key, value, options = {})
|
658
|
-
args = []
|
659
|
-
|
660
|
-
ex = options[:ex]
|
661
|
-
args.concat(["EX", ex]) if ex
|
662
|
-
|
663
|
-
px = options[:px]
|
664
|
-
args.concat(["PX", px]) if px
|
665
|
-
|
666
|
-
nx = options[:nx]
|
667
|
-
args.concat(["NX"]) if nx
|
668
|
-
|
669
|
-
xx = options[:xx]
|
670
|
-
args.concat(["XX"]) if xx
|
671
|
-
|
672
|
-
synchronize do |client|
|
673
|
-
if nx || xx
|
674
|
-
client.call([:set, key, value.to_s] + args, &_boolify_set)
|
675
|
-
else
|
676
|
-
client.call([:set, key, value.to_s] + args)
|
677
|
-
end
|
678
|
-
end
|
679
|
-
end
|
680
|
-
|
681
|
-
alias :[]= :set
|
682
|
-
|
683
|
-
# Set the time to live in seconds of a key.
|
684
|
-
#
|
685
|
-
# @param [String] key
|
686
|
-
# @param [Fixnum] ttl
|
687
|
-
# @param [String] value
|
688
|
-
# @return `"OK"`
|
689
|
-
def setex(key, ttl, value)
|
690
|
-
synchronize do |client|
|
691
|
-
client.call([:setex, key, ttl, value.to_s])
|
692
|
-
end
|
693
|
-
end
|
694
|
-
|
695
|
-
# Set the time to live in milliseconds of a key.
|
696
|
-
#
|
697
|
-
# @param [String] key
|
698
|
-
# @param [Fixnum] ttl
|
699
|
-
# @param [String] value
|
700
|
-
# @return `"OK"`
|
701
|
-
def psetex(key, ttl, value)
|
702
|
-
synchronize do |client|
|
703
|
-
client.call([:psetex, key, ttl, value.to_s])
|
704
|
-
end
|
705
|
-
end
|
706
|
-
|
707
|
-
# Set the value of a key, only if the key does not exist.
|
708
|
-
#
|
709
|
-
# @param [String] key
|
710
|
-
# @param [String] value
|
711
|
-
# @return [Boolean] whether the key was set or not
|
712
|
-
def setnx(key, value)
|
713
|
-
synchronize do |client|
|
714
|
-
client.call([:setnx, key, value.to_s], &_boolify)
|
715
|
-
end
|
716
|
-
end
|
717
|
-
|
718
|
-
# Set one or more values.
|
719
|
-
#
|
720
|
-
# @example
|
721
|
-
# redis.mset("key1", "v1", "key2", "v2")
|
722
|
-
# # => "OK"
|
723
|
-
#
|
724
|
-
# @param [Array<String>] args array of keys and values
|
725
|
-
# @return `"OK"`
|
726
|
-
#
|
727
|
-
# @see #mapped_mset
|
728
|
-
def mset(*args)
|
729
|
-
synchronize do |client|
|
730
|
-
client.call([:mset] + args)
|
731
|
-
end
|
732
|
-
end
|
733
|
-
|
734
|
-
# Set one or more values.
|
735
|
-
#
|
736
|
-
# @example
|
737
|
-
# redis.mapped_mset({ "f1" => "v1", "f2" => "v2" })
|
738
|
-
# # => "OK"
|
739
|
-
#
|
740
|
-
# @param [Hash] hash keys mapping to values
|
741
|
-
# @return `"OK"`
|
742
|
-
#
|
743
|
-
# @see #mset
|
744
|
-
def mapped_mset(hash)
|
745
|
-
mset(hash.to_a.flatten)
|
746
|
-
end
|
747
|
-
|
748
|
-
# Set one or more values, only if none of the keys exist.
|
749
|
-
#
|
750
|
-
# @example
|
751
|
-
# redis.msetnx("key1", "v1", "key2", "v2")
|
752
|
-
# # => true
|
753
|
-
#
|
754
|
-
# @param [Array<String>] args array of keys and values
|
755
|
-
# @return [Boolean] whether or not all values were set
|
756
|
-
#
|
757
|
-
# @see #mapped_msetnx
|
758
|
-
def msetnx(*args)
|
759
|
-
synchronize do |client|
|
760
|
-
client.call([:msetnx] + args, &_boolify)
|
761
|
-
end
|
762
|
-
end
|
763
|
-
|
764
|
-
# Set one or more values, only if none of the keys exist.
|
765
|
-
#
|
766
|
-
# @example
|
767
|
-
# redis.msetnx({ "key1" => "v1", "key2" => "v2" })
|
768
|
-
# # => true
|
769
|
-
#
|
770
|
-
# @param [Hash] hash keys mapping to values
|
771
|
-
# @return [Boolean] whether or not all values were set
|
772
|
-
#
|
773
|
-
# @see #msetnx
|
774
|
-
def mapped_msetnx(hash)
|
775
|
-
msetnx(hash.to_a.flatten)
|
776
|
-
end
|
777
|
-
|
778
|
-
# Get the value of a key.
|
779
|
-
#
|
780
|
-
# @param [String] key
|
781
|
-
# @return [String]
|
782
|
-
def get(key)
|
783
|
-
synchronize do |client|
|
784
|
-
client.call([:get, key])
|
785
|
-
end
|
786
|
-
end
|
787
|
-
|
788
|
-
alias :[] :get
|
789
|
-
|
790
|
-
# Get the values of all the given keys.
|
791
|
-
#
|
792
|
-
# @example
|
793
|
-
# redis.mget("key1", "key1")
|
794
|
-
# # => ["v1", "v2"]
|
795
|
-
#
|
796
|
-
# @param [Array<String>] keys
|
797
|
-
# @return [Array<String>] an array of values for the specified keys
|
798
|
-
#
|
799
|
-
# @see #mapped_mget
|
800
|
-
def mget(*keys, &blk)
|
801
|
-
synchronize do |client|
|
802
|
-
client.call([:mget] + keys, &blk)
|
803
|
-
end
|
804
|
-
end
|
805
|
-
|
806
|
-
# Get the values of all the given keys.
|
807
|
-
#
|
808
|
-
# @example
|
809
|
-
# redis.mapped_mget("key1", "key1")
|
810
|
-
# # => { "key1" => "v1", "key2" => "v2" }
|
811
|
-
#
|
812
|
-
# @param [Array<String>] keys array of keys
|
813
|
-
# @return [Hash] a hash mapping the specified keys to their values
|
814
|
-
#
|
815
|
-
# @see #mget
|
816
|
-
def mapped_mget(*keys)
|
817
|
-
mget(*keys) do |reply|
|
818
|
-
if reply.kind_of?(Array)
|
819
|
-
Hash[keys.zip(reply)]
|
820
|
-
else
|
821
|
-
reply
|
822
|
-
end
|
823
|
-
end
|
824
|
-
end
|
825
|
-
|
826
|
-
# Overwrite part of a string at key starting at the specified offset.
|
827
|
-
#
|
828
|
-
# @param [String] key
|
829
|
-
# @param [Fixnum] offset byte offset
|
830
|
-
# @param [String] value
|
831
|
-
# @return [Fixnum] length of the string after it was modified
|
832
|
-
def setrange(key, offset, value)
|
833
|
-
synchronize do |client|
|
834
|
-
client.call([:setrange, key, offset, value.to_s])
|
835
|
-
end
|
836
|
-
end
|
837
|
-
|
838
|
-
# Get a substring of the string stored at a key.
|
839
|
-
#
|
840
|
-
# @param [String] key
|
841
|
-
# @param [Fixnum] start zero-based start offset
|
842
|
-
# @param [Fixnum] stop zero-based end offset. Use -1 for representing
|
843
|
-
# the end of the string
|
844
|
-
# @return [Fixnum] `0` or `1`
|
845
|
-
def getrange(key, start, stop)
|
846
|
-
synchronize do |client|
|
847
|
-
client.call([:getrange, key, start, stop])
|
848
|
-
end
|
849
|
-
end
|
850
|
-
|
851
|
-
# Sets or clears the bit at offset in the string value stored at key.
|
852
|
-
#
|
853
|
-
# @param [String] key
|
854
|
-
# @param [Fixnum] offset bit offset
|
855
|
-
# @param [Fixnum] value bit value `0` or `1`
|
856
|
-
# @return [Fixnum] the original bit value stored at `offset`
|
857
|
-
def setbit(key, offset, value)
|
858
|
-
synchronize do |client|
|
859
|
-
client.call([:setbit, key, offset, value])
|
860
|
-
end
|
861
|
-
end
|
862
|
-
|
863
|
-
# Returns the bit value at offset in the string value stored at key.
|
864
|
-
#
|
865
|
-
# @param [String] key
|
866
|
-
# @param [Fixnum] offset bit offset
|
867
|
-
# @return [Fixnum] `0` or `1`
|
868
|
-
def getbit(key, offset)
|
869
|
-
synchronize do |client|
|
870
|
-
client.call([:getbit, key, offset])
|
871
|
-
end
|
872
|
-
end
|
873
|
-
|
874
|
-
# Append a value to a key.
|
875
|
-
#
|
876
|
-
# @param [String] key
|
877
|
-
# @param [String] value value to append
|
878
|
-
# @return [Fixnum] length of the string after appending
|
879
|
-
def append(key, value)
|
880
|
-
synchronize do |client|
|
881
|
-
client.call([:append, key, value])
|
882
|
-
end
|
883
|
-
end
|
884
|
-
|
885
|
-
# Count the number of set bits in a range of the string value stored at key.
|
886
|
-
#
|
887
|
-
# @param [String] key
|
888
|
-
# @param [Fixnum] start start index
|
889
|
-
# @param [Fixnum] stop stop index
|
890
|
-
# @return [Fixnum] the number of bits set to 1
|
891
|
-
def bitcount(key, start = 0, stop = -1)
|
892
|
-
synchronize do |client|
|
893
|
-
client.call([:bitcount, key, start, stop])
|
894
|
-
end
|
895
|
-
end
|
896
|
-
|
897
|
-
# Perform a bitwise operation between strings and store the resulting string in a key.
|
898
|
-
#
|
899
|
-
# @param [String] operation e.g. `and`, `or`, `xor`, `not`
|
900
|
-
# @param [String] destkey destination key
|
901
|
-
# @param [String, Array<String>] keys one or more source keys to perform `operation`
|
902
|
-
# @return [Fixnum] the length of the string stored in `destkey`
|
903
|
-
def bitop(operation, destkey, *keys)
|
904
|
-
synchronize do |client|
|
905
|
-
client.call([:bitop, operation, destkey] + keys)
|
906
|
-
end
|
907
|
-
end
|
908
|
-
|
909
|
-
# Return the position of the first bit set to 1 or 0 in a string.
|
910
|
-
#
|
911
|
-
# @param [String] key
|
912
|
-
# @param [Fixnum] bit whether to look for the first 1 or 0 bit
|
913
|
-
# @param [Fixnum] start start index
|
914
|
-
# @param [Fixnum] stop stop index
|
915
|
-
# @return [Fixnum] the position of the first 1/0 bit.
|
916
|
-
# -1 if looking for 1 and it is not found or start and stop are given.
|
917
|
-
def bitpos(key, bit, start=nil, stop=nil)
|
918
|
-
if stop and not start
|
919
|
-
raise(ArgumentError, 'stop parameter specified without start parameter')
|
920
|
-
end
|
921
|
-
|
922
|
-
synchronize do |client|
|
923
|
-
command = [:bitpos, key, bit]
|
924
|
-
command << start if start
|
925
|
-
command << stop if stop
|
926
|
-
client.call(command)
|
927
|
-
end
|
928
|
-
end
|
929
|
-
|
930
|
-
# Set the string value of a key and return its old value.
|
931
|
-
#
|
932
|
-
# @param [String] key
|
933
|
-
# @param [String] value value to replace the current value with
|
934
|
-
# @return [String] the old value stored in the key, or `nil` if the key
|
935
|
-
# did not exist
|
936
|
-
def getset(key, value)
|
937
|
-
synchronize do |client|
|
938
|
-
client.call([:getset, key, value.to_s])
|
939
|
-
end
|
940
|
-
end
|
941
|
-
|
942
|
-
# Get the length of the value stored in a key.
|
943
|
-
#
|
944
|
-
# @param [String] key
|
945
|
-
# @return [Fixnum] the length of the value stored in the key, or 0
|
946
|
-
# if the key does not exist
|
947
|
-
def strlen(key)
|
948
|
-
synchronize do |client|
|
949
|
-
client.call([:strlen, key])
|
950
|
-
end
|
951
|
-
end
|
952
|
-
|
953
|
-
# Get the length of a list.
|
954
|
-
#
|
955
|
-
# @param [String] key
|
956
|
-
# @return [Fixnum]
|
957
|
-
def llen(key)
|
958
|
-
synchronize do |client|
|
959
|
-
client.call([:llen, key])
|
960
|
-
end
|
961
|
-
end
|
962
|
-
|
963
|
-
# Prepend one or more values to a list, creating the list if it doesn't exist
|
964
|
-
#
|
965
|
-
# @param [String] key
|
966
|
-
# @param [String, Array] string value, or array of string values to push
|
967
|
-
# @return [Fixnum] the length of the list after the push operation
|
968
|
-
def lpush(key, value)
|
969
|
-
synchronize do |client|
|
970
|
-
client.call([:lpush, key, value])
|
971
|
-
end
|
972
|
-
end
|
973
|
-
|
974
|
-
# Prepend a value to a list, only if the list exists.
|
975
|
-
#
|
976
|
-
# @param [String] key
|
977
|
-
# @param [String] value
|
978
|
-
# @return [Fixnum] the length of the list after the push operation
|
979
|
-
def lpushx(key, value)
|
980
|
-
synchronize do |client|
|
981
|
-
client.call([:lpushx, key, value])
|
982
|
-
end
|
983
|
-
end
|
984
|
-
|
985
|
-
# Append one or more values to a list, creating the list if it doesn't exist
|
986
|
-
#
|
987
|
-
# @param [String] key
|
988
|
-
# @param [String] value
|
989
|
-
# @return [Fixnum] the length of the list after the push operation
|
990
|
-
def rpush(key, value)
|
991
|
-
synchronize do |client|
|
992
|
-
client.call([:rpush, key, value])
|
993
|
-
end
|
994
|
-
end
|
995
|
-
|
996
|
-
# Append a value to a list, only if the list exists.
|
997
|
-
#
|
998
|
-
# @param [String] key
|
999
|
-
# @param [String] value
|
1000
|
-
# @return [Fixnum] the length of the list after the push operation
|
1001
|
-
def rpushx(key, value)
|
1002
|
-
synchronize do |client|
|
1003
|
-
client.call([:rpushx, key, value])
|
1004
|
-
end
|
1005
|
-
end
|
1006
|
-
|
1007
|
-
# Remove and get the first element in a list.
|
1008
|
-
#
|
1009
|
-
# @param [String] key
|
1010
|
-
# @return [String]
|
1011
|
-
def lpop(key)
|
1012
|
-
synchronize do |client|
|
1013
|
-
client.call([:lpop, key])
|
1014
|
-
end
|
1015
|
-
end
|
1016
|
-
|
1017
|
-
# Remove and get the last element in a list.
|
1018
|
-
#
|
1019
|
-
# @param [String] key
|
1020
|
-
# @return [String]
|
1021
|
-
def rpop(key)
|
1022
|
-
synchronize do |client|
|
1023
|
-
client.call([:rpop, key])
|
1024
|
-
end
|
1025
|
-
end
|
1026
|
-
|
1027
|
-
# Remove the last element in a list, append it to another list and return it.
|
1028
|
-
#
|
1029
|
-
# @param [String] source source key
|
1030
|
-
# @param [String] destination destination key
|
1031
|
-
# @return [nil, String] the element, or nil when the source key does not exist
|
1032
|
-
def rpoplpush(source, destination)
|
1033
|
-
synchronize do |client|
|
1034
|
-
client.call([:rpoplpush, source, destination])
|
1035
|
-
end
|
1036
|
-
end
|
1037
|
-
|
1038
|
-
def _bpop(cmd, args)
|
1039
|
-
options = {}
|
1040
|
-
|
1041
|
-
case args.last
|
1042
|
-
when Hash
|
1043
|
-
options = args.pop
|
1044
|
-
when Integer
|
1045
|
-
# Issue deprecation notice in obnoxious mode...
|
1046
|
-
options[:timeout] = args.pop
|
1047
|
-
end
|
1048
|
-
|
1049
|
-
if args.size > 1
|
1050
|
-
# Issue deprecation notice in obnoxious mode...
|
1051
|
-
end
|
1052
|
-
|
1053
|
-
keys = args.flatten
|
1054
|
-
timeout = options[:timeout] || 0
|
1055
|
-
|
1056
|
-
synchronize do |client|
|
1057
|
-
command = [cmd, keys, timeout]
|
1058
|
-
timeout += client.timeout if timeout > 0
|
1059
|
-
client.call_with_timeout(command, timeout)
|
1060
|
-
end
|
1061
|
-
end
|
1062
|
-
|
1063
|
-
# Remove and get the first element in a list, or block until one is available.
|
1064
|
-
#
|
1065
|
-
# @example With timeout
|
1066
|
-
# list, element = redis.blpop("list", :timeout => 5)
|
1067
|
-
# # => nil on timeout
|
1068
|
-
# # => ["list", "element"] on success
|
1069
|
-
# @example Without timeout
|
1070
|
-
# list, element = redis.blpop("list")
|
1071
|
-
# # => ["list", "element"]
|
1072
|
-
# @example Blocking pop on multiple lists
|
1073
|
-
# list, element = redis.blpop(["list", "another_list"])
|
1074
|
-
# # => ["list", "element"]
|
1075
|
-
#
|
1076
|
-
# @param [String, Array<String>] keys one or more keys to perform the
|
1077
|
-
# blocking pop on
|
1078
|
-
# @param [Hash] options
|
1079
|
-
# - `:timeout => Fixnum`: timeout in seconds, defaults to no timeout
|
1080
|
-
#
|
1081
|
-
# @return [nil, [String, String]]
|
1082
|
-
# - `nil` when the operation timed out
|
1083
|
-
# - tuple of the list that was popped from and element was popped otherwise
|
1084
|
-
def blpop(*args)
|
1085
|
-
_bpop(:blpop, args)
|
1086
|
-
end
|
1087
|
-
|
1088
|
-
# Remove and get the last element in a list, or block until one is available.
|
1089
|
-
#
|
1090
|
-
# @param [String, Array<String>] keys one or more keys to perform the
|
1091
|
-
# blocking pop on
|
1092
|
-
# @param [Hash] options
|
1093
|
-
# - `:timeout => Fixnum`: timeout in seconds, defaults to no timeout
|
1094
|
-
#
|
1095
|
-
# @return [nil, [String, String]]
|
1096
|
-
# - `nil` when the operation timed out
|
1097
|
-
# - tuple of the list that was popped from and element was popped otherwise
|
1098
|
-
#
|
1099
|
-
# @see #blpop
|
1100
|
-
def brpop(*args)
|
1101
|
-
_bpop(:brpop, args)
|
1102
|
-
end
|
1103
|
-
|
1104
|
-
# Pop a value from a list, push it to another list and return it; or block
|
1105
|
-
# until one is available.
|
1106
|
-
#
|
1107
|
-
# @param [String] source source key
|
1108
|
-
# @param [String] destination destination key
|
1109
|
-
# @param [Hash] options
|
1110
|
-
# - `:timeout => Fixnum`: timeout in seconds, defaults to no timeout
|
1111
|
-
#
|
1112
|
-
# @return [nil, String]
|
1113
|
-
# - `nil` when the operation timed out
|
1114
|
-
# - the element was popped and pushed otherwise
|
1115
|
-
def brpoplpush(source, destination, options = {})
|
1116
|
-
case options
|
1117
|
-
when Integer
|
1118
|
-
# Issue deprecation notice in obnoxious mode...
|
1119
|
-
options = { :timeout => options }
|
1120
|
-
end
|
1121
|
-
|
1122
|
-
timeout = options[:timeout] || 0
|
1123
|
-
|
1124
|
-
synchronize do |client|
|
1125
|
-
command = [:brpoplpush, source, destination, timeout]
|
1126
|
-
timeout += client.timeout if timeout > 0
|
1127
|
-
client.call_with_timeout(command, timeout)
|
1128
|
-
end
|
1129
|
-
end
|
1130
|
-
|
1131
|
-
# Get an element from a list by its index.
|
1132
|
-
#
|
1133
|
-
# @param [String] key
|
1134
|
-
# @param [Fixnum] index
|
1135
|
-
# @return [String]
|
1136
|
-
def lindex(key, index)
|
1137
|
-
synchronize do |client|
|
1138
|
-
client.call([:lindex, key, index])
|
1139
|
-
end
|
1140
|
-
end
|
1141
|
-
|
1142
|
-
# Insert an element before or after another element in a list.
|
1143
|
-
#
|
1144
|
-
# @param [String] key
|
1145
|
-
# @param [String, Symbol] where `BEFORE` or `AFTER`
|
1146
|
-
# @param [String] pivot reference element
|
1147
|
-
# @param [String] value
|
1148
|
-
# @return [Fixnum] length of the list after the insert operation, or `-1`
|
1149
|
-
# when the element `pivot` was not found
|
1150
|
-
def linsert(key, where, pivot, value)
|
1151
|
-
synchronize do |client|
|
1152
|
-
client.call([:linsert, key, where, pivot, value])
|
1153
|
-
end
|
1154
|
-
end
|
1155
|
-
|
1156
|
-
# Get a range of elements from a list.
|
1157
|
-
#
|
1158
|
-
# @param [String] key
|
1159
|
-
# @param [Fixnum] start start index
|
1160
|
-
# @param [Fixnum] stop stop index
|
1161
|
-
# @return [Array<String>]
|
1162
|
-
def lrange(key, start, stop)
|
1163
|
-
synchronize do |client|
|
1164
|
-
client.call([:lrange, key, start, stop])
|
1165
|
-
end
|
1166
|
-
end
|
1167
|
-
|
1168
|
-
# Remove elements from a list.
|
1169
|
-
#
|
1170
|
-
# @param [String] key
|
1171
|
-
# @param [Fixnum] count number of elements to remove. Use a positive
|
1172
|
-
# value to remove the first `count` occurrences of `value`. A negative
|
1173
|
-
# value to remove the last `count` occurrences of `value`. Or zero, to
|
1174
|
-
# remove all occurrences of `value` from the list.
|
1175
|
-
# @param [String] value
|
1176
|
-
# @return [Fixnum] the number of removed elements
|
1177
|
-
def lrem(key, count, value)
|
1178
|
-
synchronize do |client|
|
1179
|
-
client.call([:lrem, key, count, value])
|
1180
|
-
end
|
1181
|
-
end
|
1182
|
-
|
1183
|
-
# Set the value of an element in a list by its index.
|
1184
|
-
#
|
1185
|
-
# @param [String] key
|
1186
|
-
# @param [Fixnum] index
|
1187
|
-
# @param [String] value
|
1188
|
-
# @return [String] `OK`
|
1189
|
-
def lset(key, index, value)
|
1190
|
-
synchronize do |client|
|
1191
|
-
client.call([:lset, key, index, value])
|
1192
|
-
end
|
1193
|
-
end
|
1194
|
-
|
1195
|
-
# Trim a list to the specified range.
|
1196
|
-
#
|
1197
|
-
# @param [String] key
|
1198
|
-
# @param [Fixnum] start start index
|
1199
|
-
# @param [Fixnum] stop stop index
|
1200
|
-
# @return [String] `OK`
|
1201
|
-
def ltrim(key, start, stop)
|
1202
|
-
synchronize do |client|
|
1203
|
-
client.call([:ltrim, key, start, stop])
|
1204
|
-
end
|
1205
|
-
end
|
1206
|
-
|
1207
|
-
# Get the number of members in a set.
|
1208
|
-
#
|
1209
|
-
# @param [String] key
|
1210
|
-
# @return [Fixnum]
|
1211
|
-
def scard(key)
|
1212
|
-
synchronize do |client|
|
1213
|
-
client.call([:scard, key])
|
1214
|
-
end
|
1215
|
-
end
|
1216
|
-
|
1217
|
-
# Add one or more members to a set.
|
1218
|
-
#
|
1219
|
-
# @param [String] key
|
1220
|
-
# @param [String, Array<String>] member one member, or array of members
|
1221
|
-
# @return [Boolean, Fixnum] `Boolean` when a single member is specified,
|
1222
|
-
# holding whether or not adding the member succeeded, or `Fixnum` when an
|
1223
|
-
# array of members is specified, holding the number of members that were
|
1224
|
-
# successfully added
|
1225
|
-
def sadd(key, member)
|
1226
|
-
synchronize do |client|
|
1227
|
-
client.call([:sadd, key, member]) do |reply|
|
1228
|
-
if member.is_a? Array
|
1229
|
-
# Variadic: return integer
|
1230
|
-
reply
|
1231
|
-
else
|
1232
|
-
# Single argument: return boolean
|
1233
|
-
_boolify.call(reply)
|
1234
|
-
end
|
1235
|
-
end
|
1236
|
-
end
|
1237
|
-
end
|
1238
|
-
|
1239
|
-
# Remove one or more members from a set.
|
1240
|
-
#
|
1241
|
-
# @param [String] key
|
1242
|
-
# @param [String, Array<String>] member one member, or array of members
|
1243
|
-
# @return [Boolean, Fixnum] `Boolean` when a single member is specified,
|
1244
|
-
# holding whether or not removing the member succeeded, or `Fixnum` when an
|
1245
|
-
# array of members is specified, holding the number of members that were
|
1246
|
-
# successfully removed
|
1247
|
-
def srem(key, member)
|
1248
|
-
synchronize do |client|
|
1249
|
-
client.call([:srem, key, member]) do |reply|
|
1250
|
-
if member.is_a? Array
|
1251
|
-
# Variadic: return integer
|
1252
|
-
reply
|
1253
|
-
else
|
1254
|
-
# Single argument: return boolean
|
1255
|
-
_boolify.call(reply)
|
1256
|
-
end
|
1257
|
-
end
|
1258
|
-
end
|
1259
|
-
end
|
1260
|
-
|
1261
|
-
# Remove and return a random member from a set.
|
1262
|
-
#
|
1263
|
-
# @param [String] key
|
1264
|
-
# @return [String]
|
1265
|
-
def spop(key)
|
1266
|
-
synchronize do |client|
|
1267
|
-
client.call([:spop, key])
|
1268
|
-
end
|
1269
|
-
end
|
1270
|
-
|
1271
|
-
# Get one or more random members from a set.
|
1272
|
-
#
|
1273
|
-
# @param [String] key
|
1274
|
-
# @param [Fixnum] count
|
1275
|
-
# @return [String]
|
1276
|
-
def srandmember(key, count = nil)
|
1277
|
-
synchronize do |client|
|
1278
|
-
if count.nil?
|
1279
|
-
client.call([:srandmember, key])
|
1280
|
-
else
|
1281
|
-
client.call([:srandmember, key, count])
|
1282
|
-
end
|
1283
|
-
end
|
1284
|
-
end
|
1285
|
-
|
1286
|
-
# Move a member from one set to another.
|
1287
|
-
#
|
1288
|
-
# @param [String] source source key
|
1289
|
-
# @param [String] destination destination key
|
1290
|
-
# @param [String] member member to move from `source` to `destination`
|
1291
|
-
# @return [Boolean]
|
1292
|
-
def smove(source, destination, member)
|
1293
|
-
synchronize do |client|
|
1294
|
-
client.call([:smove, source, destination, member], &_boolify)
|
1295
|
-
end
|
1296
|
-
end
|
1297
|
-
|
1298
|
-
# Determine if a given value is a member of a set.
|
1299
|
-
#
|
1300
|
-
# @param [String] key
|
1301
|
-
# @param [String] member
|
1302
|
-
# @return [Boolean]
|
1303
|
-
def sismember(key, member)
|
1304
|
-
synchronize do |client|
|
1305
|
-
client.call([:sismember, key, member], &_boolify)
|
1306
|
-
end
|
1307
|
-
end
|
1308
|
-
|
1309
|
-
# Get all the members in a set.
|
1310
|
-
#
|
1311
|
-
# @param [String] key
|
1312
|
-
# @return [Array<String>]
|
1313
|
-
def smembers(key)
|
1314
|
-
synchronize do |client|
|
1315
|
-
client.call([:smembers, key])
|
1316
|
-
end
|
1317
|
-
end
|
1318
|
-
|
1319
|
-
# Subtract multiple sets.
|
1320
|
-
#
|
1321
|
-
# @param [String, Array<String>] keys keys pointing to sets to subtract
|
1322
|
-
# @return [Array<String>] members in the difference
|
1323
|
-
def sdiff(*keys)
|
1324
|
-
synchronize do |client|
|
1325
|
-
client.call([:sdiff] + keys)
|
1326
|
-
end
|
1327
|
-
end
|
1328
|
-
|
1329
|
-
# Subtract multiple sets and store the resulting set in a key.
|
1330
|
-
#
|
1331
|
-
# @param [String] destination destination key
|
1332
|
-
# @param [String, Array<String>] keys keys pointing to sets to subtract
|
1333
|
-
# @return [Fixnum] number of elements in the resulting set
|
1334
|
-
def sdiffstore(destination, *keys)
|
1335
|
-
synchronize do |client|
|
1336
|
-
client.call([:sdiffstore, destination] + keys)
|
1337
|
-
end
|
1338
|
-
end
|
1339
|
-
|
1340
|
-
# Intersect multiple sets.
|
1341
|
-
#
|
1342
|
-
# @param [String, Array<String>] keys keys pointing to sets to intersect
|
1343
|
-
# @return [Array<String>] members in the intersection
|
1344
|
-
def sinter(*keys)
|
1345
|
-
synchronize do |client|
|
1346
|
-
client.call([:sinter] + keys)
|
1347
|
-
end
|
1348
|
-
end
|
1349
|
-
|
1350
|
-
# Intersect multiple sets and store the resulting set in a key.
|
1351
|
-
#
|
1352
|
-
# @param [String] destination destination key
|
1353
|
-
# @param [String, Array<String>] keys keys pointing to sets to intersect
|
1354
|
-
# @return [Fixnum] number of elements in the resulting set
|
1355
|
-
def sinterstore(destination, *keys)
|
1356
|
-
synchronize do |client|
|
1357
|
-
client.call([:sinterstore, destination] + keys)
|
1358
|
-
end
|
1359
|
-
end
|
1360
|
-
|
1361
|
-
# Add multiple sets.
|
1362
|
-
#
|
1363
|
-
# @param [String, Array<String>] keys keys pointing to sets to unify
|
1364
|
-
# @return [Array<String>] members in the union
|
1365
|
-
def sunion(*keys)
|
1366
|
-
synchronize do |client|
|
1367
|
-
client.call([:sunion] + keys)
|
1368
|
-
end
|
1369
|
-
end
|
1370
|
-
|
1371
|
-
# Add multiple sets and store the resulting set in a key.
|
1372
|
-
#
|
1373
|
-
# @param [String] destination destination key
|
1374
|
-
# @param [String, Array<String>] keys keys pointing to sets to unify
|
1375
|
-
# @return [Fixnum] number of elements in the resulting set
|
1376
|
-
def sunionstore(destination, *keys)
|
1377
|
-
synchronize do |client|
|
1378
|
-
client.call([:sunionstore, destination] + keys)
|
1379
|
-
end
|
1380
|
-
end
|
1381
|
-
|
1382
|
-
# Get the number of members in a sorted set.
|
1383
|
-
#
|
1384
|
-
# @example
|
1385
|
-
# redis.zcard("zset")
|
1386
|
-
# # => 4
|
1387
|
-
#
|
1388
|
-
# @param [String] key
|
1389
|
-
# @return [Fixnum]
|
1390
|
-
def zcard(key)
|
1391
|
-
synchronize do |client|
|
1392
|
-
client.call([:zcard, key])
|
1393
|
-
end
|
1394
|
-
end
|
1395
|
-
|
1396
|
-
# Add one or more members to a sorted set, or update the score for members
|
1397
|
-
# that already exist.
|
1398
|
-
#
|
1399
|
-
# @example Add a single `[score, member]` pair to a sorted set
|
1400
|
-
# redis.zadd("zset", 32.0, "member")
|
1401
|
-
# @example Add an array of `[score, member]` pairs to a sorted set
|
1402
|
-
# redis.zadd("zset", [[32.0, "a"], [64.0, "b"]])
|
1403
|
-
#
|
1404
|
-
# @param [String] key
|
1405
|
-
# @param [[Float, String], Array<[Float, String]>] args
|
1406
|
-
# - a single `[score, member]` pair
|
1407
|
-
# - an array of `[score, member]` pairs
|
1408
|
-
#
|
1409
|
-
# @return [Boolean, Fixnum]
|
1410
|
-
# - `Boolean` when a single pair is specified, holding whether or not it was
|
1411
|
-
# **added** to the sorted set
|
1412
|
-
# - `Fixnum` when an array of pairs is specified, holding the number of
|
1413
|
-
# pairs that were **added** to the sorted set
|
1414
|
-
def zadd(key, *args)
|
1415
|
-
synchronize do |client|
|
1416
|
-
if args.size == 1 && args[0].is_a?(Array)
|
1417
|
-
# Variadic: return integer
|
1418
|
-
client.call([:zadd, key] + args[0])
|
1419
|
-
elsif args.size == 2
|
1420
|
-
# Single pair: return boolean
|
1421
|
-
client.call([:zadd, key, args[0], args[1]], &_boolify)
|
1422
|
-
else
|
1423
|
-
raise ArgumentError, "wrong number of arguments"
|
1424
|
-
end
|
1425
|
-
end
|
1426
|
-
end
|
1427
|
-
|
1428
|
-
# Increment the score of a member in a sorted set.
|
1429
|
-
#
|
1430
|
-
# @example
|
1431
|
-
# redis.zincrby("zset", 32.0, "a")
|
1432
|
-
# # => 64.0
|
1433
|
-
#
|
1434
|
-
# @param [String] key
|
1435
|
-
# @param [Float] increment
|
1436
|
-
# @param [String] member
|
1437
|
-
# @return [Float] score of the member after incrementing it
|
1438
|
-
def zincrby(key, increment, member)
|
1439
|
-
synchronize do |client|
|
1440
|
-
client.call([:zincrby, key, increment, member], &_floatify)
|
1441
|
-
end
|
1442
|
-
end
|
1443
|
-
|
1444
|
-
# Remove one or more members from a sorted set.
|
1445
|
-
#
|
1446
|
-
# @example Remove a single member from a sorted set
|
1447
|
-
# redis.zrem("zset", "a")
|
1448
|
-
# @example Remove an array of members from a sorted set
|
1449
|
-
# redis.zrem("zset", ["a", "b"])
|
1450
|
-
#
|
1451
|
-
# @param [String] key
|
1452
|
-
# @param [String, Array<String>] member
|
1453
|
-
# - a single member
|
1454
|
-
# - an array of members
|
1455
|
-
#
|
1456
|
-
# @return [Boolean, Fixnum]
|
1457
|
-
# - `Boolean` when a single member is specified, holding whether or not it
|
1458
|
-
# was removed from the sorted set
|
1459
|
-
# - `Fixnum` when an array of pairs is specified, holding the number of
|
1460
|
-
# members that were removed to the sorted set
|
1461
|
-
def zrem(key, member)
|
1462
|
-
synchronize do |client|
|
1463
|
-
client.call([:zrem, key, member]) do |reply|
|
1464
|
-
if member.is_a? Array
|
1465
|
-
# Variadic: return integer
|
1466
|
-
reply
|
1467
|
-
else
|
1468
|
-
# Single argument: return boolean
|
1469
|
-
_boolify.call(reply)
|
1470
|
-
end
|
1471
|
-
end
|
1472
|
-
end
|
1473
|
-
end
|
1474
|
-
|
1475
|
-
# Get the score associated with the given member in a sorted set.
|
1476
|
-
#
|
1477
|
-
# @example Get the score for member "a"
|
1478
|
-
# redis.zscore("zset", "a")
|
1479
|
-
# # => 32.0
|
1480
|
-
#
|
1481
|
-
# @param [String] key
|
1482
|
-
# @param [String] member
|
1483
|
-
# @return [Float] score of the member
|
1484
|
-
def zscore(key, member)
|
1485
|
-
synchronize do |client|
|
1486
|
-
client.call([:zscore, key, member], &_floatify)
|
1487
|
-
end
|
1488
|
-
end
|
1489
|
-
|
1490
|
-
# Return a range of members in a sorted set, by index.
|
1491
|
-
#
|
1492
|
-
# @example Retrieve all members from a sorted set
|
1493
|
-
# redis.zrange("zset", 0, -1)
|
1494
|
-
# # => ["a", "b"]
|
1495
|
-
# @example Retrieve all members and their scores from a sorted set
|
1496
|
-
# redis.zrange("zset", 0, -1, :with_scores => true)
|
1497
|
-
# # => [["a", 32.0], ["b", 64.0]]
|
1498
|
-
#
|
1499
|
-
# @param [String] key
|
1500
|
-
# @param [Fixnum] start start index
|
1501
|
-
# @param [Fixnum] stop stop index
|
1502
|
-
# @param [Hash] options
|
1503
|
-
# - `:with_scores => true`: include scores in output
|
1504
|
-
#
|
1505
|
-
# @return [Array<String>, Array<[String, Float]>]
|
1506
|
-
# - when `:with_scores` is not specified, an array of members
|
1507
|
-
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
1508
|
-
def zrange(key, start, stop, options = {})
|
1509
|
-
args = []
|
1510
|
-
|
1511
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1512
|
-
|
1513
|
-
if with_scores
|
1514
|
-
args << "WITHSCORES"
|
1515
|
-
block = _floatify_pairs
|
1516
|
-
end
|
1517
|
-
|
1518
|
-
synchronize do |client|
|
1519
|
-
client.call([:zrange, key, start, stop] + args, &block)
|
1520
|
-
end
|
1521
|
-
end
|
1522
|
-
|
1523
|
-
# Return a range of members in a sorted set, by index, with scores ordered
|
1524
|
-
# from high to low.
|
1525
|
-
#
|
1526
|
-
# @example Retrieve all members from a sorted set
|
1527
|
-
# redis.zrevrange("zset", 0, -1)
|
1528
|
-
# # => ["b", "a"]
|
1529
|
-
# @example Retrieve all members and their scores from a sorted set
|
1530
|
-
# redis.zrevrange("zset", 0, -1, :with_scores => true)
|
1531
|
-
# # => [["b", 64.0], ["a", 32.0]]
|
1532
|
-
#
|
1533
|
-
# @see #zrange
|
1534
|
-
def zrevrange(key, start, stop, options = {})
|
1535
|
-
args = []
|
1536
|
-
|
1537
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1538
|
-
|
1539
|
-
if with_scores
|
1540
|
-
args << "WITHSCORES"
|
1541
|
-
block = _floatify_pairs
|
1542
|
-
end
|
1543
|
-
|
1544
|
-
synchronize do |client|
|
1545
|
-
client.call([:zrevrange, key, start, stop] + args, &block)
|
1546
|
-
end
|
1547
|
-
end
|
1548
|
-
|
1549
|
-
# Determine the index of a member in a sorted set.
|
1550
|
-
#
|
1551
|
-
# @param [String] key
|
1552
|
-
# @param [String] member
|
1553
|
-
# @return [Fixnum]
|
1554
|
-
def zrank(key, member)
|
1555
|
-
synchronize do |client|
|
1556
|
-
client.call([:zrank, key, member])
|
1557
|
-
end
|
1558
|
-
end
|
1559
|
-
|
1560
|
-
# Determine the index of a member in a sorted set, with scores ordered from
|
1561
|
-
# high to low.
|
1562
|
-
#
|
1563
|
-
# @param [String] key
|
1564
|
-
# @param [String] member
|
1565
|
-
# @return [Fixnum]
|
1566
|
-
def zrevrank(key, member)
|
1567
|
-
synchronize do |client|
|
1568
|
-
client.call([:zrevrank, key, member])
|
1569
|
-
end
|
1570
|
-
end
|
1571
|
-
|
1572
|
-
# Remove all members in a sorted set within the given indexes.
|
1573
|
-
#
|
1574
|
-
# @example Remove first 5 members
|
1575
|
-
# redis.zremrangebyrank("zset", 0, 4)
|
1576
|
-
# # => 5
|
1577
|
-
# @example Remove last 5 members
|
1578
|
-
# redis.zremrangebyrank("zset", -5, -1)
|
1579
|
-
# # => 5
|
1580
|
-
#
|
1581
|
-
# @param [String] key
|
1582
|
-
# @param [Fixnum] start start index
|
1583
|
-
# @param [Fixnum] stop stop index
|
1584
|
-
# @return [Fixnum] number of members that were removed
|
1585
|
-
def zremrangebyrank(key, start, stop)
|
1586
|
-
synchronize do |client|
|
1587
|
-
client.call([:zremrangebyrank, key, start, stop])
|
1588
|
-
end
|
1589
|
-
end
|
1590
|
-
|
1591
|
-
# Return a range of members with the same score in a sorted set, by lexicographical ordering
|
1592
|
-
#
|
1593
|
-
# @example Retrieve members matching a
|
1594
|
-
# redis.zrangebylex("zset", "[a", "[a\xff")
|
1595
|
-
# # => ["aaren", "aarika", "abagael", "abby"]
|
1596
|
-
# @example Retrieve the first 2 members matching a
|
1597
|
-
# redis.zrangebylex("zset", "[a", "[a\xff", :limit => [0, 2])
|
1598
|
-
# # => ["aaren", "aarika"]
|
1599
|
-
#
|
1600
|
-
# @param [String] key
|
1601
|
-
# @param [String] min
|
1602
|
-
# - inclusive minimum is specified by prefixing `(`
|
1603
|
-
# - exclusive minimum is specified by prefixing `[`
|
1604
|
-
# @param [String] max
|
1605
|
-
# - inclusive maximum is specified by prefixing `(`
|
1606
|
-
# - exclusive maximum is specified by prefixing `[`
|
1607
|
-
# @param [Hash] options
|
1608
|
-
# - `:limit => [offset, count]`: skip `offset` members, return a maximum of
|
1609
|
-
# `count` members
|
1610
|
-
#
|
1611
|
-
# @return [Array<String>, Array<[String, Float]>]
|
1612
|
-
def zrangebylex(key, min, max, options = {})
|
1613
|
-
args = []
|
1614
|
-
|
1615
|
-
limit = options[:limit]
|
1616
|
-
args.concat(["LIMIT"] + limit) if limit
|
1617
|
-
|
1618
|
-
synchronize do |client|
|
1619
|
-
client.call([:zrangebylex, key, min, max] + args)
|
1620
|
-
end
|
1621
|
-
end
|
1622
|
-
|
1623
|
-
# Return a range of members in a sorted set, by score.
|
1624
|
-
#
|
1625
|
-
# @example Retrieve members with score `>= 5` and `< 100`
|
1626
|
-
# redis.zrangebyscore("zset", "5", "(100")
|
1627
|
-
# # => ["a", "b"]
|
1628
|
-
# @example Retrieve the first 2 members with score `>= 0`
|
1629
|
-
# redis.zrangebyscore("zset", "0", "+inf", :limit => [0, 2])
|
1630
|
-
# # => ["a", "b"]
|
1631
|
-
# @example Retrieve members and their scores with scores `> 5`
|
1632
|
-
# redis.zrangebyscore("zset", "(5", "+inf", :with_scores => true)
|
1633
|
-
# # => [["a", 32.0], ["b", 64.0]]
|
1634
|
-
#
|
1635
|
-
# @param [String] key
|
1636
|
-
# @param [String] min
|
1637
|
-
# - inclusive minimum score is specified verbatim
|
1638
|
-
# - exclusive minimum score is specified by prefixing `(`
|
1639
|
-
# @param [String] max
|
1640
|
-
# - inclusive maximum score is specified verbatim
|
1641
|
-
# - exclusive maximum score is specified by prefixing `(`
|
1642
|
-
# @param [Hash] options
|
1643
|
-
# - `:with_scores => true`: include scores in output
|
1644
|
-
# - `:limit => [offset, count]`: skip `offset` members, return a maximum of
|
1645
|
-
# `count` members
|
1646
|
-
#
|
1647
|
-
# @return [Array<String>, Array<[String, Float]>]
|
1648
|
-
# - when `:with_scores` is not specified, an array of members
|
1649
|
-
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
1650
|
-
def zrangebyscore(key, min, max, options = {})
|
1651
|
-
args = []
|
1652
|
-
|
1653
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1654
|
-
|
1655
|
-
if with_scores
|
1656
|
-
args << "WITHSCORES"
|
1657
|
-
block = _floatify_pairs
|
1658
|
-
end
|
1659
|
-
|
1660
|
-
limit = options[:limit]
|
1661
|
-
args.concat(["LIMIT"] + limit) if limit
|
1662
|
-
|
1663
|
-
synchronize do |client|
|
1664
|
-
client.call([:zrangebyscore, key, min, max] + args, &block)
|
1665
|
-
end
|
1666
|
-
end
|
1667
|
-
|
1668
|
-
# Return a range of members in a sorted set, by score, with scores ordered
|
1669
|
-
# from high to low.
|
1670
|
-
#
|
1671
|
-
# @example Retrieve members with score `< 100` and `>= 5`
|
1672
|
-
# redis.zrevrangebyscore("zset", "(100", "5")
|
1673
|
-
# # => ["b", "a"]
|
1674
|
-
# @example Retrieve the first 2 members with score `<= 0`
|
1675
|
-
# redis.zrevrangebyscore("zset", "0", "-inf", :limit => [0, 2])
|
1676
|
-
# # => ["b", "a"]
|
1677
|
-
# @example Retrieve members and their scores with scores `> 5`
|
1678
|
-
# redis.zrevrangebyscore("zset", "+inf", "(5", :with_scores => true)
|
1679
|
-
# # => [["b", 64.0], ["a", 32.0]]
|
1680
|
-
#
|
1681
|
-
# @see #zrangebyscore
|
1682
|
-
def zrevrangebyscore(key, max, min, options = {})
|
1683
|
-
args = []
|
1684
|
-
|
1685
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1686
|
-
|
1687
|
-
if with_scores
|
1688
|
-
args << ["WITHSCORES"]
|
1689
|
-
block = _floatify_pairs
|
1690
|
-
end
|
1691
|
-
|
1692
|
-
limit = options[:limit]
|
1693
|
-
args.concat(["LIMIT"] + limit) if limit
|
1694
|
-
|
1695
|
-
synchronize do |client|
|
1696
|
-
client.call([:zrevrangebyscore, key, max, min] + args, &block)
|
1697
|
-
end
|
1698
|
-
end
|
1699
|
-
|
1700
|
-
# Remove all members in a sorted set within the given scores.
|
1701
|
-
#
|
1702
|
-
# @example Remove members with score `>= 5` and `< 100`
|
1703
|
-
# redis.zremrangebyscore("zset", "5", "(100")
|
1704
|
-
# # => 2
|
1705
|
-
# @example Remove members with scores `> 5`
|
1706
|
-
# redis.zremrangebyscore("zset", "(5", "+inf")
|
1707
|
-
# # => 2
|
1708
|
-
#
|
1709
|
-
# @param [String] key
|
1710
|
-
# @param [String] min
|
1711
|
-
# - inclusive minimum score is specified verbatim
|
1712
|
-
# - exclusive minimum score is specified by prefixing `(`
|
1713
|
-
# @param [String] max
|
1714
|
-
# - inclusive maximum score is specified verbatim
|
1715
|
-
# - exclusive maximum score is specified by prefixing `(`
|
1716
|
-
# @return [Fixnum] number of members that were removed
|
1717
|
-
def zremrangebyscore(key, min, max)
|
1718
|
-
synchronize do |client|
|
1719
|
-
client.call([:zremrangebyscore, key, min, max])
|
1720
|
-
end
|
1721
|
-
end
|
1722
|
-
|
1723
|
-
# Count the members in a sorted set with scores within the given values.
|
1724
|
-
#
|
1725
|
-
# @example Count members with score `>= 5` and `< 100`
|
1726
|
-
# redis.zcount("zset", "5", "(100")
|
1727
|
-
# # => 2
|
1728
|
-
# @example Count members with scores `> 5`
|
1729
|
-
# redis.zcount("zset", "(5", "+inf")
|
1730
|
-
# # => 2
|
1731
|
-
#
|
1732
|
-
# @param [String] key
|
1733
|
-
# @param [String] min
|
1734
|
-
# - inclusive minimum score is specified verbatim
|
1735
|
-
# - exclusive minimum score is specified by prefixing `(`
|
1736
|
-
# @param [String] max
|
1737
|
-
# - inclusive maximum score is specified verbatim
|
1738
|
-
# - exclusive maximum score is specified by prefixing `(`
|
1739
|
-
# @return [Fixnum] number of members in within the specified range
|
1740
|
-
def zcount(key, min, max)
|
1741
|
-
synchronize do |client|
|
1742
|
-
client.call([:zcount, key, min, max])
|
1743
|
-
end
|
1744
|
-
end
|
1745
|
-
|
1746
|
-
# Intersect multiple sorted sets and store the resulting sorted set in a new
|
1747
|
-
# key.
|
1748
|
-
#
|
1749
|
-
# @example Compute the intersection of `2*zsetA` with `1*zsetB`, summing their scores
|
1750
|
-
# redis.zinterstore("zsetC", ["zsetA", "zsetB"], :weights => [2.0, 1.0], :aggregate => "sum")
|
1751
|
-
# # => 4
|
1752
|
-
#
|
1753
|
-
# @param [String] destination destination key
|
1754
|
-
# @param [Array<String>] keys source keys
|
1755
|
-
# @param [Hash] options
|
1756
|
-
# - `:weights => [Float, Float, ...]`: weights to associate with source
|
1757
|
-
# sorted sets
|
1758
|
-
# - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
|
1759
|
-
# @return [Fixnum] number of elements in the resulting sorted set
|
1760
|
-
def zinterstore(destination, keys, options = {})
|
1761
|
-
args = []
|
1762
|
-
|
1763
|
-
weights = options[:weights]
|
1764
|
-
args.concat(["WEIGHTS"] + weights) if weights
|
1765
|
-
|
1766
|
-
aggregate = options[:aggregate]
|
1767
|
-
args.concat(["AGGREGATE", aggregate]) if aggregate
|
1768
|
-
|
1769
|
-
synchronize do |client|
|
1770
|
-
client.call([:zinterstore, destination, keys.size] + keys + args)
|
1771
|
-
end
|
1772
|
-
end
|
1773
|
-
|
1774
|
-
# Add multiple sorted sets and store the resulting sorted set in a new key.
|
1775
|
-
#
|
1776
|
-
# @example Compute the union of `2*zsetA` with `1*zsetB`, summing their scores
|
1777
|
-
# redis.zunionstore("zsetC", ["zsetA", "zsetB"], :weights => [2.0, 1.0], :aggregate => "sum")
|
1778
|
-
# # => 8
|
1779
|
-
#
|
1780
|
-
# @param [String] destination destination key
|
1781
|
-
# @param [Array<String>] keys source keys
|
1782
|
-
# @param [Hash] options
|
1783
|
-
# - `:weights => [Float, Float, ...]`: weights to associate with source
|
1784
|
-
# sorted sets
|
1785
|
-
# - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
|
1786
|
-
# @return [Fixnum] number of elements in the resulting sorted set
|
1787
|
-
def zunionstore(destination, keys, options = {})
|
1788
|
-
args = []
|
1789
|
-
|
1790
|
-
weights = options[:weights]
|
1791
|
-
args.concat(["WEIGHTS"] + weights) if weights
|
1792
|
-
|
1793
|
-
aggregate = options[:aggregate]
|
1794
|
-
args.concat(["AGGREGATE", aggregate]) if aggregate
|
1795
|
-
|
1796
|
-
synchronize do |client|
|
1797
|
-
client.call([:zunionstore, destination, keys.size] + keys + args)
|
1798
|
-
end
|
1799
|
-
end
|
1800
|
-
|
1801
|
-
# Get the number of fields in a hash.
|
1802
|
-
#
|
1803
|
-
# @param [String] key
|
1804
|
-
# @return [Fixnum] number of fields in the hash
|
1805
|
-
def hlen(key)
|
1806
|
-
synchronize do |client|
|
1807
|
-
client.call([:hlen, key])
|
1808
|
-
end
|
1809
|
-
end
|
1810
|
-
|
1811
|
-
# Set the string value of a hash field.
|
1812
|
-
#
|
1813
|
-
# @param [String] key
|
1814
|
-
# @param [String] field
|
1815
|
-
# @param [String] value
|
1816
|
-
# @return [Boolean] whether or not the field was **added** to the hash
|
1817
|
-
def hset(key, field, value)
|
1818
|
-
synchronize do |client|
|
1819
|
-
client.call([:hset, key, field, value], &_boolify)
|
1820
|
-
end
|
1821
|
-
end
|
1822
|
-
|
1823
|
-
# Set the value of a hash field, only if the field does not exist.
|
1824
|
-
#
|
1825
|
-
# @param [String] key
|
1826
|
-
# @param [String] field
|
1827
|
-
# @param [String] value
|
1828
|
-
# @return [Boolean] whether or not the field was **added** to the hash
|
1829
|
-
def hsetnx(key, field, value)
|
1830
|
-
synchronize do |client|
|
1831
|
-
client.call([:hsetnx, key, field, value], &_boolify)
|
1832
|
-
end
|
1833
|
-
end
|
1834
|
-
|
1835
|
-
# Set one or more hash values.
|
1836
|
-
#
|
1837
|
-
# @example
|
1838
|
-
# redis.hmset("hash", "f1", "v1", "f2", "v2")
|
1839
|
-
# # => "OK"
|
1840
|
-
#
|
1841
|
-
# @param [String] key
|
1842
|
-
# @param [Array<String>] attrs array of fields and values
|
1843
|
-
# @return `"OK"`
|
1844
|
-
#
|
1845
|
-
# @see #mapped_hmset
|
1846
|
-
def hmset(key, *attrs)
|
1847
|
-
synchronize do |client|
|
1848
|
-
client.call([:hmset, key] + attrs)
|
1849
|
-
end
|
1850
|
-
end
|
1851
|
-
|
1852
|
-
# Set one or more hash values.
|
1853
|
-
#
|
1854
|
-
# @example
|
1855
|
-
# redis.mapped_hmset("hash", { "f1" => "v1", "f2" => "v2" })
|
1856
|
-
# # => "OK"
|
1857
|
-
#
|
1858
|
-
# @param [String] key
|
1859
|
-
# @param [Hash] hash fields mapping to values
|
1860
|
-
# @return `"OK"`
|
1861
|
-
#
|
1862
|
-
# @see #hmset
|
1863
|
-
def mapped_hmset(key, hash)
|
1864
|
-
hmset(key, hash.to_a.flatten)
|
1865
|
-
end
|
1
|
+
# frozen_string_literal: true
|
1866
2
|
|
1867
|
-
|
1868
|
-
|
1869
|
-
|
1870
|
-
# @param [String] field
|
1871
|
-
# @return [String]
|
1872
|
-
def hget(key, field)
|
1873
|
-
synchronize do |client|
|
1874
|
-
client.call([:hget, key, field])
|
1875
|
-
end
|
1876
|
-
end
|
1877
|
-
|
1878
|
-
# Get the values of all the given hash fields.
|
1879
|
-
#
|
1880
|
-
# @example
|
1881
|
-
# redis.hmget("hash", "f1", "f2")
|
1882
|
-
# # => ["v1", "v2"]
|
1883
|
-
#
|
1884
|
-
# @param [String] key
|
1885
|
-
# @param [Array<String>] fields array of fields
|
1886
|
-
# @return [Array<String>] an array of values for the specified fields
|
1887
|
-
#
|
1888
|
-
# @see #mapped_hmget
|
1889
|
-
def hmget(key, *fields, &blk)
|
1890
|
-
synchronize do |client|
|
1891
|
-
client.call([:hmget, key] + fields, &blk)
|
1892
|
-
end
|
1893
|
-
end
|
3
|
+
require "monitor"
|
4
|
+
require "redis/errors"
|
5
|
+
require "redis/commands"
|
1894
6
|
|
1895
|
-
|
1896
|
-
|
1897
|
-
|
1898
|
-
|
1899
|
-
|
1900
|
-
|
1901
|
-
|
1902
|
-
|
1903
|
-
|
1904
|
-
|
1905
|
-
|
1906
|
-
|
1907
|
-
|
1908
|
-
|
1909
|
-
|
1910
|
-
|
1911
|
-
|
7
|
+
class Redis
|
8
|
+
BASE_PATH = __dir__
|
9
|
+
@exists_returns_integer = true
|
10
|
+
|
11
|
+
Deprecated = Class.new(StandardError)
|
12
|
+
|
13
|
+
class << self
|
14
|
+
attr_reader :exists_returns_integer
|
15
|
+
attr_accessor :silence_deprecations, :raise_deprecations
|
16
|
+
|
17
|
+
def exists_returns_integer=(value)
|
18
|
+
unless value
|
19
|
+
deprecate!(
|
20
|
+
"`Redis#exists(key)` will return an Integer by default in redis-rb 4.3. The option to explicitly " \
|
21
|
+
"disable this behaviour via `Redis.exists_returns_integer` will be removed in 5.0. You should use " \
|
22
|
+
"`exists?` instead."
|
23
|
+
)
|
1912
24
|
end
|
1913
|
-
end
|
1914
|
-
end
|
1915
|
-
|
1916
|
-
# Delete one or more hash fields.
|
1917
|
-
#
|
1918
|
-
# @param [String] key
|
1919
|
-
# @param [String, Array<String>] field
|
1920
|
-
# @return [Fixnum] the number of fields that were removed from the hash
|
1921
|
-
def hdel(key, field)
|
1922
|
-
synchronize do |client|
|
1923
|
-
client.call([:hdel, key, field])
|
1924
|
-
end
|
1925
|
-
end
|
1926
25
|
|
1927
|
-
|
1928
|
-
#
|
1929
|
-
# @param [String] key
|
1930
|
-
# @param [String] field
|
1931
|
-
# @return [Boolean] whether or not the field exists in the hash
|
1932
|
-
def hexists(key, field)
|
1933
|
-
synchronize do |client|
|
1934
|
-
client.call([:hexists, key, field], &_boolify)
|
26
|
+
@exists_returns_integer = value
|
1935
27
|
end
|
1936
|
-
end
|
1937
28
|
|
1938
|
-
|
1939
|
-
|
1940
|
-
|
1941
|
-
|
1942
|
-
|
1943
|
-
|
1944
|
-
|
1945
|
-
|
1946
|
-
client.call([:hincrby, key, field, increment])
|
29
|
+
def deprecate!(message)
|
30
|
+
unless silence_deprecations
|
31
|
+
if raise_deprecations
|
32
|
+
raise Deprecated, message
|
33
|
+
else
|
34
|
+
::Kernel.warn(message)
|
35
|
+
end
|
36
|
+
end
|
1947
37
|
end
|
1948
|
-
end
|
1949
38
|
|
1950
|
-
|
1951
|
-
|
1952
|
-
|
1953
|
-
# @param [String] field
|
1954
|
-
# @param [Float] increment
|
1955
|
-
# @return [Float] value of the field after incrementing it
|
1956
|
-
def hincrbyfloat(key, field, increment)
|
1957
|
-
synchronize do |client|
|
1958
|
-
client.call([:hincrbyfloat, key, field, increment], &_floatify)
|
39
|
+
def current
|
40
|
+
deprecate!("`Redis.current=` is deprecated and will be removed in 5.0. (called from: #{caller(1, 1).first})")
|
41
|
+
@current ||= Redis.new
|
1959
42
|
end
|
1960
|
-
end
|
1961
43
|
|
1962
|
-
|
1963
|
-
|
1964
|
-
|
1965
|
-
# @return [Array<String>]
|
1966
|
-
def hkeys(key)
|
1967
|
-
synchronize do |client|
|
1968
|
-
client.call([:hkeys, key])
|
44
|
+
def current=(redis)
|
45
|
+
deprecate!("`Redis.current=` is deprecated and will be removed in 5.0. (called from: #{caller(1, 1).first})")
|
46
|
+
@current = redis
|
1969
47
|
end
|
1970
48
|
end
|
1971
49
|
|
1972
|
-
|
1973
|
-
#
|
1974
|
-
# @param [String] key
|
1975
|
-
# @return [Array<String>]
|
1976
|
-
def hvals(key)
|
1977
|
-
synchronize do |client|
|
1978
|
-
client.call([:hvals, key])
|
1979
|
-
end
|
1980
|
-
end
|
50
|
+
include Commands
|
1981
51
|
|
1982
|
-
#
|
52
|
+
# Create a new client instance
|
1983
53
|
#
|
1984
|
-
# @param [
|
1985
|
-
# @
|
1986
|
-
|
1987
|
-
|
1988
|
-
|
1989
|
-
|
54
|
+
# @param [Hash] options
|
55
|
+
# @option options [String] :url (value of the environment variable REDIS_URL) a Redis URL, for a TCP connection:
|
56
|
+
# `redis://:[password]@[hostname]:[port]/[db]` (password, port and database are optional), for a unix socket
|
57
|
+
# connection: `unix://[path to Redis socket]`. This overrides all other options.
|
58
|
+
# @option options [String] :host ("127.0.0.1") server hostname
|
59
|
+
# @option options [Integer] :port (6379) server port
|
60
|
+
# @option options [String] :path path to server socket (overrides host and port)
|
61
|
+
# @option options [Float] :timeout (5.0) timeout in seconds
|
62
|
+
# @option options [Float] :connect_timeout (same as timeout) timeout for initial connect in seconds
|
63
|
+
# @option options [String] :username Username to authenticate against server
|
64
|
+
# @option options [String] :password Password to authenticate against server
|
65
|
+
# @option options [Integer] :db (0) Database to select after initial connect
|
66
|
+
# @option options [Symbol] :driver Driver to use, currently supported: `:ruby`, `:hiredis`, `:synchrony`
|
67
|
+
# @option options [String] :id ID for the client connection, assigns name to current connection by sending
|
68
|
+
# `CLIENT SETNAME`
|
69
|
+
# @option options [Hash, Integer] :tcp_keepalive Keepalive values, if Integer `intvl` and `probe` are calculated
|
70
|
+
# based on the value, if Hash `time`, `intvl` and `probes` can be specified as a Integer
|
71
|
+
# @option options [Integer] :reconnect_attempts Number of attempts trying to connect
|
72
|
+
# @option options [Boolean] :inherit_socket (false) Whether to use socket in forked process or not
|
73
|
+
# @option options [Array] :sentinels List of sentinels to contact
|
74
|
+
# @option options [Symbol] :role (:master) Role to fetch via Sentinel, either `:master` or `:slave`
|
75
|
+
# @option options [Array<String, Hash{Symbol => String, Integer}>] :cluster List of cluster nodes to contact
|
76
|
+
# @option options [Boolean] :replica Whether to use readonly replica nodes in Redis Cluster or not
|
77
|
+
# @option options [Class] :connector Class of custom connector
|
78
|
+
#
|
79
|
+
# @return [Redis] a new client instance
|
80
|
+
def initialize(options = {})
|
81
|
+
@options = options.dup
|
82
|
+
@cluster_mode = options.key?(:cluster)
|
83
|
+
client = @cluster_mode ? Cluster : Client
|
84
|
+
@original_client = @client = client.new(options)
|
85
|
+
@queue = Hash.new { |h, k| h[k] = [] }
|
86
|
+
@monitor = Monitor.new
|
1990
87
|
end
|
1991
88
|
|
1992
|
-
#
|
1993
|
-
def
|
89
|
+
# Run code with the client reconnecting
|
90
|
+
def with_reconnect(val = true, &blk)
|
1994
91
|
synchronize do |client|
|
1995
|
-
client.
|
92
|
+
client.with_reconnect(val, &blk)
|
1996
93
|
end
|
1997
94
|
end
|
1998
95
|
|
1999
|
-
|
2000
|
-
|
2001
|
-
|
2002
|
-
end
|
96
|
+
# Run code without the client reconnecting
|
97
|
+
def without_reconnect(&blk)
|
98
|
+
with_reconnect(false, &blk)
|
2003
99
|
end
|
2004
100
|
|
2005
|
-
#
|
2006
|
-
def
|
2007
|
-
|
2008
|
-
_subscription(:subscribe, channels, block)
|
2009
|
-
end
|
101
|
+
# Test whether or not the client is connected
|
102
|
+
def connected?
|
103
|
+
@original_client.connected?
|
2010
104
|
end
|
2011
105
|
|
2012
|
-
#
|
2013
|
-
def
|
2014
|
-
|
2015
|
-
raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
|
2016
|
-
client.unsubscribe(*channels)
|
2017
|
-
end
|
106
|
+
# Disconnect the client as quickly and silently as possible.
|
107
|
+
def close
|
108
|
+
@original_client.disconnect
|
2018
109
|
end
|
110
|
+
alias disconnect! close
|
2019
111
|
|
2020
|
-
#
|
2021
|
-
|
2022
|
-
|
2023
|
-
|
2024
|
-
|
2025
|
-
|
112
|
+
# @deprecated Queues a command for pipelining.
|
113
|
+
#
|
114
|
+
# Commands in the queue are executed with the Redis#commit method.
|
115
|
+
#
|
116
|
+
# See http://redis.io/topics/pipelining for more details.
|
117
|
+
#
|
118
|
+
def queue(*command)
|
119
|
+
::Redis.deprecate!(
|
120
|
+
"Redis#queue is deprecated and will be removed in Redis 5.0.0. Use Redis#pipelined instead." \
|
121
|
+
"(called from: #{caller(1, 1).first})"
|
122
|
+
)
|
2026
123
|
|
2027
|
-
|
2028
|
-
|
2029
|
-
synchronize do |client|
|
2030
|
-
raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
|
2031
|
-
client.punsubscribe(*channels)
|
124
|
+
synchronize do
|
125
|
+
@queue[Thread.current.object_id] << command
|
2032
126
|
end
|
2033
127
|
end
|
2034
128
|
|
2035
|
-
#
|
2036
|
-
#
|
2037
|
-
# Using a block is optional, but is necessary for thread-safety.
|
2038
|
-
#
|
2039
|
-
# An `#unwatch` is automatically issued if an exception is raised within the
|
2040
|
-
# block that is a subclass of StandardError and is not a ConnectionError.
|
2041
|
-
#
|
2042
|
-
# @example With a block
|
2043
|
-
# redis.watch("key") do
|
2044
|
-
# if redis.get("key") == "some value"
|
2045
|
-
# redis.multi do |multi|
|
2046
|
-
# multi.set("key", "other value")
|
2047
|
-
# multi.incr("counter")
|
2048
|
-
# end
|
2049
|
-
# else
|
2050
|
-
# redis.unwatch
|
2051
|
-
# end
|
2052
|
-
# end
|
2053
|
-
# # => ["OK", 6]
|
2054
|
-
#
|
2055
|
-
# @example Without a block
|
2056
|
-
# redis.watch("key")
|
2057
|
-
# # => "OK"
|
129
|
+
# @deprecated Sends all commands in the queue.
|
2058
130
|
#
|
2059
|
-
#
|
2060
|
-
# @return [Object] if using a block, returns the return value of the block
|
2061
|
-
# @return [String] if not using a block, returns `OK`
|
131
|
+
# See http://redis.io/topics/pipelining for more details.
|
2062
132
|
#
|
2063
|
-
|
2064
|
-
|
2065
|
-
|
2066
|
-
|
2067
|
-
|
133
|
+
def commit
|
134
|
+
::Redis.deprecate!(
|
135
|
+
"Redis#commit is deprecated and will be removed in Redis 5.0.0. Use Redis#pipelined instead. " \
|
136
|
+
"(called from: #{Kernel.caller(1, 1).first})"
|
137
|
+
)
|
2068
138
|
|
2069
|
-
|
2070
|
-
|
2071
|
-
|
2072
|
-
|
2073
|
-
|
2074
|
-
rescue StandardError
|
2075
|
-
unwatch
|
2076
|
-
raise
|
139
|
+
synchronize do |client|
|
140
|
+
begin
|
141
|
+
pipeline = Pipeline.new(client)
|
142
|
+
@queue[Thread.current.object_id].each do |command|
|
143
|
+
pipeline.call(command)
|
2077
144
|
end
|
2078
|
-
|
2079
|
-
|
145
|
+
|
146
|
+
client.call_pipelined(pipeline)
|
147
|
+
ensure
|
148
|
+
@queue.delete(Thread.current.object_id)
|
2080
149
|
end
|
2081
150
|
end
|
2082
151
|
end
|
2083
152
|
|
2084
|
-
|
2085
|
-
|
2086
|
-
# @return [String] `OK`
|
2087
|
-
#
|
2088
|
-
# @see #watch
|
2089
|
-
# @see #multi
|
2090
|
-
def unwatch
|
2091
|
-
synchronize do |client|
|
2092
|
-
client.call([:unwatch])
|
2093
|
-
end
|
153
|
+
def _client
|
154
|
+
@client
|
2094
155
|
end
|
2095
156
|
|
2096
|
-
def pipelined
|
2097
|
-
|
157
|
+
def pipelined(&block)
|
158
|
+
deprecation_displayed = false
|
159
|
+
if block&.arity == 0
|
160
|
+
Pipeline.deprecation_warning("pipelined", Kernel.caller_locations(1, 5))
|
161
|
+
deprecation_displayed = true
|
162
|
+
end
|
163
|
+
|
164
|
+
synchronize do |prior_client|
|
2098
165
|
begin
|
2099
|
-
|
2100
|
-
|
2101
|
-
|
166
|
+
pipeline = Pipeline.new(prior_client)
|
167
|
+
@client = deprecation_displayed ? pipeline : DeprecatedPipeline.new(pipeline)
|
168
|
+
pipelined_connection = PipelinedConnection.new(pipeline)
|
169
|
+
yield pipelined_connection
|
170
|
+
prior_client.call_pipeline(pipeline)
|
2102
171
|
ensure
|
2103
|
-
@client =
|
172
|
+
@client = prior_client
|
2104
173
|
end
|
2105
174
|
end
|
2106
175
|
end
|
@@ -2135,372 +204,27 @@ class Redis
|
|
2135
204
|
#
|
2136
205
|
# @see #watch
|
2137
206
|
# @see #unwatch
|
2138
|
-
def multi
|
2139
|
-
|
2140
|
-
|
2141
|
-
|
2142
|
-
|
2143
|
-
|
2144
|
-
pipeline = Pipeline::Multi.new
|
2145
|
-
original, @client = @client, pipeline
|
2146
|
-
yield(self)
|
2147
|
-
original.call_pipeline(pipeline)
|
2148
|
-
ensure
|
2149
|
-
@client = original
|
2150
|
-
end
|
207
|
+
def multi(&block)
|
208
|
+
if block_given?
|
209
|
+
deprecation_displayed = false
|
210
|
+
if block&.arity == 0
|
211
|
+
Pipeline.deprecation_warning("multi", Kernel.caller_locations(1, 5))
|
212
|
+
deprecation_displayed = true
|
2151
213
|
end
|
2152
|
-
end
|
2153
|
-
end
|
2154
|
-
|
2155
|
-
# Execute all commands issued after MULTI.
|
2156
|
-
#
|
2157
|
-
# Only call this method when `#multi` was called **without** a block.
|
2158
|
-
#
|
2159
|
-
# @return [nil, Array<...>]
|
2160
|
-
# - when commands were not executed, `nil`
|
2161
|
-
# - when commands were executed, an array with their replies
|
2162
|
-
#
|
2163
|
-
# @see #multi
|
2164
|
-
# @see #discard
|
2165
|
-
def exec
|
2166
|
-
synchronize do |client|
|
2167
|
-
client.call([:exec])
|
2168
|
-
end
|
2169
|
-
end
|
2170
|
-
|
2171
|
-
# Discard all commands issued after MULTI.
|
2172
|
-
#
|
2173
|
-
# Only call this method when `#multi` was called **without** a block.
|
2174
|
-
#
|
2175
|
-
# @return `"OK"`
|
2176
|
-
#
|
2177
|
-
# @see #multi
|
2178
|
-
# @see #exec
|
2179
|
-
def discard
|
2180
|
-
synchronize do |client|
|
2181
|
-
client.call([:discard])
|
2182
|
-
end
|
2183
|
-
end
|
2184
|
-
|
2185
|
-
# Control remote script registry.
|
2186
|
-
#
|
2187
|
-
# @example Load a script
|
2188
|
-
# sha = redis.script(:load, "return 1")
|
2189
|
-
# # => <sha of this script>
|
2190
|
-
# @example Check if a script exists
|
2191
|
-
# redis.script(:exists, sha)
|
2192
|
-
# # => true
|
2193
|
-
# @example Check if multiple scripts exist
|
2194
|
-
# redis.script(:exists, [sha, other_sha])
|
2195
|
-
# # => [true, false]
|
2196
|
-
# @example Flush the script registry
|
2197
|
-
# redis.script(:flush)
|
2198
|
-
# # => "OK"
|
2199
|
-
# @example Kill a running script
|
2200
|
-
# redis.script(:kill)
|
2201
|
-
# # => "OK"
|
2202
|
-
#
|
2203
|
-
# @param [String] subcommand e.g. `exists`, `flush`, `load`, `kill`
|
2204
|
-
# @param [Array<String>] args depends on subcommand
|
2205
|
-
# @return [String, Boolean, Array<Boolean>, ...] depends on subcommand
|
2206
|
-
#
|
2207
|
-
# @see #eval
|
2208
|
-
# @see #evalsha
|
2209
|
-
def script(subcommand, *args)
|
2210
|
-
subcommand = subcommand.to_s.downcase
|
2211
214
|
|
2212
|
-
|
2213
|
-
|
2214
|
-
|
2215
|
-
|
2216
|
-
|
2217
|
-
|
2218
|
-
|
2219
|
-
|
2220
|
-
|
2221
|
-
else
|
2222
|
-
reply.first
|
2223
|
-
end
|
215
|
+
synchronize do |prior_client|
|
216
|
+
begin
|
217
|
+
pipeline = Pipeline::Multi.new(prior_client)
|
218
|
+
@client = deprecation_displayed ? pipeline : DeprecatedMulti.new(pipeline)
|
219
|
+
pipelined_connection = PipelinedConnection.new(pipeline)
|
220
|
+
yield pipelined_connection
|
221
|
+
prior_client.call_pipeline(pipeline)
|
222
|
+
ensure
|
223
|
+
@client = prior_client
|
2224
224
|
end
|
2225
225
|
end
|
2226
226
|
else
|
2227
|
-
|
2228
|
-
client.call([:script, subcommand] + args)
|
2229
|
-
end
|
2230
|
-
end
|
2231
|
-
end
|
2232
|
-
|
2233
|
-
def _eval(cmd, args)
|
2234
|
-
script = args.shift
|
2235
|
-
options = args.pop if args.last.is_a?(Hash)
|
2236
|
-
options ||= {}
|
2237
|
-
|
2238
|
-
keys = args.shift || options[:keys] || []
|
2239
|
-
argv = args.shift || options[:argv] || []
|
2240
|
-
|
2241
|
-
synchronize do |client|
|
2242
|
-
client.call([cmd, script, keys.length] + keys + argv)
|
2243
|
-
end
|
2244
|
-
end
|
2245
|
-
|
2246
|
-
# Evaluate Lua script.
|
2247
|
-
#
|
2248
|
-
# @example EVAL without KEYS nor ARGV
|
2249
|
-
# redis.eval("return 1")
|
2250
|
-
# # => 1
|
2251
|
-
# @example EVAL with KEYS and ARGV as array arguments
|
2252
|
-
# redis.eval("return { KEYS, ARGV }", ["k1", "k2"], ["a1", "a2"])
|
2253
|
-
# # => [["k1", "k2"], ["a1", "a2"]]
|
2254
|
-
# @example EVAL with KEYS and ARGV in a hash argument
|
2255
|
-
# redis.eval("return { KEYS, ARGV }", :keys => ["k1", "k2"], :argv => ["a1", "a2"])
|
2256
|
-
# # => [["k1", "k2"], ["a1", "a2"]]
|
2257
|
-
#
|
2258
|
-
# @param [Array<String>] keys optional array with keys to pass to the script
|
2259
|
-
# @param [Array<String>] argv optional array with arguments to pass to the script
|
2260
|
-
# @param [Hash] options
|
2261
|
-
# - `:keys => Array<String>`: optional array with keys to pass to the script
|
2262
|
-
# - `:argv => Array<String>`: optional array with arguments to pass to the script
|
2263
|
-
# @return depends on the script
|
2264
|
-
#
|
2265
|
-
# @see #script
|
2266
|
-
# @see #evalsha
|
2267
|
-
def eval(*args)
|
2268
|
-
_eval(:eval, args)
|
2269
|
-
end
|
2270
|
-
|
2271
|
-
# Evaluate Lua script by its SHA.
|
2272
|
-
#
|
2273
|
-
# @example EVALSHA without KEYS nor ARGV
|
2274
|
-
# redis.evalsha(sha)
|
2275
|
-
# # => <depends on script>
|
2276
|
-
# @example EVALSHA with KEYS and ARGV as array arguments
|
2277
|
-
# redis.evalsha(sha, ["k1", "k2"], ["a1", "a2"])
|
2278
|
-
# # => <depends on script>
|
2279
|
-
# @example EVALSHA with KEYS and ARGV in a hash argument
|
2280
|
-
# redis.evalsha(sha, :keys => ["k1", "k2"], :argv => ["a1", "a2"])
|
2281
|
-
# # => <depends on script>
|
2282
|
-
#
|
2283
|
-
# @param [Array<String>] keys optional array with keys to pass to the script
|
2284
|
-
# @param [Array<String>] argv optional array with arguments to pass to the script
|
2285
|
-
# @param [Hash] options
|
2286
|
-
# - `:keys => Array<String>`: optional array with keys to pass to the script
|
2287
|
-
# - `:argv => Array<String>`: optional array with arguments to pass to the script
|
2288
|
-
# @return depends on the script
|
2289
|
-
#
|
2290
|
-
# @see #script
|
2291
|
-
# @see #eval
|
2292
|
-
def evalsha(*args)
|
2293
|
-
_eval(:evalsha, args)
|
2294
|
-
end
|
2295
|
-
|
2296
|
-
def _scan(command, cursor, args, options = {}, &block)
|
2297
|
-
# SSCAN/ZSCAN/HSCAN already prepend the key to +args+.
|
2298
|
-
|
2299
|
-
args << cursor
|
2300
|
-
|
2301
|
-
if match = options[:match]
|
2302
|
-
args.concat(["MATCH", match])
|
2303
|
-
end
|
2304
|
-
|
2305
|
-
if count = options[:count]
|
2306
|
-
args.concat(["COUNT", count])
|
2307
|
-
end
|
2308
|
-
|
2309
|
-
synchronize do |client|
|
2310
|
-
client.call([command] + args, &block)
|
2311
|
-
end
|
2312
|
-
end
|
2313
|
-
|
2314
|
-
# Scan the keyspace
|
2315
|
-
#
|
2316
|
-
# @example Retrieve the first batch of keys
|
2317
|
-
# redis.scan(0)
|
2318
|
-
# # => ["4", ["key:21", "key:47", "key:42"]]
|
2319
|
-
# @example Retrieve a batch of keys matching a pattern
|
2320
|
-
# redis.scan(4, :match => "key:1?")
|
2321
|
-
# # => ["92", ["key:13", "key:18"]]
|
2322
|
-
#
|
2323
|
-
# @param [String, Integer] cursor: the cursor of the iteration
|
2324
|
-
# @param [Hash] options
|
2325
|
-
# - `:match => String`: only return keys matching the pattern
|
2326
|
-
# - `:count => Integer`: return count keys at most per iteration
|
2327
|
-
#
|
2328
|
-
# @return [String, Array<String>] the next cursor and all found keys
|
2329
|
-
def scan(cursor, options={})
|
2330
|
-
_scan(:scan, cursor, [], options)
|
2331
|
-
end
|
2332
|
-
|
2333
|
-
# Scan the keyspace
|
2334
|
-
#
|
2335
|
-
# @example Retrieve all of the keys (with possible duplicates)
|
2336
|
-
# redis.scan_each.to_a
|
2337
|
-
# # => ["key:21", "key:47", "key:42"]
|
2338
|
-
# @example Execute block for each key matching a pattern
|
2339
|
-
# redis.scan_each(:match => "key:1?") {|key| puts key}
|
2340
|
-
# # => key:13
|
2341
|
-
# # => key:18
|
2342
|
-
#
|
2343
|
-
# @param [Hash] options
|
2344
|
-
# - `:match => String`: only return keys matching the pattern
|
2345
|
-
# - `:count => Integer`: return count keys at most per iteration
|
2346
|
-
#
|
2347
|
-
# @return [Enumerator] an enumerator for all found keys
|
2348
|
-
def scan_each(options={}, &block)
|
2349
|
-
return to_enum(:scan_each, options) unless block_given?
|
2350
|
-
cursor = 0
|
2351
|
-
loop do
|
2352
|
-
cursor, keys = scan(cursor, options)
|
2353
|
-
keys.each(&block)
|
2354
|
-
break if cursor == "0"
|
2355
|
-
end
|
2356
|
-
end
|
2357
|
-
|
2358
|
-
# Scan a hash
|
2359
|
-
#
|
2360
|
-
# @example Retrieve the first batch of key/value pairs in a hash
|
2361
|
-
# redis.hscan("hash", 0)
|
2362
|
-
#
|
2363
|
-
# @param [String, Integer] cursor: the cursor of the iteration
|
2364
|
-
# @param [Hash] options
|
2365
|
-
# - `:match => String`: only return keys matching the pattern
|
2366
|
-
# - `:count => Integer`: return count keys at most per iteration
|
2367
|
-
#
|
2368
|
-
# @return [String, Array<[String, String]>] the next cursor and all found keys
|
2369
|
-
def hscan(key, cursor, options={})
|
2370
|
-
_scan(:hscan, cursor, [key], options) do |reply|
|
2371
|
-
[reply[0], _pairify(reply[1])]
|
2372
|
-
end
|
2373
|
-
end
|
2374
|
-
|
2375
|
-
# Scan a hash
|
2376
|
-
#
|
2377
|
-
# @example Retrieve all of the key/value pairs in a hash
|
2378
|
-
# redis.hscan_each("hash").to_a
|
2379
|
-
# # => [["key70", "70"], ["key80", "80"]]
|
2380
|
-
#
|
2381
|
-
# @param [Hash] options
|
2382
|
-
# - `:match => String`: only return keys matching the pattern
|
2383
|
-
# - `:count => Integer`: return count keys at most per iteration
|
2384
|
-
#
|
2385
|
-
# @return [Enumerator] an enumerator for all found keys
|
2386
|
-
def hscan_each(key, options={}, &block)
|
2387
|
-
return to_enum(:hscan_each, key, options) unless block_given?
|
2388
|
-
cursor = 0
|
2389
|
-
loop do
|
2390
|
-
cursor, values = hscan(key, cursor, options)
|
2391
|
-
values.each(&block)
|
2392
|
-
break if cursor == "0"
|
2393
|
-
end
|
2394
|
-
end
|
2395
|
-
|
2396
|
-
# Scan a sorted set
|
2397
|
-
#
|
2398
|
-
# @example Retrieve the first batch of key/value pairs in a hash
|
2399
|
-
# redis.zscan("zset", 0)
|
2400
|
-
#
|
2401
|
-
# @param [String, Integer] cursor: the cursor of the iteration
|
2402
|
-
# @param [Hash] options
|
2403
|
-
# - `:match => String`: only return keys matching the pattern
|
2404
|
-
# - `:count => Integer`: return count keys at most per iteration
|
2405
|
-
#
|
2406
|
-
# @return [String, Array<[String, Float]>] the next cursor and all found
|
2407
|
-
# members and scores
|
2408
|
-
def zscan(key, cursor, options={})
|
2409
|
-
_scan(:zscan, cursor, [key], options) do |reply|
|
2410
|
-
[reply[0], _floatify_pairs.call(reply[1])]
|
2411
|
-
end
|
2412
|
-
end
|
2413
|
-
|
2414
|
-
# Scan a sorted set
|
2415
|
-
#
|
2416
|
-
# @example Retrieve all of the members/scores in a sorted set
|
2417
|
-
# redis.zscan_each("zset").to_a
|
2418
|
-
# # => [["key70", "70"], ["key80", "80"]]
|
2419
|
-
#
|
2420
|
-
# @param [Hash] options
|
2421
|
-
# - `:match => String`: only return keys matching the pattern
|
2422
|
-
# - `:count => Integer`: return count keys at most per iteration
|
2423
|
-
#
|
2424
|
-
# @return [Enumerator] an enumerator for all found scores and members
|
2425
|
-
def zscan_each(key, options={}, &block)
|
2426
|
-
return to_enum(:zscan_each, key, options) unless block_given?
|
2427
|
-
cursor = 0
|
2428
|
-
loop do
|
2429
|
-
cursor, values = zscan(key, cursor, options)
|
2430
|
-
values.each(&block)
|
2431
|
-
break if cursor == "0"
|
2432
|
-
end
|
2433
|
-
end
|
2434
|
-
|
2435
|
-
# Scan a set
|
2436
|
-
#
|
2437
|
-
# @example Retrieve the first batch of keys in a set
|
2438
|
-
# redis.sscan("set", 0)
|
2439
|
-
#
|
2440
|
-
# @param [String, Integer] cursor: the cursor of the iteration
|
2441
|
-
# @param [Hash] options
|
2442
|
-
# - `:match => String`: only return keys matching the pattern
|
2443
|
-
# - `:count => Integer`: return count keys at most per iteration
|
2444
|
-
#
|
2445
|
-
# @return [String, Array<String>] the next cursor and all found members
|
2446
|
-
def sscan(key, cursor, options={})
|
2447
|
-
_scan(:sscan, cursor, [key], options)
|
2448
|
-
end
|
2449
|
-
|
2450
|
-
# Scan a set
|
2451
|
-
#
|
2452
|
-
# @example Retrieve all of the keys in a set
|
2453
|
-
# redis.sscan("set").to_a
|
2454
|
-
# # => ["key1", "key2", "key3"]
|
2455
|
-
#
|
2456
|
-
# @param [Hash] options
|
2457
|
-
# - `:match => String`: only return keys matching the pattern
|
2458
|
-
# - `:count => Integer`: return count keys at most per iteration
|
2459
|
-
#
|
2460
|
-
# @return [Enumerator] an enumerator for all keys in the set
|
2461
|
-
def sscan_each(key, options={}, &block)
|
2462
|
-
return to_enum(:sscan_each, key, options) unless block_given?
|
2463
|
-
cursor = 0
|
2464
|
-
loop do
|
2465
|
-
cursor, keys = sscan(key, cursor, options)
|
2466
|
-
keys.each(&block)
|
2467
|
-
break if cursor == "0"
|
2468
|
-
end
|
2469
|
-
end
|
2470
|
-
|
2471
|
-
# Add one or more members to a HyperLogLog structure.
|
2472
|
-
#
|
2473
|
-
# @param [String] key
|
2474
|
-
# @param [String, Array<String>] member one member, or array of members
|
2475
|
-
# @return [Boolean] true if at least 1 HyperLogLog internal register was altered. false otherwise.
|
2476
|
-
def pfadd(key, member)
|
2477
|
-
synchronize do |client|
|
2478
|
-
client.call([:pfadd, key, member], &_boolify)
|
2479
|
-
end
|
2480
|
-
end
|
2481
|
-
|
2482
|
-
# Get the approximate cardinality of members added to HyperLogLog structure.
|
2483
|
-
#
|
2484
|
-
# If called with multiple keys, returns the approximate cardinality of the
|
2485
|
-
# union of the HyperLogLogs contained in the keys.
|
2486
|
-
#
|
2487
|
-
# @param [String, Array<String>] keys
|
2488
|
-
# @return [Fixnum]
|
2489
|
-
def pfcount(*keys)
|
2490
|
-
synchronize do |client|
|
2491
|
-
client.call([:pfcount] + keys)
|
2492
|
-
end
|
2493
|
-
end
|
2494
|
-
|
2495
|
-
# Merge multiple HyperLogLog values into an unique value that will approximate the cardinality of the union of
|
2496
|
-
# the observed Sets of the source HyperLogLog structures.
|
2497
|
-
#
|
2498
|
-
# @param [String] dest_key destination key
|
2499
|
-
# @param [String, Array<String>] source_key source key, or array of keys
|
2500
|
-
# @return [Boolean]
|
2501
|
-
def pfmerge(dest_key, *source_key)
|
2502
|
-
synchronize do |client|
|
2503
|
-
client.call([:pfmerge, dest_key, *source_key], &_boolify_set)
|
227
|
+
send_command([:multi])
|
2504
228
|
end
|
2505
229
|
end
|
2506
230
|
|
@@ -2516,84 +240,55 @@ class Redis
|
|
2516
240
|
self.class.new(@options)
|
2517
241
|
end
|
2518
242
|
|
2519
|
-
def
|
2520
|
-
|
2521
|
-
client.call([command] + args)
|
2522
|
-
end
|
2523
|
-
end
|
2524
|
-
|
2525
|
-
private
|
2526
|
-
|
2527
|
-
# Commands returning 1 for true and 0 for false may be executed in a pipeline
|
2528
|
-
# where the method call will return nil. Propagate the nil instead of falsely
|
2529
|
-
# returning false.
|
2530
|
-
def _boolify
|
2531
|
-
lambda { |value|
|
2532
|
-
value == 1 if value
|
2533
|
-
}
|
2534
|
-
end
|
2535
|
-
|
2536
|
-
def _boolify_set
|
2537
|
-
lambda { |value|
|
2538
|
-
if value && "OK" == value
|
2539
|
-
true
|
2540
|
-
else
|
2541
|
-
false
|
2542
|
-
end
|
2543
|
-
}
|
2544
|
-
end
|
243
|
+
def connection
|
244
|
+
return @original_client.connection_info if @cluster_mode
|
2545
245
|
|
2546
|
-
|
2547
|
-
|
2548
|
-
|
2549
|
-
|
2550
|
-
|
2551
|
-
|
2552
|
-
hash
|
246
|
+
{
|
247
|
+
host: @original_client.host,
|
248
|
+
port: @original_client.port,
|
249
|
+
db: @original_client.db,
|
250
|
+
id: @original_client.id,
|
251
|
+
location: @original_client.location
|
2553
252
|
}
|
2554
253
|
end
|
2555
254
|
|
2556
|
-
|
2557
|
-
lambda { |str|
|
2558
|
-
return unless str
|
255
|
+
private
|
2559
256
|
|
2560
|
-
|
2561
|
-
|
2562
|
-
else
|
2563
|
-
Float(str)
|
2564
|
-
end
|
2565
|
-
}
|
257
|
+
def synchronize
|
258
|
+
@monitor.synchronize { yield(@client) }
|
2566
259
|
end
|
2567
260
|
|
2568
|
-
def
|
2569
|
-
|
2570
|
-
|
2571
|
-
|
2572
|
-
array.each_slice(2).map do |member, score|
|
2573
|
-
[member, _floatify.call(score)]
|
2574
|
-
end
|
2575
|
-
}
|
261
|
+
def send_command(command, &block)
|
262
|
+
@monitor.synchronize do
|
263
|
+
@client.call(command, &block)
|
264
|
+
end
|
2576
265
|
end
|
2577
266
|
|
2578
|
-
def
|
2579
|
-
|
267
|
+
def send_blocking_command(command, timeout, &block)
|
268
|
+
@monitor.synchronize do
|
269
|
+
@client.call_with_timeout(command, timeout, &block)
|
270
|
+
end
|
2580
271
|
end
|
2581
272
|
|
2582
|
-
def _subscription(method, channels, block)
|
273
|
+
def _subscription(method, timeout, channels, block)
|
2583
274
|
return @client.call([method] + channels) if subscribed?
|
2584
275
|
|
2585
276
|
begin
|
2586
277
|
original, @client = @client, SubscribedClient.new(@client)
|
2587
|
-
|
278
|
+
if timeout > 0
|
279
|
+
@client.send(method, timeout, *channels, &block)
|
280
|
+
else
|
281
|
+
@client.send(method, *channels, &block)
|
282
|
+
end
|
2588
283
|
ensure
|
2589
284
|
@client = original
|
2590
285
|
end
|
2591
286
|
end
|
2592
|
-
|
2593
287
|
end
|
2594
288
|
|
2595
289
|
require "redis/version"
|
2596
290
|
require "redis/connection"
|
2597
291
|
require "redis/client"
|
292
|
+
require "redis/cluster"
|
2598
293
|
require "redis/pipeline"
|
2599
294
|
require "redis/subscribe"
|