lock_and_cache 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2fe1e1aa249ac319cc720916c9f3677caad588c7
4
- data.tar.gz: 4cc645768c09dbdadecf4acc1fd725f74f0868a3
3
+ metadata.gz: a51c74453543a2aea1c7a2d38029ed0ca28b19ef
4
+ data.tar.gz: 279b3e00a6356f9745163de77d4583e7dda4d90a
5
5
  SHA512:
6
- metadata.gz: f9560ee842aaaf400e9685066b7758ceb5c654ec86e218f8f79ad75e9d9e9f2ab1df602e4645a031323c969666449c7b8157c6cf0e08eef8252e7fa3a235cf77
7
- data.tar.gz: 7b7f13f14b8a6fd2a03a4dbd860b1edd5fb9090fcbdc9e6b8c1f4f64c88ecd2a98fd02eaf2fb575f5e8ee5c59d9e0e3973fb2abf8cf13c8c902d0433a79b7473
6
+ metadata.gz: db2cc229fd44e3e9432eb4233c23c02625066d5228aeb087e739922004a724627f7b85a4ceb3b54d89a6f6afc4963c17b57712cdf5d4ada077786107e21b625f
7
+ data.tar.gz: 396bcc439d0c3ff5bce552115fb69c858c70bcd921518ff7dfd6a770388f50ba6c2b22681273bd203d45afc82fd45a37b5bb187e51304082614b42d3d5d63f30
data/CHANGELOG CHANGED
@@ -1,3 +1,14 @@
1
+ 0.1.0 / 2015-01-22
2
+
3
+ * Breaking changes
4
+
5
+ * Redis only
6
+ * Now you use it inside methods (like Rails.cache.fetch) instead of outside (like cache_method)
7
+
8
+ * Enhancements
9
+
10
+ * Way simpler, no dependency on CacheMethod
11
+
1
12
  0.0.5 / 2014-12-12
2
13
 
3
14
  * Enhancements
data/README.md CHANGED
@@ -5,7 +5,7 @@ TODO: Write a gem description
5
5
  ## Wishlist
6
6
 
7
7
  * no dep on activerecord
8
- * no dep on cache_method
8
+ * no dep on redis
9
9
 
10
10
  ## Installation
11
11
 
@@ -1,36 +1,86 @@
1
1
  require 'lock_and_cache/version'
2
2
 
3
3
  require 'hash_digest'
4
- require 'cache_method'
5
4
  require 'active_record'
6
5
  require 'with_advisory_lock'
7
6
 
8
7
  module LockAndCache
9
- # only for instance methods
10
- def lock_and_cache(method_id)
11
- unlocked_method_id = "_lock_and_cache_unlocked_#{method_id}"
12
- alias_method unlocked_method_id, method_id
13
-
14
- define_method method_id do |*args|
15
- debug = (ENV['LOCK_AND_CACHE_DEBUG'] == 'true')
16
- lock_key = [self.class.name, method_id, HashDigest.digest3([as_cache_key]+args)].join('/')
17
- debug_lock_key = [self.class.name, method_id, [as_cache_key]+args].join('/') if debug
18
- Thread.exclusive { $stderr.puts "[lock_and_cache] A #{debug_lock_key}" } if debug
19
- if cache_method_cached?(method_id, args)
20
- return send(method_id, *args) # which will be the cached version
21
- end
22
- Thread.exclusive { $stderr.puts "[lock_and_cache] B #{debug_lock_key}" } if debug
23
- ActiveRecord::Base.with_advisory_lock(lock_key) do
24
- Thread.exclusive { $stderr.puts "[lock_and_cache] C #{debug_lock_key}" } if debug
25
- if cache_method_cached?(method_id, args)
26
- send method_id, *args # which will be the cached version
8
+ def LockAndCache.storage=(v)
9
+ raise "only redis for now" unless v.class.to_s == 'Redis'
10
+ @storage = v
11
+ end
12
+
13
+ def LockAndCache.storage
14
+ @storage
15
+ end
16
+
17
+ def LockAndCache.flush
18
+ storage.flushdb
19
+ end
20
+
21
+ class Key
22
+ attr_reader :obj
23
+ attr_reader :kaller
24
+
25
+ def initialize(obj, kaller, parts)
26
+ @obj = obj
27
+ @kaller = kaller
28
+ @_parts = parts
29
+ end
30
+
31
+ def digest
32
+ @digest ||= ::HashDigest.digest3([obj_class_name, method_id] + parts)
33
+ end
34
+
35
+ def debug
36
+ @debug ||= [obj_class_name, method_id] + parts
37
+ end
38
+
39
+ def parts
40
+ @parts ||= @_parts.map do |v|
41
+ case v
42
+ when ::String, ::Symbol, ::Hash, ::Array
43
+ v
27
44
  else
28
- Thread.exclusive { $stderr.puts "[lock_and_cache] D #{debug_lock_key}" } if debug
29
- send unlocked_method_id, *args
45
+ v.respond_to?(:lock_and_cache_key) ? v.lock_and_cache_key : v.id
30
46
  end
31
47
  end
32
48
  end
33
49
 
34
- cache_method method_id
50
+ def method_id
51
+ @method_id ||= begin
52
+ kaller[0] =~ /in `(\w+)'/
53
+ $1 or raise "couldn't get method_id from #{kaller[0]}"
54
+ end
55
+ end
56
+
57
+ def obj_class_name
58
+ @obj_class_name ||= (obj.class == ::Class) ? obj.name : obj.class.name
59
+ end
60
+
61
+ end
62
+
63
+ def lock_and_cache(*key_parts)
64
+ raise "need a block" unless block_given?
65
+ debug = (ENV['LOCK_AND_CACHE_DEBUG'] == 'true')
66
+ key = LockAndCache::Key.new self, caller, key_parts
67
+ digest = key.digest
68
+ storage = LockAndCache.storage
69
+ Thread.exclusive { $stderr.puts "[lock_and_cache] A #{key.debug}" } if debug
70
+ if storage.exists digest
71
+ return ::Marshal.load(storage.get(digest))
72
+ end
73
+ Thread.exclusive { $stderr.puts "[lock_and_cache] B #{key.debug}" } if debug
74
+ ActiveRecord::Base.with_advisory_lock(digest) do
75
+ Thread.exclusive { $stderr.puts "[lock_and_cache] C #{key.debug}" } if debug
76
+ if storage.exists digest
77
+ ::Marshal.load storage.get(digest)
78
+ else
79
+ Thread.exclusive { $stderr.puts "[lock_and_cache] D #{key.debug}" } if debug
80
+ memo = yield
81
+ storage.set digest, ::Marshal.dump(memo)
82
+ memo
83
+ end
84
+ end
35
85
  end
36
86
  end
@@ -1,3 +1,3 @@
1
1
  module LockAndCache
2
- VERSION = '0.0.5'
2
+ VERSION = '0.1.0'
3
3
  end
@@ -19,7 +19,6 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_runtime_dependency 'activerecord'
22
- spec.add_runtime_dependency 'cache_method'
23
22
  spec.add_runtime_dependency 'hash_digest'
24
23
  spec.add_runtime_dependency 'with_advisory_lock'
25
24
 
@@ -29,4 +28,5 @@ Gem::Specification.new do |spec|
29
28
  spec.add_development_dependency 'pg'
30
29
  spec.add_development_dependency 'rake', '~> 10.0'
31
30
  spec.add_development_dependency 'rspec'
31
+ spec.add_development_dependency 'redis'
32
32
  end
@@ -1,17 +1,20 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  class Foo
4
+ include LockAndCache
5
+
4
6
  def initialize(id)
5
7
  @id = id
6
8
  @count = 0
7
9
  end
10
+
8
11
  def click
9
- @count += 1
12
+ lock_and_cache(self) do
13
+ @count += 1
14
+ end
10
15
  end
11
16
 
12
- extend LockAndCache
13
- lock_and_cache :click
14
- def as_cache_key
17
+ def lock_and_cache_key
15
18
  @id
16
19
  end
17
20
  end
@@ -19,10 +22,13 @@ end
19
22
  require 'set'
20
23
  $clicking = Set.new
21
24
  class Bar
25
+ include LockAndCache
26
+
22
27
  def initialize(id)
23
28
  @id = id
24
29
  @count = 0
25
30
  end
31
+
26
32
  def unsafe_click
27
33
  Thread.exclusive do
28
34
  # puts "clicking bar #{@id} - #{$clicking.to_a} - #{$clicking.include?(@id)} - #{@id == $clicking.to_a[0]}"
@@ -36,18 +42,23 @@ class Bar
36
42
  end
37
43
  @count
38
44
  end
45
+
39
46
  def click
40
- unsafe_click
47
+ lock_and_cache(self) do
48
+ unsafe_click
49
+ end
41
50
  end
42
51
 
43
- extend LockAndCache
44
- lock_and_cache :click
45
- def as_cache_key
52
+ def lock_and_cache_key
46
53
  @id
47
54
  end
48
55
  end
49
56
 
50
57
  describe LockAndCache do
58
+ before do
59
+ LockAndCache.flush
60
+ end
61
+
51
62
  it 'has a version number' do
52
63
  expect(LockAndCache::VERSION).not_to be nil
53
64
  end
@@ -3,4 +3,7 @@ require 'lock_and_cache'
3
3
 
4
4
  ActiveRecord::Base.establish_connection adapter: 'postgresql', database: 'lock_and_cache_test'
5
5
 
6
+ require 'redis'
7
+ LockAndCache.storage = Redis.new
8
+
6
9
  require 'pry'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lock_and_cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Seamus Abshere
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-12 00:00:00.000000000 Z
11
+ date: 2015-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: cache_method
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: hash_digest
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -150,6 +136,20 @@ dependencies:
150
136
  - - ">="
151
137
  - !ruby/object:Gem::Version
152
138
  version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: redis
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
153
  description: Lock and cache methods, in case things should only be calculated once
154
154
  across processes.
155
155
  email: