From d9f6469b7b6230cc2308d358f17850207fcb9a7d Mon Sep 17 00:00:00 2001 From: Takeshi Nakatani Date: Tue, 3 Nov 2020 06:42:03 +0000 Subject: [PATCH] Fixed flushing dirty data and compressed the cache size --- configure.ac | 1 + src/fdcache_entity.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++ src/fdcache_entity.h | 1 + src/fdcache_page.cpp | 39 +++++++++++++++++++++++++ src/fdcache_page.h | 1 + src/s3fs.cpp | 11 +++++-- 6 files changed, 115 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index b434300..4c78470 100644 --- a/configure.ac +++ b/configure.ac @@ -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" diff --git a/src/fdcache_entity.cpp b/src/fdcache_entity.cpp index 9811258..0d86fa3 100644 --- a/src/fdcache_entity.cpp +++ b/src/fdcache_entity.cpp @@ -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(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(iter->offset), static_cast(iter->bytes)); + } + return true; +} + /* * Local variables: * tab-width: 4 diff --git a/src/fdcache_entity.h b/src/fdcache_entity.h index a2bc0b6..efa78c0 100644 --- a/src/fdcache_entity.h +++ b/src/fdcache_entity.h @@ -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 fdent_map_t; // key=path, value=FdEntity* diff --git a/src/fdcache_page.cpp b/src/fdcache_page.cpp index e65e94e..cf568cf 100644 --- a/src/fdcache_page.cpp +++ b/src/fdcache_page.cpp @@ -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; diff --git a/src/fdcache_page.h b/src/fdcache_page.h index 6ec222c..04dbfd0 100644 --- a/src/fdcache_page.h +++ b/src/fdcache_page.h @@ -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; diff --git a/src/s3fs.cpp b/src/s3fs.cpp index a8112f1..6de454c 100644 --- a/src/s3fs.cpp +++ b/src/s3fs.cpp @@ -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."); } }