From 67efc11d9494b65aad6412f20986b5a14e698695 Mon Sep 17 00:00:00 2001 From: Takeshi Nakatani Date: Sun, 13 Mar 2016 05:43:28 +0000 Subject: [PATCH] Always set stats cache for opened file --- src/cache.cpp | 38 +++++++++++++++++++++++++++++++++++--- src/cache.h | 8 ++++++-- src/s3fs.cpp | 28 ++++++++++++++++++++++------ 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/cache.cpp b/src/cache.cpp index cb0a2d0..b1ac1ff 100644 --- a/src/cache.cpp +++ b/src/cache.cpp @@ -328,9 +328,9 @@ bool StatCache::IsNoObjectCache(string& key, bool overcheck) return false; } -bool StatCache::AddStat(std::string& key, headers_t& meta, bool forcedir) +bool StatCache::AddStat(std::string& key, headers_t& meta, bool forcedir, bool no_truncate) { - if(CacheSize< 1){ + if(!no_truncate && CacheSize< 1){ return true; } S3FS_PRN_INFO3("add stat cache entry[path=%s]", key.c_str()); @@ -361,6 +361,7 @@ bool StatCache::AddStat(std::string& key, headers_t& meta, bool forcedir) ent->hit_count = 0; ent->isforce = forcedir; ent->noobjcache = false; + ent->notruncate = (no_truncate ? 1L : 0L); ent->meta.clear(); SetStatCacheTime(ent->cache_date); // Set time. //copy only some keys @@ -420,6 +421,7 @@ bool StatCache::AddNoObjectCache(string& key) ent->hit_count = 0; ent->isforce = false; ent->noobjcache = true; + ent->notruncate = 0L; ent->meta.clear(); SetStatCacheTime(ent->cache_date); // Set time. // add @@ -430,6 +432,27 @@ bool StatCache::AddNoObjectCache(string& key) return true; } +void StatCache::ChangeNoTruncateFlag(std::string key, bool no_truncate) +{ + pthread_mutex_lock(&StatCache::stat_cache_lock); + + stat_cache_t::iterator iter = stat_cache.find(key); + + if(stat_cache.end() != iter){ + stat_cache_entry* ent = iter->second; + if(ent){ + if(no_truncate){ + ++(ent->notruncate); + }else{ + if(0L < ent->notruncate){ + --(ent->notruncate); + } + } + } + } + pthread_mutex_unlock(&StatCache::stat_cache_lock); +} + bool StatCache::TruncateCache(void) { if(stat_cache.empty()){ @@ -442,7 +465,7 @@ bool StatCache::TruncateCache(void) if(IsExpireTime){ for(stat_cache_t::iterator iter = stat_cache.begin(); iter != stat_cache.end(); ){ stat_cache_entry* entry = iter->second; - if(!entry || IsExpireStatCacheTime(entry->cache_date, ExpireTime)){ + if(!entry || (0L < entry->notruncate && IsExpireStatCacheTime(entry->cache_date, ExpireTime))){ stat_cache.erase(iter++); }else{ ++iter; @@ -460,6 +483,15 @@ bool StatCache::TruncateCache(void) size_t erase_count= stat_cache.size() - CacheSize + 1; statiterlist_t erase_iters; for(stat_cache_t::iterator iter = stat_cache.begin(); iter != stat_cache.end(); ++iter){ + // check no truncate + stat_cache_entry* ent = iter->second; + if(ent && 0L < ent->notruncate){ + // skip for no truncate entry + if(0 < erase_count){ + --erase_count; // decrement + } + } + // iter is not have notruncate flag erase_iters.push_back(iter); sort(erase_iters.begin(), erase_iters.end(), sort_statiterlist()); if(erase_count < erase_iters.size()){ diff --git a/src/cache.h b/src/cache.h index 7dab659..63e5664 100644 --- a/src/cache.h +++ b/src/cache.h @@ -33,8 +33,9 @@ struct stat_cache_entry { headers_t meta; bool isforce; bool noobjcache; // Flag: cache is no object for no listing. + unsigned long notruncate; // 0<: not remove automatically at checking truncate - stat_cache_entry() : hit_count(0), isforce(false), noobjcache(false) { + stat_cache_entry() : hit_count(0), isforce(false), noobjcache(false), notruncate(0L) { memset(&stbuf, 0, sizeof(struct stat)); cache_date.tv_sec = 0; cache_date.tv_nsec = 0; @@ -112,7 +113,10 @@ class StatCache bool AddNoObjectCache(std::string& key); // Add stat cache - bool AddStat(std::string& key, headers_t& meta, bool forcedir = false); + bool AddStat(std::string& key, headers_t& meta, bool forcedir = false, bool no_truncate = false); + + // Change no truncate flag + void ChangeNoTruncateFlag(std::string key, bool no_truncate); // Delete stat cache bool DelStat(const char* key); diff --git a/src/s3fs.cpp b/src/s3fs.cpp index c0c941b..999a547 100644 --- a/src/s3fs.cpp +++ b/src/s3fs.cpp @@ -134,7 +134,7 @@ static s3fs_log_level set_s3fs_log_level(s3fs_log_level level); static s3fs_log_level bumpup_s3fs_log_level(void); static bool is_special_name_folder_object(const char* path); static int chk_dir_object_type(const char* path, string& newpath, string& nowpath, string& nowcache, headers_t* pmeta = NULL, int* pDirType = NULL); -static int get_object_attribute(const char* path, struct stat* pstbuf, headers_t* pmeta = NULL, bool overcheck = true, bool* pisforce = NULL); +static int get_object_attribute(const char* path, struct stat* pstbuf, headers_t* pmeta = NULL, bool overcheck = true, bool* pisforce = NULL, bool add_no_truncate_cache = false); static int check_object_access(const char* path, int mask, struct stat* pstbuf); static int check_object_owner(const char* path, struct stat* pstbuf); static int check_parent_object_access(const char* path, int mask); @@ -389,7 +389,7 @@ static int chk_dir_object_type(const char* path, string& newpath, string& nowpat // 2) "dir/" // 3) "dir_$folder$" // -static int get_object_attribute(const char* path, struct stat* pstbuf, headers_t* pmeta, bool overcheck, bool* pisforce) +static int get_object_attribute(const char* path, struct stat* pstbuf, headers_t* pmeta, bool overcheck, bool* pisforce, bool add_no_truncate_cache) { int result = -1; struct stat tmpstbuf; @@ -426,6 +426,7 @@ static int get_object_attribute(const char* path, struct stat* pstbuf, headers_t (*pisforce) = false; } if(StatCache::getStatCacheData()->GetStat(strpath, pstat, pheader, overcheck, pisforce)){ + StatCache::getStatCacheData()->ChangeNoTruncateFlag(strpath, add_no_truncate_cache); return 0; } if(StatCache::getStatCacheData()->IsNoObjectCache(strpath)){ @@ -507,9 +508,16 @@ static int get_object_attribute(const char* path, struct stat* pstbuf, headers_t } // Set into cache - if(0 != StatCache::getStatCacheData()->GetCacheSize()){ + // + // [NOTE] + // When add_no_truncate_cache is true, the stats is always cached. + // This cached stats is only removed by DelStat(). + // This is necessary for the case to access the attribute of opened file. + // (ex. getxattr() is called while writing to the opened file.) + // + if(add_no_truncate_cache || 0 != StatCache::getStatCacheData()->GetCacheSize()){ // add into stat cache - if(!StatCache::getStatCacheData()->AddStat(strpath, (*pheader), forcedir)){ + if(!StatCache::getStatCacheData()->AddStat(strpath, (*pheader), forcedir, add_no_truncate_cache)){ S3FS_PRN_ERR("failed adding stat cache [path=%s]", strpath.c_str()); return -ENOENT; } @@ -953,8 +961,9 @@ static int s3fs_create(const char* path, mode_t mode, struct fuse_file_info* fi) FdEntity* ent; headers_t meta; - get_object_attribute(path, NULL, &meta); + get_object_attribute(path, NULL, &meta, true, NULL, true); // no truncate cache if(NULL == (ent = FdManager::get()->Open(path, &meta, 0, -1, false, true))){ + StatCache::getStatCacheData()->DelStat(path); return -EIO; } fi->fh = ent->GetFd(); @@ -2039,8 +2048,9 @@ static int s3fs_open(const char* path, struct fuse_file_info* fi) FdEntity* ent; headers_t meta; - get_object_attribute(path, NULL, &meta); + get_object_attribute(path, NULL, &meta, true, NULL, true); // no truncate cache if(NULL == (ent = FdManager::get()->Open(path, &meta, static_cast(st.st_size), st.st_mtime, false, true))){ + StatCache::getStatCacheData()->DelStat(path); return -EIO; } @@ -2048,6 +2058,7 @@ static int s3fs_open(const char* path, struct fuse_file_info* fi) if(0 != (result = ent->RowFlush(path, true))){ S3FS_PRN_ERR("could not upload file(%s): result=%d", path, result); FdManager::get()->Close(ent); + StatCache::getStatCacheData()->DelStat(path); return result; } } @@ -2181,6 +2192,11 @@ static int s3fs_release(const char* path, struct fuse_file_info* fi) { S3FS_PRN_INFO("[path=%s][fd=%llu]", path, (unsigned long long)(fi->fh)); + // [NOTE] + // All opened file's stats is cached with no truncate flag. + // Thus we unset it here. + StatCache::getStatCacheData()->ChangeNoTruncateFlag(string(path), false); + // [NOTICE] // At first, we remove stats cache. // Because fuse does not wait for response from "release" function. :-(