diff --git a/src/cache_node.cpp b/src/cache_node.cpp index 2028c20..2753ca9 100644 --- a/src/cache_node.cpp +++ b/src/cache_node.cpp @@ -99,6 +99,8 @@ bool StatCacheNode::IsExpireIntervalType = false; time_t StatCacheNode::ExpireTime = 15 * 60; bool StatCacheNode::UseNegativeCache = true; std::mutex StatCacheNode::cache_lock; +unsigned long StatCacheNode::DisableCheckingExpire = 0L; +struct timespec StatCacheNode::DisableExpireDate = {0, 0}; // // Class Methods @@ -162,6 +164,57 @@ bool StatCacheNode::SetNegativeCache(bool flag) return old; } +bool StatCacheNode::NeedExpireCheckHasLock(const struct timespec& ts) +{ + if(!StatCacheNode::IsEnableExpireTime()){ + return false; + } + + // [NOTE] + // If the expiration date check is disabled(0 < DisableCheckingExpire) + // and the date is later than DisableExpireDate, it is determined that + // checking is not necessary. + // + if(0L < StatCacheNode::DisableCheckingExpire){ + if(0 >= CompareStatCacheTime(StatCacheNode::DisableExpireDate, ts)){ + return false; + } + } + return true; +} + +bool StatCacheNode::PreventExpireCheck() +{ + if(!StatCacheNode::IsEnableExpireTime()){ + return false; + } + std::lock_guard lock(StatCacheNode::cache_lock); + + ++StatCacheNode::DisableCheckingExpire; + + if(0 == StatCacheNode::DisableExpireDate.tv_sec){ + SetCurrentTime(StatCacheNode::DisableExpireDate); + StatCacheNode::DisableExpireDate.tv_sec -= StatCacheNode::GetExpireTime(); + } + return true; +} + +bool StatCacheNode::ResumeExpireCheck() +{ + if(!StatCacheNode::IsEnableExpireTime()){ + return false; + } + std::lock_guard lock(StatCacheNode::cache_lock); + + if(0 < StatCacheNode::DisableCheckingExpire){ + --StatCacheNode::DisableCheckingExpire; + } + if(0 == StatCacheNode::DisableCheckingExpire){ + StatCacheNode::DisableExpireDate = {0, 0}; + } + return true; +} + //------------------------------------------------------------------- // Methods //------------------------------------------------------------------- @@ -654,7 +707,7 @@ s3obj_type_map_t::size_type StatCacheNode::GetChildMap(s3obj_type_map_t& childma bool StatCacheNode::IsExpireStatCacheTimeHasLock() const { - if(StatCacheNode::IsEnableExpireTime()){ + if(NeedExpireCheckHasLock(cache_date)){ if(IsExpireStatCacheTime(cache_date, StatCacheNode::GetExpireTime())){ // this cache is expired return true; @@ -1182,11 +1235,12 @@ std::shared_ptr DirStatCache::FindHasLock(const std::string& strp bool DirStatCache::NeedTruncateProcessing() { - if(!StatCacheNode::IsEnableExpireTime()){ + std::lock_guard lock(StatCacheNode::cache_lock); + if(!NeedExpireCheckHasLock(cache_date)){ return false; } - std::lock_guard dircachelock(dir_cache_lock); + std::lock_guard dircachelock(dir_cache_lock); return IsExpireStatCacheTime(last_check_date, StatCacheNode::GetExpireTime()); } diff --git a/src/cache_node.h b/src/cache_node.h index 0eeeaaf..5a32350 100644 --- a/src/cache_node.h +++ b/src/cache_node.h @@ -79,6 +79,8 @@ class StatCacheNode : public std::enable_shared_from_this static time_t ExpireTime; static bool UseNegativeCache; static std::mutex cache_lock; // for internal data + static unsigned long DisableCheckingExpire GUARDED_BY(cache_lock); // If greater than 0, it disables the expiration check, which allows disabling checks during processing. + static struct timespec DisableExpireDate GUARDED_BY(cache_lock); // Data registerd after this time will not be truncated(if 0 < DisableCheckingExpire) private: objtype_t cache_type GUARDED_BY(StatCacheNode::cache_lock) = objtype_t::UNKNOWN; // object type is set in the constructor(except dir). @@ -97,6 +99,7 @@ class StatCacheNode : public std::enable_shared_from_this static void IncrementCacheCount(objtype_t type); static void DecrementCacheCount(objtype_t type); static bool SetNegativeCache(bool flag); + static bool NeedExpireCheckHasLock(const struct timespec& ts) REQUIRES(StatCacheNode::cache_lock); // Cache Type bool isSameObjectTypeHasLock(objtype_t type) const REQUIRES(StatCacheNode::cache_lock); @@ -156,6 +159,8 @@ class StatCacheNode : public std::enable_shared_from_this static bool EnableNegativeCache() { return SetNegativeCache(true); } static bool DisableNegativeCache() { return SetNegativeCache(false); } static bool IsEnabledNegativeCache() { return UseNegativeCache; } + static bool PreventExpireCheck(); + static bool ResumeExpireCheck(); // Constructor/Destructor explicit StatCacheNode(const char* path = nullptr, objtype_t type = objtype_t::UNKNOWN); @@ -321,6 +326,28 @@ class NegativeStatCache : public StatCacheNode NegativeStatCache& operator=(NegativeStatCache&&) = delete; }; +//------------------------------------------------------------------- +// Utility Class : PreventStatCacheExpire +//------------------------------------------------------------------- +class PreventStatCacheExpire +{ + public: + explicit PreventStatCacheExpire() + { + StatCacheNode::PreventExpireCheck(); + } + + ~PreventStatCacheExpire() + { + StatCacheNode::ResumeExpireCheck(); + } + + PreventStatCacheExpire(const PreventStatCacheExpire&) = delete; + PreventStatCacheExpire(PreventStatCacheExpire&&) = delete; + PreventStatCacheExpire& operator=(const PreventStatCacheExpire&) = delete; + PreventStatCacheExpire& operator=(PreventStatCacheExpire&&) = delete; +}; + #endif // S3FS_CACHE_NODE_H_ /* diff --git a/src/s3fs.cpp b/src/s3fs.cpp index 5f3003e..3346810 100644 --- a/src/s3fs.cpp +++ b/src/s3fs.cpp @@ -1231,6 +1231,9 @@ static int s3fs_mkdir(const char* _path, mode_t mode) return -EIO; } + // keep stat cache without checking expiration + PreventStatCacheExpire nocacheexpire; + // check parent directory attribute. if(0 != (result = check_parent_object_access(path, W_OK | X_OK))){ return result; @@ -1322,6 +1325,9 @@ static int s3fs_rmdir(const char* _path) FUSE_CTX_INFO("[path=%s]", path); + // keep stat cache without checking expiration + PreventStatCacheExpire nocacheexpire; + if(0 != (result = check_parent_object_access(path, W_OK | X_OK))){ return result; }