From: Arvin Schnell Date: Mon, 29 Oct 2018 09:48:28 +0000 (+0100) Subject: - extended space aware cleanup algorithm (fate#325774) X-Git-Tag: v0.8.0~7^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4abffe2328029d4bd19f4326262ede1abb706e44;p=thirdparty%2Fsnapper.git - extended space aware cleanup algorithm (fate#325774) --- diff --git a/VERSION b/VERSION index 7486fdbc..a3df0a69 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.2 +0.8.0 diff --git a/client/cleanup.cc b/client/cleanup.cc index 1f630bd8..07f27d8f 100644 --- a/client/cleanup.cc +++ b/client/cleanup.cc @@ -31,6 +31,7 @@ #include "utils/Range.h" #include "utils/equal-date.h" +#include "utils/HumanString.h" #include "cleanup.h" @@ -46,6 +47,7 @@ struct Parameters time_t min_age; double space_limit; + double free_limit; template void read(const ProxyConfig& config, const char* name, Type& value) @@ -59,11 +61,12 @@ struct Parameters Parameters::Parameters(const ProxySnapper* snapper) - : min_age(1800), space_limit(0.5) + : min_age(1800), space_limit(0.5), free_limit(0.2) { ProxyConfig config = snapper->getConfig(); read(config, "SPACE_LIMIT", space_limit); + read(config, "FREE_LIMIT", free_limit); } @@ -71,7 +74,8 @@ ostream& operator<<(ostream& s, const Parameters& parameters) { return s << "min-age:" << parameters.min_age << endl - << "space-limit:" << parameters.space_limit; + << "space-limit:" << parameters.space_limit + << "free-limit:" << parameters.free_limit; } @@ -114,11 +118,20 @@ protected: void remove(const list& tmp); + // Should the cleanup with quota space be run? bool is_quota_aware() const; + + // Is the quota space condition satisfied? bool is_quota_satisfied() const; - void cleanup_quota_unaware(ProxySnapshots& snapshots); - void cleanup_quota_aware(ProxySnapshots& snapshots); + // Should the cleanup with free space be run? + bool is_free_aware() const; + + // Is the free space condition satisfied? + bool is_free_satisfied() const; + + void cleanup(ProxySnapshots& snapshots); + void cleanup(ProxySnapshots& snapshots, std::function condition); ProxySnapper* snapper; bool verbose; @@ -223,41 +236,80 @@ Cleaner::is_quota_aware() const { snapper->prepareQuota(); } - catch (const DBus::ErrorException& e) + catch (const QuotaException& e) { SN_CAUGHT(e); - if (strcmp(e.name(), "error.quota") == 0) - { - cerr << "quota not working (" << e.message() << ")" << endl; - return false; - } + cerr << "quota not working (" << e.what() << ")" << endl; + return false; + } + + return parameters.space_limit < 1.0; +} + + +bool +Cleaner::is_quota_satisfied() const +{ + QuotaData quota_data = snapper->queryQuotaData(); + + double fraction = (double)(quota_data.used) / (double)(quota_data.size); + + bool satisfied = fraction < parameters.space_limit; + +#ifdef VERBOSE_LOGGING + cout << byte_to_humanstring(quota_data.size, 2) << ", " + << byte_to_humanstring(quota_data.used, 2) << ", " + << fraction << ", " << satisfied << endl; +#endif + + return satisfied; +} + + +bool +Cleaner::is_free_aware() const +{ + if (parameters.is_degenerated()) + return false; - SN_RETHROW(e); + try + { + snapper->queryFreeSpaceData(); } - catch (const QuotaException& e) + catch (const FreeSpaceException& e) { SN_CAUGHT(e); - cerr << "quota not working (" << e.what() << ")" << endl; + cerr << "free space not working (" << e.what() << ")" << endl; return false; } - return true; + return parameters.free_limit > 0.0; } bool -Cleaner::is_quota_satisfied() const +Cleaner::is_free_satisfied() const { - QuotaData quota_data = snapper->queryQuotaData(); + FreeSpaceData free_space_data = snapper->queryFreeSpaceData(); + + double fraction = (double)(free_space_data.free) / (double)(free_space_data.size); - return quota_data.used < parameters.space_limit * quota_data.size; + bool satisfied = fraction > parameters.free_limit; + +#ifdef VERBOSE_LOGGING + cout << byte_to_humanstring(free_space_data.size, 2) << ", " + << byte_to_humanstring(free_space_data.free, 2) << ", " + << fraction << ", " << satisfied << endl; +#endif + + return satisfied; } void -Cleaner::cleanup_quota_unaware(ProxySnapshots& snapshots) +Cleaner::cleanup(ProxySnapshots& snapshots) { list candidates = calculate_candidates(snapshots, Range::MAX); @@ -268,14 +320,19 @@ Cleaner::cleanup_quota_unaware(ProxySnapshots& snapshots) void -Cleaner::cleanup_quota_aware(ProxySnapshots& snapshots) +Cleaner::cleanup(ProxySnapshots& snapshots, std::function condition) { - while (!is_quota_satisfied()) + while (!condition()) { list candidates = calculate_candidates(snapshots, Range::MIN); if (candidates.empty()) { - // not enough candidates to satisfy quota + // not enough candidates to satisfy the condition + +#ifdef VERBOSE_LOGGING + cout << "condition not satisfied" << endl; +#endif + return; } @@ -293,17 +350,27 @@ Cleaner::cleanup_quota_aware(ProxySnapshots& snapshots) if (!tmp.empty()) { remove(tmp); - // after removing snapshots is_quota_satisfied must be reevaluated + + // after removing snapshots the condition must be reevaluated break; } if (next(e) == candidates.end()) { - // not enough candidates to satisfy quota + // not enough candidates to satisfy the condition + +#ifdef VERBOSE_LOGGING + cout << "condition not satisfied" << endl; +#endif + return; } } } + +#ifdef VERBOSE_LOGGING + cout << "condition satisfied" << endl; +#endif } @@ -312,10 +379,41 @@ Cleaner::cleanup() { ProxySnapshots& snapshots = snapper->getSnapshots(); - cleanup_quota_unaware(snapshots); +#ifdef VERBOSE_LOGGING + cout << "cleanup without condition" << endl; +#endif + + cleanup(snapshots); if (is_quota_aware()) - cleanup_quota_aware(snapshots); + { +#ifdef VERBOSE_LOGGING + cout << "cleanup with quota condition" << endl; +#endif + + cleanup(snapshots, std::bind(&Cleaner::is_quota_satisfied, this)); + } + else + { +#ifdef VERBOSE_LOGGING + cout << "no cleanup with quota condition" << endl; +#endif + } + + if (is_free_aware()) + { +#ifdef VERBOSE_LOGGING + cout << "cleanup with free condition" << endl; +#endif + + cleanup(snapshots, std::bind(&Cleaner::is_free_satisfied, this)); + } + else + { +#ifdef VERBOSE_LOGGING + cout << "no cleanup with free condition" << endl; +#endif + } } diff --git a/client/snapper.cc b/client/snapper.cc index 31587c77..d809677d 100644 --- a/client/snapper.cc +++ b/client/snapper.cc @@ -1833,6 +1833,12 @@ main(int argc, char** argv) cerr << sformat(_("Quota error (%s)."), e.what()) << endl; exit(EXIT_FAILURE); } + catch (const FreeSpaceException& e) + { + SN_CAUGHT(e); + cerr << sformat(_("Free space error (%s)."), e.what()) << endl; + exit(EXIT_FAILURE); + } catch (const Exception& e) { SN_CAUGHT(e); diff --git a/data/default-config b/data/default-config index 16c11f9c..a1e1900a 100644 --- a/data/default-config +++ b/data/default-config @@ -13,6 +13,9 @@ QGROUP="" # fraction of the filesystems space the snapshots may use SPACE_LIMIT="0.5" +# fraction of the filesystems space that should be free +FREE_LIMIT="0.2" + # users and groups allowed to work with config ALLOW_USERS="" diff --git a/dists/debian/changelog b/dists/debian/changelog index 1dd9c9f4..ae49a126 100644 --- a/dists/debian/changelog +++ b/dists/debian/changelog @@ -1,3 +1,9 @@ +snapper (0.8.0) stable; urgency=low + + * Updated to version 0.8.0 + + -- Arvin Schnell Mon, 29 Oct 2018 09:02:13 +0100 + snapper (0.7.2) stable; urgency=low * Updated to version 0.7.2 diff --git a/doc/snapper-configs.xml.in b/doc/snapper-configs.xml.in index 3ee8293e..e81f101a 100644 --- a/doc/snapper-configs.xml.in +++ b/doc/snapper-configs.xml.in @@ -2,13 +2,13 @@ - 2014-05-20 + 2018-10-29 snapper-configs 5 - 2013-07-09 + 2018-10-29 @VERSION@ Filesystem Snapshot Management @@ -71,6 +71,17 @@ + + + + Limit for the fraction of the filesystem space that + should be free. + Only supported for btrfs. + Default value is "0.2". + New in version 0.8.0. + + + diff --git a/doc/snapper.xml.in b/doc/snapper.xml.in index 5be5074d..87942a07 100644 --- a/doc/snapper.xml.in +++ b/doc/snapper.xml.in @@ -2,13 +2,13 @@ - 2018-10-16 + 2018-10-29 snapper 8 - 2018-10-16 + 2018-10-29 @VERSION@ Filesystem Snapshot Management @@ -138,24 +138,32 @@ - The number and timeline cleanup algorithm can also try to keep the - space used by snapshots below a limit. For that quota must be setup, see - command setup-quota, and the LIMIT variables in the config file must - have ranges (min- and max-value). The algorithms will then make two - passes: + The number and timeline cleanup algorithms can also try to + keep the space used by snapshots below a limit and the free space of + the filesystem above a limit. For the first condition quota must be + setup, see command setup-quota. Additional the NUMBER_LIMIT and + TIMELINE_LIMIT variables in the config file must have ranges (min- and + max-value). The algorithms will then make two passes: + - Delete snapshots above the max-value independent of the used - space. + Delete snapshots above the max-value independent of + the snapshot and filesystem space. - Delete snapshots above the min-value until the limit for - the used space is reached. + Delete snapshots above the min-value until the limits for + the snapshot and filesystem are reached. - The limit for the used space can be configured via the SPACE_LIMIT - variable. Note: Only snapshots that have a cleanup algorithm set are - taken into account when calculating the used space. + + The limit for the used space can be configured via the + SPACE_LIMIT variable. Note: Only snapshots that have a cleanup + algorithm set are taken into account when calculating the space + used by snapshots. + + The limit for the free space can be configured via the + FREE_LIMIT variable. + diff --git a/package/snapper.changes b/package/snapper.changes index bb25f365..2b8ffcff 100644 --- a/package/snapper.changes +++ b/package/snapper.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Mon Oct 29 10:38:59 CET 2018 - aschnell@suse.com + +- extended space aware cleanup algorithm to ensure minimal + free space for btrfs (within known ranges) (fate#325774) +- version 0.8.0 + ------------------------------------------------------------------- Mon Oct 22 09:52:01 CEST 2018 - aschnell@suse.com