mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-26 19:01:56 -04:00
branches: add per branch minfreespace w/ original value as default
example: /mnt/disk0=RW,1G:/mnt/disk1=RW,2G
This commit is contained in:
parent
98c49b8001
commit
fc3453932a
68 changed files with 3005 additions and 813 deletions
482
src/branch.cpp
482
src/branch.cpp
|
|
@ -18,8 +18,11 @@
|
|||
|
||||
#include "branch.hpp"
|
||||
#include "ef.hpp"
|
||||
#include "from_string.hpp"
|
||||
#include "fs_glob.hpp"
|
||||
#include "fs_realpathize.hpp"
|
||||
#include "nonstd/optional.hpp"
|
||||
#include "num.hpp"
|
||||
#include "str.hpp"
|
||||
|
||||
#include <string>
|
||||
|
|
@ -29,239 +32,381 @@
|
|||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using nonstd::optional;
|
||||
|
||||
|
||||
Branch::Branch(const uint64_t &default_minfreespace_)
|
||||
: _default_minfreespace(&default_minfreespace_)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
Branch::from_string(const std::string &str_)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
std::string
|
||||
Branch::to_string(void) const
|
||||
{
|
||||
std::string rv;
|
||||
|
||||
rv = path;
|
||||
rv += '=';
|
||||
switch(mode)
|
||||
{
|
||||
default:
|
||||
case Branch::Mode::RW:
|
||||
rv += "RW";
|
||||
break;
|
||||
case Branch::Mode::RO:
|
||||
rv += "RO";
|
||||
break;
|
||||
case Branch::Mode::NC:
|
||||
rv += "NC";
|
||||
break;
|
||||
}
|
||||
|
||||
if(_minfreespace.has_value())
|
||||
{
|
||||
rv += ',';
|
||||
rv += num::humanize(_minfreespace.value());
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
Branch::set_minfreespace(const uint64_t minfreespace_)
|
||||
{
|
||||
_minfreespace = minfreespace_;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Branch::minfreespace(void) const
|
||||
{
|
||||
if(_minfreespace.has_value())
|
||||
return _minfreespace.value();
|
||||
return *_default_minfreespace;
|
||||
}
|
||||
|
||||
bool
|
||||
Branch::ro(void) const
|
||||
{
|
||||
return (mode == Branch::RO);
|
||||
return (mode == Branch::Mode::RO);
|
||||
}
|
||||
|
||||
bool
|
||||
Branch::nc(void) const
|
||||
{
|
||||
return (mode == Branch::NC);
|
||||
return (mode == Branch::Mode::NC);
|
||||
}
|
||||
|
||||
bool
|
||||
Branch::ro_or_nc(void) const
|
||||
{
|
||||
return ((mode == Branch::RO) ||
|
||||
(mode == Branch::NC));
|
||||
return ((mode == Branch::Mode::RO) ||
|
||||
(mode == Branch::Mode::NC));
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
split(const std::string &s_,
|
||||
std::string *instr_,
|
||||
std::string *values_)
|
||||
namespace l
|
||||
{
|
||||
uint64_t offset;
|
||||
static
|
||||
void
|
||||
split(const std::string &s_,
|
||||
std::string *instr_,
|
||||
std::string *values_)
|
||||
{
|
||||
uint64_t offset;
|
||||
|
||||
offset = s_.find_first_of('/');
|
||||
*instr_ = s_.substr(0,offset);
|
||||
if(offset != std::string::npos)
|
||||
*values_ = s_.substr(offset);
|
||||
offset = s_.find_first_of('/');
|
||||
*instr_ = s_.substr(0,offset);
|
||||
if(offset != std::string::npos)
|
||||
*values_ = s_.substr(offset);
|
||||
}
|
||||
}
|
||||
|
||||
Branches::Branches()
|
||||
Branches::Branches(const uint64_t &default_minfreespace_)
|
||||
: default_minfreespace(default_minfreespace_)
|
||||
{
|
||||
pthread_rwlock_init(&lock,NULL);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
parse(const string &str_,
|
||||
Branches &branches_)
|
||||
namespace l
|
||||
{
|
||||
string str;
|
||||
Branch branch;
|
||||
vector<string> globbed;
|
||||
static
|
||||
int
|
||||
parse_mode(const string &str_,
|
||||
Branch::Mode *mode_)
|
||||
{
|
||||
if(str_ == "RW")
|
||||
*mode_ = Branch::Mode::RW;
|
||||
ef(str_ == "RO")
|
||||
*mode_ = Branch::Mode::RO;
|
||||
ef(str_ == "NC")
|
||||
*mode_ = Branch::Mode::NC;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
str = str_;
|
||||
branch.mode = Branch::INVALID;
|
||||
if(str::endswith(str,"=RO"))
|
||||
branch.mode = Branch::RO;
|
||||
ef(str::endswith(str,"=RW"))
|
||||
branch.mode = Branch::RW;
|
||||
ef(str::endswith(str,"=NC"))
|
||||
branch.mode = Branch::NC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(branch.mode != Branch::INVALID)
|
||||
str.resize(str.size() - 3);
|
||||
else
|
||||
branch.mode = Branch::RW;
|
||||
static
|
||||
int
|
||||
parse_minfreespace(const string &str_,
|
||||
optional<uint64_t> *minfreespace_)
|
||||
{
|
||||
int rv;
|
||||
uint64_t uint64;
|
||||
|
||||
fs::glob(str,&globbed);
|
||||
fs::realpathize(&globbed);
|
||||
for(size_t i = 0; i < globbed.size(); i++)
|
||||
{
|
||||
branch.path = globbed[i];
|
||||
branches_.push_back(branch);
|
||||
}
|
||||
}
|
||||
rv = str::from(str_,&uint64);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
|
||||
static
|
||||
void
|
||||
set(Branches &branches_,
|
||||
const std::string &str_)
|
||||
{
|
||||
vector<string> paths;
|
||||
*minfreespace_ = uint64;
|
||||
|
||||
branches_.clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
str::split(str_,':',&paths);
|
||||
static
|
||||
int
|
||||
parse_branch(const string &str_,
|
||||
string *glob_,
|
||||
Branch::Mode *mode_,
|
||||
optional<uint64_t> *minfreespace_)
|
||||
{
|
||||
int rv;
|
||||
string options;
|
||||
vector<string> v;
|
||||
|
||||
for(size_t i = 0; i < paths.size(); i++)
|
||||
{
|
||||
Branches tmp;
|
||||
str::rsplit1(str_,'=',&v);
|
||||
switch(v.size())
|
||||
{
|
||||
case 1:
|
||||
*glob_ = v[0];
|
||||
*mode_ = Branch::Mode::RW;
|
||||
break;
|
||||
case 2:
|
||||
*glob_ = v[0];
|
||||
options = v[1];
|
||||
v.clear();
|
||||
str::split(options,',',&v);
|
||||
switch(v.size())
|
||||
{
|
||||
case 2:
|
||||
rv = l::parse_minfreespace(v[1],minfreespace_);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
case 1:
|
||||
rv = l::parse_mode(v[0],mode_);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
break;
|
||||
case 0:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
parse(paths[i],tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
branches_.insert(branches_.end(),
|
||||
tmp.begin(),
|
||||
tmp.end());
|
||||
}
|
||||
}
|
||||
static
|
||||
int
|
||||
parse(const string &str_,
|
||||
const uint64_t &default_minfreespace_,
|
||||
BranchVec *branches_)
|
||||
{
|
||||
int rv;
|
||||
string glob;
|
||||
vector<string> globbed;
|
||||
optional<uint64_t> minfreespace;
|
||||
Branch branch(default_minfreespace_);
|
||||
|
||||
static
|
||||
void
|
||||
add_begin(Branches &branches_,
|
||||
const std::string &str_)
|
||||
{
|
||||
vector<string> paths;
|
||||
rv = l::parse_branch(str_,&glob,&branch.mode,&minfreespace);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
|
||||
str::split(str_,':',&paths);
|
||||
if(minfreespace.has_value())
|
||||
branch.set_minfreespace(minfreespace.value());
|
||||
|
||||
for(size_t i = 0; i < paths.size(); i++)
|
||||
{
|
||||
Branches tmp;
|
||||
fs::glob(glob,&globbed);
|
||||
fs::realpathize(&globbed);
|
||||
for(size_t i = 0; i < globbed.size(); i++)
|
||||
{
|
||||
branch.path = globbed[i];
|
||||
branches_->push_back(branch);
|
||||
}
|
||||
|
||||
parse(paths[i],tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
branches_.insert(branches_.begin(),
|
||||
tmp.begin(),
|
||||
tmp.end());
|
||||
}
|
||||
}
|
||||
static
|
||||
int
|
||||
set(const std::string &str_,
|
||||
Branches *branches_)
|
||||
{
|
||||
int rv;
|
||||
vector<string> paths;
|
||||
BranchVec tmp_branchvec;
|
||||
|
||||
static
|
||||
void
|
||||
add_end(Branches &branches_,
|
||||
const std::string &str_)
|
||||
{
|
||||
vector<string> paths;
|
||||
str::split(str_,':',&paths);
|
||||
|
||||
str::split(str_,':',&paths);
|
||||
for(size_t i = 0; i < paths.size(); i++)
|
||||
{
|
||||
rv = l::parse(paths[i],branches_->default_minfreespace,&tmp_branchvec);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < paths.size(); i++)
|
||||
{
|
||||
Branches tmp;
|
||||
branches_->vec.clear();
|
||||
branches_->vec.insert(branches_->vec.end(),
|
||||
tmp_branchvec.begin(),
|
||||
tmp_branchvec.end());
|
||||
|
||||
parse(paths[i],tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
branches_.insert(branches_.end(),
|
||||
tmp.begin(),
|
||||
tmp.end());
|
||||
}
|
||||
}
|
||||
static
|
||||
int
|
||||
add_begin(const std::string &str_,
|
||||
Branches *branches_)
|
||||
{
|
||||
int rv;
|
||||
vector<string> paths;
|
||||
BranchVec tmp_branchvec;
|
||||
|
||||
static
|
||||
void
|
||||
erase_begin(Branches &branches_)
|
||||
{
|
||||
branches_.erase(branches_.begin());
|
||||
}
|
||||
str::split(str_,':',&paths);
|
||||
|
||||
static
|
||||
void
|
||||
erase_end(Branches &branches_)
|
||||
{
|
||||
branches_.pop_back();
|
||||
}
|
||||
for(size_t i = 0; i < paths.size(); i++)
|
||||
{
|
||||
rv = l::parse(paths[i],branches_->default_minfreespace,&tmp_branchvec);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
erase_fnmatch(Branches &branches_,
|
||||
const std::string &str_)
|
||||
{
|
||||
vector<string> patterns;
|
||||
branches_->vec.insert(branches_->vec.begin(),
|
||||
tmp_branchvec.begin(),
|
||||
tmp_branchvec.end());
|
||||
|
||||
str::split(str_,':',&patterns);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(Branches::iterator i = branches_.begin();
|
||||
i != branches_.end();)
|
||||
{
|
||||
int match = FNM_NOMATCH;
|
||||
static
|
||||
int
|
||||
add_end(const std::string &str_,
|
||||
Branches *branches_)
|
||||
{
|
||||
int rv;
|
||||
vector<string> paths;
|
||||
BranchVec tmp_branchvec;
|
||||
|
||||
for(vector<string>::const_iterator pi = patterns.begin();
|
||||
pi != patterns.end() && match != 0;
|
||||
++pi)
|
||||
{
|
||||
match = ::fnmatch(pi->c_str(),i->path.c_str(),0);
|
||||
}
|
||||
str::split(str_,':',&paths);
|
||||
|
||||
i = ((match == 0) ? branches_.erase(i) : (i+1));
|
||||
}
|
||||
for(size_t i = 0; i < paths.size(); i++)
|
||||
{
|
||||
rv = l::parse(paths[i],branches_->default_minfreespace,&tmp_branchvec);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
}
|
||||
|
||||
branches_->vec.insert(branches_->vec.end(),
|
||||
tmp_branchvec.begin(),
|
||||
tmp_branchvec.end());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
erase_begin(BranchVec *branches_)
|
||||
{
|
||||
branches_->erase(branches_->begin());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
erase_end(BranchVec *branches_)
|
||||
{
|
||||
branches_->pop_back();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
erase_fnmatch(const std::string &str_,
|
||||
Branches *branches_)
|
||||
{
|
||||
vector<string> patterns;
|
||||
|
||||
str::split(str_,':',&patterns);
|
||||
|
||||
for(BranchVec::iterator i = branches_->vec.begin();
|
||||
i != branches_->vec.end();)
|
||||
{
|
||||
int match = FNM_NOMATCH;
|
||||
|
||||
for(vector<string>::const_iterator pi = patterns.begin();
|
||||
pi != patterns.end() && match != 0;
|
||||
++pi)
|
||||
{
|
||||
match = ::fnmatch(pi->c_str(),i->path.c_str(),0);
|
||||
}
|
||||
|
||||
i = ((match == 0) ? branches_->vec.erase(i) : (i+1));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
Branches::from_string(const std::string &s_)
|
||||
{
|
||||
rwlock::WriteGuard guard(&lock);
|
||||
rwlock::WriteGuard guard(lock);
|
||||
|
||||
std::string instr;
|
||||
std::string values;
|
||||
|
||||
::split(s_,&instr,&values);
|
||||
l::split(s_,&instr,&values);
|
||||
|
||||
if(instr == "+")
|
||||
::add_end(*this,values);
|
||||
ef(instr == "+<")
|
||||
::add_begin(*this,values);
|
||||
ef(instr == "+>")
|
||||
::add_end(*this,values);
|
||||
ef(instr == "-")
|
||||
::erase_fnmatch(*this,values);
|
||||
ef(instr == "-<")
|
||||
::erase_begin(*this);
|
||||
ef(instr == "->")
|
||||
::erase_end(*this);
|
||||
ef(instr == "=")
|
||||
::set(*this,values);
|
||||
ef(instr.empty())
|
||||
::set(*this,values);
|
||||
else
|
||||
return -EINVAL;
|
||||
return l::add_end(values,this);
|
||||
if(instr == "+<")
|
||||
return l::add_begin(values,this);
|
||||
if(instr == "+>")
|
||||
return l::add_end(values,this);
|
||||
if(instr == "-")
|
||||
return l::erase_fnmatch(values,this);
|
||||
if(instr == "-<")
|
||||
return l::erase_begin(&vec);
|
||||
if(instr == "->")
|
||||
return l::erase_end(&vec);
|
||||
if(instr == "=")
|
||||
return l::set(values,this);
|
||||
if(instr.empty())
|
||||
return l::set(values,this);
|
||||
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
string
|
||||
Branches::to_string(void) const
|
||||
{
|
||||
rwlock::ReadGuard guard(&lock);
|
||||
rwlock::ReadGuard guard(lock);
|
||||
|
||||
string tmp;
|
||||
|
||||
for(size_t i = 0; i < size(); i++)
|
||||
for(size_t i = 0; i < vec.size(); i++)
|
||||
{
|
||||
const Branch &branch = (*this)[i];
|
||||
|
||||
tmp += branch.path;
|
||||
|
||||
tmp += '=';
|
||||
switch(branch.mode)
|
||||
{
|
||||
default:
|
||||
case Branch::RW:
|
||||
tmp += "RW";
|
||||
break;
|
||||
case Branch::RO:
|
||||
tmp += "RO";
|
||||
break;
|
||||
case Branch::NC:
|
||||
tmp += "NC";
|
||||
break;
|
||||
}
|
||||
const Branch &branch = vec[i];
|
||||
|
||||
tmp += branch.to_string();
|
||||
tmp += ':';
|
||||
}
|
||||
|
||||
|
|
@ -274,11 +419,11 @@ Branches::to_string(void) const
|
|||
void
|
||||
Branches::to_paths(vector<string> &vec_) const
|
||||
{
|
||||
rwlock::ReadGuard guard(&lock);
|
||||
rwlock::ReadGuard guard(lock);
|
||||
|
||||
for(size_t i = 0; i < size(); i++)
|
||||
for(size_t i = 0; i < vec.size(); i++)
|
||||
{
|
||||
const Branch &branch = (*this)[i];
|
||||
const Branch &branch = vec[i];
|
||||
|
||||
vec_.push_back(branch.path);
|
||||
}
|
||||
|
|
@ -299,12 +444,13 @@ SrcMounts::from_string(const std::string &s_)
|
|||
std::string
|
||||
SrcMounts::to_string(void) const
|
||||
{
|
||||
rwlock::ReadGuard guard(&_branches.lock);
|
||||
rwlock::ReadGuard guard(_branches.lock);
|
||||
|
||||
std::string rv;
|
||||
|
||||
for(uint64_t i = 0; i < _branches.size(); i++)
|
||||
for(uint64_t i = 0; i < _branches.vec.size(); i++)
|
||||
{
|
||||
rv += _branches[i].path;
|
||||
rv += _branches.vec[i].path;
|
||||
rv += ':';
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue