distlock 0.0.9 → 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.
- data/distlock.gemspec +4 -1
- data/lib/distlock.rb +26 -3
- data/lib/distlock/noop/exclusive_lock.rb +21 -0
- data/lib/distlock/noop/noop.rb +6 -0
- data/lib/distlock/redis/common.rb +21 -0
- data/lib/distlock/redis/exclusive_lock.rb +82 -0
- data/lib/distlock/redis/redis.rb +8 -0
- data/lib/distlock/version.rb +1 -1
- data/lib/distlock/zk/exclusive_lock.rb +0 -4
- metadata +9 -19
data/distlock.gemspec
CHANGED
@@ -23,5 +23,8 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.add_development_dependency "rake", "~> 0.9"
|
24
24
|
s.add_development_dependency "rspec", "~> 2.0"
|
25
25
|
|
26
|
-
|
26
|
+
# todo remove these
|
27
|
+
# s.add_development_dependency "zookeeper", "~> 0.4"
|
28
|
+
# s.add_development_dependency "redis"
|
29
|
+
# s.add_development_dependency "system_timer"
|
27
30
|
end
|
data/lib/distlock.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'logger'
|
2
2
|
require 'distlock/version'
|
3
3
|
require 'distlock/lock_error'
|
4
|
-
require 'distlock/zk/zk'
|
5
4
|
|
6
5
|
module Distlock
|
7
6
|
def Distlock.logger
|
@@ -13,8 +12,32 @@ module Distlock
|
|
13
12
|
end
|
14
13
|
|
15
14
|
# factory method for creating instances of lock managers
|
16
|
-
def Distlock.new_instance(
|
17
|
-
|
15
|
+
def Distlock.new_instance(options={})
|
16
|
+
|
17
|
+
# attempt to require zookeeper blindly
|
18
|
+
# if require fails, fallback to redis
|
19
|
+
# if fails fall back to noop
|
20
|
+
|
21
|
+
locker=nil
|
22
|
+
|
23
|
+
begin
|
24
|
+
require 'distlock/zk/zk'
|
25
|
+
locker = Distlock::ZK::ExclusiveLock.new(options)
|
26
|
+
rescue LoadError => e
|
27
|
+
Distlock.logger.debug "failed to require - #{e}"
|
28
|
+
|
29
|
+
begin
|
30
|
+
require 'distlock/redis/redis'
|
31
|
+
locker = Distlock::Redis::ExclusiveLock.new(options)
|
32
|
+
rescue LoadError => e
|
33
|
+
Distlock.logger.debug "failed to require - #{e}"
|
34
|
+
|
35
|
+
# noop
|
36
|
+
require 'distlock/noop/noop'
|
37
|
+
locker = Distlock::Noop::ExclusiveLock.new(options)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
18
41
|
locker.logger = Distlock.logger
|
19
42
|
locker
|
20
43
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Distlock
|
2
|
+
module Noop
|
3
|
+
class ExclusiveLock
|
4
|
+
|
5
|
+
def initialize(options={})
|
6
|
+
end
|
7
|
+
|
8
|
+
def with_lock(path=nil)
|
9
|
+
yield if block_given?
|
10
|
+
end
|
11
|
+
|
12
|
+
def logger
|
13
|
+
@logger ||= Logger.new(STDOUT)
|
14
|
+
end
|
15
|
+
|
16
|
+
def logger=(logger)
|
17
|
+
@logger = logger
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Distlock
|
4
|
+
module Redis
|
5
|
+
module Common
|
6
|
+
def redis
|
7
|
+
@redis ||= begin
|
8
|
+
redis = ::Redis.new
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def logger
|
13
|
+
@logger ||= Logger.new(STDOUT)
|
14
|
+
end
|
15
|
+
|
16
|
+
def logger=(logger)
|
17
|
+
@logger = logger
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Distlock
|
2
|
+
module Redis
|
3
|
+
|
4
|
+
#
|
5
|
+
# see here for retry count based example -
|
6
|
+
# https://github.com/PatrickTulskie/redis-lock/blob/master/lib/redis/lock.rb
|
7
|
+
#
|
8
|
+
class ExclusiveLock
|
9
|
+
include Distlock::Redis::Common
|
10
|
+
|
11
|
+
DEFAULT_LEASE_FOR = 300 # 5 mins
|
12
|
+
DEFAULT_RETRY_FOR = 60 # 1 min
|
13
|
+
DEFAULT_RETRY_IN = 1 # 1 sec
|
14
|
+
|
15
|
+
def initialize(options={})
|
16
|
+
end
|
17
|
+
|
18
|
+
def my_lock
|
19
|
+
@my_lock
|
20
|
+
end
|
21
|
+
|
22
|
+
def lock(path, lease_for = DEFAULT_LEASE_FOR, retry_for = DEFAULT_RETRY_FOR)
|
23
|
+
now = Time.now
|
24
|
+
retry_until = now + retry_for
|
25
|
+
|
26
|
+
@my_lock = path
|
27
|
+
|
28
|
+
lock_value = generate_lock_value(lease_for)
|
29
|
+
|
30
|
+
while Time.now < retry_until
|
31
|
+
if redis.setnx(path, lock_value)
|
32
|
+
logger.debug "acquired lock (setnx) - #{my_lock}, #{lock_value}"
|
33
|
+
return true
|
34
|
+
end
|
35
|
+
|
36
|
+
current_lock = redis.get(my_lock)
|
37
|
+
if (current_lock.to_s.split('-').first.to_i) < Time.now.to_i
|
38
|
+
updated_lock = redis.getset(my_lock, lock_value)
|
39
|
+
if updated_lock == current_lock
|
40
|
+
logger.debug "acquired lock (getset) - #{my_lock}, #{lock_value}"
|
41
|
+
return true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
sleep DEFAULT_RETRY_IN
|
46
|
+
end
|
47
|
+
|
48
|
+
raise LockError.new("failed to get the lock")
|
49
|
+
end
|
50
|
+
|
51
|
+
def unlock
|
52
|
+
lock_value = redis.get(my_lock)
|
53
|
+
unless lock_value
|
54
|
+
logger.debug "no lock to release"
|
55
|
+
return true
|
56
|
+
end
|
57
|
+
|
58
|
+
lease_expires, owner = lock_value.split('-')
|
59
|
+
if (lease_expires.to_i > Time.now.to_i) && (owner.to_i == Process.pid)
|
60
|
+
redis.del(my_lock)
|
61
|
+
logger.debug "released lock - #{my_lock}, #{lock_value}"
|
62
|
+
return true
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def generate_lock_value(lease_for=DEFAULT_LEASE_FOR, id=Process.pid)
|
67
|
+
"#{Time.now.to_i + lease_for + 1}-#{id}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def with_lock(path='/distlock/redis/exclusive_lock/default', lease_for=DEFAULT_LEASE_FOR, retry_for=DEFAULT_RETRY_FOR)
|
71
|
+
begin
|
72
|
+
lock(path, lease_for, retry_for)
|
73
|
+
yield if block_given?
|
74
|
+
ensure
|
75
|
+
# TODO - store lock path so we don't need to pass it here
|
76
|
+
# unlock(path)
|
77
|
+
unlock
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/distlock/version.rb
CHANGED
@@ -88,10 +88,6 @@ module Distlock
|
|
88
88
|
|
89
89
|
# TODO - pass children in as parameter?
|
90
90
|
children = zk.get_children(:path => path)[:children].sort{|a,b|a.split('-').last <=> b.split('-').last}
|
91
|
-
|
92
|
-
puts lock
|
93
|
-
puts path
|
94
|
-
puts children.inspect
|
95
91
|
|
96
92
|
lock_last = lock.split('/').last
|
97
93
|
lock_idx = children.index(lock_last)
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: distlock
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 0.0.9
|
10
|
+
version: 0.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Simon Horne
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
18
|
+
date: 2012-05-03 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -48,21 +48,6 @@ dependencies:
|
|
48
48
|
version: "2.0"
|
49
49
|
type: :development
|
50
50
|
version_requirements: *id002
|
51
|
-
- !ruby/object:Gem::Dependency
|
52
|
-
name: zookeeper
|
53
|
-
prerelease: false
|
54
|
-
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
-
none: false
|
56
|
-
requirements:
|
57
|
-
- - ~>
|
58
|
-
- !ruby/object:Gem::Version
|
59
|
-
hash: 3
|
60
|
-
segments:
|
61
|
-
- 0
|
62
|
-
- 4
|
63
|
-
version: "0.4"
|
64
|
-
type: :runtime
|
65
|
-
version_requirements: *id003
|
66
51
|
description: Distributed Locking
|
67
52
|
email:
|
68
53
|
- simon@soulware.co.uk
|
@@ -81,6 +66,11 @@ files:
|
|
81
66
|
- lib/dist_lock.rb
|
82
67
|
- lib/distlock.rb
|
83
68
|
- lib/distlock/lock_error.rb
|
69
|
+
- lib/distlock/noop/exclusive_lock.rb
|
70
|
+
- lib/distlock/noop/noop.rb
|
71
|
+
- lib/distlock/redis/common.rb
|
72
|
+
- lib/distlock/redis/exclusive_lock.rb
|
73
|
+
- lib/distlock/redis/redis.rb
|
84
74
|
- lib/distlock/version.rb
|
85
75
|
- lib/distlock/zk/common.rb
|
86
76
|
- lib/distlock/zk/exclusive_lock.rb
|