diff --git a/src/policy.cpp b/src/policy.cpp index 2059cbf9..8e1cee3c 100644 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -43,7 +43,8 @@ const std::vector Policy::_policies_ = (POLICY(msplus,PRESERVES_PATH)) (POLICY(mspmfs,PRESERVES_PATH)) (POLICY(newest,DOESNT_PRESERVE_PATH)) - (POLICY(rand,DOESNT_PRESERVE_PATH)); + (POLICY(rand,DOESNT_PRESERVE_PATH)) + (POLICY(fair,DOESNT_PRESERVE_PATH)); const Policy * const Policy::policies = &_policies_[1]; @@ -67,6 +68,7 @@ CONST_POLICY(msplus); CONST_POLICY(mspmfs); CONST_POLICY(newest); CONST_POLICY(rand); +CONST_POLICY(fair); const Policy& Policy::find(const std::string &str) diff --git a/src/policy.hpp b/src/policy.hpp index 39a51d35..87d68ea8 100644 --- a/src/policy.hpp +++ b/src/policy.hpp @@ -49,6 +49,7 @@ public: mspmfs, newest, rand, + fair, END }; @@ -130,6 +131,7 @@ public: static int mspmfs(CType,const Branches&,const char *,cuint64_t,strvec*); static int newest(CType,const Branches&,const char *,cuint64_t,strvec*); static int rand(CType,const Branches&,const char *,cuint64_t,strvec*); + static int fair(CType,const Branches&,const char *,cuint64_t,strvec*); }; private: @@ -211,6 +213,7 @@ public: static const Policy &mspmfs; static const Policy &newest; static const Policy &rand; + static const Policy &fair; }; namespace std diff --git a/src/policy_fair.cpp b/src/policy_fair.cpp new file mode 100644 index 00000000..4bb0d8ca --- /dev/null +++ b/src/policy_fair.cpp @@ -0,0 +1,119 @@ +/* + Copyright (c) 2020, LiveIntent ApS, Andreas E. Dalsgaard + + 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.hpp" +#include "fs_exists.hpp" +#include "fs_info.hpp" +#include "fs_path.hpp" +#include "policy.hpp" +#include "policy_error.hpp" +#include "rwlock.hpp" + +#include +#include + +using std::string; +using std::vector; + +namespace fair +{ + uint64_t get_int64_rand(uint64_t const& min, uint64_t const& max) + { + return (((uint64_t)(unsigned int)rand() << 32) + (uint64_t)(unsigned int)rand()) % (max - min) + min; + } + + static + int + create(const Branches &branches_, + const uint64_t minfreespace_, + vector *paths_) + { + rwlock::ReadGuard guard(&branches_.lock); + + int rv; + int error; + uint64_t sum, index; + uint64_t random_byte; + fs::info_t info; + const Branch *branch; + const string *fairbasepath; + + error = ENOENT; + fairbasepath = NULL; + sum = 0, index = 0; + 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; + } + + random_byte = get_int64_rand(0, sum); + + 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); + + index += info.spaceavail; + + if(index > random_byte) { + fairbasepath = &branch->path; + break; + } + } + + if(fairbasepath == NULL) + return (errno=error,-1); + + paths_->push_back(*fairbasepath); + + return 0; + } +} + +int +Policy::Func::fair(const Category::Enum::Type type, + const Branches &branches_, + const char *fusepath, + const uint64_t minfreespace, + vector *paths) +{ + if(type == Category::Enum::create) + return fair::create(branches_,minfreespace,paths); + + return Policy::Func::epmfs(type,branches_,fusepath,minfreespace,paths); +}