mirror of
https://github.com/trapexit/mergerfs.git
synced 2024-11-25 08:56:11 +08:00
add {,ep,msp}pfrd policies
Percentage Free Random Distribution Chooses a random branch based on the available space percentage free. IE: if branch A has 1G free and branch B has 2G then B should be chosen twice as often.
This commit is contained in:
parent
7ff995631e
commit
046844083f
23
README.md
23
README.md
|
@ -1,6 +1,6 @@
|
|||
% mergerfs(1) mergerfs user manual
|
||||
% Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
% 2020-08-07
|
||||
% 2020-08-20
|
||||
|
||||
# NAME
|
||||
|
||||
|
@ -306,22 +306,25 @@ Because of the nature of the behavior the policies act diffierently depending on
|
|||
|
||||
| Policy | Description |
|
||||
|------------------|------------------------------------------------------------|
|
||||
| all | Search: same as **epall**. Action: same as **epall**. Create: for **mkdir**, **mknod**, and **symlink** it will apply to all branches. **create** works like **ff**. |
|
||||
| epall (existing path, all) | Search: same as **epff** (but more expensive because it doesn't stop after finding a valid branch). Action: apply to all found. Create: for **mkdir**, **mknod**, and **symlink** it will apply to all found. **create** works like **epff** (but more expensive because it doesn't stop after finding a valid branch). |
|
||||
| all | Search: Same as **epall**. Action: Same as **epall**. Create: for **mkdir**, **mknod**, and **symlink** it will apply to all branches. **create** works like **ff**. |
|
||||
| epall (existing path, all) | Search: Same as **epff** (but more expensive because it doesn't stop after finding a valid branch). Action: apply to all found. Create: for **mkdir**, **mknod**, and **symlink** it will apply to all found. **create** works like **epff** (but more expensive because it doesn't stop after finding a valid branch). |
|
||||
| epff (existing path, first found) | Given the order of the branches, as defined at mount time or configured at runtime, act on the first one found where the relative path exists. |
|
||||
| eplfs (existing path, least free space) | Of all the branches on which the relative path exists choose the drive with the least free space. |
|
||||
| eplus (existing path, least used space) | Of all the branches on which the relative path exists choose the drive with the least used space. |
|
||||
| epmfs (existing path, most free space) | Of all the branches on which the relative path exists choose the drive with the most free space. |
|
||||
| eppfrd (existing path, percentage free random distribution) | Like **pfrd** but limited to existing paths. |
|
||||
| eprand (existing path, random) | Calls **epall** and then randomizes. Returns 1. |
|
||||
| erofs | Exclusively return **-1** with **errno** set to **EROFS** (read-only filesystem). |
|
||||
| ff (first found) | Search: same as **epff**. Action: same as **epff**. Create: Given the order of the drives, as defined at mount time or configured at runtime, act on the first one found. |
|
||||
| lfs (least free space) | Search: same as **eplfs**. Action: same as **eplfs**. Create: Pick the drive with the least available free space. |
|
||||
| lus (least used space) | Search: same as **eplus**. Action: same as **eplus**. Create: Pick the drive with the least used space. |
|
||||
| mfs (most free space) | Search: same as **epmfs**. Action: same as **epmfs**. Create: Pick the drive with the most available free space. |
|
||||
| msplfs (most shared path, least free space) | Search: same as **eplfs**. Action: same as **eplfs**. Create: like **eplfs** but walk back the path if it fails to find a branch at that level. |
|
||||
| msplus (most shared path, least used space) | Search: same as **eplus**. Action: same as **eplus**. Create: like **eplus** but walk back the path if it fails to find a branch at that level. |
|
||||
| mspmfs (most shared path, most free space) | Search: same as **epmfss**. Action: same as **epmfs**. Create: like **eplmfs** but walk back the path if it fails to find a branch at that level. |
|
||||
| ff (first found) | Search: Same as **epff**. Action: Same as **epff**. Create: Given the order of the drives, as defined at mount time or configured at runtime, act on the first one found. |
|
||||
| lfs (least free space) | Search: Same as **eplfs**. Action: Same as **eplfs**. Create: Pick the drive with the least available free space. |
|
||||
| lus (least used space) | Search: Same as **eplus**. Action: Same as **eplus**. Create: Pick the drive with the least used space. |
|
||||
| mfs (most free space) | Search: Same as **epmfs**. Action: Same as **epmfs**. Create: Pick the drive with the most available free space. |
|
||||
| msplfs (most shared path, least free space) | Search: Same as **eplfs**. Action: Same as **eplfs**. Create: like **eplfs** but walk back the path if it fails to find a branch at that level. |
|
||||
| msplus (most shared path, least used space) | Search: Same as **eplus**. Action: Same as **eplus**. Create: like **eplus** but walk back the path if it fails to find a branch at that level. |
|
||||
| mspmfs (most shared path, most free space) | Search: Same as **epmfss**. Action: Same as **epmfs**. Create: like **eplmfs** but walk back the path if it fails to find a branch at that level. |
|
||||
| msppfrd (most shared path, percentage free random distribution) | Search: Same as **eppfrd**. Action: Same as **eppfrd**. Create: Like **eppfrd** but will walk back the path if it fails to find a branch at that level. |
|
||||
| newest | Pick the file / directory with the largest mtime. |
|
||||
| pfrd (percentage free random distribution) | Search: Same as **eppfrd**. Action: Same as **eppfrd**. Create: Chooses a branch at random with the likelihood of selection based on a branch's available space relative to the total. |
|
||||
| rand (random) | Calls **all** and then randomizes. Returns 1. |
|
||||
|
||||
**NOTE:** If you are using an underlying filesystem that reserves blocks such as ext2, ext3, or ext4 be aware that mergerfs respects the reservation by using `f_bavail` (number of free blocks for unprivileged users) rather than `f_bfree` (number of free blocks) in policy calculations. **df** does NOT use `f_bavail`, it uses `f_bfree`, so direct comparisons between **df** output and mergerfs' policies is not appropriate.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
.\"t
|
||||
.\" Automatically generated by Pandoc 1.19.2.4
|
||||
.\"
|
||||
.TH "mergerfs" "1" "2020\-08\-07" "mergerfs user manual" ""
|
||||
.TH "mergerfs" "1" "2020\-08\-20" "mergerfs user manual" ""
|
||||
.hy
|
||||
.SH NAME
|
||||
.PP
|
||||
|
@ -778,6 +778,11 @@ Of all the branches on which the relative path exists choose the drive
|
|||
with the most free space.
|
||||
T}
|
||||
T{
|
||||
eppfrd (existing path, percentage free random distribution)
|
||||
T}@T{
|
||||
Like \f[B]pfrd\f[] but limited to existing paths.
|
||||
T}
|
||||
T{
|
||||
eprand (existing path, random)
|
||||
T}@T{
|
||||
Calls \f[B]epall\f[] and then randomizes.
|
||||
|
@ -843,11 +848,27 @@ Create: like \f[B]eplmfs\f[] but walk back the path if it fails to find
|
|||
a branch at that level.
|
||||
T}
|
||||
T{
|
||||
msppfrd (most shared path, percentage free random distribution)
|
||||
T}@T{
|
||||
Search: same as \f[B]eppfrd\f[].
|
||||
Action: same as \f[B]eppfrd\f[].
|
||||
Create: Like \f[B]eppfrd\f[] but will walk back the path if it fails to
|
||||
find a branch at that level.
|
||||
T}
|
||||
T{
|
||||
newest
|
||||
T}@T{
|
||||
Pick the file / directory with the largest mtime.
|
||||
T}
|
||||
T{
|
||||
pfrd (percentage free random distribution)
|
||||
T}@T{
|
||||
Search: same as \f[B]eppfrd\f[].
|
||||
Action: same as \f[B]eppfrd\f[].
|
||||
Create: Chooses a branch at random with the likelihood of selection
|
||||
based on a branch\[aq]s available space relative to the total.
|
||||
T}
|
||||
T{
|
||||
rand (random)
|
||||
T}@T{
|
||||
Calls \f[B]all\f[] and then randomizes.
|
||||
|
|
|
@ -32,6 +32,7 @@ const std::vector<Policy> Policy::_policies_ =
|
|||
(POLICY(eplfs,PRESERVES_PATH))
|
||||
(POLICY(eplus,PRESERVES_PATH))
|
||||
(POLICY(epmfs,PRESERVES_PATH))
|
||||
(POLICY(eppfrd,PRESERVES_PATH))
|
||||
(POLICY(eprand,PRESERVES_PATH))
|
||||
(POLICY(erofs,DOESNT_PRESERVE_PATH))
|
||||
(POLICY(ff,DOESNT_PRESERVE_PATH))
|
||||
|
@ -41,7 +42,9 @@ const std::vector<Policy> Policy::_policies_ =
|
|||
(POLICY(msplfs,PRESERVES_PATH))
|
||||
(POLICY(msplus,PRESERVES_PATH))
|
||||
(POLICY(mspmfs,PRESERVES_PATH))
|
||||
(POLICY(msppfrd,PRESERVES_PATH))
|
||||
(POLICY(newest,DOESNT_PRESERVE_PATH))
|
||||
(POLICY(pfrd,DOESNT_PRESERVE_PATH))
|
||||
(POLICY(rand,DOESNT_PRESERVE_PATH));
|
||||
|
||||
const Policy * const Policy::policies = &_policies_[1];
|
||||
|
@ -55,6 +58,7 @@ CONST_POLICY(epff);
|
|||
CONST_POLICY(eplfs);
|
||||
CONST_POLICY(eplus);
|
||||
CONST_POLICY(epmfs);
|
||||
CONST_POLICY(eppfrd);
|
||||
CONST_POLICY(eprand);
|
||||
CONST_POLICY(erofs);
|
||||
CONST_POLICY(ff);
|
||||
|
@ -64,19 +68,21 @@ CONST_POLICY(mfs);
|
|||
CONST_POLICY(msplfs);
|
||||
CONST_POLICY(msplus);
|
||||
CONST_POLICY(mspmfs);
|
||||
CONST_POLICY(msppfrd);
|
||||
CONST_POLICY(newest);
|
||||
CONST_POLICY(pfrd);
|
||||
CONST_POLICY(rand);
|
||||
|
||||
const Policy&
|
||||
Policy::find(const std::string &str)
|
||||
{
|
||||
for(int i = Enum::BEGIN; i != Enum::END; ++i)
|
||||
{
|
||||
if(policies[i] == str)
|
||||
return policies[i];
|
||||
}
|
||||
for(int i = Enum::BEGIN; i != Enum::END; ++i)
|
||||
{
|
||||
if(policies[i] == str)
|
||||
return policies[i];
|
||||
}
|
||||
|
||||
return invalid;
|
||||
return invalid;
|
||||
}
|
||||
|
||||
const Policy&
|
||||
|
|
|
@ -37,6 +37,7 @@ public:
|
|||
eplfs,
|
||||
eplus,
|
||||
epmfs,
|
||||
eppfrd,
|
||||
eprand,
|
||||
erofs,
|
||||
ff,
|
||||
|
@ -46,7 +47,9 @@ public:
|
|||
msplfs,
|
||||
msplus,
|
||||
mspmfs,
|
||||
msppfrd,
|
||||
newest,
|
||||
pfrd,
|
||||
rand,
|
||||
END
|
||||
};
|
||||
|
@ -117,6 +120,7 @@ public:
|
|||
static int eplfs(Category,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int eplus(Category,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int epmfs(Category,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int eppfrd(Category,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int eprand(Category,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int erofs(Category,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int ff(Category,const Branches&,const char *,cuint64_t,strvec*);
|
||||
|
@ -126,7 +130,9 @@ public:
|
|||
static int msplfs(Category,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int msplus(Category,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int mspmfs(Category,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int msppfrd(Category,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int newest(Category,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int pfrd(Category,const Branches&,const char *,cuint64_t,strvec*);
|
||||
static int rand(Category,const Branches&,const char *,cuint64_t,strvec*);
|
||||
};
|
||||
|
||||
|
@ -198,6 +204,7 @@ public:
|
|||
static const Policy &eplfs;
|
||||
static const Policy ⩱
|
||||
static const Policy &epmfs;
|
||||
static const Policy &eppfrd;
|
||||
static const Policy &eprand;
|
||||
static const Policy &erofs;
|
||||
static const Policy &ff;
|
||||
|
@ -207,7 +214,9 @@ public:
|
|||
static const Policy &msplfs;
|
||||
static const Policy &msplus;
|
||||
static const Policy &mspmfs;
|
||||
static const Policy &msppfrd;
|
||||
static const Policy &newest;
|
||||
static const Policy &pfrd;
|
||||
static const Policy &rand;
|
||||
};
|
||||
|
||||
|
|
273
src/policy_eppfrd.cpp
Normal file
273
src/policy_eppfrd.cpp
Normal file
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
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 "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 "rnd.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
struct BranchInfo
|
||||
{
|
||||
uint64_t spaceavail;
|
||||
const string *basepath;
|
||||
};
|
||||
|
||||
typedef vector<BranchInfo> BranchInfoVec;
|
||||
|
||||
namespace eppfrd
|
||||
{
|
||||
static
|
||||
int
|
||||
get_branchinfo_create(const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
BranchInfoVec *branchinfo_,
|
||||
uint64_t *sum_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
BranchInfo bi;
|
||||
fs::info_t info;
|
||||
const Branch *branch;
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
*sum_ = 0;
|
||||
error = ENOENT;
|
||||
for(size_t i = 0, ei = branches_.size(); i < ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
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 == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace_)
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
*sum_ += info.spaceavail;
|
||||
|
||||
bi.spaceavail = info.spaceavail;
|
||||
bi.basepath = &branch->path;
|
||||
branchinfo_->push_back(bi);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
get_branchinfo_action(const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
BranchInfoVec *branchinfo_,
|
||||
uint64_t *sum_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
BranchInfo bi;
|
||||
fs::info_t info;
|
||||
const Branch *branch;
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
*sum_ = 0;
|
||||
error = ENOENT;
|
||||
for(size_t i = 0, ei = branches_.size(); i < ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
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 == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
|
||||
*sum_ += info.spaceavail;
|
||||
|
||||
bi.spaceavail = info.spaceavail;
|
||||
bi.basepath = &branch->path;
|
||||
branchinfo_->push_back(bi);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
get_branchinfo_search(const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
BranchInfoVec *branchinfo_,
|
||||
uint64_t *sum_)
|
||||
{
|
||||
int rv;
|
||||
BranchInfo bi;
|
||||
uint64_t spaceavail;
|
||||
const Branch *branch;
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
*sum_ = 0;
|
||||
for(size_t i = 0, ei = branches_.size(); i < ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(branch->path,fusepath_))
|
||||
continue;
|
||||
rv = fs::statvfs_cache_spaceavail(branch->path,&spaceavail);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
|
||||
*sum_ += spaceavail;
|
||||
|
||||
bi.spaceavail = spaceavail;
|
||||
bi.basepath = &branch->path;
|
||||
branchinfo_->push_back(bi);
|
||||
}
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
static
|
||||
const
|
||||
string*
|
||||
get_branch(const BranchInfoVec &branchinfo_,
|
||||
const uint64_t sum_)
|
||||
{
|
||||
uint64_t idx;
|
||||
uint64_t threshold;
|
||||
|
||||
idx = 0;
|
||||
threshold = RND::rand64(sum_);
|
||||
for(size_t i = 0; i < branchinfo_.size(); i++)
|
||||
{
|
||||
idx += branchinfo_[i].spaceavail;
|
||||
|
||||
if(idx < threshold)
|
||||
continue;
|
||||
|
||||
return branchinfo_[i].basepath;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
int error;
|
||||
uint64_t sum;
|
||||
const string *basepath;
|
||||
BranchInfoVec branchinfo;
|
||||
|
||||
branchinfo.reserve(branches_.size());
|
||||
error = eppfrd::get_branchinfo_create(branches_,fusepath_,minfreespace_,&branchinfo,&sum);
|
||||
basepath = eppfrd::get_branch(branchinfo,sum);
|
||||
if(basepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths_->push_back(*basepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
int error;
|
||||
uint64_t sum;
|
||||
const string *basepath;
|
||||
BranchInfoVec branchinfo;
|
||||
|
||||
branchinfo.reserve(branches_.size());
|
||||
error = eppfrd::get_branchinfo_action(branches_,fusepath_,minfreespace_,&branchinfo,&sum);
|
||||
basepath = eppfrd::get_branch(branchinfo,sum);
|
||||
if(basepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths_->push_back(*basepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
int error;
|
||||
uint64_t sum;
|
||||
const string *basepath;
|
||||
BranchInfoVec branchinfo;
|
||||
|
||||
branchinfo.reserve(branches_.size());
|
||||
error = eppfrd::get_branchinfo_search(branches_,fusepath_,minfreespace_,&branchinfo,&sum);
|
||||
basepath = eppfrd::get_branch(branchinfo,sum);
|
||||
if(basepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths_->push_back(*basepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
Policy::Func::eppfrd(const Category type_,
|
||||
const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
switch(type_)
|
||||
{
|
||||
case Category::CREATE:
|
||||
return eppfrd::create(branches_,fusepath_,minfreespace_,paths_);
|
||||
case Category::ACTION:
|
||||
return eppfrd::action(branches_,fusepath_,minfreespace_,paths_);
|
||||
default:
|
||||
case Category::SEARCH:
|
||||
return eppfrd::search(branches_,fusepath_,minfreespace_,paths_);
|
||||
}
|
||||
}
|
172
src/policy_msppfrd.cpp
Normal file
172
src/policy_msppfrd.cpp
Normal file
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2020, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
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 "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 "rnd.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
struct BranchInfo
|
||||
{
|
||||
uint64_t spaceavail;
|
||||
const string *basepath;
|
||||
};
|
||||
|
||||
typedef vector<BranchInfo> BranchInfoVec;
|
||||
|
||||
namespace msppfrd
|
||||
{
|
||||
static
|
||||
int
|
||||
create_1(const Branches &branches_,
|
||||
const string &fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
BranchInfoVec *branchinfo_,
|
||||
uint64_t *sum_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
BranchInfo bi;
|
||||
fs::info_t info;
|
||||
const Branch *branch;
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
*sum_ = 0;
|
||||
error = ENOENT;
|
||||
for(size_t i = 0, ei = branches_.size(); i < ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
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 == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace_)
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
*sum_ += info.spaceavail;
|
||||
|
||||
bi.spaceavail = info.spaceavail;
|
||||
bi.basepath = &branch->path;
|
||||
branchinfo_->push_back(bi);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
get_branchinfo(const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
BranchInfoVec *branchinfo_,
|
||||
uint64_t *sum_)
|
||||
{
|
||||
int error;
|
||||
string fusepath;
|
||||
|
||||
fusepath = fusepath_;
|
||||
do
|
||||
{
|
||||
error = msppfrd::create_1(branches_,fusepath,minfreespace_,branchinfo_,sum_);
|
||||
if(branchinfo_->size())
|
||||
return error;
|
||||
|
||||
fusepath = fs::path::dirname(fusepath);
|
||||
}
|
||||
while(!fusepath.empty());
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static
|
||||
const
|
||||
string*
|
||||
get_branch(const BranchInfoVec &branchinfo_,
|
||||
const uint64_t sum_)
|
||||
{
|
||||
uint64_t idx;
|
||||
uint64_t threshold;
|
||||
|
||||
idx = 0;
|
||||
threshold = RND::rand64(sum_);
|
||||
for(size_t i = 0; i < branchinfo_.size(); i++)
|
||||
{
|
||||
idx += branchinfo_[i].spaceavail;
|
||||
|
||||
if(idx < threshold)
|
||||
continue;
|
||||
|
||||
return branchinfo_[i].basepath;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
int error;
|
||||
uint64_t sum;
|
||||
const string *basepath;
|
||||
BranchInfoVec branchinfo;
|
||||
|
||||
branchinfo.reserve(branches_.size());
|
||||
error = msppfrd::get_branchinfo(branches_,fusepath_,minfreespace_,&branchinfo,&sum);
|
||||
basepath = msppfrd::get_branch(branchinfo,sum);
|
||||
if(basepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths_->push_back(*basepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
Policy::Func::msppfrd(const Category type_,
|
||||
const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
if(type_ == Category::CREATE)
|
||||
return msppfrd::create(branches_,fusepath_,minfreespace_,paths_);
|
||||
|
||||
return Policy::Func::eppfrd(type_,branches_,fusepath_,minfreespace_,paths_);
|
||||
}
|
140
src/policy_pfrd.cpp
Normal file
140
src/policy_pfrd.cpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
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 "errno.hpp"
|
||||
#include "fs_info.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
#include "rnd.hpp"
|
||||
#include "rwlock.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
struct BranchInfo
|
||||
{
|
||||
uint64_t spaceavail;
|
||||
const string *basepath;
|
||||
};
|
||||
|
||||
typedef vector<BranchInfo> BranchInfoVec;
|
||||
|
||||
namespace pfrd
|
||||
{
|
||||
static
|
||||
int
|
||||
get_branchinfo(const Branches &branches_,
|
||||
const uint64_t minfreespace_,
|
||||
BranchInfoVec *branchinfo_,
|
||||
uint64_t *sum_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
BranchInfo bi;
|
||||
fs::info_t info;
|
||||
const Branch *branch;
|
||||
rwlock::ReadGuard guard(&branches_.lock);
|
||||
|
||||
*sum_ = 0;
|
||||
error = ENOENT;
|
||||
for(size_t i = 0, ei = branches_.size(); i < ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(branch->ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(branch->path,&info);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace_)
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
*sum_ += info.spaceavail;
|
||||
|
||||
bi.spaceavail = info.spaceavail;
|
||||
bi.basepath = &branch->path;
|
||||
branchinfo_->push_back(bi);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static
|
||||
const
|
||||
string*
|
||||
get_branch(const BranchInfoVec &branchinfo_,
|
||||
const uint64_t sum_)
|
||||
{
|
||||
uint64_t idx;
|
||||
uint64_t threshold;
|
||||
|
||||
idx = 0;
|
||||
threshold = RND::rand64(sum_);
|
||||
for(size_t i = 0; i < branchinfo_.size(); i++)
|
||||
{
|
||||
idx += branchinfo_[i].spaceavail;
|
||||
|
||||
if(idx < threshold)
|
||||
continue;
|
||||
|
||||
return branchinfo_[i].basepath;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
int error;
|
||||
uint64_t sum;
|
||||
const string *basepath;
|
||||
BranchInfoVec branchinfo;
|
||||
|
||||
branchinfo.reserve(branches_.size());
|
||||
error = pfrd::get_branchinfo(branches_,minfreespace_,&branchinfo,&sum);
|
||||
basepath = pfrd::get_branch(branchinfo,sum);
|
||||
if(basepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths_->push_back(*basepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
Policy::Func::pfrd(const Category type_,
|
||||
const Branches &branches_,
|
||||
const char *fusepath_,
|
||||
const uint64_t minfreespace_,
|
||||
vector<string> *paths_)
|
||||
{
|
||||
if(type_ == Category::CREATE)
|
||||
return pfrd::create(branches_,fusepath_,minfreespace_,paths_);
|
||||
|
||||
return Policy::Func::eppfrd(type_,branches_,fusepath_,minfreespace_,paths_);
|
||||
}
|
55
src/rnd.cpp
Normal file
55
src/rnd.cpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2020, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
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 "rnd.hpp"
|
||||
|
||||
#include "wyhash.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
static uint64_t G_SEED;
|
||||
static RND G_RND;
|
||||
|
||||
RND::RND()
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv,NULL);
|
||||
|
||||
G_SEED = ((tv.tv_sec << 32) | (tv.tv_usec));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
RND::rand64(void)
|
||||
{
|
||||
return wyrand(&G_SEED);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
RND::rand64(const uint64_t max_)
|
||||
{
|
||||
return (wyrand(&G_SEED) % max_);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
RND::rand64(const uint64_t min_,
|
||||
const uint64_t max_)
|
||||
{
|
||||
return (min_ + (wyrand(&G_SEED) % (max_ - min_)));
|
||||
}
|
33
src/rnd.hpp
Normal file
33
src/rnd.hpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2020, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
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 <stdint.h>
|
||||
|
||||
class RND
|
||||
{
|
||||
public:
|
||||
RND();
|
||||
|
||||
public:
|
||||
static uint64_t rand64(void);
|
||||
static uint64_t rand64(const uint64_t max_);
|
||||
static uint64_t rand64(const uint64_t min_,
|
||||
const uint64_t max_);
|
||||
};
|
Loading…
Reference in New Issue
Block a user