Skip to content

Commit

Permalink
Merge pull request #23 from remotezygote/performance-greatly-improved
Browse files Browse the repository at this point in the history
Performance greatly improved
  • Loading branch information
John Bragg committed Dec 3, 2013
2 parents 339ba3d + 1d73645 commit 7b3fd45
Show file tree
Hide file tree
Showing 30 changed files with 223 additions and 155 deletions.
4 changes: 2 additions & 2 deletions lib/redis_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ class RedisObject
include Seabright::CachedScripts
include Seabright::Storage
include Seabright::Keys
include Seabright::Types
include Seabright::DefaultValues
include Seabright::Indices
include Seabright::Collections
include Seabright::Types
include Seabright::Triggers
include Seabright::Indices
include Seabright::Views
include Seabright::ViewCaching
include Seabright::Timestamps
Expand Down
45 changes: 44 additions & 1 deletion lib/redis_object/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,13 @@ def raw
alias_method :actual, :raw

def get(k)
cached_hash_values[k.to_s] ||= _get(k)
filter_gotten_value(k, (cached_hash_values[k.to_s] || _get(k)))
end

def filter_gotten_value(k,v)
self.class.get_filters.inject(v) do |acc, filter|
filter.call(self, k, acc)
end
end

def _get(k)
Expand All @@ -92,6 +98,9 @@ def is_set?(k)
end

def mset(dat)
dat = self.class.mset_filters.inject(dat) do |acc,filter|
filter.call(self, acc)
end
store.hmset(hkey, *(dat.inject([]){|acc,(k,v)| acc << [k,v] }.flatten))
cached_hash_values.merge!(dat)
dat.each do |k,v|
Expand All @@ -115,6 +124,9 @@ def undefine_setter_getter(key)
end

def set(k,v)
(k,v) = self.class.set_filters.inject([k,v]) do |acc,filter|
filter.call(self,*acc) unless acc.nil? or acc[0].nil?
end
return nil if k.nil?
return set_ref(k,v) if v.is_a?(RedisObject)
store.hset(hkey, k.to_s, v.to_s)
Expand Down Expand Up @@ -151,6 +163,9 @@ def get_reference(hkey)
end

def setnx(k,v)
(k,v) = self.class.set_filters.inject([k,v]) do |acc,filter|
filter.call(self,*acc)
end
if success = store.hsetnx(hkey, k.to_s, v.to_s)
cached_hash_values[k.to_s] = v
define_setter_getter(k)
Expand Down Expand Up @@ -216,6 +231,34 @@ def undefine_access(key)

module ClassMethods

def action_filters
@@action_filters ||= {}
end

def set_filters
action_filters[:set] ||= []
end

def filter_sets(&block)
set_filters << block
end

def mset_filters
action_filters[:mset] ||= []
end

def filter_msets(&block)
mset_filters << block
end

def get_filters
action_filters[:get] ||= []
end

def filter_gets(&block)
get_filters << block
end

def clean_id(i)
i.to_s.gsub(/.*:/,'').gsub(/_h$/,'')
end
Expand Down
102 changes: 61 additions & 41 deletions lib/redis_object/collection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,6 @@ def hkey_col(ident = nil)
"#{hkey}:collections"
end

def load(o_id)
super(o_id)
store.smembers(hkey_col).each do |name|
collections[name] = Seabright::Collection.load(name,self)
define_access(name) do
get_collection(name)
end
define_access(name.to_s.singularize) do
get_collection(name).latest
end
end
true
end

def delete_child(obj)
if col = get_collection(obj.collection_name)
col.delete obj
Expand Down Expand Up @@ -78,14 +64,18 @@ def dereference_from_backreferences
end
end

def get(k)
if has_collection?(k)
get_collection(k)
elsif has_collection?(pk = k.to_s.pluralize)
get_collection(pk).first
else
super(k)
def load(o_id)
super(o_id)
store.smembers(hkey_col).each do |name|
collections[name] = Seabright::Collection.load(name,self)
define_access(name) do
get_collection(name)
end
define_access(name.to_s.singularize) do
get_collection(name).latest
end
end
true
end

def has_collection?(name)
Expand All @@ -97,13 +87,13 @@ def get_collection(name)
collections[name.to_s] ||= Collection.load(name,self)
else
store.sadd hkey_col, name
@collection_names << name.to_s
collection_names << name.to_s
collections[name.to_s] ||= Collection.load(name,self)
define_access(name.to_s.pluralize) do
get_collection(name)
end
define_access(name.to_s.singularize) do
get_collection(name).latest
get_collection(name).first
end
end
collections[name.to_s]
Expand All @@ -117,16 +107,6 @@ def collection_names
@collection_names ||= store.smembers(hkey_col)
end

def mset(dat)
dat.select! {|k,v| !collections[k.to_s] }
super(dat)
end

def set(k,v)
@data ? super(k,v) : has_collection?(k) ? get_collection(k.to_s).replace(v) : super(k,v)
v
end

def collect_type_by_key(col,*keys)
collect = get_collection(col)
keys.each do |k|
Expand All @@ -136,6 +116,37 @@ def collect_type_by_key(col,*keys)

module ClassMethods

def intercept_sets_for_collecting!
return if @intercepted_sets_for_collecting
self.class_eval do

filter_gets do |obj, k, v|
if obj.has_collection?(k)
obj.get_collection(k)
elsif obj.has_collection?(pk = k.to_s.pluralize)
obj.get_collection(pk).first
else
v
end
end

filter_sets do |obj, k, v|
if obj.has_collection?(k)
obj.get_collection(k.to_s).replace(v)
return [nil,nil]
else
[k,v]
end
end

filter_msets do |obj, dat|
dat.select {|k,v| !obj.collections[k.to_s] }
end

end
@intercepted_sets_for_collecting = true
end

def hkey_col(ident = nil)
"#{hkey(ident)}:collections"
end
Expand Down Expand Up @@ -170,12 +181,11 @@ def remove_collection!(name)

def get(k)
if has_collection?(k)
get_collection(k)
return get_collection(k)
elsif has_collection?(pk = k.to_s.pluralize)
get_collection(pk).first
else
super(k)
return get_collection(pk).first
end
nil
end

def has_collection?(name)
Expand All @@ -195,6 +205,7 @@ def collections

def self.included(base)
base.extend(ClassMethods)
base.intercept_sets_for_collecting!
end

end
Expand Down Expand Up @@ -238,12 +249,18 @@ def temp_key
"#{key}::zintersect_temp::#{RedisObject.new_id(4)}"
end

RedisObject::ScriptSources::FwdScript = "redis.call('ZINTERSTORE', KEYS[1], 2, KEYS[2], KEYS[3], 'WEIGHTS', 1, 0)\nlocal keys = redis.call('ZRANGE', KEYS[1], 0, KEYS[4])\nredis.call('DEL', KEYS[1])\nreturn keys".freeze
RedisObject::ScriptSources::RevScript = "redis.call('ZINTERSTORE', KEYS[1], 2, KEYS[2], KEYS[3], 'WEIGHTS', 1, 0)\nlocal keys = redis.call('ZREVRANGE', KEYS[1], 0, KEYS[4])\nredis.call('DEL', KEYS[1])\nreturn keys".freeze
RedisObject::ScriptSources::FwdScript = "redis.call('ZINTERSTORE', KEYS[1], 2, KEYS[2], KEYS[3], 'WEIGHTS', 1, 0)
local keys = redis.call('ZRANGE', KEYS[1], 0, KEYS[4])
redis.call('DEL', KEYS[1])
return keys".freeze
RedisObject::ScriptSources::RevScript = "redis.call('ZINTERSTORE', KEYS[1], 2, KEYS[2], KEYS[3], 'WEIGHTS', 1, 0)
local keys = redis.call('ZREVRANGE', KEYS[1], 0, KEYS[4])
redis.call('DEL', KEYS[1])
return keys".freeze

def keys_by_index(idx,num=-1,reverse=false)
keys = run_script(reverse ? :RevScript : :FwdScript, [temp_key, sort_index_key(idx), key, num])
ListEnumerator.new(keys) do |y|
keys = run_script(reverse ? :RevScript : :FwdScript, [temp_key, sort_index_key(idx), key, num>0 ? num - 1 : -1])
ListEnumerator.new(keys.uniq) do |y|
keys.each do |member|
y << member
end
Expand Down Expand Up @@ -584,6 +601,9 @@ def load(name,owner)
end

def class_const_for(name)
if cls = RedisObject.constant_lookups[name.to_s.classify.to_sym]
return cls
end
Object.const_get(name.to_s.classify.to_sym) rescue RedisObject
end

Expand Down
10 changes: 5 additions & 5 deletions lib/redis_object/defaults.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ def intercept_for_defaults!
return if @intercepted_for_defaults
self.class_eval do

alias_method :undefaulted_get, :get unless method_defined?(:undefaulted_get)
def get(k)
if !is_set?(k) && (d = self.class.default_vals[k.to_sym]) && !d.nil?
return d
filter_gets do |obj, k, v|
if !obj.is_set?(k) && (d = obj.class.default_vals[k.to_sym]) && !d.nil?
d
else
v
end
undefaulted_get(k)
end

end
Expand Down
50 changes: 27 additions & 23 deletions lib/redis_object/ext/filters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,45 @@ def intercept_for_filters!
return if @intercept_for_filters
self.class_eval do

def filtered_method_call(method,*args)
if filters = self.class.filters_for(method)
filters.each do |f|
next unless args.is_a?(Array) and !args[0].nil?
args = send(f,*args)
filter_gets do |obj, k, v|
if filters = obj.class.filters_for(:get)
return filters.inject(v) do |acc,f|
obj.send(f,acc)
end
else
v
end
unless args.is_a?(Array)
args = [nil,nil]
end
send("unfiltered_#{method.to_s}".to_sym,*args)
end

alias_method :unfiltered_get, :get unless method_defined?(:unfiltered_get)
def get(k)
filtered_method_call(:get,k)
end

alias_method :unfiltered_set, :set unless method_defined?(:unfiltered_set)
def set(k,v)
filtered_method_call(:set,k,v)
end

alias_method :unfiltered_setnx, :setnx unless method_defined?(:unfiltered_setnx)
def setnx(k,v)
filtered_method_call(:setnx,k,v)
filter_sets do |obj, k, v|
if filters = obj.class.filters_for(:set)
filters.inject([k,v]) do |acc,f|
obj.send(f,*acc)
end
else
[k,v]
end
end

# filter_msets do |dat|
# if filters = self.class.filters_for(method)
# filters.each do |f|
# next unless args.is_a?(Array) and !args[0].nil?
# args = send(f,*args)
# end
# end
# unless args.is_a?(Array)
# args = [nil,nil]
# end
# args
# end
#
end
@intercept_for_filters = true
end

def set_filter(filter)
filter_method(:set,filter)
filter_method(:setnx,filter)
end

def get_filter(filter)
Expand Down
Loading

0 comments on commit 7b3fd45

Please sign in to comment.