blob: 75ed2f7cdc1629058200e2c2202b3085056996e0 [file]
#!/bin/bash
# ------------------------------------------------------------------------------
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed
# with this work for additional information regarding copyright
# ownership. The ASF licenses this file to You under the Apache
# License, Version 2.0 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of the
# License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# ------------------------------------------------------------------------------
# Non-perf scale tests for GitHub Actions Cloudberry demo cluster.
# This focuses on backup/restore correctness under moderate object/data scale.
# ------------------------------------------------------------------------------
set -euo pipefail
BACKUP_DIR="${BACKUP_DIR:-/tmp/scale_backup}"
LOG_DIR="${LOG_DIR:-/tmp/scale-test-logs}"
mkdir -p "${BACKUP_DIR}" "${LOG_DIR}"
extract_timestamp() {
local log_file="$1"
local ts
ts="$(grep -E "Backup Timestamp[[:space:]]*=" "${log_file}" | grep -Eo "[[:digit:]]{14}" | head -n 1 || true)"
if [ -z "${ts}" ]; then
local latest_gpbackup_log
latest_gpbackup_log="$(ls -1t "${HOME}/gpAdminLogs"/gpbackup_*.log 2>/dev/null | head -n 1 || true)"
if [ -n "${latest_gpbackup_log}" ]; then
ts="$(grep -E "Backup Timestamp[[:space:]]*=" "${latest_gpbackup_log}" | grep -Eo "[[:digit:]]{14}" | head -n 1 || true)"
fi
fi
if [ -z "${ts}" ]; then
echo "Could not parse backup timestamp from ${log_file}"
return 1
fi
echo "${ts}"
}
validate_datascaledb_restore() {
local restore_db="$1"
local src_tables
local dst_tables
local src_big
local dst_big
src_tables="$(psql -X -d datascaledb -Atc "SELECT count(*) FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace WHERE n.nspname='public' AND c.relkind='r'")"
dst_tables="$(psql -X -d "${restore_db}" -Atc "SELECT count(*) FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace WHERE n.nspname='public' AND c.relkind='r'")"
src_big="$(psql -X -d datascaledb -Atc "SELECT count(*) FROM tbl_big")"
dst_big="$(psql -X -d "${restore_db}" -Atc "SELECT count(*) FROM tbl_big")"
if [ "${src_tables}" != "${dst_tables}" ] || [ "${src_big}" != "${dst_big}" ]; then
echo "Data scale restore validation failed for ${restore_db}"
echo "source tables=${src_tables}, restored tables=${dst_tables}"
echo "source tbl_big=${src_big}, restored tbl_big=${dst_big}"
return 1
fi
}
echo "## Preparing copy queue scale database ##"
psql -X -d postgres -qc "DROP DATABASE IF EXISTS copyqueuedb"
createdb copyqueuedb
for j in $(seq 1 300); do
psql -X -d copyqueuedb -q -c "CREATE TABLE tbl_1k_${j}(i int) DISTRIBUTED BY (i);"
psql -X -d copyqueuedb -q -c "INSERT INTO tbl_1k_${j} SELECT generate_series(1,1000)"
done
echo "## Copy queue backup/restore matrix ##"
for q in 2 4 8; do
b_log="${LOG_DIR}/copyqueue_backup_q${q}.log"
echo "Running gpbackup copy queue size ${q}"
gpbackup --dbname copyqueuedb --backup-dir "${BACKUP_DIR}" --single-data-file --no-compression --copy-queue-size "${q}" \
2>&1 | tee "${b_log}"
timestamp="$(extract_timestamp "${b_log}")"
restore_db="copyqueue_restore_q${q}"
psql -X -d postgres -qc "DROP DATABASE IF EXISTS ${restore_db}"
gprestore --timestamp "${timestamp}" --backup-dir "${BACKUP_DIR}" --create-db --redirect-db "${restore_db}" --copy-queue-size "${q}" \
2>&1 | tee "${LOG_DIR}/copyqueue_restore_q${q}.log"
src_tbl_count="$(psql -X -d copyqueuedb -Atc "SELECT count(*) FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace WHERE n.nspname='public' AND c.relkind='r'")"
dst_tbl_count="$(psql -X -d "${restore_db}" -Atc "SELECT count(*) FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace WHERE n.nspname='public' AND c.relkind='r'")"
if [ "${src_tbl_count}" != "${dst_tbl_count}" ]; then
echo "Copy queue restore validation failed for ${restore_db}: source tables=${src_tbl_count}, restored tables=${dst_tbl_count}"
exit 1
fi
done
echo "## Preparing data scale database ##"
psql -X -d postgres -qc "DROP DATABASE IF EXISTS datascaledb"
createdb datascaledb
for j in $(seq 1 200); do
psql -X -d datascaledb -q -c "CREATE TABLE tbl_1k_${j}(i int) DISTRIBUTED BY (i);"
psql -X -d datascaledb -q -c "INSERT INTO tbl_1k_${j} SELECT generate_series(1,1000)"
done
psql -X -d datascaledb -q -c "CREATE TABLE tbl_big(i int) DISTRIBUTED BY (i);"
for j in $(seq 1 25); do
psql -X -d datascaledb -q -c "INSERT INTO tbl_big SELECT generate_series(1,100000)"
done
psql -X -d datascaledb -q -c "CREATE TABLE big_partition(a int, b int, c int) DISTRIBUTED BY (a) PARTITION BY RANGE (b) (START (1) END (101) EVERY (1))"
psql -X -d datascaledb -q -c "INSERT INTO big_partition SELECT i, i, i FROM generate_series(1,100) i"
for j in $(seq 1 8); do
psql -X -d datascaledb -q -c "INSERT INTO big_partition SELECT * FROM big_partition"
done
echo "## Running data scale backup/restore matrix ##"
run_data_scale_case() {
local case_name="$1"
local backup_flags="$2"
local restore_db="$3"
local jobs="$4"
local b_log="${LOG_DIR}/datascale_${case_name}_backup.log"
local r_log="${LOG_DIR}/datascale_${case_name}_restore.log"
gpbackup --dbname datascaledb --backup-dir "${BACKUP_DIR}" ${backup_flags} 2>&1 | tee "${b_log}"
local ts
ts="$(extract_timestamp "${b_log}")"
psql -X -d postgres -qc "DROP DATABASE IF EXISTS ${restore_db}"
gprestore --timestamp "${ts}" --backup-dir "${BACKUP_DIR}" --create-db --redirect-db "${restore_db}" --jobs "${jobs}" \
2>&1 | tee "${r_log}"
validate_datascaledb_restore "${restore_db}"
}
run_data_scale_case "multi_data_file" "--leaf-partition-data" "datascale_restore_multi" "4"
run_data_scale_case "multi_data_file_zstd" "--leaf-partition-data --compression-type zstd" "datascale_restore_multi_zstd" "4"
run_data_scale_case "single_data_file" "--leaf-partition-data --single-data-file" "datascale_restore_single" "1"
run_data_scale_case "single_data_file_zstd" "--leaf-partition-data --single-data-file --compression-type zstd" "datascale_restore_single_zstd" "1"
echo "## Preparing metadata scale database ##"
psql -X -d postgres -qc "DROP DATABASE IF EXISTS metadatascaledb"
createdb metadatascaledb
psql -X -d metadatascaledb <<'SQL'
DO $$
DECLARE
i int;
BEGIN
FOR i IN 1..80 LOOP
EXECUTE format('CREATE SCHEMA IF NOT EXISTS s_%s', i);
EXECUTE format('CREATE TABLE s_%s.t_%s(id int, val text) DISTRIBUTED BY (id)', i, i);
EXECUTE format('CREATE VIEW s_%s.v_%s AS SELECT * FROM s_%s.t_%s', i, i, i, i);
END LOOP;
END$$;
SQL
echo "## Running metadata-only backup/restore ##"
meta_backup_log="${LOG_DIR}/metadata_backup.log"
meta_restore_log="${LOG_DIR}/metadata_restore.log"
gpbackup --dbname metadatascaledb --backup-dir "${BACKUP_DIR}" --metadata-only --verbose 2>&1 | tee "${meta_backup_log}"
meta_ts="$(extract_timestamp "${meta_backup_log}")"
psql -X -d postgres -qc "DROP DATABASE IF EXISTS metadatascaledb_res"
gprestore --timestamp "${meta_ts}" --backup-dir "${BACKUP_DIR}" --redirect-db metadatascaledb_res --jobs 4 --create-db \
2>&1 | tee "${meta_restore_log}"
echo "## Minimal correctness checks ##"
src_schema_count="$(psql -X -d metadatascaledb -Atc "SELECT count(*) FROM pg_namespace WHERE nspname LIKE 's_%'")"
dst_schema_count="$(psql -X -d metadatascaledb_res -Atc "SELECT count(*) FROM pg_namespace WHERE nspname LIKE 's_%'")"
if [ "${src_schema_count}" != "${dst_schema_count}" ]; then
echo "Metadata restore schema count mismatch: src=${src_schema_count} dst=${dst_schema_count}"
exit 1
fi
echo "Scale tests completed successfully"