mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-15 18:13:18 +08:00
Currently, MN is not supported on PG16. Therefore, the creation of distributed restore points fails on PG16. This patch disables the CI test for this PG version.
323 lines
8.8 KiB
Bash
Executable File
323 lines
8.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
#
|
|
# Test PostgreSQL restore point recovery for single node (1 instance, regular hypertable)
|
|
# and multi node cluster (4 instances, distributed hypertable).
|
|
#
|
|
# Make sure that single and multi node results match after recovery.
|
|
#
|
|
|
|
set -e
|
|
set -o pipefail
|
|
set -x
|
|
|
|
SN_NAME=${SN_NAME:-sn}
|
|
AN_NAME=${AN_NAME:-an}
|
|
DN1_NAME=${DN1_NAME:-dn1}
|
|
DN2_NAME=${DN2_NAME:-dn2}
|
|
DN3_NAME=${DN3_NAME:-dn3}
|
|
|
|
HOST=${HOST:-'localhost'}
|
|
SN_PORT=${SN_PORT:-5442}
|
|
AN_PORT=${AN_PORT:-5442}
|
|
DN1_PORT=${DN1_PORT:-5443}
|
|
DN2_PORT=${DN2_PORT:-5444}
|
|
DN3_PORT=${DN3_PORT:-5445}
|
|
|
|
TEST_DIR=${TEST_DIR:-$(pwd)}
|
|
WAL_DIR=${TEST_DIR}/wal
|
|
BASEBACKUP_DIR=${TEST_DIR}/basebackup
|
|
STORAGE_DIR=${TEST_DIR}/storage
|
|
RESULT_DIR=${TEST_DIR}/result
|
|
|
|
TEST_RESTORE_POINT_1=${TEST_RESTORE_POINT_1:-rp1}
|
|
TEST_RESTORE_POINT_2=${TEST_RESTORE_POINT_2:-rp2}
|
|
TEST_RESTORE_POINT_3=${TEST_RESTORE_POINT_3:-rp3}
|
|
|
|
PG_BINDIR=${PG_BINDIR:-$(pg_config --bindir)}
|
|
PG_VERSION_MAJOR=$(${PG_BINDIR}/postgres -V | awk '{print $3}' | sed 's/\./ /g' | awk '{print $1}')
|
|
PG_USER=${PG_USER:-postgres}
|
|
|
|
function instance_configure()
|
|
{
|
|
NAME=$1
|
|
PORT=$2
|
|
RESTORE_POINT_NAME=$3
|
|
${PG_BINDIR}/pg_ctl init -U ${PG_USER} -D "${STORAGE_DIR}/${NAME}"
|
|
cat > "${STORAGE_DIR}/${NAME}/postgresql.conf" <<EOF
|
|
port=${PORT}
|
|
shared_preload_libraries = 'timescaledb'
|
|
autovacuum=false
|
|
timescaledb.telemetry_level=off
|
|
timescaledb_telemetry.cloud='ci'
|
|
max_prepared_transactions = 100
|
|
wal_level = 'archive'
|
|
archive_mode = on
|
|
archive_command = 'test ! -f ${WAL_DIR}/${NAME}/%f && cp %p ${WAL_DIR}/${NAME}/%f'
|
|
EOF
|
|
}
|
|
|
|
function instance_start()
|
|
{
|
|
NAME=$1
|
|
HOST=$2
|
|
PORT=$3
|
|
${PG_BINDIR}/pg_ctl start -U ${PG_USER} -D "${STORAGE_DIR}/${NAME}"
|
|
for _ in {1..20}; do
|
|
sleep 0.5
|
|
if ${PG_BINDIR}/pg_isready -q -U ${PG_USER} -h ${HOST} -p ${PORT} -d postgres
|
|
then
|
|
sleep 0.2
|
|
return 0
|
|
fi
|
|
done
|
|
exit 1
|
|
}
|
|
|
|
function instance_create()
|
|
{
|
|
NAME=$1
|
|
HOST=$2
|
|
PORT=$3
|
|
RESTORE_POINT_NAME=$4
|
|
mkdir -p "${WAL_DIR}/${NAME}"
|
|
mkdir -p "${STORAGE_DIR}/${NAME}"
|
|
mkdir -p "${BASEBACKUP_DIR}/${NAME}"
|
|
instance_configure ${NAME} ${PORT} ${RESTORE_POINT_NAME}
|
|
instance_start ${NAME} ${HOST} ${PORT}
|
|
}
|
|
|
|
function instance_stop()
|
|
{
|
|
NAME=$1
|
|
${PG_BINDIR}/pg_ctl stop -U ${PG_USER} -D "${STORAGE_DIR}/${NAME}"
|
|
}
|
|
|
|
function instance_recover()
|
|
{
|
|
NAME=$1
|
|
HOST=$2
|
|
PORT=$3
|
|
cp -R "${BASEBACKUP_DIR}/${NAME}" "${STORAGE_DIR}/${NAME}"
|
|
chmod 700 "${STORAGE_DIR}/${NAME}"
|
|
touch "${STORAGE_DIR}/${NAME}/recovery.signal"
|
|
RECOVERY_FILE="${STORAGE_DIR}/${NAME}/postgresql.conf"
|
|
cat >> "${RECOVERY_FILE}" <<EOF
|
|
restore_command = 'cp ${WAL_DIR}/${NAME}/%f %p'
|
|
recovery_target_name = '${RESTORE_POINT_NAME}'
|
|
recovery_target_action = 'promote'
|
|
EOF
|
|
instance_start ${NAME} ${HOST} ${PORT}
|
|
}
|
|
|
|
function instance_basebackup()
|
|
{
|
|
NAME=$1
|
|
HOST=$2
|
|
PORT=$3
|
|
echo "CHECKPOINT" |${PG_BINDIR}/psql -U ${PG_USER} -p ${PORT} -h ${HOST} ${NAME}
|
|
${PG_BINDIR}/pg_basebackup -U ${PG_USER} --progress -p ${PORT} -h ${HOST} -D "${BASEBACKUP_DIR}/${NAME}"
|
|
}
|
|
|
|
function instance_cleanup_storage()
|
|
{
|
|
NAME=$1
|
|
rm -rf "${STORAGE_DIR:?}/${NAME}"
|
|
}
|
|
|
|
function instance_cleanup()
|
|
{
|
|
NAME=$1
|
|
rm -rf "${STORAGE_DIR:?}/${NAME}"
|
|
rm -rf "${WAL_DIR:?}/${NAME}"
|
|
rm -rf "${BASEBACKUP_DIR:?}/${NAME}"
|
|
}
|
|
|
|
function instance_cleanup_dirs()
|
|
{
|
|
rm -rf ${STORAGE_DIR}
|
|
rm -rf ${WAL_DIR}
|
|
rm -rf ${BASEBACKUP_DIR}
|
|
rm -rf ${RESULT_DIR}
|
|
}
|
|
|
|
function test_single_node()
|
|
{
|
|
RESTORE_POINT_NAME=$1
|
|
RESULT_FILE_NAME=${RESULT_DIR}/single_node_${RESTORE_POINT_NAME}
|
|
|
|
# create and start single node instance
|
|
instance_create ${SN_NAME} ${HOST} ${SN_PORT} ${RESTORE_POINT_NAME}
|
|
|
|
# setup database
|
|
${PG_BINDIR}/createdb -U ${PG_USER} -p ${SN_PORT} -h ${HOST} ${SN_NAME}
|
|
|
|
${PG_BINDIR}/psql -U ${PG_USER} -p ${SN_PORT} -h ${HOST} ${SN_NAME} <<EOF
|
|
CREATE EXTENSION timescaledb;
|
|
|
|
CREATE TABLE test(time timestamp NOT NULL, device int, temp float);
|
|
SELECT create_hypertable('test', 'time', 'device', 3);
|
|
|
|
INSERT INTO test VALUES('2017-01-01 06:01', 1, 1.1), ('2017-01-01 09:11', 3, 2.1);
|
|
EOF
|
|
# do initial basebackup
|
|
instance_basebackup ${SN_NAME} ${HOST} ${SN_PORT}
|
|
|
|
# insert more data and create the restore points
|
|
${PG_BINDIR}/psql -U ${PG_USER} -p ${SN_PORT} -h ${HOST} ${SN_NAME} <<EOF
|
|
SELECT pg_create_restore_point('${TEST_RESTORE_POINT_1}');
|
|
|
|
INSERT INTO test VALUES('2017-01-01 08:01', 1, 1.2), ('2017-01-02 08:01', 2, 1.3);
|
|
|
|
SELECT pg_create_restore_point('${TEST_RESTORE_POINT_2}');
|
|
|
|
INSERT INTO test VALUES
|
|
('2018-07-02 08:01', 87, 1.6),
|
|
('2018-07-01 06:01', 13, 1.4),
|
|
('2018-07-01 09:11', 90, 2.7),
|
|
('2018-07-01 08:01', 29, 1.5);
|
|
|
|
SELECT pg_create_restore_point('${TEST_RESTORE_POINT_3}');
|
|
EOF
|
|
|
|
# stop instance and cleanup data
|
|
instance_stop ${SN_NAME}
|
|
|
|
# delete original data
|
|
instance_cleanup_storage ${SN_NAME}
|
|
|
|
# recover database up to the restore point
|
|
instance_recover ${SN_NAME} ${HOST} ${SN_PORT}
|
|
|
|
# ensure database has expected set of row
|
|
${PG_BINDIR}/psql -U ${PG_USER} -p ${SN_PORT} -h ${HOST} ${SN_NAME} > ${RESULT_FILE_NAME} <<EOF
|
|
SELECT * FROM test ORDER BY time;
|
|
EOF
|
|
|
|
# stop instance and clean the repository
|
|
instance_stop ${SN_NAME}
|
|
instance_cleanup ${SN_NAME}
|
|
}
|
|
|
|
function test_multi_node()
|
|
{
|
|
RESTORE_POINT_NAME=$1
|
|
RESULT_FILE_NAME=${RESULT_DIR}/multi_node_${RESTORE_POINT_NAME}
|
|
|
|
# setup instances
|
|
instance_create ${AN_NAME} ${HOST} ${AN_PORT} ${RESTORE_POINT_NAME}
|
|
instance_create ${DN1_NAME} ${HOST} ${DN1_PORT} ${RESTORE_POINT_NAME}
|
|
instance_create ${DN2_NAME} ${HOST} ${DN2_PORT} ${RESTORE_POINT_NAME}
|
|
instance_create ${DN3_NAME} ${HOST} ${DN3_PORT} ${RESTORE_POINT_NAME}
|
|
|
|
# setup multinode cluster
|
|
${PG_BINDIR}/createdb -U ${PG_USER} -p ${AN_PORT} -h ${HOST} ${AN_NAME}
|
|
|
|
${PG_BINDIR}/psql -U ${PG_USER} -p ${AN_PORT} -h ${HOST} ${AN_NAME} <<EOF
|
|
CREATE EXTENSION timescaledb;
|
|
|
|
SELECT add_data_node('${DN1_NAME}', database => '${DN1_NAME}', host => '${HOST}', port => ${DN1_PORT});
|
|
SELECT add_data_node('${DN2_NAME}', database => '${DN2_NAME}', host => '${HOST}', port => ${DN2_PORT});
|
|
SELECT add_data_node('${DN3_NAME}', database => '${DN3_NAME}', host => '${HOST}', port => ${DN3_PORT});
|
|
|
|
CREATE TABLE test(time timestamp NOT NULL, device int, temp float);
|
|
SELECT create_distributed_hypertable('test', 'time', 'device', 3);
|
|
|
|
INSERT INTO test VALUES('2017-01-01 06:01', 1, 1.1), ('2017-01-01 09:11', 3, 2.1);
|
|
EOF
|
|
|
|
# do initial basebackup
|
|
instance_basebackup ${AN_NAME} ${HOST} ${AN_PORT}
|
|
instance_basebackup ${DN1_NAME} ${HOST} ${DN1_PORT}
|
|
instance_basebackup ${DN2_NAME} ${HOST} ${DN2_PORT}
|
|
instance_basebackup ${DN3_NAME} ${HOST} ${DN3_PORT}
|
|
|
|
# insert more data and create the restore points
|
|
${PG_BINDIR}/psql -U ${PG_USER} -p ${AN_PORT} -h ${HOST} ${AN_NAME} <<EOF
|
|
SELECT create_distributed_restore_point('${TEST_RESTORE_POINT_1}');
|
|
|
|
INSERT INTO test VALUES('2017-01-01 08:01', 1, 1.2), ('2017-01-02 08:01', 2, 1.3);
|
|
|
|
SELECT create_distributed_restore_point('${TEST_RESTORE_POINT_2}');
|
|
|
|
INSERT INTO test VALUES
|
|
('2018-07-02 08:01', 87, 1.6),
|
|
('2018-07-01 06:01', 13, 1.4),
|
|
('2018-07-01 09:11', 90, 2.7),
|
|
('2018-07-01 08:01', 29, 1.5);
|
|
|
|
SELECT create_distributed_restore_point('${TEST_RESTORE_POINT_3}');
|
|
|
|
INSERT INTO test VALUES ('2021-01-01 00:00', 95, 1.3);
|
|
EOF
|
|
|
|
# stop instances and cleanup data
|
|
instance_stop ${AN_NAME}
|
|
instance_stop ${DN1_NAME}
|
|
instance_stop ${DN2_NAME}
|
|
instance_stop ${DN3_NAME}
|
|
|
|
# delete original data
|
|
instance_cleanup_storage ${AN_NAME}
|
|
instance_cleanup_storage ${DN1_NAME}
|
|
instance_cleanup_storage ${DN2_NAME}
|
|
instance_cleanup_storage ${DN3_NAME}
|
|
|
|
# recover multinode cluster up to the restore point
|
|
instance_recover ${AN_NAME} ${HOST} ${AN_PORT}
|
|
instance_recover ${DN1_NAME} ${HOST} ${DN1_PORT}
|
|
instance_recover ${DN2_NAME} ${HOST} ${DN2_PORT}
|
|
instance_recover ${DN3_NAME} ${HOST} ${DN3_PORT}
|
|
|
|
# ensure cluster has expected set of row
|
|
${PG_BINDIR}/psql -U ${PG_USER} -p ${AN_PORT} -h ${HOST} ${AN_NAME} > ${RESULT_FILE_NAME} <<EOF
|
|
SELECT * FROM test ORDER BY time;
|
|
EOF
|
|
|
|
# stop instances and clean repositories
|
|
instance_stop ${AN_NAME}
|
|
instance_stop ${DN1_NAME}
|
|
instance_stop ${DN2_NAME}
|
|
instance_stop ${DN3_NAME}
|
|
|
|
instance_cleanup ${AN_NAME}
|
|
instance_cleanup ${DN1_NAME}
|
|
instance_cleanup ${DN2_NAME}
|
|
instance_cleanup ${DN3_NAME}
|
|
}
|
|
|
|
function test_diff()
|
|
{
|
|
RESTORE_POINT_NAME=$1
|
|
diff ${RESULT_DIR}/single_node_${RESTORE_POINT_NAME} ${RESULT_DIR}/multi_node_${RESTORE_POINT_NAME}
|
|
}
|
|
|
|
if [ ${PG_VERSION_MAJOR} -lt 13 ]; then
|
|
echo "Current PostgreSQL version is not supported (expected version >= PG13)"
|
|
exit 1
|
|
fi
|
|
|
|
if [ ${PG_VERSION_MAJOR} -ge 16 ]; then
|
|
echo "Multi-node is currently not supported on PG >= 16"
|
|
exit 0
|
|
fi
|
|
|
|
mkdir -p ${RESULT_DIR}
|
|
|
|
echo "Running single node tests"
|
|
test_single_node ${TEST_RESTORE_POINT_1}
|
|
test_single_node ${TEST_RESTORE_POINT_2}
|
|
test_single_node ${TEST_RESTORE_POINT_3}
|
|
|
|
echo "Running multi node tests"
|
|
test_multi_node ${TEST_RESTORE_POINT_1}
|
|
test_multi_node ${TEST_RESTORE_POINT_2}
|
|
test_multi_node ${TEST_RESTORE_POINT_3}
|
|
|
|
echo "Compare results"
|
|
test_diff ${TEST_RESTORE_POINT_1}
|
|
test_diff ${TEST_RESTORE_POINT_2}
|
|
test_diff ${TEST_RESTORE_POINT_3}
|
|
|
|
instance_cleanup_dirs
|