b728fe84f2
Co-authored-by: Copilot <copilot@github.com>
119 lines
2.5 KiB
Bash
119 lines
2.5 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
ARCHIVE_DIR="/var/lib/postgresql_archive/18/main/pg_wal"
|
|
MIN_AGE_DAYS=7
|
|
DRY_RUN=1
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage: clean_walfiles.sh [--apply] [--archive-dir PATH] [--min-age-days N]
|
|
|
|
Cleans PostgreSQL archive WAL files using both rules:
|
|
1) Candidate file mtime is older than the oldest *.backup file mtime
|
|
2) Candidate file mtime is older than N days (default: 7)
|
|
|
|
Defaults to dry-run. Use --apply to actually delete files.
|
|
EOF
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--apply)
|
|
DRY_RUN=0
|
|
shift
|
|
;;
|
|
--archive-dir)
|
|
ARCHIVE_DIR="$2"
|
|
shift 2
|
|
;;
|
|
--min-age-days)
|
|
MIN_AGE_DAYS="$2"
|
|
shift 2
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown argument: $1" >&2
|
|
usage
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ ! -d "$ARCHIVE_DIR" ]]; then
|
|
echo "Archive directory does not exist: $ARCHIVE_DIR" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! [[ "$MIN_AGE_DAYS" =~ ^[0-9]+$ ]]; then
|
|
echo "--min-age-days must be a non-negative integer" >&2
|
|
exit 2
|
|
fi
|
|
|
|
mapfile -d '' backup_files < <(find "$ARCHIVE_DIR" -maxdepth 1 -type f -name '*.backup' -print0)
|
|
|
|
if [[ ${#backup_files[@]} -eq 0 ]]; then
|
|
echo "No .backup files found in $ARCHIVE_DIR; nothing to do."
|
|
exit 0
|
|
fi
|
|
|
|
oldest_backup=""
|
|
oldest_backup_ts=""
|
|
|
|
for backup_file in "${backup_files[@]}"; do
|
|
backup_ts=$(stat -c %Y "$backup_file")
|
|
if [[ -z "$oldest_backup_ts" || "$backup_ts" -lt "$oldest_backup_ts" ]]; then
|
|
oldest_backup_ts="$backup_ts"
|
|
oldest_backup="$backup_file"
|
|
fi
|
|
done
|
|
|
|
age_cutoff_ts=$(date -d "$MIN_AGE_DAYS days ago" +%s)
|
|
|
|
echo "Archive dir : $ARCHIVE_DIR"
|
|
echo "Oldest .backup file : $oldest_backup"
|
|
echo "Oldest .backup mtime: $oldest_backup_ts"
|
|
echo "Age cutoff (epoch) : $age_cutoff_ts"
|
|
|
|
declare -a files_to_delete=()
|
|
|
|
while IFS= read -r -d '' file; do
|
|
file_ts=$(stat -c %Y "$file")
|
|
|
|
# Delete only when both constraints are true.
|
|
if [[ "$file_ts" -lt "$oldest_backup_ts" && "$file_ts" -lt "$age_cutoff_ts" ]]; then
|
|
files_to_delete+=("$file")
|
|
fi
|
|
done < <(find "$ARCHIVE_DIR" -maxdepth 1 -type f ! -name '*.backup' -print0)
|
|
|
|
if [[ ${#files_to_delete[@]} -eq 0 ]]; then
|
|
echo "No files matched cleanup criteria."
|
|
exit 0
|
|
fi
|
|
|
|
echo ""
|
|
echo "Files matching cleanup criteria (${#files_to_delete[@]}):"
|
|
for file in "${files_to_delete[@]}"; do
|
|
echo " $file"
|
|
done
|
|
|
|
if [[ "$DRY_RUN" -eq 1 ]]; then
|
|
echo ""
|
|
echo "Dry-run mode: no files were deleted."
|
|
echo "Re-run with --apply to delete the files above."
|
|
exit 0
|
|
fi
|
|
|
|
deleted=0
|
|
for file in "${files_to_delete[@]}"; do
|
|
rm -f -- "$file"
|
|
((deleted += 1))
|
|
done
|
|
|
|
echo ""
|
|
echo "Deleted $deleted file(s)."
|