distributed_mutex 1.0.2 → 1.1.0

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/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.2
1
+ 1.1.0
@@ -1,4 +1,5 @@
1
1
  require 'mutex_lock_timeout'
2
+ require 'mutex_lock_release_failure'
2
3
 
3
4
  class DistributedMutex < Mutex
4
5
 
@@ -16,7 +17,8 @@ class DistributedMutex < Mutex
16
17
  end
17
18
 
18
19
  def lock
19
- if @locked = get_lock
20
+ @locked = get_lock
21
+ if true == @locked
20
22
  true
21
23
  else
22
24
  if @exception_on_timeout
@@ -56,12 +58,12 @@ class DistributedMutex < Mutex
56
58
  end
57
59
 
58
60
  def unlock
59
- if @locked
61
+ if locked?
60
62
  if release_lock
61
63
  @locked = false
62
64
  true
63
65
  else
64
- false
66
+ raise MutexLockReleaseFailure
65
67
  end
66
68
  else
67
69
  false
@@ -0,0 +1,6 @@
1
+ class MutexLockReleaseFailure < StandardError
2
+
3
+ def message
4
+ 'Failed to release Mutex lock. This should be regarded as a system bug.'
5
+ end
6
+ end
data/lib/mysql_mutex.rb CHANGED
@@ -3,40 +3,82 @@ require 'distributed_mutex'
3
3
 
4
4
  class MySQLMutex < DistributedMutex
5
5
 
6
- @active_locks = Hash.new
6
+ @@thread_locks = Hash.new { |h,k| h[k] = Hash.new(0) } # Accounting for nested locks.
7
7
 
8
8
  def initialize(key, timeout = DEFAULT_TIMEOUT, exception_on_timeout = DEFAULT_EXCEPTION_ON_TIMEOUT, connection = ActiveRecord::Base.connection)
9
+ super(key, timeout, exception_on_timeout)
9
10
  @connection = connection
10
- @lock_was_free = false
11
- @get_sql = ActiveRecord::Base.send(:sanitize_sql_array,["SELECT IS_FREE_LOCK(?), GET_LOCK(?,?)", key, key, timeout])
11
+ @connection_id = connection.show_variable('pseudo_thread_id')
12
+ @get_sql = ActiveRecord::Base.send(:sanitize_sql_array,["SELECT GET_LOCK(?,?)", key, timeout])
12
13
  @release_sql = ActiveRecord::Base.send(:sanitize_sql_array,["SELECT RELEASE_LOCK(?)", key])
13
- super(key, timeout, exception_on_timeout)
14
- end
15
-
16
- def self.active_locks
17
- @active_locks
18
14
  end
19
15
 
20
16
  def self.synchronize(key, timeout = DEFAULT_TIMEOUT, exception_on_timeout = DEFAULT_TIMEOUT, con = ActiveRecord::Base.connection, &block)
21
17
  mutex = new(key, timeout, exception_on_timeout, con)
22
- @active_locks[key] = timeout
23
18
  mutex.synchronize(&block)
24
- @active_locks.delete(key)
19
+ end
20
+
21
+ def self.active_locks
22
+ @@thread_locks
25
23
  end
26
24
 
27
25
  private
28
26
 
29
27
  def get_lock
30
- is_free_lock, get_lock = @connection.select_rows(@get_sql).first
31
- @lock_was_free = ('1' == is_free_lock)
32
- '1' == get_lock
28
+ if thread_lock_count > 0
29
+ increment_thread_lock_count
30
+ true
31
+ else
32
+ get_lock = @connection.select_value(@get_sql)
33
+
34
+ if defined?(Rails)
35
+ Rails.logger.debug("MySQLMutex: GET_LOCK=#{get_lock}")
36
+ end
37
+
38
+ if '1' == get_lock
39
+ increment_thread_lock_count
40
+ true
41
+ else
42
+ false
43
+ end
44
+ end
33
45
  end
34
46
 
35
47
  def release_lock
36
- if @lock_was_free
37
- '1' == @connection.select_value(@release_sql)
38
- else
48
+ if thread_lock_count > 1
49
+ decrement_thread_lock_count
39
50
  true
51
+ elsif thread_lock_count > 0
52
+ lock_release = @connection.select_value(@release_sql)
53
+
54
+ if defined?(Rails)
55
+ Rails.logger.debug("MySQLMutex: RELEASE_LOCK=#{lock_release}")
56
+ end
57
+
58
+ if '1' == lock_release
59
+ decrement_thread_lock_count
60
+ true
61
+ else
62
+ false
63
+ end
64
+ else
65
+ false
66
+ end
67
+ end
68
+
69
+ def thread_lock_count
70
+ @@thread_locks[@connection_id][self.key]
71
+ end
72
+
73
+ def increment_thread_lock_count
74
+ @@thread_locks[@connection_id][self.key] += 1
75
+ end
76
+
77
+ def decrement_thread_lock_count
78
+ @@thread_locks[@connection_id][self.key] -= 1
79
+
80
+ if 0 == @@thread_locks[@connection_id][self.key]
81
+ @@thread_locks[@connection_id].delete(self.key)
40
82
  end
41
83
  end
42
84
 
@@ -44,6 +86,10 @@ end
44
86
 
45
87
  at_exit do
46
88
  locks = MySQLMutex.active_locks
89
+ locks.delete_if do |k, v|
90
+ v.empty?
91
+ end
92
+
47
93
  if locks.size > 0
48
94
  if defined?(Rails)
49
95
  Rails.logger.error("MySQLMutex: Locks still active! - #{locks.inspect}")
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 1
7
+ - 1
7
8
  - 0
8
- - 2
9
- version: 1.0.2
9
+ version: 1.1.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Birkir A. Barkarson
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-12-06 00:00:00 +09:00
17
+ date: 2010-12-10 00:00:00 +09:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -33,6 +33,7 @@ files:
33
33
  - init.rb
34
34
  - lib/distributed_mutex.rb
35
35
  - lib/global_mutex.rb
36
+ - lib/mutex_lock_release_failure.rb
36
37
  - lib/mutex_lock_timeout.rb
37
38
  - lib/mysql_mutex.rb
38
39
  - rails/init.rb