Class: SolidObjects::DatabaseAdapters::Mysql
Constant Summary
collapse
- MAXIMUM_EXECUTION_TIME_EXCEEDED =
3024
SolidObjects::DatabaseAdapter::FAMILIES, SolidObjects::DatabaseAdapter::TRANSACTION_CLOCK, SolidObjects::DatabaseAdapter::TRANSACTION_CLOCK_SCOPE
Instance Attribute Summary
#connection_pool, #fixed_connection
Instance Method Summary
collapse
#configure_transaction_deadline, #database_now, family, for, #initialize, #lock_candidates, #read_database_now, #server_version, #transaction, #unsupported_server_reasons, #with_connection, #with_lock_probe, #with_lock_retry, #with_transaction_clock
Instance Method Details
#additional_server_reasons ⇒ Array[String]
A non-transactional engine would silently break fenced commits, so the
storage engine is verified rather than assumed.
21
22
23
24
25
26
27
|
# File 'lib/solid_objects/database_adapters/mysql.rb', line 21
def additional_server_reasons
tables = non_innodb_tables
return [] if tables.empty?
[ "these Solid Objects tables do not use InnoDB, so their commits are " \
"not transactional: #{tables.join(", ")}" ]
end
|
#claim_lock ⇒ String
14
15
16
|
# File 'lib/solid_objects/database_adapters/mysql.rb', line 14
def claim_lock
"FOR UPDATE SKIP LOCKED"
end
|
#current_time_expression ⇒ String
47
48
49
|
# File 'lib/solid_objects/database_adapters/mysql.rb', line 47
def current_time_expression
"CURRENT_TIMESTAMP(6)"
end
|
#deadline_error?(error) ⇒ Boolean
A deadline is enforced by asking the server to interrupt the statement,
so recognising that interruption is what turns it back into a timeout
the caller asked for. Active Record classifies it for every client, and
the raw code is the fallback: mysql2 names it error_number and
Trilogy names it error_code, so both are read.
89
90
91
92
93
94
95
96
97
98
99
100
101
|
# File 'lib/solid_objects/database_adapters/mysql.rb', line 89
def deadline_error?(error)
return false unless SyncDeadline.active?
return true if error.is_a?(ActiveRecord::LockWaitTimeout)
return true if error.is_a?(ActiveRecord::StatementTimeout)
cause = error
while cause
return true if error_code(cause) == MAXIMUM_EXECUTION_TIME_EXCEEDED
cause = cause.cause
end
false
end
|
#error_code(error) ⇒ Integer?
104
105
106
107
108
109
|
# File 'lib/solid_objects/database_adapters/mysql.rb', line 104
def error_code(error)
return error.error_number if error.respond_to?(:error_number)
return error.error_code if error.respond_to?(:error_code)
nil
end
|
#minimum_server_version ⇒ Gem::Version?
42
43
44
|
# File 'lib/solid_objects/database_adapters/mysql.rb', line 42
def minimum_server_version
Gem::Version.new("8.0")
end
|
#non_innodb_tables ⇒ Array[String]
30
31
32
33
34
35
36
37
38
39
|
# File 'lib/solid_objects/database_adapters/mysql.rb', line 30
def non_innodb_tables
names = SolidObjects::Doctor::EXPECTED_COLUMNS.keys.map { |name| SolidObjects.table_name(name) }
with_connection do |connection|
connection.select_rows(<<~SQL.squish).filter_map { |table, engine| table if engine != "InnoDB" }
SELECT table_name, engine FROM information_schema.tables
WHERE table_schema = DATABASE()
AND table_name IN (#{names.map { |name| connection.quote(name) }.join(", ")})
SQL
end
end
|
#supports_skip_locked? ⇒ Boolean
9
10
11
|
# File 'lib/solid_objects/database_adapters/mysql.rb', line 9
def supports_skip_locked?
true
end
|
#with_transaction_deadline(connection) { ... } ⇒ Object
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
# File 'lib/solid_objects/database_adapters/mysql.rb', line 54
def with_transaction_deadline(connection)
return yield unless SyncDeadline.active?
previous_lock_timeout = connection.select_value(
"SELECT @@SESSION.innodb_lock_wait_timeout"
).to_i
previous_execution_timeout = connection.select_value(
"SELECT @@SESSION.max_execution_time"
).to_i
connection.execute(
"SET SESSION innodb_lock_wait_timeout = #{SyncDeadline.remaining_seconds}"
)
connection.execute(
"SET SESSION max_execution_time = #{SyncDeadline.remaining_milliseconds}"
)
yield
ensure
if previous_lock_timeout
connection.execute(
"SET SESSION innodb_lock_wait_timeout = #{previous_lock_timeout}"
)
end
if previous_execution_timeout
connection.execute(
"SET SESSION max_execution_time = #{previous_execution_timeout}"
)
end
end
|