redis-em-mutex 0.2.0 → 0.2.1

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