Break FdEntity locks into data and metadata

Previously long-running data operations like RowFlush would block
metadata operations like GetStats and thus user readdir.  Fixes #928.
This commit is contained in:
Andrew Gaul 2019-04-15 16:28:43 +09:00
parent 21321a9d96
commit ecf13a8cb9
2 changed files with 19 additions and 12 deletions

View File

@ -623,14 +623,16 @@ int FdEntity::FillFile(int fd, unsigned char byte, off_t size, off_t start)
// FdEntity methods // FdEntity methods
//------------------------------------------------ //------------------------------------------------
FdEntity::FdEntity(const char* tpath, const char* cpath) FdEntity::FdEntity(const char* tpath, const char* cpath)
: is_lock_init(false), refcnt(0), path(SAFESTRPTR(tpath)), cachepath(SAFESTRPTR(cpath)), mirrorpath(""), : is_lock_init(false), refcnt(0), path(SAFESTRPTR(tpath)),
fd(-1), pfile(NULL), is_modify(false), size_orgmeta(0), upload_id(""), mp_start(0), mp_size(0) fd(-1), pfile(NULL), size_orgmeta(0), upload_id(""), mp_start(0), mp_size(0), is_modify(false),
cachepath(SAFESTRPTR(cpath)), mirrorpath("")
{ {
try{ try{
pthread_mutexattr_t attr; pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr); pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, S3FS_MUTEX_RECURSIVE); // recursive mutex pthread_mutexattr_settype(&attr, S3FS_MUTEX_RECURSIVE); // recursive mutex
pthread_mutex_init(&fdent_lock, &attr); pthread_mutex_init(&fdent_lock, &attr);
pthread_mutex_init(&fdent_data_lock, &attr);
is_lock_init = true; is_lock_init = true;
}catch(exception& e){ }catch(exception& e){
S3FS_PRN_CRIT("failed to init mutex"); S3FS_PRN_CRIT("failed to init mutex");
@ -643,6 +645,7 @@ FdEntity::~FdEntity()
if(is_lock_init){ if(is_lock_init){
try{ try{
pthread_mutex_destroy(&fdent_data_lock);
pthread_mutex_destroy(&fdent_lock); pthread_mutex_destroy(&fdent_lock);
}catch(exception& e){ }catch(exception& e){
S3FS_PRN_CRIT("failed to destroy mutex"); S3FS_PRN_CRIT("failed to destroy mutex");
@ -654,6 +657,7 @@ FdEntity::~FdEntity()
void FdEntity::Clear() void FdEntity::Clear()
{ {
AutoLock auto_lock(&fdent_lock); AutoLock auto_lock(&fdent_lock);
AutoLock auto_data_lock(&fdent_data_lock);
if(-1 != fd){ if(-1 != fd){
if(!cachepath.empty()){ if(!cachepath.empty()){
@ -696,6 +700,7 @@ void FdEntity::Close()
abort(); abort();
} }
if(0 == refcnt){ if(0 == refcnt){
AutoLock auto_data_lock(&fdent_data_lock);
if(!cachepath.empty()){ if(!cachepath.empty()){
CacheFileStat cfstat(path.c_str()); CacheFileStat cfstat(path.c_str());
if(!pagelist.Serialize(cfstat, true)){ if(!pagelist.Serialize(cfstat, true)){
@ -796,6 +801,7 @@ int FdEntity::Open(headers_t* pmeta, off_t size, time_t time, bool no_fd_lock_wa
return -EIO; return -EIO;
} }
AutoLock auto_data_lock(&fdent_data_lock);
if(-1 != fd){ if(-1 != fd){
// already opened, needs to increment refcnt. // already opened, needs to increment refcnt.
Dup(); Dup();
@ -994,7 +1000,7 @@ bool FdEntity::OpenAndLoadAll(headers_t* pmeta, off_t* size, bool force_load)
return false; return false;
} }
} }
AutoLock auto_lock(&fdent_lock); AutoLock auto_lock(&fdent_data_lock);
if(force_load){ if(force_load){
SetAllStatusUnloaded(); SetAllStatusUnloaded();
@ -1173,7 +1179,7 @@ int FdEntity::Load(off_t start, off_t size)
if(-1 == fd){ if(-1 == fd){
return -EBADF; return -EBADF;
} }
AutoLock auto_lock(&fdent_lock); AutoLock auto_lock(&fdent_data_lock);
int result = 0; int result = 0;
@ -1475,7 +1481,7 @@ int FdEntity::RowFlush(const char* tpath, bool force_sync)
if(-1 == fd){ if(-1 == fd){
return -EBADF; return -EBADF;
} }
AutoLock auto_lock(&fdent_lock); AutoLock auto_lock(&fdent_data_lock);
if(!force_sync && !is_modify){ if(!force_sync && !is_modify){
// nothing to update. // nothing to update.
@ -1629,7 +1635,7 @@ ssize_t FdEntity::Read(char* bytes, off_t start, size_t size, bool force_load)
if(-1 == fd){ if(-1 == fd){
return -EBADF; return -EBADF;
} }
AutoLock auto_lock(&fdent_lock); AutoLock auto_lock(&fdent_data_lock);
if(force_load){ if(force_load){
pagelist.SetPageLoadedStatus(start, size, false); pagelist.SetPageLoadedStatus(start, size, false);
@ -1692,7 +1698,7 @@ ssize_t FdEntity::Write(const char* bytes, off_t start, size_t size)
if(FdManager::IsCacheDir() && !FdManager::IsSafeDiskSpace(NULL, size)){ if(FdManager::IsCacheDir() && !FdManager::IsSafeDiskSpace(NULL, size)){
FdManager::get()->CleanupCacheDir(); FdManager::get()->CleanupCacheDir();
} }
AutoLock auto_lock(&fdent_lock); AutoLock auto_lock(&fdent_data_lock);
// check file size // check file size
if(pagelist.Size() < start){ if(pagelist.Size() < start){

View File

@ -112,22 +112,23 @@ class FdEntity
private: private:
pthread_mutex_t fdent_lock; pthread_mutex_t fdent_lock;
bool is_lock_init; bool is_lock_init;
PageList pagelist;
int refcnt; // reference count int refcnt; // reference count
std::string path; // object path std::string path; // object path
std::string cachepath; // local cache file path
// (if this is empty, does not load/save pagelist.)
std::string mirrorpath; // mirror file path to local cache file path
int fd; // file descriptor(tmp file or cache file) int fd; // file descriptor(tmp file or cache file)
FILE* pfile; // file pointer(tmp file or cache file) FILE* pfile; // file pointer(tmp file or cache file)
bool is_modify; // if file is changed, this flag is true
headers_t orgmeta; // original headers at opening headers_t orgmeta; // original headers at opening
off_t size_orgmeta; // original file size in original headers off_t size_orgmeta; // original file size in original headers
pthread_mutex_t fdent_data_lock;// protects the following members
PageList pagelist;
std::string upload_id; // for no cached multipart uploading when no disk space std::string upload_id; // for no cached multipart uploading when no disk space
etaglist_t etaglist; // for no cached multipart uploading when no disk space etaglist_t etaglist; // for no cached multipart uploading when no disk space
off_t mp_start; // start position for no cached multipart(write method only) off_t mp_start; // start position for no cached multipart(write method only)
off_t mp_size; // size for no cached multipart(write method only) off_t mp_size; // size for no cached multipart(write method only)
bool is_modify; // if file is changed, this flag is true
std::string cachepath; // local cache file path
// (if this is empty, does not load/save pagelist.)
std::string mirrorpath; // mirror file path to local cache file path
private: private:
static int FillFile(int fd, unsigned char byte, off_t size, off_t start); static int FillFile(int fd, unsigned char byte, off_t size, off_t start);