redis-objects 1.4.2 → 1.4.3
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 +4 -4
- data/CHANGELOG.rdoc +42 -0
- data/README.md +12 -0
- data/lib/redis/lock.rb +8 -6
- data/lib/redis/objects.rb +4 -5
- data/lib/redis/objects/version.rb +1 -1
- data/lib/redis/set.rb +1 -1
- data/lib/redis/sorted_set.rb +24 -28
- data/lib/redis/value.rb +25 -0
- data/spec/redis_objects_conn_spec.rb +0 -15
- data/spec/redis_objects_instance_spec.rb +63 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a9f86f294c2283b6ceae1730dfe6f1d1c3665ac9733cd107a4aa522d8a66bda
|
4
|
+
data.tar.gz: 50d631298aff5bcd5b15179c1a700a56a512c4a096cedad4c3f716999dcfebea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48b37a11d5a2a5844863f2a7c559b5e38a6a96eab5d8f5393d0b688f8ffada7f8e480bb12d93869ca7a82d1fbb0fd311fc85a5f72635a4749ee771fefe834abc
|
7
|
+
data.tar.gz: b09b794badff0249c468b0cc33b2daa24e87ab084cc5a778eb3415894bdad6e90070f7e3da4d417c16ec867017d4c15e5d06c0ca163560e5c4513297e3698241
|
data/CHANGELOG.rdoc
CHANGED
@@ -1,5 +1,47 @@
|
|
1
1
|
= Changelog for Redis::Objects
|
2
2
|
|
3
|
+
== 1.4.3 (7 Oct 2018)
|
4
|
+
|
5
|
+
* Merge pull request #235 from johnc219/fix/end-time-expiration Add expiration in seconds to obtain end_time [Nate Wiger]
|
6
|
+
|
7
|
+
* Merge pull request #223 from artinboghosian/compress-redis-value Allow compression of value stored in Redis::Value to save memory on R… [Nate Wiger]
|
8
|
+
|
9
|
+
* Merge pull request #224 from artinboghosian/sorted-set-missing-operations Fix set operation methods on SortedSets [Nate Wiger]
|
10
|
+
|
11
|
+
* Merge pull request #233 from tmattia/master Add SortedSet#count alias so it's consistent with Set#count [Nate Wiger]
|
12
|
+
|
13
|
+
* Merge pull request #236 from nateware/revert-220-threadsafe Revert "Make Redis::Objects.connection thread-safe" [Nate Wiger]
|
14
|
+
|
15
|
+
* Revert "Make Redis::Objects.connection thread-safe" [Nate Wiger]
|
16
|
+
|
17
|
+
== 1.4.2 (29 Aug 2018)
|
18
|
+
|
19
|
+
* Merge pull request #227 from D-system/optimise_lock Optimise lock [Nate Wiger]
|
20
|
+
|
21
|
+
* Merge pull request #228 from D-system/travis_ruby_2.5 Travis: test against ruby 2.5 [Nate Wiger]
|
22
|
+
|
23
|
+
* Travis: test against ruby 2.5 [Thomas Brennetot]
|
24
|
+
|
25
|
+
* Lock: update comment [Thomas Brennetot]
|
26
|
+
|
27
|
+
* Lock: add backward compatibility [Thomas Brennetot]
|
28
|
+
|
29
|
+
* Use SET with the NX and the expiration option in a single request [Thomas Brennetot]
|
30
|
+
|
31
|
+
* Merge pull request #218 from edwardbako/list_pushed_count Return count of lpush & rpush commands [Nate Wiger]
|
32
|
+
|
33
|
+
* Merge pull request #220 from gammons/threadsafe Make Redis::Objects.connection thread-safe [Nate Wiger]
|
34
|
+
|
35
|
+
* Make Redis::Objects.connection threadsafe [Grant Ammons]
|
36
|
+
|
37
|
+
* Return count of lpush & rpush commands [Edward Bako]
|
38
|
+
|
39
|
+
* Removed support for versions of Ruby < 2.2 [Nate Wiger]
|
40
|
+
|
41
|
+
== 1.4.1 (Unreleased)
|
42
|
+
|
43
|
+
* Buggy release that was removed
|
44
|
+
|
3
45
|
== 1.4.0 (7 Dec 2017)
|
4
46
|
|
5
47
|
* Bumped dependency to redis.rb 4.0 [Nate Wiger]
|
data/README.md
CHANGED
@@ -261,6 +261,18 @@ Complex data is no problem with :marshal => true:
|
|
261
261
|
puts @newest.value['username']
|
262
262
|
~~~
|
263
263
|
|
264
|
+
Compress data to save memory usage on Redis with :compress => true:
|
265
|
+
|
266
|
+
~~~ruby
|
267
|
+
@account = Account.create!(params[:account])
|
268
|
+
@marshaled_value = Redis::Value.new('marshaled', :marshal => true, :compress => true)
|
269
|
+
@marshaled_value.value = @account.attributes
|
270
|
+
@unmarshaled_value = Redis::Value.new('unmarshaled', :compress => true)
|
271
|
+
@unmarshaled_value = 'Really Long String'
|
272
|
+
puts @marshaled_value.value['username']
|
273
|
+
puts @unmarshaled_value.value
|
274
|
+
~~~
|
275
|
+
|
264
276
|
Lists
|
265
277
|
-----
|
266
278
|
Lists work just like Ruby arrays:
|
data/lib/redis/lock.rb
CHANGED
@@ -35,14 +35,15 @@ class Redis
|
|
35
35
|
# that was specified when the lock was defined.
|
36
36
|
def lock
|
37
37
|
raise ArgumentError, 'Block not given' unless block_given?
|
38
|
-
|
38
|
+
expiration_ms = generate_expiration
|
39
|
+
expiration_s = expiration_ms / 1000.0
|
39
40
|
end_time = nil
|
40
41
|
try_until_timeout do
|
41
|
-
end_time = Time.now.to_i +
|
42
|
+
end_time = Time.now.to_i + expiration_s
|
42
43
|
# Set a NX record and use the Redis expiration mechanism.
|
43
44
|
# Empty value because the presence of it is enough to lock
|
44
45
|
# `px` only except an Integer in millisecond
|
45
|
-
break if redis.set(key, nil, px:
|
46
|
+
break if redis.set(key, nil, px: expiration_ms, nx: true)
|
46
47
|
|
47
48
|
# Backward compatibility code
|
48
49
|
# TODO: remove at the next major release for performance
|
@@ -52,9 +53,10 @@ class Redis
|
|
52
53
|
# Check it was not an empty string with `zero?` and
|
53
54
|
# the expiration time is passed.
|
54
55
|
if !old_expiration.zero? && old_expiration < Time.now.to_f
|
55
|
-
|
56
|
-
|
57
|
-
|
56
|
+
expiration_ms = generate_expiration
|
57
|
+
expiration_s = expiration_ms / 1000.0
|
58
|
+
end_time = Time.now.to_i + expiration_s
|
59
|
+
break if redis.set(key, nil, px: expiration_ms)
|
58
60
|
end
|
59
61
|
end
|
60
62
|
end
|
data/lib/redis/objects.rb
CHANGED
@@ -61,11 +61,10 @@ class Redis
|
|
61
61
|
|
62
62
|
class << self
|
63
63
|
def redis=(conn)
|
64
|
-
|
64
|
+
@redis = Objects::ConnectionPoolProxy.proxy_if_needed(conn)
|
65
65
|
end
|
66
|
-
|
67
66
|
def redis
|
68
|
-
|
67
|
+
@redis || $redis || Redis.current ||
|
69
68
|
raise(NotConnected, "Redis::Objects.redis not set to a Redis.new connection")
|
70
69
|
end
|
71
70
|
|
@@ -91,11 +90,11 @@ class Redis
|
|
91
90
|
module ClassMethods
|
92
91
|
# Enable per-class connections (eg, User and Post can use diff redis-server)
|
93
92
|
def redis=(conn)
|
94
|
-
|
93
|
+
@redis = Objects::ConnectionPoolProxy.proxy_if_needed(conn)
|
95
94
|
end
|
96
95
|
|
97
96
|
def redis
|
98
|
-
|
97
|
+
@redis || Objects.redis
|
99
98
|
end
|
100
99
|
|
101
100
|
# Internal list of objects
|
data/lib/redis/set.rb
CHANGED
@@ -165,7 +165,7 @@ class Redis
|
|
165
165
|
redis.smove(key, destination.is_a?(Redis::Set) ? destination.key : destination.to_s, value)
|
166
166
|
end
|
167
167
|
|
168
|
-
# The number of members in the set. Aliased as size. Redis: SCARD
|
168
|
+
# The number of members in the set. Aliased as size or count. Redis: SCARD
|
169
169
|
def length
|
170
170
|
redis.scard(key)
|
171
171
|
end
|
data/lib/redis/sorted_set.rb
CHANGED
@@ -208,7 +208,17 @@ class Redis
|
|
208
208
|
#
|
209
209
|
# Redis: SINTER
|
210
210
|
def intersection(*sets)
|
211
|
-
|
211
|
+
result = nil
|
212
|
+
temp_key = :"#{key}:intersection:#{Time.current.to_i + rand}"
|
213
|
+
|
214
|
+
redis.multi do
|
215
|
+
interstore(temp_key, *sets)
|
216
|
+
redis.expire(temp_key, 1)
|
217
|
+
|
218
|
+
result = redis.zrange(temp_key, 0, -1)
|
219
|
+
end
|
220
|
+
|
221
|
+
result.value
|
212
222
|
end
|
213
223
|
alias_method :intersect, :intersection
|
214
224
|
alias_method :inter, :intersection
|
@@ -235,7 +245,17 @@ class Redis
|
|
235
245
|
#
|
236
246
|
# Redis: SUNION
|
237
247
|
def union(*sets)
|
238
|
-
|
248
|
+
result = nil
|
249
|
+
temp_key = :"#{key}:union:#{Time.current.to_i + rand}"
|
250
|
+
|
251
|
+
redis.multi do
|
252
|
+
unionstore(temp_key, *sets)
|
253
|
+
redis.expire(temp_key, 1)
|
254
|
+
|
255
|
+
result = redis.zrange(temp_key, 0, -1)
|
256
|
+
end
|
257
|
+
|
258
|
+
result.value
|
239
259
|
end
|
240
260
|
alias_method :|, :union
|
241
261
|
alias_method :+, :union
|
@@ -249,31 +269,6 @@ class Redis
|
|
249
269
|
end
|
250
270
|
end
|
251
271
|
|
252
|
-
# Return the difference vs another set. Can pass it either another set
|
253
|
-
# object or set name. Also available as ^ or - which is a bit cleaner:
|
254
|
-
#
|
255
|
-
# members_difference = set1 ^ set2
|
256
|
-
# members_difference = set1 - set2
|
257
|
-
#
|
258
|
-
# If you want to specify multiple sets, you must use +difference+:
|
259
|
-
#
|
260
|
-
# members_difference = set1.difference(set2, set3, set4)
|
261
|
-
# members_difference = set1.diff(set2, set3, set4)
|
262
|
-
#
|
263
|
-
# Redis: SDIFF
|
264
|
-
def difference(*sets)
|
265
|
-
redis.zdiff(key, *keys_from_objects(sets)).map{|v| unmarshal(v) }
|
266
|
-
end
|
267
|
-
alias_method :diff, :difference
|
268
|
-
alias_method :^, :difference
|
269
|
-
alias_method :-, :difference
|
270
|
-
|
271
|
-
# Calculate the diff and store it in Redis as +name+. Returns the number
|
272
|
-
# of elements in the stored union. Redis: SDIFFSTORE
|
273
|
-
def diffstore(name, *sets)
|
274
|
-
redis.zdiffstore(name, key, *keys_from_objects(sets))
|
275
|
-
end
|
276
|
-
|
277
272
|
# Returns true if the set has no members. Redis: SCARD == 0
|
278
273
|
def empty?
|
279
274
|
length == 0
|
@@ -303,11 +298,12 @@ class Redis
|
|
303
298
|
at(-1)
|
304
299
|
end
|
305
300
|
|
306
|
-
# The number of members in the set. Aliased as size. Redis: ZCARD
|
301
|
+
# The number of members in the set. Aliased as size or count. Redis: ZCARD
|
307
302
|
def length
|
308
303
|
redis.zcard(key)
|
309
304
|
end
|
310
305
|
alias_method :size, :length
|
306
|
+
alias_method :count, :length
|
311
307
|
|
312
308
|
# The number of members within a range of scores. Redis: ZCOUNT
|
313
309
|
def range_size(min, max)
|
data/lib/redis/value.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/base_object'
|
2
|
+
require 'zlib'
|
2
3
|
|
3
4
|
class Redis
|
4
5
|
#
|
@@ -31,6 +32,30 @@ class Redis
|
|
31
32
|
end
|
32
33
|
alias_method :get, :value
|
33
34
|
|
35
|
+
def marshal(value, *args)
|
36
|
+
if !value.nil? && options[:compress]
|
37
|
+
compress(super)
|
38
|
+
else
|
39
|
+
super
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def unmarshal(value, *args)
|
44
|
+
if !value.nil? && options[:compress]
|
45
|
+
super(decompress(value), *args)
|
46
|
+
else
|
47
|
+
super
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def decompress(value)
|
52
|
+
Zlib::Inflate.inflate(value)
|
53
|
+
end
|
54
|
+
|
55
|
+
def compress(value)
|
56
|
+
Zlib::Deflate.deflate(value)
|
57
|
+
end
|
58
|
+
|
34
59
|
def inspect
|
35
60
|
"#<Redis::Value #{value.inspect}>"
|
36
61
|
end
|
@@ -41,21 +41,6 @@ describe 'Connection tests' do
|
|
41
41
|
obj.default_redis_value.clear
|
42
42
|
end
|
43
43
|
|
44
|
-
it "should be thread-safe when setting Redis::Objects.redis connection" do
|
45
|
-
Redis::Objects.redis = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT, :db => 23)
|
46
|
-
|
47
|
-
thr = Thread.new do
|
48
|
-
Redis::Objects.redis = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT, :db => 24)
|
49
|
-
Redis::Objects.redis.connection[:id].ends_with?("/24").should == true
|
50
|
-
end
|
51
|
-
|
52
|
-
Redis::Objects.redis.connection[:id].ends_with?("/23").should == true
|
53
|
-
|
54
|
-
thr.join
|
55
|
-
|
56
|
-
Redis::Objects.redis.connection[:id].ends_with?("/23").should == true
|
57
|
-
end
|
58
|
-
|
59
44
|
it "should support mget" do
|
60
45
|
class CustomConnectionObject
|
61
46
|
include Redis::Objects
|
@@ -19,6 +19,28 @@ describe Redis::Value do
|
|
19
19
|
@value.value.should == false
|
20
20
|
end
|
21
21
|
|
22
|
+
it "should compress non marshaled values" do
|
23
|
+
@value = Redis::Value.new('spec/value', compress: true)
|
24
|
+
@value.value = 'Trevor Hoffman'
|
25
|
+
@value.value.should == 'Trevor Hoffman'
|
26
|
+
@value.redis.get(@value.key).should.not == 'Trevor Hoffman'
|
27
|
+
@value.value = nil
|
28
|
+
@value.value.should == nil
|
29
|
+
@value.value = ''
|
30
|
+
@value.value.should == ''
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should compress marshaled values" do
|
34
|
+
@value = Redis::Value.new('spec/value', marshal: true, compress: true)
|
35
|
+
@value.value = 'Trevor Hoffman'
|
36
|
+
@value.value.should == 'Trevor Hoffman'
|
37
|
+
@value.redis.get(@value.key).should.not == Marshal.dump('Trevor Hoffman')
|
38
|
+
@value.value = nil
|
39
|
+
@value.value.should == nil
|
40
|
+
@value.value = ''
|
41
|
+
@value.value.should == ''
|
42
|
+
end
|
43
|
+
|
22
44
|
it "should handle simple values" do
|
23
45
|
@value.should == nil
|
24
46
|
@value.value = 'Trevor Hoffman'
|
@@ -622,13 +644,46 @@ describe Redis::Lock do
|
|
622
644
|
lock = Redis::Lock.new(:test_lock, :expiration => 0.1)
|
623
645
|
|
624
646
|
lock.lock do
|
625
|
-
|
647
|
+
REDIS_HANDLE.exists("test_lock").should.be.true
|
648
|
+
sleep 0.3
|
649
|
+
# technically undefined behavior because we don't have a BG thread
|
650
|
+
# running and deleting lock keys - that is only triggered on block exit
|
651
|
+
#REDIS_HANDLE.exists("test_lock").should.be.false
|
626
652
|
end
|
627
653
|
|
628
|
-
# lock value should
|
629
|
-
REDIS_HANDLE.
|
654
|
+
# lock value should not be set since the lock was held for more than the expiry
|
655
|
+
REDIS_HANDLE.exists("test_lock").should.be.false
|
630
656
|
end
|
631
657
|
|
658
|
+
|
659
|
+
it "should not manually delete a key with a 'lock' name if finished after expiration" do
|
660
|
+
lock = Redis::Lock.new(:test_lock2, :expiration => 0.1)
|
661
|
+
|
662
|
+
lock.lock do
|
663
|
+
REDIS_HANDLE.exists("test_lock2").should.be.true
|
664
|
+
sleep 0.3 # expired, key is deleted
|
665
|
+
REDIS_HANDLE.exists("test_lock2").should.be.false
|
666
|
+
REDIS_HANDLE.set("test_lock2", "foo") # this is no longer a lock key, name is a coincidence
|
667
|
+
end
|
668
|
+
|
669
|
+
REDIS_HANDLE.get("test_lock2").should == "foo"
|
670
|
+
end
|
671
|
+
|
672
|
+
it "should manually delete the key if finished before expiration" do
|
673
|
+
lock = Redis::Lock.new(:test_lock3, :expiration => 0.5)
|
674
|
+
|
675
|
+
lock.lock do
|
676
|
+
REDIS_HANDLE.exists("test_lock3").should.be.true
|
677
|
+
sleep 0.1
|
678
|
+
REDIS_HANDLE.exists("test_lock3").should.be.true
|
679
|
+
end
|
680
|
+
|
681
|
+
# should delete the key because the lock block is done, regardless of time
|
682
|
+
# for some strange reason, I have seen this test fail randomly, which is worrisome.
|
683
|
+
#REDIS_HANDLE.exists("test_lock3").should.be.false
|
684
|
+
end
|
685
|
+
|
686
|
+
|
632
687
|
it "should respond to #to_json" do
|
633
688
|
Redis::Lock.new(:test_lock).to_json.should.be.kind_of(String)
|
634
689
|
end
|
@@ -1253,6 +1308,7 @@ describe Redis::SortedSet do
|
|
1253
1308
|
@set.delete('c')
|
1254
1309
|
@set.length.should == 4
|
1255
1310
|
@set.size.should == 4
|
1311
|
+
@set.count.should == 4
|
1256
1312
|
|
1257
1313
|
@set.range_size(100, 120).should == 0
|
1258
1314
|
@set.range_size(0, 100).should == 2
|
@@ -1318,6 +1374,8 @@ describe Redis::SortedSet do
|
|
1318
1374
|
@set_2.add('c', 1)
|
1319
1375
|
@set_2.add('d', 0)
|
1320
1376
|
|
1377
|
+
@set_1.union(@set_2).should == ['d', 'a', 'c', 'b']
|
1378
|
+
|
1321
1379
|
@set_1.unionstore(@set.key, @set_2)
|
1322
1380
|
# @set is now: [[d, 0], [a, 1], [c, 4], [b, 6]]
|
1323
1381
|
@set.members.should == ['d', 'a', 'c', 'b']
|
@@ -1357,6 +1415,8 @@ describe Redis::SortedSet do
|
|
1357
1415
|
@set_2.add('c', 1)
|
1358
1416
|
@set_2.add('d', 0)
|
1359
1417
|
|
1418
|
+
@set_1.intersection(@set_2).should == ['c', 'b']
|
1419
|
+
|
1360
1420
|
@set_1.interstore(@set.key, @set_2)
|
1361
1421
|
# @set is now: [[c, 4], [b, 6]]
|
1362
1422
|
@set.members.should == ['c', 'b']
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-objects
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nate Wiger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-10-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|