Fixed flushing dirty data and compressed the cache size
This commit is contained in:
parent
852e6ee4c6
commit
d9f6469b7b
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
11
src/s3fs.cpp
11
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.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue