From: Arvin Schnell Date: Tue, 22 Sep 2020 07:35:31 +0000 (+0200) Subject: - added option to cleanup to make requested free space available X-Git-Tag: v0.8.14~2^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F569%2Fhead;p=thirdparty%2Fsnapper.git - added option to cleanup to make requested free space available --- diff --git a/VERSION b/VERSION index c2f73c6e..832bad27 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.8.13 +0.8.14 diff --git a/client/cleanup.cc b/client/cleanup.cc index 2119e047..6803c20f 100644 --- a/client/cleanup.cc +++ b/client/cleanup.cc @@ -1,6 +1,6 @@ /* * Copyright (c) [2011-2014] Novell, Inc. - * Copyright (c) [2016,2018] SUSE LLC + * Copyright (c) [2016-2020] SUSE LLC * * All Rights Reserved. * @@ -89,6 +89,7 @@ public: virtual ~Cleaner() {} void cleanup(); + void cleanup(std::function condition); protected: @@ -423,6 +424,19 @@ Cleaner::cleanup() } +void +Cleaner::cleanup(std::function condition) +{ + ProxySnapshots& snapshots = snapper->getSnapshots(); + +#ifdef VERBOSE_LOGGING + cout << "cleanup with user condition" << '\n'; +#endif + + cleanup(snapshots, condition); +} + + struct NumberParameters : public Parameters { NumberParameters(const ProxySnapper* snapper); @@ -534,6 +548,15 @@ do_cleanup_number(ProxySnapper* snapper, bool verbose) } +void +do_cleanup_number(ProxySnapper* snapper, bool verbose, std::function condition) +{ + NumberParameters parameters(snapper); + NumberCleaner cleaner(snapper, verbose, parameters); + cleaner.cleanup(condition); +} + + struct TimelineParameters : public Parameters { TimelineParameters(const ProxySnapper* snapper); @@ -737,6 +760,15 @@ do_cleanup_timeline(ProxySnapper* snapper, bool verbose) } +void +do_cleanup_timeline(ProxySnapper* snapper, bool verbose, std::function condition) +{ + TimelineParameters parameters(snapper); + TimelineCleaner cleaner(snapper, verbose, parameters); + cleaner.cleanup(condition); +} + + struct EmptyPrePostParameters : public Parameters { EmptyPrePostParameters(const ProxySnapper* snapper); @@ -796,3 +828,12 @@ do_cleanup_empty_pre_post(ProxySnapper* snapper, bool verbose) EmptyPrePostCleaner cleaner(snapper, verbose, parameters); cleaner.cleanup(); } + + +void +do_cleanup_empty_pre_post(ProxySnapper* snapper, bool verbose, std::function condition) +{ + EmptyPrePostParameters parameters(snapper); + EmptyPrePostCleaner cleaner(snapper, verbose, parameters); + cleaner.cleanup(condition); +} diff --git a/client/cleanup.h b/client/cleanup.h index 000b6698..6d250079 100644 --- a/client/cleanup.h +++ b/client/cleanup.h @@ -1,6 +1,6 @@ /* * Copyright (c) [2011-2012] Novell, Inc. - * Copyright (c) 2016 SUSE LLC + * Copyright (c) [2016-2020] SUSE LLC * * All Rights Reserved. * @@ -21,9 +21,16 @@ */ +#include + #include "proxy.h" +/* + * The following three functions do the cleanup based on the conditionals defined in the + * config, that are hard limit, quota and free space. + */ + void do_cleanup_number(ProxySnapper* snapper, bool verbose); @@ -32,3 +39,18 @@ do_cleanup_timeline(ProxySnapper* snapper, bool verbose); void do_cleanup_empty_pre_post(ProxySnapper* snapper, bool verbose); + + +/* + * The following three functions do the cleanup only based on the provided + * conditional. The lower range and min-age defined in the config are respected. + */ + +void +do_cleanup_number(ProxySnapper* snapper, bool verbose, std::function condition); + +void +do_cleanup_timeline(ProxySnapper* snapper, bool verbose, std::function condition); + +void +do_cleanup_empty_pre_post(ProxySnapper* snapper, bool verbose, std::function condition); diff --git a/client/cmd-cleanup.cc b/client/cmd-cleanup.cc index a969a6f4..20f09167 100644 --- a/client/cmd-cleanup.cc +++ b/client/cmd-cleanup.cc @@ -22,13 +22,19 @@ #include +#include #include +#include +#include +#include "utils/HumanString.h" #include "utils/text.h" #include "GlobalOptions.h" #include "proxy.h" #include "cleanup.h" +#include "misc.h" +#include "cmd.h" namespace snapper @@ -42,39 +48,327 @@ namespace snapper { cout << _(" Cleanup snapshots:") << '\n' << _("\tsnapper cleanup ") << '\n' + << '\n' + << _(" Options for 'cleanup' command:") << '\n' + << _("\t--path \t\t\tCleanup all configs affecting path.") << '\n' + << _("\t--free-space \t\tTry to make space available.") << '\n' << endl; } + namespace + { + + enum class CleanupAlgorithm { ALL, NUMBER, TIMELINE, EMPTY_PRE_POST }; + + class FreeSpaceCondition + { + public: + + FreeSpaceCondition(const string& path, unsigned long long free_space) + : sdir(path), free_space(free_space) + { + } + + bool + is_satisfied() const + { + FreeSpaceData free_space_data; + std::tie(free_space_data.size, free_space_data.free) = sdir.statvfs(); + + bool satisfied = free_space_data.free >= free_space; + +#ifdef VERBOSE_LOGGING + cout << byte_to_humanstring(free_space_data.size, 2) << ", " + << byte_to_humanstring(free_space_data.free, 2) << ", " + << byte_to_humanstring(free_space, 2) << ", " << satisfied << '\n'; +#endif + + return satisfied; + } + + bool + is_satisfied(const ProxySnapper* snapper) const + { + snapper->syncFilesystem(); + + return is_satisfied(); + } + + private: + + SDir sdir; + + unsigned long long free_space; + + }; + + + void + run_cleanup(ProxySnapper* snapper, CleanupAlgorithm cleanup_algorithm, bool verbose) + { + switch (cleanup_algorithm) + { + case CleanupAlgorithm::NUMBER: + do_cleanup_number(snapper, verbose); + break; + + case CleanupAlgorithm::TIMELINE: + do_cleanup_timeline(snapper, verbose); + break; + + case CleanupAlgorithm::EMPTY_PRE_POST: + do_cleanup_empty_pre_post(snapper, verbose); + break; + + case CleanupAlgorithm::ALL: + do_cleanup_number(snapper, verbose); + do_cleanup_timeline(snapper, verbose); + do_cleanup_empty_pre_post(snapper, verbose); + break; + } + } + + + void + run_cleanup(ProxySnapper* snapper, CleanupAlgorithm cleanup_algorithm, bool verbose, + const FreeSpaceCondition& free_space_condition) + { + std::function condition = [snapper, &free_space_condition]() { + return free_space_condition.is_satisfied(snapper); + }; + + switch (cleanup_algorithm) + { + case CleanupAlgorithm::NUMBER: + do_cleanup_number(snapper, verbose, condition); + break; + + case CleanupAlgorithm::TIMELINE: + do_cleanup_timeline(snapper, verbose, condition); + break; + + case CleanupAlgorithm::EMPTY_PRE_POST: + do_cleanup_empty_pre_post(snapper, verbose, condition); + break; + + case CleanupAlgorithm::ALL: + do_cleanup_number(snapper, verbose, condition); + do_cleanup_timeline(snapper, verbose, condition); + do_cleanup_empty_pre_post(snapper, verbose, condition); + break; + } + } + + + void + run_cleanup(const vector& snappers, CleanupAlgorithm cleanup_algorithm, bool verbose) + { + for (ProxySnapper* snapper : snappers) + { +#ifdef VERBOSE_LOGGING + cout << "config " << snapper->configName() << '\n'; +#endif + + run_cleanup(snapper, cleanup_algorithm, verbose); + } + } + + + void + run_cleanup(const vector& snappers, CleanupAlgorithm cleanup_algorithm, bool verbose, + const FreeSpaceCondition& free_space_condition) + { + for (ProxySnapper* snapper : snappers) + { +#ifdef VERBOSE_LOGGING + cout << "config " << snapper->configName() << '\n'; +#endif + + if (free_space_condition.is_satisfied()) + break; + + try + { + run_cleanup(snapper, cleanup_algorithm, verbose, free_space_condition); + } + catch (...) + { +#ifdef VERBOSE_LOGGING + cout << "failed for " << snapper->configName() << '\n'; +#endif + } + } + } + + } + + void - command_cleanup(GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers*, ProxySnapper* snapper) + command_cleanup(GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper*) { - ParsedOpts opts = get_opts.parse("cleanup", GetOpts::no_options); - if (get_opts.num_args() != 1) + const vector