chiark / gitweb /
initial expire-iso860
authorianmdlvl <ianmdlvl>
Sat, 12 Aug 2006 19:00:57 +0000 (19:00 +0000)
committerianmdlvl <ianmdlvl>
Sat, 12 Aug 2006 19:00:57 +0000 (19:00 +0000)
debian/changelog
scripts/expire-iso8601 [new file with mode: 0755]

index 9ef478a..6a24e34 100644 (file)
@@ -1,3 +1,9 @@
+chiark-utils (4.1.5) unstable; urgency=low
+
+  * expire-iso8601 - new script.
+
+ --
+
 chiark-utils (4.1.4) unstable; urgency=low
 
   summer bugfix:
diff --git a/scripts/expire-iso8601 b/scripts/expire-iso8601
new file mode 100755 (executable)
index 0000000..55cdd7f
--- /dev/null
@@ -0,0 +1,168 @@
+#!/bin/bash
+# usage:
+#   expire-iso8601 <unit-in-seconds> <slop-in-seconds>
+#      <min-interval-in-units> <extent-in-min-intervals>
+#     [<min-interval-in-units> <extent-in-min-intervals> ...]
+#
+# eg
+#   /home/ian/junk/expire-iso8601 86400 10000  1 14  7 4
+# uses units of 86400s (1 day) with a slop of 10ks;
+# it keeps daily copies (that is, dated no more than 86400+10000s apart)
+#  for at least 1*14 days, ie the oldest will be at least 86400s*1*14-10000s
+#  older than the very newest
+# and weekly copies (that is, dated no more than 7*86400+10000s apart)
+#  for at least 7*4 days, ie the oldest will be at least 86400s*7*4-10000s
+#  older than the very newest
+
+set -e
+
+fail () { echo >&2 "$*"; exit 2; }
+badusage () { fail "bad usage: $*"; }
+
+#-------------------- argument parsing --------------------
+
+[ $# -ge 4 ] || badusage 'too few arguments'
+
+unit=$1
+slop=$2
+shift;shift
+
+[ $(($# % 2)) = 0 ] || badusage 'odd keep arguments (need min/extent pairs)'
+argl="$*"
+
+alldigits () {
+       [ "x${1##*[^0-9]}" = "x$1" ] || badusage "$2 must be all digits"
+       [ x$1 ] || badusage "$2 must be nonempty"
+}
+
+while [ $# -gt 0 ]; do
+       min=$1; shift; extent=$1; shift
+       alldigits $min min
+       alldigits $extent extent
+done
+
+#-------------------- scanning the directory ----------
+
+# We build in $l a list of the relevant filenames and the time_t's
+# they represent.  And, while we're at it, we find the most recent
+# such time_t ($ls) and its name ($ln).
+#
+# Each entry in $l is $time_t/$filename, and the list is
+# newline-separated for the benefit of sort(1).
+
+ls=0
+for cn in [0-9]*; do
+       echo $cn
+       case "$cn" in
+       ????-??-??)
+               conv="$cn";;
+       ????-??-??T[0-2][0-9]+[0-9][0-9][0-9][0-9]|\
+       ????-??-??T[0-2][0-9]:[0-6][0-9]+[0-9][0-9][0-9][0-9]|\
+       ????-??-??T[0-2][0-9]:[0-6][0-9]:[0-6][0-9]+[0-9][0-9][0-9][0-9])
+               conv="${cn%T*} ${cn#*T}";;
+       *)
+               echo >&2 "ignoring $cn"
+               continue;;
+       esac
+       cs=$(date -d "$conv" +%s)
+       if [ $cs -gt $ls ]; then
+               ls=$cs; ln=$cn
+       fi
+       l="$cs/$cn
+$l"
+done
+
+echo "newest $ln"
+
+#-------------------- main computation --------------------
+
+# We go through the items from most to least recent
+#   ie in order of increasing age
+#   ie in order of decreasing time_t
+# We constantly maintain records of this item (c) and the last two
+# (b and a).
+#
+# We then check to see if any of the specified minimum/extent pairs
+# mean we should keep c and b.
+#
+# We can delete c if b is older than every specified extent.  b will
+# then be the latest version we keep and is old enough.  (Note that if
+# the density isn't satisfied, the expected number of old items may
+# not be satisfied either; in the worst case, if b is very old, we
+# might end up with just two items left.)
+#
+# If we delete c then we just go on to the next c, which will
+# definitely be older, so will be deleted too (because b remains
+# unchanged): ie we then delete all the rest.
+#
+# If we don't delete c, we look at the gap between a and c.  If this
+# gap is not too long (according to any of the minimum/extent pairs)
+# then it is OK to delete b.  (A gap is too long if it's longer than a
+# relevant pair's minimum, but a pair isn't relevant if c is older
+# than the extent.)  If we delete b then current c becomes the new b.
+#
+# If we don't delete either then b and c become the new a and b.
+
+- because b is clearly sufficient to
+# satisfy the 
+# if we delete 
+
+# {l,a,b,c}{s,n,a} = seconds, name of a,b,c where
+#      c is one we're looking at now and
+#      b is previous one
+#      a is one before that
+#      l is last (most recent)
+# where a, b, c have not been removed
+
+as=''
+an=''
+bs=''
+bn=''
+
+remove () {
+       echo "expire $1 (have $2)"
+}
+
+l=$(sort -nr <<END
+$l
+END
+)
+
+for ce in $l; do
+       cs=${ce%%/*}; cn=${ce#*/}
+       set $argl
+       c_mightneed=false
+       b_needfordensity=false
+       if test "$as"; then
+               ac_interval=$(( $as - $cs ))
+       fi
+       while [ $# != 0 ]; do
+               min=$(( $1 * $unit + $slop ))
+               extent=$(( $1 * $2 * $unit - $slop ))
+               # if b is as old as required by anything
+               #  then c is definitely surplus
+               if ! [ "$bs" ] || \
+                  [ $(($ls - $bs)) -le $extent ]; then
+                       c_mightneed=true
+               fi
+               if ! test "$as" || \
+                  [ $(($ls - $as)) -le $extent -a \
+                    $ac_interval -gt $min ]; then
+                       b_needfordensity=true
+               fi
+               shift;shift
+       done
+       if ! $c_mightneed; then
+               remove $cn "$bn"
+               continue
+       fi
+       if ! $b_needfordensity; then
+               remove $bn "$an $cn"
+               bn=$cn; bs=$cs
+               continue
+       fi
+       an=$bn; as=$bs
+       bn=$cn; bs=$cs
+done
+
+exit 0