redis-semaphore 0.1.2 → 0.1.3
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/lib/redis/semaphore.rb +30 -28
- data/spec/redis_spec.rb +44 -8
- metadata +2 -2
data/lib/redis/semaphore.rb
CHANGED
@@ -2,16 +2,16 @@ require 'redis'
|
|
2
2
|
|
3
3
|
class Redis
|
4
4
|
class Semaphore
|
5
|
-
|
5
|
+
|
6
6
|
attr_reader :resources
|
7
|
-
|
7
|
+
|
8
8
|
# RedisSempahore.new(:my_semaphore, 5, myRedis)
|
9
9
|
# RedisSemaphore.new(:my_semaphore, myRedis)
|
10
10
|
# RedisSemaphore.new(:my_semaphore, :connection => "", :port => "")
|
11
11
|
# RedisSemaphore.new(:my_semaphore, :path => "bla")
|
12
12
|
def initialize(*args)
|
13
13
|
raise "Need at least two arguments" if args.size < 2
|
14
|
-
|
14
|
+
|
15
15
|
@locked = false
|
16
16
|
@name = args.shift.to_s
|
17
17
|
@redis = args.pop
|
@@ -19,69 +19,71 @@ class Redis
|
|
19
19
|
@redis = Redis.new(@redis)
|
20
20
|
end
|
21
21
|
@resources = args.pop || 1
|
22
|
-
|
22
|
+
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
def available
|
26
26
|
@redis.llen(list_name)
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def exists?
|
30
30
|
@redis.exists(exists_name)
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def delete!
|
34
34
|
@redis.del(list_name)
|
35
35
|
@redis.del(exists_name)
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
def lock(timeout = 0)
|
39
39
|
exists_or_create!
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
|
41
|
+
|
42
|
+
resource_index = @redis.blpop(list_name, timeout)
|
43
|
+
return false if resource_index.nil?
|
44
|
+
|
45
|
+
@locked = resource_index[1].to_i
|
44
46
|
if block_given?
|
45
47
|
begin
|
46
|
-
yield
|
48
|
+
yield @locked
|
47
49
|
ensure
|
48
50
|
unlock
|
49
51
|
end
|
50
52
|
end
|
51
|
-
|
53
|
+
|
52
54
|
true
|
53
55
|
end
|
54
|
-
|
56
|
+
|
55
57
|
def unlock
|
56
58
|
return false unless locked?
|
57
|
-
|
58
|
-
@redis.
|
59
|
+
|
60
|
+
@redis.lpush(list_name, @locked)
|
59
61
|
@locked = false
|
60
62
|
end
|
61
|
-
|
63
|
+
|
62
64
|
def locked?
|
63
|
-
|
65
|
+
!!@locked
|
64
66
|
end
|
65
|
-
|
66
|
-
|
67
|
-
private
|
67
|
+
|
68
|
+
|
69
|
+
private
|
68
70
|
def list_name
|
69
71
|
"SEMAPHORE::#{@name}::LIST"
|
70
72
|
end
|
71
|
-
|
73
|
+
|
72
74
|
def exists_name
|
73
75
|
"SEMAPHORE::#{@name}::EXISTS"
|
74
76
|
end
|
75
|
-
|
77
|
+
|
76
78
|
def exists_or_create!
|
77
79
|
exists = @redis.getset(exists_name, 1)
|
78
|
-
|
80
|
+
|
79
81
|
if "1" != exists
|
80
|
-
@resources.times do
|
81
|
-
@redis.
|
82
|
+
@resources.times do |index|
|
83
|
+
@redis.rpush(list_name, index)
|
82
84
|
end
|
83
85
|
end
|
84
86
|
end
|
85
|
-
|
87
|
+
|
86
88
|
end
|
87
89
|
end
|
data/spec/redis_spec.rb
CHANGED
@@ -18,36 +18,72 @@ describe "redis" do
|
|
18
18
|
after(:all) do
|
19
19
|
@redis.quit
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
it "should be unlocked from the start" do
|
23
23
|
@semaphore.locked?.should == false
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
it "should lock and unlock" do
|
27
27
|
@semaphore.lock
|
28
28
|
@semaphore.locked?.should == true
|
29
29
|
@semaphore.unlock
|
30
30
|
@semaphore.locked?.should == false
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
it "should not lock twice as a mutex" do
|
34
34
|
@semaphore.lock
|
35
35
|
@semaphore.lock(1).should == false
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
it "should not lock three times when only two available" do
|
39
39
|
multisem = Redis::Semaphore.new(:my_semaphore2, 2, @redis)
|
40
40
|
multisem.lock.should == true
|
41
41
|
multisem.lock(1).should == true
|
42
42
|
multisem.lock(1).should == false
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
|
+
it "should reuse the same index for 5 calls in serial" do
|
46
|
+
multisem = Redis::Semaphore.new(:my_semaphore5_serial, 5, @redis)
|
47
|
+
ids = []
|
48
|
+
5.times do
|
49
|
+
multisem.lock(1) do |i|
|
50
|
+
ids << i
|
51
|
+
end
|
52
|
+
end
|
53
|
+
ids.size.should == 5
|
54
|
+
ids.uniq.size.should == 1
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should have 5 different indexes for 5 parallel calls" do
|
58
|
+
multisem = Redis::Semaphore.new(:my_semaphore5_parallel, 5, @redis)
|
59
|
+
ids = []
|
60
|
+
multisem.lock(1) do |i|
|
61
|
+
ids << i
|
62
|
+
multisem.lock(1) do |i|
|
63
|
+
ids << i
|
64
|
+
multisem.lock(1) do |i|
|
65
|
+
ids << i
|
66
|
+
multisem.lock(1) do |i|
|
67
|
+
ids << i
|
68
|
+
multisem.lock(1) do |i|
|
69
|
+
ids << i
|
70
|
+
multisem.lock(1) do |i|
|
71
|
+
ids << i
|
72
|
+
end.should == false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
(0..4).to_a.should == ids
|
79
|
+
end
|
80
|
+
|
45
81
|
it "should execute the given code block" do
|
46
82
|
code_executed = false
|
47
83
|
@semaphore.lock do
|
48
84
|
code_executed = true
|
49
85
|
end
|
50
|
-
code_executed.should == true
|
86
|
+
code_executed.should == true
|
51
87
|
end
|
52
88
|
|
53
89
|
it "should pass an exception right through" do
|
@@ -59,12 +95,12 @@ describe "redis" do
|
|
59
95
|
end
|
60
96
|
|
61
97
|
it "should not leave the semaphore locked after raising an exception" do
|
62
|
-
lambda do
|
98
|
+
lambda do
|
63
99
|
@semaphore.lock do
|
64
100
|
raise Exception
|
65
101
|
end
|
66
102
|
end.should raise_error
|
67
|
-
|
103
|
+
|
68
104
|
@semaphore.locked?.should == false
|
69
105
|
end
|
70
106
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-semaphore
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
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-
|
12
|
+
date: 2012-07-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redis
|