retained 0.2.3 → 0.3.0
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.md +7 -0
- data/Gemfile +0 -1
- data/Gemfile.lock +0 -9
- data/lib/retained/tracker.rb +22 -12
- data/lib/retained/version.rb +2 -2
- data/retained.gemspec +3 -6
- data/test/tracker_spec.rb +32 -4
- metadata +2 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca84fa50ba4a030bab29edbe18ff45345aff78f7
|
4
|
+
data.tar.gz: ae826caf63c1b345aad1c1938320d3e410416393
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ae5a327d375d7b3770ca897dfb76771842ef9fa39be8ee7915c920f57f2cb2b538800cba211f6c0fd5742c8babf7193b30ab27565dc064e1d93aab1c12304f34
|
7
|
+
data.tar.gz: ae0cffa2a5020e55a21878889b546ed733f3f3d0bf144a87658a7e6ade076a935227404db67c961a111595dabc294d690e1d5ba6b0a3903b224be8f9961694e2
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# 0.3.0
|
2
|
+
|
3
|
+
* BREAKING CHANGE: Removed dependency on redis-bitops, which
|
4
|
+
while conserving space resulted in significant degradation of
|
5
|
+
performance due to the additional overhead of tracking chunks
|
6
|
+
and additional bit operations.
|
7
|
+
|
1
8
|
# 0.2.3
|
2
9
|
|
3
10
|
* Updated to latest redis-bitops, which includes multiple fixes
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,11 +1,3 @@
|
|
1
|
-
GIT
|
2
|
-
remote: git://github.com/msaffitz/redis-bitops.git
|
3
|
-
revision: 2ebd12b5044046db67e7958eda0701257b3eb3f9
|
4
|
-
ref: 2ebd12b5044046db67e7958eda0701257b3eb3f9
|
5
|
-
specs:
|
6
|
-
redis-bitops (0.2.1)
|
7
|
-
redis
|
8
|
-
|
9
1
|
GEM
|
10
2
|
remote: http://rubygems.org/
|
11
3
|
specs:
|
@@ -84,7 +76,6 @@ DEPENDENCIES
|
|
84
76
|
minitest
|
85
77
|
rdoc (~> 3.12)
|
86
78
|
redis (~> 3.1.0)
|
87
|
-
redis-bitops!
|
88
79
|
simplecov
|
89
80
|
timecop (~> 0.7.1)
|
90
81
|
yard (~> 0.7)
|
data/lib/retained/tracker.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
require 'redis
|
1
|
+
require 'redis'
|
2
2
|
require 'active_support/core_ext/time/calculations'
|
3
|
+
require 'securerandom'
|
3
4
|
require 'retained/configuration'
|
4
5
|
|
5
6
|
module Retained
|
@@ -18,29 +19,31 @@ module Retained
|
|
18
19
|
# is provided.
|
19
20
|
def retain(entity, group: 'default', period: Time.now)
|
20
21
|
index = entity_index(entity, group)
|
21
|
-
|
22
|
-
bitmap[index] = true
|
22
|
+
config.redis_connection.setbit key_period(group, period), index, 1
|
23
23
|
end
|
24
24
|
|
25
25
|
# Total active entities in the period, or now if no period,
|
26
26
|
# is provided.
|
27
27
|
def total_active(group: 'default', period: Time.now)
|
28
|
-
|
29
|
-
bitmap.bitcount
|
28
|
+
config.redis_connection.bitcount key_period(group, period)
|
30
29
|
end
|
31
30
|
|
32
31
|
# Returns the total number of unique active entities between
|
33
32
|
# the start and end periods (inclusive), or now if no stop
|
34
33
|
# period is provided.
|
35
34
|
def unique_active(group: 'default', start:, stop: Time.now)
|
36
|
-
|
35
|
+
keys = []
|
37
36
|
start = period_start(group, start)
|
38
37
|
while (start <= stop)
|
39
|
-
|
38
|
+
keys << key_period(group, start)
|
40
39
|
start += seconds_in_reporting_interval(config.group(group).reporting_interval)
|
41
40
|
end
|
42
|
-
return 0 if
|
43
|
-
|
41
|
+
return 0 if keys.length == 0
|
42
|
+
|
43
|
+
temp_bitmap do |key|
|
44
|
+
config.redis_connection.bitop 'OR', key, *keys
|
45
|
+
config.redis_connection.bitcount key
|
46
|
+
end
|
44
47
|
end
|
45
48
|
|
46
49
|
# Returns true if the entity was active in the given period,
|
@@ -51,9 +54,7 @@ module Retained
|
|
51
54
|
group = groups if group == [] || !group
|
52
55
|
|
53
56
|
group.to_a.each do |g|
|
54
|
-
|
55
|
-
index = entity_index(entity, g)
|
56
|
-
return bitmap[index] if bitmap[index]
|
57
|
+
return true if config.redis_connection.getbit(key_period(g, period), entity_index(entity, g)) == 1
|
57
58
|
end
|
58
59
|
false
|
59
60
|
end
|
@@ -88,6 +89,15 @@ LUA
|
|
88
89
|
end
|
89
90
|
|
90
91
|
private
|
92
|
+
def temp_bitmap
|
93
|
+
temp_key = "#{config.prefix}:temp:#{SecureRandom.hex}"
|
94
|
+
begin
|
95
|
+
yield temp_key
|
96
|
+
ensure
|
97
|
+
config.redis_connection.del temp_key
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
91
101
|
# Returns the time (UTC) that the period starts at for the given group
|
92
102
|
def period_start(group, period)
|
93
103
|
period.utc.send("beginning_of_#{config.group(group).reporting_interval}")
|
data/lib/retained/version.rb
CHANGED
data/retained.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: retained 0.
|
5
|
+
# stub: retained 0.3.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "retained"
|
9
|
-
s.version = "0.
|
9
|
+
s.version = "0.3.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["Mike Saffitz"]
|
14
|
-
s.date = "
|
14
|
+
s.date = "2015-01-23"
|
15
15
|
s.description = "\n Easy tracking of activity and retention at scale in daily, hourly, or minute intervals\n using sparse Redis bitmaps.\n "
|
16
16
|
s.email = "m@saffitz.com"
|
17
17
|
s.extra_rdoc_files = [
|
@@ -48,7 +48,6 @@ Gem::Specification.new do |s|
|
|
48
48
|
|
49
49
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
50
50
|
s.add_runtime_dependency(%q<redis>, ["~> 3.1.0"])
|
51
|
-
s.add_runtime_dependency(%q<redis-bitops>, [">= 0"])
|
52
51
|
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
53
52
|
s.add_development_dependency(%q<minitest>, [">= 0"])
|
54
53
|
s.add_development_dependency(%q<yard>, ["~> 0.7"])
|
@@ -59,7 +58,6 @@ Gem::Specification.new do |s|
|
|
59
58
|
s.add_development_dependency(%q<timecop>, ["~> 0.7.1"])
|
60
59
|
else
|
61
60
|
s.add_dependency(%q<redis>, ["~> 3.1.0"])
|
62
|
-
s.add_dependency(%q<redis-bitops>, [">= 0"])
|
63
61
|
s.add_dependency(%q<activesupport>, [">= 0"])
|
64
62
|
s.add_dependency(%q<minitest>, [">= 0"])
|
65
63
|
s.add_dependency(%q<yard>, ["~> 0.7"])
|
@@ -71,7 +69,6 @@ Gem::Specification.new do |s|
|
|
71
69
|
end
|
72
70
|
else
|
73
71
|
s.add_dependency(%q<redis>, ["~> 3.1.0"])
|
74
|
-
s.add_dependency(%q<redis-bitops>, [">= 0"])
|
75
72
|
s.add_dependency(%q<activesupport>, [">= 0"])
|
76
73
|
s.add_dependency(%q<minitest>, [">= 0"])
|
77
74
|
s.add_dependency(%q<yard>, ["~> 0.7"])
|
data/test/tracker_spec.rb
CHANGED
@@ -15,10 +15,10 @@ describe Retained::Tracker do
|
|
15
15
|
|
16
16
|
it 'retain tracks using the default group in the current period' do
|
17
17
|
Timecop.freeze(Time.new(2014, 8, 29, 9, 03, 35)) do
|
18
|
-
|
18
|
+
tracker.retain('entity_a')
|
19
19
|
prefix = tracker.config.prefix
|
20
20
|
group = tracker.config.default_group
|
21
|
-
tracker.
|
21
|
+
tracker.active?('entity_a').must_equal true
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -27,7 +27,7 @@ describe Retained::Tracker do
|
|
27
27
|
tracker.retain('entity_a', group: 'group_a', period: period)
|
28
28
|
|
29
29
|
prefix = tracker.config.prefix
|
30
|
-
tracker.
|
30
|
+
tracker.active?('entity_a', period: period).must_equal true
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'retains using the "default" group' do
|
@@ -40,7 +40,7 @@ describe Retained::Tracker do
|
|
40
40
|
tracker.retain('entity_a', group: 'group_a')
|
41
41
|
|
42
42
|
prefix = tracker.config.prefix
|
43
|
-
tracker.
|
43
|
+
tracker.active?('entity_a', group: 'group_a', period: Time.now).must_equal true
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
@@ -162,4 +162,32 @@ describe Retained::Tracker do
|
|
162
162
|
tracker.key_period('minute', Time.new(2014, 8, 30, 10, 35, 47, 5*3600)).must_equal 'retained:minute:1409376900'
|
163
163
|
tracker.key_period('day', Time.new(2014, 8, 30, 10, 35, 47, -2*3600)).must_equal 'retained:day:1409356800'
|
164
164
|
end
|
165
|
+
|
166
|
+
it 'temp_bitmap cleans up the temporary bitmap' do
|
167
|
+
tmp_key = nil
|
168
|
+
tracker.send(:temp_bitmap) do |key|
|
169
|
+
tmp_key = key
|
170
|
+
tracker.config.redis_connection.setbit key, 0, 1
|
171
|
+
end
|
172
|
+
tracker.config.redis_connection.exists(tmp_key).must_equal false
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'temp_bitmap cleans up the temporary bitmap with exception raised' do
|
176
|
+
tmp_key = nil
|
177
|
+
begin
|
178
|
+
tracker.send(:temp_bitmap) do |key|
|
179
|
+
tmp_key = key
|
180
|
+
tracker.config.redis_connection.setbit key, 0, 1
|
181
|
+
raise 'exception'
|
182
|
+
end
|
183
|
+
rescue
|
184
|
+
end
|
185
|
+
tracker.config.redis_connection.exists(tmp_key).must_equal false
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'temp_bitmap returns the value' do
|
189
|
+
tracker.send(:temp_bitmap) do |key|
|
190
|
+
4
|
191
|
+
end.must_equal 4
|
192
|
+
end
|
165
193
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: retained
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Saffitz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 3.1.0
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: redis-bitops
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: activesupport
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|