Skip to content

Commit

Permalink
Properly report lost files in prune command.
Browse files Browse the repository at this point in the history
  • Loading branch information
weetmuts committed Aug 23, 2023
1 parent c735afd commit 6934886
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 28 deletions.
2 changes: 1 addition & 1 deletion src/beak.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ LIST_OF_OPTIONS
X(store_cmd, (14, background_option, contentsplit_option, delta_option, depth_option, splitsize_option, targetsize_option, triggersize_option, triggerglob_option, exclude_option, include_option, padding_option, progress_option, relaxtimechecks_option, tarheader_option, yesorigin_option) ) \
X(stored_cmd, (14, background_option, contentsplit_option, delta_option, depth_option, splitsize_option, targetsize_option, triggersize_option, triggerglob_option, exclude_option, include_option, padding_option, progress_option, relaxtimechecks_option, tarheader_option, yesorigin_option) ) \
X(mount_cmd, (3, progress_option,foreground_option, fusedebug_option ) ) \
X(prune_cmd, (3, keep_option, now_option, yesprune_option) ) \
X(prune_cmd, (4, keep_option, now_option, dryrun_option, yesprune_option) ) \
X(pull_cmd, (2, background_option, progress_option) ) \
X(push_cmd, (2, background_option, delta_option, progress_option) ) \
X(pushd_cmd, (2, background_option, delta_option, progress_option) ) \
Expand Down
76 changes: 53 additions & 23 deletions src/beak_prune.cc
Original file line number Diff line number Diff line change
Expand Up @@ -76,42 +76,59 @@ RC BeakImplementation::prune(Settings *settings, Monitor *monitor)
// Perform the prune calculation
prune->prune(&keeps);

// List all existing beak storage files.
vector<pair<Path*,FileStat>> existing_beak_files;
backup_fs->listFilesBelow(root, &existing_beak_files, SortOrder::Unspecified);

set<Path*> set_of_existing_beak_files;
for (auto& p : existing_beak_files)
{
set_of_existing_beak_files.insert(p.first);
}

int num_kept_points_in_time = 0;

for (PointInTime& i : restore->historyOldToNew())
{
if (keeps[i.point()]) {
if (keeps[i.point()])
{
// We should keep this point in time, lets remember all the tars required.
num_kept_points_in_time++;
for (auto& t : *(i.tarfiles())) {
int num_lost_files = 0;

for (auto& t : *(i.tarfiles()))
{
if (set_of_existing_beak_files.count(t) == 0)
{
debug(PRUNE, "storage lost: %s\n", t->c_str());
i.addLostFile(t);
num_lost_files++;
}
required_beak_files.insert(t);
}
Path *p = Path::lookup(i.filename);
required_beak_files.insert(p);
}
}

vector<pair<Path*,FileStat>> existing_beak_files;
backup_fs->listFilesBelow(root, &existing_beak_files, SortOrder::Unspecified);
// Add the gz file to the required files.
Path *gz_index_file = Path::lookup(i.filename);
required_beak_files.insert(gz_index_file);

set<Path*> set_of_existing_beak_files;
for (auto& p : existing_beak_files)
{
set_of_existing_beak_files.insert(p.first);
if (num_lost_files > 0)
{
prune->pointHasLostFiles(i.point(), num_lost_files, 0);
}
}
}

vector<Path*> beak_files_to_delete;
size_t total_size_removed = 0;
size_t total_size_kept = 0;
int total_num_lost_files = 0;

int num_lost = 0;
// Check that all expected tars actually exist in the storage location.
for (auto p : required_beak_files)
{
if (set_of_existing_beak_files.count(p) == 0)
{
warning(PRUNE, "storage lost: %s\n", p->c_str());
num_lost++;
//debug(PRUNE, "storage lost: %s\n", p->c_str());
total_num_lost_files++;
}
}

Expand All @@ -137,6 +154,8 @@ RC BeakImplementation::prune(Settings *settings, Monitor *monitor)
}
}

prune->verbosePruneDecisions();

string removed_size = humanReadableTwoDecimals(total_size_removed);
string last_size = humanReadableTwoDecimals(restore->historyOldToNew().back().size);
string kept_size = humanReadableTwoDecimals(total_size_kept);
Expand All @@ -151,16 +170,27 @@ RC BeakImplementation::prune(Settings *settings, Monitor *monitor)
}
else
{
UI::output("Prune will delete %s (%d points in time) and keep %s (%d).\n",
removed_size.c_str(),
num_existing_points_in_time - num_kept_points_in_time,
kept_size.c_str(),
num_kept_points_in_time);
int points_to_delete = num_existing_points_in_time - num_kept_points_in_time;
if (total_size_removed > 0 && points_to_delete == 0)
{
UI::output("Prune will only delete %s of superfluous data (no more points in time will be removed) and keep %s (%d).\n",
removed_size.c_str(),
kept_size.c_str(),
num_kept_points_in_time);
}
else
{
UI::output("Prune will delete %s (%d points in time) and keep %s (%d).\n",
removed_size.c_str(),
num_existing_points_in_time - num_kept_points_in_time,
kept_size.c_str(),
num_kept_points_in_time);
}
}

if (num_lost > 0)
if (total_num_lost_files > 0)
{
warning(PRUNE, "Warning! Lost %d backup files!!\n", num_lost);
warning(PRUNE, "Warning! Lost %d backup files!!\n", total_num_lost_files);
}

if (settings->dryrun == false)
Expand Down
17 changes: 16 additions & 1 deletion src/diff.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include"fileinfo.h"
#include"log.h"

#include<algorithm>
#include<map>
#include<set>
#include<utility>
Expand Down Expand Up @@ -53,6 +54,16 @@ struct TypeSummary
if (f) files.push_back(f);
assert(suffix);
}

void getSortedSuffixes(vector<const char*> *suffix_list)
{
suffix_list->clear();
for (auto s : suffixes) suffix_list->insert(suffix_list->end(), s);
std::sort(suffix_list->begin(), suffix_list->end(),
[](const char *a, const char *b)->bool {
return strcmp(a, b) < 0;
});
}
};

class DirSummary
Expand Down Expand Up @@ -481,7 +492,11 @@ void DirSummary::print(Path *p, bool hide_content, bool all_added)
bool comma = false;
bool dotdotdot = false;
int count = 0;
for (auto s: st->suffixes) {
vector<const char*> suffix_list;
st->getSortedSuffixes(&suffix_list);

for (auto s: suffix_list)
{
if (++count > 10) {
dotdotdot = true;
break;
Expand Down
22 changes: 20 additions & 2 deletions src/prune.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ struct PruneImplementation : public Prune
public:
void addPointInTime(uint64_t p);
void prune(std::map<uint64_t,bool> *result);
void pointHasLostFiles(uint64_t point, int num_files, size_t size_files);
void verbosePruneDecisions();
uint64_t mostRecentWeeklyBackup();

PruneImplementation(uint64_t now, const Keep &keep) { now_ = now; keep_ = keep; }
Expand All @@ -40,6 +42,8 @@ struct PruneImplementation : public Prune
Keep keep_;
uint64_t prev_ {};
map<uint64_t,bool> points_;
map<uint64_t,int> num_lost_files_;
map<uint64_t,size_t> size_lost_files_;
uint64_t latest_;
set<uint64_t> all_;
map<uint64_t,uint64_t> daily_max_;
Expand Down Expand Up @@ -128,6 +132,12 @@ bool PruneImplementation::isMonthlyMax(uint64_t p)
return false;
}

void PruneImplementation::pointHasLostFiles(uint64_t point, int num_files, size_t size_lost_files)
{
num_lost_files_[point] = num_files;
size_lost_files_[point] = size_lost_files;
}

void PruneImplementation::addPointInTime(uint64_t p)
{
assert(p <= now_);
Expand Down Expand Up @@ -184,7 +194,11 @@ void PruneImplementation::prune(std::map<uint64_t,bool> *result)
for (auto& e : daily_max_) { points_[e.second] = true; }
for (auto& e : weekly_max_) { points_[e.second] = true; }
for (auto& e : monthly_max_) { points_[e.second] = true; }
*result = points_;
}

void PruneImplementation::verbosePruneDecisions()
{
// Print the pruning decisions...
verbose(PRUNE, "Action Date Time Daynr Weeknr Monthnr\n");
for (auto& e : points_)
Expand All @@ -210,10 +224,14 @@ void PruneImplementation::prune(std::map<uint64_t,bool> *result)
if (isDailyMax(p)) verbose(PRUNE, " DAY");
if (isWeeklyMax(p)) verbose(PRUNE, " WEEK");
if (isMonthlyMax(p)) verbose(PRUNE, " MONTH");

if (num_lost_files_.count(p) > 0)
{
int n = num_lost_files_[p];
verbose(PRUNE, " ! WARNING ! LOST %d files", n);
}
verbose(PRUNE, " \n");
}
string nows = timeToString(now_);
verbose(PRUNE, "now %s\n", nows.c_str());

*result = points_;
}
2 changes: 2 additions & 0 deletions src/prune.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ struct Prune
{
virtual void addPointInTime(uint64_t p) = 0;
virtual void prune(std::map<uint64_t,bool> *result) = 0;
virtual void pointHasLostFiles(uint64_t point, int num_files, size_t size_files) = 0;
virtual void verbosePruneDecisions() = 0;
virtual uint64_t mostRecentWeeklyBackup() = 0;

virtual ~Prune() = default;
Expand Down
7 changes: 6 additions & 1 deletion src/restore.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,15 @@ struct PointInTime {
bool hasGzFiles() { return gz_files_.size() != 0; }
void addGzFile(Path *parent, Path *gzfile)
{
//fprintf(stderr, "GURKA Add gz file %s to dir %s\n", gzfile->c_str(), parent->c_str());
gz_files_[parent] = gzfile;
}
void addLostFile(Path *f)
{
lost_files_.insert(f);
}
Path *getGzFile(Path *dir) { if (gz_files_.count(dir) == 1) { return gz_files_[dir]; } else { return NULL; } }
std::vector<Path*> *tarfiles() { return &tars_; }
std::set<Path*> *lostFiles() { return &lost_files_; }

const struct timespec *ts() { return &ts_; }
uint64_t point() { return point_; }
Expand All @@ -143,6 +147,7 @@ struct PointInTime {
std::map<Path*,RestoreEntry,depthFirstSortPath> entries_;
std::map<Path*,Path*> gz_files_;
std::set<Path*> loaded_gz_files_;
std::set<Path*> lost_files_;
};

struct Restore
Expand Down

0 comments on commit 6934886

Please sign in to comment.