redis-em-mutex 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY.rdoc CHANGED
@@ -1,3 +1,7 @@
1
+ 0.2.1
2
+ - fixed: sleep
3
+ - fixed: possible deadlock after #unlock! with multiple names
4
+
1
5
  0.2.0
2
6
  - added compatibility with EM::Synchrony::Thread::ConditionVariable
3
7
  - added #sleep and #wakeup
data/README.rdoc CHANGED
@@ -44,7 +44,7 @@ Author:: Rafał Michalski (mailto:rafal@yeondir.com)
44
44
 
45
45
  ==== Gemfile
46
46
 
47
- gem "redis-em-mutex", "~> 0.2.0"
47
+ gem "redis-em-mutex", "~> 0.2.1"
48
48
 
49
49
  ==== Github
50
50
 
@@ -1,7 +1,7 @@
1
1
  class Redis
2
2
  module EM
3
3
  class Mutex
4
- VERSION = '0.2.0'
4
+ VERSION = '0.2.1'
5
5
  end
6
6
  end
7
7
  end
@@ -3,7 +3,6 @@ require 'ostruct'
3
3
  require 'securerandom'
4
4
  require 'redis/connection/synchrony' unless defined? Redis::Connection::Synchrony
5
5
  require 'redis'
6
- require 'redis/em-mutex/version'
7
6
 
8
7
  class Redis
9
8
  module EM
@@ -210,24 +209,30 @@ class Redis
210
209
  # Releases the lock. Returns self on success.
211
210
  # Returns `false` if the semaphore wasn't locked or when it was locked but it has expired
212
211
  # and now it's got a new owner.
212
+ # In case of unlocking multiple name semaphore this method returns self only when all
213
+ # of the names have been unlocked successfully.
213
214
  def unlock!
214
- ret = false
215
+ sem_left = @ns_names.length
215
216
  if @locked_id && owner_ident(@locked_id) == (lock_full_ident = @locked_owner_id)
216
217
  @@redis_pool.execute(false) do |r|
217
- r.watch(*@ns_names) do
218
- if r.mget(*@ns_names).all? {|v| v == lock_full_ident}
219
- ret = !!r.multi do |multi|
220
- multi.del(*@ns_names)
221
- multi.publish SIGNAL_QUEUE_CHANNEL, Marshal.dump(@ns_names)
218
+ @ns_names.each do |name|
219
+ r.watch(name) do
220
+ if r.get(name) == lock_full_ident
221
+ if (r.multi {|multi|
222
+ multi.del(name)
223
+ multi.publish SIGNAL_QUEUE_CHANNEL, Marshal.dump([name])
224
+ })
225
+ sem_left -= 1
226
+ end
227
+ else
228
+ r.unwatch
222
229
  end
223
- else
224
- r.unwatch
225
230
  end
226
231
  end
227
232
  end
228
233
  @locked_owner_id = @locked_id = nil
229
234
  end
230
- ret && self
235
+ sem_left.zero? && self
231
236
  end
232
237
 
233
238
  # Releases the lock unconditionally.
@@ -548,7 +553,7 @@ class Redis
548
553
  # EM sleep helper
549
554
  def sleep(seconds)
550
555
  fiber = Fiber.current
551
- ::EM::Timer.new(secs) { fiber.resume }
556
+ ::EM::Timer.new(seconds) { fiber.resume }
552
557
  Fiber.yield
553
558
  end
554
559
 
@@ -635,3 +640,5 @@ class Redis
635
640
  end
636
641
  end
637
642
  end
643
+
644
+ require 'redis/em-mutex/version'
@@ -1,4 +1,4 @@
1
- if defined?(Redis::EM::Mutex)
1
+ if defined?(::Redis) && ::Redis.const_defined?(:EM, false) && ::Redis::EM.const_defined?(:Mutex, false)
2
2
  require 'redis/em-mutex'
3
3
  else
4
4
  class Redis
@@ -54,8 +54,8 @@ describe Redis::EM::Mutex do
54
54
  ::EM.add_timer(0.15) do
55
55
  mutex.wakeup(fiber)
56
56
  end
57
- mutex.sleep(0.25).should be_within(0.001).of(0.15)
58
- (Time.now - start).should be_within(0.001).of(0.15)
57
+ mutex.sleep(0.25).should be_within(0.005).of(0.15)
58
+ (Time.now - start).should be_within(0.005).of(0.15)
59
59
  mutex.owned?.should be true
60
60
  mutex.unlock!.should be_true
61
61
  ensure
@@ -122,7 +122,7 @@ describe Redis::EM::Mutex do
122
122
  end
123
123
  start = Time.now
124
124
  now = Fiber.yield
125
- (now - signal).should be_within(0.001).of(0.001)
125
+ (now - signal).should be_within(0.002).of(0.001)
126
126
  (now - start).should be_within(0.01).of(0.2)
127
127
  mutex.synchronize do
128
128
  signal = nil
@@ -80,6 +80,12 @@ describe Redis::EM::Mutex do
80
80
  redis.client.scheme.should eq 'redis'
81
81
  end
82
82
 
83
+ it "should be able to sleep" do
84
+ t = Time.now
85
+ described_class.sleep 0.11
86
+ (Time.now - t).should be_within(0.02).of(0.11)
87
+ end
88
+
83
89
  around(:each) do |testcase|
84
90
  @after_em_stop = nil
85
91
  ::EM.synchrony do
@@ -103,7 +103,7 @@ describe Redis::EM::Mutex do
103
103
  ::EM.next_tick { fiber.resume }
104
104
  start = Time.now
105
105
  mutex2.lock.should be true
106
- (Time.now - start).should be_within(0.01).of(0.5)
106
+ (Time.now - start).should be_within(0.02).of(0.5)
107
107
  rescue Exception => e
108
108
  @exception = e
109
109
  ensure
@@ -386,6 +386,27 @@ describe Redis::EM::Mutex do
386
386
  end
387
387
  end
388
388
 
389
+ it "should unlock multiple names independently" do
390
+ begin
391
+ mutex = described_class.lock(*@lock_names[0,2], expire: 0.01)
392
+ mutex.should be_an_instance_of described_class
393
+ EM::Synchrony.sleep 0.02
394
+ fiber = Fiber.current
395
+ EM::Synchrony.next_tick {
396
+ mutex2 = described_class.lock(*@lock_names[1,2])
397
+ mutex2.should be_an_instance_of described_class
398
+ mutex2.unlock!.should be mutex2
399
+ fiber.resume
400
+ }
401
+ Fiber.yield
402
+ mutex.unlock!.should be false
403
+ mutex.lock.should be true
404
+ mutex.should be_an_instance_of described_class
405
+ ensure
406
+ mutex.unlock if mutex
407
+ end
408
+ end
409
+
389
410
  around(:each) do |testcase|
390
411
  @after_em_stop = nil
391
412
  @exception = nil
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis-em-mutex
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-25 00:00:00.000000000 Z
12
+ date: 2012-11-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis
16
- requirement: &133617360 !ruby/object:Gem::Requirement
16
+ requirement: &219325340 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 3.0.1
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *133617360
24
+ version_requirements: *219325340
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: hiredis
27
- requirement: &133616520 !ruby/object:Gem::Requirement
27
+ requirement: &219340740 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 0.4.5
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *133616520
35
+ version_requirements: *219340740
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: eventmachine
38
- requirement: &133615240 !ruby/object:Gem::Requirement
38
+ requirement: &219339740 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 1.0.0.beta.1
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *133615240
46
+ version_requirements: *219339740
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec
49
- requirement: &133614140 !ruby/object:Gem::Requirement
49
+ requirement: &219338960 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 2.8.0
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *133614140
57
+ version_requirements: *219338960
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: eventmachine
60
- requirement: &133629580 !ruby/object:Gem::Requirement
60
+ requirement: &219338220 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 1.0.0
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *133629580
68
+ version_requirements: *219338220
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: em-synchrony
71
- requirement: &133629000 !ruby/object:Gem::Requirement
71
+ requirement: &219337400 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ~>
@@ -76,7 +76,7 @@ dependencies:
76
76
  version: 1.0.0
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *133629000
79
+ version_requirements: *219337400
80
80
  description: Cross server-process-fiber EventMachine + Redis based semaphore with
81
81
  many features
82
82
  email: rafal@yeondir.com