Browse Source

Merge pull request #112 from trapexit/epmfs+minfreespace

add minfreespace check to epmfs create policy
pull/113/head
Antonio SJ Musumeci 9 years ago
parent
commit
908a2f61f7
  1. 14
      README.md
  2. 98
      src/policy_epmfs.cpp

14
README.md

@ -21,7 +21,7 @@ Why create **mergerfs** when those exist? **mhddfs** has not been updated in som
###options### ###options###
* **defaults** is a shortcut for **auto_cache**. **big_writes**, **atomic_o_trunc**, **splice_read**, **splice_write**, and **splice_move** are in effect also enabled (by asking **FUSE** internally for such features) but if unavailable will be ignored. These options seem to provide the best performance. * **defaults** is a shortcut for **auto_cache**. **big_writes**, **atomic_o_trunc**, **splice_read**, **splice_write**, and **splice_move** are in effect also enabled (by asking **FUSE** internally for such features) but if unavailable will be ignored. These options seem to provide the best performance.
* **minfreespace** (defaults to **4G**) is the minimum space value used for the **lfs** and **fwfs** policies. Understands 'K', 'M', and 'G' to represent kilobyte, megabyte, and gigabyte respectively.
* **minfreespace** (defaults to **4G**) is the minimum space value used for the **lfs**, **fwfs**, and **epmfs** policies. Understands 'K', 'M', and 'G' to represent kilobyte, megabyte, and gigabyte respectively.
* All FUSE functions which have a category (see below) are option keys. The syntax being **func.<func>=<policy>**. Example: **func.getattr=newest**. * All FUSE functions which have a category (see below) are option keys. The syntax being **func.<func>=<policy>**. Example: **func.getattr=newest**.
* To set all function policies in a category use **categor.<category>=<policy>**. Example: **category.create=mfs**. * To set all function policies in a category use **categor.<category>=<policy>**. Example: **category.create=mfs**.
* Options are evaluated in the order listed so if the options are **func.rmdir=rand,category.action=ff** the **action** category setting will override the **rmdir** setting. * Options are evaluated in the order listed so if the options are **func.rmdir=rand,category.action=ff** the **action** category setting will override the **rmdir** setting.
@ -64,14 +64,14 @@ Filesystem calls are broken up into 3 categories: **action**, **create**, **sear
| Policy | Description | | Policy | Description |
|--------------|-------------| |--------------|-------------|
| ff (first found) | Given the order of the paths act on the first one found (regardless if stat would return EACCES). |
| ffwp (first found w/ permissions) | Given the order of the paths act on the first one found which you have access (stat does not error with EACCES). |
| ff (first found) | Given the order of the drives act on the first one found (regardless if stat would return EACCES). |
| ffwp (first found w/ permissions) | Given the order of the drives act on the first one found which you have access (stat does not error with EACCES). |
| newest (newest file) | If multiple files exist return the one with the most recent mtime. | | newest (newest file) | If multiple files exist return the one with the most recent mtime. |
| mfs (most free space) | Use the drive with the most free space available. | | mfs (most free space) | Use the drive with the most free space available. |
| epmfs (existing path, most free space) | If the path exists in multiple locations use the one with the most free space. Otherwise fall back to **mfs**. |
| fwfs (first with free space) | Pick the first path which has at least **minfreespace**. |
| lfs (least free space) | Pick the path with least available space but more than **minfreespace**. |
| rand (random) | Pick an existing destination at random. |
| epmfs (existing path, most free space) | If the path exists on multiple drives use the one with the most free space and is greater than **minfreespace**. If no drive has at least **minfreespace** then fallback to **mfs**. |
| fwfs (first with free space) | Pick the first drive which has at least **minfreespace**. |
| lfs (least free space) | Pick the drive with least available space but more than **minfreespace**. |
| rand (random) | Pick an existing drive at random. |
| all | Applies action to all found. For searches it will behave like first found **ff**. | | all | Applies action to all found. For searches it will behave like first found **ff**. |
| enosys, einval, enotsup, exdev, erofs | Exclusively return `-1` with `errno` set to the respective value. Useful for debugging other applications' behavior to errors. | | enosys, einval, enotsup, exdev, erofs | Exclusively return `-1` with `errno` set to the respective value. Useful for debugging other applications' behavior to errors. |

98
src/policy_epmfs.cpp

@ -36,117 +36,57 @@
using std::string; using std::string;
using std::vector; using std::vector;
using std::size_t; using std::size_t;
using mergerfs::Policy;
using mergerfs::Category;
typedef struct statvfs statvfs_t;
static static
inline inline
void void
_calc_epmfs(const struct statvfs &fsstats,
const string &basepath,
fsblkcnt_t &epmfs,
string &epmfsbasepath,
fsblkcnt_t &mfs,
string &mfsbasepath)
{
fsblkcnt_t spaceavail;
spaceavail = (fsstats.f_frsize * fsstats.f_bavail);
if(spaceavail > epmfs)
{
epmfs = spaceavail;
epmfsbasepath = basepath;
}
if(spaceavail > mfs)
{
mfs = spaceavail;
mfsbasepath = basepath;
}
}
static
inline
void
_calc_mfs(const struct statvfs &fsstats,
_calc_mfs(const statvfs_t &fsstats,
const string &basepath, const string &basepath,
const size_t minfreespace,
fsblkcnt_t &mfs, fsblkcnt_t &mfs,
string &mfsbasepath) string &mfsbasepath)
{ {
fsblkcnt_t spaceavail; fsblkcnt_t spaceavail;
spaceavail = (fsstats.f_frsize * fsstats.f_bavail); spaceavail = (fsstats.f_frsize * fsstats.f_bavail);
if(spaceavail > mfs)
if((spaceavail > minfreespace) && (spaceavail > mfs))
{ {
mfs = spaceavail; mfs = spaceavail;
mfsbasepath = basepath; mfsbasepath = basepath;
} }
} }
static
inline
int
_try_statvfs(const string &basepath,
const string &fullpath,
fsblkcnt_t &epmfs,
string &epmfsbasepath,
fsblkcnt_t &mfs,
string &mfsbasepath)
{
int rv;
struct statvfs fsstats;
rv = ::statvfs(fullpath.c_str(),&fsstats);
if(rv == 0)
_calc_epmfs(fsstats,basepath,epmfs,epmfsbasepath,mfs,mfsbasepath);
return rv;
}
static
inline
int
_try_statvfs(const string &basepath,
fsblkcnt_t &mfs,
string &mfsbasepath)
{
int rv;
struct statvfs fsstats;
rv = ::statvfs(basepath.c_str(),&fsstats);
if(rv == 0)
_calc_mfs(fsstats,basepath,mfs,mfsbasepath);
return rv;
}
static static
int int
_epmfs_create(const vector<string> &basepaths, _epmfs_create(const vector<string> &basepaths,
const string &fusepath, const string &fusepath,
const size_t minfreespace,
vector<string> &paths) vector<string> &paths)
{ {
int rv;
fsblkcnt_t epmfs; fsblkcnt_t epmfs;
fsblkcnt_t mfs;
string mfsbasepath;
string epmfsbasepath; string epmfsbasepath;
string fullpath; string fullpath;
statvfs_t fsstats;
mfs = 0;
epmfs = 0; epmfs = 0;
for(size_t i = 0, ei = basepaths.size(); i != ei; i++) for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
{ {
int rv;
const string &basepath = basepaths[i]; const string &basepath = basepaths[i];
fullpath = fs::path::make(basepath,fusepath);
fs::path::make(basepath,fusepath,fullpath);
rv = _try_statvfs(basepath,fullpath,epmfs,epmfsbasepath,mfs,mfsbasepath);
if(rv == -1)
_try_statvfs(basepath,mfs,mfsbasepath);
rv = ::statvfs(fullpath.c_str(),&fsstats);
if(rv == 0)
_calc_mfs(fsstats,basepath,minfreespace,epmfs,epmfsbasepath);
} }
if(epmfsbasepath.empty()) if(epmfsbasepath.empty())
epmfsbasepath = mfsbasepath;
return Policy::Func::mfs(Category::Enum::create,basepaths,fusepath,minfreespace,paths);
paths.push_back(epmfsbasepath); paths.push_back(epmfsbasepath);
@ -160,22 +100,22 @@ _epmfs(const vector<string> &basepaths,
vector<string> &paths) vector<string> &paths)
{ {
int rv;
fsblkcnt_t epmfs; fsblkcnt_t epmfs;
string epmfsbasepath; string epmfsbasepath;
string fullpath; string fullpath;
statvfs_t fsstats;
epmfs = 0; epmfs = 0;
for(size_t i = 0, ei = basepaths.size(); i != ei; i++) for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
{ {
int rv;
struct statvfs fsstats;
const string &basepath = basepaths[i]; const string &basepath = basepaths[i];
fullpath = fs::path::make(basepath,fusepath);
fs::path::make(basepath,fusepath,fullpath);
rv = ::statvfs(fullpath.c_str(),&fsstats); rv = ::statvfs(fullpath.c_str(),&fsstats);
if(rv == 0) if(rv == 0)
_calc_mfs(fsstats,basepath,epmfs,epmfsbasepath);
_calc_mfs(fsstats,basepath,0,epmfs,epmfsbasepath);
} }
if(epmfsbasepath.empty()) if(epmfsbasepath.empty())
@ -196,7 +136,7 @@ namespace mergerfs
vector<string> &paths) vector<string> &paths)
{ {
if(type == Category::Enum::create) if(type == Category::Enum::create)
return _epmfs_create(basepaths,fusepath,paths);
return _epmfs_create(basepaths,fusepath,minfreespace,paths);
return _epmfs(basepaths,fusepath,paths); return _epmfs(basepaths,fusepath,paths);
} }

Loading…
Cancel
Save