Skip to content

Instantly share code, notes, and snippets.

@neon12345
Last active September 24, 2023 16:17
Show Gist options
  • Save neon12345/89968c0a71f064657b33ddd5047b3722 to your computer and use it in GitHub Desktop.
Save neon12345/89968c0a71f064657b33ddd5047b3722 to your computer and use it in GitHub Desktop.
Backup cleanup algorithm test
#!/bin/bash
# This script will simulate an infinite backup cycle per day.
# Empty backup files are created in the current working directory
# and deleted acording to the cleanup algorithm parameters.
# One file per second is created, which is one simulated day.
# => It is best to run this script form inside an empty test directory.
# This script will not halt and must be aborted!
# The same algorithm is used in https://github.com/bit-team/backintime
set -o pipefail
KEEP_LAST=2
KEEP_DAY=7
KEEP_WEEK=4
KEEP_MONTH=24
function err() { echo "$@" 1>&2; }
function sscanf() {
local str="$1"
if [[ "$str" =~ ^([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+).inc.backup$ ]]; then
HOUR=${BASH_REMATCH[1]}
DAY=${BASH_REMATCH[2]}
MONTH=${BASH_REMATCH[3]}
YEAR=${BASH_REMATCH[4]}
WEEK=${BASH_REMATCH[5]}
return
fi
false
}
function date_ts_from_ymd() {
local YEAR="$1"
local MONTH="$2"
local DAY="$3"
date -d "$YEAR-$MONTH-$DAY 00:00:00" "+%s"
}
function date_from_ts() {
local TS="$1"
local FORMAT="$2"
local OTHER="$3"
date -d "$(date -d @$TS "+%Y-%m-%d %H:%M:%S") $OTHER" "$FORMAT"
}
function date_in_range() {
local TS="$1"
local MIN="$2"
local MAX="$3"
(( MIN <= TS && TS < MAX ))
}
D=0
CURRENT_DATE=$(date "+%s")
while true; do
D="$(( D + 1 ))"
CURRENT_HOUR=$(date_from_ts "$CURRENT_DATE" "+%s" "$D days")
CURRENT_DAY=$(date_from_ts "$CURRENT_DATE" "+%d" "$D days")
CURRENT_WEEK=$(date_from_ts "$CURRENT_DATE" "+%V" "$D days")
CURRENT_MONTH=$(date_from_ts "$CURRENT_DATE" "+%m" "$D days")
CURRENT_YEAR=$(date_from_ts "$CURRENT_DATE" "+%Y" "$D days")
FILE="$CURRENT_HOUR-$CURRENT_DAY-$CURRENT_MONTH-$CURRENT_YEAR-$CURRENT_WEEK.inc.backup"
function date_current_ts() {
local OTHER="$1"
local FROM="$2"
if [[ -z "$FROM" ]]; then
FROM="$CURRENT_HOUR"
fi
date_from_ts "$FROM" "+%s" "$OTHER"
}
function find_snapshots() {
local MIN_YEAR=9999
while IFS= read -r -d $'\0' file; do
THE_FILE=$(basename $file)
if sscanf "$THE_FILE"; then
if (( MIN_YEAR > YEAR )); then
MIN_YEAR=$YEAR
fi
echo "$THE_FILE"
fi
done < <(find $TARGET_DIR -maxdepth 1 -type f -print0 | sort -Vz)
echo $MIN_YEAR
}
function find_remove() {
local TARGET_DIR="$1"
local MIN=0
local MAX=0
local CURRENT=0
local CURRENT2=0
local SNAPSHOTS=$(find_snapshots)
local MIN_YEAR=0
local KEEP=""
local MAP=""
declare -A MAP
function find_keep() {
if (( KEEP_LAST > 0 )); then
MIN=$(date_current_ts "$(( KEEP_LAST )) days ago")
MAX=$(date_current_ts "1 days")
for file in $SNAPSHOTS; do
sscanf "$file"
if date_in_range $HOUR $MIN $MAX; then
echo "$file"
fi
MIN_YEAR="$file"
done
fi
if (( KEEP_DAY > 0 )); then
for (( j=0; j < $KEEP_DAY; j++ )); do
MIN=$(date_current_ts "$j days ago")
MAX=$(date_current_ts "1 days" $MIN)
for file in $SNAPSHOTS; do
sscanf "$file"
if date_in_range $HOUR $MIN $MAX; then
echo "$file"
break
fi
done
done
fi
if (( KEEP_WEEK > 0 )); then
local WEEK_DAY=$(date_from_ts $(date_current_ts "") "+%u")
CURRENT=$(date_current_ts "$WEEK_DAY days ago")
for (( j=0; j < KEEP_WEEK; j++ )); do
MIN=$CURRENT
MAX=$(date_current_ts "8 days" $MIN)
for file in $SNAPSHOTS; do
sscanf "$file"
if date_in_range $HOUR $MIN $MAX; then
echo "$file"
break
fi
done
CURRENT=$(date_current_ts "7 days ago" $CURRENT)
done
fi
if (( KEEP_MONTH > 0 )); then
CURRENT=$(date_ts_from_ymd "$CURRENT_YEAR" "$CURRENT_MONTH" "1")
CURRENT2=$(date_current_ts "1 months" $CURRENT)
for (( j=0; j < KEEP_MONTH; j++ )); do
MIN=$CURRENT
MAX=$CURRENT2
for file in $SNAPSHOTS; do
sscanf "$file"
if date_in_range $HOUR $MIN $MAX; then
echo "$file"
break
fi
done
CURRENT2=$CURRENT
CURRENT=$(date_current_ts "1 months ago" $CURRENT)
done
fi
for (( j=MIN_YEAR; j <= CURRENT_YEAR; j++ )); do
MIN=$(date_ts_from_ymd "$j" "1" "1")
MAX=$(date_ts_from_ymd "$(( j + 1))" "1" "1")
for file in $SNAPSHOTS; do
sscanf "$file"
if date_in_range $HOUR $MIN $MAX; then
echo "$file"
break
fi
done
done
}
KEEP=$(find_keep | sort -u)
for file in $KEEP; do
MAP["$file"]=1
done
for file in $SNAPSHOTS; do
if [[ ${MAP["$file"]} != 1 ]]; then
if (( ${#file} > 10 )); then
echo "$file"
fi
fi
done
}
OUT_FILE="$FILE"
if [[ -f "$OUT_FILE" ]]; then
err "$FILE exists, try later."
exit 1
fi
#date_from_ts $(date_current_ts "") "+%Y-%m-%d %H:%M:%S"
#date_from_ts $(date_current_ts "1 months") "+%Y-%m-%d %H:%M:%S"
#echo "add $OUT_FILE"
touch "$OUT_FILE"
TO_REMOVE=$(find_remove .)
for line in $TO_REMOVE; do
#echo "remove: $line"
rm "$line"
done
sleep 1
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment