Skip to content

Commit

Permalink
move counters to Counters namespace
Browse files Browse the repository at this point in the history
  • Loading branch information
trvsdnn committed Jan 30, 2013
1 parent c534c3f commit 853cf87
Show file tree
Hide file tree
Showing 10 changed files with 186 additions and 198 deletions.
32 changes: 8 additions & 24 deletions lib/von.rb
Expand Up @@ -3,9 +3,9 @@

require 'von/config'
require 'von/period'
require 'von/counter'
require 'von/best_counter'
require 'von/period_counter'
require 'von/counters/total'
require 'von/counters/period'
require 'von/counters/best'
require 'von/version'

module Von
Expand Down Expand Up @@ -38,42 +38,26 @@ def self.increment(field)
end

def self.increment_counts_for(field)
counter = Counter.new(field)
counter = Counters::Total.new(field)
total = counter.increment

if config.periods_defined_for_counter?(counter)
periods = config.periods[counter.field]
PeriodCounter.new(counter.field, periods).increment
Counters::Period.new(counter.field, periods).increment
elsif config.bests_defined_for_counter?(counter)
periods = config.bests[counter.field]
BestCounter.new(counter.field, periods).increment
Counters::Best.new(counter.field, periods).increment
end

total
end

# Increment the Redis count for this Counter.
# If the key has parents, increment them as well.
#
# Returns the Integer total for the key
# def self.increment(field)
# total = Counter.new(field).increment
# parents = field.sub(PARENT_REGEX, '')
#
# until parents.empty? do
# Counter.new(parents).increment
# parents.sub!(PARENT_REGEX, '')
# end
#
# total
# end

def self.count(field, period = nil)
if period.nil?
Counter.new(field).count
Counters::Total.new(field).count
else
periods = config.periods[field.to_sym]
PeriodCounter.new(field, periods).count(period)
Counters::Period.new(field, periods).count(period)
end
rescue Redis::BaseError => e
raise e if config.raise_connection_errors
Expand Down
62 changes: 0 additions & 62 deletions lib/von/best_counter.rb

This file was deleted.

46 changes: 0 additions & 46 deletions lib/von/counter.rb

This file was deleted.

63 changes: 63 additions & 0 deletions lib/von/counters/best.rb
@@ -0,0 +1,63 @@
module Von
module Counters
class Best

def initialize(field, periods = nil)
@field = field.to_sym
@periods = periods || []
end

def hash_key
@hash_key ||= "#{Von.config.namespace}:counters:bests:#{@field}"
end

def best_total(period)
Von.connection.hget("#{hash_key}:#{period}:best", 'total').to_i
end

def best_timestamp(period)
Von.connection.hget("#{hash_key}:#{period}:best", 'timestamp')
end

def current_total(period)
Von.connection.hget("#{hash_key}:#{period}:current", 'total').to_i
end

def current_timestamp(period)
Von.connection.hget("#{hash_key}:#{period}:current", 'timestamp')
end

def increment
return if @periods.empty?

@periods.each do |period|
# TODO: subclass counter (or somethin) and add hincrby/etc helpers
_current_timestamp = current_timestamp(period)
_current_total = current_total(period)

if period.timestamp != _current_timestamp
# changing current period
Von.connection.hset("#{hash_key}:#{period}:current", 'total', 1)
Von.connection.hset("#{hash_key}:#{period}:current", 'timestamp', period.timestamp)

if best_total(period) < _current_total
Von.connection.hset("#{hash_key}:#{period}:best", 'total', _current_total)
Von.connection.hset("#{hash_key}:#{period}:best", 'timestamp', _current_timestamp)
end
else
Von.connection.hincrby("#{hash_key}:#{period}:current", 'total', 1)
end
end
end

def count(period)
if current_timestamp > best_timestamp
{ current_timestamp => current_total }
else
{ best_timestamp => best_total }
end
end

end
end
end
61 changes: 61 additions & 0 deletions lib/von/counters/period.rb
@@ -0,0 +1,61 @@
module Von
module Counters
class Period

def initialize(field, periods = nil)
@field = field.to_sym
@periods = periods || []
end

# Returns the Redis hash key used for storing counts for this Period
def hash_key(period)
"#{Von.config.namespace}:counters:#{@field}:#{period}"
end

# Returns the Redis list key used for storing current "active" counters
def list_key(period)
"#{Von.config.namespace}:lists:#{@field}:#{period}"
end

def increment
return if @periods.empty?

@periods.each do |period|
_hash_key = hash_key(period)
_list_key = list_key(period)

Von.connection.hincrby(_hash_key, period.timestamp, 1)

unless Von.connection.lrange(_list_key, 0, -1).include?(period.timestamp)
Von.connection.rpush(_list_key, period.timestamp)
end

if Von.connection.llen(_list_key) > period.length
expired_counter = Von.connection.lpop(_list_key)
Von.connection.hdel(_hash_key, expired_counter)
end
end
end

# Count the fields for the given time period for this Counter.
#
# Returns an Array of Hashes representing the count
def count(period)
return if @periods.empty?

counts = []
this_period = nil
_period = @periods.select { |p| p.period == period }.first

_period.length.times do |i|
this_period = _period.prev(i)
counts.unshift(this_period)
end

keys = Von.connection.hgetall(hash_key(period))
counts.map { |date| { date => keys.fetch(date, 0).to_i }}
end

end
end
end
48 changes: 48 additions & 0 deletions lib/von/counters/total.rb
@@ -0,0 +1,48 @@
module Von
module Counters
class Total
attr_reader :field

# Initialize a new Counter
#
# field - counter field name
def initialize(field)
@field = field.to_sym
end

# Returns the Redis hash key used for storing counts for this Counter
def hash_key
"#{Von.config.namespace}:counters:#{@field}"
end

# Increment the total count for this Counter
# If the key has time periods specified, increment those.
#
# Returns the Integer total for the key
def increment
Von.connection.hincrby(hash_key, 'total', 1).to_i
end

# Count the "total" field for this Counter.
#
# Returns an Integer count
def count
count = Von.connection.hget(hash_key, 'total')
count.nil? ? 0 : count.to_i
end

# Lookup the count for this Counter in Redis.
# If a Period argument is given we lookup the count for
# all of the possible units (not expired), zeroing ones that
# aren't set in Redis already.
#
# period - A Period to lookup
#
# Returns an Integer representing the count or an Array of counts.
def self.count(field)
Counter.new(field).count
end

end
end
end

0 comments on commit 853cf87

Please sign in to comment.