-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpg_refclone.sh
More file actions
executable file
·86 lines (66 loc) · 2.69 KB
/
pg_refclone.sh
File metadata and controls
executable file
·86 lines (66 loc) · 2.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/bin/bash
set -eux
ORIGINAL_DIR=$1
CLONE_DIR=$2
# create directory for clone
mkdir ${CLONE_DIR}
# make sure data directory cannot be started before we finish properly
cat <<EOT >> ${CLONE_DIR}/backup_label
pg_refclone.sh is not finished!
Removing this file and starting PG
will implicitly accept data corruption,
as the recovery will not run through
enough WAL to make things consistent.
EOT
# coprocess to handle backup control
coproc PSQL { psql -qtAX ; }
if [ $? -ne 0 ]; then exit 1; fi
# create replication slot so that we can later pull all the required WAL
echo "SELECT pg_create_physical_replication_slot('pg_refclone', TRUE);" >&${PSQL[1]}
if [ $? -ne 0 ]; then exit 1; fi
read -u ${PSQL[0]}
# drop slot later
clean_up () {
echo "SELECT pg_drop_replication_slot('pg_refclone');" >&${PSQL[1]}
echo '\q' >&${PSQL[1]}
}
trap clean_up EXIT
# start backup
echo "SELECT pg_backup_start('pg_refclone', TRUE);" >&${PSQL[1]}
if [ $? -ne 0 ]; then exit 1; fi
read -u ${PSQL[0]} START_LSN
echo $START_LSN
# do the reflink copy
cp -a --reflink=always ${ORIGINAL_DIR}/. ${CLONE_DIR}/
# make sure the clone is started in standby mode
touch ${CLONE_DIR}/standby.signal
# stop backup, saving return values for later use
# the return values are :lsn, :labelfile, :spcmapfile
echo "SELECT * FROM pg_backup_stop(FALSE) \gset" >&${PSQL[1]}
if [ $? -ne 0 ]; then exit 1; fi
echo "\echo :lsn" >&${PSQL[1]}
read -u ${PSQL[0]} END_LSN
echo $END_LSN
# create backup_label file
echo "\o ${CLONE_DIR}/backup_label \qecho :labelfile" >&${PSQL[1]}
# create tablespace_map file
echo "\o ${CLONE_DIR}/tablespace_map \qecho :spcmapfile" >&${PSQL[1]}
# reset output
echo "\o" >&${PSQL[1]}
# get the WAL file name matching the backup end LSN, ensuring the latter is properly quoted
echo "SELECT pg_walfile_name(:'lsn');" >&${PSQL[1]}
read -u ${PSQL[0]} END_WALFILE
echo $END_WALFILE
# advance slot to start of backup (otherwise we get all the WAL produced before pg_backup_start was called)
echo "SELECT pg_replication_slot_advance('pg_refclone', '$START_LSN');" >&${PSQL[1]}
if [ $? -ne 0 ]; then exit 1; fi
read -u ${PSQL[0]}
# clean out pg_wal so pg_receivewal encounters no conflicts
rm -rf ${CLONE_DIR}/pg_wal
mkdir ${CLONE_DIR}/pg_wal
# pull all the WAL that we need, should end automatically when we reach backup end LSN
/usr/pgsql-18/bin/pg_receivewal -v -D ${CLONE_DIR}/pg_wal/ -S pg_refclone -E $END_LSN -s 1
# rename the WAL file containing the backup stop and SWITCH WAL record, as pg_receivewal would have kept them as ".partial" files.
mv ${CLONE_DIR}/pg_wal/${END_WALFILE}.partial ${CLONE_DIR}/pg_wal/${END_WALFILE}
# remove postmaster.pid file that was cloned, we are safe to run on our own now.
rm -f ${CLONE_DIR}/postmaster.pid