retained 0.2.3 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|