deadlock_retry 1.1.1 → 1.1.2

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/CHANGELOG CHANGED
@@ -1,5 +1,10 @@
1
1
  deadlock_retry changes
2
2
 
3
+ == v1.1.2
4
+
5
+ * Exponential backoff, sleep 0, 1, 2, 4... seconds between retries.
6
+ * Support new syntax for InnoDB status in MySQL 5.5.
7
+
3
8
  == v1.1.1 (2011-05-13)
4
9
 
5
10
  * Conditionally log INNODB STATUS only if user has permission. (osheroff)
@@ -1,12 +1,15 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
+ require './lib/deadlock_retry'
4
+
3
5
  Gem::Specification.new do |s|
4
6
  s.name = %q{deadlock_retry}
5
- s.version = "1.1.1"
7
+ s.version = DeadlockRetry::VERSION
6
8
  s.authors = ["Jamis Buck", "Mike Perham"]
7
9
  s.description = s.summary = %q{Provides automatic deadlock retry and logging functionality for ActiveRecord and MySQL}
8
10
  s.email = %q{mperham@gmail.com}
9
11
  s.files = `git ls-files`.split("\n")
10
12
  s.homepage = %q{http://github.com/mperham/deadlock_retry}
11
13
  s.require_paths = ["lib"]
14
+ s.add_development_dependency 'mocha'
12
15
  end
@@ -1,4 +1,9 @@
1
+ require 'active_support/core_ext/module/attribute_accessors'
2
+
1
3
  module DeadlockRetry
4
+
5
+ VERSION = '1.1.2'
6
+
2
7
  def self.included(base)
3
8
  base.extend(ClassMethods)
4
9
  base.class_eval do
@@ -8,15 +13,7 @@ module DeadlockRetry
8
13
  end
9
14
  end
10
15
 
11
- @@innodb_status_available = nil
12
-
13
- def self.innodb_status_available?
14
- @@innodb_status_available
15
- end
16
-
17
- def self.innodb_status_available=(bool)
18
- @@innodb_status_available = bool
19
- end
16
+ mattr_accessor :innodb_status_cmd
20
17
 
21
18
  module ClassMethods
22
19
  DEADLOCK_ERROR_MESSAGES = [
@@ -40,7 +37,8 @@ module DeadlockRetry
40
37
  raise if retry_count >= MAXIMUM_RETRIES_ON_DEADLOCK
41
38
  retry_count += 1
42
39
  logger.info "Deadlock detected on retry #{retry_count}, restarting transaction"
43
- log_innodb_status if DeadlockRetry.innodb_status_available?
40
+ log_innodb_status if DeadlockRetry.innodb_status_cmd
41
+ exponential_pause(retry_count)
44
42
  retry
45
43
  else
46
44
  raise
@@ -50,25 +48,41 @@ module DeadlockRetry
50
48
 
51
49
  private
52
50
 
51
+ WAIT_TIMES = [0, 1, 2, 4, 8, 16, 32]
52
+
53
+ def exponential_pause(count)
54
+ sec = WAIT_TIMES[count-1] || 32
55
+ # sleep 0, 1, 2, 4, ... seconds up to the MAXIMUM_RETRIES.
56
+ # Cap the pause time at 32 seconds.
57
+ sleep(sec) if sec != 0
58
+ end
59
+
53
60
  def in_nested_transaction?
54
61
  # open_transactions was added in 2.2's connection pooling changes.
55
62
  connection.open_transactions != 0
56
63
  end
57
64
 
58
65
  def show_innodb_status
59
- self.connection.select_value("show innodb status")
66
+ self.connection.select_value(DeadlockRetry.innodb_status_cmd)
60
67
  end
61
68
 
62
69
  # Should we try to log innodb status -- if we don't have permission to,
63
70
  # we actually break in-flight transactions, silently (!)
64
71
  def check_innodb_status_available
65
- return unless DeadlockRetry.innodb_status_available? == nil
72
+ return unless DeadlockRetry.innodb_status_cmd == nil
66
73
 
67
74
  begin
68
- show_innodb_status
69
- DeadlockRetry.innodb_status_available = true
75
+ mysql_version = self.connection.execute('show variables like \'version\'').to_a[0][1]
76
+ cmd = if mysql_version < '5.5'
77
+ 'show innodb status'
78
+ else
79
+ 'show engine innodb status'
80
+ end
81
+ self.connection.select_value(cmd)
82
+ DeadlockRetry.innodb_status_cmd = cmd
70
83
  rescue
71
- DeadlockRetry.innodb_status_available = false
84
+ logger.info "Cannot log innodb status: #{$!.message}"
85
+ DeadlockRetry.innodb_status_cmd = false
72
86
  end
73
87
  end
74
88
 
@@ -80,12 +94,12 @@ module DeadlockRetry
80
94
  lines.each_line do |line|
81
95
  logger.warn line
82
96
  end
83
- rescue Exception => e
97
+ rescue => e
84
98
  # Access denied, ignore
85
- logger.warn "Cannot log innodb status: #{e.message}"
99
+ logger.info "Cannot log innodb status: #{e.message}"
86
100
  end
87
101
 
88
102
  end
89
103
  end
90
104
 
91
- ActiveRecord::Base.send(:include, DeadlockRetry)
105
+ ActiveRecord::Base.send(:include, DeadlockRetry) if defined?(ActiveRecord)
@@ -7,6 +7,7 @@ require 'active_record/version'
7
7
  puts "Testing ActiveRecord #{ActiveRecord::VERSION::STRING}"
8
8
 
9
9
  require 'test/unit'
10
+ require 'mocha'
10
11
  require 'logger'
11
12
  require "deadlock_retry"
12
13
 
@@ -36,8 +37,12 @@ class MockModel
36
37
  []
37
38
  end
38
39
 
39
- def self.reset_innodb_status_availability
40
- DeadlockRetry.innodb_status_availability = nil
40
+ def self.execute(sql)
41
+ [['version', '5.1.45']]
42
+ end
43
+
44
+ def self.select_value(sql)
45
+ true
41
46
  end
42
47
 
43
48
  include DeadlockRetry
@@ -48,6 +53,7 @@ class DeadlockRetryTest < Test::Unit::TestCase
48
53
  TIMEOUT_ERROR = "MySQL::Error: Lock wait timeout exceeded"
49
54
 
50
55
  def setup
56
+ MockModel.stubs(:exponential_pause)
51
57
  end
52
58
 
53
59
  def test_no_errors
@@ -83,9 +89,9 @@ class DeadlockRetryTest < Test::Unit::TestCase
83
89
  end
84
90
 
85
91
  def test_innodb_status_availability
86
- DeadlockRetry.innodb_status_available = nil
92
+ DeadlockRetry.innodb_status_cmd = nil
87
93
  MockModel.transaction {}
88
- assert_equal true, DeadlockRetry.innodb_status_available?
94
+ assert_equal "show innodb status", DeadlockRetry.innodb_status_cmd
89
95
  end
90
96
 
91
97
 
metadata CHANGED
@@ -1,28 +1,35 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: deadlock_retry
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.2
4
5
  prerelease:
5
- version: 1.1.1
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Jamis Buck
9
9
  - Mike Perham
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
-
14
- date: 2011-05-14 00:00:00 Z
15
- dependencies: []
16
-
17
- description: Provides automatic deadlock retry and logging functionality for ActiveRecord and MySQL
13
+ date: 2011-10-27 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: mocha
17
+ requirement: &2152103420 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *2152103420
26
+ description: Provides automatic deadlock retry and logging functionality for ActiveRecord
27
+ and MySQL
18
28
  email: mperham@gmail.com
19
29
  executables: []
20
-
21
30
  extensions: []
22
-
23
31
  extra_rdoc_files: []
24
-
25
- files:
32
+ files:
26
33
  - .gitignore
27
34
  - CHANGELOG
28
35
  - LICENSE
@@ -33,30 +40,27 @@ files:
33
40
  - test/deadlock_retry_test.rb
34
41
  homepage: http://github.com/mperham/deadlock_retry
35
42
  licenses: []
36
-
37
43
  post_install_message:
38
44
  rdoc_options: []
39
-
40
- require_paths:
45
+ require_paths:
41
46
  - lib
42
- required_ruby_version: !ruby/object:Gem::Requirement
47
+ required_ruby_version: !ruby/object:Gem::Requirement
43
48
  none: false
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: "0"
48
- required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
54
  none: false
50
- requirements:
51
- - - ">="
52
- - !ruby/object:Gem::Version
53
- version: "0"
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
54
59
  requirements: []
55
-
56
60
  rubyforge_project:
57
- rubygems_version: 1.7.2
61
+ rubygems_version: 1.8.10
58
62
  signing_key:
59
63
  specification_version: 3
60
- summary: Provides automatic deadlock retry and logging functionality for ActiveRecord and MySQL
64
+ summary: Provides automatic deadlock retry and logging functionality for ActiveRecord
65
+ and MySQL
61
66
  test_files: []
62
-