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.
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