Skip to content

Commit

Permalink
Work on delta.
Browse files Browse the repository at this point in the history
  • Loading branch information
weetmuts committed Mar 14, 2024
1 parent 10088e4 commit 7e3e966
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 1 deletion.
5 changes: 4 additions & 1 deletion src/beak.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright (C) 2016-2020 Fredrik Öhrström
Copyright (C) 2016-2024 Fredrik Öhrström
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -68,6 +68,7 @@ struct Beak
virtual RC prune(Settings *settings, Monitor *monitor) = 0;

virtual RC diff(Settings *settings, Monitor *monitor) = 0;
virtual RC delta(Settings *settings, Monitor *monitor) = 0;
virtual RC stat(Settings *settings, Monitor *monitor) = 0;
virtual RC fsck(Settings *settings, Monitor *monitor) = 0;
virtual RC configure(Settings *settings) = 0;
Expand Down Expand Up @@ -124,6 +125,7 @@ enum ArgumentType
#define LIST_OF_COMMANDS \
X(bmount,CommandType::SECONDARY,"Mount your file system as a backup.",ArgOrigin,ArgDir) \
X(config,CommandType::PRIMARY,"Configure backup rules.",ArgNone,ArgNone) \
X(delta,CommandType::PRIMARY,"Create new delta files in to storage for beak files not in from storage.",ArgStorage,ArgStorage) \
X(diff,CommandType::PRIMARY,"Show differences between backups and/or origins.",ArgORS,ArgORS) \
X(fsck,CommandType::PRIMARY,"Check the integrity of your backup.",ArgStorage,ArgNone) \
X(genautocomplete,CommandType::SECONDARY,"Output bash completion script for beak.",ArgFileOrNone,ArgNone) \
Expand Down Expand Up @@ -203,6 +205,7 @@ LIST_OF_OPTIONS
#define LIST_OF_OPTIONS_PER_COMMAND \
X(bmount_cmd, (16, contentsplit_option, depth_option, foreground_option, fusedebug_option, splitsize_option, tarheader_option, targetsize_option, triggersize_option, triggerglob_option, exclude_option, include_option, progress_option, padding_option, relaxtimechecks_option, tarheader_option, yesorigin_option) ) \
X(config_cmd, (0) ) \
X(delta_cmd, (0) ) \
X(diff_cmd, (1, depth_option) ) \
X(stat_cmd, (1, depth_option) ) \
X(fsck_cmd, (1, deepcheck_option) ) \
Expand Down
165 changes: 165 additions & 0 deletions src/beak_delta.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*
Copyright (C) 2024 Fredrik Öhrström
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "beak.h"
#include "beak_implementation.h"
#include "backup.h"
#include "log.h"
#include "origintool.h"
#include "storagetool.h"

static ComponentId DELTA = registerLogComponent("delta");

RC BeakImplementation::delta(Settings *settings, Monitor *monitor)
{
RC rc = RC::OK;

// From is usually the remote that has fewer beak files.
assert(settings->from.type == ArgStorage);
// To is the local storage with more beak files.
// We want to write delta files to the local storage that can be sent
// to the remote instead of the full beak files.
// The delta files can be used to recreate the new beak files from existing beak files
// already on the remote.
assert(settings->to.type == ArgStorage);

auto progress = monitor->newProgressStatistics(buildJobName("delta", settings));

FileSystem *remote_fs;
Path *remote_root;
auto remote = accessSingleStorageBackup_(&settings->from, "", monitor, &remote_fs, &remote_root);

FileSystem *local_fs;
Path *local_root;
auto local = accessSingleStorageBackup_(&settings->to, "", monitor, &local_fs, &local_root);

set<Path*> remote_beak_files;
vector<pair<Path*,FileStat>> existing_remote_beak_files;
set<Path*> set_of_existing_beak_files;
size_t total_files_size = 0;

for (auto& i : remote->historyOldToNew())
{
Path *p = Path::lookup(i.filename);
remote_beak_files.insert(p);
for (auto& t : *(i.tarfiles()))
{
required_remote_beak_files.insert(t);
}
}

vector<Path*> superfluous_files;
size_t superfluous_files_size = 0;
//vector<Path*> lost_files;
//size_t lost_files_size = 0;
vector<Path*> broken_points_in_time;

backup_fs->listFilesBelow(root, &existing_beak_files, SortOrder::Unspecified);
for (auto& p : existing_beak_files)
{
debug(DELTA, "existing: %s\n", p.first->c_str());
set_of_existing_beak_files.insert(p.first);
total_files_size += p.second.st_size;
if (required_beak_files.count(p.first) == 0)
{
verbose(DELTA, "superfluous: %s\n", p.first->c_str());
superfluous_files.push_back(p.first);
superfluous_files_size += p.second.st_size;
}
}

bool lost_file = false;
for (auto p : required_beak_files)
{
if (set_of_existing_beak_files.count(p) == 0)
{
verbose(DELTA, "lost: %s\n", p->c_str());
lost_file = true;
//lost_files.push_back(p);
//lost_files_size += p.second.st_size;
}
}

if (lost_file) {
// Ouch, a backup file was lost. Are there any ok points in time?
for (auto& i : restore->historyOldToNew())
{
Path *p = Path::lookup(i.filename);
bool missing = 0 == set_of_existing_beak_files.count(p);
if (!missing)
{
for (auto& t : *(i.tarfiles()))
{
if (set_of_existing_beak_files.count(t) == 0) {
missing = true;
break;
}
}
}
if (missing) {
info(DELTA, "Broken %s\n", i.datetime.c_str());
broken_points_in_time.push_back(Path::lookup(i.filename));
} else {
info(DELTA, "OK %s\n", i.datetime.c_str());
}
}
} else {
string last_size = humanReadableTwoDecimals(restore->historyOldToNew().back().size);
string kept_size = humanReadableTwoDecimals(total_files_size);
UI::output("OK! Last backup %s, all backups %s (%d points in time).\n",
last_size.c_str(),
kept_size.c_str(),
restore->historyOldToNew().size());
}

int sn = superfluous_files.size();
if (sn > 0) {
string ss = humanReadableTwoDecimals(superfluous_files_size);
UI::output("Found %d superfluous file(s) with a total size of %s \n", sn, ss.c_str());
auto proceed = UINo;
if (UI::isatty()) {
proceed = UI::yesOrNo("Delete?");
}

if (proceed == UIYes)
{
storage_tool_->removeBackupFiles(settings->from.storage,
superfluous_files,
progress.get());
UI::output("Superflous files are now deleted.\n");
}
}
int bn = broken_points_in_time.size();
if (bn > 0) {
//string ss = humanReadableTwoDecimals(superfluous_files_size);
UI::output("Found %d broken points in time\n", bn);
auto proceed = UINo;
if (UI::isatty()) {
proceed = UI::yesOrNo("Delete?");
}

if (proceed == UIYes)
{
storage_tool_->removeBackupFiles(settings->from.storage,
broken_points_in_time,
progress.get());
UI::output("Broken points in time are now deleted. Run fsck again.\n");
}
}

return rc;
}
1 change: 1 addition & 0 deletions src/beak_implementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ struct BeakImplementation : Beak
void printVersion(bool verbose);

RC configure(Settings *settings);
RC delta(Settings *settings, Monitor *monitor);
RC diff(Settings *settings, Monitor *monitor);
RC stat(Settings *settings, Monitor *monitor);
RC fsck(Settings *settings, Monitor *monitor);
Expand Down

0 comments on commit 7e3e966

Please sign in to comment.