lock_method 0.5.3 → 0.5.4
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/CHANGELOG +10 -0
- data/Gemfile +1 -0
- data/lib/lock_method.rb +47 -10
- data/lib/lock_method/default_storage_client.rb +7 -9
- data/lib/lock_method/lock.rb +26 -71
- data/lib/lock_method/version.rb +1 -1
- data/test/shared_tests.rb +2 -2
- data/test/test_redis_storage.rb +11 -12
- metadata +2 -2
data/CHANGELOG
CHANGED
data/Gemfile
CHANGED
data/lib/lock_method.rb
CHANGED
@@ -16,13 +16,51 @@ module LockMethod
|
|
16
16
|
class Locked < ::StandardError
|
17
17
|
end
|
18
18
|
|
19
|
-
|
19
|
+
CONFIG_MUTEX = ::Mutex.new
|
20
20
|
|
21
21
|
def LockMethod.config #:nodoc:
|
22
|
-
@config ||
|
22
|
+
@config || CONFIG_MUTEX.synchronize do
|
23
23
|
@config ||= Config.new
|
24
24
|
end
|
25
25
|
end
|
26
|
+
|
27
|
+
def LockMethod.original_method_id(method_id)
|
28
|
+
"_unlocked_#{method_id}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def LockMethod.klass_name(obj)
|
32
|
+
(obj.is_a?(::Class) or obj.is_a?(::Module)) ? obj.to_s : obj.class.to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
def LockMethod.method_delimiter(obj)
|
36
|
+
(obj.is_a?(::Class) or obj.is_a?(::Module)) ? '.' : '#'
|
37
|
+
end
|
38
|
+
|
39
|
+
def LockMethod.method_signature(obj, method_id)
|
40
|
+
[ klass_name(obj), method_id ].join method_delimiter(obj)
|
41
|
+
end
|
42
|
+
|
43
|
+
def LockMethod.resolve_lock(obj)
|
44
|
+
case obj
|
45
|
+
when ::Array
|
46
|
+
obj.map do |v|
|
47
|
+
resolve_lock v
|
48
|
+
end
|
49
|
+
when ::Hash
|
50
|
+
obj.inject({}) do |memo, (k, v)|
|
51
|
+
kk = resolve_lock k
|
52
|
+
vv = resolve_lock v
|
53
|
+
memo[kk] = vv
|
54
|
+
memo
|
55
|
+
end
|
56
|
+
else
|
57
|
+
obj.respond_to?(:as_lock) ? [obj.class.name, obj.as_lock] : obj
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def LockMethod.digest(obj)
|
62
|
+
::Digest::SHA1.hexdigest ::Marshal.dump(resolve_lock(obj))
|
63
|
+
end
|
26
64
|
|
27
65
|
# All Objects, including instances and Classes, get the <tt>#lock_method_clear</tt> method.
|
28
66
|
module InstanceMethods
|
@@ -58,17 +96,16 @@ module LockMethod
|
|
58
96
|
# # lock_method :get_latest_entries, 800 #seconds
|
59
97
|
# end
|
60
98
|
def lock_method(*args)
|
61
|
-
options = args.extract_options
|
62
|
-
|
99
|
+
options = args.extract_options!.symbolize_keys
|
100
|
+
spin = options[:spin]
|
101
|
+
ttl = options[:ttl]
|
63
102
|
method_id = args.first
|
64
103
|
if args.last.is_a?(::Numeric)
|
65
|
-
|
104
|
+
ttl ||= args.last
|
66
105
|
end
|
67
|
-
original_method_id
|
68
|
-
|
69
|
-
|
70
|
-
options1 = options.merge(:args => args1, :original_method_id => original_method_id)
|
71
|
-
lock = ::LockMethod::Lock.new self, method_id, options1, &blk
|
106
|
+
alias_method LockMethod.original_method_id(method_id), method_id
|
107
|
+
define_method method_id do |*my_args, &blk|
|
108
|
+
lock = ::LockMethod::Lock.new(self, method_id, my_args, ttl, spin, &blk)
|
72
109
|
lock.call_and_lock
|
73
110
|
end
|
74
111
|
end
|
@@ -8,7 +8,7 @@ module LockMethod
|
|
8
8
|
attr_reader :created_at
|
9
9
|
attr_reader :ttl
|
10
10
|
attr_reader :v
|
11
|
-
def initialize(
|
11
|
+
def initialize(v, ttl)
|
12
12
|
@created_at = ::Time.now
|
13
13
|
@ttl = ttl.to_f
|
14
14
|
@v = v
|
@@ -18,13 +18,11 @@ module LockMethod
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
|
21
|
+
DIR = ::File.join ::Dir.tmpdir, 'lock_method'
|
22
22
|
|
23
23
|
def initialize
|
24
24
|
@mutex = ::Mutex.new
|
25
|
-
|
26
|
-
::FileUtils.mkdir(dir) unless ::File.directory?(dir)
|
27
|
-
@dir = dir
|
25
|
+
::FileUtils.mkdir(DIR) unless ::File.directory?(DIR)
|
28
26
|
end
|
29
27
|
|
30
28
|
def get(k)
|
@@ -39,11 +37,11 @@ module LockMethod
|
|
39
37
|
end
|
40
38
|
|
41
39
|
def set(k, v, ttl)
|
42
|
-
entry = Entry.new
|
40
|
+
entry = Entry.new v, ttl
|
43
41
|
@mutex.synchronize do
|
44
42
|
::File.open(path(k), 'wb') do |f|
|
45
43
|
f.flock ::File::LOCK_EX
|
46
|
-
f.write ::Marshal.dump
|
44
|
+
f.write ::Marshal.dump(entry)
|
47
45
|
end
|
48
46
|
end
|
49
47
|
end
|
@@ -53,7 +51,7 @@ module LockMethod
|
|
53
51
|
end
|
54
52
|
|
55
53
|
def flush
|
56
|
-
::Dir["#{
|
54
|
+
::Dir["#{DIR}/*.lock"].each do |path|
|
57
55
|
::FileUtils.rm_f path
|
58
56
|
end
|
59
57
|
end
|
@@ -61,7 +59,7 @@ module LockMethod
|
|
61
59
|
private
|
62
60
|
|
63
61
|
def path(k)
|
64
|
-
::File.join
|
62
|
+
::File.join DIR, "#{::Digest::SHA1.hexdigest(k)}.lock"
|
65
63
|
end
|
66
64
|
end
|
67
65
|
end
|
data/lib/lock_method/lock.rb
CHANGED
@@ -1,80 +1,29 @@
|
|
1
1
|
require 'digest/sha1'
|
2
|
+
|
2
3
|
module LockMethod
|
3
4
|
class Lock #:nodoc: all
|
4
|
-
class << self
|
5
|
-
def find(cache_key)
|
6
|
-
LockMethod.config.storage.get cache_key
|
7
|
-
end
|
8
|
-
def klass_name(obj)
|
9
|
-
(obj.is_a?(::Class) or obj.is_a?(::Module)) ? obj.to_s : obj.class.to_s
|
10
|
-
end
|
11
|
-
def method_delimiter(obj)
|
12
|
-
(obj.is_a?(::Class) or obj.is_a?(::Module)) ? '.' : '#'
|
13
|
-
end
|
14
|
-
def method_signature(obj, method_id)
|
15
|
-
[ klass_name(obj), method_id ].join method_delimiter(obj)
|
16
|
-
end
|
17
|
-
def resolve_lock(obj)
|
18
|
-
case obj
|
19
|
-
when ::Array
|
20
|
-
obj.map do |v|
|
21
|
-
resolve_lock v
|
22
|
-
end
|
23
|
-
when ::Hash
|
24
|
-
obj.inject({}) do |memo, (k, v)|
|
25
|
-
kk = resolve_lock k
|
26
|
-
vv = resolve_lock v
|
27
|
-
memo[kk] = vv
|
28
|
-
memo
|
29
|
-
end
|
30
|
-
else
|
31
|
-
obj.respond_to?(:as_lock) ? [obj.class.name, obj.as_lock] : obj
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
5
|
attr_reader :obj
|
37
6
|
attr_reader :method_id
|
38
7
|
attr_reader :args
|
39
8
|
attr_reader :blk
|
40
9
|
attr_reader :original_method_id
|
10
|
+
attr_reader :method_signature
|
11
|
+
attr_reader :ttl
|
12
|
+
attr_reader :args_digest
|
41
13
|
|
42
|
-
def initialize(obj, method_id,
|
14
|
+
def initialize(obj, method_id, args = nil, ttl = LockMethod.config.default_ttl, spin = false, &blk)
|
43
15
|
@mutex = ::Mutex.new
|
44
16
|
@obj = obj
|
45
17
|
@method_id = method_id
|
18
|
+
@original_method_id = LockMethod.original_method_id method_id
|
19
|
+
@method_signature = LockMethod.method_signature obj, method_id
|
20
|
+
@args = args
|
21
|
+
@args_digest = args.to_a.empty? ? 'empty' : LockMethod.digest(args)
|
22
|
+
@ttl = ttl #!!!!!
|
23
|
+
@spin = spin
|
46
24
|
@blk = blk
|
47
|
-
options = options.symbolize_keys
|
48
|
-
@ttl = options[:ttl]
|
49
|
-
@args = options[:args]
|
50
|
-
@spin = options[:spin]
|
51
|
-
@original_method_id = options[:original_method_id]
|
52
|
-
end
|
53
|
-
|
54
|
-
def spin?
|
55
|
-
@spin == true
|
56
|
-
end
|
57
|
-
|
58
|
-
def method_signature
|
59
|
-
@method_signature ||= Lock.method_signature(obj, method_id)
|
60
25
|
end
|
61
26
|
|
62
|
-
def ttl
|
63
|
-
@ttl ||= LockMethod.config.default_ttl
|
64
|
-
end
|
65
|
-
|
66
|
-
def obj_digest
|
67
|
-
@obj_digest || @mutex.synchronize do
|
68
|
-
@obj_digest ||= ::Digest::SHA1.hexdigest(::Marshal.dump(Lock.resolve_lock(obj)))
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def args_digest
|
73
|
-
@args_digest || @mutex.synchronize do
|
74
|
-
@args_digest ||= args.to_a.empty? ? 'empty' : ::Digest::SHA1.hexdigest(::Marshal.dump(Lock.resolve_lock(args)))
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
27
|
def delete
|
79
28
|
LockMethod.config.storage.delete cache_key
|
80
29
|
end
|
@@ -84,17 +33,9 @@ module LockMethod
|
|
84
33
|
end
|
85
34
|
|
86
35
|
def locked?
|
87
|
-
!!
|
36
|
+
!!LockMethod.config.storage.get(cache_key)
|
88
37
|
end
|
89
38
|
|
90
|
-
def cache_key
|
91
|
-
if obj.is_a?(::Class) or obj.is_a?(::Module)
|
92
|
-
[ 'LockMethod', 'Lock', method_signature, args_digest ].join ','
|
93
|
-
else
|
94
|
-
[ 'LockMethod', 'Lock', method_signature, obj_digest, args_digest ].join ','
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
39
|
def marshal_dump
|
99
40
|
[]
|
100
41
|
end
|
@@ -118,5 +59,19 @@ module LockMethod
|
|
118
59
|
end
|
119
60
|
end
|
120
61
|
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def cache_key
|
66
|
+
if obj.is_a?(::Class) or obj.is_a?(::Module)
|
67
|
+
[ 'LockMethod', 'Lock', method_signature, args_digest ].join ','
|
68
|
+
else
|
69
|
+
[ 'LockMethod', 'Lock', method_signature, LockMethod.digest(obj), args_digest ].join ','
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def spin?
|
74
|
+
@spin == true
|
75
|
+
end
|
121
76
|
end
|
122
77
|
end
|
data/lib/lock_method/version.rb
CHANGED
data/test/shared_tests.rb
CHANGED
@@ -159,8 +159,8 @@ module SharedTests
|
|
159
159
|
Blog2.get_latest_entries2
|
160
160
|
end
|
161
161
|
|
162
|
-
# but the lock expiry is
|
163
|
-
sleep
|
162
|
+
# but the lock expiry is 5 seconds, so by 5.2&change we're done
|
163
|
+
sleep 3.2
|
164
164
|
assert_nothing_raised do
|
165
165
|
Blog2.get_latest_entries2
|
166
166
|
end
|
data/test/test_redis_storage.rb
CHANGED
@@ -1,17 +1,16 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
require 'redis'
|
4
|
+
require 'redis-namespace'
|
5
|
+
require 'uri'
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
include SharedTests
|
7
|
+
class TestRedisStorage < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
# uri = URI.parse(ENV["REDIS_URL"])
|
10
|
+
r = Redis.new#(:host => uri.host, :port => uri.port, :password => uri.password)
|
11
|
+
my_cache = Redis::Namespace.new(:test_lock_method, :redis => r)
|
12
|
+
LockMethod.config.storage = my_cache
|
16
13
|
end
|
14
|
+
|
15
|
+
include SharedTests
|
17
16
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lock_method
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-04-
|
12
|
+
date: 2012-04-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: cache
|