redis-roc 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1425 @@
1
+ require 'roc/store/roc_store'
2
+ require 'roc/store/object_initializers'
3
+ module ROC
4
+ module Store
5
+ class TransientStore < ROCStore
6
+ include ObjectInitializers
7
+
8
+ KEYSPACES = {}
9
+ MDSPACES = {}
10
+
11
+ attr_reader :name
12
+
13
+ def initialize(name=nil)
14
+ if name.nil?
15
+ @keyspace = {}
16
+ @mdspace = {}
17
+ else
18
+ @name = name.to_s
19
+ TransientStore::KEYSPACES[@name] ||= {}
20
+ TransientStore::MDSPACES[@name] ||= {}
21
+ end
22
+ end
23
+
24
+ def shared?
25
+ !@name.nil?
26
+ end
27
+
28
+ protected
29
+
30
+ def keyspace
31
+ @keyspace || TransientStore::KEYSPACES[self.name]
32
+ end
33
+
34
+ def mdspace
35
+ @mdspace || TransientStore::MDSPACES[self.name]
36
+ end
37
+
38
+ def expunge_if_expired(key)
39
+ if (md = self.mdspace[key.to_s]) && (ea = md[:expire_at]) && (ea < ::Time.now.to_i)
40
+ self.expunge(key)
41
+ end
42
+ end
43
+
44
+ def expunge(key)
45
+ self.keyspace.delete(key.to_s)
46
+ self.mdspace.delete(key.to_s)
47
+ end
48
+
49
+ def with_type(key, type)
50
+ md = self.mdspace[key.to_s]
51
+ if md.nil? || (md[:type] == type)
52
+ ret = yield
53
+ if self.keyspace[key.to_s]
54
+ self.mdspace[key.to_s] ||= {:type => type}
55
+ end
56
+ ret
57
+ else
58
+ raise TypeError, "#{type} required"
59
+ end
60
+ end
61
+
62
+ public
63
+
64
+ def call(method_name, *args)
65
+ if @multi_mode
66
+ @multi_calls << [method_name, *args]
67
+ 'QUEUED'
68
+ else
69
+ self.send method_name, *args
70
+ end
71
+ end
72
+
73
+ ## start of redis methods
74
+
75
+ # All keys
76
+
77
+ def del(*keys)
78
+ keys.each{|key| expunge_if_expired(key)}
79
+ i = 0
80
+ keys.each do |key|
81
+ if self.exists(key)
82
+ self.expunge(key)
83
+ i += 1
84
+ end
85
+ end
86
+ if keys.size > 1
87
+ true
88
+ else
89
+ i
90
+ end
91
+ end
92
+
93
+ def exists(key)
94
+ expunge_if_expired(key)
95
+ self.keyspace.has_key?(key.to_s)
96
+ end
97
+
98
+ def expire(key, secs)
99
+ self.expireat(key, ::Time.now.to_i + secs.to_i)
100
+ end
101
+
102
+ def expireat(key, epoch)
103
+ if self.exists(key)
104
+ self.mdspace[key.to_s] ||= {}
105
+ self.mdspace[key.to_s][:expire_at] = epoch.to_i
106
+ true
107
+ else
108
+ false
109
+ end
110
+ end
111
+
112
+ def keys(pattern='*')
113
+ if '*' == pattern
114
+ self.keyspace.keys
115
+ else
116
+ raise "patterns not implemented yet"
117
+ end
118
+ end
119
+
120
+ def move(key, db)
121
+ raise NotImplementedError
122
+ end
123
+
124
+ def persist(key)
125
+ if self.exists(key) && (md = self.mdspace[key.to_s]) && md.has_key?(:expire_at)
126
+ md.delete(:expire_at)
127
+ true
128
+ else
129
+ false
130
+ end
131
+ end
132
+
133
+ def randomkey
134
+ ks = self.keys
135
+ ks[Kernel.rand(ks.size)]
136
+ end
137
+
138
+ def rename(key, newkey)
139
+ if key.to_s == newkey.to_s
140
+ raise ArgumentError, "keys are the same"
141
+ elsif self.exists(key)
142
+ self.keyspace[newkey.to_s] = self.keyspace.delete(key.to_s)
143
+ true
144
+ else
145
+ raise ArgumentError, "no such key: #{key}"
146
+ end
147
+ end
148
+
149
+ def renamenx(key, newkey)
150
+ if key.to_s == newkey.to_s
151
+ raise ArgumentError, "keys are the same"
152
+ elsif self.exists(key)
153
+ if self.exists(newkey)
154
+ false
155
+ else
156
+ self.keyspace[newkey.to_s] = self.keyspace.delete(key.to_s)
157
+ true
158
+ end
159
+ else
160
+ raise ArgumentError, "no such key: #{key}"
161
+ end
162
+ end
163
+
164
+ def sort(key, *args)
165
+ opts = parse_sort_args(args)
166
+
167
+ raise ":by not yet supported" if opts.has_key?(:by)
168
+ raise ":get not yet supported" if opts.has_key?(:get)
169
+
170
+ limit = opts[:limit]
171
+ order = (opts[:order] || '').split(' ')
172
+ store = opts[:store]
173
+
174
+ md = self.mdspace[key.to_s]
175
+
176
+ vals = if md.nil?
177
+ []
178
+ elsif 'list' == md[:type]
179
+ self.lrange(key, 0, -1)
180
+ elsif 'set' == md[:type]
181
+ self.smembers(key)
182
+ elsif 'zset' == md[:type]
183
+ self.zrange(key, 0, -1)
184
+ else
185
+ raise TypeError, 'list, set or zset required'
186
+ end
187
+
188
+ sorter = if order.include?('alpha')
189
+ if order.include?('desc')
190
+ lambda{|a, b| b <=> a}
191
+ else
192
+ lambda{|a, b| a <=> b}
193
+ end
194
+ elsif order.include?('desc')
195
+ lambda{|a, b| b.to_f <=> a.to_f}
196
+ else
197
+ lambda{|a, b| a.to_f <=> b.to_f}
198
+ end
199
+
200
+ vals.sort!{|a, b| sorter.call(a, b)}
201
+
202
+ if limit
203
+ vals = vals[*limit]
204
+ end
205
+
206
+ if store
207
+ with_type(store, 'list') do
208
+ self.keyspace[store.to_s] = vals
209
+ end
210
+ end
211
+
212
+ vals
213
+ end
214
+
215
+ def ttl(key)
216
+ val = -1
217
+ if self.exists(key)
218
+ if (md = self.mdspace[key.to_s]) && (ea = md[:expire_at])
219
+ val = ea - ::Time.now.to_i
220
+ end
221
+ end
222
+ val
223
+ end
224
+
225
+ def type(key)
226
+ if md = self.mdspace[key.to_s]
227
+ md[:type].dup
228
+ else
229
+ 'none'
230
+ end
231
+ end
232
+
233
+ # Strings
234
+
235
+ def get(key)
236
+ with_type(key, 'string') do
237
+ expunge_if_expired(key)
238
+ v = self.keyspace[key.to_s]
239
+ v.nil? ? nil : v.dup
240
+ end
241
+ end
242
+
243
+ def set(key, val)
244
+ with_type(key, 'string') do
245
+ expunge_if_expired(key)
246
+ v = if val.is_a?(::String)
247
+ val.dup
248
+ else
249
+ val.to_s
250
+ end
251
+ self.keyspace[key.to_s] = v
252
+ self.persist(key)
253
+ true
254
+ end
255
+ end
256
+
257
+ def getset(key, val)
258
+ current_val = self.get(key)
259
+ self.set(key, val)
260
+ current_val
261
+ end
262
+
263
+ def mget(*keys)
264
+ keys.map{|k| self.get(k)}
265
+ end
266
+
267
+ def mset(*pairs)
268
+ i=0
269
+ while i < pairs.size
270
+ self.set(pairs[i], pairs[i+1])
271
+ i+=2
272
+ end
273
+ true
274
+ end
275
+
276
+ def setnx(key, val)
277
+ if self.exists(key)
278
+ false
279
+ else
280
+ self.set(key, val)
281
+ true
282
+ end
283
+ end
284
+
285
+ def msetnx(*pairs)
286
+ i=0
287
+ any_exist = false
288
+ while i < pairs.size
289
+ if self.exists(pairs[i])
290
+ any_exist = true
291
+ break
292
+ end
293
+ end
294
+ if !any_exist
295
+ i=0
296
+ while i < pairs.size
297
+ self.set(pairs[i], pairs[i+1])
298
+ i+=2
299
+ end
300
+ true
301
+ else
302
+ false
303
+ end
304
+ end
305
+
306
+ def append(key, val)
307
+ if self.exists(key)
308
+ with_type(key, 'string') do
309
+ self.keyspace[key.to_s] << val.to_s
310
+ end
311
+ else
312
+ self.set(key, val)
313
+ end
314
+ self.strlen(key)
315
+ end
316
+
317
+ def getbit(key, index)
318
+ raise ArgumentError, 'setbit takes a non-negative index' unless index > 0
319
+
320
+ bitstring = self.get(key).unpack('B*')[0]
321
+ if index < bitstring.length
322
+ if RUBY_VERSION.match(/^1\.8/)
323
+ bitstring[index].chr.to_i
324
+ else
325
+ bitstring[index].to_i
326
+ end
327
+ else
328
+ 0
329
+ end
330
+ end
331
+
332
+ def setbit(key, index, value)
333
+ raise ArgumentError, 'setbit takes a non-negative index' unless index > 0
334
+ raise ArgumentError, 'setbit takes a 1 or 0 for the value' unless((0 == value) || (1 == value))
335
+
336
+ bitstring = self.get(key).unpack('B*')[0]
337
+ current_val = 0
338
+ if index < bitstring.length
339
+ current_val = if RUBY_VERSION.match(/^1\.8/)
340
+ bitstring[index].chr.to_i
341
+ else
342
+ bitstring[index].to_i
343
+ end
344
+ bitstring[index] = value.to_s
345
+ else
346
+ bitstring << ('0' * (index - bitstring.length))
347
+ bitstring << value.to_s
348
+ end
349
+ self.set(key, [bitstring].pack('B*'))
350
+ current_val
351
+ end
352
+
353
+ def getrange(key, first_index, last_index)
354
+ if self.exists(key)
355
+ with_type(key, 'string') do
356
+ arr = self.keyspace[key.to_s].bytes.to_a[first_index..last_index]
357
+ if arr
358
+ arr.map{|c| c.chr}.join('')
359
+ else
360
+ ''
361
+ end
362
+ end
363
+ else
364
+ ''
365
+ end
366
+ end
367
+
368
+ def setrange(key, start_index, val)
369
+ with_type(key, 'string') do
370
+ expunge_if_expired(key)
371
+ if start_index < 1
372
+ raise "index out of range: #{start_index}"
373
+ end
374
+ length = self.strlen(key)
375
+ padding_length = start_index - length
376
+ v = val.to_s
377
+ if padding_length > 0
378
+ #self.keyspace[key.to_s][length, padding_length + v.length] = ("\u0000" * padding_length) + v
379
+ self.keyspace[key.to_s][length, padding_length + v.length] = ("\000" * padding_length) + v
380
+ else
381
+ self.keyspace[key.to_s][start_index, v.length] = v
382
+ end
383
+ self.strlen(key)
384
+ end
385
+ end
386
+
387
+ def strlen(key)
388
+ val = self.get(key)
389
+ if val.nil?
390
+ 0
391
+ else
392
+ if "".respond_to?(:bytesize)
393
+ val.bytesize
394
+ else
395
+ val.length
396
+ end
397
+ end
398
+ end
399
+
400
+ def incr(key)
401
+ self.incrby(key, 1)
402
+ end
403
+
404
+ def incrby(key, by)
405
+ raise "value (#{by}) is not an integer" unless by.is_a?(::Integer)
406
+ val = self.get(key)
407
+ new_val = val.to_i + by
408
+ self.set(key, new_val.to_s)
409
+ new_val
410
+ end
411
+
412
+ def decr(key)
413
+ self.incrby(key, -1)
414
+ end
415
+
416
+ def decrby(key, by)
417
+ self.incrby(key, -by)
418
+ end
419
+
420
+ # Lists
421
+
422
+ def lrange(key, start_index, stop_index)
423
+ with_type(key, 'list') do
424
+ expunge_if_expired(key)
425
+ val = self.keyspace[key.to_s]
426
+ if val.nil? || (start_index >= val.size) || ( (start_index < 0) && (stop_index < start_index) )
427
+ []
428
+ else
429
+ val[start_index..stop_index] || [] ## never return nil -- happens if start_index is neg and before begining of list
430
+ end
431
+ end
432
+ end
433
+
434
+ def llen(key)
435
+ with_type(key, 'list') do
436
+ expunge_if_expired(key)
437
+ val = self.keyspace[key.to_s]
438
+ if val.nil?
439
+ 0
440
+ else
441
+ val.size
442
+ end
443
+ end
444
+ end
445
+
446
+ def rpush(key, val)
447
+ with_type(key, 'list') do
448
+ if !self.exists(key)
449
+ self.keyspace[key.to_s] = []
450
+ end
451
+ v = if val.is_a?(::String)
452
+ val.dup
453
+ else
454
+ val.to_s
455
+ end
456
+ self.keyspace[key.to_s] << v
457
+ self.keyspace[key.to_s].size
458
+ end
459
+ end
460
+
461
+ def rpushx(key, val)
462
+ if self.exists(key)
463
+ self.rpush(key, val)
464
+ else
465
+ 0
466
+ end
467
+ end
468
+
469
+ def lpush(key, val)
470
+ with_type(key, 'list') do
471
+ if !self.exists(key)
472
+ self.keyspace[key.to_s] = []
473
+ end
474
+ v = if val.is_a?(::String)
475
+ val.dup
476
+ else
477
+ val.to_s
478
+ end
479
+ self.keyspace[key.to_s].unshift(v)
480
+ self.keyspace[key.to_s].size
481
+ end
482
+ end
483
+
484
+ def lpushx(key, val)
485
+ if self.exists(key)
486
+ self.lpush(key, val)
487
+ else
488
+ 0
489
+ end
490
+ end
491
+
492
+ def rpop(key)
493
+ with_type(key, 'list') do
494
+ if !self.exists(key)
495
+ nil
496
+ else
497
+ val = self.keyspace[key.to_s].pop
498
+ if 0 == self.llen(key)
499
+ self.del(key)
500
+ end
501
+ val
502
+ end
503
+ end
504
+ end
505
+
506
+ def lpop(key)
507
+ with_type(key, 'list') do
508
+ if !self.exists(key)
509
+ nil
510
+ else
511
+ val = self.keyspace[key.to_s].shift
512
+ if 0 == self.llen(key)
513
+ self.del(key)
514
+ end
515
+ val
516
+ end
517
+ end
518
+ end
519
+
520
+ def lindex(key, ind)
521
+ with_type(key, 'list') do
522
+ if !self.exists(key)
523
+ nil
524
+ else
525
+ v = self.keyspace[key.to_s][ind]
526
+ v.nil? ? nil : v.dup
527
+ end
528
+ end
529
+ end
530
+
531
+ def lset(key, ind, val)
532
+ with_type(key, 'list') do
533
+ expunge_if_expired(key)
534
+ arr = self.keyspace[key.to_s]
535
+ if arr.nil?
536
+ raise ArgumentError, "No such key: #{key}"
537
+ elsif ((ind < 0) && (ind < -arr.size)) || (ind >= arr.size)
538
+ raise ArgumentError, "index out of range: #{ind}"
539
+ else
540
+ v = if val.is_a?(::String)
541
+ val.dup
542
+ else
543
+ val.to_s
544
+ end
545
+ self.keyspace[key.to_s][ind] = v
546
+ end
547
+ end
548
+ end
549
+
550
+ def lrem(key, count, val)
551
+ with_type(key, 'list') do
552
+ if self.exists(key)
553
+ iterator = self.keyspace[key.to_s]
554
+ limit = iterator.size
555
+ reverse = false
556
+ if count > 0
557
+ limit = count
558
+ elsif count < 0
559
+ limit = count.abs
560
+ iterator = iterator.reverse
561
+ reverse = true
562
+ end
563
+ indexes_to_del = []
564
+ v = val.to_s
565
+ iterator.each_with_index do |test, i|
566
+ if test == v
567
+ if reverse
568
+ indexes_to_del.unshift iterator.size - (i + 1)
569
+ else
570
+ indexes_to_del << i
571
+ end
572
+ end
573
+ if indexes_to_del.size == limit
574
+ break
575
+ end
576
+ end
577
+ correction = 0
578
+ indexes_to_del.each do |i|
579
+ self.keyspace[key.to_s].delete_at(i - correction)
580
+ correction += 1
581
+ end
582
+ indexes_to_del.size
583
+ else
584
+ 0
585
+ end
586
+ end
587
+ end
588
+
589
+ def ltrim(key, start_index, stop_index)
590
+ arr = self.lrange(key, start_index, stop_index)
591
+ if 0 == arr.size
592
+ self.del(key)
593
+ else
594
+ self.keyspace[key.to_s] = arr
595
+ end
596
+ true
597
+ end
598
+
599
+ def rpoplpush(source_key, dest_key)
600
+ if self.exists(source_key)
601
+ val = self.rpop(source_key)
602
+ self.lpush(dest_key, val)
603
+ val
604
+ else
605
+ nil
606
+ end
607
+ end
608
+
609
+ def linsert(key, where, pivot, val)
610
+ if !['before', 'after'].include?(where.to_s.downcase)
611
+ raise ArgumentError "BEFORE or AFTER please"
612
+ else
613
+ if self.exists(key)
614
+ ind = self.keyspace[key.to_s].index(pivot)
615
+ if ind
616
+ if 'after' == where
617
+ ind +=1
618
+ end
619
+ v = if val.is_a?(::String)
620
+ val.dup
621
+ else
622
+ val.to_s
623
+ end
624
+ self.keyspace[key.to_s].insert(ind, v)
625
+ self.keyspace[key.to_s].size
626
+ else
627
+ -1
628
+ end
629
+ else
630
+ 0
631
+ end
632
+ end
633
+ end
634
+
635
+ def blpop
636
+ raise "blocking methods not implemented"
637
+ end
638
+
639
+ def brpop
640
+ raise "blocking methods not implemented"
641
+ end
642
+
643
+ def brpoplpush
644
+ raise "blocking methods not implemented"
645
+ end
646
+
647
+ # Set
648
+
649
+ def sadd(key, val)
650
+ with_type(key, 'set') do
651
+ v = val.to_s
652
+ if !self.exists(key)
653
+ self.keyspace[key.to_s] = {}
654
+ end
655
+ if self.keyspace[key.to_s].has_key?(v)
656
+ false
657
+ else
658
+ self.keyspace[key.to_s][v] = true
659
+ true
660
+ end
661
+ end
662
+ end
663
+
664
+ def scard(key)
665
+ with_type(key, 'set') do
666
+ expunge_if_expired(key)
667
+ val = self.keyspace[key.to_s]
668
+ if val.nil?
669
+ 0
670
+ else
671
+ val.size
672
+ end
673
+ end
674
+ end
675
+
676
+ def smembers(key)
677
+ with_type(key, 'set') do
678
+ expunge_if_expired(key)
679
+ val = self.keyspace[key.to_s]
680
+ if val.nil?
681
+ []
682
+ else
683
+ val.keys
684
+ end
685
+ end
686
+ end
687
+
688
+ def spop(key)
689
+ with_type(key, 'set') do
690
+ expunge_if_expired(key)
691
+ hsh = self.keyspace[key.to_s]
692
+ if hsh.nil?
693
+ nil
694
+ else
695
+ val = hsh.keys.sort{Kernel.rand}[0]
696
+ self.keyspace[key.to_s].delete(val)
697
+ if 0 == self.keyspace[key.to_s].size
698
+ self.del(key)
699
+ end
700
+ val
701
+ end
702
+ end
703
+ end
704
+
705
+ def sismember(key, val)
706
+ with_type(key, 'set') do
707
+ expunge_if_expired(key)
708
+ hsh = self.keyspace[key.to_s]
709
+ if hsh.nil?
710
+ false
711
+ else
712
+ hsh.has_key?(val.to_s)
713
+ end
714
+ end
715
+ end
716
+
717
+ def srem(key, val)
718
+ with_type(key, 'set') do
719
+ expunge_if_expired(key)
720
+ hsh = self.keyspace[key.to_s]
721
+ if hsh.nil?
722
+ false
723
+ else
724
+ !!hsh.delete(val.to_s)
725
+ end
726
+ end
727
+ end
728
+
729
+ def srandmember(key)
730
+ with_type(key, 'set') do
731
+ expunge_if_expired(key)
732
+ hsh = self.keyspace[key.to_s]
733
+ if hsh.nil?
734
+ nil
735
+ else
736
+ hsh.keys.sort{Kernel.rand}[0]
737
+ end
738
+ end
739
+ end
740
+
741
+ def smove(source_key, dest_key, val)
742
+ if self.exists(source_key)
743
+ if self.srem(source_key, val)
744
+ self.sadd(dest_key, val)
745
+ true
746
+ else
747
+ false
748
+ end
749
+ else
750
+ false
751
+ end
752
+ end
753
+
754
+ def sunion(*keys)
755
+ raise ArgumentError, 'sunion needs at least one key' unless keys.size > 0
756
+ union = self.smembers(keys.shift)
757
+ while k = keys.shift
758
+ union = union | self.smembers(k)
759
+ end
760
+ union
761
+ end
762
+
763
+ def sinter(*keys)
764
+ raise ArgumentError, 'sinter needs at least one key' unless keys.size > 0
765
+ inter = self.smembers(keys.shift)
766
+ while k = keys.shift
767
+ inter = inter & self.smembers(k)
768
+ end
769
+ inter
770
+ end
771
+
772
+ def sdiff(*keys)
773
+ raise ArgumentError, 'sinter needs at least one key' unless keys.size > 0
774
+ diff = self.smembers(keys.shift)
775
+ while k = keys.shift
776
+ diff = diff - self.smembers(k)
777
+ end
778
+ diff
779
+ end
780
+
781
+ def sunionstore(key, *other_keys)
782
+ vals = self.sunion(*other_keys)
783
+ vals.each{|v| self.sadd(key, v)}
784
+ vals.size
785
+ end
786
+
787
+ def sinterstore(key, *other_keys)
788
+ vals = self.sinter(*other_keys)
789
+ vals.each{|v| self.sadd(key, v)}
790
+ vals.size
791
+ end
792
+
793
+ def sdiffstore(key, *other_keys)
794
+ vals = self.sdiff(*other_keys)
795
+ vals.each{|v| self.sadd(key, v)}
796
+ vals.size
797
+ end
798
+
799
+ # Sorted Sets
800
+
801
+ def zadd(key, score, val)
802
+ with_type(key, 'zset') do
803
+ s = if score.is_a?(Numeric)
804
+ score
805
+ elsif score.is_a?(::String)
806
+ (score.index('.') ? score.to_f : score.to_i)
807
+ else
808
+ raise ArgumentError, "score is not numeric"
809
+ end
810
+ if !self.exists(key)
811
+ self.keyspace[key.to_s] = {:map => {}, :list => []}
812
+ end
813
+ ret = true
814
+ v = val.to_s
815
+ if self.keyspace[key.to_s][:map].has_key?(v)
816
+ ret = false
817
+ end
818
+ self.keyspace[key.to_s][:map][v] = s
819
+ self.resort(key)
820
+ ret
821
+ end
822
+ end
823
+
824
+ def zcard(key)
825
+ with_type(key, 'zset') do
826
+ expunge_if_expired(key)
827
+ val = self.keyspace[key.to_s]
828
+ if val.nil?
829
+ 0
830
+ else
831
+ val[:list].size
832
+ end
833
+ end
834
+ end
835
+
836
+ def zrange(key, start_index, stop_index, opts=nil)
837
+ opts = parse_zrange_arg(opts)
838
+
839
+ with_type(key, 'zset') do
840
+ expunge_if_expired(key)
841
+ val = self.keyspace[key.to_s]
842
+ if val.nil? || (start_index >= val[:list].size) || ( (start_index < 0) && (stop_index < start_index) )
843
+ []
844
+ else
845
+ ## emulate redis -- a neg start index before beginning meams the beginning
846
+ if (start_index < 0) && (-start_index > val[:list].size)
847
+ start_index = 0
848
+ end
849
+ if opts[:with_scores] || opts[:withscores]
850
+ ret = []
851
+ val[:list][start_index..stop_index].each do |v|
852
+ ret << v
853
+ ret << val[:map][v].to_s
854
+ end
855
+ ret
856
+ else
857
+ val[:list][start_index..stop_index] || [] ## never return nil
858
+ end
859
+ end
860
+ end
861
+ end
862
+
863
+ def zrevrange(key, start_index, stop_index, opts=nil)
864
+ opts = parse_zrange_arg(opts)
865
+
866
+ with_type(key, 'zset') do
867
+ expunge_if_expired(key)
868
+ val = self.keyspace[key.to_s]
869
+ if val.nil? || (start_index >= val[:list].size) || ( (start_index < 0) && (stop_index < start_index) )
870
+ []
871
+ else
872
+ list = val[:list].reverse
873
+ if opts[:with_scores] || opts[:withscores]
874
+ ret = []
875
+ list[start_index..stop_index].each do |v|
876
+ ret << v
877
+ ret << val[:map][v].to_s
878
+ end
879
+ ret
880
+ else
881
+ list[start_index..stop_index]
882
+ end
883
+ end
884
+ end
885
+ end
886
+
887
+ def zrangebyscore(key, min, max, *opts)
888
+ opts = parse_zscore_args(opts)
889
+
890
+ with_type(key, 'zset') do
891
+ expunge_if_expired(key)
892
+ val = self.keyspace[key.to_s]
893
+ if val.nil?
894
+ []
895
+ else
896
+ parse = lambda {|v|
897
+ if v.is_a?(::String)
898
+ if v[0] == '('[0]
899
+ [v[1..v.length-1].to_i, false]
900
+ elsif '+inf' == v
901
+ [1.0/0, true]
902
+ elsif '-inf' == v
903
+ [-1.0/0, true]
904
+ else
905
+ [v.to_i, true]
906
+ end
907
+ else
908
+ [v.to_i, true]
909
+ end
910
+ }
911
+ min_int, min_incl = *parse.call(min)
912
+ max_int, max_incl = *parse.call(max)
913
+
914
+ ret = []
915
+
916
+ pass = lambda { |v, op, incl, test|
917
+ v.send( op + (incl ? '=' : ''), test)
918
+ }
919
+
920
+ val[:list].each do |v|
921
+ if pass.call(val[:map][v], '>', min_incl, min_int) && pass.call(val[:map][v], '<', max_incl, max_int)
922
+ ret << v
923
+ if opts[:with_scores] || opts[:withscores]
924
+ ret << val[:map][v].to_s
925
+ end
926
+ end
927
+ end
928
+ if opts.has_key?(:limit)
929
+ limit = if opts[:with_scores] || opts[:withscores]
930
+ opts[:limit].map{|x| x * 2}
931
+ else
932
+ opts[:limit]
933
+ end
934
+ ret[limit[0], limit[1]]
935
+ else
936
+ ret
937
+ end
938
+ end
939
+ end
940
+ end
941
+
942
+ def zrevrangebyscore(key, max, min, *opts)
943
+ opts = parse_zscore_args(opts)
944
+
945
+ limit = opts.delete(:limit)
946
+ ret = self.zrangebyscore(key, min, max, opts).reverse
947
+ if limit
948
+ ret[limit[0], limit[1]]
949
+ else
950
+ ret
951
+ end
952
+ end
953
+
954
+ def zcount(key, min, max)
955
+ self.zrangebyscore(key, min, max).size
956
+ end
957
+
958
+ def zrank(key, val)
959
+ with_type(key, 'zset') do
960
+ expunge_if_expired(key)
961
+ hsh = self.keyspace[key.to_s]
962
+ if hsh.nil?
963
+ nil
964
+ else
965
+ hsh[:list].index(val.to_s)
966
+ end
967
+ end
968
+ end
969
+
970
+ def zrevrank(key, val)
971
+ r = self.zrank(key, val)
972
+ if r
973
+ self.keyspace[key.to_s][:list].size - (r + 1)
974
+ else
975
+ nil
976
+ end
977
+ end
978
+
979
+ def zscore(key, val)
980
+ with_type(key, 'zset') do
981
+ expunge_if_expired(key)
982
+ hsh = self.keyspace[key.to_s]
983
+ if hsh.nil?
984
+ nil
985
+ else
986
+ v = hsh[:map][val.to_s]
987
+ if v
988
+ v.to_s
989
+ else
990
+ nil
991
+ end
992
+ end
993
+ end
994
+ end
995
+
996
+ def zincrby(key, by, val)
997
+ score = self.zscore(key, val) || '0'
998
+ new_score = (score.index('.') ? score.to_f : score.to_i) + by
999
+ self.zadd(key, new_score, val)
1000
+ new_score.to_s
1001
+ end
1002
+
1003
+ def zrem(key, val)
1004
+ with_type(key, 'zset') do
1005
+ expunge_if_expired(key)
1006
+ hsh = self.keyspace[key.to_s]
1007
+ if hsh.nil?
1008
+ false
1009
+ else
1010
+ if hsh[:map].delete(val.to_s)
1011
+ self.resort(key)
1012
+ true
1013
+ else
1014
+ false
1015
+ end
1016
+ end
1017
+ end
1018
+ end
1019
+
1020
+ def zremrangebyscore(key, min, max)
1021
+ vals = self.zrangebyscore(key, min, max)
1022
+ if vals.size > 0
1023
+ vals.each do |val|
1024
+ self.keyspace[key.to_s][:map].delete(val)
1025
+ end
1026
+ self.resort(key)
1027
+ vals.size
1028
+ else
1029
+ 0
1030
+ end
1031
+ end
1032
+
1033
+ def zremrangebyrank(key, start, stop)
1034
+ vals = self.zrange(key, start, stop)
1035
+ if vals.size > 0
1036
+ vals.each do |val|
1037
+ self.keyspace[key.to_s][:map].delete(val)
1038
+ end
1039
+ self.resort(key)
1040
+ vals.size
1041
+ else
1042
+ 0
1043
+ end
1044
+ end
1045
+
1046
+ ## craziness here is to support both the Ruby Redis gem args style and the raw redis args styl
1047
+ def zunionstore(key, *args)
1048
+ other_keys, opts = parse_zop_args(args)
1049
+
1050
+ raise ArgumentError, 'zunionstore needs at least one key' unless other_keys.size > 0
1051
+ raise ArgumentError, 'mismatch weights count' unless (!opts.has_key?(:weights) || (opts[:weights].size == other_keys.size))
1052
+ with_type(key, 'zset') do
1053
+ sorted_sets = other_keys.map{|k| self.keyspace[k.to_s]}.compact
1054
+ u = sorted_sets.pop
1055
+ if u
1056
+ weight_a = (opts.has_key?(:weights) ? opts[:weights].pop : 1)
1057
+ while ss = sorted_sets.pop
1058
+ weight_b = (opts.has_key?(:weights) ? opts[:weights].pop : 1)
1059
+ u = self.ss_union(u, ss, weight_a, weight_b, (opts.has_key?(:aggregate) ? opts[:aggregate] : 'sum')) ##@@ weights and agg
1060
+ weight_a = 1
1061
+ end
1062
+ else
1063
+ u = {:map => {}, :list => []}
1064
+ end
1065
+ self.keyspace[key.to_s] = u
1066
+ u[:list].size
1067
+ end
1068
+ end
1069
+
1070
+ def zinterstore(key, *args)
1071
+ other_keys, opts = parse_zop_args(args)
1072
+
1073
+ raise ArgumentError, 'zinterstore needs at least one key' unless other_keys.size > 0
1074
+ with_type(key, 'zset') do
1075
+ sorted_sets = other_keys.map{|k| self.keyspace[k.to_s]}.compact
1076
+ i = sorted_sets.pop
1077
+ if i
1078
+ weight_a = (opts.has_key?(:weights) ? opts[:weights].pop : 1)
1079
+ while ss = sorted_sets.pop
1080
+ weight_b = (opts.has_key?(:weights) ? opts[:weights].pop : 1)
1081
+ i = self.ss_intersect(i, ss, weight_a, weight_b, (opts.has_key?(:aggregate) ? opts[:aggregate] : 'sum')) ##@@ weights and agg
1082
+ weight_a = 1
1083
+ end
1084
+ else
1085
+ i = {:map => {}, :list => []}
1086
+ end
1087
+ self.keyspace[key.to_s] = i
1088
+ i[:list].size
1089
+ end
1090
+ end
1091
+
1092
+ # Hashes
1093
+
1094
+ def hget(key, field)
1095
+ with_type(key, 'hash') do
1096
+ expunge_if_expired(key)
1097
+ hsh = self.keyspace[key.to_s]
1098
+ if !hsh.nil? && hsh.has_key?(field.to_s)
1099
+ hsh[field.to_s].dup
1100
+ else
1101
+ nil
1102
+ end
1103
+ end
1104
+ end
1105
+
1106
+ def hexists(key, field)
1107
+ with_type(key, 'hash') do
1108
+ self.exists(key) && self.keyspace[key.to_s].has_key?(field.to_s)
1109
+ end
1110
+ end
1111
+
1112
+ def hset(key, field, val)
1113
+ with_type(key, 'hash') do
1114
+ f = field.to_s
1115
+ v = if val.is_a?(::String)
1116
+ val.dup
1117
+ else
1118
+ val.to_s
1119
+ end
1120
+ if !self.exists(key)
1121
+ self.keyspace[key.to_s] = {}
1122
+ end
1123
+ ret = !self.keyspace[key.to_s].has_key?(f)
1124
+ self.keyspace[key.to_s][f] = v
1125
+ ret
1126
+ end
1127
+ end
1128
+
1129
+ def hgetall(key)
1130
+ with_type(key, 'hash') do
1131
+ hsh = self.keyspace[key.to_s]
1132
+ if hsh
1133
+ hsh.dup
1134
+ else
1135
+ {}
1136
+ end
1137
+ end
1138
+ end
1139
+
1140
+ def hkeys(key)
1141
+ if hsh = self.hgetall(key)
1142
+ hsh.keys
1143
+ else
1144
+ []
1145
+ end
1146
+ end
1147
+
1148
+ def hvals(key)
1149
+ if hsh = self.hgetall(key)
1150
+ hsh.values
1151
+ else
1152
+ []
1153
+ end
1154
+ end
1155
+
1156
+ def hlen(key)
1157
+ if hsh = self.hgetall(key)
1158
+ hsh.size
1159
+ else
1160
+ 0
1161
+ end
1162
+ end
1163
+
1164
+ def hdel(key, field)
1165
+ with_type(key, 'hash') do
1166
+ self.exists(key) && !!self.keyspace[key.to_s].delete(field.to_s)
1167
+ end
1168
+ end
1169
+
1170
+ def hincrby(key, field, by)
1171
+ raise "value (#{by}) is not an integer" unless by.is_a?(::Integer)
1172
+ val = self.hget(key, field)
1173
+ new_val = val.to_i + by
1174
+ self.hset(key, field, new_val)
1175
+ new_val
1176
+ end
1177
+
1178
+ def hmget(key, *fields)
1179
+ fields.map{|f| self.hget(key, f)}
1180
+ end
1181
+
1182
+ def hmset(key, *pairs)
1183
+ i = 0
1184
+ while i < pairs.length
1185
+ self.hset(key, pairs[i], pairs[i+1])
1186
+ i += 2
1187
+ end
1188
+ true
1189
+ end
1190
+
1191
+ def hsetnx(key, field, val)
1192
+ if self.hexists(key, field)
1193
+ false
1194
+ else
1195
+ self.hset(key, field, val)
1196
+ end
1197
+ end
1198
+
1199
+ # Transactions
1200
+
1201
+ def multi
1202
+ if @multi_mode
1203
+ raise "multi calls can't be nested"
1204
+ else
1205
+ @multi_mode = true
1206
+ @multi_calls = []
1207
+ if block_given?
1208
+ begin
1209
+ yield
1210
+ rescue Exception => e
1211
+ self.discard
1212
+ raise e
1213
+ end
1214
+ self.exec
1215
+ end
1216
+ end
1217
+ end
1218
+
1219
+ def exec
1220
+ if @multi_mode
1221
+ ret = []
1222
+ @multi_mode = false
1223
+ @multi_calls.each do |call|
1224
+ ret << (self.call *call)
1225
+ end
1226
+ @multi_calls = []
1227
+ ret
1228
+ else
1229
+ raise "exec without a multi"
1230
+ end
1231
+ end
1232
+
1233
+ def discard
1234
+ if @multi_mode
1235
+ @multi_mode = false
1236
+ @multi_calls = []
1237
+ else
1238
+ raise "discard without a multi"
1239
+ end
1240
+ end
1241
+
1242
+ def in_multi?
1243
+ !!@multi_mode
1244
+ end
1245
+
1246
+ def watch(*keys)
1247
+ if @multi_mode
1248
+ raise "watch inside multi not allowed"
1249
+ end
1250
+ ## nothing, we are non concurrent
1251
+ true
1252
+ end
1253
+
1254
+ def unwatch
1255
+ ## nothing, we are non concurrent
1256
+ true
1257
+ end
1258
+
1259
+ def flushdb
1260
+ if self.shared?
1261
+ TransientStore::KEYSPACES[self.name] = {}
1262
+ TransientStore::MDSPACES[self.name] ={}
1263
+ else
1264
+ @keyspace = {}
1265
+ @mdspace = {}
1266
+ end
1267
+ end
1268
+
1269
+ # non-public helpers for redis methods
1270
+ protected
1271
+
1272
+ def parse_sort_args(args)
1273
+ if args.size == 1 && args[0].is_a?(::Hash)
1274
+ return args[0]
1275
+ end
1276
+ opts = {}
1277
+ while arg = args.shift
1278
+ if 'by' == arg.to_s.downcase
1279
+ opts[:by] = args.shift
1280
+ elsif 'limit' == arg.to_s.downcase
1281
+ opts[:limit] = [args.shift, args.shift]
1282
+ elsif 'get' == arg.to_s.downcase
1283
+ opts[:get] ||= []
1284
+ opts[:get] << args.shift
1285
+ elsif 'store' == arg.to_s.downcase
1286
+ opts[:store] = args.shift
1287
+ end
1288
+ end
1289
+ if args.size > 0
1290
+ opts[:order] = args.join(' ')
1291
+ end
1292
+ opts
1293
+ end
1294
+
1295
+ def parse_zscore_args(opts)
1296
+ if 0 == opts.size
1297
+ {}
1298
+ elsif (opts.size > 1) || !opts[0].is_a?(::Hash)
1299
+ parsed_opts = {}
1300
+ while o = opts.shift
1301
+ if 'withscores' == o.to_s.downcase
1302
+ parsed_opts[:withscores] = true
1303
+ elsif 'withscores' == o.to_s.downcase
1304
+ parsed_opts[:limit] = [opts.shift.to_i, opts.shift.to_i]
1305
+ end
1306
+ end
1307
+ parsed_opts
1308
+ else
1309
+ opts[0]
1310
+ end
1311
+ end
1312
+
1313
+ def parse_zrange_arg(opts)
1314
+ if opts.nil?
1315
+ {}
1316
+ elsif opts.is_a?(::Hash)
1317
+ opts
1318
+ elsif ('withscores' == opts.to_s.downcase)
1319
+ {:withscores => true}
1320
+ else
1321
+ {}
1322
+ end
1323
+ end
1324
+
1325
+ def parse_zop_args(args)
1326
+ other_keys = []
1327
+ opts = {}
1328
+
1329
+ if args[0].is_a?(::Array)
1330
+ other_keys = args.shift
1331
+ elsif args[0].is_a?(::Numeric)
1332
+ num_keys = args.shift
1333
+ 1.upto(num_keys)
1334
+ other_keys << args.shift
1335
+ end
1336
+
1337
+ if (args.size == 1) && args[0].is_a?(::Hash)
1338
+ opts = args[0]
1339
+ else
1340
+ while arg = args.shift
1341
+ if 'weight' == arg.to_s.downcase
1342
+ opts[:weights] = []
1343
+ elsif 'aggregate' == arg.to_s.downcase
1344
+ opts[:aggregate] = nil
1345
+ elsif opts.has_key?(:weights)
1346
+ opts[:weights] << arg.to_i
1347
+ elsif opts.has_key?(:aggregate)
1348
+ opts[:aggregate] = arg.to_s.downcase
1349
+ end
1350
+ end
1351
+ end
1352
+ [other_keys, opts]
1353
+ end
1354
+
1355
+ def resort(key)
1356
+ self.keyspace[key.to_s][:list] = do_sort(self.keyspace[key.to_s][:map])
1357
+ end
1358
+
1359
+ def do_sort(map)
1360
+ map.keys.sort do |a, b|
1361
+ score = (map[a] <=> map[b])
1362
+ if 0 == score
1363
+ a <=> b
1364
+ else
1365
+ score
1366
+ end
1367
+ end
1368
+ end
1369
+
1370
+ def ss_union(a, b, weight_a, weight_b, aggregate)
1371
+ self.do_ss_calc( (a[:list] | b[:list] ), a, b, weight_a, weight_b, aggregate )
1372
+ end
1373
+
1374
+ def ss_intersect(a, b, weight_a, weight_b, aggregate)
1375
+ self.do_ss_calc( (a[:list] & b[:list] ), a, b, weight_a, weight_b, aggregate )
1376
+ end
1377
+
1378
+ def do_ss_calc(set, a, b, weight_a, weight_b, aggregate)
1379
+ r = {:map => {}, :list => []}
1380
+ set.each do |k|
1381
+ a_score = a[:map].has_key?(k) && (a[:map][k] * weight_a)
1382
+ b_score = b[:map].has_key?(k) && (b[:map][k] * weight_b)
1383
+ r[:map][k] = if a_score && b_score
1384
+ case aggregate.to_s.downcase
1385
+ when 'sum'
1386
+ a_score + b_score
1387
+ when 'min'
1388
+ [a_score, b_score].min
1389
+ when 'max'
1390
+ [a_score, b_score].max
1391
+ else
1392
+ raise ArgumentError, "Invalid aggregate: #{aggregate}"
1393
+ end
1394
+ elsif a_score
1395
+ a_score
1396
+ else
1397
+ b_score
1398
+ end
1399
+ end
1400
+ r[:list] = do_sort(r[:map])
1401
+ r
1402
+ end
1403
+
1404
+ ## end of redis methods
1405
+
1406
+ def method_missing(*args)
1407
+ puts "unimplemented: #{args}"
1408
+ end
1409
+
1410
+ public
1411
+
1412
+ def inspect
1413
+ "<#{self.class} @name=#{self.name.inspect}>"
1414
+ end
1415
+
1416
+ def enable_eval
1417
+ require 'roc/store/transient_eval'
1418
+ if !self.class.include?(ROC::Store::TransientEval)
1419
+ self.class.send(:include, ROC::Store::TransientEval)
1420
+ end
1421
+ end
1422
+
1423
+ end
1424
+ end
1425
+ end