viximo-cache-money 0.3.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.
- data/LICENSE +201 -0
- data/README +204 -0
- data/README.markdown +204 -0
- data/TODO +17 -0
- data/UNSUPPORTED_FEATURES +13 -0
- data/config/environment.rb +8 -0
- data/config/memcached.yml +4 -0
- data/db/schema.rb +18 -0
- data/init.rb +1 -0
- data/lib/cache_money.rb +105 -0
- data/lib/cash/accessor.rb +83 -0
- data/lib/cash/adapter/memcache_client.rb +36 -0
- data/lib/cash/adapter/memcached.rb +127 -0
- data/lib/cash/adapter/redis.rb +144 -0
- data/lib/cash/buffered.rb +137 -0
- data/lib/cash/config.rb +78 -0
- data/lib/cash/fake.rb +83 -0
- data/lib/cash/finders.rb +50 -0
- data/lib/cash/index.rb +211 -0
- data/lib/cash/local.rb +105 -0
- data/lib/cash/lock.rb +63 -0
- data/lib/cash/mock.rb +158 -0
- data/lib/cash/query/abstract.rb +219 -0
- data/lib/cash/query/calculation.rb +45 -0
- data/lib/cash/query/primary_key.rb +50 -0
- data/lib/cash/query/select.rb +16 -0
- data/lib/cash/request.rb +3 -0
- data/lib/cash/transactional.rb +43 -0
- data/lib/cash/util/array.rb +9 -0
- data/lib/cash/util/marshal.rb +19 -0
- data/lib/cash/version.rb +3 -0
- data/lib/cash/write_through.rb +71 -0
- data/lib/mem_cached_session_store.rb +49 -0
- data/lib/mem_cached_support_store.rb +143 -0
- data/rails/init.rb +1 -0
- data/spec/cash/accessor_spec.rb +186 -0
- data/spec/cash/active_record_spec.rb +224 -0
- data/spec/cash/buffered_spec.rb +9 -0
- data/spec/cash/calculations_spec.rb +78 -0
- data/spec/cash/finders_spec.rb +455 -0
- data/spec/cash/local_buffer_spec.rb +9 -0
- data/spec/cash/local_spec.rb +9 -0
- data/spec/cash/lock_spec.rb +110 -0
- data/spec/cash/marshal_spec.rb +60 -0
- data/spec/cash/order_spec.rb +172 -0
- data/spec/cash/transactional_spec.rb +602 -0
- data/spec/cash/window_spec.rb +195 -0
- data/spec/cash/without_caching_spec.rb +32 -0
- data/spec/cash/write_through_spec.rb +252 -0
- data/spec/spec_helper.rb +87 -0
- metadata +300 -0
@@ -0,0 +1,137 @@
|
|
1
|
+
module Cash
|
2
|
+
class Buffered
|
3
|
+
def self.push(cache, lock)
|
4
|
+
if cache.is_a?(Buffered)
|
5
|
+
cache.push
|
6
|
+
else
|
7
|
+
Buffered.new(cache, lock)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(memcache, lock)
|
12
|
+
@buffer = {}
|
13
|
+
@commands = []
|
14
|
+
@cache = memcache
|
15
|
+
@lock = lock
|
16
|
+
end
|
17
|
+
|
18
|
+
def pop
|
19
|
+
@cache
|
20
|
+
end
|
21
|
+
|
22
|
+
def push
|
23
|
+
NestedBuffered.new(self, @lock)
|
24
|
+
end
|
25
|
+
|
26
|
+
def get(key, *options)
|
27
|
+
if @buffer.has_key?(key)
|
28
|
+
# Since buffered ActiveRecord objects can be modified before they get
|
29
|
+
# written to the repository, a shallow clone should always be returned
|
30
|
+
if @buffer[key].is_a?(Array) && @buffer[key][0].is_a?(ActiveRecord::Base)
|
31
|
+
@buffer[key].map(&:shallow_clone)
|
32
|
+
elsif @buffer[key].is_a?(ActiveRecord::Base)
|
33
|
+
@buffer[key].shallow_clone
|
34
|
+
else
|
35
|
+
@buffer[key]
|
36
|
+
end
|
37
|
+
else
|
38
|
+
@buffer[key] = @cache.get(key, *options)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def set(key, value, *options)
|
43
|
+
@buffer[key] = value
|
44
|
+
buffer_command Command.new(:set, key, value, *options)
|
45
|
+
end
|
46
|
+
|
47
|
+
def incr(key, amount = 1)
|
48
|
+
return unless value = get(key, true)
|
49
|
+
|
50
|
+
@buffer[key] = value.to_i + amount
|
51
|
+
buffer_command Command.new(:incr, key, amount)
|
52
|
+
@buffer[key]
|
53
|
+
end
|
54
|
+
|
55
|
+
def decr(key, amount = 1)
|
56
|
+
return unless value = get(key, true)
|
57
|
+
|
58
|
+
@buffer[key] = [value.to_i - amount, 0].max
|
59
|
+
buffer_command Command.new(:decr, key, amount)
|
60
|
+
@buffer[key]
|
61
|
+
end
|
62
|
+
|
63
|
+
def add(key, value, *options)
|
64
|
+
@buffer[key] = value
|
65
|
+
buffer_command Command.new(:add, key, value, *options)
|
66
|
+
end
|
67
|
+
|
68
|
+
def delete(key, *options)
|
69
|
+
@buffer[key] = nil
|
70
|
+
buffer_command Command.new(:delete, key, *options)
|
71
|
+
end
|
72
|
+
|
73
|
+
def get_multi(*keys)
|
74
|
+
values = keys.collect { |key| get(key) }
|
75
|
+
keys.zip(values).to_hash_without_nils
|
76
|
+
end
|
77
|
+
|
78
|
+
def flush
|
79
|
+
sorted_keys = @commands.select(&:requires_lock?).collect(&:key).uniq.sort
|
80
|
+
sorted_keys.each do |key|
|
81
|
+
@lock.acquire_lock(key)
|
82
|
+
end
|
83
|
+
perform_commands
|
84
|
+
ensure
|
85
|
+
@buffer = {}
|
86
|
+
sorted_keys.each do |key|
|
87
|
+
@lock.release_lock(key)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def respond_to?(method)
|
92
|
+
@cache.respond_to?(method)
|
93
|
+
end
|
94
|
+
|
95
|
+
protected
|
96
|
+
|
97
|
+
def perform_commands
|
98
|
+
@commands.each do |command|
|
99
|
+
command.call(@cache)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def buffer_command(command)
|
104
|
+
@commands << command
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def method_missing(method, *args, &block)
|
110
|
+
@cache.send(method, *args, &block)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class NestedBuffered < Buffered
|
115
|
+
def flush
|
116
|
+
perform_commands
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class Command
|
121
|
+
attr_accessor :key
|
122
|
+
|
123
|
+
def initialize(name, key, *args)
|
124
|
+
@name = name
|
125
|
+
@key = key
|
126
|
+
@args = args
|
127
|
+
end
|
128
|
+
|
129
|
+
def requires_lock?
|
130
|
+
@name == :set
|
131
|
+
end
|
132
|
+
|
133
|
+
def call(cache)
|
134
|
+
cache.send @name, @key, *@args
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
data/lib/cash/config.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
module Cash
|
2
|
+
module Config
|
3
|
+
def self.create(active_record, options, indices = [])
|
4
|
+
active_record.cache_config = Cash::Config::Config.new(active_record, options)
|
5
|
+
indices.each { |i| active_record.index i.attributes, i.options }
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.included(a_module)
|
9
|
+
a_module.module_eval do
|
10
|
+
extend ClassMethods
|
11
|
+
delegate :repository, :to => "self.class"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def self.extended(a_class)
|
17
|
+
class << a_class
|
18
|
+
def cache_config
|
19
|
+
@cache_config
|
20
|
+
end
|
21
|
+
|
22
|
+
delegate :repository, :indices, :to => :cache_config
|
23
|
+
alias_method_chain :inherited, :cache_config
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def inherited_with_cache_config(subclass)
|
28
|
+
inherited_without_cache_config(subclass)
|
29
|
+
@cache_config.inherit(subclass) if @cache_config
|
30
|
+
end
|
31
|
+
|
32
|
+
def index(attributes, options = {})
|
33
|
+
options.assert_valid_keys(:ttl, :order, :limit, :buffer, :order_column)
|
34
|
+
(@cache_config.indices.unshift(Index.new(@cache_config, self, attributes, options))).uniq!
|
35
|
+
end
|
36
|
+
|
37
|
+
def version(number)
|
38
|
+
@cache_config.options[:version] = number
|
39
|
+
end
|
40
|
+
|
41
|
+
def cache_config=(config)
|
42
|
+
@cache_config = config
|
43
|
+
end
|
44
|
+
|
45
|
+
def cacheable?(*args)
|
46
|
+
Cash.enabled && cache_config
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Config
|
51
|
+
attr_reader :active_record, :options
|
52
|
+
|
53
|
+
def initialize(active_record, options = {})
|
54
|
+
@active_record, @options = active_record, options
|
55
|
+
end
|
56
|
+
|
57
|
+
def repository
|
58
|
+
@options[:repository]
|
59
|
+
end
|
60
|
+
|
61
|
+
def ttl
|
62
|
+
@ttl ||= (repository.respond_to?(:default_ttl) && repository.default_ttl) || @options[:ttl]
|
63
|
+
end
|
64
|
+
|
65
|
+
def version
|
66
|
+
@options[:version] || 1
|
67
|
+
end
|
68
|
+
|
69
|
+
def indices
|
70
|
+
@indices ||= active_record == ActiveRecord::Base ? [] : [Index.new(self, active_record, active_record.primary_key)]
|
71
|
+
end
|
72
|
+
|
73
|
+
def inherit(active_record)
|
74
|
+
Cash::Config.create(active_record, @options, indices)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/cash/fake.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
module Cash
|
2
|
+
class Fake < HashWithIndifferentAccess
|
3
|
+
attr_accessor :servers
|
4
|
+
|
5
|
+
def get_multi(*keys)
|
6
|
+
slice(*keys).collect { |k,v| [k, Marshal.load(v)] }.to_hash
|
7
|
+
end
|
8
|
+
|
9
|
+
def set(key, value, ttl = 0, raw = false)
|
10
|
+
self[key] = marshal(value, raw)
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(key, raw = false)
|
14
|
+
if raw
|
15
|
+
self[key]
|
16
|
+
else
|
17
|
+
if self.has_key?(key)
|
18
|
+
Marshal.load(self[key])
|
19
|
+
else
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def incr(key, amount = 1)
|
26
|
+
if self.has_key?(key)
|
27
|
+
self[key] = (self[key].to_i + amount).to_s
|
28
|
+
self[key].to_i
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def decr(key, amount = 1)
|
33
|
+
if self.has_key?(key)
|
34
|
+
self[key] = (self[key].to_i - amount).to_s
|
35
|
+
self[key].to_i
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def add(key, value, ttl = 0, raw = false)
|
40
|
+
return false if self.has_key?(key)
|
41
|
+
|
42
|
+
self[key] = marshal(value, raw)
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def append(key, value)
|
47
|
+
set(key, get(key, true).to_s + value.to_s, nil, true)
|
48
|
+
end
|
49
|
+
|
50
|
+
def namespace
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
|
54
|
+
def flush_all
|
55
|
+
clear
|
56
|
+
end
|
57
|
+
|
58
|
+
def stats
|
59
|
+
{}
|
60
|
+
end
|
61
|
+
|
62
|
+
def reset_runtime
|
63
|
+
[0, Hash.new(0)]
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
def marshal(value, raw)
|
68
|
+
if raw
|
69
|
+
value.to_s
|
70
|
+
else
|
71
|
+
Marshal.dump(value)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def unmarshal(marshaled_obj)
|
76
|
+
Marshal.load(marshaled_obj)
|
77
|
+
end
|
78
|
+
|
79
|
+
def deep_clone(obj)
|
80
|
+
unmarshal(marshal(obj))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/cash/finders.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Cash
|
2
|
+
module Finders
|
3
|
+
def self.included(active_record_class)
|
4
|
+
active_record_class.class_eval do
|
5
|
+
extend ClassMethods
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def self.extended(active_record_class)
|
11
|
+
class << active_record_class
|
12
|
+
alias_method_chain :find_every, :cache
|
13
|
+
alias_method_chain :find_from_ids, :cache
|
14
|
+
alias_method_chain :calculate, :cache
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def without_cache(&block)
|
19
|
+
with_scope(:find => {:readonly => true}, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
# User.find(:first, ...), User.find_by_foo(...), User.find(:all, ...), User.find_all_by_foo(...)
|
23
|
+
def find_every_with_cache(options)
|
24
|
+
if cacheable?
|
25
|
+
Query::Select.perform(self, options, scope(:find))
|
26
|
+
else
|
27
|
+
find_every_without_cache(options)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# User.find(1), User.find(1, 2, 3), User.find([1, 2, 3]), User.find([])
|
32
|
+
def find_from_ids_with_cache(ids, options)
|
33
|
+
if cacheable?
|
34
|
+
Query::PrimaryKey.perform(self, ids, options, scope(:find))
|
35
|
+
else
|
36
|
+
find_from_ids_without_cache(ids, options)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# User.count(:all), User.count, User.sum(...)
|
41
|
+
def calculate_with_cache(operation, column_name, options = {})
|
42
|
+
if cacheable?
|
43
|
+
Query::Calculation.perform(self, operation, column_name, options, scope(:find))
|
44
|
+
else
|
45
|
+
calculate_without_cache(operation, column_name, options)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/cash/index.rb
ADDED
@@ -0,0 +1,211 @@
|
|
1
|
+
module Cash
|
2
|
+
class Index
|
3
|
+
attr_reader :attributes, :options
|
4
|
+
delegate :each, :hash, :to => :@attributes
|
5
|
+
delegate :get, :set, :expire, :find_every_without_cache, :calculate_without_cache, :calculate_with_cache, :incr, :decr, :primary_key, :logger, :to => :@active_record
|
6
|
+
|
7
|
+
def initialize(config, active_record, attributes, options = {})
|
8
|
+
@config, @active_record, @attributes, @options = config, active_record, Array(attributes).collect(&:to_s).sort, options
|
9
|
+
end
|
10
|
+
|
11
|
+
def ==(other)
|
12
|
+
case other
|
13
|
+
when Index
|
14
|
+
attributes == other.attributes
|
15
|
+
else
|
16
|
+
attributes == Array(other)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
alias_method :eql?, :==
|
20
|
+
|
21
|
+
module Commands
|
22
|
+
def add(object)
|
23
|
+
_, new_attribute_value_pairs = old_and_new_attribute_value_pairs(object)
|
24
|
+
add_to_index_with_minimal_network_operations(new_attribute_value_pairs, object)
|
25
|
+
end
|
26
|
+
|
27
|
+
def update(object)
|
28
|
+
old_attribute_value_pairs, new_attribute_value_pairs = old_and_new_attribute_value_pairs(object)
|
29
|
+
update_index_with_minimal_network_operations(old_attribute_value_pairs, new_attribute_value_pairs, object)
|
30
|
+
end
|
31
|
+
|
32
|
+
def remove(object)
|
33
|
+
old_attribute_value_pairs, _ = old_and_new_attribute_value_pairs(object)
|
34
|
+
remove_from_index_with_minimal_network_operations(old_attribute_value_pairs, object)
|
35
|
+
end
|
36
|
+
|
37
|
+
def delete(object)
|
38
|
+
old_attribute_value_pairs, _ = old_and_new_attribute_value_pairs(object)
|
39
|
+
key = cache_key(old_attribute_value_pairs)
|
40
|
+
expire(key)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
include Commands
|
44
|
+
|
45
|
+
module Attributes
|
46
|
+
def ttl
|
47
|
+
@ttl ||= options[:ttl] || @config.ttl
|
48
|
+
end
|
49
|
+
|
50
|
+
def order
|
51
|
+
@order ||= options[:order] || :asc
|
52
|
+
end
|
53
|
+
|
54
|
+
def limit
|
55
|
+
options[:limit]
|
56
|
+
end
|
57
|
+
|
58
|
+
def buffer
|
59
|
+
options[:buffer]
|
60
|
+
end
|
61
|
+
|
62
|
+
def window
|
63
|
+
limit && limit + buffer
|
64
|
+
end
|
65
|
+
|
66
|
+
def order_column
|
67
|
+
options[:order_column] || 'id'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
include Attributes
|
71
|
+
|
72
|
+
def serialize_object(object)
|
73
|
+
primary_key? ? object.shallow_clone : object.id
|
74
|
+
end
|
75
|
+
|
76
|
+
def matches?(query)
|
77
|
+
query.calculation? ||
|
78
|
+
(query.order == [order_column, order] &&
|
79
|
+
(!limit || (query.limit && query.limit + query.offset <= limit)))
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
def old_and_new_attribute_value_pairs(object)
|
84
|
+
old_attribute_value_pairs = []
|
85
|
+
new_attribute_value_pairs = []
|
86
|
+
@attributes.each do |name|
|
87
|
+
new_value = object.attributes[name]
|
88
|
+
if object.changed.include? name
|
89
|
+
original_value = object.send("#{name}_was")
|
90
|
+
else
|
91
|
+
original_value = new_value
|
92
|
+
end
|
93
|
+
old_attribute_value_pairs << [name, original_value]
|
94
|
+
new_attribute_value_pairs << [name, new_value]
|
95
|
+
end
|
96
|
+
[old_attribute_value_pairs, new_attribute_value_pairs]
|
97
|
+
end
|
98
|
+
|
99
|
+
def add_to_index_with_minimal_network_operations(attribute_value_pairs, object)
|
100
|
+
if primary_key?
|
101
|
+
add_object_to_primary_key_cache(attribute_value_pairs, object)
|
102
|
+
else
|
103
|
+
add_object_to_cache(attribute_value_pairs, object)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def primary_key?
|
108
|
+
@attributes.size == 1 && @attributes.first == primary_key
|
109
|
+
end
|
110
|
+
|
111
|
+
def add_object_to_primary_key_cache(attribute_value_pairs, object)
|
112
|
+
set(cache_key(attribute_value_pairs), [serialize_object(object)], :ttl => ttl)
|
113
|
+
end
|
114
|
+
|
115
|
+
def cache_key(attribute_value_pairs)
|
116
|
+
attribute_value_pairs.flatten.join('/')
|
117
|
+
end
|
118
|
+
|
119
|
+
def add_object_to_cache(attribute_value_pairs, object, overwrite = true)
|
120
|
+
return if invalid_cache_key?(attribute_value_pairs)
|
121
|
+
|
122
|
+
key, cache_value, cache_hit = get_key_and_value_at_index(attribute_value_pairs)
|
123
|
+
if !cache_hit || overwrite
|
124
|
+
object_to_add = serialize_object(object)
|
125
|
+
objects = (cache_value + [object_to_add]).sort do |a, b|
|
126
|
+
(a <=> b) * (order == :asc ? 1 : -1)
|
127
|
+
end.uniq
|
128
|
+
objects = truncate_if_necessary(objects)
|
129
|
+
set(key, objects, :ttl => ttl)
|
130
|
+
incr("#{key}/count") { calculate_at_index(:count, attribute_value_pairs) }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def invalid_cache_key?(attribute_value_pairs)
|
135
|
+
attribute_value_pairs.collect { |_,value| value }.any? { |x| x.nil? }
|
136
|
+
end
|
137
|
+
|
138
|
+
def get_key_and_value_at_index(attribute_value_pairs)
|
139
|
+
key = cache_key(attribute_value_pairs)
|
140
|
+
cache_hit = true
|
141
|
+
cache_value = get(key) do
|
142
|
+
cache_hit = false
|
143
|
+
conditions = attribute_value_pairs.to_hash_without_nils
|
144
|
+
find_every_without_cache(:conditions => conditions, :limit => window).collect do |object|
|
145
|
+
serialize_object(object)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
[key, cache_value, cache_hit]
|
149
|
+
end
|
150
|
+
|
151
|
+
def truncate_if_necessary(objects)
|
152
|
+
objects.slice(0, window || objects.size)
|
153
|
+
end
|
154
|
+
|
155
|
+
def calculate_at_index(operation, attribute_value_pairs)
|
156
|
+
conditions = attribute_value_pairs.to_hash_without_nils
|
157
|
+
calculate_without_cache(operation, :all, :conditions => conditions)
|
158
|
+
end
|
159
|
+
|
160
|
+
def update_index_with_minimal_network_operations(old_attribute_value_pairs, new_attribute_value_pairs, object)
|
161
|
+
if index_is_stale?(old_attribute_value_pairs, new_attribute_value_pairs)
|
162
|
+
remove_object_from_cache(old_attribute_value_pairs, object)
|
163
|
+
add_object_to_cache(new_attribute_value_pairs, object)
|
164
|
+
elsif primary_key?
|
165
|
+
add_object_to_primary_key_cache(new_attribute_value_pairs, object)
|
166
|
+
else
|
167
|
+
add_object_to_cache(new_attribute_value_pairs, object, false)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def index_is_stale?(old_attribute_value_pairs, new_attribute_value_pairs)
|
172
|
+
old_attribute_value_pairs != new_attribute_value_pairs
|
173
|
+
end
|
174
|
+
|
175
|
+
def remove_from_index_with_minimal_network_operations(attribute_value_pairs, object)
|
176
|
+
if primary_key?
|
177
|
+
remove_object_from_primary_key_cache(attribute_value_pairs, object)
|
178
|
+
else
|
179
|
+
remove_object_from_cache(attribute_value_pairs, object)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def remove_object_from_primary_key_cache(attribute_value_pairs, object)
|
184
|
+
set(cache_key(attribute_value_pairs), [], :ttl => ttl)
|
185
|
+
end
|
186
|
+
|
187
|
+
def remove_object_from_cache(attribute_value_pairs, object)
|
188
|
+
return if invalid_cache_key?(attribute_value_pairs)
|
189
|
+
|
190
|
+
key, cache_value, _ = get_key_and_value_at_index(attribute_value_pairs)
|
191
|
+
object_to_remove = serialize_object(object)
|
192
|
+
objects = cache_value - [object_to_remove]
|
193
|
+
objects = resize_if_necessary(attribute_value_pairs, objects)
|
194
|
+
set(key, objects, :ttl => ttl)
|
195
|
+
end
|
196
|
+
|
197
|
+
def resize_if_necessary(attribute_value_pairs, objects)
|
198
|
+
conditions = attribute_value_pairs.to_hash_without_nils
|
199
|
+
key = cache_key(attribute_value_pairs)
|
200
|
+
count = decr("#{key}/count") { calculate_at_index(:count, attribute_value_pairs) }
|
201
|
+
|
202
|
+
if limit && objects.size < limit && objects.size < count
|
203
|
+
find_every_without_cache(:select => :id, :conditions => conditions).collect do |object|
|
204
|
+
serialize_object(object)
|
205
|
+
end
|
206
|
+
else
|
207
|
+
objects
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|