redis 1.0.7 → 2.0.0.rc1
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.
- data/README.markdown +8 -0
- data/lib/redis.rb +467 -3
- data/lib/redis/client.rb +145 -464
- data/lib/redis/distributed.rb +388 -67
- data/lib/redis/pipeline.rb +5 -11
- data/lib/redis/subscribe.rb +83 -10
- metadata +11 -9
- data/lib/redis/dist_redis.rb +0 -16
data/README.markdown
CHANGED
@@ -2,6 +2,14 @@
|
|
2
2
|
|
3
3
|
A Ruby client library for the [Redis](http://code.google.com/p/redis) key-value store.
|
4
4
|
|
5
|
+
## A note about versions
|
6
|
+
|
7
|
+
Versions *1.0.x* target all versions of Redis. You have to use this one if you are using Redis < 1.2.
|
8
|
+
|
9
|
+
Version *2.0* is a big refactoring of the previous version and makes little effort to be
|
10
|
+
backwards-compatible when it shouldn't. It does not support Redis' original protocol, favoring the
|
11
|
+
new, binary-safe one. You should be using this version if you're running Redis 1.2+.
|
12
|
+
|
5
13
|
## Information about Redis
|
6
14
|
|
7
15
|
Redis is a key-value store with some interesting features:
|
data/lib/redis.rb
CHANGED
@@ -1,15 +1,479 @@
|
|
1
1
|
require 'socket'
|
2
2
|
|
3
3
|
class Redis
|
4
|
-
VERSION = "
|
4
|
+
VERSION = "2.0.0.rc1"
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
class ProtocolError < RuntimeError
|
7
|
+
def initialize(reply_type)
|
8
|
+
super("Protocol error, got '#{reply_type}' as initial reply byte")
|
9
|
+
end
|
8
10
|
end
|
9
11
|
|
10
12
|
def self.deprecate(message, trace = caller[0])
|
11
13
|
$stderr.puts "\n#{message} (in #{trace})"
|
12
14
|
end
|
15
|
+
|
16
|
+
attr :client
|
17
|
+
|
18
|
+
def self.connect(options = {})
|
19
|
+
require "uri"
|
20
|
+
|
21
|
+
url = URI(options.delete(:url) || ENV["REDIS_URL"] || "redis://127.0.0.1:6379/0")
|
22
|
+
|
23
|
+
options[:host] = url.host
|
24
|
+
options[:port] = url.port
|
25
|
+
options[:password] = url.password
|
26
|
+
options[:db] = url.path[1..-1].to_i
|
27
|
+
|
28
|
+
new(options)
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(options = {})
|
32
|
+
@client = Client.new(options)
|
33
|
+
end
|
34
|
+
|
35
|
+
def select(db)
|
36
|
+
@client.db = db
|
37
|
+
@client.call(:select, db)
|
38
|
+
end
|
39
|
+
|
40
|
+
def info
|
41
|
+
Hash[*@client.call(:info).split(/:|\r\n/)]
|
42
|
+
end
|
43
|
+
|
44
|
+
def flushdb
|
45
|
+
@client.call(:flushdb)
|
46
|
+
end
|
47
|
+
|
48
|
+
def save
|
49
|
+
@client.call(:save)
|
50
|
+
end
|
51
|
+
|
52
|
+
def bgsave
|
53
|
+
@client.call(:bgsave)
|
54
|
+
end
|
55
|
+
|
56
|
+
def get(key)
|
57
|
+
@client.call(:get, key)
|
58
|
+
end
|
59
|
+
|
60
|
+
def getset(key, value)
|
61
|
+
@client.call(:getset, key, value)
|
62
|
+
end
|
63
|
+
|
64
|
+
def mget(*keys)
|
65
|
+
@client.call(:mget, *keys)
|
66
|
+
end
|
67
|
+
|
68
|
+
def hgetall(key)
|
69
|
+
Hash[*@client.call(:hgetall, key)]
|
70
|
+
end
|
71
|
+
|
72
|
+
def hget(key, field)
|
73
|
+
@client.call(:hget, key, field)
|
74
|
+
end
|
75
|
+
|
76
|
+
def hdel(key, field)
|
77
|
+
@client.call(:hdel, key, field)
|
78
|
+
end
|
79
|
+
|
80
|
+
def hkeys(key)
|
81
|
+
@client.call(:hkeys, key)
|
82
|
+
end
|
83
|
+
|
84
|
+
def keys(pattern = "*")
|
85
|
+
@client.call(:keys, pattern)
|
86
|
+
end
|
87
|
+
|
88
|
+
def randomkey
|
89
|
+
@client.call(:randomkey)
|
90
|
+
end
|
91
|
+
|
92
|
+
def echo(value)
|
93
|
+
@client.call(:echo, value)
|
94
|
+
end
|
95
|
+
|
96
|
+
def ping
|
97
|
+
@client.call(:ping)
|
98
|
+
end
|
99
|
+
|
100
|
+
def lastsave
|
101
|
+
@client.call(:lastsave)
|
102
|
+
end
|
103
|
+
|
104
|
+
def dbsize
|
105
|
+
@client.call(:dbsize)
|
106
|
+
end
|
107
|
+
|
108
|
+
def exists(key)
|
109
|
+
_bool @client.call(:exists, key)
|
110
|
+
end
|
111
|
+
|
112
|
+
def llen(key)
|
113
|
+
@client.call(:llen, key)
|
114
|
+
end
|
115
|
+
|
116
|
+
def lrange(key, start, stop)
|
117
|
+
@client.call(:lrange, key, start, stop)
|
118
|
+
end
|
119
|
+
|
120
|
+
def ltrim(key, start, stop)
|
121
|
+
@client.call(:ltrim, key, start, stop)
|
122
|
+
end
|
123
|
+
|
124
|
+
def lindex(key, index)
|
125
|
+
@client.call(:lindex, key, index)
|
126
|
+
end
|
127
|
+
|
128
|
+
def lset(key, index, value)
|
129
|
+
@client.call(:lset, key, index, value)
|
130
|
+
end
|
131
|
+
|
132
|
+
def lrem(key, count, value)
|
133
|
+
@client.call(:lrem, key, count, value)
|
134
|
+
end
|
135
|
+
|
136
|
+
def rpush(key, value)
|
137
|
+
@client.call(:rpush, key, value)
|
138
|
+
end
|
139
|
+
|
140
|
+
def lpush(key, value)
|
141
|
+
@client.call(:lpush, key, value)
|
142
|
+
end
|
143
|
+
|
144
|
+
def rpop(key)
|
145
|
+
@client.call(:rpop, key)
|
146
|
+
end
|
147
|
+
|
148
|
+
def blpop(key, timeout)
|
149
|
+
@client.call_blocking(:blpop, key, timeout)
|
150
|
+
end
|
151
|
+
|
152
|
+
def brpop(key, timeout)
|
153
|
+
@client.call_blocking(:brpop, key, timeout)
|
154
|
+
end
|
155
|
+
|
156
|
+
def rpoplpush(source, destination)
|
157
|
+
@client.call(:rpoplpush, source, destination)
|
158
|
+
end
|
159
|
+
|
160
|
+
def lpop(key)
|
161
|
+
@client.call(:lpop, key)
|
162
|
+
end
|
163
|
+
|
164
|
+
def smembers(key)
|
165
|
+
@client.call(:smembers, key)
|
166
|
+
end
|
167
|
+
|
168
|
+
def sismember(key, member)
|
169
|
+
_bool @client.call(:sismember, key, member)
|
170
|
+
end
|
171
|
+
|
172
|
+
def sadd(key, value)
|
173
|
+
_bool @client.call(:sadd, key, value)
|
174
|
+
end
|
175
|
+
|
176
|
+
def srem(key, value)
|
177
|
+
_bool @client.call(:srem, key, value)
|
178
|
+
end
|
179
|
+
|
180
|
+
def smove(source, destination, member)
|
181
|
+
_bool @client.call(:smove, source, destination, member)
|
182
|
+
end
|
183
|
+
|
184
|
+
def spop(key)
|
185
|
+
@client.call(:spop, key)
|
186
|
+
end
|
187
|
+
|
188
|
+
def scard(key)
|
189
|
+
@client.call(:scard, key)
|
190
|
+
end
|
191
|
+
|
192
|
+
def sinter(*keys)
|
193
|
+
@client.call(:sinter, *keys)
|
194
|
+
end
|
195
|
+
|
196
|
+
def sinterstore(destination, *keys)
|
197
|
+
@client.call(:sinterstore, destination, *keys)
|
198
|
+
end
|
199
|
+
|
200
|
+
def sunion(*keys)
|
201
|
+
@client.call(:sunion, *keys)
|
202
|
+
end
|
203
|
+
|
204
|
+
def sunionstore(destination, *keys)
|
205
|
+
@client.call(:sunionstore, destination, *keys)
|
206
|
+
end
|
207
|
+
|
208
|
+
def sdiff(*keys)
|
209
|
+
@client.call(:sdiff, *keys)
|
210
|
+
end
|
211
|
+
|
212
|
+
def sdiffstore(destination, *keys)
|
213
|
+
@client.call(:sdiffstore, destination, *keys)
|
214
|
+
end
|
215
|
+
|
216
|
+
def srandmember(key)
|
217
|
+
@client.call(:srandmember, key)
|
218
|
+
end
|
219
|
+
|
220
|
+
def zadd(key, score, member)
|
221
|
+
_bool @client.call(:zadd, key, score, member)
|
222
|
+
end
|
223
|
+
|
224
|
+
def zincrby(key, increment, member)
|
225
|
+
@client.call(:zincrby, key, increment, member)
|
226
|
+
end
|
227
|
+
|
228
|
+
def zcard(key)
|
229
|
+
@client.call(:zcard, key)
|
230
|
+
end
|
231
|
+
|
232
|
+
def zrange(key, start, stop, with_scores = false)
|
233
|
+
if with_scores
|
234
|
+
@client.call(:zrange, key, start, stop, "WITHSCORES")
|
235
|
+
else
|
236
|
+
@client.call(:zrange, key, start, stop)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def zrangebyscore(key, min, max)
|
241
|
+
@client.call(:zrangebyscore, key, min, max)
|
242
|
+
end
|
243
|
+
|
244
|
+
def zrevrange(key, start, stop, with_scores = false)
|
245
|
+
if with_scores
|
246
|
+
@client.call(:zrevrange, key, start, stop, "WITHSCORES")
|
247
|
+
else
|
248
|
+
@client.call(:zrevrange, key, start, stop)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def zscore(key, member)
|
253
|
+
@client.call(:zscore, key, member)
|
254
|
+
end
|
255
|
+
|
256
|
+
def zrem(key, member)
|
257
|
+
_bool @client.call(:zrem, key, member)
|
258
|
+
end
|
259
|
+
|
260
|
+
def move(key, db)
|
261
|
+
_bool @client.call(:move, key, db)
|
262
|
+
end
|
263
|
+
|
264
|
+
def setnx(key, value)
|
265
|
+
_bool @client.call(:setnx, key, value)
|
266
|
+
end
|
267
|
+
|
268
|
+
def del(*keys)
|
269
|
+
_bool @client.call(:del, *keys)
|
270
|
+
end
|
271
|
+
|
272
|
+
def rename(old_name, new_name)
|
273
|
+
@client.call(:rename, old_name, new_name)
|
274
|
+
end
|
275
|
+
|
276
|
+
def renamenx(old_name, new_name)
|
277
|
+
_bool @client.call(:renamenx, old_name, new_name)
|
278
|
+
end
|
279
|
+
|
280
|
+
def expire(key, seconds)
|
281
|
+
_bool @client.call(:expire, key, seconds)
|
282
|
+
end
|
283
|
+
|
284
|
+
def ttl(key)
|
285
|
+
@client.call(:ttl, key)
|
286
|
+
end
|
287
|
+
|
288
|
+
def expireat(key, unix_time)
|
289
|
+
_bool @client.call(:expireat, key, unix_time)
|
290
|
+
end
|
291
|
+
|
292
|
+
def hset(key, field, value)
|
293
|
+
_bool @client.call(:hset, key, field, value)
|
294
|
+
end
|
295
|
+
|
296
|
+
def hmset(key, *attrs)
|
297
|
+
@client.call(:hmset, key, *attrs)
|
298
|
+
end
|
299
|
+
|
300
|
+
def hlen(key)
|
301
|
+
@client.call(:hlen, key)
|
302
|
+
end
|
303
|
+
|
304
|
+
def hvals(key)
|
305
|
+
@client.call(:hvals, key)
|
306
|
+
end
|
307
|
+
|
308
|
+
def discard
|
309
|
+
@client.call(:discard)
|
310
|
+
end
|
311
|
+
|
312
|
+
def hexists(key, field)
|
313
|
+
_bool @client.call(:hexists, key, field)
|
314
|
+
end
|
315
|
+
|
316
|
+
def monitor
|
317
|
+
raise NotImplementedError
|
318
|
+
end
|
319
|
+
|
320
|
+
def [](key)
|
321
|
+
get(key)
|
322
|
+
end
|
323
|
+
|
324
|
+
def []=(key,value)
|
325
|
+
set(key, value)
|
326
|
+
end
|
327
|
+
|
328
|
+
def set(key, value)
|
329
|
+
@client.call(:set, key, value)
|
330
|
+
end
|
331
|
+
|
332
|
+
def setex(key, ttl, value)
|
333
|
+
@client.call(:setex, key, ttl, value)
|
334
|
+
end
|
335
|
+
|
336
|
+
def mset(*args)
|
337
|
+
@client.call(:mset, *args)
|
338
|
+
end
|
339
|
+
|
340
|
+
def mapped_mset(hash)
|
341
|
+
mset(*hash.to_a.flatten)
|
342
|
+
end
|
343
|
+
|
344
|
+
def msetnx(*args)
|
345
|
+
@client.call(:msetnx, *args)
|
346
|
+
end
|
347
|
+
|
348
|
+
def mapped_msetnx(hash)
|
349
|
+
msetnx(*hash.to_a.flatten)
|
350
|
+
end
|
351
|
+
|
352
|
+
def mapped_mget(*keys)
|
353
|
+
result = {}
|
354
|
+
mget(*keys).each do |value|
|
355
|
+
key = keys.shift
|
356
|
+
result.merge!(key => value) unless value.nil?
|
357
|
+
end
|
358
|
+
result
|
359
|
+
end
|
360
|
+
|
361
|
+
def sort(key, options = {})
|
362
|
+
cmd = []
|
363
|
+
cmd << "SORT"
|
364
|
+
cmd << key
|
365
|
+
cmd += ["BY", options[:by]] if options[:by]
|
366
|
+
|
367
|
+
Array(options[:get]).each do |k|
|
368
|
+
cmd += ["GET", k]
|
369
|
+
end if options[:get]
|
370
|
+
|
371
|
+
cmd += options[:order].split(" ") if options[:order]
|
372
|
+
cmd += ["LIMIT", *options[:limit]] if options[:limit]
|
373
|
+
cmd += ["STORE", options[:store]] if options[:store]
|
374
|
+
|
375
|
+
@client.call(*cmd)
|
376
|
+
end
|
377
|
+
|
378
|
+
def incr(key)
|
379
|
+
@client.call(:incr, key)
|
380
|
+
end
|
381
|
+
|
382
|
+
def incrby(key, increment)
|
383
|
+
@client.call(:incrby, key, increment)
|
384
|
+
end
|
385
|
+
|
386
|
+
def decr(key)
|
387
|
+
@client.call(:decr, key)
|
388
|
+
end
|
389
|
+
|
390
|
+
def decrby(key, decrement)
|
391
|
+
@client.call(:decrby, key, decrement)
|
392
|
+
end
|
393
|
+
|
394
|
+
def type(key)
|
395
|
+
@client.call(:type, key)
|
396
|
+
end
|
397
|
+
|
398
|
+
def quit
|
399
|
+
@client.call(:quit)
|
400
|
+
rescue Errno::ECONNRESET
|
401
|
+
end
|
402
|
+
|
403
|
+
def pipelined
|
404
|
+
original, @client = @client, Pipeline.new
|
405
|
+
yield
|
406
|
+
original.call_pipelined(@client.commands) unless @client.commands.empty?
|
407
|
+
ensure
|
408
|
+
@client = original
|
409
|
+
end
|
410
|
+
|
411
|
+
def exec
|
412
|
+
@client.call(:exec)
|
413
|
+
end
|
414
|
+
|
415
|
+
def multi(&block)
|
416
|
+
result = @client.call :multi
|
417
|
+
|
418
|
+
return result unless block_given?
|
419
|
+
|
420
|
+
begin
|
421
|
+
yield(self)
|
422
|
+
exec
|
423
|
+
rescue Exception => e
|
424
|
+
discard
|
425
|
+
raise e
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
def publish(channel, message)
|
430
|
+
@client.call(:publish, channel, message)
|
431
|
+
end
|
432
|
+
|
433
|
+
def unsubscribe(*channels)
|
434
|
+
if @client.kind_of?(SubscribedClient)
|
435
|
+
@client = @client.unsubscribe(*channels)
|
436
|
+
else
|
437
|
+
@client.call(:unsubscribe, *channels)
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
def subscribe(*channels, &block)
|
442
|
+
if @client.kind_of?(SubscribedClient)
|
443
|
+
@client.call(:subscribe, *channels)
|
444
|
+
else
|
445
|
+
begin
|
446
|
+
original, @client = @client, SubscribedClient.new(@client)
|
447
|
+
@client.subscribe(*channels, &block)
|
448
|
+
ensure
|
449
|
+
@client = original
|
450
|
+
end
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
def psubscribe(*channels, &block)
|
455
|
+
if @client.kind_of?(SubscribedClient)
|
456
|
+
@client.call(:psubscribe, *channels)
|
457
|
+
else
|
458
|
+
begin
|
459
|
+
original, @client = @client, SubscribedClient.new(@client)
|
460
|
+
@client.psubscribe(*channels, &block)
|
461
|
+
ensure
|
462
|
+
@client = original
|
463
|
+
end
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
def method_missing(command, *args)
|
468
|
+
@client.call(command, *args)
|
469
|
+
end
|
470
|
+
|
471
|
+
private
|
472
|
+
|
473
|
+
def _bool(value)
|
474
|
+
value == 1
|
475
|
+
end
|
476
|
+
|
13
477
|
end
|
14
478
|
|
15
479
|
begin
|