Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit de38db4

Browse files
committed
Merge branch 'master' of git.postgrespro.ru:pgpro-dev/pg_probackup
2 parents 3873318 + 0e99b6f commit de38db4

File tree

6 files changed

+184
-24
lines changed

6 files changed

+184
-24
lines changed

Documentation.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ Current version - 2.1.3
107107

108108
As compared to other backup solutions, pg_probackup offers the following benefits that can help you implement different backup strategies and deal with large amounts of data:
109109

110-
- Incremental backup: page-level incremental backup allows you save to disk space, speed up backup and restore. With three different incremental modes you can plan the backup strategy in accordance with your data flow
110+
- Incremental backup: page-level incremental backup allows you to save disk space, speed up backup and restore. With three different incremental modes you can plan the backup strategy in accordance with your data flow
111111
- Validation: Automatic data consistency checks and on-demand backup validation without actual data recovery
112112
- Verification: On-demand verification of PostgreSQL instance via dedicated command `checkdb`
113113
- Retention: Managing backups in accordance with retention policies - Time and/or Redundancy based, with two retention methods: `delete expired` and `merge expired`
@@ -778,7 +778,7 @@ Specifies remote host user for SSH connection. If you omit this option, the curr
778778
Specifies pg_probackup installation directory on the remote system.
779779

780780
--ssh-options
781-
Specifies a string of SSH command-line options.
781+
Specifies a string of SSH command-line options. For example, the following options can used to set keep-alive for ssh connections opened by pg_probackup: `--ssh-options='-o ServerAliveCountMax=5 -o ServerAliveInterval=60'`. Full list of possible options can be found here: (https://linux.die.net/man/5/ssh_config)[https://linux.die.net/man/5/ssh_config]
782782

783783
#### Replica Options
784784

src/backup.c

+16-4
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,9 @@ do_backup_instance(PGconn *backup_conn)
344344
dir_list_file(backup_files_list, parray_get(external_dirs, i),
345345
false, true, false, i+1, FIO_DB_HOST);
346346

347+
/* close ssh session in main thread */
348+
fio_disconnect();
349+
347350
/* Sanity check for backup_files_list, thank you, Windows:
348351
* https://github.com/postgrespro/pg_probackup/issues/48
349352
*/
@@ -512,6 +515,9 @@ do_backup_instance(PGconn *backup_conn)
512515
parray_free(prev_backup_filelist);
513516
}
514517

518+
/* Notify end of backup */
519+
pg_stop_backup(&current, pg_startbackup_conn);
520+
515521
/* In case of backup from replica >= 9.6 we must fix minRecPoint,
516522
* First we must find pg_control in backup_files_list.
517523
*/
@@ -532,13 +538,16 @@ do_backup_instance(PGconn *backup_conn)
532538
break;
533539
}
534540
}
535-
}
536541

537-
/* Notify end of backup */
538-
pg_stop_backup(&current, pg_startbackup_conn);
542+
if (!pg_control)
543+
elog(ERROR, "Failed to find file \"%s\" in backup filelist.",
544+
pg_control_path);
539545

540-
if (current.from_replica && !exclusive_backup)
541546
set_min_recovery_point(pg_control, database_path, current.stop_lsn);
547+
}
548+
549+
/* close ssh session in main thread */
550+
fio_disconnect();
542551

543552
/* Add archived xlog files into the list of files of this backup */
544553
if (stream_wal)
@@ -2143,6 +2152,9 @@ backup_files(void *arg)
21432152
elog(WARNING, "unexpected file type %d", buf.st_mode);
21442153
}
21452154

2155+
/* ssh connection to longer needed */
2156+
fio_disconnect();
2157+
21462158
/* Close connection */
21472159
if (arguments->conn_arg.conn)
21482160
pgut_disconnect(arguments->conn_arg.conn);

tests/__init__.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
def load_tests(loader, tests, pattern):
1313
suite = unittest.TestSuite()
1414

15-
if os.environ['PG_PROBACKUP_TEST_BASIC'] == 'ON':
16-
loader.testMethodPrefix = 'test_basic'
15+
if 'PG_PROBACKUP_TEST_BASIC' in os.environ:
16+
if os.environ['PG_PROBACKUP_TEST_BASIC'] == 'ON':
17+
loader.testMethodPrefix = 'test_basic'
1718

1819
# suite.addTests(loader.loadTestsFromModule(auth_test))
1920
suite.addTests(loader.loadTestsFromModule(archive))

tests/archive.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -452,22 +452,23 @@ def test_archive_push_partial_file_exists(self):
452452
filename = filename_orig + '.partial'
453453
file = os.path.join(wals_dir, filename)
454454

455+
# emulate stale .partial file
455456
with open(file, 'a') as f:
456457
f.write(b"blahblah")
457458
f.flush()
458459
f.close()
459460

460461
self.switch_wal_segment(node)
461-
sleep(15)
462+
sleep(20)
462463

463464
# check that segment is archived
464465
if self.archive_compress:
465466
filename_orig = filename_orig + '.gz'
466467

467468
file = os.path.join(wals_dir, filename_orig)
468-
469469
self.assertTrue(os.path.isfile(file))
470470

471+
# successful validate means that archive-push reused stale wal segment
471472
self.validate_pb(
472473
backup_dir, 'node',
473474
options=['--recovery-target-xid={0}'.format(xid)])

tests/backup.py

+72-14
Original file line numberDiff line numberDiff line change
@@ -468,16 +468,74 @@ def test_backup_detect_corruption(self):
468468
"\n Output: {0} \n CMD: {1}".format(
469469
repr(self.output), self.cmd))
470470
except ProbackupException as e:
471-
self.assertIn(
472-
'WARNING: Corruption detected in file',
473-
e.message,
474-
'\n Unexpected Error Message: {0}\n CMD: {1}'.format(
475-
repr(e.message), self.cmd))
476-
self.assertIn(
477-
'ERROR: Data file corruption',
478-
e.message,
479-
'\n Unexpected Error Message: {0}\n CMD: {1}'.format(
480-
repr(e.message), self.cmd))
471+
if self.remote:
472+
self.assertTrue(
473+
"ERROR: Failed to read file" in e.message and
474+
"data file checksum mismatch" in e.message,
475+
'\n Unexpected Error Message: {0}\n CMD: {1}'.format(
476+
repr(e.message), self.cmd))
477+
else:
478+
self.assertIn(
479+
'WARNING: Corruption detected in file',
480+
e.message,
481+
'\n Unexpected Error Message: {0}\n CMD: {1}'.format(
482+
repr(e.message), self.cmd))
483+
self.assertIn(
484+
'ERROR: Data file corruption',
485+
e.message,
486+
'\n Unexpected Error Message: {0}\n CMD: {1}'.format(
487+
repr(e.message), self.cmd))
488+
489+
# Clean after yourself
490+
self.del_test_dir(module_name, fname)
491+
492+
# @unittest.skip("skip")
493+
def test_backup_truncate_misaligned(self):
494+
"""
495+
make node, truncate file to size not even to BLCKSIZE,
496+
take backup
497+
"""
498+
fname = self.id().split('.')[3]
499+
node = self.make_simple_node(
500+
base_dir=os.path.join(module_name, fname, 'node'),
501+
set_replication=True,
502+
initdb_params=['--data-checksums'])
503+
504+
backup_dir = os.path.join(self.tmp_path, module_name, fname, 'backup')
505+
506+
self.init_pb(backup_dir)
507+
self.add_instance(backup_dir, 'node', node)
508+
node.slow_start()
509+
510+
node.safe_psql(
511+
"postgres",
512+
"create table t_heap as select 1 as id, md5(i::text) as text, "
513+
"md5(repeat(i::text,10))::tsvector as tsvector "
514+
"from generate_series(0,100000) i")
515+
516+
node.safe_psql(
517+
"postgres",
518+
"CHECKPOINT;")
519+
520+
heap_path = node.safe_psql(
521+
"postgres",
522+
"select pg_relation_filepath('t_heap')").rstrip()
523+
524+
heap_size = node.safe_psql(
525+
"postgres",
526+
"select pg_relation_size('t_heap')")
527+
528+
with open(os.path.join(node.data_dir, heap_path), "rb+", 0) as f:
529+
f.truncate(int(heap_size) - 4096)
530+
f.flush()
531+
f.close
532+
533+
output = self.backup_node(
534+
backup_dir, 'node', node, backup_type="full",
535+
options=["-j", "4", "--stream"], return_id=False)
536+
537+
self.assertIn("WARNING: File", output)
538+
self.assertIn("invalid file size", output)
481539

482540
# Clean after yourself
483541
self.del_test_dir(module_name, fname)
@@ -1449,16 +1507,16 @@ def test_backup_with_least_privileges_role(self):
14491507

14501508
node.safe_psql(
14511509
'backupdb',
1452-
"REVOKE TEMPORARY ON DATABASE backupdb FROM PUBLIC;"
1453-
"REVOKE ALL on SCHEMA public from PUBLIC; "
1510+
"REVOKE ALL ON DATABASE backupdb from PUBLIC; "
1511+
"REVOKE ALL ON SCHEMA public from PUBLIC; "
14541512
"REVOKE ALL ON ALL TABLES IN SCHEMA public FROM PUBLIC; "
14551513
"REVOKE ALL ON ALL FUNCTIONS IN SCHEMA public FROM PUBLIC; "
14561514
"REVOKE ALL ON ALL SEQUENCES IN SCHEMA public FROM PUBLIC; "
1457-
"REVOKE ALL on SCHEMA pg_catalog from PUBLIC; "
1515+
"REVOKE ALL ON SCHEMA pg_catalog from PUBLIC; "
14581516
"REVOKE ALL ON ALL TABLES IN SCHEMA pg_catalog FROM PUBLIC; "
14591517
"REVOKE ALL ON ALL FUNCTIONS IN SCHEMA pg_catalog FROM PUBLIC; "
14601518
"REVOKE ALL ON ALL SEQUENCES IN SCHEMA pg_catalog FROM PUBLIC; "
1461-
"REVOKE ALL on SCHEMA information_schema from PUBLIC; "
1519+
"REVOKE ALL ON SCHEMA information_schema from PUBLIC; "
14621520
"REVOKE ALL ON ALL TABLES IN SCHEMA information_schema FROM PUBLIC; "
14631521
"REVOKE ALL ON ALL FUNCTIONS IN SCHEMA information_schema FROM PUBLIC; "
14641522
"REVOKE ALL ON ALL SEQUENCES IN SCHEMA information_schema FROM PUBLIC; "

tests/replica.py

+88
Original file line numberDiff line numberDiff line change
@@ -437,3 +437,91 @@ def test_take_backup_from_delayed_replica(self):
437437

438438
# Clean after yourself
439439
self.del_test_dir(module_name, fname)
440+
441+
# @unittest.skip("skip")
442+
def test_replica_promote(self):
443+
"""
444+
start backup from replica, during backup promote replica
445+
check that backup is failed
446+
"""
447+
fname = self.id().split('.')[3]
448+
backup_dir = os.path.join(self.tmp_path, module_name, fname, 'backup')
449+
master = self.make_simple_node(
450+
base_dir=os.path.join(module_name, fname, 'master'),
451+
set_replication=True,
452+
initdb_params=['--data-checksums'],
453+
pg_options={
454+
'archive_timeout': '10s',
455+
'checkpoint_timeout': '30s',
456+
'max_wal_size': '32MB'})
457+
458+
self.init_pb(backup_dir)
459+
self.add_instance(backup_dir, 'master', master)
460+
self.set_archiving(backup_dir, 'master', master)
461+
master.slow_start()
462+
463+
replica = self.make_simple_node(
464+
base_dir=os.path.join(module_name, fname, 'replica'))
465+
replica.cleanup()
466+
467+
self.backup_node(backup_dir, 'master', master)
468+
469+
master.psql(
470+
"postgres",
471+
"create table t_heap as select i as id, md5(i::text) as text, "
472+
"md5(repeat(i::text,10))::tsvector as tsvector "
473+
"from generate_series(0,165000) i")
474+
475+
self.restore_node(
476+
backup_dir, 'master', replica, options=['-R'])
477+
478+
# Settings for Replica
479+
self.add_instance(backup_dir, 'replica', replica)
480+
self.set_archiving(backup_dir, 'replica', replica, replica=True)
481+
self.set_replica(
482+
master, replica,
483+
replica_name='replica', synchronous=True)
484+
485+
replica.slow_start(replica=True)
486+
487+
master.psql(
488+
"postgres",
489+
"create table t_heap_1 as select i as id, md5(i::text) as text, "
490+
"md5(repeat(i::text,10))::tsvector as tsvector "
491+
"from generate_series(0,165000) i")
492+
493+
self.wait_until_replica_catch_with_master(master, replica)
494+
495+
# start backup from replica
496+
gdb = self.backup_node(
497+
backup_dir, 'replica', replica, gdb=True,
498+
options=['--log-level-file=verbose'])
499+
500+
gdb.set_breakpoint('backup_data_file')
501+
gdb.run_until_break()
502+
gdb.continue_execution_until_break(20)
503+
504+
replica.promote()
505+
506+
gdb.remove_all_breakpoints()
507+
gdb.continue_execution_until_exit()
508+
509+
backup_id = self.show_pb(
510+
backup_dir, 'replica')[0]["id"]
511+
512+
# read log file content
513+
with open(os.path.join(backup_dir, 'log', 'pg_probackup.log')) as f:
514+
log_content = f.read()
515+
f.close
516+
517+
self.assertIn(
518+
'ERROR: the standby was promoted during online backup',
519+
log_content)
520+
521+
self.assertIn(
522+
'WARNING: Backup {0} is running, '
523+
'setting its status to ERROR'.format(backup_id),
524+
log_content)
525+
526+
# Clean after yourself
527+
self.del_test_dir(module_name, fname)

0 commit comments

Comments
 (0)