Merge pull request #371 from ggtakec/master

Always set stats cache for opened file
This commit is contained in:
Takeshi Nakatani 2016-03-13 15:15:30 +09:00
commit fbd8959d69
3 changed files with 63 additions and 11 deletions

View File

@ -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()){

View File

@ -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);

View File

@ -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<ssize_t>(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. :-(