redis_counters 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/CHANGELOG.md +38 -0
- data/Gemfile +3 -0
- data/Makefile +14 -0
- data/README.md +320 -0
- data/Rakefile +15 -0
- data/lib/redis_counters.rb +21 -0
- data/lib/redis_counters/base_counter.rb +84 -0
- data/lib/redis_counters/bucket.rb +59 -0
- data/lib/redis_counters/cluster.rb +22 -0
- data/lib/redis_counters/clusterize_and_partitionize.rb +194 -0
- data/lib/redis_counters/hash_counter.rb +70 -0
- data/lib/redis_counters/partition.rb +16 -0
- data/lib/redis_counters/unique_hash_counter.rb +51 -0
- data/lib/redis_counters/unique_values_lists/base.rb +57 -0
- data/lib/redis_counters/unique_values_lists/blocking.rb +167 -0
- data/lib/redis_counters/unique_values_lists/expirable.rb +155 -0
- data/lib/redis_counters/unique_values_lists/non_blocking.rb +91 -0
- data/lib/redis_counters/version.rb +3 -0
- data/redis_counters.gemspec +31 -0
- data/spec/redis_counters/base_spec.rb +29 -0
- data/spec/redis_counters/hash_counter_spec.rb +462 -0
- data/spec/redis_counters/unique_hash_counter_spec.rb +83 -0
- data/spec/redis_counters/unique_values_lists/blocking_spec.rb +94 -0
- data/spec/redis_counters/unique_values_lists/expirable_spec.rb +6 -0
- data/spec/redis_counters/unique_values_lists/non_blicking_spec.rb +6 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support/unique_values_lists/common.rb +563 -0
- data/spec/support/unique_values_lists/expirable.rb +162 -0
- data/spec/support/unique_values_lists/set.rb +119 -0
- data/tasks/audit.rake +6 -0
- data/tasks/cane.rake +12 -0
- data/tasks/changelog.rake +7 -0
- data/tasks/coverage.rake +21 -0
- data/tasks/support.rb +24 -0
- metadata +242 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7686748e5af2550c7895c4d3b893a4464e12495f
|
4
|
+
data.tar.gz: da77d21dac0066c38745affc6301055191f10dc6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ee6ce001671fc800cb85327c64e39196197708da7f32d07a5ef3fbd7b9a1937fb2526e207a8c5c5ef8902973db5e7e2d827434b09401982f7af1cfe917203815
|
7
|
+
data.tar.gz: 3b2fa28eb9a5c12efb45fae68c96da2ac03ad68e95ad59264ca152f3bc080371a79efc61c4d5890653de54c217f10193a56663e4ea4951dc4357d7d2edfd3ce2
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
#### [Current]
|
3
|
+
|
4
|
+
|
5
|
+
#### v1.2.0
|
6
|
+
* 2014-11-10 [be642ce](../../commit/be642ce) - __(Artem Napolskih)__ Release 1.2.0
|
7
|
+
* 2014-11-10 [6257dc2](../../commit/6257dc2) - __(Artem Napolskih)__ feature(hash_counter): added float mode
|
8
|
+
* 2014-10-17 [48deb40](../../commit/48deb40) - __(Artem Napolskih)__ feature(unique_values_list): introduced a list of unique values to expiry of the members
|
9
|
+
* 2014-10-17 [e1206b7](../../commit/e1206b7) - __(Artem Napolskih)__ feature(unique_values_list): introduce has_value? method
|
10
|
+
* 2014-10-17 [cccc2be](../../commit/cccc2be) - __(Artem Napolskih)__ feature(unique_values_list): rename Standard and Fast unique values list to Blocking and NonBlocking respectively
|
11
|
+
* 2014-10-17 [7521fd8](../../commit/7521fd8) - __(Artem Napolskih)__ chore(specs): reorganize unique lists specs
|
12
|
+
* 2014-04-23 [94fada3](../../commit/94fada3) - __(Artem Napolskih)__ chore(all): fix circleci badge
|
13
|
+
* 2013-11-20 [0ae5531](../../commit/0ae5531) - __(Artem Napolskih)__ Release 1.1.0
|
14
|
+
|
15
|
+
#### v1.1.0
|
16
|
+
* 2013-11-20 [01f12f9](../../commit/01f12f9) - __(Artem Napolskih)__ Release 1.1.0
|
17
|
+
* 2013-11-20 [3897988](../../commit/3897988) - __(Artem Napolskih)__ refactor(all): back delete_all! methods
|
18
|
+
* 2013-11-15 [2d1c733](../../commit/2d1c733) - __(Artem Napolskih)__ refactor(all): extract Cluster and Partition classes
|
19
|
+
* 2013-10-22 [020cc8e](../../commit/020cc8e) - __(Napolskih)__ refactor(all): shared code of clustering and partitioning extracted into module - group_keys -> cluster_keys - shared code of clustering and partitioning extracted into module
|
20
|
+
|
21
|
+
#### v1.0.1
|
22
|
+
* 2013-10-21 [9b5e13b](../../commit/9b5e13b) - __(Artem Napolskih)__ Release 1.0.1
|
23
|
+
* 2013-10-21 [bfa328a](../../commit/bfa328a) - __(Artem Napolskih)__ feature(hash_counter): method date when called with a block, now returns the total number of lines
|
24
|
+
* 2013-10-21 [6d04c95](../../commit/6d04c95) - __(Artem Napolskih)__ Release 1.0.0
|
25
|
+
|
26
|
+
#### v1.0.0
|
27
|
+
* 2013-10-21 [b5f5344](../../commit/b5f5344) - __(Artem Napolskih)__ Release 1.0.0
|
28
|
+
* 2013-10-10 [b29eab7](../../commit/b29eab7) - __(Artem Napolskih)__ feature(unique_values_lists): added methods to read and delete data
|
29
|
+
* 2013-10-10 [67c5200](../../commit/67c5200) - __(Artem Napolskih)__ feature(unique_hash_counter): introduce unique list postfix delimiter
|
30
|
+
* 2013-10-08 [8a9a2a9](../../commit/8a9a2a9) - __(Artem Napolskih)__ feature(hash_counter): added methods to read and delete data
|
31
|
+
* 2013-09-13 [f8d037c](../../commit/f8d037c) - __(Artem Napolskih)__ docs(all): documenting
|
32
|
+
|
33
|
+
#### v1.0.0beta1
|
34
|
+
* 2013-09-13 [43016ec](../../commit/43016ec) - __(Artem Napolskih)__ Release 1.0.0beta1
|
35
|
+
* 2013-09-12 [0a176fa](../../commit/0a176fa) - __(Artem Napolskih)__ feature(all) introduce key and value delimiters
|
36
|
+
* 2013-09-12 [addbb40](../../commit/addbb40) - __(Artem Napolskih)__ feature(unique_values_list): fast (non blocking) unique values list added
|
37
|
+
* 2013-08-23 [897418d](../../commit/897418d) - __(Artem Napolskih)__ Initial commit
|
38
|
+
* 2013-08-21 [21ed53b](../../commit/21ed53b) - __(napolskih)__ dummy commit
|
data/Gemfile
ADDED
data/Makefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
BUNDLE = bundle
|
2
|
+
BUNDLE_OPTIONS = -j 4
|
3
|
+
RSPEC = ${BUNDLE} exec rspec
|
4
|
+
|
5
|
+
all: test
|
6
|
+
|
7
|
+
test: bundler/install
|
8
|
+
${RSPEC} 2>&1
|
9
|
+
|
10
|
+
bundler/install:
|
11
|
+
if ! gem list bundler -i > /dev/null; then \
|
12
|
+
gem install bundler; \
|
13
|
+
fi
|
14
|
+
${BUNDLE} install ${BUNDLE_OPTIONS}
|
data/README.md
ADDED
@@ -0,0 +1,320 @@
|
|
1
|
+
# RedisCounters
|
2
|
+
|
3
|
+
[![Dolly](http://dolly.railsc.ru/badges/abak-press/redis_counters/master)](http://dolly.railsc.ru/projects/36/builds/latest/?ref=master)
|
4
|
+
[![Code Climate](https://codeclimate.com/repos/522e9b497e00a46a0d01227c/badges/ae868ca76e52852ebc5a/gpa.png)](https://codeclimate.com/repos/522e9b497e00a46a0d01227c/feed)
|
5
|
+
[![Test Coverage](https://codeclimate.com/repos/522e9b497e00a46a0d01227c/badges/ae868ca76e52852ebc5a/coverage.svg)](https://codeclimate.com/repos/522e9b497e00a46a0d01227c/feed)
|
6
|
+
|
7
|
+
Набор структур данных на базе Redis.
|
8
|
+
|
9
|
+
## RedisCounters::HashCounter
|
10
|
+
|
11
|
+
Счетчик на основе Hash, с ~~преферансом и тайками-близняшками~~ партиционированием и кластеризацией значений.
|
12
|
+
|
13
|
+
Обязательные параметры: counter_name, field_name или group_keys.
|
14
|
+
|
15
|
+
### Сложность
|
16
|
+
+ инкремент - O(1).
|
17
|
+
|
18
|
+
### Примеры использования
|
19
|
+
|
20
|
+
Простой счетчик значений.
|
21
|
+
```ruby
|
22
|
+
counter = RedisCounters::HashCounter.new(redis, {
|
23
|
+
:counter_name => :simple_counter,
|
24
|
+
:field_name => :pages
|
25
|
+
})
|
26
|
+
|
27
|
+
5.times { counter.increment }
|
28
|
+
|
29
|
+
redis:
|
30
|
+
simple_counter = {
|
31
|
+
pages => 5
|
32
|
+
}
|
33
|
+
|
34
|
+
> counter.partitions
|
35
|
+
=> [{}]
|
36
|
+
|
37
|
+
> counter.data
|
38
|
+
=> [{:value=>5}]
|
39
|
+
```
|
40
|
+
|
41
|
+
Счетчик посещенных страниц компании с партиционированием по дате.
|
42
|
+
```ruby
|
43
|
+
counter = RedisCounters::HashCounter.new(redis, {
|
44
|
+
:counter_name => :pages_by_day,
|
45
|
+
:group_keys => [:company_id],
|
46
|
+
:partition_keys => [:date]
|
47
|
+
})
|
48
|
+
|
49
|
+
2.times { counter.increment(:company_id => 1, :date => '2013-08-01') }
|
50
|
+
3.times { counter.increment(:company_id => 2, :date => '2013-08-01') }
|
51
|
+
1.times { counter.increment(:company_id => 3, :date => '2013-08-02') }
|
52
|
+
|
53
|
+
redis:
|
54
|
+
pages_by_day:2013-08-01 = {
|
55
|
+
1 => 2
|
56
|
+
2 => 3
|
57
|
+
}
|
58
|
+
pages_by_day:2013-08-02 = {
|
59
|
+
3 => 1
|
60
|
+
}
|
61
|
+
|
62
|
+
> counter.partitions
|
63
|
+
=> [{:date=>"2013-08-01"}, {:date=>"2013-08-02"}]
|
64
|
+
|
65
|
+
> counter.data
|
66
|
+
=> [{:company_id=>"1", :value=>2},
|
67
|
+
{:company_id=>"2", :value=>3},
|
68
|
+
{:company_id=>"3", :value=>1}]
|
69
|
+
|
70
|
+
> counter.delete_partitions!(:date => '2013-08-01')
|
71
|
+
=> [1]
|
72
|
+
|
73
|
+
> counter.partitions
|
74
|
+
=> [{:date=>"2013-08-02"}]
|
75
|
+
|
76
|
+
> counter.data
|
77
|
+
=> [{:company_id=>"3", :value=>1}]
|
78
|
+
|
79
|
+
> counter.delete_all!
|
80
|
+
=> [1]
|
81
|
+
|
82
|
+
> counter.data
|
83
|
+
=> []
|
84
|
+
```
|
85
|
+
|
86
|
+
Тоже самое, но партиция задается с помощью proc.
|
87
|
+
```ruby
|
88
|
+
counter = RedisCounters::HashCounter.new(redis, {
|
89
|
+
:counter_name => :pages_by_day,
|
90
|
+
:group_keys => [:company_id],
|
91
|
+
:partition_keys => proc { |params| params.fetch(:date) }
|
92
|
+
})
|
93
|
+
```
|
94
|
+
|
95
|
+
Счетчик посещенных страниц с группировкой по городу посетителя и партиционированием по дате и компании.
|
96
|
+
```ruby
|
97
|
+
counter = RedisCounters::HashCounter.new(redis, {
|
98
|
+
:counter_name => :pages_by_day_city,
|
99
|
+
:group_keys => [:company_id, :city_id],
|
100
|
+
:partition_keys => [:date, :company_id]
|
101
|
+
})
|
102
|
+
|
103
|
+
2.times { counter.increment(:date => '2013-08-01', :company_id => 1, :city_id => 11) }
|
104
|
+
1.times { counter.increment(:date => '2013-08-01', :company_id => 1, :city_id => 12) }
|
105
|
+
4.times { counter.increment(:date => '2013-08-01', :company_id => 2, :city_id => 10) }
|
106
|
+
3.times { counter.increment(:date => '2013-08-02', :company_id => 1, :city_id => 15) }
|
107
|
+
|
108
|
+
redis:
|
109
|
+
pages_by_day_city:2013-08-01:1 = {
|
110
|
+
1:11 => 2,
|
111
|
+
1:12 => 1
|
112
|
+
}
|
113
|
+
|
114
|
+
pages_by_day_city:2013-08-01:2 = {
|
115
|
+
2:10 => 4
|
116
|
+
}
|
117
|
+
|
118
|
+
pages_by_day_city:2013-08-02:1 = {
|
119
|
+
1:15 => 3
|
120
|
+
}
|
121
|
+
|
122
|
+
> counter.partitions
|
123
|
+
=> [{:date=>"2013-08-02", :company_id=>"1"},
|
124
|
+
{:date=>"2013-08-01", :company_id=>"1"},
|
125
|
+
{:date=>"2013-08-01", :company_id=>"2"}]
|
126
|
+
|
127
|
+
> counter.partitions(:date => '2013-08-01')
|
128
|
+
=> [{:date=>"2013-08-01", :company_id=>"1"},
|
129
|
+
{:date=>"2013-08-01", :company_id=>"2"}]
|
130
|
+
|
131
|
+
> counter.data
|
132
|
+
=> [{:company_id => 1, :city_id=>"15", :value=>3},
|
133
|
+
{:company_id => 1, :city_id=>"11", :value=>2},
|
134
|
+
{:company_id => 1, :city_id=>"12", :value=>1},
|
135
|
+
{:company_id => 2, :city_id=>"10", :value=>4}]
|
136
|
+
|
137
|
+
> counter.data(:date => '2013-08-01')
|
138
|
+
=> [{:company_id => 1, :city_id=>"11", :value=>2},
|
139
|
+
{:company_id => 1, :city_id=>"12", :value=>1},
|
140
|
+
{:company_id => 2, :city_id=>"10", :value=>4}]
|
141
|
+
|
142
|
+
> counter.data(:date => '2013-08-01') { |batch| puts batch }
|
143
|
+
{:company_id => 1, :city_id=>"11", :value=>2}
|
144
|
+
{:company_id => 1, :city_id=>"12", :value=>1}
|
145
|
+
{:company_id => 2, :city_id=>"10", :value=>4}
|
146
|
+
```
|
147
|
+
|
148
|
+
## RedisCounters::UniqueValuesLists::Blocking
|
149
|
+
|
150
|
+
Список уникальных значений, с возможностью кластеризации и партиционирования значений.
|
151
|
+
|
152
|
+
Особенности:
|
153
|
+
- Использует механизм оптимистичных блокировок.
|
154
|
+
- Помимо списка значений, ведет так же, список партиций, для каждого кластера.
|
155
|
+
- Полностью транзакционен - сторонний блок, выполняемый после добавления уникального элемента,
|
156
|
+
выполняется в той же транзакции, в которой добавляется уникальный элемент.
|
157
|
+
|
158
|
+
Вероятно, в условиях большой конкурентности, обладает не лучшей производительносью из-за частых блокировок.
|
159
|
+
|
160
|
+
Обязательные параметры: counter_name и value_keys.
|
161
|
+
|
162
|
+
### Сложность
|
163
|
+
+ добавление элемента - от O(1), при отсутствии партиционирования, до O(N), где N - кол-во партиций.
|
164
|
+
|
165
|
+
### Примеры использования
|
166
|
+
|
167
|
+
Простой список уникальных пользователей.
|
168
|
+
```ruby
|
169
|
+
counter = RedisCounters::UniqueValuesLists::Blocking.new(redis, {
|
170
|
+
:counter_name => :users,
|
171
|
+
:value_keys => [:user_id]
|
172
|
+
})
|
173
|
+
|
174
|
+
counter.increment(:user_id => 1)
|
175
|
+
counter.increment(:user_id => 2)
|
176
|
+
counter.increment(:user_id => 1)
|
177
|
+
|
178
|
+
redis:
|
179
|
+
users = ['1', '2']
|
180
|
+
```
|
181
|
+
|
182
|
+
Список уникальных пользователей, посетивших компаниию, за месяц, партиционированный по суткам.
|
183
|
+
```ruby
|
184
|
+
counter = RedisCounters::UniqueValuesLists::Blocking.new(redis, {
|
185
|
+
:counter_name => :company_users_by_month,
|
186
|
+
:value_keys => [:company_id, :user_id],
|
187
|
+
:cluster_keys => [:start_month_date],
|
188
|
+
:partition_keys => [:date]
|
189
|
+
})
|
190
|
+
|
191
|
+
2.times { counter.add(:company_id => 1, :user_id => 11, :date => '2013-08-10', :start_month_date => '2013-08-01') }
|
192
|
+
3.times { counter.add(:company_id => 1, :user_id => 22, :date => '2013-08-10', :start_month_date => '2013-08-01') }
|
193
|
+
3.times { counter.add(:company_id => 1, :user_id => 22, :date => '2013-09-05', :start_month_date => '2013-09-01') }
|
194
|
+
3.times { counter.add(:company_id => 2, :user_id => 11, :date => '2013-08-10', :start_month_date => '2013-08-01') }
|
195
|
+
1.times { counter.add(:company_id => 2, :user_id => 22, :date => '2013-08-11', :start_month_date => '2013-08-01') }
|
196
|
+
|
197
|
+
redis:
|
198
|
+
company_users_by_month:2013-08-01:partitions = ['2013-08-10', '2013-08-11']
|
199
|
+
company_users_by_month:2013-08-01:2013-08-10 = ['1:11', '1:22', '2:11']
|
200
|
+
company_users_by_month:2013-08-01:2013-08-11 = ['2:22']
|
201
|
+
|
202
|
+
company_users_by_month:2013-09-01:partitions = ['2013-09-05']
|
203
|
+
company_users_by_month:2013-09-01:2013-09-05 = ['1:22']
|
204
|
+
```
|
205
|
+
|
206
|
+
## RedisCounters::UniqueValuesLists::NonBlocking
|
207
|
+
|
208
|
+
Быстрый список уникальных значений, с возможностью кластеризации и партиционирования значений.
|
209
|
+
|
210
|
+
Скорость работы достигается за счет следующих особенностей:
|
211
|
+
- Использует 2х объема памяти для хранения элементов,
|
212
|
+
при использовании партиционирования.
|
213
|
+
Eсли партиционирование не используется, то расход памяти такой-же как у UniqueValuesLists::Blocking.
|
214
|
+
- Не транзакционен - сторонний блок, выполняемый после добавления уникального элемента,
|
215
|
+
выполняется за пределами транзакции, в которой добавляется уникальный элемент.
|
216
|
+
- Не ведется список партиций.
|
217
|
+
|
218
|
+
Обязательные параметры: counter_name и value_keys.
|
219
|
+
|
220
|
+
### Сложность
|
221
|
+
+ добавление элемента - O(1)
|
222
|
+
|
223
|
+
|
224
|
+
## RedisCounters::UniqueValuesLists::Expirable
|
225
|
+
|
226
|
+
Список уникальных значений, с возможностью expire отдельных элементов.
|
227
|
+
|
228
|
+
На основе сортированного множества.
|
229
|
+
http://redis4you.com/code.php?id=010
|
230
|
+
|
231
|
+
На основе механизма оптимистических блокировок.
|
232
|
+
смотри Optimistic locking using check-and-set:
|
233
|
+
http://redis.io/topics/transactions
|
234
|
+
|
235
|
+
Особенности:
|
236
|
+
- Expire - таймаут, можно установить как на уровне счетчика,
|
237
|
+
так и на уровне отдельного занчения;
|
238
|
+
- Очистка возможна как в автоматическогом режиме так в и ручном;
|
239
|
+
- Значения сохраняет в партициях;
|
240
|
+
- Ведет список партиций;
|
241
|
+
- Полностью транзакционен.
|
242
|
+
|
243
|
+
Обязательные параметры: counter_name и value_keys.
|
244
|
+
Таймаут задается параметром :expire. По умолчанию :never.
|
245
|
+
:clean_expired - режим автоочистки. По умолчанию true.
|
246
|
+
|
247
|
+
### Примеры использования
|
248
|
+
|
249
|
+
```ruby
|
250
|
+
counter = RedisCounters::UniqueValuesLists::Expirable.new(redis,
|
251
|
+
:counter_name => :sessions,
|
252
|
+
:value_keys => [:session_id],
|
253
|
+
:expire => 10.minutes
|
254
|
+
)
|
255
|
+
|
256
|
+
counter << session_id: 1
|
257
|
+
counter << session_id: 2
|
258
|
+
counter << session_id: 3, expire: :never
|
259
|
+
|
260
|
+
counter.data
|
261
|
+
> [{session_id: 1}, {session_id: 2}, {session_id: 3}]
|
262
|
+
|
263
|
+
# after 10 minutes
|
264
|
+
|
265
|
+
counter.data
|
266
|
+
> [{session_id: 3}]
|
267
|
+
|
268
|
+
counter.has_value?(session_id: 1)
|
269
|
+
false
|
270
|
+
```
|
271
|
+
|
272
|
+
## RedisCounters::UniqueHashCounter
|
273
|
+
|
274
|
+
Сборная конструкция на основе предыдущих.
|
275
|
+
HashCounter, с возможностью подсчета только у уникальных событий.
|
276
|
+
|
277
|
+
### Сложность
|
278
|
+
аналогично сложности, используемого уникального списка.
|
279
|
+
|
280
|
+
### Примеры использования
|
281
|
+
|
282
|
+
Счетчик уникальных пользователей, посетивших компаниию, за месяц, кластеризованный по суткам.
|
283
|
+
```ruby
|
284
|
+
counter = RedisCounters::UniqueHashCounter.new(redis, {
|
285
|
+
:counter_name => :company_users_by_month,
|
286
|
+
:group_keys => [:company_id],
|
287
|
+
:partition_keys => [:date],
|
288
|
+
:unique_list => {
|
289
|
+
:list_class => RedisCounters::UniqueValuesLists::Blocking
|
290
|
+
:value_keys => [:company_id, :user_id],
|
291
|
+
:cluster_keys => [:start_month_date],
|
292
|
+
:partition_keys => [:date]
|
293
|
+
}
|
294
|
+
})
|
295
|
+
|
296
|
+
2.times { counter.increment(:company_id => 1, :user_id => 11, :date => '2013-08-10', :start_month_date => '2013-08-01') }
|
297
|
+
3.times { counter.increment(:company_id => 1, :user_id => 22, :date => '2013-08-10', :start_month_date => '2013-08-01') }
|
298
|
+
3.times { counter.increment(:company_id => 1, :user_id => 22, :date => '2013-09-05', :start_month_date => '2013-09-01') }
|
299
|
+
3.times { counter.increment(:company_id => 2, :user_id => 11, :date => '2013-08-10', :start_month_date => '2013-08-01') }
|
300
|
+
1.times { counter.increment(:company_id => 2, :user_id => 22, :date => '2013-08-11', :start_month_date => '2013-08-01') }
|
301
|
+
|
302
|
+
redis:
|
303
|
+
company_users_by_month:2013-08-10 = {
|
304
|
+
1 = 2,
|
305
|
+
2 = 1
|
306
|
+
}
|
307
|
+
company_users_by_month:2013-08-11 = {
|
308
|
+
2 = 1
|
309
|
+
}
|
310
|
+
company_users_by_month:2013-09-05 = {
|
311
|
+
1 = 1
|
312
|
+
}
|
313
|
+
|
314
|
+
company_users_by_month_uq:2013-08-01:partitions = ['2013-08-10', '2013-08-11']
|
315
|
+
company_users_by_month_uq:2013-08-01:2013-08-10 = ['1:11', '1:22', '2:11']
|
316
|
+
company_users_by_month_uq:2013-08-01:2013-08-11 = ['2:22']
|
317
|
+
|
318
|
+
company_users_by_month_uq:2013-09-01:partitions = ['2013-09-05']
|
319
|
+
company_users_by_month_uq:2013-09-01:2013-09-05 = ['1:22']
|
320
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
|
4
|
+
# load everything from tasks/ directory
|
5
|
+
Dir[File.join(File.dirname(__FILE__), 'tasks', '*.{rb,rake}')].each { |f| load(f) }
|
6
|
+
|
7
|
+
task :release => [:check, :changelog]
|
8
|
+
|
9
|
+
desc 'Check quality'
|
10
|
+
task :check => [:audit, :quality, :coverage]
|
11
|
+
|
12
|
+
require 'rspec/core/rake_task'
|
13
|
+
|
14
|
+
# setup `spec` task
|
15
|
+
RSpec::Core::RakeTask.new(:spec)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'redis_counters/version'
|
3
|
+
require 'redis_counters/base_counter'
|
4
|
+
require 'redis_counters/hash_counter'
|
5
|
+
require 'redis_counters/unique_hash_counter'
|
6
|
+
require 'redis_counters/unique_values_lists/base'
|
7
|
+
require 'redis_counters/unique_values_lists/blocking'
|
8
|
+
require 'redis_counters/unique_values_lists/non_blocking'
|
9
|
+
require 'redis_counters/unique_values_lists/expirable'
|
10
|
+
|
11
|
+
require 'active_support'
|
12
|
+
require 'active_support/core_ext'
|
13
|
+
|
14
|
+
module RedisCounters
|
15
|
+
|
16
|
+
def create_counter(redis, opts)
|
17
|
+
BaseCounter.create(redis, opts)
|
18
|
+
end
|
19
|
+
|
20
|
+
module_function :create_counter
|
21
|
+
end
|