summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Ohly <patrick.ohly@intel.com>2012-08-24 15:33:50 +0200
committerPatrick Ohly <patrick.ohly@intel.com>2012-08-29 11:44:30 +0200
commitde7ff9fdc76a443ff87372ca1d91e22ce5e85236 (patch)
treed6b037d6a1e881486b49510ab0b4dcf0334a5a65
parent72033969e09934c4630fba20585f8b47c85358e8 (diff)
engine: override merge optionspbap
In caching mode, the local data is meant to be an exact copy of the client's data. If the client removes fields in an item and then does a slow sync, no fields of a matching server item are meant to be preserved (= merged). This can be achieved with merge=no in the field list. But the field list is static and shared between data stores, which might not all operate in caching mode. This makes updating the config cumbersome. Therefore this patch adds a flag to the merging functions instead which overrides the configured behavior such that fields are always copied from one side into the other. This is activated when in caching mode and also (optionally) via the MERGEITEMS() function. The comparison is still needed, to determine whether anything changed at all during a slow sync and prevent unnecessary database writes. The loosing side is always the server in caching mode, no need to check (similar to making the local store read-only). This all applies to "slow sync" and "conflict" code paths. In caching mode, a <mergescript> is currently ignored in favor of doing the intended copying directly. Needs to be fixed.
-rw-r--r--src/sysync/localengineds.cpp20
-rwxr-xr-xsrc/sysync/multifielditem.cpp26
-rwxr-xr-xsrc/sysync/multifielditem.h4
-rwxr-xr-xsrc/sysync/multifielditemtype.cpp7
-rwxr-xr-xsrc/sysync/syncitem.h7
5 files changed, 45 insertions, 19 deletions
diff --git a/src/sysync/localengineds.cpp b/src/sysync/localengineds.cpp
index f6c5be4..c81c412 100644
--- a/src/sysync/localengineds.cpp
+++ b/src/sysync/localengineds.cpp
@@ -5652,6 +5652,10 @@ bool TLocalEngineDS::engProcessRemoteItemAsServer(
PDEBUGPRINTFX(DBG_DATA,("Read-Only or IgnoreUpdate: server always wins"));
crstrategy=cr_server_wins;
}
+ else if (fCacheData) {
+ PDEBUGPRINTFX(DBG_DATA,("Caching data: client always wins"));
+ crstrategy=cr_client_wins;
+ }
else {
// two-way
crstrategy = fItemConflictStrategy; // get conflict strategy pre-set for this item
@@ -5849,7 +5853,7 @@ bool TLocalEngineDS::engProcessRemoteItemAsServer(
aStatusCommand.setStatusCode(208); // client wins
fConflictsClientWins++;
// - attempt to merge data from loosing item (accumulating fields)
- if (!deleteconflict) {
+ if (!fCacheData && !deleteconflict) {
aSyncItemP->mergeWith(*conflictingItemP,changedincoming,changedexisting,this);
}
if (changedincoming) {
@@ -5977,11 +5981,19 @@ bool TLocalEngineDS::engProcessRemoteItemAsServer(
}
// if adds prevented, we cannot duplicate, let server win
if (fPreventAdd && crstrategy==cr_duplicate) crstrategy=cr_server_wins;
+ else if (fCacheData) crstrategy=cr_client_wins;
// now execute chosen strategy
if (crstrategy==cr_client_wins) {
- // - merge server's data into client item
- PDEBUGPRINTFX(DBG_DATA,("Trying to merge some data from loosing server item into winning client item"));
- aSyncItemP->mergeWith(*matchingItemP,changedincoming,changedexisting,this);
+ if (fCacheData) {
+ // - merge server's data into client item
+ PDEBUGPRINTFX(DBG_DATA,("Caching: copying winning client item into loosing server item"));
+ aSyncItemP->mergeWith(*matchingItemP,changedincoming,changedexisting,this,
+ TSyncItem::MERGE_OPTION_CHANGE_OTHER);
+ } else {
+ // - merge server's data into client item
+ PDEBUGPRINTFX(DBG_DATA,("Trying to merge some data from loosing server item into winning client item"));
+ aSyncItemP->mergeWith(*matchingItemP,changedincoming,changedexisting,this);
+ }
// only count if server gets updated
if (changedexisting) fConflictsClientWins++;
// Note: changedexisting will cause needserverupdate to be set below
diff --git a/src/sysync/multifielditem.cpp b/src/sysync/multifielditem.cpp
index 3436c29..3d00435 100755
--- a/src/sysync/multifielditem.cpp
+++ b/src/sysync/multifielditem.cpp
@@ -1356,15 +1356,15 @@ bool TMultiFieldItem::checkItem(TLocalEngineDS *aDatastoreP)
// - also updates other item to make sure it is equal to the winning after the merge
// sets (but does not reset) change status of this and other item.
// Note that changes of non-relevant fields are not reported here.
-void TMultiFieldItem::mergeWith(TSyncItem &aItem, bool &aChangedThis, bool &aChangedOther, TLocalEngineDS *aDatastoreP)
+void TMultiFieldItem::mergeWith(TSyncItem &aItem, bool &aChangedThis, bool &aChangedOther, TLocalEngineDS *aDatastoreP, int mode)
{
TMultiFieldItem *multifielditemP = castToSameTypeP(&aItem);
if (!multifielditemP) return;
// do the merge
- if (fItemTypeP)
+ if (fItemTypeP && mode == MERGE_OPTION_FROM_CONFIG)
fItemTypeP->mergeItems(*this,*multifielditemP,aChangedThis,aChangedOther,aDatastoreP);
else
- standardMergeWith(*multifielditemP,aChangedThis,aChangedOther);
+ standardMergeWith(*multifielditemP,aChangedThis,aChangedOther, mode);
// show result
OBJDEBUGPRINTFX(getItemType()->getSession(),DBG_DATA+DBG_CONFLICT,(
"mergeWith() final status: thisitem: %schanged, otheritem: %schanged (relevant; eqm_none field changes are not indicated)",
@@ -1380,7 +1380,8 @@ void TMultiFieldItem::mergeWith(TSyncItem &aItem, bool &aChangedThis, bool &aCha
// - also updates other item to make sure it is equal to the winning after the merge
// returns update status of this and other item. Note that changes of non-relevant fields are
// not reported here.
-void TMultiFieldItem::standardMergeWith(TMultiFieldItem &aItem, bool &aChangedThis, bool &aChangedOther)
+void TMultiFieldItem::standardMergeWith(TMultiFieldItem &aItem, bool &aChangedThis, bool &aChangedOther,
+ int mode)
{
// same type of multifield, try to merge
for (sInt16 i=0; i<fFieldDefinitionsP->numFields(); i++) {
@@ -1401,7 +1402,7 @@ void TMultiFieldItem::standardMergeWith(TMultiFieldItem &aItem, bool &aChangedTh
bool winning = winningField.isAssigned();
bool loosing = loosingField.isAssigned();
// - now decide what to do
- if (sep!=mem_none) {
+ if (sep!=mem_none && mode == MERGE_OPTION_FROM_CONFIG) {
// merge enabled
PDEBUGPRINTFX(DBG_DATA+DBG_CONFLICT,(
"Field '%s' available and enabled for merging, mode/sep=0x%04hX, %srelevant",
@@ -1483,7 +1484,11 @@ void TMultiFieldItem::standardMergeWith(TMultiFieldItem &aItem, bool &aChangedTh
// assignment just passes the proxy)
if (!mergerelevant) {
// everything is handled by the field assignment mechanisms
- loosingField = winningField;
+ if (mode == MERGE_OPTION_CHANGE_THIS) {
+ winningField = loosingField;
+ } else {
+ loosingField = winningField;
+ }
}
else if (winningField!=loosingField) {
// merge relevant fields will get more sophisticated treatment, such
@@ -1498,16 +1503,17 @@ void TMultiFieldItem::standardMergeWith(TMultiFieldItem &aItem, bool &aChangedTh
FMT_LENGTH_LIMITED(30,wfv.c_str()),FMT_LENGTH_LIMITED(30,lfv.c_str())
));
#endif
- // update loosing item, too
- if (loosingField.isShortVers(winningField,fItemTypeP->getFieldOptions(i)->maxsize)) {
+ // update loosing item, too, unless the winning field is shorter or explicitly requested
+ if (mode == MERGE_OPTION_CHANGE_THIS ||
+ loosingField.isShortVers(winningField,fItemTypeP->getFieldOptions(i)->maxsize)) {
// winning field is short version of loosing field -> loosing field is "better", use it
winningField=loosingField;
- if (mergerelevant) aChangedThis=true;
+ aChangedThis=true;
}
else {
// standard case, loosing field is replaced by winning field
loosingField=winningField;
- if (mergerelevant) aChangedOther=true;
+ aChangedOther=true;
}
// this is some kind of item-level merge as well
#ifdef SYDEBUG
diff --git a/src/sysync/multifielditem.h b/src/sysync/multifielditem.h
index 0582f66..0cc14bd 100755
--- a/src/sysync/multifielditem.h
+++ b/src/sysync/multifielditem.h
@@ -325,9 +325,9 @@ public:
// - also updates other item to make sure it is equal to the winning after the merge
// sets (but does not reset) change status of this and other item.
// Note that changes of non-relevant fields are not reported here.
- virtual void mergeWith(TSyncItem &aItem, bool &aChangedThis, bool &aChangedOther, TLocalEngineDS *aDatastoreP);
+ virtual void mergeWith(TSyncItem &aItem, bool &aChangedThis, bool &aChangedOther, TLocalEngineDS *aDatastoreP, int mode = MERGE_OPTION_FROM_CONFIG);
// standard merge (subset of mergeWith, used if no merge script is defined)
- void standardMergeWith(TMultiFieldItem &aItem, bool &aChangedThis, bool &aChangedOther);
+ void standardMergeWith(TMultiFieldItem &aItem, bool &aChangedThis, bool &aChangedOther, int mode = MERGE_OPTION_FROM_CONFIG);
// compare: returns 0 if equal, 1 if this > aItem, -1 if this < aItem
// SYSYNC_NOT_COMPARABLE if not equal and no ordering known
virtual sInt16 compareWith(
diff --git a/src/sysync/multifielditemtype.cpp b/src/sysync/multifielditemtype.cpp
index 02d629f..6dd32d9 100755
--- a/src/sysync/multifielditemtype.cpp
+++ b/src/sysync/multifielditemtype.cpp
@@ -189,12 +189,15 @@ public:
}; // func_IgnoreUpdate
- // void MERGEFIELDS()
+ // void MERGEFIELDS(mode = 0)
+ // Optional mode parameter determines the result of the merge.
+ // 0 = according to config, 1 = loosing item is overwritten, 2 = winning item is overwritten
static void func_MergeFields(TItemField *&aTermP, TScriptContext *aFuncContextP)
{
TMultiFieldItemType *mfitP = static_cast<TMultiFieldItemType *>(aFuncContextP->getCallerContext());
if (mfitP->fFirstItemP)
- mfitP->fFirstItemP->standardMergeWith(*(mfitP->fSecondItemP),mfitP->fChangedFirst,mfitP->fChangedSecond);
+ mfitP->fFirstItemP->standardMergeWith(*(mfitP->fSecondItemP),mfitP->fChangedFirst,mfitP->fChangedSecond,
+ aFuncContextP->getLocalVar(0)->getAsInteger());
}; // func_MergeFields
diff --git a/src/sysync/syncitem.h b/src/sysync/syncitem.h
index df40c15..ae455c9 100755
--- a/src/sysync/syncitem.h
+++ b/src/sysync/syncitem.h
@@ -126,13 +126,18 @@ public:
virtual bool replaceDataFrom(TSyncItem & /* aItem */, bool /* aAvailableOnly */=false, bool /* aDetectCutoffs */=false, bool /* aAssignedOnly */=false, bool /* aTransferUnassigned */=false) { return true; }; // no data -> nop
// check item before processing it
virtual bool checkItem(TLocalEngineDS * /* aDatastoreP */) { return true; }; // default is: ok
+ enum {
+ MERGE_OPTION_FROM_CONFIG, /**< merge as defined in the field list */
+ MERGE_OPTION_CHANGE_OTHER, /**< ensure that the other item is the same as this item */
+ MERGE_OPTION_CHANGE_THIS /**< ensure that this items is the same as the other */
+ };
// merge this item with specified item.
// Notes:
// - specified item is treated as loosing item, this item is winning item
// - also updates other item to make sure it is equal to the winning after the merge
// sets (but does not reset) change status of this and other item.
// Note that changes of non-relevant fields are not reported here.
- virtual void mergeWith(TSyncItem & /* aItem */, bool &aChangedThis, bool &aChangedOther, TLocalEngineDS * /* aDatastoreP */) { aChangedThis=false; aChangedOther=false; }; // nop by default
+ virtual void mergeWith(TSyncItem & /* aItem */, bool &aChangedThis, bool &aChangedOther, TLocalEngineDS * /* aDatastoreP */, int mode = MERGE_OPTION_FROM_CONFIG) { aChangedThis=false; aChangedOther=false; }; // nop by default
// remote and local ID
string fRemoteID; // ID in remote party (if this is a server: LUID, GUID otherwise)
string fLocalID; // ID in this party (if this is a server: GUID, LUID otherwise)