diff --git a/src/fs_inode.cpp b/src/fs_inode.cpp index 99091f32..e415d3aa 100644 --- a/src/fs_inode.cpp +++ b/src/fs_inode.cpp @@ -18,20 +18,18 @@ #include "fs_inode.hpp" -#include "ef.hpp" #include "rapidhash/rapidhash.h" #include -#include #include -typedef u64 (*inodefunc_t)(const std::string &, - const std::string &, +typedef u64 (*inodefunc_t)(const std::string_view, + const std::string_view, const mode_t, const ino_t); -static u64 _hybrid_hash(const std::string &, - const std::string &, +static u64 _hybrid_hash(const std::string_view, + const std::string_view, const mode_t, const ino_t); @@ -39,6 +37,13 @@ static u64 _hybrid_hash(const std::string &, static std::atomic g_func{::_hybrid_hash}; +static +const void* +_data(const std::string_view s_) +{ + return (s_.empty() ? "" : s_.data()); +} + static u32 _h64_to_h32(u64 h_) @@ -50,83 +55,116 @@ _h64_to_h32(u64 h_) static u64 -_passthrough(const std::string &branch_path_, - const std::string &fusepath_, - const mode_t mode_, - const ino_t ino_) +_hash(const std::string_view s_) +{ + return rapidhash(::_data(s_), + s_.size()); +} + +static +u64 +_branch_seed(const std::string_view branch_path_) +{ + return ::_hash(branch_path_); +} + +static +u64 +_devino_hash_from_seed(const u64 branch_seed_, + const ino_t ino_) +{ + return rapidhash_withSeed(&ino_, + sizeof(ino_), + branch_seed_); +} + +static +u64 +_path_hash_value(const std::string_view fusepath_) +{ + return ::_hash(fusepath_); +} + +static +u64 +_path_hash32_value(const std::string_view fusepath_) +{ + return ::_h64_to_h32(::_path_hash_value(fusepath_)); +} + +static +u64 +_devino_hash_value(const std::string_view branch_path_, + const ino_t ino_) +{ + return ::_devino_hash_from_seed(::_branch_seed(branch_path_), + ino_); +} + +static +u64 +_devino_hash32_value(const std::string_view branch_path_, + const ino_t ino_) +{ + return ::_h64_to_h32(::_devino_hash_value(branch_path_,ino_)); +} + +static +u64 +_passthrough(const std::string_view branch_path_, + const std::string_view fusepath_, + const mode_t mode_, + const ino_t ino_) { return ino_; } static u64 -_path_hash(const std::string &branch_path_, - const std::string &fusepath_, - const mode_t mode_, - const ino_t ino_) +_path_hash(const std::string_view branch_path_, + const std::string_view fusepath_, + const mode_t mode_, + const ino_t ino_) { - u64 seed; - - seed = rapidhash(&fusepath_[0],fusepath_.size()); - - return seed; + return ::_path_hash_value(fusepath_); } static u64 -_path_hash32(const std::string &branch_path_, - const std::string &fusepath_, - const mode_t mode_, - const ino_t ino_) +_path_hash32(const std::string_view branch_path_, + const std::string_view fusepath_, + const mode_t mode_, + const ino_t ino_) { - u64 h; - - h = ::_path_hash(branch_path_, - fusepath_, - mode_, - ino_); - - return ::_h64_to_h32(h); + return ::_path_hash32_value(fusepath_); } static u64 -_devino_hash(const std::string &branch_path_, - const std::string &fusepath_, - const mode_t mode_, - const ino_t ino_) +_devino_hash(const std::string_view branch_path_, + const std::string_view fusepath_, + const mode_t mode_, + const ino_t ino_) { - u64 seed; - - seed = rapidhash(&branch_path_[0],branch_path_.size()); - seed = rapidhash_withSeed(&ino_,sizeof(ino_),seed); - - return seed; + return ::_devino_hash_value(branch_path_,ino_); } static u64 -_devino_hash32(const std::string &branch_path_, - const std::string &fusepath_, - const mode_t mode_, - const ino_t ino_) +_devino_hash32(const std::string_view branch_path_, + const std::string_view fusepath_, + const mode_t mode_, + const ino_t ino_) { - u64 h; - - h = ::_devino_hash(branch_path_, - fusepath_, - mode_, - ino_); - - return ::_h64_to_h32(h); + return ::_devino_hash32_value(branch_path_,ino_); } static u64 -_hybrid_hash(const std::string &branch_path_, - const std::string &fusepath_, - const mode_t mode_, - const ino_t ino_) +_hybrid_hash(const std::string_view branch_path_, + const std::string_view fusepath_, + const mode_t mode_, + const ino_t ino_) { return (S_ISDIR(mode_) ? ::_path_hash(branch_path_,fusepath_,mode_,ino_) : @@ -135,8 +173,8 @@ _hybrid_hash(const std::string &branch_path_, static u64 -_hybrid_hash32(const std::string &branch_path_, - const std::string &fusepath_, +_hybrid_hash32(const std::string_view branch_path_, + const std::string_view fusepath_, const mode_t mode_, const ino_t ino_) { @@ -145,58 +183,180 @@ _hybrid_hash32(const std::string &branch_path_, ::_devino_hash32(branch_path_,fusepath_,mode_,ino_)); } +static +fs::inode::Algo +_algo_from_func(const inodefunc_t func_) +{ + if(func_ == ::_passthrough) + return fs::inode::Algo::PASSTHROUGH; + if(func_ == ::_path_hash) + return fs::inode::Algo::PATH_HASH; + if(func_ == ::_path_hash32) + return fs::inode::Algo::PATH_HASH32; + if(func_ == ::_devino_hash) + return fs::inode::Algo::DEVINO_HASH; + if(func_ == ::_devino_hash32) + return fs::inode::Algo::DEVINO_HASH32; + if(func_ == ::_hybrid_hash) + return fs::inode::Algo::HYBRID_HASH; + if(func_ == ::_hybrid_hash32) + return fs::inode::Algo::HYBRID_HASH32; + + return fs::inode::Algo::HYBRID_HASH; +} + +static +u64 +_calc_with_algo(const fs::inode::Algo algo_, + const u64 branch_seed_, + const std::string_view fusepath_, + const mode_t mode_, + const ino_t ino_) +{ + switch(algo_) + { + case fs::inode::Algo::PASSTHROUGH: + return ino_; + case fs::inode::Algo::PATH_HASH: + return ::_path_hash_value(fusepath_); + case fs::inode::Algo::PATH_HASH32: + return ::_path_hash32_value(fusepath_); + case fs::inode::Algo::DEVINO_HASH: + return ::_devino_hash_from_seed(branch_seed_,ino_); + case fs::inode::Algo::DEVINO_HASH32: + return ::_h64_to_h32(::_devino_hash_from_seed(branch_seed_,ino_)); + case fs::inode::Algo::HYBRID_HASH: + return (S_ISDIR(mode_) ? + ::_path_hash_value(fusepath_) : + ::_devino_hash_from_seed(branch_seed_,ino_)); + case fs::inode::Algo::HYBRID_HASH32: + return (S_ISDIR(mode_) ? + ::_path_hash32_value(fusepath_) : + ::_h64_to_h32(::_devino_hash_from_seed(branch_seed_,ino_))); + } + + return ino_; +} + int fs::inode::set_algo(const std::string &algo_) { + inodefunc_t func = nullptr; + if(algo_ == "passthrough") - g_func.store(::_passthrough); - ef(algo_ == "path-hash") - g_func.store(::_path_hash); - ef(algo_ == "path-hash32") - g_func.store(::_path_hash32); - ef(algo_ == "devino-hash") - g_func.store(::_devino_hash); - ef(algo_ == "devino-hash32") - g_func.store(::_devino_hash32); - ef(algo_ == "hybrid-hash") - g_func.store(::_hybrid_hash); - ef(algo_ == "hybrid-hash32") - g_func.store(::_hybrid_hash32); + func = ::_passthrough; + else if(algo_ == "path-hash") + func = ::_path_hash; + else if(algo_ == "path-hash32") + func = ::_path_hash32; + else if(algo_ == "devino-hash") + func = ::_devino_hash; + else if(algo_ == "devino-hash32") + func = ::_devino_hash32; + else if(algo_ == "hybrid-hash") + func = ::_hybrid_hash; + else if(algo_ == "hybrid-hash32") + func = ::_hybrid_hash32; else return -EINVAL; + g_func.store(func); + return 0; } std::string fs::inode::get_algo(void) { - inodefunc_t func = g_func.load(); - if(func == ::_passthrough) - return "passthrough"; - if(func == ::_path_hash) - return "path-hash"; - if(func == ::_path_hash32) - return "path-hash32"; - if(func == ::_devino_hash) - return "devino-hash"; - if(func == ::_devino_hash32) - return "devino-hash32"; - if(func == ::_hybrid_hash) - return "hybrid-hash"; - if(func == ::_hybrid_hash32) - return "hybrid-hash32"; + switch(::_algo_from_func(g_func.load())) + { + case fs::inode::Algo::PASSTHROUGH: + return "passthrough"; + case fs::inode::Algo::PATH_HASH: + return "path-hash"; + case fs::inode::Algo::PATH_HASH32: + return "path-hash32"; + case fs::inode::Algo::DEVINO_HASH: + return "devino-hash"; + case fs::inode::Algo::DEVINO_HASH32: + return "devino-hash32"; + case fs::inode::Algo::HYBRID_HASH: + return "hybrid-hash"; + case fs::inode::Algo::HYBRID_HASH32: + return "hybrid-hash32"; + } return {}; } +fs::inode::ReaddirCalc::ReaddirCalc(const fs::path &branch_path_, + const fs::path &dirpath_) + : _algo(::_algo_from_func(g_func.load())), + _branch_seed(::_branch_seed(branch_path_.native())), + _fusepath((dirpath_ / "__mergerfs__").native()), + _filename_offset(_fusepath.size() - std::string_view("__mergerfs__").size()) +{ +} + +u64 +fs::inode::ReaddirCalc::calc(const char *name_, + const std::size_t namelen_, + const mode_t mode_, + const ino_t ino_) +{ + switch(_algo) + { + case Algo::PASSTHROUGH: + return ino_; + case Algo::DEVINO_HASH: + return ::_devino_hash_from_seed(_branch_seed,ino_); + case Algo::DEVINO_HASH32: + return ::_h64_to_h32(::_devino_hash_from_seed(_branch_seed,ino_)); + case Algo::HYBRID_HASH: + if(!S_ISDIR(mode_)) + return ::_devino_hash_from_seed(_branch_seed,ino_); + break; + case Algo::HYBRID_HASH32: + if(!S_ISDIR(mode_)) + return ::_h64_to_h32(::_devino_hash_from_seed(_branch_seed,ino_)); + break; + case Algo::PATH_HASH: + case Algo::PATH_HASH32: + break; + } + + _fusepath.resize(_filename_offset); + _fusepath.append(name_,namelen_); + + return ::_calc_with_algo(_algo, + _branch_seed, + _fusepath, + mode_, + ino_); +} + u64 fs::inode::calc(const std::string &branch_path_, const std::string &fusepath_, const mode_t mode_, const ino_t ino_) { - return g_func.load()(branch_path_,fusepath_,mode_,ino_); + return g_func.load()(branch_path_, + fusepath_, + mode_, + ino_); +} + +u64 +fs::inode::calc(const fs::path &branch_path_, + const fs::path &fusepath_, + const mode_t mode_, + const ino_t ino_) +{ + return g_func.load()(branch_path_.native(), + fusepath_.native(), + mode_, + ino_); } void @@ -210,6 +370,17 @@ fs::inode::calc(const std::string &branch_path_, st_->st_ino); } +void +fs::inode::calc(const fs::path &branch_path_, + const fs::path &fusepath_, + struct stat *st_) +{ + st_->st_ino = calc(branch_path_, + fusepath_, + st_->st_mode, + st_->st_ino); +} + void fs::inode::calc(const std::string &branch_path_, const std::string &fusepath_, @@ -220,3 +391,14 @@ fs::inode::calc(const std::string &branch_path_, st_->mode, st_->ino); } + +void +fs::inode::calc(const fs::path &branch_path_, + const fs::path &fusepath_, + struct fuse_statx *st_) +{ + st_->ino = calc(branch_path_, + fusepath_, + st_->mode, + st_->ino); +} diff --git a/src/fs_inode.hpp b/src/fs_inode.hpp index 877807a9..36ecc0b9 100644 --- a/src/fs_inode.hpp +++ b/src/fs_inode.hpp @@ -19,9 +19,12 @@ #pragma once #include "base_types.h" +#include "fs_path.hpp" #include "fuse_kernel.h" +#include #include +#include #include @@ -30,6 +33,36 @@ namespace fs { namespace inode { + enum class Algo + { + PASSTHROUGH, + PATH_HASH, + PATH_HASH32, + DEVINO_HASH, + DEVINO_HASH32, + HYBRID_HASH, + HYBRID_HASH32, + }; + + class ReaddirCalc + { + public: + ReaddirCalc(const fs::path &branch_path, + const fs::path &dirpath); + + public: + u64 calc(const char *name, + const size_t namelen, + const mode_t mode, + const ino_t ino); + + private: + Algo _algo; + u64 _branch_seed; + std::string _fusepath; + std::size_t _filename_offset; + }; + int set_algo(const std::string &s); std::string get_algo(void); @@ -37,12 +70,22 @@ namespace fs const std::string &fusepath, const mode_t mode, const ino_t ino); + u64 calc(const fs::path &basepath, + const fs::path &fusepath, + const mode_t mode, + const ino_t ino); void calc(const std::string &basepath, const std::string &fusepath, struct stat *st); + void calc(const fs::path &basepath, + const fs::path &fusepath, + struct stat *st); void calc(const std::string &basepath, const std::string &fusepath, struct fuse_statx *st); + void calc(const fs::path &basepath, + const fs::path &fusepath, + struct fuse_statx *st); } }