redis-ick 0.1.3 → 0.1.4
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/.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
|