3 # expire-iso8601 <unit-in-seconds> <slop-in-seconds>
4 # <min-interval-in-units> <extent-in-min-intervals>
5 # [<min-interval-in-units> <extent-in-min-intervals> ...]
8 # /home/ian/junk/expire-iso8601 86400 10000 1 14 7 4
9 # uses units of 86400s (1 day) with a slop of 10ks;
10 # it keeps daily copies (that is, dated no more than 86400+10000s apart)
11 # for at least 1*14 days, ie the oldest will be at least 86400s*1*14-10000s
12 # older than the very newest
13 # and weekly copies (that is, dated no more than 7*86400+10000s apart)
14 # for at least 7*4 days, ie the oldest will be at least 86400s*7*4-10000s
15 # older than the very newest
19 fail () { echo >&2 "$*"; exit 2; }
20 badusage () { fail "bad usage: $*"; }
22 #-------------------- argument parsing --------------------
24 [ $# -ge 4 ] || badusage 'too few arguments'
30 [ $(($# % 2)) = 0 ] || badusage 'odd keep arguments (need min/extent pairs)'
34 [ "x${1##*[^0-9]}" = "x$1" ] || badusage "$2 must be all digits"
35 [ x$1 ] || badusage "$2 must be nonempty"
38 while [ $# -gt 0 ]; do
39 min=$1; shift; extent=$1; shift
41 alldigits $extent extent
44 #-------------------- scanning the directory ----------
46 # We build in $l a list of the relevant filenames and the time_t's
47 # they represent. And, while we're at it, we find the most recent
48 # such time_t ($ls) and its name ($ln).
50 # Each entry in $l is $time_t/$filename, and the list is
51 # newline-separated for the benefit of sort(1).
59 ????-??-??T[0-2][0-9]+[0-9][0-9][0-9][0-9]|\
60 ????-??-??T[0-2][0-9]:[0-6][0-9]+[0-9][0-9][0-9][0-9]|\
61 ????-??-??T[0-2][0-9]:[0-6][0-9]:[0-6][0-9]+[0-9][0-9][0-9][0-9])
62 conv="${cn%T*} ${cn#*T}";;
64 echo >&2 "ignoring $cn"
67 cs=$(date -d "$conv" +%s)
68 if [ $cs -gt $ls ]; then
77 #-------------------- main computation --------------------
79 # We go through the items from most to least recent
80 # ie in order of increasing age
81 # ie in order of decreasing time_t
82 # We constantly maintain records of this item (c) and the last two
85 # We then check to see if any of the specified minimum/extent pairs
86 # mean we should keep c and b.
88 # We can delete c if b is older than every specified extent. b will
89 # then be the latest version we keep and is old enough. (Note that if
90 # the density isn't satisfied, the expected number of old items may
91 # not be satisfied either; in the worst case, if b is very old, we
92 # might end up with just two items left.)
94 # If we delete c then we just go on to the next c, which will
95 # definitely be older, so will be deleted too (because b remains
96 # unchanged): ie we then delete all the rest.
98 # If we don't delete c, we look at the gap between a and c. If this
99 # gap is not too long (according to any of the minimum/extent pairs)
100 # then it is OK to delete b. (A gap is too long if it's longer than a
101 # relevant pair's minimum, but a pair isn't relevant if c is older
102 # than the extent.) If we delete b then current c becomes the new b.
104 # If we don't delete either then b and c become the new a and b.
106 - because b is clearly sufficient to
110 # {l,a,b,c}{s,n,a} = seconds, name of a,b,c where
111 # c is one we're looking at now and
113 # a is one before that
114 # l is last (most recent)
115 # where a, b, c have not been removed
123 echo "expire $1 (have $2)"
132 cs=${ce%%/*}; cn=${ce#*/}
135 b_needfordensity=false
137 ac_interval=$(( $as - $cs ))
139 while [ $# != 0 ]; do
140 min=$(( $1 * $unit + $slop ))
141 extent=$(( $1 * $2 * $unit - $slop ))
142 # if b is as old as required by anything
143 # then c is definitely surplus
145 [ $(($ls - $bs)) -le $extent ]; then
149 [ $(($ls - $as)) -le $extent -a \
150 $ac_interval -gt $min ]; then
151 b_needfordensity=true
155 if ! $c_mightneed; then
159 if ! $b_needfordensity; then