memcache-client-activerecord 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -10,12 +10,16 @@ begin
10
10
  gem.email = "m.ishihara@gmail.com"
11
11
  gem.homepage = "http://github.com/m4i/memcache-client-activerecord"
12
12
  gem.authors = ["ISHIHARA Masaki"]
13
+ gem.rubyforge_project = "mc-activerecord"
13
14
  gem.add_runtime_dependency "activerecord", ">= 2.1"
14
15
  gem.add_development_dependency "rspec", ">= 1.2.9"
15
16
  gem.add_development_dependency "memcache-client", ">= 1.7.7"
16
17
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
18
  end
18
19
  Jeweler::GemcutterTasks.new
20
+ Jeweler::RubyforgeTasks.new do |rubyforge|
21
+ rubyforge.doc_task = "rdoc"
22
+ end
19
23
  rescue LoadError
20
24
  puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
25
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
@@ -4,19 +4,19 @@ class <%= migration_name %> < ActiveRecord::Migration
4
4
  when 'MySQL'
5
5
  execute(<<-SQL)
6
6
  CREATE TABLE `<%= table_name %>` (
7
- `key` VARBINARY(250) NOT NULL PRIMARY KEY,
8
- `value` MEDIUMBLOB NOT NULL,
9
- `cas` INT UNSIGNED NOT NULL,
10
- `expire_at` DATETIME
7
+ `key` VARBINARY(250) NOT NULL PRIMARY KEY,
8
+ `value` MEDIUMBLOB NOT NULL,
9
+ `cas` INT UNSIGNED NOT NULL,
10
+ `expiry` INT
11
11
  ) ENGINE=InnoDB
12
12
  SQL
13
13
 
14
14
  else
15
15
  create_table :<%= table_name %>, :id => false do |t|
16
- t.string :key, :null => false, :limit => 250
17
- t.binary :value, :null => false
18
- t.integer :cas, :null => false
19
- t.datetime :expire_at
16
+ t.string :key, :null => false, :limit => 250
17
+ t.binary :value, :null => false
18
+ t.integer :cas, :null => false
19
+ t.integer :expiry
20
20
  end
21
21
  add_index :<%= table_name %>, :key, :unique => true
22
22
  end
@@ -17,12 +17,13 @@ class MemCache
17
17
 
18
18
  MAX_KEY_SIZE = 250
19
19
  MAX_VALUE_SIZE = 2 ** 20
20
+ THIRTY_DAYS = 60 * 60 * 24 * 30
20
21
 
21
22
  COLUMN_NAMES = {
22
- :key => 'key',
23
- :value => 'value',
24
- :cas => 'cas',
25
- :expire_at => 'expire_at',
23
+ :key => 'key',
24
+ :value => 'value',
25
+ :cas => 'cas',
26
+ :expiry => 'expiry',
26
27
  }
27
28
 
28
29
  STORED = "STORED\r\n"
@@ -82,7 +83,7 @@ class MemCache
82
83
 
83
84
  def get(key, raw = false)
84
85
  cache_key = make_cache_key(key)
85
- if value = find(cache_key, :value, true, __method__)
86
+ if value = find(__method__, cache_key, :value, true)
86
87
  raw ? value : Marshal.load(value)
87
88
  end
88
89
  end
@@ -103,7 +104,7 @@ class MemCache
103
104
  cache_keys[make_cache_key(key)] = key
104
105
  cache_keys
105
106
  end
106
- rows = find_all(cache_keys.keys, [:key, :value], true, __method__)
107
+ rows = find_all(__method__, cache_keys.keys, [:key, :value], true)
107
108
  rows.inject({}) do |hash, (key, value)|
108
109
  hash[cache_keys[key]] = Marshal.load(value)
109
110
  hash
@@ -116,9 +117,9 @@ class MemCache
116
117
  cache_key = make_cache_key(key)
117
118
  value = value_to_storable(value, raw)
118
119
 
119
- unless update(cache_key, value, expiry, __method__)
120
+ unless update(__method__, cache_key, value, expiry)
120
121
  # rescue duplicate key error
121
- insert(cache_key, value, expiry, __method__) rescue nil
122
+ insert(__method__, cache_key, value, expiry) rescue nil
122
123
  end
123
124
 
124
125
  STORED unless @no_reply
@@ -128,7 +129,7 @@ class MemCache
128
129
  check_readonly!
129
130
  raise MemCacheError, 'A block is required' unless block_given?
130
131
 
131
- result = cas_with_reply(key, expiry, raw, __method__, &block)
132
+ result = cas_with_reply(__method__, key, expiry, raw, &block)
132
133
  result unless @no_reply
133
134
  end
134
135
 
@@ -138,18 +139,18 @@ class MemCache
138
139
  cache_key = make_cache_key(key)
139
140
  value = value_to_storable(value, raw)
140
141
 
141
- old_value, expire_at =
142
- find(cache_key, [:value, :expire_at], false, __method__)
142
+ old_value, old_expiry =
143
+ find(__method__, cache_key, [:value, :expiry], false)
143
144
 
144
- if old_value && available?(expire_at)
145
+ if old_value && available?(old_expiry)
145
146
  NOT_STORED unless @no_reply
146
147
 
147
148
  else
148
149
  if old_value
149
- update(cache_key, value, expiry, __method__)
150
+ update(__method__, cache_key, value, expiry)
150
151
  else
151
152
  # rescue duplicate key error
152
- insert(cache_key, value, expiry, __method__) rescue nil
153
+ insert(__method__, cache_key, value, expiry) rescue nil
153
154
  end
154
155
 
155
156
  STORED unless @no_reply
@@ -162,7 +163,7 @@ class MemCache
162
163
  cache_key = make_cache_key(key)
163
164
  value = value_to_storable(value, raw)
164
165
 
165
- if update(cache_key, value, expiry, __method__, true)
166
+ if update(__method__, cache_key, value, expiry, true)
166
167
  STORED unless @no_reply
167
168
  else
168
169
  NOT_STORED unless @no_reply
@@ -192,11 +193,11 @@ class MemCache
192
193
  conditions = { COLUMN_NAMES[:key] => cache_key }
193
194
 
194
195
  if @no_reply
195
- _delete(conditions, __method__)
196
+ _delete(__method__, conditions)
196
197
  nil
197
198
  else
198
- exists = !!find(cache_key, :key, true, __method__)
199
- _delete(conditions, __method__)
199
+ exists = !!find(__method__, cache_key, :key, true)
200
+ _delete(__method__, conditions)
200
201
  exists ? DELETED : NOT_FOUND
201
202
  end
202
203
  end
@@ -213,7 +214,7 @@ class MemCache
213
214
  end
214
215
 
215
216
  def garbage_collection!
216
- _delete(["#{quote_column_name(:expire_at)} <= ?", now], __method__)
217
+ _delete(__method__, ["#{quote_column_name(:expiry)} <= ?", now])
217
218
  end
218
219
 
219
220
  private
@@ -247,6 +248,14 @@ class MemCache
247
248
  value
248
249
  end
249
250
 
251
+ def expiry_to_storable(expiry)
252
+ expiry.zero? ?
253
+ nil :
254
+ expiry <= THIRTY_DAYS ?
255
+ now + expiry :
256
+ expiry
257
+ end
258
+
250
259
  def check_value_size!(value)
251
260
  if @check_size && value.size > MAX_VALUE_SIZE
252
261
  raise MemCacheError,
@@ -254,27 +263,27 @@ class MemCache
254
263
  end
255
264
  end
256
265
 
257
- def gets(key, raw, method)
266
+ def gets(_method_, key, raw)
258
267
  cache_key = make_cache_key(key)
259
- value, cas = find(cache_key, [:value, :cas], true, method)
268
+ value, cas = find(_method_, cache_key, [:value, :cas], true)
260
269
  if cas
261
270
  [raw ? value : Marshal.load(value), cas]
262
271
  end
263
272
  end
264
273
 
265
- def cas_with_reply(key, expiry, raw, method, &block)
266
- value, cas = gets(key, raw, method)
274
+ def cas_with_reply(_method_, key, expiry, raw, &block)
275
+ value, cas = gets(_method_, key, raw)
267
276
  if cas
268
277
  cache_key = make_cache_key(key)
269
278
  value = value_to_storable(yield(value), raw)
270
279
 
271
- update(cache_key, value, expiry, method, true, cas) ?
280
+ update(_method_, cache_key, value, expiry, true, cas) ?
272
281
  STORED : EXISTS
273
282
  end
274
283
  end
275
284
 
276
285
  # TODO: check value size
277
- def append_or_prepend(method, key, value)
286
+ def append_or_prepend(_method_, key, value)
278
287
  check_readonly!
279
288
 
280
289
  cache_key = make_cache_key(key)
@@ -283,33 +292,33 @@ class MemCache
283
292
  old = quote_column_name(:value)
284
293
  new = quote_value(:value, value)
285
294
  pairs = {
286
- :value => concat_sql(*(method == :append ? [old, new] : [new, old]))
295
+ :value => concat_sql(*(_method_ == :append ? [old, new] : [new, old]))
287
296
  }
288
297
 
289
298
  affected_rows = @ar.connection.update(
290
299
  update_sql(cache_key, pairs, true, nil),
291
- sql_name(method)
300
+ sql_name(_method_)
292
301
  )
293
302
 
294
303
  affected_rows > 0 ? STORED : NOT_STORED unless @no_reply
295
304
  end
296
305
 
297
- def incr_or_decl(method, key, amount)
306
+ def incr_or_decl(_method_, key, amount)
298
307
  check_readonly!
299
308
 
300
309
  unless /\A\s*\d+\s*\z/ =~ amount.to_s
301
310
  raise MemCacheError, 'invalid numeric delta argument'
302
311
  end
303
- amount = method == :incr ? amount.to_i : - amount.to_i
312
+ amount = _method_ == :incr ? amount.to_i : - amount.to_i
304
313
 
305
314
  value = nil
306
315
 
307
316
  count = 0
308
317
  begin
309
318
  count += 1
310
- raise MemCacheError, "cannot #{method}" if count > 10
319
+ raise MemCacheError, "cannot #{_method_}" if count > 10
311
320
 
312
- result = cas_with_reply(key, nil, true, method) do |old_value|
321
+ result = cas_with_reply(_method_, key, nil, true) do |old_value|
313
322
  unless /\A\s*\d+\s*\z/ =~old_value
314
323
  raise MemCacheError,
315
324
  'cannot increment or decrement non-numeric value'
@@ -324,7 +333,7 @@ class MemCache
324
333
  raise unless @no_reply
325
334
  end
326
335
 
327
- def find(cache_key, column_keys, only_available, method)
336
+ def find(_method_, cache_key, column_keys, only_available)
328
337
  result = @ar.connection.send(
329
338
  column_keys.is_a?(Array) ? :select_one : :select_value,
330
339
  select_sql(
@@ -332,7 +341,7 @@ class MemCache
332
341
  quote_column_name(*Array(column_keys)),
333
342
  only_available
334
343
  ),
335
- sql_name(method)
344
+ sql_name(_method_)
336
345
  )
337
346
 
338
347
  (result && column_keys.is_a?(Array)) ?
@@ -340,7 +349,7 @@ class MemCache
340
349
  result
341
350
  end
342
351
 
343
- def find_all(cache_keys, column_keys, only_available, method)
352
+ def find_all(_method_, cache_keys, column_keys, only_available)
344
353
  return [] if cache_keys.empty?
345
354
 
346
355
  result = @ar.connection.send(
@@ -350,7 +359,7 @@ class MemCache
350
359
  quote_column_name(*Array(column_keys)),
351
360
  only_available
352
361
  ),
353
- sql_name(method)
362
+ sql_name(_method_)
354
363
  )
355
364
 
356
365
  column_keys.is_a?(Array) ?
@@ -358,7 +367,7 @@ class MemCache
358
367
  result
359
368
  end
360
369
 
361
- def insert(cache_key, value, expiry, method)
370
+ def insert(_method_, cache_key, value, expiry)
362
371
  attributes = attributes_for_update(value, expiry).merge(
363
372
  :key => cache_key,
364
373
  :cas => 0
@@ -374,11 +383,11 @@ class MemCache
374
383
  "INSERT INTO #{@ar.quoted_table_name}" +
375
384
  " (#{quote_column_name(*column_keys)})" +
376
385
  " VALUES(#{quoted_values.join(', ')})",
377
- sql_name(method)
386
+ sql_name(_method_)
378
387
  )
379
388
  end
380
389
 
381
- def update(cache_key, value, expiry, method, only_available = false, cas = nil)
390
+ def update(_method_, cache_key, value, expiry, only_available = false, cas = nil)
382
391
  attributes = attributes_for_update(value, expiry)
383
392
 
384
393
  pairs = attributes.keys.inject({}) do |pairs, column_key|
@@ -388,32 +397,32 @@ class MemCache
388
397
 
389
398
  @ar.connection.update(
390
399
  update_sql(cache_key, pairs, only_available, cas),
391
- sql_name(method)
400
+ sql_name(_method_)
392
401
  ) > 0
393
402
  end
394
403
 
395
- def _delete(conditions, method)
404
+ def _delete(_method_, conditions)
396
405
  @ar.connection.execute(
397
406
  "DELETE FROM #{@ar.quoted_table_name}" +
398
407
  " WHERE #{@ar.send(:sanitize_sql, conditions)}",
399
- sql_name(method)
408
+ sql_name(_method_)
400
409
  )
401
410
  end
402
411
 
403
- def truncate(method)
412
+ def truncate(_method_)
404
413
  sql = case @ar.connection.adapter_name
405
414
  when 'SQLite'
406
415
  "DELETE FROM #{@ar.quoted_table_name}"
407
416
  else
408
417
  "TRUNCATE TABLE #{@ar.quoted_table_name}"
409
418
  end
410
- @ar.connection.execute(sql, sql_name(method))
419
+ @ar.connection.execute(sql, sql_name(_method_))
411
420
  end
412
421
 
413
422
  def attributes_for_update(value, expiry)
414
423
  attributes = { :value => value }
415
424
  unless expiry.nil?
416
- attributes.update(:expire_at => expiry.zero? ? nil : now(expiry))
425
+ attributes.update(:expiry => expiry_to_storable(expiry))
417
426
  end
418
427
  attributes
419
428
  end
@@ -449,8 +458,8 @@ class MemCache
449
458
 
450
459
  if only_available
451
460
  conditions.first << ' AND (' +
452
- "#{quote_column_name(:expire_at)} IS NULL" +
453
- " OR #{quote_column_name(:expire_at)} > ?" +
461
+ "#{quote_column_name(:expiry)} IS NULL" +
462
+ " OR #{quote_column_name(:expiry)} > ?" +
454
463
  ')'
455
464
  conditions << now
456
465
  end
@@ -467,12 +476,12 @@ class MemCache
467
476
  end
468
477
  end
469
478
 
470
- def sql_name(method)
471
- "#{self.class.name}##{method}"
479
+ def sql_name(_method_)
480
+ "#{self.class.name}##{_method_}"
472
481
  end
473
482
 
474
- def now(delay = 0)
475
- Time.now + delay
483
+ def now
484
+ Time.now.to_i
476
485
  end
477
486
 
478
487
  def quote_column_name(*column_keys)
@@ -486,12 +495,8 @@ class MemCache
486
495
  @ar.connection.quote(value, @ar.columns_hash[COLUMN_NAMES[column_key]])
487
496
  end
488
497
 
489
- def available?(expire_at)
490
- expire_at.nil? || now < to_time(expire_at)
491
- end
492
-
493
- def to_time(expire_at)
494
- @ar.columns_hash[COLUMN_NAMES[:expire_at]].type_cast(expire_at)
498
+ def available?(expiry)
499
+ expiry.nil? || now < expiry.to_i
495
500
  end
496
501
  end
497
502
 
@@ -138,6 +138,27 @@ describe "#{adapter}:" do
138
138
  caches.same(:get, 'FOO').should == 2
139
139
  end
140
140
 
141
+ it 'should support a number of seconds starting from current time' do
142
+ [
143
+ 1,
144
+ MemCache::ActiveRecord::THIRTY_DAYS,
145
+ ].each do |expiry|
146
+ dbcache.set('foo', 1, expiry)
147
+ cache_class.find_by_key('foo').expiry.should ==
148
+ Time.now.to_i + expiry
149
+ end
150
+ end
151
+
152
+ it 'should support an unix time expiry' do
153
+ [
154
+ MemCache::ActiveRecord::THIRTY_DAYS + 1,
155
+ Time.now.to_i,
156
+ ].each do |expiry|
157
+ dbcache.set('foo', 1, expiry)
158
+ cache_class.find_by_key('foo').expiry.should == expiry
159
+ end
160
+ end
161
+
141
162
  unless ENV['LOG']
142
163
  it 'should behave like MemCache with over 64KB value' do
143
164
  value = 'a' * (2 ** 16 + 1)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: memcache-client-activerecord
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ISHIHARA Masaki
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-30 00:00:00 +09:00
12
+ date: 2009-12-31 00:00:00 +09:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -90,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
90
90
  version:
91
91
  requirements: []
92
92
 
93
- rubyforge_project:
93
+ rubyforge_project: mc-activerecord
94
94
  rubygems_version: 1.3.5
95
95
  signing_key:
96
96
  specification_version: 3