summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Ohly <patrick.ohly@intel.com>2014-09-03 14:39:36 +0200
committerPatrick Ohly <patrick.ohly@intel.com>2014-09-04 17:27:09 +0200
commitfa9c56e913259101dfd054c56f3af708b002294f (patch)
tree3a871ff58f1be773d57106b722af57425f062c0d
parent115cef8a0ec1823b58808bbb9820f7cb82c2a313 (diff)
binfile: avoid unnecessary write and truncate
The goal is to leave binfile completely untouched, including its "last modified" time stamp, if nothing changes. There are cases where the upper layers will call TBinFileBase::updateRecord() and write the same data that already is in the file. Instead of catching those case-by-case, let's check at the lowest level. On btrfs (and possibly other file systems), ftruncate() bumps the "last modified" time stamp of a file even if the requested size matches the existing one. Avoid that by skipping the ftruncate() when the file already has the desired size.
-rwxr-xr-xsrc/platform_adapters/binfile.cpp21
1 files changed, 19 insertions, 2 deletions
diff --git a/src/platform_adapters/binfile.cpp b/src/platform_adapters/binfile.cpp
index e1da717..02d6c52 100755
--- a/src/platform_adapters/binfile.cpp
+++ b/src/platform_adapters/binfile.cpp
@@ -21,6 +21,7 @@
#endif
#include <string.h>
+#include <vector>
namespace sysync {
@@ -141,7 +142,20 @@ bool TBinFile::platformWriteFile(const void *aBuffer, uInt32 aBytes)
return true;
}
- return fwrite(aBuffer,aBytes,1,fCBinFile) == 1;
+ // Don't overwrite content which is already exactly what we want it
+ // to be.
+ std::vector<char> buffer(aBytes);
+ char *addr = &buffer.front();
+ long offset = ftell(fCBinFile);
+ if (offset == -1)
+ return false;
+ if (fread(addr,aBytes,1,fCBinFile) != 1 ||
+ memcmp(addr,aBuffer,aBytes)) {
+ return fseek(fCBinFile,offset,SEEK_SET) == 0 &&
+ fwrite(aBuffer,aBytes,1,fCBinFile) == 1;
+ } else {
+ return true;
+ }
} // TBinFile::platformWriteFile
@@ -167,7 +181,10 @@ bool TBinFile::platformTruncateFile(uInt32 aNewSize)
#if defined(LINUX) || defined(MACOSX)
fflush(fCBinFile); // unbuffer everything
int fd = fileno(fCBinFile); // get file descriptor
- if (ftruncate(fd,aNewSize)) {
+ struct stat buffer;
+ if (fstat(fd, &buffer) ||
+ buffer.st_size == (off_t)aNewSize || // avoid modifying file if it already has the right size
+ ftruncate(fd,aNewSize)) {
; // error ignored
}
#elif defined(WIN32)