Fixed flushing dirty data and compressed the cache size

This commit is contained in:
Takeshi Nakatani 2020-11-03 06:42:03 +00:00 committed by Andrew Gaul
parent 852e6ee4c6
commit d9f6469b7b
6 changed files with 115 additions and 3 deletions

View File

@ -32,6 +32,7 @@ AC_PROG_CC
AC_CHECK_HEADERS([sys/xattr.h])
AC_CHECK_HEADERS([attr/xattr.h])
AC_CHECK_HEADERS([sys/extattr.h])
AC_CHECK_FUNCS([fallocate])
CXXFLAGS="$CXXFLAGS -Wall -fno-exceptions -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2"

View File

@ -1601,6 +1601,71 @@ int FdEntity::UploadPendingMeta()
return result;
}
// [NOTE]
// For systems where the fallocate function cannot be detected, use a dummy function.
// ex. OSX
//
#ifndef HAVE_FALLOCATE
// We need the symbols defined in fallocate, so we define them here.
// The definitions are copied from linux/falloc.h, but if HAVE_FALLOCATE is undefined,
// these values can be anything.
//
#define FALLOC_FL_PUNCH_HOLE 0x02 /* de-allocates range */
#define FALLOC_FL_KEEP_SIZE 0x01
static int fallocate(int /*fd*/, int /*mode*/, off_t /*offset*/, off_t /*len*/)
{
errno = ENOSYS; // This is a bad idea, but the caller can handle it simply.
return -1;
}
#endif // HAVE_FALLOCATE
// [NOTE]
// This method punches an area(on cache file) that has no data at the time it is called.
// This is called to prevent the cache file from growing.
// However, this method uses the non-portable(Linux specific) system call fallocate().
// Also, depending on the file system, FALLOC_FL_PUNCH_HOLE mode may not work and HOLE
// will not open.(Filesystems for which this method works are ext4, btrfs, xfs, etc.)
//
bool FdEntity::PunchHole(off_t start, size_t size)
{
S3FS_PRN_DBG("[path=%s][fd=%d][offset=%lld][size=%zu]", path.c_str(), fd, static_cast<long long int>(start), size);
if(-1 == fd){
return false;
}
AutoLock auto_lock(&fdent_data_lock);
// get page list that have no data
fdpage_list_t nodata_pages;
if(!pagelist.GetNoDataPageLists(nodata_pages)){
S3FS_PRN_ERR("filed to get page list that have no data.");
return false;
}
if(nodata_pages.empty()){
S3FS_PRN_DBG("there is no page list that have no data, so nothing to do.");
return true;
}
// try to punch hole to file
for(fdpage_list_t::const_iterator iter = nodata_pages.begin(); iter != nodata_pages.end(); ++iter){
if(0 != fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, iter->offset, iter->bytes)){
if(ENOSYS == errno || EOPNOTSUPP == errno){
S3FS_PRN_ERR("filed to fallocate for punching hole to file with errno(%d), it maybe the fallocate function is not implemented in this kernel, or the file system does not support FALLOC_FL_PUNCH_HOLE.", errno);
}else{
S3FS_PRN_ERR("filed to fallocate for punching hole to file with errno(%d)", errno);
}
return false;
}
if(!pagelist.SetPageLoadedStatus(iter->offset, iter->bytes, PageList::PAGE_NOT_LOAD_MODIFIED)){
S3FS_PRN_ERR("succeed to punch HOLEs in the cache file, but failed to update the cache stat.");
return false;
}
S3FS_PRN_DBG("made a hole at [%lld - %lld bytes](into a boundary) of the cache file.", static_cast<long long int>(iter->offset), static_cast<long long int>(iter->bytes));
}
return true;
}
/*
* Local variables:
* tab-width: 4

View File

@ -117,6 +117,7 @@ class FdEntity
ssize_t Write(const char* bytes, off_t start, size_t size);
bool ReserveDiskSpace(off_t size);
bool PunchHole(off_t start = 0, size_t size = 0);
};
typedef std::map<std::string, class FdEntity*> fdent_map_t; // key=path, value=FdEntity*

View File

@ -689,6 +689,45 @@ bool PageList::GetPageListsForMultipartUpload(fdpage_list_t& dlpages, fdpage_lis
return true;
}
bool PageList::GetNoDataPageLists(fdpage_list_t& nodata_pages, off_t start, size_t size)
{
// compress before this processing
if(!Compress()){
return false;
}
// extract areas without data
fdpage_list_t tmp_pagelist;
off_t stop_pos = (0L == size ? -1 : (start + size));
for(fdpage_list_t::const_iterator iter = pages.begin(); iter != pages.end(); ++iter){
if((iter->offset + iter->bytes) < start){
continue;
}
if(-1 != stop_pos && stop_pos <= iter->offset){
break;
}
if(iter->modified){
continue;
}
fdpage tmppage;
tmppage.offset = std::max(iter->offset, start);
tmppage.bytes = (-1 != stop_pos ? iter->bytes : std::min(iter->bytes, (stop_pos - tmppage.offset)));
tmppage.loaded = iter->loaded;
tmppage.modified = iter->modified;
tmp_pagelist.push_back(tmppage);
}
if(tmp_pagelist.empty()){
nodata_pages.clear();
}else{
// compress
nodata_pages = compress_fdpage_list(tmp_pagelist);
}
return true;
}
off_t PageList::BytesModified() const
{
off_t total = 0;

View File

@ -109,6 +109,7 @@ class PageList
off_t GetTotalUnloadedPageSize(off_t start = 0, off_t size = 0) const; // size=0 is checking to end of list
int GetUnloadedPages(fdpage_list_t& unloaded_list, off_t start = 0, off_t size = 0) const; // size=0 is checking to end of list
bool GetPageListsForMultipartUpload(fdpage_list_t& dlpages, fdpage_list_t& mixuppages, off_t max_partsize);
bool GetNoDataPageLists(fdpage_list_t& nodata_pages, off_t start = 0, size_t size = 0);
off_t BytesModified() const;
bool IsModified() const;

View File

@ -2285,10 +2285,15 @@ static int s3fs_write(const char* _path, const char* buf, size_t size, off_t off
}
if(max_dirty_data != -1 && ent->BytesModified() >= max_dirty_data){
if(0 != (res = ent->RowFlush(path, true))){
S3FS_PRN_ERR("could not upload file(%s): result=%zd", path, res);
int flushres;
if(0 != (flushres = ent->RowFlush(path, true))){
S3FS_PRN_ERR("could not upload file(%s): result=%d", path, flushres);
StatCache::getStatCacheData()->DelStat(path);
return res;
return -EIO;
}
// Punch a hole in the file to recover disk space.
if(!ent->PunchHole()){
S3FS_PRN_WARN("could not punching HOLEs to a cache file, but continue.");
}
}