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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 73e354c2a489016a3d1c873e021d8f1b58a18dd2
4
- data.tar.gz: 84dc43a781952b4a5b6d97584e1fff0d7ff77665
3
+ metadata.gz: ca84fa50ba4a030bab29edbe18ff45345aff78f7
4
+ data.tar.gz: ae826caf63c1b345aad1c1938320d3e410416393
5
5
  SHA512:
6
- metadata.gz: 2939b0bf01bfd76a12106ad70b87c57885b9a80d27b6cac0e7ae28fabebc02efec4e8fba4dab704421c68104f7280d06a147c89dc64106868a535bc237fdf75c
7
- data.tar.gz: de8476c725c0db2dfeb7335309a42e3524ddf857a1ec43efd6e7f573160f357adca06edb3636c0ac3f83539bffadcac91c4c2d614e631243196a945bc2e6279c
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
@@ -1,7 +1,6 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
3
  gem 'redis', '~> 3.1.0'
4
- gem 'redis-bitops', github: 'msaffitz/redis-bitops', ref: '2ebd12b5044046db67e7958eda0701257b3eb3f9'
5
4
  gem 'activesupport'
6
5
 
7
6
  group :development do
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)
@@ -1,5 +1,6 @@
1
- require 'redis/bitops'
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
- bitmap = config.redis_connection.sparse_bitmap(key_period(group, period))
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
- bitmap = config.redis_connection.sparse_bitmap(key_period(group, period))
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
- bitmaps = []
35
+ keys = []
37
36
  start = period_start(group, start)
38
37
  while (start <= stop)
39
- bitmaps << config.redis_connection.sparse_bitmap(key_period(group, start))
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 bitmaps.length == 0
43
- bitmaps.inject { |uniques,bitmap| uniques | bitmap }.bitcount
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
- bitmap = config.redis_connection.sparse_bitmap(key_period(g, period))
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}")
@@ -1,8 +1,8 @@
1
1
  module Retained
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 2
5
- PATCH = 3
4
+ MINOR = 3
5
+ PATCH = 0
6
6
  BUILD = nil
7
7
 
8
8
  STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
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.2.3 ruby lib
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.2.3"
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 = "2014-11-16"
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
- tracker.retain('entity_a')
18
+ tracker.retain('entity_a')
19
19
  prefix = tracker.config.prefix
20
20
  group = tracker.config.default_group
21
- tracker.config.redis_connection.sparse_bitmap("#{prefix}:#{group}:1409328000")[0]
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.config.redis_connection.sparse_bitmap("#{prefix}:group_a:1409356800")[0]
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.config.redis_connection.sparse_bitmap("#{prefix}:group_a:1409328000")[0]
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.2.3
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: 2014-11-16 00:00:00.000000000 Z
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