Introduce --min-complete.
authorAndre Noll <maan@systemlinux.org>
Tue, 18 Feb 2014 13:16:02 +0000 (14:16 +0100)
committerAndre Noll <maan@tuebingen.mpg.de>
Tue, 16 Sep 2014 16:26:36 +0000 (18:26 +0200)
Currently dss cowardly refuses to remove the last complete snapshot
even if disk space is low, and fails if there is not enough disk space
left for a second snapshot. However, in some situations it is more
important to have a recent snapshot and to to keep dss up and running.

This commit introduces a new integer option, --min-complete, which
defaults to one to resemble the old behaviour.

If it is set to zero, dss will happily remove the last complete
snapshot, even if it is used as the reference directory for rsync's
--link-dest option. This is dangerous, but it's the only way to keep
dss going.

Conversely, --min-complete may be set to a value greater than one
to guarantee there is always a certain number of complete snapshots
available.

dss.c
dss.ggo
snap.c
snap.h

diff --git a/dss.c b/dss.c
index 3a2f468..9f39324 100644 (file)
--- a/dss.c
+++ b/dss.c
@@ -531,17 +531,25 @@ static struct snapshot *find_outdated_snapshot(struct snapshot_list *sl)
 
 static struct snapshot *find_oldest_removable_snapshot(struct snapshot_list *sl)
 {
-       int i;
-       struct snapshot *s;
+       int i, num_complete;
+       struct snapshot *s, *ref = NULL;
+
+       num_complete = num_complete_snapshots(sl);
+       if (num_complete <= conf.min_complete_arg)
+               return NULL;
        FOR_EACH_SNAPSHOT(s, i, sl) {
                if (snapshot_is_being_created(s))
                        continue;
-               if (is_reference_snapshot(s))
+               if (is_reference_snapshot(s)) { /* avoid this one */
+                       ref = s;
                        continue;
+               }
                DSS_INFO_LOG(("oldest removable snapshot: %s\n", s->name));
                return s;
        }
-       return NULL;
+       assert(ref);
+       DSS_WARNING_LOG(("removing reference snapshot %s\n", ref->name));
+       return ref;
 }
 
 static int rename_incomplete_snapshot(int64_t start)
diff --git a/dss.ggo b/dss.ggo
index 2f50474..d8b956e 100644 (file)
--- a/dss.ggo
+++ b/dss.ggo
@@ -439,3 +439,23 @@ details="
        becomes low. Use this flag if the file system containing the
        destination directory is used for snapshots only.
 "
+
+option "min-complete" -
+#~~~~~~~~~~~~~~~~~~~~~~
+"Minimal number of complete snapshots to keep"
+int typestr = "num"
+default = "1"
+optional
+details = "
+       This option is only relevant if snapshots must be deleted
+       because disk space gets low.
+
+       dss refuses to remove old snapshots if there are fewer complete
+       snapshots left than the given number. The default value of one
+       guarantees that at least one complete snapshot is available
+       at all times.
+
+       If only <num> complete snapshot are left, and there is not
+       enough disk space available for another snapshot, the program
+       terminates with a \"No space left on device\" error.
+"
diff --git a/snap.c b/snap.c
index aef0c51..ec0449d 100644 (file)
--- a/snap.c
+++ b/snap.c
@@ -232,3 +232,13 @@ __malloc char *name_of_newest_complete_snapshot(struct snapshot_list *sl)
        return name;
 }
 
+int num_complete_snapshots(struct snapshot_list *sl)
+{
+       struct snapshot *s;
+       int i, ret = 0;
+
+       FOR_EACH_SNAPSHOT(s, i, sl)
+               if (s->flags & SS_COMPLETE)
+                       ret++;
+       return ret;
+}
diff --git a/snap.h b/snap.h
index fc82850..c817de2 100644 (file)
--- a/snap.h
+++ b/snap.h
@@ -88,6 +88,7 @@ __malloc char *incomplete_name(int64_t start);
 __malloc char *being_deleted_name(struct snapshot *s);
 int complete_name(int64_t start, int64_t end, char **result);
 __malloc char *name_of_newest_complete_snapshot(struct snapshot_list *sl);
+int num_complete_snapshots(struct snapshot_list *sl);
 
 /**
  * Get the newest snapshot in a snapshot list.