mirror of
https://github.com/jimeh/redistat.git
synced 2026-02-19 13:26:39 +00:00
Merge branch 'key-expiry'
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
|
language: ruby
|
||||||
rvm:
|
rvm:
|
||||||
- 1.8.7
|
- 1.8.7
|
||||||
- 1.9.2
|
- 1.9.2
|
||||||
- jruby
|
- 1.9.3
|
||||||
|
- jruby-18mode
|
||||||
|
- jruby-19mode
|
||||||
- ree
|
- ree
|
||||||
|
|||||||
30
README.md
30
README.md
@@ -202,6 +202,36 @@ This section does need further expanding as there's a lot to cover when it
|
|||||||
comes to the finder.
|
comes to the finder.
|
||||||
|
|
||||||
|
|
||||||
|
## Key Expiry
|
||||||
|
|
||||||
|
Support for expiring keys from Redis is available, allowing you too keep
|
||||||
|
varying levels of details for X period of time. This allows you easily keep
|
||||||
|
things nice and tidy by only storing varying levels detailed stats only for as
|
||||||
|
long as you need.
|
||||||
|
|
||||||
|
In the below example we define how long Redis keys for varying depths are
|
||||||
|
stored. Second by second stats are available for 10 minutes, minute by minute
|
||||||
|
stats for 6 hours, hourly stats for 3 months, daily stats for 2 years, and
|
||||||
|
yearly stats are retained forever.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
class ViewStats
|
||||||
|
include Redistat::Model
|
||||||
|
|
||||||
|
depth :sec
|
||||||
|
|
||||||
|
expire \
|
||||||
|
:sec => 10.minutes.to_i,
|
||||||
|
:min => 6.hours.to_i,
|
||||||
|
:hour => 3.months.to_i,
|
||||||
|
:day => 2.years.to_i
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Keep in mind that when storing stats for a custom date in the past for
|
||||||
|
example, the expiry time for the keys will be relative to now. The values you
|
||||||
|
specify are simply passed to the `Redis#expire` method.
|
||||||
|
|
||||||
|
|
||||||
## Internals
|
## Internals
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ module Redistat
|
|||||||
module Connection
|
module Connection
|
||||||
|
|
||||||
REQUIRED_SERVER_VERSION = "1.3.10"
|
REQUIRED_SERVER_VERSION = "1.3.10"
|
||||||
|
MIN_EXPIRE_SERVER_VERSION = "2.1.3"
|
||||||
|
|
||||||
# TODO: Create a ConnectionPool instance object using Sychronize mixin to replace Connection class
|
# TODO: Create a ConnectionPool instance object using Sychronize mixin to replace Connection class
|
||||||
|
|
||||||
@@ -67,6 +68,10 @@ module Redistat
|
|||||||
|
|
||||||
def check_redis_version(conn)
|
def check_redis_version(conn)
|
||||||
raise RedisServerIsTooOld if conn.info["redis_version"] < REQUIRED_SERVER_VERSION
|
raise RedisServerIsTooOld if conn.info["redis_version"] < REQUIRED_SERVER_VERSION
|
||||||
|
if conn.info["redis_version"] < MIN_EXPIRE_SERVER_VERSION
|
||||||
|
STDOUT.puts "WARNING: You MUST upgrade Redis to v2.1.3 or later " +
|
||||||
|
"if you are using key expiry."
|
||||||
|
end
|
||||||
conn
|
conn
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,14 @@ module Redistat
|
|||||||
|
|
||||||
alias :class_name :scope
|
alias :class_name :scope
|
||||||
|
|
||||||
|
def expire(exp = nil)
|
||||||
|
if !exp.nil?
|
||||||
|
options[:expire] = exp.is_a?(Hash) ? exp : Hash.new(exp)
|
||||||
|
else
|
||||||
|
options[:expire]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def connect_to(opts = {})
|
def connect_to(opts = {})
|
||||||
Connection.create(opts.merge(:ref => name))
|
Connection.create(opts.merge(:ref => name))
|
||||||
options[:connection_ref] = name
|
options[:connection_ref] = name
|
||||||
|
|||||||
@@ -5,9 +5,12 @@ module Redistat
|
|||||||
class << self
|
class << self
|
||||||
|
|
||||||
def default_options
|
def default_options
|
||||||
{ :enable_grouping => true,
|
{
|
||||||
:label_indexing => true,
|
:enable_grouping => true,
|
||||||
:connection_ref => nil }
|
:label_indexing => true,
|
||||||
|
:connection_ref => nil,
|
||||||
|
:expire => {}
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def buffer
|
def buffer
|
||||||
@@ -29,30 +32,34 @@ module Redistat
|
|||||||
update(*args) unless buffer.store(*args)
|
update(*args) unless buffer.store(*args)
|
||||||
end
|
end
|
||||||
|
|
||||||
def update(key, stats, depth_limit, opts)
|
def update(key, stats, depth_limit, opts = {})
|
||||||
if opts[:enable_grouping]
|
if opts[:enable_grouping]
|
||||||
stats = inject_group_summaries(stats)
|
stats = inject_group_summaries(stats)
|
||||||
key.groups.each do |k|
|
key.groups.each do |k|
|
||||||
update_key(k, stats, depth_limit, opts[:connection_ref])
|
update_key(k, stats, depth_limit, opts)
|
||||||
k.update_index if opts[:label_indexing]
|
k.update_index if opts[:label_indexing]
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
update_key(key, stats, depth_limit, opts[:connection_ref])
|
update_key(key, stats, depth_limit, opts)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def update_key(key, stats, depth_limit, connection_ref)
|
def update_key(key, stats, depth_limit, opts = {})
|
||||||
Date::DEPTHS.each do |depth|
|
Date::DEPTHS.each do |depth|
|
||||||
update_fields(key, stats, depth, connection_ref)
|
update_fields(key, stats, depth, opts)
|
||||||
break if depth == depth_limit
|
break if depth == depth_limit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_fields(key, stats, depth, connection_ref = nil)
|
def update_fields(key, stats, depth, opts = {})
|
||||||
stats.each do |field, value|
|
stats.each do |field, value|
|
||||||
db(connection_ref).hincrby key.to_s(depth), field, value
|
db(opts[:connection_ref]).hincrby key.to_s(depth), field, value
|
||||||
|
end
|
||||||
|
|
||||||
|
if opts[:expire] && !opts[:expire][depth].nil?
|
||||||
|
db(opts[:connection_ref]).expire key.to_s(depth), opts[:expire][depth]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -26,5 +26,6 @@ class ModelHelper4
|
|||||||
include Redistat::Model
|
include Redistat::Model
|
||||||
|
|
||||||
scope "FancyHelper"
|
scope "FancyHelper"
|
||||||
|
expire :hour => 24*3600
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ describe Redistat::Model do
|
|||||||
ModelHelper2.store_event.should == true
|
ModelHelper2.store_event.should == true
|
||||||
ModelHelper2.hashed_label.should == true
|
ModelHelper2.hashed_label.should == true
|
||||||
ModelHelper2.scope.should be_nil
|
ModelHelper2.scope.should be_nil
|
||||||
|
ModelHelper2.expire.should be_nil
|
||||||
|
|
||||||
ModelHelper1.depth.should == nil
|
ModelHelper1.depth.should == nil
|
||||||
ModelHelper1.store_event.should == nil
|
ModelHelper1.store_event.should == nil
|
||||||
@@ -57,6 +58,7 @@ describe Redistat::Model do
|
|||||||
|
|
||||||
ModelHelper4.scope.should == "FancyHelper"
|
ModelHelper4.scope.should == "FancyHelper"
|
||||||
ModelHelper4.send(:name).should == "FancyHelper"
|
ModelHelper4.send(:name).should == "FancyHelper"
|
||||||
|
ModelHelper4.expire.should == {:hour => 24*3600}
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should store and fetch stats" do
|
it "should store and fetch stats" do
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ describe Redistat::Summary do
|
|||||||
@date = Time.now
|
@date = Time.now
|
||||||
@key = Redistat::Key.new(@scope, @label, @date, {:depth => :day})
|
@key = Redistat::Key.new(@scope, @label, @date, {:depth => :day})
|
||||||
@stats = {"views" => 3, "visitors" => 2}
|
@stats = {"views" => 3, "visitors" => 2}
|
||||||
|
@expire = {:hour => 24*3600}
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should update a single summary properly" do
|
it "should update a single summary properly" do
|
||||||
@@ -32,6 +33,20 @@ describe Redistat::Summary do
|
|||||||
summary["visitors"].should == "1"
|
summary["visitors"].should == "1"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should set key expiry properly" do
|
||||||
|
Redistat::Summary.update_all(@key, @stats, :hour,{:expire => @expire})
|
||||||
|
((24*3600)-1..(24*3600)+1).should include(db.ttl(@key.to_s(:hour)))
|
||||||
|
[:day, :month, :year].each do |depth|
|
||||||
|
db.ttl(@key.to_s(depth)).should == -1
|
||||||
|
end
|
||||||
|
|
||||||
|
db.flushdb
|
||||||
|
Redistat::Summary.update_all(@key, @stats, :hour, {:expire => {}})
|
||||||
|
[:hour, :day, :month, :year].each do |depth|
|
||||||
|
db.ttl(@key.to_s(depth)).should == -1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "should update all summaries properly" do
|
it "should update all summaries properly" do
|
||||||
Redistat::Summary.update_all(@key, @stats, :sec)
|
Redistat::Summary.update_all(@key, @stats, :sec)
|
||||||
[:year, :month, :day, :hour, :min, :sec, :usec].each do |depth|
|
[:year, :month, :day, :hour, :min, :sec, :usec].each do |depth|
|
||||||
|
|||||||
Reference in New Issue
Block a user