redisrank 0.1.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 +7 -0
- data/.document +5 -0
- data/.gitignore +27 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +297 -0
- data/Rakefile +69 -0
- data/lib/redisrank.rb +106 -0
- data/lib/redisrank/buffer.rb +110 -0
- data/lib/redisrank/collection.rb +20 -0
- data/lib/redisrank/connection.rb +89 -0
- data/lib/redisrank/core_ext.rb +5 -0
- data/lib/redisrank/core_ext/bignum.rb +8 -0
- data/lib/redisrank/core_ext/date.rb +8 -0
- data/lib/redisrank/core_ext/fixnum.rb +8 -0
- data/lib/redisrank/core_ext/hash.rb +20 -0
- data/lib/redisrank/core_ext/time.rb +3 -0
- data/lib/redisrank/date.rb +88 -0
- data/lib/redisrank/event.rb +98 -0
- data/lib/redisrank/finder.rb +245 -0
- data/lib/redisrank/finder/date_set.rb +99 -0
- data/lib/redisrank/key.rb +84 -0
- data/lib/redisrank/label.rb +69 -0
- data/lib/redisrank/mixins/database.rb +11 -0
- data/lib/redisrank/mixins/date_helper.rb +8 -0
- data/lib/redisrank/mixins/options.rb +41 -0
- data/lib/redisrank/mixins/synchronize.rb +52 -0
- data/lib/redisrank/model.rb +77 -0
- data/lib/redisrank/result.rb +18 -0
- data/lib/redisrank/scope.rb +18 -0
- data/lib/redisrank/summary.rb +90 -0
- data/lib/redisrank/version.rb +3 -0
- data/redisrank.gemspec +31 -0
- data/spec/Find Results +3349 -0
- data/spec/buffer_spec.rb +104 -0
- data/spec/collection_spec.rb +20 -0
- data/spec/connection_spec.rb +67 -0
- data/spec/core_ext/hash_spec.rb +26 -0
- data/spec/database_spec.rb +10 -0
- data/spec/date_spec.rb +95 -0
- data/spec/event_spec.rb +86 -0
- data/spec/finder/date_set_spec.rb +527 -0
- data/spec/finder_spec.rb +205 -0
- data/spec/key_spec.rb +129 -0
- data/spec/label_spec.rb +86 -0
- data/spec/model_helper.rb +31 -0
- data/spec/model_spec.rb +191 -0
- data/spec/options_spec.rb +36 -0
- data/spec/redis-test.conf +9 -0
- data/spec/result_spec.rb +23 -0
- data/spec/scope_spec.rb +27 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/summary_spec.rb +177 -0
- data/spec/synchronize_spec.rb +125 -0
- data/spec/thread_safety_spec.rb +39 -0
- metadata +235 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 750cd449e44719036541e0fd53226339bc06da26
|
4
|
+
data.tar.gz: 808d6302c856ae4f132da7420e6c45434b94819f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 412112104821d68d5603ff6df2a629b519c61f4286cbecd10896b273bbea978b334df366b63e77cf77a613cbfbc68cc27f890f63623abf62b29a4b19a474fa96
|
7
|
+
data.tar.gz: 3e35841285088e42ffc6ba54b753aa17d9e147fef79d0639384c0dfeb072dc1f58a6c88e4419e51a7ed0129d896c880d56a7aef8d02d4ec69a553f420dfd57d4
|
data/.document
ADDED
data/.gitignore
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
## MAC OS
|
2
|
+
.DS_Store
|
3
|
+
|
4
|
+
## TEXTMATE
|
5
|
+
*.tmproj
|
6
|
+
tmtags
|
7
|
+
|
8
|
+
## EMACS
|
9
|
+
*~
|
10
|
+
\#*
|
11
|
+
.\#*
|
12
|
+
|
13
|
+
## VIM
|
14
|
+
*.swp
|
15
|
+
|
16
|
+
## PROJECT::GENERAL
|
17
|
+
coverage
|
18
|
+
rdoc
|
19
|
+
pkg/*
|
20
|
+
*.gem
|
21
|
+
.bundle
|
22
|
+
Gemfile.lock
|
23
|
+
|
24
|
+
## PROJECT::SPECIFIC
|
25
|
+
.yardoc/*
|
26
|
+
spec/db/*
|
27
|
+
doc/*
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Jim Myhrberg.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,297 @@
|
|
1
|
+
A Redis-backed statistics storage and querying library written in Ruby.
|
2
|
+
|
3
|
+
Redisrank was created taking as reference a Gem called Redistat by Jimeh.
|
4
|
+
The motivations for the gem creation were similar to the Redistat too, I had a
|
5
|
+
collection solution which was MySQL-based with the following requirements.
|
6
|
+
|
7
|
+
* Fetch the top most ...
|
8
|
+
* This ranks should be fetched in any time-range
|
9
|
+
* Screamingly fast
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
gem install redisrank
|
14
|
+
|
15
|
+
If you are using Ruby 1.8.x, it's recommended you also install the
|
16
|
+
`SystemTimer` gem, as the Redis gem will otherwise complain.
|
17
|
+
|
18
|
+
## Usage (Crash Course)
|
19
|
+
|
20
|
+
view\_stats.rb:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
require 'redisrank'
|
24
|
+
|
25
|
+
class ViewRank
|
26
|
+
include Redisrank::Model
|
27
|
+
end
|
28
|
+
|
29
|
+
# if using Redisrank in multiple threads set this
|
30
|
+
# somewhere in the beginning of the execution stack
|
31
|
+
Redisrank.thread_safe = true
|
32
|
+
```
|
33
|
+
|
34
|
+
|
35
|
+
### Simple Example
|
36
|
+
|
37
|
+
Store:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
ViewRank.store('hello', {:world => 4})
|
41
|
+
ViewRank.store('hello', {:world => 2}, 2.hours.ago)
|
42
|
+
```
|
43
|
+
|
44
|
+
Fetch:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
ViewRank.find('hello', 1.hour.ago, 1.hour.from_now).all
|
48
|
+
#=> [{'world' => 4}]
|
49
|
+
ViewRank.find('hello', 3.hour.ago, 1.hour.from_now).rank
|
50
|
+
#=> {'world' => 4}
|
51
|
+
ViewRank.find('hello', 3.hour.ago, 1.hour.ago).rank
|
52
|
+
#=> {'world' => 2}
|
53
|
+
```
|
54
|
+
|
55
|
+
### Other usefull Use Cases
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
## Terminology
|
60
|
+
|
61
|
+
### Scope
|
62
|
+
|
63
|
+
A type of global-namespace for storing data. When using the `Redisrank::Model`
|
64
|
+
wrapper, the scope is automatically set to the class name. In the examples
|
65
|
+
above, the scope is `ViewRank`. Can be overridden by calling the `#scope`
|
66
|
+
class method on your model class.
|
67
|
+
|
68
|
+
### Label
|
69
|
+
|
70
|
+
Identifier string to separate different types and groups of statistics from
|
71
|
+
each other. The first argument of the `#store`, `#find`, and `#fetch` methods
|
72
|
+
is the label that you're storing to, or fetching from.
|
73
|
+
|
74
|
+
Labels support multiple grouping levels by splitting the label string with `/`
|
75
|
+
and storing the same stats for each level. For example, when storing data to a
|
76
|
+
label called `views/product/44`, the data is stored for the label you specify,
|
77
|
+
and also for `views/product` and `views`. You may also configure a different
|
78
|
+
group separator using the `Redisrank.group_separator=` method. For example:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
Redisrank.group_separator = '|'
|
82
|
+
```
|
83
|
+
|
84
|
+
A word of caution: Don't use a crazy number of group levels. As two levels
|
85
|
+
causes twice as many `hincrby` calls to Redis as not using the grouping
|
86
|
+
feature. Hence using 10 grouping levels, causes 10 times as many write calls
|
87
|
+
to Redis.
|
88
|
+
|
89
|
+
### Input Statistics Data
|
90
|
+
|
91
|
+
You provide Redisrank with the data you want to store using a Ruby Hash. This
|
92
|
+
data is then stored in a corresponding Redis hash with identical key/field
|
93
|
+
names.
|
94
|
+
|
95
|
+
Key names in the hash also support grouping features similar to those
|
96
|
+
available for Labels. Again, the more levels you use, the more write calls to
|
97
|
+
Redis, so avoid using 10-15 levels.
|
98
|
+
|
99
|
+
### Depth (Storage Accuracy)
|
100
|
+
|
101
|
+
Define how accurately data should be stored, and how accurately it's looked up
|
102
|
+
when fetching it again. By default Redisrank uses a depth value of `:hour`,
|
103
|
+
which means it's impossible to separate two events which were stored at 10:18
|
104
|
+
and 10:23. In Redis they are both stored within a date key of `2011031610`.
|
105
|
+
|
106
|
+
You can set depth within your model using the `#depth` class method. Available
|
107
|
+
depths are: `:year`, `:month`, `:day`, `:hour`, `:min`, `:sec`
|
108
|
+
|
109
|
+
### Time Ranges
|
110
|
+
|
111
|
+
When you fetch data, you need to specify a start and an end time. The
|
112
|
+
selection behavior can seem a bit weird at first when, but makes sense when
|
113
|
+
you understand how Redisrank works internally.
|
114
|
+
|
115
|
+
For example, if we are using a Depth value of `:hour`, and we trigger a fetch
|
116
|
+
call starting at `1.hour.ago` (13:34), till `Time.now` (14:34), only stats
|
117
|
+
from 13:00:00 till 13:59:59 are returned, as they were all stored within the
|
118
|
+
key for the 13th hour. If both 13:00 and 14:00 was returned, you would get
|
119
|
+
results from two whole hours. Hence if you want up to the second data, use an
|
120
|
+
end time of `1.hour.from_now`.
|
121
|
+
|
122
|
+
### The Finder Object
|
123
|
+
|
124
|
+
Calling the `#find` method on a Redisrank model class returns a
|
125
|
+
`Redisrank::Finder` object. The finder is a lazy-loaded gateway to your
|
126
|
+
data. Meaning you can create a new finder, and modify instantiated finder's
|
127
|
+
label, scope, dates, and more. It does not call Redis and fetch the data until
|
128
|
+
you call `#total`, `#all`, `#map`, `#each`, or `#each_with_index` on the
|
129
|
+
finder.
|
130
|
+
|
131
|
+
This section does need further expanding as there's a lot to cover when it
|
132
|
+
comes to the finder.
|
133
|
+
|
134
|
+
|
135
|
+
## Key Expiry
|
136
|
+
|
137
|
+
Support for expiring keys from Redis is available, allowing you too keep
|
138
|
+
varying levels of details for X period of time. This allows you easily keep
|
139
|
+
things nice and tidy by only storing varying levels detailed stats only for as
|
140
|
+
long as you need.
|
141
|
+
|
142
|
+
In the below example we define how long Redis keys for varying depths are
|
143
|
+
stored. Second by second stats are available for 10 minutes, minute by minute
|
144
|
+
stats for 6 hours, hourly stats for 3 months, daily stats for 2 years, and
|
145
|
+
yearly stats are retained forever.
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
class ViewRank
|
149
|
+
include Redisrank::Model
|
150
|
+
|
151
|
+
depth :sec
|
152
|
+
|
153
|
+
expire \
|
154
|
+
:sec => 10.minutes.to_i,
|
155
|
+
:min => 6.hours.to_i,
|
156
|
+
:hour => 3.months.to_i,
|
157
|
+
:day => 2.years.to_i
|
158
|
+
end
|
159
|
+
```
|
160
|
+
|
161
|
+
Keep in mind that when storing stats for a custom date in the past for
|
162
|
+
example, the expiry time for the keys will be relative to now. The values you
|
163
|
+
specify are simply passed to the `Redis#expire` method.
|
164
|
+
|
165
|
+
|
166
|
+
## Internals
|
167
|
+
|
168
|
+
### Storing / Writing
|
169
|
+
|
170
|
+
Redisrank stores all data into a Redis hash keys. The Redis key name the used
|
171
|
+
consists of three parts. The scope, label, and datetime:
|
172
|
+
|
173
|
+
{scope}/{label}:{datetime}
|
174
|
+
|
175
|
+
For example, this...
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
ViewRank.store('views/product/44', {'count/chrome/11' => 1})
|
179
|
+
```
|
180
|
+
|
181
|
+
...would store the follow hash of data...
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
{ 'count' => 1, 'count/chrome' => 1, 'count/chrome/11' => 1 }
|
185
|
+
```
|
186
|
+
|
187
|
+
...to all 12 of these Redis hash keys...
|
188
|
+
|
189
|
+
ViewRank/views:2011
|
190
|
+
ViewRank/views:201103
|
191
|
+
ViewRank/views:20110315
|
192
|
+
ViewRank/views:2011031510
|
193
|
+
ViewRank/views/product:2011
|
194
|
+
ViewRank/views/product:201103
|
195
|
+
ViewRank/views/product:20110315
|
196
|
+
ViewRank/views/product:2011031510
|
197
|
+
ViewRank/views/product/44:2011
|
198
|
+
ViewRank/views/product/44:201103
|
199
|
+
ViewRank/views/product/44:20110315
|
200
|
+
ViewRank/views/product/44:2011031510
|
201
|
+
|
202
|
+
...by creating the Redis key, and/or hash field if needed, otherwise it simply
|
203
|
+
increments the already existing data.
|
204
|
+
|
205
|
+
It would also create the following Redis sets to keep track of which child
|
206
|
+
labels are available:
|
207
|
+
|
208
|
+
ViewRank.label_index:
|
209
|
+
ViewRank.label_index:views
|
210
|
+
ViewRank.label_index:views/product
|
211
|
+
|
212
|
+
It should now be more obvious to you why you should think about how you use
|
213
|
+
the grouping capabilities so you don't go crazy and use 10-15 levels. Storing
|
214
|
+
is done through Redis' `hincrby` call, which only supports a single key/field
|
215
|
+
combo. Meaning the above example would call `hincrby` a total of 36 times to
|
216
|
+
store the data, and `sadd` a total of 3 times to ensure the label index is
|
217
|
+
accurate. 39 calls is however not a problem for Redis, most calls happen in
|
218
|
+
less than 0.15ms (0.00015 seconds) on my local machine.
|
219
|
+
|
220
|
+
|
221
|
+
### Fetching / Reading
|
222
|
+
|
223
|
+
By default when fetching statistics, Redisrank will figure out how to do the
|
224
|
+
least number of reads from Redis. First it checks how long range you're
|
225
|
+
fetching. If whole days, months or years for example fit within the start and
|
226
|
+
end dates specified, it will fetch the one key for the day/month/year in
|
227
|
+
question. It further drills down to the smaller units.
|
228
|
+
|
229
|
+
It is also intelligent enough to not fetch each day from 3-31 of a month,
|
230
|
+
instead it would fetch the data for the whole month and the first two days,
|
231
|
+
which are then removed from the summary of the whole month. This means three
|
232
|
+
calls to `hgetall` instead of 29 if each whole day was fetched.
|
233
|
+
|
234
|
+
### Buffer
|
235
|
+
|
236
|
+
The buffer is a new, still semi-beta, feature aimed to reduce the number of
|
237
|
+
Redis `hincrby` that Redisrank sends. This should only really be useful when
|
238
|
+
you're hitting north of 30,000 Redis requests per second, if your Redis server
|
239
|
+
has limited resources, or against my recommendation you've opted to use 10,
|
240
|
+
20, or more label grouping levels.
|
241
|
+
|
242
|
+
Buffering tries to fold together multiple `store` calls into as few as
|
243
|
+
possible by merging the statistics hashes from all calls and groups them based
|
244
|
+
on scope, label, date depth, and more. You configure the the buffer by setting
|
245
|
+
`Redisrank.buffer_size` to an integer higher than 1. This basically tells
|
246
|
+
Redisrank how many `store` calls to buffer in memory before writing all data to
|
247
|
+
Redis.
|
248
|
+
|
249
|
+
|
250
|
+
## Todo
|
251
|
+
|
252
|
+
* More details in Readme.
|
253
|
+
* Documentation.
|
254
|
+
* Anything else that becomes apparent after real-world use.
|
255
|
+
|
256
|
+
|
257
|
+
## Credits
|
258
|
+
|
259
|
+
[Encore Alert](http://encorealert.com/) that allowed me to spend some
|
260
|
+
company time to further develop the project. @jimeh for creating the Redistat
|
261
|
+
that was not a inspiration but the base version of Redisrank.
|
262
|
+
|
263
|
+
|
264
|
+
## Note on Patches/Pull Requests
|
265
|
+
|
266
|
+
* Fork the project.
|
267
|
+
* Make your feature addition or bug fix.
|
268
|
+
* Add tests for it. This is important so I don't break it in a
|
269
|
+
future version unintentionally.
|
270
|
+
* Commit, do not mess with rakefile, version, or history. (if you want to
|
271
|
+
have your own version, that is fine but bump version in a commit by itself I
|
272
|
+
can ignore when I pull)
|
273
|
+
* Send me a pull request. Bonus points for topic branches.
|
274
|
+
|
275
|
+
|
276
|
+
## License and Copyright
|
277
|
+
|
278
|
+
Copyright (c) 2011 Jim Myhrberg.
|
279
|
+
|
280
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
281
|
+
a copy of this software and associated documentation files (the
|
282
|
+
"Software"), to deal in the Software without restriction, including
|
283
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
284
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
285
|
+
permit persons to whom the Software is furnished to do so, subject to
|
286
|
+
the following conditions:
|
287
|
+
|
288
|
+
The above copyright notice and this permission notice shall be
|
289
|
+
included in all copies or substantial portions of the Software.
|
290
|
+
|
291
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
292
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
293
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
294
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
295
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
296
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
297
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
|
5
|
+
#
|
6
|
+
# Rspec
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'rspec/core/rake_task'
|
10
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
11
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
12
|
+
end
|
13
|
+
|
14
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
15
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
16
|
+
spec.rcov = true
|
17
|
+
spec.rcov_opts = ['--exclude', 'spec']
|
18
|
+
end
|
19
|
+
|
20
|
+
task :default => [:start, :spec, :stop]
|
21
|
+
|
22
|
+
|
23
|
+
#
|
24
|
+
# Start/stop Redis test server
|
25
|
+
#
|
26
|
+
|
27
|
+
REDIS_DIR = File.expand_path(File.join("..", "spec"), __FILE__)
|
28
|
+
REDIS_CNF = File.join(REDIS_DIR, "redis-test.conf")
|
29
|
+
REDIS_PID = File.join(REDIS_DIR, "db", "redis.pid")
|
30
|
+
|
31
|
+
desc "Start the Redis test server"
|
32
|
+
task :start do
|
33
|
+
unless File.exists?(REDIS_PID)
|
34
|
+
system "redis-server #{REDIS_CNF}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "Stop the Redis test server"
|
39
|
+
task :stop do
|
40
|
+
if File.exists?(REDIS_PID)
|
41
|
+
system "kill #{File.read(REDIS_PID)}"
|
42
|
+
system "rm #{REDIS_PID}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
#
|
48
|
+
# Yard
|
49
|
+
#
|
50
|
+
|
51
|
+
begin
|
52
|
+
require 'yard'
|
53
|
+
YARD::Rake::YardocTask.new
|
54
|
+
rescue LoadError
|
55
|
+
task :yardoc do
|
56
|
+
abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
#
|
62
|
+
# Misc.
|
63
|
+
#
|
64
|
+
|
65
|
+
desc "Start an irb console with Redisrank pre-loaded."
|
66
|
+
task :console do
|
67
|
+
exec "irb -r spec/spec_helper"
|
68
|
+
end
|
69
|
+
task :c => :console
|
data/lib/redisrank.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'date'
|
4
|
+
require 'time'
|
5
|
+
require 'digest/sha1'
|
6
|
+
require 'monitor'
|
7
|
+
|
8
|
+
# Active Support 2.x or 3.x
|
9
|
+
require 'active_support'
|
10
|
+
if !{}.respond_to?(:with_indifferent_access)
|
11
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
12
|
+
require 'active_support/core_ext/hash/reverse_merge'
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'time_ext'
|
16
|
+
require 'redis'
|
17
|
+
require 'json'
|
18
|
+
|
19
|
+
require 'redisrank/mixins/options'
|
20
|
+
require 'redisrank/mixins/synchronize'
|
21
|
+
require 'redisrank/mixins/database'
|
22
|
+
require 'redisrank/mixins/date_helper'
|
23
|
+
|
24
|
+
require 'redisrank/connection'
|
25
|
+
require 'redisrank/buffer'
|
26
|
+
require 'redisrank/collection'
|
27
|
+
require 'redisrank/date'
|
28
|
+
require 'redisrank/event'
|
29
|
+
require 'redisrank/finder'
|
30
|
+
require 'redisrank/key'
|
31
|
+
require 'redisrank/label'
|
32
|
+
require 'redisrank/model'
|
33
|
+
require 'redisrank/result'
|
34
|
+
require 'redisrank/scope'
|
35
|
+
require 'redisrank/summary'
|
36
|
+
require 'redisrank/version'
|
37
|
+
|
38
|
+
require 'redisrank/core_ext'
|
39
|
+
|
40
|
+
|
41
|
+
module Redisrank
|
42
|
+
|
43
|
+
KEY_NEXT_ID = ".next_id"
|
44
|
+
KEY_EVENT = ".event:"
|
45
|
+
KEY_LABELS = "Redisrank.labels:" # used for reverse label hash lookup
|
46
|
+
KEY_EVENT_IDS = ".event_ids"
|
47
|
+
LABEL_INDEX = ".label_index:"
|
48
|
+
GROUP_SEPARATOR = "/"
|
49
|
+
|
50
|
+
class InvalidOptions < ArgumentError; end
|
51
|
+
class RedisServerIsTooOld < Exception; end
|
52
|
+
|
53
|
+
class << self
|
54
|
+
|
55
|
+
def buffer
|
56
|
+
Buffer.instance
|
57
|
+
end
|
58
|
+
|
59
|
+
def buffer_size
|
60
|
+
buffer.size
|
61
|
+
end
|
62
|
+
|
63
|
+
def buffer_size=(size)
|
64
|
+
buffer.size = size
|
65
|
+
end
|
66
|
+
|
67
|
+
def thread_safe
|
68
|
+
Synchronize.thread_safe
|
69
|
+
end
|
70
|
+
|
71
|
+
def thread_safe=(value)
|
72
|
+
Synchronize.thread_safe = value
|
73
|
+
end
|
74
|
+
|
75
|
+
def connection(ref = nil)
|
76
|
+
Connection.get(ref)
|
77
|
+
end
|
78
|
+
alias :redis :connection
|
79
|
+
|
80
|
+
def connection=(connection)
|
81
|
+
Connection.add(connection)
|
82
|
+
end
|
83
|
+
alias :redis= :connection=
|
84
|
+
|
85
|
+
def connect(options)
|
86
|
+
Connection.create(options)
|
87
|
+
end
|
88
|
+
|
89
|
+
def flush
|
90
|
+
puts "WARNING: Redisrank.flush is deprecated. Use Redisrank.redis.flushdb instead."
|
91
|
+
connection.flushdb
|
92
|
+
end
|
93
|
+
|
94
|
+
def group_separator
|
95
|
+
@group_separator ||= GROUP_SEPARATOR
|
96
|
+
end
|
97
|
+
attr_writer :group_separator
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
# ensure buffer is flushed on program exit
|
104
|
+
Kernel.at_exit do
|
105
|
+
Redisrank.buffer.flush(true)
|
106
|
+
end
|