]> git.tuebingen.mpg.de Git - dss.git/commitdiff
Merge branch 'refs/heads/t/prune'
authorAndre Noll <maan@tuebingen.mpg.de>
Thu, 7 Nov 2019 11:31:02 +0000 (12:31 +0100)
committerAndre Noll <maan@tuebingen.mpg.de>
Thu, 7 Nov 2019 11:31:02 +0000 (12:31 +0100)
A couple of cleanups and unifications for the snapshot pruning code,
which is executed by the prune and run subcommands. With the patches
applied, both subcommands behave identically, i.e. they consider
the same set of snapshots as candidates for pruning. Also the prune
command gained the new --disk-space option to force it to act as if
disk space was high or low.

Cooking for six weeks.

* refs/heads/t/prune:
  Introduce prune --disk-space.
  Revamp com_prune().
  Factor out find_removable_snapshot().
  prune Simplify rm exit code logic.
  find_oldest_removable_snapshot(): Improve log message.
  prune: Print a message if there is nothing to prune.
  get_snapshot_list(): Add comment about sorting.
  prune: Fail gracefully if pre-rm hook fails.

1  2 
dss.c

diff --combined dss.c
index 5f35435727e956c13bb82f6801fdbe251204665f,4396e6e5975c79d2806aa39625fea99d23a2ee90..f61f33597d7863e236a804d6c0541934e6ced8d5
--- 1/dss.c
--- 2/dss.c
+++ b/dss.c
@@@ -651,6 -651,7 +651,7 @@@ static struct snapshot *find_oldest_rem
        int i, num_complete;
        struct snapshot *s, *ref = NULL;
  
+       DSS_DEBUG_LOG(("picking snapshot with earliest creation time\n"));
        num_complete = num_complete_snapshots(sl);
        if (num_complete <= OPT_UINT32_VAL(DSS, MIN_COMPLETE))
                return NULL;
                        ref = s;
                        continue;
                }
-               DSS_INFO_LOG(("oldest removable snapshot: %s\n", s->name));
                return s;
        }
        assert(ref);
        return ref;
  }
  
+ /* returns NULL <==> *reason is set to NULL */
+ static struct snapshot *find_removable_snapshot(struct snapshot_list *sl,
+               bool try_hard, char **reason)
+ {
+       struct snapshot *victim;
+       /*
+        * Don't remove anything if there is free space and we have fewer
+        * snapshots than configured, plus one. This way there is always one
+        * snapshot that can be recycled.
+        */
+       if (!try_hard && sl->num_snapshots <=
+                       1 << OPT_UINT32_VAL(DSS, NUM_INTERVALS))
+               goto nope;
+       victim = find_orphaned_snapshot(sl);
+       if (victim) {
+               *reason = make_message("orphaned");
+               return victim;
+       }
+       victim = find_outdated_snapshot(sl);
+       if (victim) {
+               *reason = make_message("outdated");
+               return victim;
+       }
+       if (!OPT_GIVEN(DSS, KEEP_REDUNDANT)) {
+               victim = find_redundant_snapshot(sl);
+               if (victim) {
+                       *reason = make_message("redundant");
+                       return victim;
+               }
+       }
+       if (!try_hard)
+               goto nope;
+       DSS_WARNING_LOG(("nothing obvious to remove\n"));
+       victim = find_oldest_removable_snapshot(sl);
+       if (victim) {
+               *reason = make_message("oldest");
+               return victim;
+       }
+ nope:
+       *reason = NULL;
+       return NULL;
+ }
  static int rename_incomplete_snapshot(int64_t start)
  {
        char *old_name;
@@@ -701,7 -745,7 +745,7 @@@ static int try_to_free_disk_space(void
        struct snapshot_list sl;
        struct snapshot *victim;
        struct timeval now;
-       const char *why;
+       char *why;
        int low_disk_space;
  
        ret = disk_space_low(NULL);
        if (tv_diff(&next_removal_check, &now, NULL) > 0)
                return 0;
        if (!low_disk_space) {
-               if (OPT_GIVEN(DSS, KEEP_REDUNDANT))
-                       return 0;
                if (snapshot_creation_status != HS_READY)
                        return 0;
                if (next_snapshot_is_due())
                        return 0;
        }
-       /*
-        * Idle and --keep_redundant not given, or low disk space. Look at
-        * existing snapshots.
-        */
+       /* Idle or low disk space, look at existing snapshots. */
        dss_get_snapshot_list(&sl);
-       ret = 0;
-       /*
-        * Don't remove anything if there is free space and we have fewer
-        * snapshots than configured, plus one. This way there is always one
-        * snapshot that can be recycled.
-        */
-       if (!low_disk_space && sl.num_snapshots <=
-                       1 << OPT_UINT32_VAL(DSS, NUM_INTERVALS))
-               goto out;
-       why = "outdated";
-       victim = find_outdated_snapshot(&sl);
-       if (victim)
-               goto remove;
-       why = "redundant";
-       victim = find_redundant_snapshot(&sl);
-       if (victim)
-               goto remove;
-       why = "orphaned";
-       victim = find_orphaned_snapshot(&sl);
+       victim = find_removable_snapshot(&sl, low_disk_space, &why);
+       if (victim) {
+               pre_remove_hook(victim, why);
+               free(why);
+       }
+       free_snapshot_list(&sl);
        if (victim)
-               goto remove;
-       /* try harder only if disk space is low */
+               return 1;
        if (!low_disk_space)
-               goto out;
-       DSS_WARNING_LOG(("disk space low and nothing obvious to remove\n"));
-       why = "oldest";
-       victim = find_oldest_removable_snapshot(&sl);
-       if (victim)
-               goto remove;
+               return 0;
        DSS_CRIT_LOG(("uhuhu: disk space low and nothing to remove\n"));
-       ret = -ERRNO_TO_DSS_ERROR(ENOSPC);
-       goto out;
- remove:
-       pre_remove_hook(victim, why);
- out:
-       free_snapshot_list(&sl);
-       return ret;
+       return -ERRNO_TO_DSS_ERROR(ENOSPC);
  }
  
  static void post_create_hook(void)
@@@ -1444,7 -1458,7 +1458,7 @@@ static void create_rsync_argv(char ***a
                                        OPT_STRING_VAL(DSS, REMOTE_USER) : logname,
                                OPT_STRING_VAL(DSS, REMOTE_HOST),
                                lls_string_val(j, OPT_RESULT(DSS, SOURCE_DIR)),
 -                              N == 1? "/" : ""
 +                              OPT_GIVEN(DSS, SOURCE_DIR) == 1? "/" : ""
                        );
                }
        }
@@@ -1567,7 -1581,7 +1581,7 @@@ static void exit_hook(int exit_code
  {
        pid_t pid;
        char **argv, *tmp = dss_strdup(OPT_STRING_VAL(DSS, EXIT_HOOK));
 -      unsigned n = split_args(tmp, &argv, " \t");
 +      unsigned n = split_args(tmp, &argv);
  
        n++;
        argv = dss_realloc(argv, (n + 1) * sizeof(char *));
@@@ -1645,55 -1659,55 +1659,55 @@@ static int com_prune(void
        struct snapshot_list sl;
        struct snapshot *victim;
        struct disk_space ds;
-       const char *why;
+       char *why;
+       bool try_hard;
  
        lock_dss_or_die();
-       ret = get_disk_space(".", &ds);
-       if (ret < 0)
-               return ret;
-       log_disk_space(&ds);
+       switch (OPT_UINT32_VAL(PRUNE, DISK_SPACE)) {
+       case FDS_LOW: try_hard = true; break;
+       case FDS_HIGH: try_hard = false; break;
+       default:
+               ret = get_disk_space(".", &ds);
+               if (ret < 0)
+                       return ret;
+               log_disk_space(&ds);
+               try_hard = disk_space_low(&ds);
+       }
        dss_get_snapshot_list(&sl);
-       why = "outdated";
-       victim = find_outdated_snapshot(&sl);
-       if (victim)
-               goto rm;
-       why = "redundant";
-       victim = find_redundant_snapshot(&sl);
-       if (victim)
-               goto rm;
-       ret = 0;
-       goto out;
- rm:
+       victim = find_removable_snapshot(&sl, try_hard, &why);
+       if (!victim) {
+               dss_msg("nothing to prune\n");
+               ret = 0;
+               goto free_sl;
+       }
        if (OPT_GIVEN(DSS, DRY_RUN)) {
-               dss_msg("%s snapshot %s (interval = %i)\n",
+               dss_msg("picking %s snapshot %s (interval = %i)\n",
                        why, victim->name, victim->interval);
                ret = 0;
-               goto out;
+               goto free_why;
        }
        pre_remove_hook(victim, why);
        if (snapshot_removal_status == HS_PRE_RUNNING) {
                ret = wait_for_remove_process();
                if (ret < 0)
-                       goto out;
+                       goto free_why;
+               ret = -E_HOOK_FAILED;
                if (snapshot_removal_status != HS_PRE_SUCCESS)
-                       goto out;
+                       goto free_why;
        }
        ret = exec_rm();
        if (ret < 0)
-               goto out;
+               goto free_why;
        ret = wait_for_remove_process();
        if (ret < 0)
-               goto out;
-       if (snapshot_removal_status != HS_SUCCESS)
-               goto out;
+               goto free_why;
+       assert(snapshot_removal_status == HS_SUCCESS);
        post_remove_hook();
-       if (snapshot_removal_status != HS_POST_RUNNING)
-               goto out;
+       assert(snapshot_removal_status == HS_POST_RUNNING);
        ret = wait_for_remove_process();
-       if (ret < 0)
-               goto out;
-       ret = 1;
- out:
+ free_why:
+       free(why);
+ free_sl:
        free_snapshot_list(&sl);
        return ret;
  }