redis-semaphore 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/redis/semaphore.rb +30 -28
  2. data/spec/redis_spec.rb +44 -8
  3. metadata +2 -2
@@ -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
- return false if @redis.blpop(list_name, timeout).nil?
42
-
43
- @locked = true
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.rpush(list_name, 1)
59
+
60
+ @redis.lpush(list_name, @locked)
59
61
  @locked = false
60
62
  end
61
-
63
+
62
64
  def locked?
63
- @locked
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.lpush(list_name, 1)
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.2
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-06-01 00:00:00.000000000 Z
12
+ date: 2012-07-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis