Skip to content

Commit a7329d9

Browse files
committed
bugfix: nullified page shouldn`t be skipped by DELTA backup
1 parent c90d578 commit a7329d9

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

src/data.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,9 +339,11 @@ prepare_page(backup_files_arg *arguments,
339339

340340
}
341341

342+
/* Nullified pages must be copied by DELTA backup, just to be safe */
342343
if (backup_mode == BACKUP_MODE_DIFF_DELTA &&
343344
file->exists_in_prev &&
344345
!page_is_truncated &&
346+
page_lsn &&
345347
page_lsn < prev_backup_start_lsn)
346348
{
347349
elog(VERBOSE, "Skipping blknum: %u in file: %s", blknum, file->path);

tests/delta.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,3 +1263,73 @@ def test_page_corruption_heal_via_ptrack_2(self):
12631263

12641264
# Clean after yourself
12651265
self.del_test_dir(module_name, fname)
1266+
1267+
def test_delta_nullified_heap_page_backup(self):
1268+
"""
1269+
make node, take full backup, nullify some heap block,
1270+
take delta backup, restore, physically compare pgdata`s
1271+
"""
1272+
fname = self.id().split('.')[3]
1273+
node = self.make_simple_node(
1274+
base_dir="{0}/{1}/node".format(module_name, fname),
1275+
initdb_params=['--data-checksums'],
1276+
pg_options={'wal_level': 'replica'}
1277+
)
1278+
backup_dir = os.path.join(self.tmp_path, module_name, fname, 'backup')
1279+
self.init_pb(backup_dir)
1280+
self.add_instance(backup_dir, 'node', node)
1281+
self.set_archiving(backup_dir, 'node', node)
1282+
node.slow_start()
1283+
1284+
node.pgbench_init(scale=1)
1285+
1286+
file_path = node.safe_psql(
1287+
"postgres",
1288+
"select pg_relation_filepath('pgbench_accounts')").rstrip()
1289+
1290+
node.safe_psql(
1291+
"postgres",
1292+
"CHECKPOINT")
1293+
1294+
self.backup_node(
1295+
backup_dir, 'node', node)
1296+
1297+
# Nullify some block in PostgreSQL
1298+
file = os.path.join(node.data_dir, file_path)
1299+
1300+
with open(file, 'r+b', 0) as f:
1301+
f.seek(8192)
1302+
f.write(b"\x00"*8192)
1303+
f.flush()
1304+
f.close
1305+
1306+
self.backup_node(
1307+
backup_dir, 'node', node,
1308+
backup_type='delta', options=["--log-level-file=verbose"])
1309+
1310+
if self.paranoia:
1311+
pgdata = self.pgdata_content(node.data_dir)
1312+
1313+
log_file_path = os.path.join(backup_dir, "log", "pg_probackup.log")
1314+
with open(log_file_path) as f:
1315+
self.assertTrue("LOG: File: {0} blknum 1, empty page".format(
1316+
file) in f.read())
1317+
self.assertFalse("Skipping blknum: 1 in file: {0}".format(
1318+
file) in f.read())
1319+
1320+
# Restore DELTA backup
1321+
node_restored = self.make_simple_node(
1322+
base_dir="{0}/{1}/node_restored".format(module_name, fname),
1323+
)
1324+
node_restored.cleanup()
1325+
1326+
self.restore_node(
1327+
backup_dir, 'node', node_restored
1328+
)
1329+
1330+
if self.paranoia:
1331+
pgdata_restored = self.pgdata_content(node_restored.data_dir)
1332+
self.compare_pgdata(pgdata, pgdata_restored)
1333+
1334+
# Clean after yourself
1335+
self.del_test_dir(module_name, fname)

0 commit comments

Comments
 (0)