lock_and_cache 0.0.5 → 0.1.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.
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: