pg-replication-protocol 0.0.6 → 0.0.8
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/Gemfile +2 -0
- data/Gemfile.lock +7 -1
- data/Rakefile +4 -0
- data/lib/pg/replication/buffer.rb +50 -24
- data/lib/pg/replication/version.rb +1 -1
- data/lib/pg/replication.rb +139 -51
- data/sig/pg/replication.rbs +283 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f00c769aee5ae5e1d41063e827f2d5fcaa19991aed6d4676f414ce5f6d6326ef
|
|
4
|
+
data.tar.gz: a99c6f062f9c33109a409b58ef465833fb1d0b3fd8499a91461db9ea3e2586af
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a97e4828c3c0d41607c021fe3b3b87b9c2c2dc01ae70131a984ce4513a46c2386e8d86ce5fc3029f395cc16a9f410c1fbe4c2dff8f77c833bc40f4d75ff8e509
|
|
7
|
+
data.tar.gz: def00e2668b59de09ed0eb8a2fa8efb5974c25c36ea82fcf64b83115afb7519b38010019310267dc4efddeca76df56e6861696abd285d2b2dfab8c00a309e21b
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
pg-replication-protocol (0.0.
|
|
4
|
+
pg-replication-protocol (0.0.7)
|
|
5
5
|
pg (~> 1.0)
|
|
6
6
|
|
|
7
7
|
GEM
|
|
8
8
|
remote: https://rubygems.org/
|
|
9
9
|
specs:
|
|
10
|
+
base64 (0.3.0)
|
|
10
11
|
diff-lcs (1.5.1)
|
|
11
12
|
docker-api (2.4.0)
|
|
12
13
|
excon (>= 0.64.0)
|
|
13
14
|
multi_json
|
|
14
15
|
excon (1.2.1)
|
|
16
|
+
logger (1.7.0)
|
|
15
17
|
multi_json (1.15.0)
|
|
16
18
|
pg (1.5.9)
|
|
17
19
|
rake (13.2.1)
|
|
20
|
+
rbs (3.9.4)
|
|
21
|
+
logger
|
|
18
22
|
rspec (3.13.0)
|
|
19
23
|
rspec-core (~> 3.13.0)
|
|
20
24
|
rspec-expectations (~> 3.13.0)
|
|
@@ -38,8 +42,10 @@ PLATFORMS
|
|
|
38
42
|
x86_64-linux
|
|
39
43
|
|
|
40
44
|
DEPENDENCIES
|
|
45
|
+
base64
|
|
41
46
|
pg-replication-protocol!
|
|
42
47
|
rake (~> 13.0)
|
|
48
|
+
rbs
|
|
43
49
|
rspec (~> 3.0)
|
|
44
50
|
testcontainers-postgres
|
|
45
51
|
|
data/Rakefile
CHANGED
|
@@ -1,21 +1,49 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "delegate"
|
|
4
|
-
require "stringio"
|
|
5
|
-
|
|
6
3
|
module PG
|
|
7
4
|
module Replication
|
|
8
|
-
|
|
5
|
+
POSTGRES_EPOCH = Time.utc(2000, 1, 1).freeze
|
|
6
|
+
POSTGRES_EPOCH_USECS = (POSTGRES_EPOCH.to_r * 1_000_000).to_i
|
|
7
|
+
|
|
8
|
+
class Buffer
|
|
9
|
+
def initialize(data)
|
|
10
|
+
@data = data
|
|
11
|
+
@pos = 0
|
|
12
|
+
end
|
|
13
|
+
|
|
9
14
|
def self.from_string(str)
|
|
10
|
-
new(
|
|
15
|
+
new(str.b)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def eof?
|
|
19
|
+
@pos >= @data.bytesize
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def read(n = nil)
|
|
23
|
+
return nil if @pos >= @data.bytesize
|
|
24
|
+
if n.nil?
|
|
25
|
+
result = @data.byteslice(@pos..-1)
|
|
26
|
+
@pos = @data.bytesize
|
|
27
|
+
else
|
|
28
|
+
result = @data.byteslice(@pos, n)
|
|
29
|
+
@pos += result.bytesize
|
|
30
|
+
end
|
|
31
|
+
result
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def readbyte
|
|
35
|
+
raise EOFError if @pos >= @data.bytesize
|
|
36
|
+
byte = @data.getbyte(@pos)
|
|
37
|
+
@pos += 1
|
|
38
|
+
byte
|
|
11
39
|
end
|
|
12
40
|
|
|
13
41
|
def read_char
|
|
14
|
-
|
|
42
|
+
readbyte.chr
|
|
15
43
|
end
|
|
16
44
|
|
|
17
45
|
def read_bool
|
|
18
|
-
|
|
46
|
+
readbyte == 1
|
|
19
47
|
end
|
|
20
48
|
|
|
21
49
|
def read_int8
|
|
@@ -23,40 +51,38 @@ module PG
|
|
|
23
51
|
end
|
|
24
52
|
|
|
25
53
|
def read_int16
|
|
26
|
-
read_bytes(2).
|
|
54
|
+
read_bytes(2).unpack1("n")
|
|
27
55
|
end
|
|
28
56
|
|
|
29
57
|
def read_int32
|
|
30
|
-
read_bytes(4).
|
|
58
|
+
read_bytes(4).unpack1("N")
|
|
31
59
|
end
|
|
32
60
|
|
|
33
61
|
def read_int64
|
|
34
|
-
read_bytes(8).
|
|
62
|
+
read_bytes(8).unpack1("Q>")
|
|
35
63
|
end
|
|
36
64
|
|
|
37
65
|
def read_timestamp
|
|
38
|
-
usecs =
|
|
39
|
-
Time.at(usecs /
|
|
66
|
+
usecs = POSTGRES_EPOCH_USECS + read_int64
|
|
67
|
+
Time.at(usecs / 1_000_000, usecs % 1_000_000, :microsecond, in: "UTC")
|
|
40
68
|
end
|
|
41
69
|
|
|
42
70
|
def read_cstring
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
str << chr
|
|
50
|
-
end
|
|
51
|
-
end
|
|
71
|
+
null_pos = @data.index("\0", @pos)
|
|
72
|
+
raise EOFError, "Unterminated C-string" if null_pos.nil?
|
|
73
|
+
|
|
74
|
+
str = @data.byteslice(@pos, null_pos - @pos)
|
|
75
|
+
@pos = null_pos + 1 # Skip past null terminator
|
|
76
|
+
str
|
|
52
77
|
end
|
|
53
78
|
|
|
54
79
|
private
|
|
55
80
|
|
|
56
81
|
def read_bytes(n)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
82
|
+
raise EOFError if @pos + n > @data.bytesize
|
|
83
|
+
result = @data.byteslice(@pos, n)
|
|
84
|
+
@pos += n
|
|
85
|
+
result
|
|
60
86
|
end
|
|
61
87
|
end
|
|
62
88
|
end
|
data/lib/pg/replication.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "pg"
|
|
4
|
+
require "thread"
|
|
4
5
|
require_relative "replication/version"
|
|
5
6
|
require_relative "replication/buffer"
|
|
6
7
|
require_relative "replication/pg_output"
|
|
@@ -8,7 +9,12 @@ require_relative "replication/protocol"
|
|
|
8
9
|
|
|
9
10
|
module PG
|
|
10
11
|
module Replication
|
|
11
|
-
|
|
12
|
+
DEFAULT_QUEUE_SIZE = 10_000
|
|
13
|
+
|
|
14
|
+
StreamEnd = Object.new.freeze
|
|
15
|
+
StreamError = Data.define(:exception)
|
|
16
|
+
|
|
17
|
+
def start_replication_slot(slot, logical: true, auto_keep_alive: true, location: "0/0", queue_size: DEFAULT_QUEUE_SIZE, **params)
|
|
12
18
|
keep_alive_secs = wal_receiver_status_interval
|
|
13
19
|
@last_confirmed_lsn = confirmed_slot_lsn(slot) || 0
|
|
14
20
|
|
|
@@ -22,51 +28,11 @@ module PG
|
|
|
22
28
|
end
|
|
23
29
|
query(start_query)
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if auto_keep_alive && Time.now - last_keep_alive > keep_alive_secs
|
|
31
|
-
standby_status_update(write_lsn: @last_confirmed_lsn)
|
|
32
|
-
last_keep_alive = Time.now
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
consume_input
|
|
36
|
-
next if is_busy
|
|
37
|
-
|
|
38
|
-
case get_copy_data(async: true)
|
|
39
|
-
in nil
|
|
40
|
-
get_last_result
|
|
41
|
-
break
|
|
42
|
-
|
|
43
|
-
in false
|
|
44
|
-
IO.select([socket_io], nil, nil, keep_alive_secs)
|
|
45
|
-
next
|
|
46
|
-
|
|
47
|
-
in data
|
|
48
|
-
case (msg = Protocol.read_message(Buffer.new(StringIO.new(data))))
|
|
49
|
-
in Protocol::XLogData(lsn:, data:) if auto_keep_alive
|
|
50
|
-
y << msg
|
|
51
|
-
standby_status_update(write_lsn: lsn) if lsn > 0
|
|
52
|
-
last_keep_alive = Time.now
|
|
53
|
-
|
|
54
|
-
in Protocol::PrimaryKeepalive(current_lsn:, server_time:, asap: true) if auto_keep_alive
|
|
55
|
-
standby_status_update(write_lsn: current_lsn)
|
|
56
|
-
last_keep_alive = Time.now
|
|
57
|
-
y << msg
|
|
58
|
-
|
|
59
|
-
in Protocol::PrimaryKeepalive(current_lsn:)
|
|
60
|
-
y << msg
|
|
61
|
-
@last_confirmed_lsn = [@last_confirmed_lsn, current_lsn].compact.max
|
|
62
|
-
|
|
63
|
-
else
|
|
64
|
-
y << msg
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
.lazy
|
|
31
|
+
if auto_keep_alive
|
|
32
|
+
start_threaded_replication(keep_alive_secs, queue_size)
|
|
33
|
+
else
|
|
34
|
+
start_sync_replication
|
|
35
|
+
end
|
|
70
36
|
end
|
|
71
37
|
|
|
72
38
|
def start_pgoutput_replication_slot(slot, publication_names, **kwargs)
|
|
@@ -96,17 +62,25 @@ module PG
|
|
|
96
62
|
write_lsn,
|
|
97
63
|
flush_lsn,
|
|
98
64
|
apply_lsn,
|
|
99
|
-
(timestamp -
|
|
65
|
+
((timestamp.to_r - POSTGRES_EPOCH.to_r) * 1_000_000).to_i,
|
|
100
66
|
reply ? 1 : 0,
|
|
101
67
|
].pack("CQ>Q>Q>Q>C")
|
|
102
68
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
69
|
+
status_update_mutex.synchronize do
|
|
70
|
+
put_copy_data(msg)
|
|
71
|
+
flush
|
|
72
|
+
@last_confirmed_lsn = [@last_confirmed_lsn, write_lsn].compact.max
|
|
73
|
+
end
|
|
106
74
|
end
|
|
107
75
|
|
|
108
76
|
def last_confirmed_lsn
|
|
109
|
-
@last_confirmed_lsn
|
|
77
|
+
status_update_mutex.synchronize { @last_confirmed_lsn }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def stop_replication
|
|
81
|
+
status_update_mutex.synchronize do
|
|
82
|
+
put_copy_end
|
|
83
|
+
end
|
|
110
84
|
end
|
|
111
85
|
|
|
112
86
|
def wal_receiver_status_interval
|
|
@@ -124,6 +98,120 @@ module PG
|
|
|
124
98
|
rescue StandardError
|
|
125
99
|
nil
|
|
126
100
|
end
|
|
101
|
+
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
def status_update_mutex
|
|
105
|
+
@status_update_mutex ||= Mutex.new
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def start_threaded_replication(keep_alive_secs, queue_size)
|
|
109
|
+
conn = self
|
|
110
|
+
queue = SizedQueue.new(queue_size)
|
|
111
|
+
last_keepalive = Time.now
|
|
112
|
+
|
|
113
|
+
thread = Thread.new do
|
|
114
|
+
loop do
|
|
115
|
+
break if queue.closed?
|
|
116
|
+
|
|
117
|
+
conn.consume_input
|
|
118
|
+
next if conn.is_busy
|
|
119
|
+
|
|
120
|
+
case (data = conn.get_copy_data(async: true))
|
|
121
|
+
when nil
|
|
122
|
+
queue.push(StreamEnd, true) rescue nil
|
|
123
|
+
conn.get_last_result
|
|
124
|
+
break
|
|
125
|
+
|
|
126
|
+
when false
|
|
127
|
+
timeout = [keep_alive_secs - (Time.now - last_keepalive), 0.1].max
|
|
128
|
+
IO.select([conn.socket_io], nil, nil, timeout)
|
|
129
|
+
|
|
130
|
+
if Time.now - last_keepalive >= keep_alive_secs
|
|
131
|
+
conn.standby_status_update(write_lsn: conn.last_confirmed_lsn)
|
|
132
|
+
last_keepalive = Time.now
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
else
|
|
136
|
+
msg = Protocol.read_message(Buffer.from_string(data))
|
|
137
|
+
|
|
138
|
+
if msg.is_a?(Protocol::PrimaryKeepalive) && msg.asap
|
|
139
|
+
conn.standby_status_update(write_lsn: msg.current_lsn)
|
|
140
|
+
last_keepalive = Time.now
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Non-blocking push with keepalive retry loop
|
|
144
|
+
loop do
|
|
145
|
+
break if queue.closed?
|
|
146
|
+
begin
|
|
147
|
+
queue.push(msg, true)
|
|
148
|
+
break
|
|
149
|
+
rescue ThreadError
|
|
150
|
+
if Time.now - last_keepalive >= keep_alive_secs
|
|
151
|
+
conn.standby_status_update(write_lsn: conn.last_confirmed_lsn)
|
|
152
|
+
last_keepalive = Time.now
|
|
153
|
+
end
|
|
154
|
+
sleep(0.05)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
rescue ClosedQueueError
|
|
160
|
+
# Clean exit
|
|
161
|
+
rescue => e
|
|
162
|
+
queue.push(StreamError.new(e), true) rescue nil
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
Enumerator.new do |y|
|
|
166
|
+
loop do
|
|
167
|
+
msg = queue.pop
|
|
168
|
+
|
|
169
|
+
case msg
|
|
170
|
+
when StreamEnd
|
|
171
|
+
break
|
|
172
|
+
when StreamError
|
|
173
|
+
raise msg.exception
|
|
174
|
+
else
|
|
175
|
+
y << msg
|
|
176
|
+
|
|
177
|
+
lsn = case msg
|
|
178
|
+
when Protocol::XLogData
|
|
179
|
+
msg.lsn
|
|
180
|
+
when Protocol::PrimaryKeepalive
|
|
181
|
+
msg.current_lsn
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
if lsn && lsn > 0
|
|
185
|
+
status_update_mutex.synchronize { @last_confirmed_lsn = lsn }
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
ensure
|
|
190
|
+
queue.close
|
|
191
|
+
thread.join(5)
|
|
192
|
+
thread.kill if thread.alive?
|
|
193
|
+
end.lazy
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def start_sync_replication
|
|
197
|
+
Enumerator.new do |y|
|
|
198
|
+
loop do
|
|
199
|
+
consume_input
|
|
200
|
+
next if is_busy
|
|
201
|
+
|
|
202
|
+
case get_copy_data(async: true)
|
|
203
|
+
in nil
|
|
204
|
+
get_last_result
|
|
205
|
+
break
|
|
206
|
+
in false
|
|
207
|
+
IO.select([socket_io], nil, nil, 10)
|
|
208
|
+
next
|
|
209
|
+
in data
|
|
210
|
+
y << Protocol.read_message(Buffer.new(data))
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end.lazy
|
|
214
|
+
end
|
|
127
215
|
end
|
|
128
216
|
|
|
129
217
|
Connection.send(:include, Replication)
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
module PG
|
|
2
|
+
module Replication
|
|
3
|
+
module Protocol
|
|
4
|
+
class PrimaryKeepalive < ::Data
|
|
5
|
+
def self.new: (Integer current_lsn, Time server_time, Boolean asap) -> instance
|
|
6
|
+
| (current_lsn: Integer, server_time: Time, asap: Boolean) -> instance
|
|
7
|
+
|
|
8
|
+
def self.[]: (Integer current_lsn, Time server_time, Boolean asap) -> instance
|
|
9
|
+
| (current_lsn: Integer, server_time: Time, asap: Boolean) -> instance
|
|
10
|
+
|
|
11
|
+
def self.members: () -> [ :current_lsn, :server_time, :asap ]
|
|
12
|
+
|
|
13
|
+
def members: () -> [ :current_lsn, :server_time, :asap ]
|
|
14
|
+
|
|
15
|
+
attr_reader current_lsn: Integer
|
|
16
|
+
|
|
17
|
+
attr_reader server_time: Time
|
|
18
|
+
|
|
19
|
+
attr_reader asap: Boolean
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class XLogData[T] < ::Data
|
|
23
|
+
def self.new: (Integer lsn, Integer current_lsn, Time server_time, T data) -> instance
|
|
24
|
+
| (lsn: Integer, current_lsn: Integer, server_time: Time, data: T) -> instance
|
|
25
|
+
|
|
26
|
+
def self.[]: (Integer lsn, Integer current_lsn, Time server_time, T data) -> instance
|
|
27
|
+
| (lsn: Integer, current_lsn: Integer, server_time: Time, data: T) -> instance
|
|
28
|
+
|
|
29
|
+
def self.members: () -> [ :lsn, :current_lsn, :server_time, :data ]
|
|
30
|
+
|
|
31
|
+
def members: () -> [ :lsn, :current_lsn, :server_time, :data ]
|
|
32
|
+
|
|
33
|
+
attr_reader lsn: Integer
|
|
34
|
+
|
|
35
|
+
attr_reader current_lsn: Integer
|
|
36
|
+
|
|
37
|
+
attr_reader server_time: Time
|
|
38
|
+
|
|
39
|
+
attr_reader data: T
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
module PGOutput
|
|
44
|
+
class Begin < ::Data
|
|
45
|
+
def self.new: (Integer final_lsn, Time timestamp, Integer xid) -> instance
|
|
46
|
+
| (final_lsn: Integer, timestamp: Time, xid: Integer) -> instance
|
|
47
|
+
|
|
48
|
+
def self.[]: (Integer final_lsn, Time timestamp, Integer xid) -> instance
|
|
49
|
+
| (final_lsn: Integer, timestamp: Time, xid: Integer) -> instance
|
|
50
|
+
|
|
51
|
+
def self.members: () -> [ :final_lsn, :timestamp, :xid ]
|
|
52
|
+
|
|
53
|
+
def members: () -> [ :final_lsn, :timestamp, :xid ]
|
|
54
|
+
|
|
55
|
+
attr_reader final_lsn: Integer
|
|
56
|
+
|
|
57
|
+
attr_reader timestamp: Time
|
|
58
|
+
|
|
59
|
+
attr_reader xid: Integer
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class Column < ::Data
|
|
63
|
+
def self.new: (Integer flags, String name, Integer oid, Integer modifier) -> instance
|
|
64
|
+
| (flags: Integer, name: String, oid: Integer, modifier: Integer) -> instance
|
|
65
|
+
|
|
66
|
+
def self.[]: (Integer flags, String name, Integer oid, Integer modifier) -> instance
|
|
67
|
+
| (flags: Integer, name: String, oid: Integer, modifier: Integer) -> instance
|
|
68
|
+
|
|
69
|
+
def self.members: () -> [ :flags, :name, :oid, :modifier ]
|
|
70
|
+
|
|
71
|
+
def members: () -> [ :flags, :name, :oid, :modifier ]
|
|
72
|
+
|
|
73
|
+
attr_reader flags: Integer
|
|
74
|
+
|
|
75
|
+
attr_reader name: String
|
|
76
|
+
|
|
77
|
+
attr_reader oid: Integer
|
|
78
|
+
|
|
79
|
+
attr_reader modifier: Integer
|
|
80
|
+
|
|
81
|
+
def key?: () -> Boolean
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
class Commit < ::Data
|
|
85
|
+
def self.new: (Integer lsn, Integer end_lsn, Time timestamp) -> instance
|
|
86
|
+
| (lsn: Integer, end_lsn: Integer, timestamp: Time) -> instance
|
|
87
|
+
|
|
88
|
+
def self.[]: (Integer lsn, Integer end_lsn, Time timestamp) -> instance
|
|
89
|
+
| (lsn: Integer, end_lsn: Integer, timestamp: Time) -> instance
|
|
90
|
+
|
|
91
|
+
def self.members: () -> [ :lsn, :end_lsn, :timestamp ]
|
|
92
|
+
|
|
93
|
+
def members: () -> [ :lsn, :end_lsn, :timestamp ]
|
|
94
|
+
|
|
95
|
+
attr_reader lsn: Integer
|
|
96
|
+
|
|
97
|
+
attr_reader end_lsn: Integer
|
|
98
|
+
|
|
99
|
+
attr_reader timestamp: Time
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
class Delete < ::Data
|
|
103
|
+
def self.new: (Integer oid, Array[String] key, Array[String] old) -> instance
|
|
104
|
+
| (oid: Integer, key: Array[String], old: Array[String]) -> instance
|
|
105
|
+
|
|
106
|
+
def self.[]: (Integer oid, Array[String] key, Array[String] old) -> instance
|
|
107
|
+
| (oid: Integer, key: Array[String], old: Array[String]) -> instance
|
|
108
|
+
|
|
109
|
+
def self.members: () -> [ :oid, :key, :old ]
|
|
110
|
+
|
|
111
|
+
def members: () -> [ :oid, :key, :old ]
|
|
112
|
+
|
|
113
|
+
attr_reader oid: Integer
|
|
114
|
+
|
|
115
|
+
attr_reader key: Array[String]
|
|
116
|
+
|
|
117
|
+
attr_reader old: Array[String]
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
class Insert < ::Data
|
|
121
|
+
def self.new: (Integer oid, Array[String] new) -> instance
|
|
122
|
+
| (oid: Integer, new: Array[String]) -> instance
|
|
123
|
+
|
|
124
|
+
def self.[]: (Integer oid, Array[String] new) -> instance
|
|
125
|
+
| (oid: Integer, new: Array[String]) -> instance
|
|
126
|
+
|
|
127
|
+
def self.members: () -> [ :oid, :new ]
|
|
128
|
+
|
|
129
|
+
def members: () -> [ :oid, :new ]
|
|
130
|
+
|
|
131
|
+
attr_reader oid: Integer
|
|
132
|
+
|
|
133
|
+
attr_reader new: Array[String]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
class Message < ::Data
|
|
137
|
+
def self.new: (Boolean transactional, Integer lsn, String? prefix, String? content) -> instance
|
|
138
|
+
| (transactional: Boolean, lsn: Integer, prefix: String?, content: String?) -> instance
|
|
139
|
+
|
|
140
|
+
def self.[]: (Boolean transactional, Integer lsn, String? prefix, String? content) -> instance
|
|
141
|
+
| (transactional: Boolean, lsn: Integer, prefix: String?, content: String?) -> instance
|
|
142
|
+
|
|
143
|
+
def self.members: () -> [ :transactional, :lsn, :prefix, :content ]
|
|
144
|
+
|
|
145
|
+
def members: () -> [ :transactional, :lsn, :prefix, :content ]
|
|
146
|
+
|
|
147
|
+
attr_reader transactional: Boolean
|
|
148
|
+
|
|
149
|
+
attr_reader lsn: Integer
|
|
150
|
+
|
|
151
|
+
attr_reader prefix: String?
|
|
152
|
+
|
|
153
|
+
attr_reader content: String?
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
class Origin < ::Data
|
|
157
|
+
def self.new: (Integer commit_lsn, String name) -> instance
|
|
158
|
+
| (commit_lsn: Integer, name: String) -> instance
|
|
159
|
+
|
|
160
|
+
def self.[]: (Integer commit_lsn, String name) -> instance
|
|
161
|
+
| (commit_lsn: Integer, name: String) -> instance
|
|
162
|
+
|
|
163
|
+
def self.members: () -> [ :commit_lsn, :name ]
|
|
164
|
+
|
|
165
|
+
def members: () -> [ :commit_lsn, :name ]
|
|
166
|
+
|
|
167
|
+
attr_reader commit_lsn: Integer
|
|
168
|
+
|
|
169
|
+
attr_reader name: String
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
class Relation < ::Data
|
|
173
|
+
def self.new: (Integer oid, String namespace, String name, String replica_identity, Array[PG::Replication::PGOutput::Column] columns) -> instance
|
|
174
|
+
| (oid: Integer, namespace: String, name: String, replica_identity: String, columns: Array[PG::Replication::PGOutput::Column]) -> instance
|
|
175
|
+
|
|
176
|
+
def self.[]: (Integer oid, String namespace, String name, String replica_identity, Array[PG::Replication::PGOutput::Column] columns) -> instance
|
|
177
|
+
| (oid: Integer, namespace: String, name: String, replica_identity: String, columns: Array[PG::Replication::PGOutput::Column]) -> instance
|
|
178
|
+
|
|
179
|
+
def self.members: () -> [ :oid, :namespace, :name, :replica_identity, :columns ]
|
|
180
|
+
|
|
181
|
+
def members: () -> [ :oid, :namespace, :name, :replica_identity, :columns ]
|
|
182
|
+
|
|
183
|
+
attr_reader oid: Integer
|
|
184
|
+
|
|
185
|
+
attr_reader namespace: String
|
|
186
|
+
|
|
187
|
+
attr_reader name: String
|
|
188
|
+
|
|
189
|
+
attr_reader replica_identity: String
|
|
190
|
+
|
|
191
|
+
attr_reader columns: Array[PG::Replication::PGOutput::Column]
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
class Truncate < ::Data
|
|
195
|
+
def self.new: (Integer oid) -> instance
|
|
196
|
+
| (oid: Integer) -> instance
|
|
197
|
+
|
|
198
|
+
def self.[]: (Integer oid) -> instance
|
|
199
|
+
| (oid: Integer) -> instance
|
|
200
|
+
|
|
201
|
+
def self.members: () -> [ :oid ]
|
|
202
|
+
|
|
203
|
+
def members: () -> [ :oid ]
|
|
204
|
+
|
|
205
|
+
attr_reader oid: Integer
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
class Tuple < ::Data
|
|
209
|
+
def self.new: (String type, String? data) -> instance
|
|
210
|
+
| (type: String, data: String?) -> instance
|
|
211
|
+
|
|
212
|
+
def self.[]: (String type, String? data) -> instance
|
|
213
|
+
| (type: String, data: String?) -> instance
|
|
214
|
+
|
|
215
|
+
def self.members: () -> [ :type, :data ]
|
|
216
|
+
|
|
217
|
+
def members: () -> [ :type, :data ]
|
|
218
|
+
|
|
219
|
+
attr_reader type: String
|
|
220
|
+
|
|
221
|
+
attr_reader data: String?
|
|
222
|
+
|
|
223
|
+
def text?: () -> Boolean
|
|
224
|
+
|
|
225
|
+
def binary?: () -> Boolean
|
|
226
|
+
|
|
227
|
+
def toast?: () -> Boolean
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
class Type < ::Data
|
|
231
|
+
def self.new: (Integer oid, String namespace, String name) -> instance
|
|
232
|
+
| (oid: Integer, namespace: String, name: String) -> instance
|
|
233
|
+
|
|
234
|
+
def self.[]: (Integer oid, String namespace, String name) -> instance
|
|
235
|
+
| (oid: Integer, namespace: String, name: String) -> instance
|
|
236
|
+
|
|
237
|
+
def self.members: () -> [ :oid, :namespace, :name ]
|
|
238
|
+
|
|
239
|
+
def members: () -> [ :oid, :namespace, :name ]
|
|
240
|
+
|
|
241
|
+
attr_reader oid: Integer
|
|
242
|
+
|
|
243
|
+
attr_reader namespace: String
|
|
244
|
+
|
|
245
|
+
attr_reader name: String
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
class Update < ::Data
|
|
249
|
+
def self.new: (Integer oid, Array[String] key, Array[String] old, Array[String] new) -> instance
|
|
250
|
+
| (oid: Integer, key: Array[String], old: Array[String], new: Array[String]) -> instance
|
|
251
|
+
|
|
252
|
+
def self.[]: (Integer oid, Array[String] key, Array[String] old, Array[String] new) -> instance
|
|
253
|
+
| (oid: Integer, key: Array[String], old: Array[String], new: Array[String]) -> instance
|
|
254
|
+
|
|
255
|
+
def self.members: () -> [ :oid, :key, :old, :new ]
|
|
256
|
+
|
|
257
|
+
def members: () -> [ :oid, :key, :old, :new ]
|
|
258
|
+
|
|
259
|
+
attr_reader oid: Integer
|
|
260
|
+
|
|
261
|
+
attr_reader key: Array[String]
|
|
262
|
+
|
|
263
|
+
attr_reader old: Array[String]
|
|
264
|
+
|
|
265
|
+
attr_reader new: Array[String]
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
@last_confirmed_lsn: Integer?
|
|
270
|
+
|
|
271
|
+
def start_replication_slot: (String slot, ?logical: bool, ?auto_keep_alive: bool, ?location: ::String, **untyped params) -> Enumerator::Lazy[PG::Replication::Protocol::PrimaryKeepalive | PG::Replication::Protocol::XLogData[String]]
|
|
272
|
+
|
|
273
|
+
def start_pgoutput_replication_slot: (String slot, Array[String] publication_names, **untyped kwargs) -> Enumerator::Lazy[PG::Replication::Protocol::PrimaryKeepalive | PG::Replication::Protocol::XLogData[PG::Replication::PGOutput]]
|
|
274
|
+
|
|
275
|
+
def standby_status_update: (write_lsn: Integer, ?flush_lsn: Integer, ?apply_lsn: Integer, ?timestamp: Time, ?reply: bool) -> void
|
|
276
|
+
|
|
277
|
+
def last_confirmed_lsn: () -> Integer?
|
|
278
|
+
|
|
279
|
+
def wal_receiver_status_interval: () -> Integer
|
|
280
|
+
|
|
281
|
+
def confirmed_slot_lsn: (String slot) -> Integer?
|
|
282
|
+
end
|
|
283
|
+
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pg-replication-protocol
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rodrigo Navarro
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 2026-01-14 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: pg
|
|
@@ -41,6 +41,7 @@ files:
|
|
|
41
41
|
- lib/pg/replication/protocol.rb
|
|
42
42
|
- lib/pg/replication/version.rb
|
|
43
43
|
- pg-replication-protocol.gemspec
|
|
44
|
+
- sig/pg/replication.rbs
|
|
44
45
|
licenses:
|
|
45
46
|
- MIT
|
|
46
47
|
metadata:
|