ngmoco-cache-money 0.2.9 → 0.2.10
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/UNSUPPORTED_FEATURES +0 -1
- data/lib/cash/lock.rb +9 -4
- data/lib/cash/query/abstract.rb +9 -1
- data/lib/memcached_wrapper.rb +34 -5
- data/spec/cash/finders_spec.rb +8 -0
- data/spec/spec_helper.rb +3 -2
- metadata +3 -2
data/UNSUPPORTED_FEATURES
CHANGED
@@ -7,7 +7,6 @@
|
|
7
7
|
* attr_readonly - no technical obstacle, just not yet supported
|
8
8
|
* attributes before typecast behave unpredictably - hard to support
|
9
9
|
* ActiveRecord::Rollback is unsupported - the exception gets swallowed so there isn't an opportunity to rollback the cache transaction - not hard to support
|
10
|
-
* Named bind variables :conditions => ["name = :name", { :name => "37signals!" }] - not hard to support
|
11
10
|
* printf style binds: :conditions => ["name = '%s'", "37signals!"] - not too hard to support
|
12
11
|
* objects as attributes that are serialized. story.title = {:foo => :bar}; customer.balance = Money.new(...) - these could be coerced using Column#type_cast?
|
13
12
|
|
data/lib/cash/lock.rb
CHANGED
@@ -2,8 +2,8 @@ module Cash
|
|
2
2
|
class Lock
|
3
3
|
class Error < RuntimeError; end
|
4
4
|
|
5
|
-
INITIAL_WAIT =
|
6
|
-
DEFAULT_RETRY =
|
5
|
+
INITIAL_WAIT = 2
|
6
|
+
DEFAULT_RETRY = 8
|
7
7
|
DEFAULT_EXPIRY = 30
|
8
8
|
|
9
9
|
def initialize(cache)
|
@@ -27,10 +27,10 @@ module Cash
|
|
27
27
|
retries.times do |count|
|
28
28
|
response = @cache.add("lock/#{key}", Process.pid, lock_expiry)
|
29
29
|
return if response == "STORED\r\n"
|
30
|
-
raise Error if count == retries - 1
|
31
30
|
exponential_sleep(count, initial_wait) unless count == retries - 1
|
32
31
|
end
|
33
|
-
|
32
|
+
debug_lock(key)
|
33
|
+
raise Error, "Couldn't acquire memcache lock for: #{key} server: #{@cache.get_server_for_key(key)}"
|
34
34
|
end
|
35
35
|
|
36
36
|
def release_lock(key)
|
@@ -47,5 +47,10 @@ module Cash
|
|
47
47
|
@cache.get("lock/#{key}") == Process.pid
|
48
48
|
end
|
49
49
|
|
50
|
+
def debug_lock(key)
|
51
|
+
@cache.logger.warn("#{@cache.get("lock/#{key}")}") if @cache.respond_to?(:logger) && @cache.logger.respond_to?(:warn)
|
52
|
+
rescue
|
53
|
+
@cache.logger.warn("#{$!}") if @cache.respond_to?(:logger) && @cache.logger.respond_to?(:warn)
|
54
|
+
end
|
50
55
|
end
|
51
56
|
end
|
data/lib/cash/query/abstract.rb
CHANGED
@@ -119,7 +119,15 @@ module Cash
|
|
119
119
|
conditions.split(AND).inject([]) do |indices, condition|
|
120
120
|
matched, table_name, column_name, sql_value = *(KEY_EQ_VALUE.match(condition))
|
121
121
|
if matched
|
122
|
-
value = sql_value == '?' ? values.shift : columns_hash[column_name].type_cast(sql_value)
|
122
|
+
# value = sql_value == '?' ? values.shift : columns_hash[column_name].type_cast(sql_value)
|
123
|
+
if sql_value == '?'
|
124
|
+
value = values.shift
|
125
|
+
elsif sql_value[0..0] == ':' && values && values.count > 0 && values[0].is_a?(Hash)
|
126
|
+
symb = sql_value[1..-1].to_sym
|
127
|
+
value = columns_hash[column_name].type_cast(values[0][symb])
|
128
|
+
else
|
129
|
+
value = columns_hash[column_name].type_cast(sql_value)
|
130
|
+
end
|
123
131
|
indices << [column_name, value]
|
124
132
|
else
|
125
133
|
return nil
|
data/lib/memcached_wrapper.rb
CHANGED
@@ -10,14 +10,14 @@
|
|
10
10
|
####### they have MemCache installed (don't need the wrapper)
|
11
11
|
if defined? MemCache
|
12
12
|
|
13
|
-
Rails.logger.info("cache-money: MemCache installed")
|
13
|
+
Rails.logger.info("cache-money: MemCache installed") if defined? Rails
|
14
14
|
#TODO add logging?
|
15
15
|
class MemcachedWrapper < ::MemCache
|
16
16
|
end
|
17
17
|
|
18
18
|
########## they have Memcached installed (do need the wrapper)
|
19
19
|
elsif defined? Memcached
|
20
|
-
Rails.logger.info("cache-money: Memcached installed")
|
20
|
+
Rails.logger.info("cache-money: Memcached installed") if defined? Rails
|
21
21
|
|
22
22
|
class Memcached
|
23
23
|
alias :get_multi :get #:nodoc:
|
@@ -69,20 +69,25 @@ class MemcachedWrapper < ::Memcached
|
|
69
69
|
|
70
70
|
# Wraps Memcached::Rails#add to return a text string - for cache money
|
71
71
|
def add(key, value, ttl=@default_ttl, raw=false)
|
72
|
+
logger.debug("Memcached add: #{key.inspect}") if logger && @debug
|
72
73
|
super(key, value, ttl, !raw)
|
74
|
+
logger.debug("Memcached hit: #{key.inspect}") if logger && @debug
|
73
75
|
stored
|
74
76
|
rescue Memcached::NotStored
|
77
|
+
logger.debug("Memcached miss: #{key.inspect}") if logger && @debug
|
75
78
|
not_stored
|
76
79
|
rescue Memcached::Error
|
77
|
-
log_error($!)
|
78
80
|
log_error($!) if logger
|
79
81
|
not_stored
|
80
82
|
end
|
81
83
|
|
82
84
|
def replace(key, value, ttl = @default_ttl, raw = false)
|
85
|
+
logger.debug("Memcached replace: #{key.inspect}") if logger && @debug
|
83
86
|
super(key, value, ttl, !raw)
|
87
|
+
logger.debug("Memcached hit: #{key.inspect}") if logger && @debug
|
84
88
|
stored
|
85
89
|
rescue Memcached::NotStored
|
90
|
+
logger.debug("Memcached miss: #{key.inspect}") if logger && @debug
|
86
91
|
not_stored
|
87
92
|
rescue Memcached::Error
|
88
93
|
log_error($!) if logger
|
@@ -122,9 +127,12 @@ class MemcachedWrapper < ::Memcached
|
|
122
127
|
|
123
128
|
# Wraps Memcached#cas so that it doesn't raise. Doesn't set anything if no value is present.
|
124
129
|
def cas(key, ttl=@default_ttl, raw=false, &block)
|
130
|
+
logger.debug("Memcached cas: #{key.inspect}") if logger && @debug
|
125
131
|
super(key, ttl, !raw, &block)
|
132
|
+
logger.debug("Memcached hit: #{key.inspect}") if logger && @debug
|
126
133
|
stored
|
127
134
|
rescue Memcached::NotFound
|
135
|
+
logger.debug("Memcached miss: #{key.inspect}") if logger && @debug
|
128
136
|
rescue TypeError
|
129
137
|
log_error($!) if logger
|
130
138
|
delete(key)
|
@@ -138,7 +146,13 @@ class MemcachedWrapper < ::Memcached
|
|
138
146
|
|
139
147
|
def get_multi(*keys)
|
140
148
|
keys.flatten!
|
141
|
-
|
149
|
+
logger.debug("Memcached get_multi: #{keys.inspect}") if logger && @debug
|
150
|
+
values = super(keys, true)
|
151
|
+
logger.debug("Memcached hit: #{keys.inspect}") if logger && @debug
|
152
|
+
values
|
153
|
+
rescue Memcached::NotFound
|
154
|
+
logger.debug("Memcached miss: #{keys.inspect}") if logger && @debug
|
155
|
+
{}
|
142
156
|
rescue TypeError
|
143
157
|
log_error($!) if logger
|
144
158
|
keys.each { |key| delete(key) }
|
@@ -150,7 +164,9 @@ class MemcachedWrapper < ::Memcached
|
|
150
164
|
end
|
151
165
|
|
152
166
|
def set(key, value, ttl=@default_ttl, raw=false)
|
167
|
+
logger.debug("Memcached set: #{key.inspect}") if logger && @debug
|
153
168
|
super(key, value, ttl, !raw)
|
169
|
+
logger.debug("Memcached hit: #{key.inspect}") if logger && @debug
|
154
170
|
stored
|
155
171
|
rescue Memcached::Error
|
156
172
|
log_error($!) if logger
|
@@ -158,27 +174,36 @@ class MemcachedWrapper < ::Memcached
|
|
158
174
|
end
|
159
175
|
|
160
176
|
def append(key, value)
|
177
|
+
logger.debug("Memcached append: #{key.inspect}") if logger && @debug
|
161
178
|
super(key, value)
|
179
|
+
logger.debug("Memcached hit: #{key.inspect}") if logger && @debug
|
162
180
|
stored
|
163
181
|
rescue Memcached::NotStored
|
182
|
+
logger.debug("Memcached miss: #{key.inspect}") if logger && @debug
|
164
183
|
not_stored
|
165
184
|
rescue Memcached::Error
|
166
185
|
log_error($!) if logger
|
167
186
|
end
|
168
187
|
|
169
188
|
def prepend(key, value)
|
189
|
+
logger.debug("Memcached prepend: #{key.inspect}") if logger && @debug
|
170
190
|
super(key, value)
|
191
|
+
logger.debug("Memcached hit: #{key.inspect}") if logger && @debug
|
171
192
|
stored
|
172
193
|
rescue Memcached::NotStored
|
194
|
+
logger.debug("Memcached miss: #{key.inspect}") if logger && @debug
|
173
195
|
not_stored
|
174
196
|
rescue Memcached::Error
|
175
197
|
log_error($!) if logger
|
176
198
|
end
|
177
199
|
|
178
200
|
def delete(key)
|
201
|
+
logger.debug("Memcached delete: #{key.inspect}") if logger && @debug
|
179
202
|
super(key)
|
203
|
+
logger.debug("Memcached hit: #{key.inspect}") if logger && @debug
|
180
204
|
deleted
|
181
205
|
rescue Memcached::NotFound
|
206
|
+
logger.debug("Memcached miss: #{key.inspect}") if logger && @debug
|
182
207
|
not_found
|
183
208
|
rescue Memcached::Error
|
184
209
|
log_error($!) if logger
|
@@ -198,6 +223,10 @@ class MemcachedWrapper < ::Memcached
|
|
198
223
|
log_error($!) if logger
|
199
224
|
end
|
200
225
|
|
226
|
+
def get_server_for_key(key, options = {})
|
227
|
+
server_by_key(key)
|
228
|
+
end
|
229
|
+
|
201
230
|
alias :reset :quit
|
202
231
|
alias :close :quit #nodoc
|
203
232
|
alias :flush_all :flush
|
@@ -229,5 +258,5 @@ private
|
|
229
258
|
|
230
259
|
end
|
231
260
|
else
|
232
|
-
Rails.logger.warn 'unable to determine memcache implementation'
|
261
|
+
Rails.logger.warn 'unable to determine memcache implementation' if defined? Rails
|
233
262
|
end #include the wraper
|
data/spec/cash/finders_spec.rb
CHANGED
@@ -30,6 +30,14 @@ module Cash
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
describe '#find(:first, :conditions => [ "id = :id", { :id => story.id } ])' do
|
34
|
+
it "does not use the database" do
|
35
|
+
story = Story.create!
|
36
|
+
mock(Story.connection).execute.never
|
37
|
+
Story.find(:first, :conditions => [ "id = :id", { :id => story.id } ]).should == story
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
33
41
|
describe "#find(:first, :conditions => 'id = ?')" do
|
34
42
|
it "does not use the database" do
|
35
43
|
story = Story.create!
|
data/spec/spec_helper.rb
CHANGED
@@ -6,7 +6,8 @@ require 'spec'
|
|
6
6
|
require 'pp'
|
7
7
|
require 'cache_money'
|
8
8
|
#require 'memcache'
|
9
|
-
|
9
|
+
require 'memcached'
|
10
|
+
require 'memcached_wrapper'
|
10
11
|
|
11
12
|
require File.join(dir, '../config/environment')
|
12
13
|
|
@@ -16,7 +17,7 @@ Spec::Runner.configure do |config|
|
|
16
17
|
load File.join(dir, "../db/schema.rb")
|
17
18
|
|
18
19
|
config = YAML.load(IO.read((File.expand_path(File.dirname(__FILE__) + "/../config/memcached.yml"))))['test']
|
19
|
-
$memcache = MemcachedWrapper.new(config[
|
20
|
+
$memcache = MemcachedWrapper.new(config["servers"].gsub(' ', '').split(','), config)
|
20
21
|
$lock = Cash::Lock.new($memcache)
|
21
22
|
end
|
22
23
|
|
metadata
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ngmoco-cache-money
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Kallen
|
8
|
+
- Ashley Martens
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
12
|
|
12
|
-
date:
|
13
|
+
date: 2010-01-08 00:00:00 -08:00
|
13
14
|
default_executable:
|
14
15
|
dependencies:
|
15
16
|
- !ruby/object:Gem::Dependency
|