mirror of https://github.com/trapexit/mergerfs.git
5 changed files with 496 additions and 0 deletions
-
8src/policies.hpp
-
236src/policy_eplup.cpp
-
70src/policy_eplup.hpp
-
112src/policy_lup.cpp
-
70src/policy_lup.hpp
@ -0,0 +1,236 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2025, François-Xavier Payet <fx@payet.io> |
||||
|
|
||||
|
Permission to use, copy, modify, and/or distribute this software for any |
||||
|
purpose with or without fee is hereby granted, provided that the above |
||||
|
copyright notice and this permission notice appear in all copies. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "policy_eplup.hpp"
|
||||
|
|
||||
|
#include "errno.hpp"
|
||||
|
#include "fs_exists.hpp"
|
||||
|
#include "fs_info.hpp"
|
||||
|
#include "fs_path.hpp"
|
||||
|
#include "fs_statvfs_cache.hpp"
|
||||
|
#include "policy.hpp"
|
||||
|
#include "policy_error.hpp"
|
||||
|
#include "rwlock.hpp"
|
||||
|
|
||||
|
#include <limits>
|
||||
|
#include <string>
|
||||
|
|
||||
|
using std::string; |
||||
|
|
||||
|
static int |
||||
|
_create(const Branches::Ptr &branches_, |
||||
|
const fs::path &fusepath_, |
||||
|
std::vector<Branch *> &paths_) |
||||
|
{ |
||||
|
int rv; |
||||
|
int error; |
||||
|
fs::info_t info; |
||||
|
Branch *obranch; |
||||
|
|
||||
|
obranch = nullptr; |
||||
|
error = ENOENT; |
||||
|
|
||||
|
uint64_t best_used = 0; |
||||
|
uint64_t best_total = 1; /* avoid div-by-zero */ |
||||
|
|
||||
|
for (auto &branch : *branches_) |
||||
|
{ |
||||
|
if (branch.ro_or_nc()) |
||||
|
error_and_continue(error, EROFS); |
||||
|
if (!fs::exists(branch.path, fusepath_)) |
||||
|
error_and_continue(error, ENOENT); |
||||
|
rv = fs::info(branch.path, &info); |
||||
|
if (rv < 0) |
||||
|
error_and_continue(error, ENOENT); |
||||
|
if (info.readonly) |
||||
|
error_and_continue(error, EROFS); |
||||
|
if (info.spaceavail < branch.minfreespace()) |
||||
|
error_and_continue(error, ENOSPC); |
||||
|
|
||||
|
uint64_t used = info.spaceused; |
||||
|
uint64_t total = info.spaceused + info.spaceavail; |
||||
|
if (total == 0) |
||||
|
{ |
||||
|
used = 0; |
||||
|
total = 1; |
||||
|
} |
||||
|
|
||||
|
if (obranch == nullptr) |
||||
|
{ |
||||
|
best_used = used; |
||||
|
best_total = total; |
||||
|
obranch = &branch; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
unsigned __int128 lhs = (unsigned __int128)used * (unsigned __int128)best_total; |
||||
|
unsigned __int128 rhs = (unsigned __int128)best_used * (unsigned __int128)total; |
||||
|
if (lhs >= rhs) |
||||
|
continue; |
||||
|
|
||||
|
best_used = used; |
||||
|
best_total = total; |
||||
|
obranch = &branch; |
||||
|
} |
||||
|
|
||||
|
if (obranch == nullptr) |
||||
|
return -error; |
||||
|
|
||||
|
paths_.emplace_back(obranch); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static int |
||||
|
_action(const Branches::Ptr &branches_, |
||||
|
const fs::path &fusepath_, |
||||
|
std::vector<Branch *> &paths_) |
||||
|
{ |
||||
|
int rv; |
||||
|
int error; |
||||
|
fs::info_t info; |
||||
|
Branch *obranch; |
||||
|
|
||||
|
obranch = nullptr; |
||||
|
error = ENOENT; |
||||
|
|
||||
|
uint64_t best_used = 0; |
||||
|
uint64_t best_total = 1; |
||||
|
|
||||
|
for (auto &branch : *branches_) |
||||
|
{ |
||||
|
if (branch.ro()) |
||||
|
error_and_continue(error, EROFS); |
||||
|
if (!fs::exists(branch.path, fusepath_)) |
||||
|
error_and_continue(error, ENOENT); |
||||
|
rv = fs::info(branch.path, &info); |
||||
|
if (rv < 0) |
||||
|
error_and_continue(error, ENOENT); |
||||
|
if (info.readonly) |
||||
|
error_and_continue(error, EROFS); |
||||
|
|
||||
|
uint64_t used = info.spaceused; |
||||
|
uint64_t total = info.spaceused + info.spaceavail; |
||||
|
if (total == 0) |
||||
|
{ |
||||
|
used = 0; |
||||
|
total = 1; |
||||
|
} |
||||
|
|
||||
|
if (obranch == nullptr) |
||||
|
{ |
||||
|
best_used = used; |
||||
|
best_total = total; |
||||
|
obranch = &branch; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
unsigned __int128 lhs = (unsigned __int128)used * (unsigned __int128)best_total; |
||||
|
unsigned __int128 rhs = (unsigned __int128)best_used * (unsigned __int128)total; |
||||
|
if (lhs >= rhs) |
||||
|
continue; |
||||
|
|
||||
|
best_used = used; |
||||
|
best_total = total; |
||||
|
obranch = &branch; |
||||
|
} |
||||
|
|
||||
|
if (obranch == nullptr) |
||||
|
return -error; |
||||
|
|
||||
|
paths_.emplace_back(obranch); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static int |
||||
|
_search(const Branches::Ptr &branches_, |
||||
|
const fs::path &fusepath_, |
||||
|
std::vector<Branch *> &paths_) |
||||
|
{ |
||||
|
int rv; |
||||
|
uint64_t used; |
||||
|
uint64_t avail; |
||||
|
uint64_t best_used = 0; |
||||
|
uint64_t best_total = 1; |
||||
|
Branch *obranch; |
||||
|
|
||||
|
obranch = nullptr; |
||||
|
|
||||
|
for (auto &branch : *branches_) |
||||
|
{ |
||||
|
if (!fs::exists(branch.path, fusepath_)) |
||||
|
continue; |
||||
|
rv = fs::statvfs_cache_spaceused(branch.path, &used); |
||||
|
if (rv < 0) |
||||
|
continue; |
||||
|
rv = fs::statvfs_cache_spaceavail(branch.path, &avail); |
||||
|
if (rv < 0) |
||||
|
continue; |
||||
|
|
||||
|
uint64_t total = used + avail; |
||||
|
if (total == 0) |
||||
|
{ |
||||
|
used = 0; |
||||
|
total = 1; |
||||
|
} |
||||
|
|
||||
|
if (obranch == nullptr) |
||||
|
{ |
||||
|
best_used = used; |
||||
|
best_total = total; |
||||
|
obranch = &branch; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
unsigned __int128 lhs = (unsigned __int128)used * (unsigned __int128)best_total; |
||||
|
unsigned __int128 rhs = (unsigned __int128)best_used * (unsigned __int128)total; |
||||
|
if (lhs >= rhs) |
||||
|
continue; |
||||
|
|
||||
|
best_used = used; |
||||
|
best_total = total; |
||||
|
obranch = &branch; |
||||
|
} |
||||
|
|
||||
|
if (obranch == nullptr) |
||||
|
return -ENOENT; |
||||
|
|
||||
|
paths_.emplace_back(obranch); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int Policy::EPLUP::Action::operator()(const Branches::Ptr &branches_, |
||||
|
const fs::path &fusepath_, |
||||
|
std::vector<Branch *> &paths_) const |
||||
|
{ |
||||
|
return ::_action(branches_, fusepath_, paths_); |
||||
|
} |
||||
|
|
||||
|
int Policy::EPLUP::Create::operator()(const Branches::Ptr &branches_, |
||||
|
const fs::path &fusepath_, |
||||
|
std::vector<Branch *> &paths_) const |
||||
|
{ |
||||
|
return ::_create(branches_, fusepath_, paths_); |
||||
|
} |
||||
|
|
||||
|
int Policy::EPLUP::Search::operator()(const Branches::Ptr &branches_, |
||||
|
const fs::path &fusepath_, |
||||
|
std::vector<Branch *> &paths_) const |
||||
|
{ |
||||
|
return ::_search(branches_, fusepath_, paths_); |
||||
|
} |
||||
@ -0,0 +1,70 @@ |
|||||
|
/*
|
||||
|
ISC License |
||||
|
|
||||
|
Copyright (c) 2025, François-Xavier Payet <fx@payet.io> |
||||
|
|
||||
|
Permission to use, copy, modify, and/or distribute this software for any |
||||
|
purpose with or without fee is hereby granted, provided that the above |
||||
|
copyright notice and this permission notice appear in all copies. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#pragma once
|
||||
|
|
||||
|
#include "policy.hpp"
|
||||
|
|
||||
|
namespace Policy |
||||
|
{ |
||||
|
namespace EPLUP |
||||
|
{ |
||||
|
class Action final : public Policy::ActionImpl |
||||
|
{ |
||||
|
public: |
||||
|
Action() |
||||
|
: Policy::ActionImpl("eplup") |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public: |
||||
|
int operator()(const Branches::Ptr &, |
||||
|
const fs::path &, |
||||
|
std::vector<Branch *> &) const final; |
||||
|
}; |
||||
|
|
||||
|
class Create final : public Policy::CreateImpl |
||||
|
{ |
||||
|
public: |
||||
|
Create() |
||||
|
: Policy::CreateImpl("eplup") |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public: |
||||
|
int operator()(const Branches::Ptr &, |
||||
|
const fs::path &, |
||||
|
std::vector<Branch *> &) const final; |
||||
|
bool path_preserving(void) const final { return true; } |
||||
|
}; |
||||
|
|
||||
|
class Search final : public Policy::SearchImpl |
||||
|
{ |
||||
|
public: |
||||
|
Search() |
||||
|
: Policy::SearchImpl("eplup") |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public: |
||||
|
int operator()(const Branches::Ptr &, |
||||
|
const fs::path &, |
||||
|
std::vector<Branch *> &) const final; |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,112 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2025, François-Xavier Payet <fx@payet.io> |
||||
|
|
||||
|
Permission to use, copy, modify, and/or distribute this software for any |
||||
|
purpose with or without fee is hereby granted, provided that the above |
||||
|
copyright notice and this permission notice appear in all copies. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "policy_lup.hpp"
|
||||
|
|
||||
|
#include "errno.hpp"
|
||||
|
#include "fs_info.hpp"
|
||||
|
#include "fs_path.hpp"
|
||||
|
#include "fs_statvfs_cache.hpp"
|
||||
|
#include "policy.hpp"
|
||||
|
#include "policy_error.hpp"
|
||||
|
#include "rwlock.hpp"
|
||||
|
|
||||
|
#include <limits>
|
||||
|
#include <string>
|
||||
|
|
||||
|
using std::string; |
||||
|
|
||||
|
static int |
||||
|
_create(const Branches::Ptr &branches_, |
||||
|
std::vector<Branch *> &paths_) |
||||
|
{ |
||||
|
int rv; |
||||
|
int error; |
||||
|
fs::info_t info; |
||||
|
Branch *obranch; |
||||
|
|
||||
|
obranch = nullptr; |
||||
|
error = ENOENT; |
||||
|
|
||||
|
uint64_t best_used = 0; |
||||
|
uint64_t best_total = 1; |
||||
|
|
||||
|
for (auto &branch : *branches_) |
||||
|
{ |
||||
|
if (branch.ro_or_nc()) |
||||
|
error_and_continue(error, EROFS); |
||||
|
rv = fs::info(branch.path, &info); |
||||
|
if (rv < 0) |
||||
|
error_and_continue(error, ENOENT); |
||||
|
if (info.readonly) |
||||
|
error_and_continue(error, EROFS); |
||||
|
if (info.spaceavail < branch.minfreespace()) |
||||
|
error_and_continue(error, ENOSPC); |
||||
|
|
||||
|
uint64_t used = info.spaceused; |
||||
|
uint64_t total = info.spaceused + info.spaceavail; |
||||
|
if (total == 0) |
||||
|
{ |
||||
|
used = 0; |
||||
|
total = 1; |
||||
|
} |
||||
|
|
||||
|
if (obranch == nullptr) |
||||
|
{ |
||||
|
best_used = used; |
||||
|
best_total = total; |
||||
|
obranch = &branch; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
unsigned __int128 lhs = (unsigned __int128)used * (unsigned __int128)best_total; |
||||
|
unsigned __int128 rhs = (unsigned __int128)best_used * (unsigned __int128)total; |
||||
|
if (lhs >= rhs) |
||||
|
continue; |
||||
|
|
||||
|
best_used = used; |
||||
|
best_total = total; |
||||
|
obranch = &branch; |
||||
|
} |
||||
|
|
||||
|
if (obranch == nullptr) |
||||
|
return -error; |
||||
|
|
||||
|
paths_.push_back(obranch); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int Policy::LUP::Action::operator()(const Branches::Ptr &branches_, |
||||
|
const fs::path &fusepath_, |
||||
|
std::vector<Branch *> &paths_) const |
||||
|
{ |
||||
|
return Policies::Action::eplup(branches_, fusepath_, paths_); |
||||
|
} |
||||
|
|
||||
|
int Policy::LUP::Create::operator()(const Branches::Ptr &branches_, |
||||
|
const fs::path &fusepath_, |
||||
|
std::vector<Branch *> &paths_) const |
||||
|
{ |
||||
|
return ::_create(branches_, paths_); |
||||
|
} |
||||
|
|
||||
|
int Policy::LUP::Search::operator()(const Branches::Ptr &branches_, |
||||
|
const fs::path &fusepath_, |
||||
|
std::vector<Branch *> &paths_) const |
||||
|
{ |
||||
|
return Policies::Search::eplup(branches_, fusepath_, paths_); |
||||
|
} |
||||
@ -0,0 +1,70 @@ |
|||||
|
/*
|
||||
|
ISC License |
||||
|
|
||||
|
Copyright (c) 2025, François-Xavier Payet <fx@payet.io> |
||||
|
|
||||
|
Permission to use, copy, modify, and/or distribute this software for any |
||||
|
purpose with or without fee is hereby granted, provided that the above |
||||
|
copyright notice and this permission notice appear in all copies. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#pragma once
|
||||
|
|
||||
|
#include "policy.hpp"
|
||||
|
|
||||
|
namespace Policy |
||||
|
{ |
||||
|
namespace LUP |
||||
|
{ |
||||
|
class Action final : public Policy::ActionImpl |
||||
|
{ |
||||
|
public: |
||||
|
Action() |
||||
|
: Policy::ActionImpl("lup") |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public: |
||||
|
int operator()(const Branches::Ptr &, |
||||
|
const fs::path &, |
||||
|
std::vector<Branch *> &) const final; |
||||
|
}; |
||||
|
|
||||
|
class Create final : public Policy::CreateImpl |
||||
|
{ |
||||
|
public: |
||||
|
Create() |
||||
|
: Policy::CreateImpl("lup") |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public: |
||||
|
int operator()(const Branches::Ptr &, |
||||
|
const fs::path &, |
||||
|
std::vector<Branch *> &) const final; |
||||
|
bool path_preserving() const final { return false; } |
||||
|
}; |
||||
|
|
||||
|
class Search final : public Policy::SearchImpl |
||||
|
{ |
||||
|
public: |
||||
|
Search() |
||||
|
: Policy::SearchImpl("lup") |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public: |
||||
|
int operator()(const Branches::Ptr &, |
||||
|
const fs::path &, |
||||
|
std::vector<Branch *> &) const final; |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue