Additional bug fixing for not creating zero-byte object

This commit is contained in:
Takeshi Nakatani 2021-05-07 18:24:36 +00:00 committed by Andrew Gaul
parent 42f5965d8a
commit b5fef788da
3 changed files with 89 additions and 13 deletions

View File

@ -100,7 +100,9 @@ inline bool IsExpireStatCacheTime(const struct timespec& ts, const time_t& expir
{
struct timespec nowts;
SetStatCacheTime(nowts);
return ((ts.tv_sec + expire) < nowts.tv_sec);
nowts.tv_sec -= expire;
return (0 < CompareStatCacheTime(nowts, ts));
}
//
@ -258,7 +260,7 @@ bool StatCache::GetStat(const std::string& key, struct stat* pst, headers_t* met
if(iter != stat_cache.end() && (*iter).second){
stat_cache_entry* ent = (*iter).second;
if(!IsExpireTime || !IsExpireStatCacheTime(ent->cache_date, ExpireTime)){
if(0 < ent->notruncate || !IsExpireTime || !IsExpireStatCacheTime(ent->cache_date, ExpireTime)){
if(ent->noobjcache){
if(!IsCacheNoObject){
// need to delete this cache.
@ -343,7 +345,8 @@ bool StatCache::IsNoObjectCache(const std::string& key, bool overcheck)
}
if(iter != stat_cache.end() && (*iter).second) {
if(!IsExpireTime || !IsExpireStatCacheTime((*iter).second->cache_date, ExpireTime)){
stat_cache_entry* ent = (*iter).second;
if(0 < ent->notruncate || !IsExpireTime || !IsExpireStatCacheTime((*iter).second->cache_date, ExpireTime)){
if((*iter).second->noobjcache){
// noobjcache = true means no object.
SetStatCacheTime((*iter).second->cache_date);
@ -434,6 +437,47 @@ bool StatCache::AddStat(const std::string& key, headers_t& meta, bool forcedir,
return true;
}
// [NOTE]
// Updates only meta data if cached data exists.
// And when these are updated, it also updates the cache time.
//
bool StatCache::UpdateMetaStats(const std::string& key, headers_t& meta)
{
if(CacheSize < 1){
return true;
}
S3FS_PRN_INFO3("update stat cache entry[path=%s]", key.c_str());
AutoLock lock(&StatCache::stat_cache_lock);
stat_cache_t::iterator iter = stat_cache.find(key);
if(stat_cache.end() == iter || !(iter->second)){
return true;
}
stat_cache_entry* ent = iter->second;
// update only meta keys
for(headers_t::iterator metaiter = meta.begin(); metaiter != meta.end(); ++metaiter){
std::string tag = lower(metaiter->first);
std::string value = metaiter->second;
if(tag == "content-type"){
ent->meta[metaiter->first] = value;
}else if(tag == "content-length"){
ent->meta[metaiter->first] = value;
}else if(tag == "etag"){
ent->meta[metaiter->first] = value;
}else if(tag == "last-modified"){
ent->meta[metaiter->first] = value;
}else if(is_prefix(tag.c_str(), "x-amz")){
ent->meta[tag] = value; // key is lower case for "x-amz"
}
}
// Update time.
SetStatCacheTime(ent->cache_date);
return true;
}
bool StatCache::AddNoObjectCache(const std::string& key)
{
if(!IsCacheNoObject){

View File

@ -158,6 +158,9 @@ class StatCache
// Add stat cache
bool AddStat(const std::string& key, headers_t& meta, bool forcedir = false, bool no_truncate = false);
// Update meta stats
bool UpdateMetaStats(const std::string& key, headers_t& meta);
// Change no truncate flag
void ChangeNoTruncateFlag(const std::string& key, bool no_truncate);

View File

@ -385,7 +385,6 @@ static int get_object_attribute(const char* path, struct stat* pstbuf, headers_t
strpath += "/";
}
if(StatCache::getStatCacheData()->GetStat(strpath, pstat, pheader, overcheck, pisforce)){
StatCache::getStatCacheData()->ChangeNoTruncateFlag(strpath, add_no_truncate_cache);
return 0;
}
if(StatCache::getStatCacheData()->IsNoObjectCache(strpath)){
@ -980,7 +979,16 @@ static int s3fs_create(const char* _path, mode_t mode, struct fuse_file_info* fi
meta["x-amz-meta-atime"] = str(now);
meta["x-amz-meta-mtime"] = str(now);
meta["x-amz-meta-ctime"] = str(now);
if(!StatCache::getStatCacheData()->AddStat(path, meta)){
// [NOTE] set no_truncate flag
// At this point, the file has not been created(uploaded) and
// the data is only present in the Stats cache.
// The Stats cache should not be deleted automatically by
// timeout. If this stats is deleted, s3fs will try to get it
// from the server with a Head request and will get an
// unexpected error because the result object does not exist.
//
if(!StatCache::getStatCacheData()->AddStat(path, meta, false, true)){
return -EIO;
}
@ -1066,9 +1074,9 @@ static int s3fs_unlink(const char* _path)
}
S3fsCurl s3fscurl;
result = s3fscurl.DeleteRequest(path);
FdManager::DeleteCacheFile(path);
StatCache::getStatCacheData()->DelStat(path);
StatCache::getStatCacheData()->DelSymlink(path);
FdManager::DeleteCacheFile(path);
S3FS_MALLOCTRIM(0);
return result;
@ -1671,6 +1679,9 @@ static int s3fs_chmod(const char* _path, mode_t mode)
// then the meta is pending and accumulated to be put after the upload is complete.
S3FS_PRN_INFO("meta pending until upload is complete");
need_put_header = false;
// If there is data in the Stats cache, update the Stats cache.
StatCache::getStatCacheData()->UpdateMetaStats(strpath, updatemeta);
}
}
if(need_put_header){
@ -1845,6 +1856,9 @@ static int s3fs_chown(const char* _path, uid_t uid, gid_t gid)
// then the meta is pending and accumulated to be put after the upload is complete.
S3FS_PRN_INFO("meta pending until upload is complete");
need_put_header = false;
// If there is data in the Stats cache, update the Stats cache.
StatCache::getStatCacheData()->UpdateMetaStats(strpath, updatemeta);
}
}
if(need_put_header){
@ -2026,6 +2040,9 @@ static int s3fs_utimens(const char* _path, const struct timespec ts[2])
need_put_header = false;
ent->SetHoldingMtime(ts[1]); // ts[1] is mtime
// If there is data in the Stats cache, update the Stats cache.
StatCache::getStatCacheData()->UpdateMetaStats(strpath, updatemeta);
}else{
S3FS_PRN_INFO("meta is not pending, but need to keep current mtime.");
@ -2223,15 +2240,20 @@ static int s3fs_open(const char* _path, struct fuse_file_info* fi)
return -EACCES;
}
// clear stat for reading fresh stat.
// (if object stat is changed, we refresh it. then s3fs gets always
// stat when s3fs open the object).
// [NOTE]
// Delete the Stats cache only if the file is not open.
// If the file is open, the stats cache will not be deleted as
// there are cases where the object does not exist on the server
// and only the Stats cache exists.
//
if(StatCache::getStatCacheData()->HasStat(path)){
// flush any dirty data so that subsequent stat gets correct size
if((result = s3fs_flush(_path, fi)) != 0){
S3FS_PRN_ERR("could not flush(%s): result=%d", path, result);
AutoFdEntity autoent_local;
if(NULL == autoent_local.ExistOpen(path, -1, true)){
if((result = s3fs_flush(_path, fi)) != 0){
S3FS_PRN_ERR("could not flush(%s): result=%d", path, result);
}
StatCache::getStatCacheData()->DelStat(path);
}
StatCache::getStatCacheData()->DelStat(path);
}
int mask = (O_RDONLY != (fi->flags & O_ACCMODE) ? W_OK : R_OK);
@ -2390,6 +2412,7 @@ static int s3fs_flush(const char* _path, struct fuse_file_info* fi)
ent->UpdateMtime(true); // clear the flag not to update mtime.
ent->UpdateCtime();
result = ent->Flush(false);
StatCache::getStatCacheData()->DelStat(path);
}
S3FS_MALLOCTRIM(0);
@ -3048,6 +3071,9 @@ static int s3fs_setxattr(const char* path, const char* name, const char* value,
// then the meta is pending and accumulated to be put after the upload is complete.
S3FS_PRN_INFO("meta pending until upload is complete");
need_put_header = false;
// If there is data in the Stats cache, update the Stats cache.
StatCache::getStatCacheData()->UpdateMetaStats(strpath, updatemeta);
}
}
if(need_put_header){
@ -3318,6 +3344,9 @@ static int s3fs_removexattr(const char* path, const char* name)
// then the meta is pending and accumulated to be put after the upload is complete.
S3FS_PRN_INFO("meta pending until upload is complete");
need_put_header = false;
// If there is data in the Stats cache, update the Stats cache.
StatCache::getStatCacheData()->UpdateMetaStats(strpath, updatemeta);
}
}
if(need_put_header){