Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit b4051cf

Browse files
authored
Merge pull request #41 from zilder/repslot
Replication slots
2 parents 7251c95 + 0b4ac3a commit b4051cf

File tree

4 files changed

+57
-6
lines changed

4 files changed

+57
-6
lines changed

testgres/backup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ def spawn_primary(self, name=None, destroy=True):
154154

155155
return node
156156

157-
def spawn_replica(self, name=None, destroy=True):
157+
def spawn_replica(self, name=None, destroy=True, slot_name=None):
158158
"""
159159
Create a replica of the original node from a backup.
160160
@@ -171,7 +171,7 @@ def spawn_replica(self, name=None, destroy=True):
171171

172172
# Assign it a master and a recovery file (private magic)
173173
node._assign_master(self.original_node)
174-
node._create_recovery_conf(username=self.username)
174+
node._create_recovery_conf(username=self.username, slot_name=slot_name)
175175

176176
return node
177177

testgres/consts.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,6 @@
2424
PG_LOG_FILE = "postgresql.log"
2525
UTILS_LOG_FILE = "utils.log"
2626
BACKUP_LOG_FILE = "backup.log"
27+
28+
# default replication slots number
29+
REPLICATION_SLOTS = 10

testgres/node.py

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
RECOVERY_CONF_FILE, \
3333
PG_LOG_FILE, \
3434
UTILS_LOG_FILE, \
35-
PG_PID_FILE
35+
PG_PID_FILE, \
36+
REPLICATION_SLOTS
3637

3738
from .decorators import \
3839
method_decorator, \
@@ -277,7 +278,7 @@ def _assign_master(self, master):
277278
# now this node has a master
278279
self._master = master
279280

280-
def _create_recovery_conf(self, username):
281+
def _create_recovery_conf(self, username, slot_name=None):
281282
"""NOTE: this is a private method!"""
282283

283284
# fetch master of this node
@@ -305,6 +306,9 @@ def _create_recovery_conf(self, username):
305306
"standby_mode=on\n"
306307
).format(conninfo)
307308

309+
if slot_name:
310+
line += "primary_slot_name={}\n".format(slot_name)
311+
308312
self.append_conf(RECOVERY_CONF_FILE, line)
309313

310314
def _maybe_start_logger(self):
@@ -348,6 +352,28 @@ def _collect_special_files(self):
348352

349353
return result
350354

355+
def _create_replication_slot(self, slot_name, dbname=None, username=None):
356+
"""
357+
Create a physical replication slot.
358+
359+
Args:
360+
slot_name: slot name
361+
dbname: database name
362+
username: database user name
363+
"""
364+
rs = self.execute("select exists (select * from pg_replication_slots "
365+
"where slot_name = '{}')".format(slot_name),
366+
dbname=dbname, username=username)
367+
368+
if rs[0][0]:
369+
raise TestgresException("Slot '{}' already exists".format(slot_name))
370+
371+
query = (
372+
"select pg_create_physical_replication_slot('{}')"
373+
).format(slot_name)
374+
375+
self.execute(query=query, dbname=dbname, username=username)
376+
351377
def init(self, initdb_params=None, **kwargs):
352378
"""
353379
Perform initdb for this node.
@@ -458,8 +484,10 @@ def get_auth_method(t):
458484
wal_keep_segments = 20 # for convenience
459485
conf.write(u"hot_standby = on\n"
460486
u"max_wal_senders = {}\n"
487+
u"max_replication_slots = {}\n"
461488
u"wal_keep_segments = {}\n"
462489
u"wal_level = {}\n".format(max_wal_senders,
490+
REPLICATION_SLOTS,
463491
wal_keep_segments,
464492
wal_level))
465493

@@ -941,7 +969,7 @@ def backup(self, **kwargs):
941969

942970
return NodeBackup(node=self, **kwargs)
943971

944-
def replicate(self, name=None, **kwargs):
972+
def replicate(self, name=None, slot_name=None, **kwargs):
945973
"""
946974
Create a binary replica of this node.
947975
@@ -952,10 +980,15 @@ def replicate(self, name=None, **kwargs):
952980
base_dir: the base directory for data files and logs
953981
"""
954982

983+
if slot_name:
984+
self._create_replication_slot(slot_name, **kwargs)
985+
955986
backup = self.backup(**kwargs)
956987

957988
# transform backup into a replica
958-
return backup.spawn_replica(name=name, destroy=True)
989+
return backup.spawn_replica(name=name,
990+
destroy=True,
991+
slot_name=slot_name)
959992

960993
def catchup(self, dbname=None, username=None):
961994
"""

tests/test_simple.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,21 @@ def test_replicate(self):
383383
res = node.execute('select * from test')
384384
self.assertListEqual(res, [])
385385

386+
def test_replication_slots(self):
387+
query_create = 'create table test as select generate_series(1, 2) as val'
388+
389+
with get_new_node() as node:
390+
node.init(allow_streaming=True).start()
391+
node.execute(query_create)
392+
393+
with node.replicate(slot_name='slot1').start() as replica:
394+
res = replica.execute('select * from test')
395+
self.assertListEqual(res, [(1, ), (2, )])
396+
397+
# cannot create new slot with the same name
398+
with self.assertRaises(TestgresException):
399+
node._create_replication_slot('slot1')
400+
386401
def test_incorrect_catchup(self):
387402
with get_new_node() as node:
388403
node.init(allow_streaming=True).start()

0 commit comments

Comments
 (0)