redis-ick 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +7 -37
- data/CHANGELOG.md +8 -1
- data/lib/redis/ick.rb +92 -57
- data/lib/redis/ick/version.rb +1 -1
- 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: 5a3b91d98498be4ca9b767fa2af1a90aeccb041038d50e1df47eb8d0218ab4d5
|
4
|
+
data.tar.gz: 439ccf38a34252f6b1dd52c8d44cad3bb2b3f4cdbb9955455db966b51cc73cc4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 42542453d2526f2a0e8fc10debc07648f80252e8c349ee9349eefecdd26756596da846a61c5f38e5b025b8c6eaae7ad1689737b953616504acfbd52c2771989b
|
7
|
+
data.tar.gz: aea66c00ee53155fe58367975988f2c450e8d9e366f4182a9a6268e036cf03a9235043dafc45812cb5122f55fe791a11cbabce5e10929fdea444e49ff824061c
|
data/.rubocop.yml
CHANGED
@@ -6,54 +6,24 @@ AllCops:
|
|
6
6
|
Exclude:
|
7
7
|
- 'gemfiles/vendor/**/*'
|
8
8
|
|
9
|
-
#
|
9
|
+
# Some classes and methods need to be big.
|
10
10
|
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# cutting tests or splitting up my test suites.
|
11
|
+
# I'll break them down for testability or composability or
|
12
|
+
# applicability, but not because I crossed an invisible line that
|
13
|
+
# somebody made up.
|
15
14
|
#
|
16
|
-
Metrics
|
17
|
-
|
18
|
-
- 'test/**/*.rb'
|
19
|
-
Metrics/ClassLength:
|
20
|
-
Max: 400
|
21
|
-
Exclude:
|
22
|
-
- 'test/**/*.rb'
|
23
|
-
|
24
|
-
# I like this Metric in principle, but I don't like the default max of
|
25
|
-
# 15.
|
26
|
-
#
|
27
|
-
# Also, as per Metrics/ClassLength IMO this kind of limit should not
|
28
|
-
# apply to test code (I get up to 318 over there).
|
29
|
-
#
|
30
|
-
Metrics/AbcSize:
|
31
|
-
Max: 30
|
32
|
-
Exclude:
|
33
|
-
- 'test/**/*.rb'
|
34
|
-
|
35
|
-
# I like this Metric in principle, but I don't like the default max of
|
36
|
-
# 10.
|
37
|
-
#
|
38
|
-
# Also, as per Metrics/ClassLength IMO this kind of limit should not
|
39
|
-
# apply to test code.
|
40
|
-
#
|
41
|
-
Metrics/MethodLength:
|
42
|
-
Max: 50
|
43
|
-
Exclude:
|
44
|
-
- 'test/**/*.rb'
|
15
|
+
Metrics:
|
16
|
+
Enabled: false
|
45
17
|
|
46
18
|
# I put extra spaces in a lot of expressions for a lot of different
|
47
19
|
# reasons, including especially readability.
|
48
20
|
#
|
49
|
-
# I reject these cops.
|
50
|
-
#
|
51
21
|
Layout:
|
52
22
|
Enabled: false
|
53
23
|
|
54
24
|
# As a group, the Style cops are bewilderingly opiniated.
|
55
25
|
#
|
56
|
-
# In some cases IMO they are harmful e.g. Style/TernaryParentheses.
|
26
|
+
# In some cases IMO they are actively harmful e.g. Style/TernaryParentheses.
|
57
27
|
#
|
58
28
|
# I reject these cops.
|
59
29
|
#
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,11 @@
|
|
1
|
-
## 0.1.
|
1
|
+
## 0.1.4 (2019-11-18)
|
2
|
+
- ICKUNLINK, as ICKDEL but uses Redis UNLINK for O(1) time.
|
3
|
+
- Clear recommendation not to use backwash unless clearly needed.
|
4
|
+
- Assuming a full cset, it can more than double the cost of ICKEXCHANGE.
|
5
|
+
- Performance optimizations in Redis Lua code.
|
6
|
+
- 13%-25% faster for large reservations on large Icks
|
7
|
+
|
8
|
+
## 0.1.3 (2019-06-07)
|
2
9
|
- Support for redis >= 4.0.0 added.
|
3
10
|
- Breaking changes at redis v4.0.0 addressed.
|
4
11
|
- Support for ruby < 2.2.2 dropped.
|
data/lib/redis/ick.rb
CHANGED
@@ -80,19 +80,47 @@ class Redis
|
|
80
80
|
#
|
81
81
|
# @param ick_key String the base key for the Ick
|
82
82
|
#
|
83
|
+
# @param unlink true to use UNLINK, default false to use DEL.
|
84
|
+
#
|
83
85
|
# @return an integer, the number of Redis keys deleted, which will
|
84
86
|
# be >= 1 if an Ick existed at key.
|
85
87
|
#
|
86
|
-
def ickdel(ick_key)
|
88
|
+
def ickdel(ick_key,unlink: false)
|
87
89
|
if !ick_key.is_a?(String)
|
88
90
|
raise ArgumentError, "bogus non-String ick_key #{ick_key}"
|
89
91
|
end
|
90
|
-
|
91
|
-
|
92
|
-
|
92
|
+
stats_prefix = unlink ? 'profile.ick.ickunlink' : 'profile.ick.ickdel'
|
93
|
+
redis_cmd = unlink ? 'UNLINK' : 'DEL'
|
94
|
+
_statsd_increment("#{stats_prefix}.calls")
|
95
|
+
_statsd_time("#{stats_prefix}.time") do
|
96
|
+
_eval(
|
97
|
+
LUA_ICK_PREFIX +
|
98
|
+
"return redis.call('#{redis_cmd}',ick_key,ick_pset_key,ick_cset_key)",
|
99
|
+
ick_key
|
100
|
+
)
|
93
101
|
end
|
94
102
|
end
|
95
103
|
|
104
|
+
# Removes all data associated with the Ick in Redis at key.
|
105
|
+
#
|
106
|
+
# Similar to UNLINK key, http://redis.io/commands/unlink, but may
|
107
|
+
# unlink multiple keys which together implement the Ick data
|
108
|
+
# structure.
|
109
|
+
#
|
110
|
+
# UNLINK is O(1) in the number of messages in the Ick, and is
|
111
|
+
# available with redis-server >= 4.0.0. Physical space
|
112
|
+
# reclamation in Redis, which can be O(N), is deferred to
|
113
|
+
# asynchronous server threads.
|
114
|
+
#
|
115
|
+
# @param ick_key String the base key for the Ick
|
116
|
+
#
|
117
|
+
# @return an integer, the number of Redis keys unlinked, which will
|
118
|
+
# be >= 1 if an Ick existed at key.
|
119
|
+
#
|
120
|
+
def ickunlink(ick_key)
|
121
|
+
ickdel(ick_key,unlink: true)
|
122
|
+
end
|
123
|
+
|
96
124
|
# Fetches stats.
|
97
125
|
#
|
98
126
|
# @param ick_key String the base key for the Ick
|
@@ -575,21 +603,6 @@ class Redis
|
|
575
603
|
end
|
576
604
|
}.freeze
|
577
605
|
|
578
|
-
#######################################################################
|
579
|
-
# LUA_ICKDEL
|
580
|
-
#######################################################################
|
581
|
-
#
|
582
|
-
# Removes all keys associated with the Ick at KEYS[1].
|
583
|
-
#
|
584
|
-
# @param uses no ARGV
|
585
|
-
#
|
586
|
-
# @return the number of Redis keys deleted, which will be 0 if and
|
587
|
-
# only if no Ick existed at KEYS[1]
|
588
|
-
#
|
589
|
-
LUA_ICKDEL = (LUA_ICK_PREFIX + %{
|
590
|
-
return redis.call('DEL',ick_key,ick_pset_key,ick_cset_key)
|
591
|
-
}).freeze
|
592
|
-
|
593
606
|
#######################################################################
|
594
607
|
# LUA_ICKSTATS
|
595
608
|
#######################################################################
|
@@ -747,54 +760,76 @@ class Redis
|
|
747
760
|
# cset by the commit function followed by up to ARGV[1] pairs
|
748
761
|
# [member,score,...] from the reserve funciton.
|
749
762
|
#
|
750
|
-
# Note: This Lua
|
751
|
-
#
|
752
|
-
#
|
753
|
-
#
|
754
|
-
# would be preferable to call ZREM in larger batches.
|
763
|
+
# Note: This Lua code calls unpack(ARGV,i,j) in limited-size
|
764
|
+
# slices, no larger than 7990, to avoid a "too many results to
|
765
|
+
# unpack" failure which has been observed when unpacking tables as
|
766
|
+
# small as 8000.
|
755
767
|
#
|
756
768
|
LUA_ICKEXCHANGE = (LUA_ICK_PREFIX + %{
|
757
769
|
local reserve_size = tonumber(ARGV[1])
|
758
770
|
local backwash = ARGV[2]
|
759
771
|
local argc = table.getn(ARGV)
|
760
772
|
local num_committed = 0
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
local
|
770
|
-
local
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
773
|
+
local unpack_limit = 7990
|
774
|
+
for i = 3,argc,unpack_limit do
|
775
|
+
local max = math.min(i+unpack_limit,argc)
|
776
|
+
local num_zrem = redis.call('ZREM',ick_cset_key,unpack(ARGV,i,max))
|
777
|
+
num_committed = num_committed + num_zrem
|
778
|
+
end
|
779
|
+
local ick_fold = function(key_from,key_to,max_size_key_to)
|
780
|
+
while true do
|
781
|
+
local size_key_to = redis.call('ZCARD',key_to)
|
782
|
+
local num = math.min(
|
783
|
+
max_size_key_to - size_key_to,
|
784
|
+
unpack_limit / 2 -- room for both scores and members
|
785
|
+
)
|
786
|
+
if num < 1 then
|
787
|
+
break
|
788
|
+
end
|
789
|
+
local head_from =
|
790
|
+
redis.call('ZRANGE',key_from,0,num-1,'WITHSCORES')
|
791
|
+
local head_size = table.getn(head_from)
|
792
|
+
if 0 == head_size then
|
793
|
+
break
|
794
|
+
end
|
795
|
+
local to_zadd = {} -- both scores and members
|
796
|
+
local to_zrem = {} -- members only
|
797
|
+
for i = 1,head_size,2 do
|
798
|
+
local member = head_from[i]
|
799
|
+
local score_from = tonumber(head_from[i+1])
|
800
|
+
local score_to = redis.call('ZSCORE',key_to,member)
|
801
|
+
if false == score_to or score_from < tonumber(score_to) then
|
802
|
+
to_zadd[#to_zadd+1] = score_from
|
803
|
+
to_zadd[#to_zadd+1] = member
|
804
|
+
end
|
805
|
+
to_zrem[#to_zrem+1] = member
|
806
|
+
end
|
807
|
+
redis.call('ZREM',key_from,unpack(to_zrem))
|
808
|
+
if 0 < table.getn(to_zadd) then
|
809
|
+
redis.call('ZADD',key_to,unpack(to_zadd))
|
776
810
|
end
|
777
|
-
end
|
778
|
-
redis.call('DEL',ick_cset_key)
|
779
|
-
end
|
780
|
-
while true do
|
781
|
-
local cset_size = redis.call('ZCARD',ick_cset_key)
|
782
|
-
if cset_size and reserve_size <= cset_size then
|
783
|
-
break
|
784
|
-
end
|
785
|
-
local first_pset = redis.call('ZRANGE',ick_pset_key,0,0,'WITHSCORES')
|
786
|
-
if 0 == table.getn(first_pset) then
|
787
|
-
break
|
788
|
-
end
|
789
|
-
local first_member = first_pset[1]
|
790
|
-
local first_score = tonumber(first_pset[2])
|
791
|
-
redis.call('ZREM',ick_pset_key,first_member)
|
792
|
-
local old_score = redis.call('ZSCORE',ick_cset_key,first_member)
|
793
|
-
if false == old_score or first_score < tonumber(old_score) then
|
794
|
-
redis.call('ZADD',ick_cset_key,first_score,first_member)
|
795
811
|
end
|
796
812
|
end
|
813
|
+
if 'backwash' == backwash then
|
814
|
+
--
|
815
|
+
-- Fold everything in the cset back into the pset.
|
816
|
+
--
|
817
|
+
local pset_size = redis.call('ZCARD',ick_pset_key) or 0
|
818
|
+
local cset_size = redis.call('ZCARD',ick_cset_key) or 0
|
819
|
+
ick_fold(ick_cset_key,ick_pset_key,pset_size+cset_size)
|
820
|
+
end
|
821
|
+
--
|
822
|
+
-- Fold enough from the pset to the cset to grow the cset
|
823
|
+
-- to at most reserve_size members.
|
824
|
+
--
|
825
|
+
ick_fold(ick_pset_key,ick_cset_key,reserve_size)
|
826
|
+
--
|
827
|
+
-- Make sure ick_key exists per specification.
|
828
|
+
--
|
797
829
|
redis.call('SETNX', ick_key, 'ick.v1')
|
830
|
+
--
|
831
|
+
-- Package up return results, which may be smaller than the cset.
|
832
|
+
--
|
798
833
|
local result = { num_committed }
|
799
834
|
if reserve_size > 0 then
|
800
835
|
local max = reserve_size - 1
|
data/lib/redis/ick/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-ick
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jhwillett
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-11-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|