summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Ohly <patrick.ohly@intel.com>2014-08-29 10:39:17 +0200
committerPatrick Ohly <patrick.ohly@intel.com>2014-08-29 10:45:38 +0200
commit115cef8a0ec1823b58808bbb9820f7cb82c2a313 (patch)
treea7f66bad6f1512ff168c7a9b30bb53fa334bf362
parent4683fceb72cef0e7301b735a23b1f40323da52ba (diff)
binfileclient: avoid disk writes in changeLogPreflight()
During a normal sync where nothing changed, only the header gets updated. This change is not critical and thus does not have to be flushed to disk unless also some entries get added or updated. The advantage is that when SyncEvolution detects a sync where nothing changed on either side and skips the client's session shutdown, the .bfi is left unchanged, which reduces flash wearout. To detect item changes, a brute-force byte comparison is used. This requires less changes to the code and is less error-prone than adding "modified=true" to all places where "existingentries" gets modified.
-rwxr-xr-xsrc/sysync/binfileimplds.cpp24
1 files changed, 19 insertions, 5 deletions
diff --git a/src/sysync/binfileimplds.cpp b/src/sysync/binfileimplds.cpp
index 314ccc7..947fa0c 100755
--- a/src/sysync/binfileimplds.cpp
+++ b/src/sysync/binfileimplds.cpp
@@ -741,9 +741,9 @@ localstatus TBinfileImplDS::changeLogPreflight(bool &aValidChangelog)
lsd.c_str()
));
#endif
- // - save header
- err = fChangeLog.flushHeader();
- if (err!=BFE_OK) goto done;
+ // - force saving of header only if some entry changes
+ bool modified=false;
+ string origentries;
// - we don't need the changelog to be updated when all we do is refresh from server
if (isRefreshOnly()) goto done; // done ok
// - load entire existing changelog into memory
@@ -751,10 +751,12 @@ localstatus TBinfileImplDS::changeLogPreflight(bool &aValidChangelog)
PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("changeLogPreflight: at start, changelog has %ld entries",(long)numexistinglogentries));
if (numexistinglogentries>0) {
// - allocate array for all existing entries (use sysync_malloc because e.g. on PalmOS this uses special funcs to allow > 64k)
- existingentries = (TChangeLogEntry *)sysync_malloc(sizeof(TChangeLogEntry)*numexistinglogentries);
+ size_t entriessize = sizeof(TChangeLogEntry)*numexistinglogentries;
+ existingentries = (TChangeLogEntry *)sysync_malloc(entriessize);
if (!existingentries) { err=BFE_MEMORY; goto done; } // not enough memory
// - read all entries
fChangeLog.readRecord(0,existingentries,numexistinglogentries);
+ origentries.assign((char *)existingentries, entriessize);
// Mark all not-yet-deleted in the log as delete candidate
// (those that still exist will be get the candidate mark removed below)
for (logindex=0;logindex<numexistinglogentries;logindex++) {
@@ -952,6 +954,7 @@ localstatus TBinfileImplDS::changeLogPreflight(bool &aValidChangelog)
// create if entry is new
if (!chgentryexists) {
// this is a new, additional entry (and not a resurrected deleted one)
+ modified=true;
fChangeLog.newRecord(currentEntryP);
PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("- item was newly added (no entry existed in changelog before)"));
}
@@ -1033,7 +1036,18 @@ localstatus TBinfileImplDS::changeLogPreflight(bool &aValidChangelog)
}
#endif
// - write back all existing entries
- fChangeLog.updateRecord(0,existingentries,numexistinglogentries);
+ if (existingentries &&
+ memcmp(existingentries, origentries.c_str(), origentries.size())) {
+ fChangeLog.updateRecord(0,existingentries,numexistinglogentries);
+ modified=true;
+ }
+
+ // Also write updated header if (and only if) something changed.
+ if (modified) {
+ err = fChangeLog.flushHeader();
+ if (err!=BFE_OK) goto done;
+ }
+
// - now we can confirm we have a valid changelog
aValidChangelog=true;
DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,("changeLogPreflight: seen=%ld, fNumberOfLocalChanges=%ld",(long)seen,(long)fNumberOfLocalChanges));