deadlock_retry 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
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
-