pg_pipeline 0.3.3 → 0.3.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/lib/pg_pipeline/bounded_queue.rb +8 -6
- data/lib/pg_pipeline/client.rb +55 -37
- data/lib/pg_pipeline/connection_driver.rb +349 -272
- data/lib/pg_pipeline/pool.rb +229 -157
- data/lib/pg_pipeline/prepared_statement.rb +5 -5
- data/lib/pg_pipeline/request.rb +18 -17
- data/lib/pg_pipeline/runtime/notification.rb +2 -1
- data/lib/pg_pipeline/runtime/semaphore.rb +3 -3
- data/lib/pg_pipeline/runtime/task.rb +14 -8
- data/lib/pg_pipeline/runtime.rb +17 -18
- data/lib/pg_pipeline/server_caps.rb +3 -3
- data/lib/pg_pipeline/session.rb +9 -7
- data/lib/pg_pipeline/session_guard.rb +108 -73
- data/lib/pg_pipeline/transaction.rb +33 -34
- data/lib/pg_pipeline/type_maps.rb +37 -22
- data/lib/pg_pipeline/version.rb +1 -1
- metadata +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require 'pg'
|
|
4
4
|
|
|
5
|
-
require_relative
|
|
5
|
+
require_relative 'session'
|
|
6
6
|
|
|
7
7
|
module PgPipeline
|
|
8
8
|
class Transaction < Session
|
|
@@ -30,68 +30,67 @@ module PgPipeline
|
|
|
30
30
|
module TransactionOps
|
|
31
31
|
module_function
|
|
32
32
|
|
|
33
|
-
def run(
|
|
34
|
-
SessionOps.ensure_active!(
|
|
35
|
-
raise Error,
|
|
33
|
+
def run(transaction)
|
|
34
|
+
SessionOps.ensure_active!(transaction)
|
|
35
|
+
raise Error, 'transaction is already open' if transaction.open?
|
|
36
36
|
|
|
37
|
-
conn = SessionOps.connection(
|
|
38
|
-
conn.exec(
|
|
39
|
-
|
|
37
|
+
conn = SessionOps.connection(transaction)
|
|
38
|
+
conn.exec('BEGIN')
|
|
39
|
+
transaction.__send__(:open=, true)
|
|
40
40
|
begin
|
|
41
|
-
result = yield
|
|
41
|
+
result = yield transaction
|
|
42
42
|
commit(conn)
|
|
43
|
-
|
|
43
|
+
transaction.__send__(:open=, false)
|
|
44
44
|
result
|
|
45
45
|
rescue Exception
|
|
46
|
-
rollback_quietly(
|
|
46
|
+
rollback_quietly(transaction)
|
|
47
47
|
raise
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
def commit(conn)
|
|
52
|
-
conn.exec(
|
|
53
|
-
rescue PG::Error =>
|
|
54
|
-
raise unless indeterminate_commit_failure?(conn,
|
|
52
|
+
conn.exec('COMMIT')
|
|
53
|
+
rescue PG::Error => e
|
|
54
|
+
raise unless indeterminate_commit_failure?(conn, e)
|
|
55
55
|
|
|
56
56
|
raise IndeterminateCommitError.new(
|
|
57
|
-
|
|
58
|
-
"and must not be retried blindly (#{
|
|
59
|
-
), cause:
|
|
57
|
+
'COMMIT acknowledgement was not received; the transaction may have committed ' \
|
|
58
|
+
"and must not be retried blindly (#{e.class}: #{e.message})"
|
|
59
|
+
), cause: e
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
def indeterminate_commit_failure?(conn, error)
|
|
63
63
|
return true if defined?(PG::ConnectionBad) && error.is_a?(PG::ConnectionBad)
|
|
64
|
+
return false unless conn.respond_to?(:finished?) && conn.respond_to?(:status)
|
|
64
65
|
return true if conn.finished?
|
|
65
66
|
|
|
66
67
|
conn.status != PG::CONNECTION_OK
|
|
67
68
|
rescue PG::Error
|
|
68
69
|
true
|
|
69
|
-
rescue NoMethodError
|
|
70
|
-
false
|
|
71
70
|
end
|
|
72
71
|
|
|
73
|
-
def savepoint(
|
|
74
|
-
SessionOps.ensure_active!(
|
|
75
|
-
raise Error,
|
|
72
|
+
def savepoint(transaction, name)
|
|
73
|
+
SessionOps.ensure_active!(transaction)
|
|
74
|
+
raise Error, 'savepoint requires an open transaction' unless transaction.open?
|
|
76
75
|
|
|
77
|
-
conn = SessionOps.connection(
|
|
78
|
-
seq =
|
|
79
|
-
|
|
76
|
+
conn = SessionOps.connection(transaction)
|
|
77
|
+
seq = transaction.__send__(:savepoint_seq) + 1
|
|
78
|
+
transaction.__send__(:savepoint_seq=, seq)
|
|
80
79
|
point = name || "pgp_sp_#{seq}"
|
|
81
80
|
ident = conn.quote_ident(point)
|
|
82
81
|
conn.exec("SAVEPOINT #{ident}")
|
|
83
82
|
begin
|
|
84
|
-
result = yield
|
|
83
|
+
result = yield transaction
|
|
85
84
|
conn.exec("RELEASE SAVEPOINT #{ident}")
|
|
86
85
|
result
|
|
87
86
|
rescue Exception
|
|
88
|
-
rollback_to_savepoint(
|
|
87
|
+
rollback_to_savepoint(transaction, ident)
|
|
89
88
|
raise
|
|
90
89
|
end
|
|
91
90
|
end
|
|
92
91
|
|
|
93
|
-
def rollback_to_savepoint(
|
|
94
|
-
conn = SessionOps.connection(
|
|
92
|
+
def rollback_to_savepoint(transaction, ident)
|
|
93
|
+
conn = SessionOps.connection(transaction)
|
|
95
94
|
return unless conn
|
|
96
95
|
|
|
97
96
|
conn.exec("ROLLBACK TO SAVEPOINT #{ident}")
|
|
@@ -100,15 +99,15 @@ module PgPipeline
|
|
|
100
99
|
nil
|
|
101
100
|
end
|
|
102
101
|
|
|
103
|
-
def rollback_quietly(
|
|
104
|
-
return unless
|
|
102
|
+
def rollback_quietly(transaction)
|
|
103
|
+
return unless transaction.open?
|
|
105
104
|
|
|
106
|
-
conn = SessionOps.connection(
|
|
107
|
-
conn&.exec(
|
|
105
|
+
conn = SessionOps.connection(transaction)
|
|
106
|
+
conn&.exec('ROLLBACK')
|
|
108
107
|
rescue PG::Error
|
|
109
108
|
nil
|
|
110
109
|
ensure
|
|
111
|
-
|
|
110
|
+
transaction.__send__(:open=, false)
|
|
112
111
|
end
|
|
113
112
|
end
|
|
114
113
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require_relative
|
|
3
|
+
require 'pg'
|
|
4
|
+
require_relative 'errors'
|
|
5
5
|
|
|
6
6
|
module PgPipeline
|
|
7
7
|
class TypeMaps
|
|
@@ -40,47 +40,62 @@ module PgPipeline
|
|
|
40
40
|
def ensure_bundle!(connection_args)
|
|
41
41
|
return if @bundle && @bundle != :failed
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
conn = connection_args.nil? ? PG::Connection.new : PG::Connection.new(connection_args)
|
|
45
|
-
@bundle = PG::BasicTypeRegistry::CoderMapsBundle.new(conn)
|
|
46
|
-
@text_map_for_results = PG::BasicTypeMapForResults.new(@bundle)
|
|
43
|
+
build_bundle(connection_args)
|
|
47
44
|
rescue StandardError => e
|
|
48
45
|
@bundle = :failed
|
|
49
46
|
@text_map_for_results = nil
|
|
50
47
|
raise Error, "failed to build CoderMapsBundle (#{e.class}: #{e.message})"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def build_bundle(connection_args)
|
|
53
|
+
conn = open_connection(connection_args)
|
|
54
|
+
@bundle = PG::BasicTypeRegistry::CoderMapsBundle.new(conn)
|
|
55
|
+
@text_map_for_results = PG::BasicTypeMapForResults.new(@bundle)
|
|
51
56
|
ensure
|
|
52
|
-
|
|
53
|
-
conn&.close
|
|
54
|
-
rescue StandardError
|
|
55
|
-
nil
|
|
56
|
-
end
|
|
57
|
+
close_connection(conn)
|
|
57
58
|
end
|
|
58
59
|
|
|
60
|
+
def open_connection(connection_args)
|
|
61
|
+
return PG::Connection.new if connection_args.nil?
|
|
62
|
+
|
|
63
|
+
PG::Connection.new(connection_args)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def close_connection(conn)
|
|
67
|
+
conn&.close
|
|
68
|
+
rescue StandardError
|
|
69
|
+
nil
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
public
|
|
73
|
+
|
|
59
74
|
def apply!(request, result, _conn)
|
|
60
75
|
map = request.type_map
|
|
61
76
|
return if map.nil?
|
|
62
77
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
map = @cache[name]
|
|
66
|
-
unless map
|
|
67
|
-
map = build_column_map!(result)
|
|
68
|
-
@cache[name] = map
|
|
69
|
-
end
|
|
70
|
-
request.type_map = map
|
|
71
|
-
end
|
|
78
|
+
map = resolve_type_map(request, result, map)
|
|
79
|
+
request.type_map = map if request.type_map.equal?(PENDING)
|
|
72
80
|
|
|
73
81
|
result.type_map = map
|
|
74
82
|
end
|
|
75
83
|
|
|
76
84
|
private
|
|
77
85
|
|
|
86
|
+
def resolve_type_map(request, result, map)
|
|
87
|
+
return map unless map.equal?(PENDING)
|
|
88
|
+
|
|
89
|
+
name = request.statement_name
|
|
90
|
+
@cache[name] ||= build_column_map!(result)
|
|
91
|
+
end
|
|
92
|
+
|
|
78
93
|
def build_column_map!(result)
|
|
79
94
|
unless result.result_status == PG::PGRES_TUPLES_OK && result.nfields.positive?
|
|
80
|
-
raise Error,
|
|
95
|
+
raise Error, 'typed mapping requires a TUPLES_OK result with at least one column'
|
|
81
96
|
end
|
|
82
97
|
if @bundle == :failed || @text_map_for_results.nil?
|
|
83
|
-
raise Error,
|
|
98
|
+
raise Error, 'typed result mapping is unavailable (CoderMapsBundle failed)'
|
|
84
99
|
end
|
|
85
100
|
|
|
86
101
|
@text_map_for_results.build_column_map(result)
|
data/lib/pg_pipeline/version.rb
CHANGED