Bug Summary

File:libsynthesis/src/sysync/superdatastore.cpp
Warning:line 724, column 15
Value stored to 'regular' is never read

Annotated Source Code

1/*
2 * File: SuperDataStore.h
3 *
4 * Author: Lukas Zeller (luz@plan44.ch)
5 *
6 * TSuperDataStore
7 * "Virtual" datastore consisting of an union of other
8 * datastores, for example a vCal datastore based on
9 * two separate vEvent and vTodo datastores.
10 *
11 * Copyright (c) 2002-2011 by Synthesis AG + plan44.ch
12 *
13 * 2002-08-05 : luz : created
14 *
15 */
16
17// includes
18#include "prefix_file.h"
19#include "sysync.h"
20#include "syncappbase.h"
21#include "superdatastore.h"
22
23#ifdef SUPERDATASTORES1
24
25
26using namespace sysync;
27
28
29// sub-datastore link config
30// =========================
31
32
33// config constructor
34TSubDSLinkConfig::TSubDSLinkConfig(TLocalDSConfig *aLocalDSConfigP, TConfigElement *aParentElementP) :
35 TConfigElement(aLocalDSConfigP->getName(),aParentElementP)
36{
37 clear();
38 fLinkedDSConfigP=aLocalDSConfigP;
39} // TSubDSLinkConfig::TSubDSLinkConfig
40
41
42// config destructor
43TSubDSLinkConfig::~TSubDSLinkConfig()
44{
45 clear();
46} // TSubDSLinkConfig::~TSubDSLinkConfig
47
48
49// init defaults
50void TSubDSLinkConfig::clear(void)
51{
52 // init defaults
53 fDispatchFilter.erase();
54 fGUIDPrefix.erase();
55 // clear inherited
56 inherited::clear();
57} // TSubDSLinkConfig::clear
58
59
60#ifndef HARDCODED_CONFIG
61
62// remote rule config element parsing
63bool TSubDSLinkConfig::localStartElement(const char *aElementName, const char **aAttributes, sInt32 aLine)
64{
65 // checking the elements
66 // - identification of remote
67 if (strucmp(aElementName,"dispatchfilter")==0)
68 expectString(fDispatchFilter);
69 else if (strucmp(aElementName,"guidprefix")==0)
70 expectString(fGUIDPrefix);
71 // - not known here
72 else
73 return inherited::localStartElement(aElementName,aAttributes,aLine);
74 // ok
75 return true;
76} // TSubDSLinkConfig::localStartElement
77
78#endif
79
80
81// superdatastore config
82// =====================
83
84TSuperDSConfig::TSuperDSConfig(const char* aName, TConfigElement *aParentElement) :
85 TLocalDSConfig(aName,aParentElement)
86{
87 clear();
88} // TSuperDSConfig::TSuperDSConfig
89
90
91TSuperDSConfig::~TSuperDSConfig()
92{
93 clear();
94} // TSuperDSConfig::~TSuperDSConfig
95
96
97// init defaults
98void TSuperDSConfig::clear(void)
99{
100 // init defaults
101 // - no datastore links
102 TSubDSConfigList::iterator pos;
103 for(pos=fSubDatastores.begin();pos!=fSubDatastores.end();pos++)
104 delete *pos;
105 fSubDatastores.clear();
106 // clear inherited
107 inherited::clear();
108} // TSuperDSConfig::clear
109
110
111#ifndef HARDCODED_CONFIG
112
113// config element parsing
114bool TSuperDSConfig::localStartElement(const char *aElementName, const char **aAttributes, sInt32 aLine)
115{
116 // checking the elements
117 // - links to sub-datastores
118 if (strucmp(aElementName,"contains")==0) {
119 // definition of a new datastore
120 const char* nam = getAttr(aAttributes,"datastore");
121 if (!nam)
122 return fail("'contains' missing 'datastore' attribute");
123 // search sub-datastore
124 TLocalDSConfig *subdscfgP =
125 static_cast<TSessionConfig *>(getParentElement())->getLocalDS(nam);
126 if (!subdscfgP)
127 return fail("unknown datastore '%s' specified",nam);
128 // create new datastore link
129 TSubDSLinkConfig *dslinkcfgP =
130 new TSubDSLinkConfig(subdscfgP,this);
131 // - save in list
132 fSubDatastores.push_back(dslinkcfgP);
133 // - let element handle parsing
134 expectChildParsing(*dslinkcfgP);
135 }
136 // - none known here
137 else
138 return TLocalDSConfig::localStartElement(aElementName,aAttributes,aLine);
139 // ok
140 return true;
141} // TSuperDSConfig::localStartElement
142
143#endif
144
145// resolve
146void TSuperDSConfig::localResolve(bool aLastPass)
147{
148 if (aLastPass) {
149 // check for required settings
150 // %%% tbd
151 }
152 // resolve inherited
153 inherited::localResolve(aLastPass);
154} // TSuperDSConfig::localResolve
155
156
157// - create appropriate datastore from config, calls addTypeSupport as well
158TLocalEngineDS *TSuperDSConfig::newLocalDataStore(TSyncSession *aSessionP)
159{
160 // Synccap defaults to normal set supported by the engine by default
161 TSuperDataStore *sdsP =
162 new TSuperDataStore(this,aSessionP,getName(),aSessionP->getSyncCapMask());
163 // add type support
164 addTypes(sdsP,aSessionP);
165 return sdsP;
166} // TLocalDSConfig::newLocalDataStore
167
168
169
170
171
172/*
173 * Implementation of TSuperDataStore
174 */
175
176/* public TSuperDataStore members */
177
178
179TSuperDataStore::TSuperDataStore(TSuperDSConfig *aDSConfigP, TSyncSession *aSessionP, const char *aName, uInt32 aCommonSyncCapMask) :
180 TLocalEngineDS(aDSConfigP, aSessionP, aName, aCommonSyncCapMask)
181{
182 // set config ptr
183 fDSConfigP = aDSConfigP;
184 if (!fDSConfigP)
185 SYSYNC_THROW(TSyncException(DEBUGTEXT("TSuperDataStore::TSuperDataStore called with NULL config","lds1")))throw TSyncException("TSuperDataStore::TSuperDataStore called with NULL config"
)
;
186 // reset first
187 InternalResetDataStore();
188 // for server, all configured subdatastores are automatically linked in
189 // (for client, only those that are active will be linked in at dsSetClientParams() time)
190 if (IS_SERVER(getSyncAppBase()->isServer())) {
191 // create links to subdatastores
192 TSubDSConfigList::iterator pos;
193 for(pos=aDSConfigP->fSubDatastores.begin();pos!=aDSConfigP->fSubDatastores.end();pos++) {
194 // add link
195 addSubDatastoreLink(*pos,NULL__null); // search datastore
196 }
197 }
198} // TSuperDataStore::TSuperDataStore
199
200
201void TSuperDataStore::addSubDatastoreLink(TSubDSLinkConfig *aDSLinkConfigP, TLocalEngineDS *aDatastoreP)
202{
203 TSubDatastoreLink link;
204 // start not yet pending
205 link.fStartPending = false;
206 // set link to subdatastore's config
207 link.fDSLinkConfigP = aDSLinkConfigP;
208 if (aDatastoreP)
209 link.fDatastoreLinkP = aDatastoreP; // we already know the datastore (for client, it might not yet be in session list of datastores)
210 else
211 link.fDatastoreLinkP = fSessionP->findLocalDataStore(link.fDSLinkConfigP->fLinkedDSConfigP); // find actual datastore by "handle" (= config pointer)
212 // make sure datastore is instantiated
213 if (!link.fDatastoreLinkP) {
214 // instantiate now (should not happen on server, as all datastores are instantiated on a server anyway)
215 link.fDatastoreLinkP=fSessionP->addLocalDataStore(link.fDSLinkConfigP->fLinkedDSConfigP);
216 }
217 // save link
218 fSubDSLinks.push_back(link);
219 // Important: We need to get the iterator now again, in case the list was empty before
220 // (because the iterator set in InternalResetDataStore() is invalid because it was created for an empty list).
221 fCurrentGenDSPos=fSubDSLinks.begin();
222}
223
224
225void TSuperDataStore::InternalResetDataStore(void)
226{
227 // init
228 fFirstTimeSync=false;
229 TSubDSLinkList::iterator pos;
230 // cancel all pending starts
231 for(pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
232 pos->fStartPending=false;
233 }
234 fSuperStartPending = false;
235 // make sure this is set in case startSync() is not called before generateSyncCommands()
236 fCurrentGenDSPos=fSubDSLinks.begin();
237} // TSuperDataStore::InternalResetDataStore
238
239
240TSuperDataStore::~TSuperDataStore()
241{
242 InternalResetDataStore();
243} // TSuperDataStore::~TSuperDataStore
244
245
246
247// Session events, which need some distribution to subdatastores
248// =============================================================
249
250// Methods overriding TLocalEngineDS
251// ----------------------------------
252
253bool TSuperDataStore::canRestart()
254{
255 TSubDSLinkList::iterator pos;
256 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
257 if (!pos->fDatastoreLinkP->canRestart()) {
258 return false;
259 }
260 }
261 return true;
262}
263
264// obtain Sync Cap mask, must be lowest common mask of all subdatastores
265uInt32 TSuperDataStore::getSyncCapMask(void)
266{
267 // AND of all subdatastores
268 uInt32 capmask = ~0; // all bits set
269 TSubDSLinkList::iterator pos;
270 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
271 capmask = capmask & pos->fDatastoreLinkP->getSyncCapMask();
272 }
273 return capmask;
274} // TSuperDataStore::getSyncCapMask
275
276bool TSuperDataStore::syncModeSupported(const std::string &mode)
277{
278 TSubDSLinkList::iterator pos;
279 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
280 if (!pos->fDatastoreLinkP->syncModeSupported(mode)) {
281 return false;
282 }
283 }
284 return true;
285}
286
287void TSuperDataStore::getSyncModes(set<string> &modes)
288{
289 // Initialize with content from first subdatastore.
290 TSubDSLinkList::iterator pos = fSubDSLinks.begin();
291 if (pos!=fSubDSLinks.end()) {
292 pos->fDatastoreLinkP->getSyncModes(modes);
293 ++pos;
294 }
295 // Remove any mode not found in any of the other subdatastores.
296 while (pos!=fSubDSLinks.end() && !modes.empty()) {
297 set<string> b;
298 pos->fDatastoreLinkP->getSyncModes(b);
299 set<string>::iterator it = modes.begin();
300 while (it != modes.end()) {
301 if (b.find(*it) != b.end()) {
302 ++it;
303 } else {
304 set<string>::iterator del = it;
305 ++it;
306 modes.erase(del);
307 }
308 }
309 pos++;
310 }
311}
312
313
314// process Sync alert from remote party: check if alert code is supported,
315// check if slow sync is needed due to anchor mismatch
316// - server case: also generate appropriate Alert acknowledge command
317TAlertCommand *TSuperDataStore::engProcessSyncAlert(
318 TSuperDataStore *aAsSubDatastoreOf, // if acting as subdatastore
319 uInt16 aAlertCode, // the alert code
320 const char *aLastRemoteAnchor, // last anchor of client
321 const char *aNextRemoteAnchor, // next anchor of client
322 const char *aTargetURI, // target URI as sent by remote, no processing at all
323 const char *aIdentifyingTargetURI, // target URI that was used to identify datastore
324 const char *aTargetURIOptions, // option string contained in target URI
325 SmlFilterPtr_t aTargetFilter, // DS 1.2 filter, NULL if none
326 const char *aSourceURI, // source URI
327 TStatusCommand &aStatusCommand // status that might be modified
328)
329{
330 TAlertCommand *alertcmdP=NULL__null;
331
332 TAlertCommand *subalertcmdP=NULL__null;
333 TStatusCommand substatus(fSessionP);
334
335 SYSYNC_TRYtry {
336 // alert all subdatastores
337 TSubDSLinkList::iterator pos;
338 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
339 subalertcmdP=pos->fDatastoreLinkP->engProcessSyncAlert(
340 this, // as subdatastore of myself
341 aAlertCode, // the alert code
342 aLastRemoteAnchor, // last anchor of client
343 aNextRemoteAnchor, // next anchor of client
344 aTargetURI, // target URI as sent by remote, no processing at all
345 aIdentifyingTargetURI, // target URI (without possible CGI)
346 aTargetURIOptions, // filtering CGI (NULL or empty if none)
347 aTargetFilter, // DS 1.2 filter, NULL if none
348 aSourceURI, // source URI
349 substatus // status that might be modified
350 );
351 if (subalertcmdP) {
352 // get rid of this, we don't need it (server case only, client case does not generate an alert command here anyway)
353 delete subalertcmdP;
354 }
355 // check if processing alert had a problem
356 // Notes:
357 // - When we have a subalertcmdP here, it is the server case, which means a non-zero status code
358 // (such as 508) at this point is ok and should not stop processing alerts.
359 // Only in case we have no alert we need to check the status code and abort immediately if it's not ok.
360 // - 508 can happen even in client for the rare case the server thinks anchors are ok, but client check
361 // says they are not, so we need to exclude 508 here.
362 if (!subalertcmdP && substatus.getStatusCode()!=0 && substatus.getStatusCode()!=508) {
363 // basic problem with one of the subdatastores
364 // - propagate error code
365 aStatusCommand.setStatusCode(substatus.getStatusCode());
366 // - no alert to send
367 return NULL__null;
368 }
369 // this one is pending for start
370 pos->fStartPending=true;
371 }
372 // set flag to indicate this subdatastore has init pending
373 // Now all subdatastores should be successfully alerted and have current anchor infos ready,
374 // so we can call inherited (which will obtain combined anchors from our logicInitSyncAnchors)
375 alertcmdP = inherited::engProcessSyncAlert(
376 aAsSubDatastoreOf, // as indicated by caller (normally, superdatastore is not subdatastore of another superdatastore, but...)
377 aAlertCode, // the alert code
378 aLastRemoteAnchor, // last anchor of client
379 aNextRemoteAnchor, // next anchor of client
380 aTargetURI, // target URI as sent by remote, no processing at all
381 aIdentifyingTargetURI, // target URI (without possible CGI)
382 aTargetURIOptions, // filtering CGI (NULL or empty if none)
383 aTargetFilter, // DS 1.2 filter, NULL if none
384 aSourceURI, // source URI
385 aStatusCommand // status that might be modified
386 );
387 // entire superdatastore is pending for start
388 fSuperStartPending=true;
389 }
390 SYSYNC_CATCH (...)catch(...) {
391 // clean up locally owned objects
392 if (alertcmdP) delete alertcmdP;
393 if (subalertcmdP) delete subalertcmdP;
394 SYSYNC_RETHROWthrow;
395 SYSYNC_ENDCATCH}
396 return alertcmdP;
397} // TSuperDataStore::engProcessSyncAlert
398
399
400// process status received for sync alert
401bool TSuperDataStore::engHandleAlertStatus(TSyError aStatusCode)
402{
403 // show it to all subdatastores
404 TSubDSLinkList::iterator pos;
405 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
406 pos->fDatastoreLinkP->engHandleAlertStatus(aStatusCode);
407 }
408 // all subdatastores have seen the alert status, so let superdatastore handle it as well
409 return TLocalEngineDS::engHandleAlertStatus(aStatusCode);
410} // TSuperDataStore::engHandleAlertStatus
411
412
413// Set remote datastore for local
414void TSuperDataStore::engSetRemoteDatastore(
415 TRemoteDataStore *aRemoteDatastoreP // the remote datastore involved
416)
417{
418 // set all subdatastores to (same) remote datastore as superdatastore itself
419 TSubDSLinkList::iterator pos;
420 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
421 pos->fDatastoreLinkP->engSetRemoteDatastore(aRemoteDatastoreP);
422 }
423 // set in superdatastore as well
424 TLocalEngineDS::engSetRemoteDatastore(aRemoteDatastoreP);
425} // TSuperDataStore::engSetRemoteDatastore
426
427
428// set Sync types needed for sending local data to remote DB
429void TSuperDataStore::setSendTypeInfo(
430 TSyncItemType *aLocalSendToRemoteTypeP,
431 TSyncItemType *aRemoteReceiveFromLocalTypeP
432)
433{
434 // set all subdatastores to (same) types as superdatastore itself
435 TSubDSLinkList::iterator pos;
436 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
437 pos->fDatastoreLinkP->setSendTypeInfo(aLocalSendToRemoteTypeP,aRemoteReceiveFromLocalTypeP);
438 }
439 // set in superdatastore as well
440 TLocalEngineDS::setSendTypeInfo(aLocalSendToRemoteTypeP,aRemoteReceiveFromLocalTypeP);
441} // TSuperDataStore::setSendTypeInfo
442
443
444// set Sync types needed for receiving remote data in local DB
445void TSuperDataStore::setReceiveTypeInfo(
446 TSyncItemType *aLocalReceiveFromRemoteTypeP,
447 TSyncItemType *aRemoteSendToLocalTypeP
448)
449{
450 // set all subdatastores to (same) types as superdatastore itself
451 TSubDSLinkList::iterator pos;
452 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
453 pos->fDatastoreLinkP->setReceiveTypeInfo(aLocalReceiveFromRemoteTypeP,aRemoteSendToLocalTypeP);
454 }
455 // set in superdatastore as well
456 TLocalEngineDS::setReceiveTypeInfo(aLocalReceiveFromRemoteTypeP,aRemoteSendToLocalTypeP);
457} // TSuperDataStore::setReceiveTypeInfo
458
459
460// init usage of datatypes set with setSendTypeInfo/setReceiveTypeInfo
461localstatus TSuperDataStore::initDataTypeUse(void)
462{
463 localstatus sta=LOCERR_OK;
464
465 // set all subdatastores to (same) types as superdatastore itself
466 TSubDSLinkList::iterator pos;
467 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
468 sta = pos->fDatastoreLinkP->initDataTypeUse();
469 if (sta!=LOCERR_OK)
470 return sta; // failed
471 }
472 // set in superdatastore as well
473 return TLocalEngineDS::initDataTypeUse();
474} // TSuperDataStore::initDataTypeUse
475
476
477// SYNC command bracket start (check credentials if needed)
478bool TSuperDataStore::engProcessSyncCmd(
479 SmlSyncPtr_t aSyncP, // the Sync element
480 TStatusCommand &aStatusCommand, // status that might be modified
481 bool &aQueueForLater // will be set if command must be queued for later (re-)execution
482)
483{
484 // start sync for all subdatastores
485 bool ok=true;
486 bool doqueue;
487 TSubDSLinkList::iterator pos;
488 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
489 // Note: this will cause subdatastores to call their own startSync,
490 // so we do NOT need to iterate over subdatastores in our startSync!
491 doqueue=false;
492 // if in init phase (entire superdatastore pending to start)
493 // only call subdatastores that are still pending for start, too
494 ok=true;
495 if (!fSuperStartPending || pos->fStartPending) {
496 ok=pos->fDatastoreLinkP->engProcessSyncCmd(aSyncP,aStatusCommand,doqueue);
497 if (!doqueue) {
498 // this one is now initialized. Do not do it again until all others are initialized, too
499 pos->fStartPending=false;
500 }
501 else {
502 // we must queue the entire command for later (but some subdatastores might be excluded then)
503 aQueueForLater=true; // queue if one of the subdatastores needs it
504 }
505 }
506 if (!ok) return false;
507 }
508 // start sync myself
509 ok=TLocalEngineDS::engProcessSyncCmd(aSyncP,aStatusCommand,doqueue);
510 if (doqueue) aQueueForLater=true; // queue if one of the subdatastores needs it
511 // if we reach this w/o queueing, start is no longer pending
512 if (!aQueueForLater) fSuperStartPending=false;
513 // done
514 return ok;
515} // TSuperDataStore::processSyncCmd
516
517
518// SYNC command bracket end (but another might follow in next message)
519bool TSuperDataStore::engProcessSyncCmdEnd(bool &aQueueForLater)
520{
521 // signal sync end to all subdatastores
522 bool ok=true;
523 bool doqueue;
524 TSubDSLinkList::iterator pos;
525 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
526 doqueue=false;
527 ok=pos->fDatastoreLinkP->engProcessSyncCmdEnd(doqueue);
528 if (doqueue) aQueueForLater=true; // queue if one of the subdatastores needs it
529 if (!ok) return false;
530 }
531 // signal it to myself
532 ok=TLocalEngineDS::engProcessSyncCmdEnd(doqueue);
533 if (doqueue) aQueueForLater=true; // queue if one of the subdatastores needs it
534 return ok;
535} // TSuperDataStore::engProcessSyncCmdEnd
536
537
538#ifdef SYSYNC_SERVER1
539
540// process map
541localstatus TSuperDataStore::engProcessMap(cAppCharP aRemoteID, cAppCharP aLocalID)
542{
543 TSubDatastoreLink *linkP = NULL__null;
544 localstatus sta = LOCERR_OK;
545
546 // item has local ID, we can find datastore by prefix
547 linkP = findSubLinkByLocalID(aLocalID);
548 if (!linkP) {
549 sta = 404; // not found
550 goto done;
551 }
552 // let subdatastore process (and only show subDS part of localID)
553 sta=linkP->fDatastoreLinkP->engProcessMap(
554 aRemoteID,
555 aLocalID+linkP->fDSLinkConfigP->fGUIDPrefix.size()
556 );
557done:
558 return sta;
559} // TSuperDataStore::engProcessMap
560
561#endif // SYSYNC_SERVER
562
563
564// called to process incoming item operation
565// Method takes ownership of syncitemP in all cases
566// - returns true (and unmodified or non-200-successful status) if
567// operation could be processed regularily
568// - returns false (but probably still successful status) if
569// operation was processed with internal irregularities, such as
570// trying to delete non-existant item in datastore with
571// incomplete Rollbacks (which returns status 200 in this case!).
572bool TSuperDataStore::engProcessRemoteItem(
573 TSyncItem *syncitemP,
574 TStatusCommand &aStatusCommand
575)
576{
577 bool regular=true;
578 string datatext;
579 #ifdef SYSYNC_SERVER1
580 TSyncItem *itemcopyP = NULL__null;
581 #endif
582
583 // show
584 PDEBUGBLOCKFMT((getDbgLogger()->DebugOpenBlockExpanded ( "SuperProcessItem"
, "Processing incoming item in superdatastore", "datastore=%s|SyncOp=%s|RemoteID=%s|LocalID=%s"
, getName(), SyncOpNames[syncitemP->getSyncOp()], syncitemP
->getRemoteID(), syncitemP->getLocalID() )
585 "SuperProcessItem", "Processing incoming item in superdatastore",getDbgLogger()->DebugOpenBlockExpanded ( "SuperProcessItem"
, "Processing incoming item in superdatastore", "datastore=%s|SyncOp=%s|RemoteID=%s|LocalID=%s"
, getName(), SyncOpNames[syncitemP->getSyncOp()], syncitemP
->getRemoteID(), syncitemP->getLocalID() )
586 "datastore=%s|SyncOp=%s|RemoteID=%s|LocalID=%s",getDbgLogger()->DebugOpenBlockExpanded ( "SuperProcessItem"
, "Processing incoming item in superdatastore", "datastore=%s|SyncOp=%s|RemoteID=%s|LocalID=%s"
, getName(), SyncOpNames[syncitemP->getSyncOp()], syncitemP
->getRemoteID(), syncitemP->getLocalID() )
587 getName(),getDbgLogger()->DebugOpenBlockExpanded ( "SuperProcessItem"
, "Processing incoming item in superdatastore", "datastore=%s|SyncOp=%s|RemoteID=%s|LocalID=%s"
, getName(), SyncOpNames[syncitemP->getSyncOp()], syncitemP
->getRemoteID(), syncitemP->getLocalID() )
588 SyncOpNames[syncitemP->getSyncOp()],getDbgLogger()->DebugOpenBlockExpanded ( "SuperProcessItem"
, "Processing incoming item in superdatastore", "datastore=%s|SyncOp=%s|RemoteID=%s|LocalID=%s"
, getName(), SyncOpNames[syncitemP->getSyncOp()], syncitemP
->getRemoteID(), syncitemP->getLocalID() )
589 syncitemP->getRemoteID(),getDbgLogger()->DebugOpenBlockExpanded ( "SuperProcessItem"
, "Processing incoming item in superdatastore", "datastore=%s|SyncOp=%s|RemoteID=%s|LocalID=%s"
, getName(), SyncOpNames[syncitemP->getSyncOp()], syncitemP
->getRemoteID(), syncitemP->getLocalID() )
590 syncitemP->getLocalID()getDbgLogger()->DebugOpenBlockExpanded ( "SuperProcessItem"
, "Processing incoming item in superdatastore", "datastore=%s|SyncOp=%s|RemoteID=%s|LocalID=%s"
, getName(), SyncOpNames[syncitemP->getSyncOp()], syncitemP
->getRemoteID(), syncitemP->getLocalID() )
591 ))getDbgLogger()->DebugOpenBlockExpanded ( "SuperProcessItem"
, "Processing incoming item in superdatastore", "datastore=%s|SyncOp=%s|RemoteID=%s|LocalID=%s"
, getName(), SyncOpNames[syncitemP->getSyncOp()], syncitemP
->getRemoteID(), syncitemP->getLocalID() )
;
592 // let appropriate subdatastore handle the command
593 TSubDatastoreLink *linkP = NULL__null;
594 TSyncOperation sop=syncitemP->getSyncOp();
595 string remid;
596 TSubDSLinkList::iterator pos;
597 #ifdef SYSYNC_SERVER1
598 if (IS_SERVER(getSyncAppBase()->isServer())) {
599 switch (sop) {
600 // Server case
601 case sop_wants_replace:
602 case sop_replace:
603 case sop_wants_add:
604 case sop_add:
605 // item has no local ID, we need to apply filters to item data
606 PDEBUGPRINTFX(DBG_DATA,("Checkin subdatastore filters to find where it belongs")){ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ("Checkin subdatastore filters to find where it belongs"
); }
;
607 linkP = findSubLinkByData(*syncitemP);
608 if (!linkP) goto nods;
609 PDEBUGPRINTFX(DBG_DATA,({ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Found item belongs to subdatastore '%s'"
, linkP->fDatastoreLinkP->getName() ); }
610 "Found item belongs to subdatastore '%s'",{ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Found item belongs to subdatastore '%s'"
, linkP->fDatastoreLinkP->getName() ); }
611 linkP->fDatastoreLinkP->getName(){ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Found item belongs to subdatastore '%s'"
, linkP->fDatastoreLinkP->getName() ); }
612 )){ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Found item belongs to subdatastore '%s'"
, linkP->fDatastoreLinkP->getName() ); }
;
613 // make sure item does not have a local ID (which would be wrong because of prefixes anyway)
614 syncitemP->clearLocalID();
615 // remembert because we might need it below for move-replace
616 remid=syncitemP->getRemoteID();
617 // let subdatastore process
618 regular=linkP->fDatastoreLinkP->engProcessRemoteItem(syncitemP,aStatusCommand);
619 // now check if replace was treated as add, if yes, this indicates
620 // that this might be a move between subdatastores
621 if (
622 (sop==sop_replace || sop==sop_wants_replace) &&
623 !fSlowSync && aStatusCommand.getStatusCode()==201
624 ) {
625 // this is probably a move from another datastore by changing an attribute
626 // that dispatches datastores (such as a vEvent changed to a vToDo)
627 // - so we delete all items with this remote ID in all other datastores
628 PDEBUGPRINTFX(DBG_DATA,("Replace could be a move between subdatastores, trying to delete all items with same remoteID in other subdatastores")){ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ("Replace could be a move between subdatastores, trying to delete all items with same remoteID in other subdatastores"
); }
;
629 TStatusCommand substatus(fSessionP);
630 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
631 if (&(*pos) != linkP) {
632 // all but original datastore
633 substatus.setStatusCode(200);
634 itemcopyP = new TSyncItem();
635 // - only remote ID and syncop are relevant, leave everything else empty
636 itemcopyP->setRemoteID(remid.c_str());
637 itemcopyP->setSyncOp(sop_delete);
638 // - now try to delete. This might fail if replace above wasn't a move
639 // itemcopyP is consumed
640 PDEBUGPRINTFX(DBG_DATA+DBG_DETAILS,({ if (((0x00000080 +0x40000000) & getDbgMask()) == (0x00000080
+0x40000000)) getDbgLogger()->setNextMask(0x00000080 +0x40000000
).DebugPrintfLastMask ( "Trying to delete item with remoteID='%s' from subdatastore '%s'"
, itemcopyP->getRemoteID(), linkP->fDatastoreLinkP->
getName() ); }
641 "Trying to delete item with remoteID='%s' from subdatastore '%s'",{ if (((0x00000080 +0x40000000) & getDbgMask()) == (0x00000080
+0x40000000)) getDbgLogger()->setNextMask(0x00000080 +0x40000000
).DebugPrintfLastMask ( "Trying to delete item with remoteID='%s' from subdatastore '%s'"
, itemcopyP->getRemoteID(), linkP->fDatastoreLinkP->
getName() ); }
642 itemcopyP->getRemoteID(),{ if (((0x00000080 +0x40000000) & getDbgMask()) == (0x00000080
+0x40000000)) getDbgLogger()->setNextMask(0x00000080 +0x40000000
).DebugPrintfLastMask ( "Trying to delete item with remoteID='%s' from subdatastore '%s'"
, itemcopyP->getRemoteID(), linkP->fDatastoreLinkP->
getName() ); }
643 linkP->fDatastoreLinkP->getName(){ if (((0x00000080 +0x40000000) & getDbgMask()) == (0x00000080
+0x40000000)) getDbgLogger()->setNextMask(0x00000080 +0x40000000
).DebugPrintfLastMask ( "Trying to delete item with remoteID='%s' from subdatastore '%s'"
, itemcopyP->getRemoteID(), linkP->fDatastoreLinkP->
getName() ); }
644 )){ if (((0x00000080 +0x40000000) & getDbgMask()) == (0x00000080
+0x40000000)) getDbgLogger()->setNextMask(0x00000080 +0x40000000
).DebugPrintfLastMask ( "Trying to delete item with remoteID='%s' from subdatastore '%s'"
, itemcopyP->getRemoteID(), linkP->fDatastoreLinkP->
getName() ); }
;
645 regular=pos->fDatastoreLinkP->engProcessRemoteItem(itemcopyP,substatus);
646 #ifdef SYDEBUG2
647 if (regular) {
648 // deleted ok
649 PDEBUGPRINTFX(DBG_DATA,({ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Found item in '%s', deleted here (and moved to '%s')"
, pos->fDatastoreLinkP->getName(), linkP->fDatastoreLinkP
->getName() ); }
650 "Found item in '%s', deleted here (and moved to '%s')",{ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Found item in '%s', deleted here (and moved to '%s')"
, pos->fDatastoreLinkP->getName(), linkP->fDatastoreLinkP
->getName() ); }
651 pos->fDatastoreLinkP->getName(),{ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Found item in '%s', deleted here (and moved to '%s')"
, pos->fDatastoreLinkP->getName(), linkP->fDatastoreLinkP
->getName() ); }
652 linkP->fDatastoreLinkP->getName(){ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Found item in '%s', deleted here (and moved to '%s')"
, pos->fDatastoreLinkP->getName(), linkP->fDatastoreLinkP
->getName() ); }
653 )){ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Found item in '%s', deleted here (and moved to '%s')"
, pos->fDatastoreLinkP->getName(), linkP->fDatastoreLinkP
->getName() ); }
;
654 }
655 #endif
656 }
657 }
658 PDEBUGPRINTFX(DBG_DATA,("End of (possible) move-replace between subdatastores")){ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ("End of (possible) move-replace between subdatastores"
); }
;
659 regular=true; // fully ok, no matter if delete above has succeeded or not
660 }
661 goto done;
662 case sop_archive_delete:
663 case sop_soft_delete:
664 case sop_delete:
665 case sop_copy:
666 // item has no local ID AND no data, only a remoteID:
667 // we must try to read item or attempt to delete in all subdatastores by remoteID
668 // until found in one of them
669
670 // get an empty item of correct type to call logicRetrieveItemByID
671 itemcopyP = getLocalReceiveType()->newSyncItem(getRemoteSendType(),this);
672 // - only remote ID is relevant, leave everything else empty
673 itemcopyP->setRemoteID(syncitemP->getRemoteID());
674 // try to find item in any of the subdatastores
675 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
676 linkP = &(*pos);
677 // always start with 200
678 aStatusCommand.setStatusCode(200);
679
680 // item deleted by a failed engProcessRemoteItem()?
681 if (!syncitemP) {
682 // recreate it for next attempt
683 syncitemP = getLocalReceiveType()->newSyncItem(getRemoteSendType(),this);
684 syncitemP->setRemoteID(itemcopyP->getRemoteID());
685 syncitemP->setSyncOp(sop);
686 }
687
688 if (sop!=sop_copy && linkP->fDatastoreLinkP->dsDeleteDetectsItemPresence()) {
689 // attempt to delete, consuming original item on success
690 regular=linkP->fDatastoreLinkP->engProcessRemoteItem(syncitemP,aStatusCommand);
691 // must be ok AND not 404 (item not found)
692 if (regular && aStatusCommand.getStatusCode()!=404) {
693 PDEBUGPRINTFX(DBG_DATA,({ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Item found in subdatastore '%s', deleted it there"
, linkP->fDatastoreLinkP->getName() ); }
694 "Item found in subdatastore '%s', deleted it there",{ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Item found in subdatastore '%s', deleted it there"
, linkP->fDatastoreLinkP->getName() ); }
695 linkP->fDatastoreLinkP->getName(){ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Item found in subdatastore '%s', deleted it there"
, linkP->fDatastoreLinkP->getName() ); }
696 )){ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Item found in subdatastore '%s', deleted it there"
, linkP->fDatastoreLinkP->getName() ); }
;
697
698 // done
699 goto done;
700 } else {
701 // syncitemP was deleted by engProcessRemoteItem() (for
702 // example, in TStdLogicDS::logicProcessRemoteItem()),
703 // so we must remember to recreate it from the copy for
704 // another attempt if there is one
705 syncitemP = NULL__null;
706 }
707 } else {
708 // try to read first to determine whether the subdatastore contains the item;
709 // necessary because the subdatastore is not able to report a 404 error in
710 // the delete operation when the item does not exist
711 PDEBUGPRINTFX(DBG_DATA+DBG_DETAILS,({ if (((0x00000080 +0x40000000) & getDbgMask()) == (0x00000080
+0x40000000)) getDbgLogger()->setNextMask(0x00000080 +0x40000000
).DebugPrintfLastMask ( "Trying to read item by remoteID='%s' from subdatastore '%s' to see if it is there"
, itemcopyP->getRemoteID(), linkP->fDatastoreLinkP->
getName() ); }
712 "Trying to read item by remoteID='%s' from subdatastore '%s' to see if it is there",{ if (((0x00000080 +0x40000000) & getDbgMask()) == (0x00000080
+0x40000000)) getDbgLogger()->setNextMask(0x00000080 +0x40000000
).DebugPrintfLastMask ( "Trying to read item by remoteID='%s' from subdatastore '%s' to see if it is there"
, itemcopyP->getRemoteID(), linkP->fDatastoreLinkP->
getName() ); }
713 itemcopyP->getRemoteID(),{ if (((0x00000080 +0x40000000) & getDbgMask()) == (0x00000080
+0x40000000)) getDbgLogger()->setNextMask(0x00000080 +0x40000000
).DebugPrintfLastMask ( "Trying to read item by remoteID='%s' from subdatastore '%s' to see if it is there"
, itemcopyP->getRemoteID(), linkP->fDatastoreLinkP->
getName() ); }
714 linkP->fDatastoreLinkP->getName(){ if (((0x00000080 +0x40000000) & getDbgMask()) == (0x00000080
+0x40000000)) getDbgLogger()->setNextMask(0x00000080 +0x40000000
).DebugPrintfLastMask ( "Trying to read item by remoteID='%s' from subdatastore '%s' to see if it is there"
, itemcopyP->getRemoteID(), linkP->fDatastoreLinkP->
getName() ); }
715 )){ if (((0x00000080 +0x40000000) & getDbgMask()) == (0x00000080
+0x40000000)) getDbgLogger()->setNextMask(0x00000080 +0x40000000
).DebugPrintfLastMask ( "Trying to read item by remoteID='%s' from subdatastore '%s' to see if it is there"
, itemcopyP->getRemoteID(), linkP->fDatastoreLinkP->
getName() ); }
;
716 regular=linkP->fDatastoreLinkP->logicRetrieveItemByID(*itemcopyP,aStatusCommand);
717 // must be ok AND not 404 (item not found)
718 if (regular && aStatusCommand.getStatusCode()!=404) {
719 PDEBUGPRINTFX(DBG_DATA,({ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Item found in subdatastore '%s', deleting it there"
, linkP->fDatastoreLinkP->getName() ); }
720 "Item found in subdatastore '%s', deleting it there",{ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Item found in subdatastore '%s', deleting it there"
, linkP->fDatastoreLinkP->getName() ); }
721 linkP->fDatastoreLinkP->getName(){ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Item found in subdatastore '%s', deleting it there"
, linkP->fDatastoreLinkP->getName() ); }
722 )){ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Item found in subdatastore '%s', deleting it there"
, linkP->fDatastoreLinkP->getName() ); }
;
723 // now we can delete or copy, consuming original item
724 regular=linkP->fDatastoreLinkP->engProcessRemoteItem(syncitemP,aStatusCommand);
Value stored to 'regular' is never read
725 // done
726 regular=true;
727 goto done;
728 }
729 }
730 }
731 // none of the datastores could process this item --> error
732 // - make sure delete reports 200 for incomplete-rollback-datastores
733 if (aStatusCommand.getStatusCode()==404 && sop!=sop_copy) {
734 // not finding an item for delete might be ok for remote...
735 if (fSessionP->getSessionConfig()->fDeletingGoneOK) {
736 // 404/410: item not found, could be because previous aborted session has
737 // already committed deletion of that item -> behave as if delete was ok
738 PDEBUGPRINTFX(DBG_DATA,("to-be-deleted item was not found, but do NOT report %hd",aStatusCommand.getStatusCode())){ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ("to-be-deleted item was not found, but do NOT report %hd"
,aStatusCommand.getStatusCode()); }
;
739 aStatusCommand.setStatusCode(200);
740 }
741 // ...but it is a internal irregularity, fall thru to return false
742 }
743 // is an internal irregularity
744 regular=false;
745 goto done;
746 case sop_reference_only:
747 case sop_move:
748 case sop_none:
749 case numSyncOperations:
750 // nothing to do or shouldn't happen
751 break;
752 } // switch
753 } // server
754 #endif // SYSYNC_SERVER
755 #ifdef SYSYNC_CLIENT1
756 if (IS_CLIENT(!getSyncAppBase()->isServer())) {
757 switch (sop) {
758 // Client case
759 case sop_wants_replace:
760 case sop_replace:
761 case sop_archive_delete:
762 case sop_soft_delete:
763 case sop_delete:
764 case sop_copy:
765 // item has local ID, we can find datastore by prefix
766 linkP = findSubLinkByLocalID(syncitemP->getLocalID());
767 if (!linkP) goto nods;
768 // remove prefix before letting subdatastore process it
769 syncitemP->fLocalID.erase(0,linkP->fDSLinkConfigP->fGUIDPrefix.size());
770 // now let subdatastore process
771 regular=linkP->fDatastoreLinkP->engProcessRemoteItem(syncitemP,aStatusCommand);
772 goto done;
773 case sop_wants_add:
774 case sop_add:
775 // item has no local ID, we need to apply filters to item data
776 linkP = findSubLinkByData(*syncitemP);
777 if (!linkP) goto nods;
778 // make sure item does not have a local ID (which would be wrong because of prefixes anyway)
779 syncitemP->clearLocalID();
780 // let subdatastore process
781 regular=linkP->fDatastoreLinkP->engProcessRemoteItem(syncitemP,aStatusCommand);
782 goto done;
783 case sop_reference_only:
784 case sop_move:
785 case sop_none:
786 case numSyncOperations:
787 // nothing to do or shouldn't happen
788 break;
789 } // switch
790 } // client
791 #endif // SYSYNC_CLIENT
792nods:
793 // no datastore or unknown command, general DB error
794 aStatusCommand.setStatusCode(510);
795 PDEBUGPRINTFX(DBG_ERROR,("TSuperDataStore::processRemoteItem Fatal: Item cannot be processed by any subdatastore")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("TSuperDataStore::processRemoteItem Fatal: Item cannot be processed by any subdatastore"
); }
;
796 // consume item
797 delete syncitemP;
798 regular=false;
799 goto done;
800done:
801 #ifdef SYSYNC_SERVER1
802 delete itemcopyP;
803 #endif
804 PDEBUGENDBLOCK("SuperProcessItem")getDbgLogger()->DebugCloseBlock( "SuperProcessItem");
805 return regular;
806} // TSuperDataStore::engProcessRemoteItem
807
808
809
810// - must return true if this datastore is finished with <sync>
811// (if all datastores return true,
812// session is allowed to finish sync packet with outgoing message
813bool TSuperDataStore::isSyncDone(void)
814{
815 // check subdatastores
816 bool done=true;
817 TSubDSLinkList::iterator pos;
818 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
819 done=done && pos->fDatastoreLinkP->isSyncDone();
820 }
821 // check myself
822 return done && TLocalEngineDS::isSyncDone();
823} // TSuperDataStore::isSyncDone
824
825
826// abort sync with this super datastore (that is, with all subdatastores as well)
827void TSuperDataStore::engAbortDataStoreSync(TSyError aStatusCode, bool aLocalProblem, bool aResumable)
828{
829 // abort subdatastores
830 TSubDSLinkList::iterator pos;
831 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
832 pos->fDatastoreLinkP->engAbortDataStoreSync(aStatusCode,aLocalProblem,aResumable);
833 }
834 // set code in my own ancestor
835 TLocalEngineDS::engAbortDataStoreSync(aStatusCode,aLocalProblem,aResumable);
836} // TSuperDataStore::engAbortDataStoreSync
837
838
839// - must return true if this datastore is finished with <sync>
840// (if all datastores return true,
841// session is allowed to finish sync packet with outgoing message
842bool TSuperDataStore::isAborted(void)
843{
844 // check subdatastores
845 TSubDSLinkList::iterator pos;
846 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
847 if (pos->fDatastoreLinkP->isAborted()) return true; // one aborted, super aborted as well
848 }
849 // check myself
850 return TLocalEngineDS::isAborted();
851} // TSuperDataStore::isAborted
852
853
854// called at very end of sync session, when everything is done
855// Note: is also called before deleting a datastore (so aborted sessions
856// can do cleanup and/or statistics display as well)
857void TSuperDataStore::engFinishDataStoreSync(localstatus aErrorStatus)
858{
859 // inform all subdatastores
860 TSubDSLinkList::iterator pos;
861 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
862 pos->fDatastoreLinkP->engFinishDataStoreSync(aErrorStatus);
863 }
864 // call inherited
865 inherited::engFinishDataStoreSync(aErrorStatus);
866} // TSuperDataStore::engFinishDataStoreSync
867
868
869// Internal events during sync to access local database
870// ====================================================
871
872// Methods overriding TLocalEngineDS
873// ----------------------------------
874
875
876
877// called at sync alert (before generating for client, after receiving for server)
878// - obtains combined anchor from subdatastores
879// - combines them into a common anchor (if possible)
880// - updates fFirstTimeSync as well
881localstatus TSuperDataStore::engInitSyncAnchors(
882 cAppCharP aDatastoreURI, // (Note: unused in superdatastore) local datastore URI
883 cAppCharP aRemoteDBID // (Note: unused in superdatastore) ID of remote datastore (to find session information in local DB)
884)
885{
886 bool allanchorsequal=true;
887 localstatus sta=LOCERR_OK;
888
889 // superdatastore has no own anchors, so collect data from subdatastores
890 fFirstTimeSync=false;
891 TSubDSLinkList::iterator pos;
892 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
893 if (pos==fSubDSLinks.begin()) {
894 // Server case note:
895 // Subdatastore's engInitSyncAnchors() MUST NOT be called here, because this routine will
896 // always be called after all subdatastore's engProcessSyncAlert() was called
897 // which in turn contains a call to engInitSyncAnchors().
898 // Client case note:
899 // Subdatastore's engInitSyncAnchors() MUST NOT be called here, because this routine will
900 // be called from TSuperDataStore::engPrepareClientSyncAlert() after iterating through
901 // subdatastores and calling their engPrepareClientDSForAlert(), which in turn
902 // contains a call to engInitSyncAnchors().
903 // This means we can safely assume we have the fLastRemoteAnchor/fNextLocalAnchor info
904 // ready here.
905 // - Assign references of first datastore
906 // Note: remote anchor must be same from all subdatastores
907 fLastRemoteAnchor=pos->fDatastoreLinkP->fLastRemoteAnchor;
908 // - these are used from the first datastore, and might differ (a few seconds,
909 // that is) for other datastores
910 fLastLocalAnchor=pos->fDatastoreLinkP->fLastLocalAnchor;
911 fNextLocalAnchor=pos->fDatastoreLinkP->fNextLocalAnchor;
912 }
913 else {
914 // see if all are equal
915 allanchorsequal = allanchorsequal &&
916 pos->fDatastoreLinkP->fLastRemoteAnchor == fLastRemoteAnchor;
917 }
918 // also combine firstTimeSync (first time if it's first for any of the subdatastores)
919 fFirstTimeSync = fFirstTimeSync || pos->fDatastoreLinkP->fFirstTimeSync;
920 }
921 // make sure common anchor is valid only if all of the subdatastores have equal anchors
922 if (sta!=LOCERR_OK || fFirstTimeSync || !allanchorsequal) {
923 fLastLocalAnchor.empty();
924 fLastRemoteAnchor.empty();
925 }
926 // superdatastore gets adminready when all subdatastores have successfully done engInitSyncAnchors()
927 if (sta==LOCERR_OK) {
928 changeState(dssta_adminready); // admin data is now ready
929 }
930 // return status
931 return sta;
932} // TSuperDataStore::engInitSyncAnchors
933
934
935// - called at start of first <Sync> command (prepare DB for reading/writing)
936bool TSuperDataStore::startSync(TStatusCommand &aStatusCommand)
937{
938 DEBUGPRINTFX(DBG_HOT,("TSuperDataStore::startSync")){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger
()->setNextMask(0x00000001).DebugPrintfLastMask ("TSuperDataStore::startSync"
); }
;
939 // make sure we start generating with first datastore
940 fCurrentGenDSPos=fSubDSLinks.begin();
941 // NOTE: Do NOT iterate subdatastores, because these were called already
942 // by engProcessSyncCmd (server case) or engProcessSyncAlert (client case)
943 return true; // ok
944} // TSuperDataStore::startSync
945
946
947/// check is datastore is completely started.
948/// @param[in] aWait if set, call will not return until either started state is reached
949/// or cannot be reached within the maximally allowed request processing time left.
950bool TSuperDataStore::engIsStarted(bool aWait)
951{
952 // check subdatastores
953 bool ready=true;
954 TSubDSLinkList::iterator pos;
955 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
956 ready=ready && pos->fDatastoreLinkP->engIsStarted(aWait);
957 }
958 // check myself
959 return ready && inherited::engIsStarted(aWait);
960} // TSuperDataStore::engIsStarted
961
962
963// remove prefix for given subDatastore
964// @param[in] aIDWithPrefix points to ID with prefix
965// @return NULL if either datastore not found or prefix not present in aIDWithPrefix
966// @return pointer to first char in aIDWithPrefix which is not part of the prefix
967cAppCharP TSuperDataStore::removeSubDSPrefix(cAppCharP aIDWithPrefix, TLocalEngineDS *aLocalDatastoreP)
968{
969 if (!aIDWithPrefix) return NULL__null;
970 TSubDSLinkList::iterator pos;
971 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
972 if (pos->fDatastoreLinkP == aLocalDatastoreP) {
973 // check the prefix
974 if (strnncmp(
975 aIDWithPrefix,
976 pos->fDSLinkConfigP->fGUIDPrefix.c_str(),
977 pos->fDSLinkConfigP->fGUIDPrefix.size()
978 ) ==0)
979 return aIDWithPrefix+pos->fDSLinkConfigP->fGUIDPrefix.size(); // return start of subDS ID
980 else
981 return aIDWithPrefix; // datastore found, but prefix is not there, return unmodified
982 }
983 }
984 return NULL__null;
985} // TSuperDataStore::removeSubDSPrefix
986
987
988// private helper: find subdatastore which matches prefix of given localID
989TSubDatastoreLink *TSuperDataStore::findSubLinkByLocalID(const char *aLocalID)
990{
991 TSubDSLinkList::iterator pos;
992 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
993 if (strnncmp(
994 aLocalID,
995 pos->fDSLinkConfigP->fGUIDPrefix.c_str(),
996 pos->fDSLinkConfigP->fGUIDPrefix.size()
997 ) ==0) {
998 // found
999 return &(*pos);
1000 }
1001 }
1002 return NULL__null; // not found
1003} // TSuperDataStore::findSubLinkByLocalID
1004
1005
1006// private helper: find subdatastore which can accept item data
1007TSubDatastoreLink *TSuperDataStore::findSubLinkByData(TSyncItem &aSyncItem)
1008{
1009 TSubDSLinkList::iterator pos;
1010 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
1011 PDEBUGPRINTFX(DBG_DATA+DBG_DETAILS,({ if (((0x00000080 +0x40000000) & getDbgMask()) == (0x00000080
+0x40000000)) getDbgLogger()->setNextMask(0x00000080 +0x40000000
).DebugPrintfLastMask ( "Testing item data against <dispatchfilter> of subdatastore '%s'"
, pos->fDatastoreLinkP->getName() ); }
1012 "Testing item data against <dispatchfilter> of subdatastore '%s'",{ if (((0x00000080 +0x40000000) & getDbgMask()) == (0x00000080
+0x40000000)) getDbgLogger()->setNextMask(0x00000080 +0x40000000
).DebugPrintfLastMask ( "Testing item data against <dispatchfilter> of subdatastore '%s'"
, pos->fDatastoreLinkP->getName() ); }
1013 pos->fDatastoreLinkP->getName(){ if (((0x00000080 +0x40000000) & getDbgMask()) == (0x00000080
+0x40000000)) getDbgLogger()->setNextMask(0x00000080 +0x40000000
).DebugPrintfLastMask ( "Testing item data against <dispatchfilter> of subdatastore '%s'"
, pos->fDatastoreLinkP->getName() ); }
1014 )){ if (((0x00000080 +0x40000000) & getDbgMask()) == (0x00000080
+0x40000000)) getDbgLogger()->setNextMask(0x00000080 +0x40000000
).DebugPrintfLastMask ( "Testing item data against <dispatchfilter> of subdatastore '%s'"
, pos->fDatastoreLinkP->getName() ); }
;
1015 if (aSyncItem.testFilter(pos->fDSLinkConfigP->fDispatchFilter.c_str())) {
1016 // found
1017 return &(*pos);
1018 }
1019 }
1020 return NULL__null; // not found
1021} // TSuperDataStore::findSubLinkByData
1022
1023
1024// only dummy, creates error if called
1025bool TSuperDataStore::logicRetrieveItemByID(
1026 TSyncItem &aSyncItem, // item to be filled with data from server. Local or Remote ID must already be set
1027 TStatusCommand &aStatusCommand // status, must be set on error or non-200-status
1028)
1029{
1030 aStatusCommand.setStatusCode(500);
1031 DEBUGPRINTFX(DBG_ERROR,("TSuperDataStore::logicRetrieveItemByID called, which should never happen!!!!!!")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("TSuperDataStore::logicRetrieveItemByID called, which should never happen!!!!!!"
); }
;
1032 return false; // not ok
1033} // TSuperDataStore::logicRetrieveItemByID
1034
1035
1036// only dummy, creates error if called
1037// - Method takes ownership of syncitemP in all cases
1038bool TSuperDataStore::logicProcessRemoteItem(
1039 TSyncItem *syncitemP,
1040 TStatusCommand &aStatusCommand,
1041 bool &aVisibleInSyncset, // on entry: tells if resulting item SHOULD be visible; on exit: set if processed item remains visible in the sync set.
1042 string *aGUID // GUID is stored here if not NULL
1043)
1044{
1045 delete syncitemP; // consume
1046 aStatusCommand.setStatusCode(500);
1047 DEBUGPRINTFX(DBG_ERROR,("TSuperDataStore::logicProcessRemoteItem called, which should never happen!!!!!!")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("TSuperDataStore::logicProcessRemoteItem called, which should never happen!!!!!!"
); }
;
1048 return false; // not ok
1049} // TSuperDataStore::logicProcessRemoteItem
1050
1051
1052// - returns true if DB implementation can filter during database fetch
1053// (otherwise, fetched items must be filtered after being read from DB)
1054bool TSuperDataStore::engFilteredFetchesFromDB(bool aFilterChanged)
1055{
1056 // only if all subdatastores support it
1057 bool yes=true;
1058 TSubDSLinkList::iterator pos;
1059 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
1060 yes = yes && pos->fDatastoreLinkP->engFilteredFetchesFromDB(aFilterChanged);
1061 }
1062 return yes;
1063} // TSuperDataStore::engFilteredFetchesFromDB
1064
1065
1066// - called for SyncML 1.1 if remote wants number of changes.
1067// Must return -1 if no NOC value can be returned
1068sInt32 TSuperDataStore::getNumberOfChanges(void)
1069{
1070 sInt32 noc,totalNoc = 0;
1071 TSubDSLinkList::iterator pos;
1072 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
1073 noc = pos->fDatastoreLinkP->getNumberOfChanges();
1074 if (noc<0) return -1; // if one of the subdatastores does not know NOC, we can't return a NOC
1075 // subdatastore knows its NOC, sum up
1076 totalNoc+=noc;
1077 }
1078 // return sum of all NOCs
1079 return totalNoc;
1080}; // TSuperDataStore::getNumberOfChanges
1081
1082
1083// show statistics or error of current sync
1084void TSuperDataStore::showStatistics(void)
1085{
1086 // show something in debug log
1087 PDEBUGPRINTFX(DBG_HOT,("Superdatastore Sync for '%s' (%s), %s sync status:",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger
()->setNextMask(0x00000001).DebugPrintfLastMask ("Superdatastore Sync for '%s' (%s), %s sync status:"
, getName(), fRemoteViewOfLocalURI.c_str(), fSlowSync ? "slow"
: "normal" ); }
1088 getName(),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger
()->setNextMask(0x00000001).DebugPrintfLastMask ("Superdatastore Sync for '%s' (%s), %s sync status:"
, getName(), fRemoteViewOfLocalURI.c_str(), fSlowSync ? "slow"
: "normal" ); }
1089 fRemoteViewOfLocalURI.c_str(),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger
()->setNextMask(0x00000001).DebugPrintfLastMask ("Superdatastore Sync for '%s' (%s), %s sync status:"
, getName(), fRemoteViewOfLocalURI.c_str(), fSlowSync ? "slow"
: "normal" ); }
1090 fSlowSync ? "slow" : "normal"{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger
()->setNextMask(0x00000001).DebugPrintfLastMask ("Superdatastore Sync for '%s' (%s), %s sync status:"
, getName(), fRemoteViewOfLocalURI.c_str(), fSlowSync ? "slow"
: "normal" ); }
1091 )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger
()->setNextMask(0x00000001).DebugPrintfLastMask ("Superdatastore Sync for '%s' (%s), %s sync status:"
, getName(), fRemoteViewOfLocalURI.c_str(), fSlowSync ? "slow"
: "normal" ); }
;
1092 // and on user console
1093 CONSOLEPRINTF((""))SySync_ConsolePrintf(stderr, "SYSYNC " "" "\n");
1094 CONSOLEPRINTF(("- Superdatastore Sync for '%s' (%s), %s sync status:",SySync_ConsolePrintf(stderr, "SYSYNC " "- Superdatastore Sync for '%s' (%s), %s sync status:"
"\n", getName(), fRemoteViewOfLocalURI.c_str(), fSlowSync ? "slow"
: "normal")
1095 getName(),SySync_ConsolePrintf(stderr, "SYSYNC " "- Superdatastore Sync for '%s' (%s), %s sync status:"
"\n", getName(), fRemoteViewOfLocalURI.c_str(), fSlowSync ? "slow"
: "normal")
1096 fRemoteViewOfLocalURI.c_str(),SySync_ConsolePrintf(stderr, "SYSYNC " "- Superdatastore Sync for '%s' (%s), %s sync status:"
"\n", getName(), fRemoteViewOfLocalURI.c_str(), fSlowSync ? "slow"
: "normal")
1097 fSlowSync ? "slow" : "normal"SySync_ConsolePrintf(stderr, "SYSYNC " "- Superdatastore Sync for '%s' (%s), %s sync status:"
"\n", getName(), fRemoteViewOfLocalURI.c_str(), fSlowSync ? "slow"
: "normal")
1098 ))SySync_ConsolePrintf(stderr, "SYSYNC " "- Superdatastore Sync for '%s' (%s), %s sync status:"
"\n", getName(), fRemoteViewOfLocalURI.c_str(), fSlowSync ? "slow"
: "normal")
;
1099 // now show results
1100 if (isAborted()) {
1101 // failed
1102 PDEBUGPRINTFX(DBG_ERROR,("Warning: Failed with status code=%hd",fAbortStatusCode)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("Warning: Failed with status code=%hd"
,fAbortStatusCode); }
;
1103 CONSOLEPRINTF((" ************ Failed with status code=%hd",fAbortStatusCode))SySync_ConsolePrintf(stderr, "SYSYNC " " ************ Failed with status code=%hd"
"\n",fAbortStatusCode)
;
1104 }
1105 else {
1106 // successful: show statistics on console
1107 PDEBUGPRINTFX(DBG_HOT,("Completed successfully - details see subdatastores")){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger
()->setNextMask(0x00000001).DebugPrintfLastMask ("Completed successfully - details see subdatastores"
); }
;
1108 CONSOLEPRINTF((" Completed successfully - details see subdatastores"))SySync_ConsolePrintf(stderr, "SYSYNC " " Completed successfully - details see subdatastores"
"\n")
;
1109 }
1110 CONSOLEPRINTF((""))SySync_ConsolePrintf(stderr, "SYSYNC " "" "\n");
1111} // TSuperDataStore::showStatistics
1112
1113
1114// - returns true if DB implementation of all subdatastores support resume
1115bool TSuperDataStore::dsResumeSupportedInDB(void)
1116{
1117 // yes if all subdatastores support it
1118 bool yes=true;
1119 TSubDSLinkList::iterator pos;
1120 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
1121 yes = yes && pos->fDatastoreLinkP->dsResumeSupportedInDB();
1122 }
1123 return yes;
1124} // TSuperDataStore::dsResumeSupportedInDB
1125
1126
1127// helper to save resume state either at end of request or explicitly at reception of a "suspend"
1128localstatus TSuperDataStore::engSaveSuspendState(bool aAnyway)
1129{
1130 // only save here if not aborted already (aborting saves the state immediately)
1131 // or explicitly requested
1132 if (aAnyway || !isAborted()) {
1133 // only save if DS 1.2 and supported by DB
1134 if ((fSessionP->getSyncMLVersion()>=syncml_vers_1_2) && dsResumeSupportedInDB()) {
1135 PDEBUGBLOCKFMT(("SuperSaveSuspendState","Saving superdatastore suspend/resume state","superdatastore=%s",getName()))getDbgLogger()->DebugOpenBlockExpanded ("SuperSaveSuspendState"
,"Saving superdatastore suspend/resume state","superdatastore=%s"
,getName())
;
1136 // save alert state
1137 fResumeAlertCode=fAlertCode;
1138 TSubDSLinkList::iterator pos;
1139 if (fResumeAlertCode) {
1140 // let all subdatastores update partial item and markOnlyUngeneratedForResume()
1141 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
1142 // save partial state if any
1143 if (pos->fDatastoreLinkP->fPartialItemState!=pi_state_save_outgoing) {
1144 // ONLY if we have no request for saving an outgoing item state already,
1145 // we possibly need to save a pending incoming item
1146 // if there is an incompletely received item, let it update Partial Item (fPIxxx) state
1147 // (if it is an item of this datastore, that is).
1148 if (fSessionP->fIncompleteDataCommandP) {
1149 fSessionP->fIncompleteDataCommandP->updatePartialItemState(pos->fDatastoreLinkP);
1150 }
1151 }
1152 // mark ungenerated
1153 pos->fDatastoreLinkP->logicMarkOnlyUngeneratedForResume();
1154 }
1155 /// @note that already generated items are related to the originating
1156 /// localEngineDS, so markPendingForResume() on existing commands will
1157 /// directly reach the correct datastore
1158 /// @note markItemForResume() will get the localID as presented to
1159 /// remote, that is in case of superdatastores with prefixes that need to be removed
1160 fSessionP->markPendingForResume(this);
1161 }
1162 // let all subdatastores logicSaveResumeMarks() to make all this persistent
1163 localstatus globErr=LOCERR_OK;
1164 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
1165 localstatus err=pos->fDatastoreLinkP->logicSaveResumeMarks();
1166 if (err!=LOCERR_OK) globErr=err;
1167 }
1168 PDEBUGENDBLOCK("SuperSaveSuspendState")getDbgLogger()->DebugCloseBlock( "SuperSaveSuspendState");
1169 return globErr;
1170 }
1171 }
1172 return LOCERR_OK;
1173} // TSuperDataStore::engSaveSuspendState
1174
1175
1176#ifdef SYSYNC_SERVER1
1177
1178/// @brief called at end of request processing, should be used to save suspend state
1179/// @note subdatastores don't do anything themselves, to make sure superds can make things happen in correct order
1180void TSuperDataStore::engRequestEnded(void)
1181{
1182 // variant for superdatastore - also handles its subdatastores
1183 // For DS 1.2: Make sure everything is ready for a resume in case there's an abort (implicit Suspend)
1184 // before the next request. Note that the we cannot wait for session timeout, as the resume attempt
1185 // from the client probably arrives much earlier.
1186 if (testState(dssta_syncmodestable)) {
1187 // make sure all unsent items are marked for resume
1188 localstatus sta=engSaveSuspendState(false); // only if not already aborted
1189 if (sta!=LOCERR_OK) {
1190 DEBUGPRINTFX(DBG_ERROR,("Could not save suspend state at end of Request: err=%hd",sta)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("Could not save suspend state at end of Request: err=%hd"
,sta); }
;
1191 }
1192 }
1193 // let datastore prepare for end of request (other than thread change)
1194 TSubDSLinkList::iterator pos;
1195 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
1196 pos->fDatastoreLinkP->dsRequestEnded();
1197 }
1198 // then let them know that thread may change
1199 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
1200 pos->fDatastoreLinkP->dsThreadMayChangeNow();
1201 }
1202} // TSuperDataStore::engRequestEnded
1203
1204#endif
1205
1206
1207// - called to let server generate sync commands for client
1208// Returns true if now finished for this datastore
1209// also sets fState to dss_syncdone when finished
1210bool TSuperDataStore::engGenerateSyncCommands(
1211 TSmlCommandPContainer &aNextMessageCommands,
1212 TSmlCommand * &aInterruptedCommandP,
1213 const char *aLocalIDPrefix
1214)
1215{
1216 PDEBUGBLOCKFMT(("SuperSyncGen","Now generating sync commands from superdatastore","datastore=%s",getName()))getDbgLogger()->DebugOpenBlockExpanded ("SuperSyncGen","Now generating sync commands from superdatastore"
,"datastore=%s",getName())
;
1217 bool finished=false;
1218 string prefix;
1219
1220 while (!isAborted()) {
1221 // check for end
1222 if (fCurrentGenDSPos==fSubDSLinks.end()) {
1223 // done, update status
1224 changeState(dssta_syncgendone,true);
1225 break;
1226 }
1227 // create current prefix
1228 AssignString(prefix,aLocalIDPrefix);
1229 prefix.append(fCurrentGenDSPos->fDSLinkConfigP->fGUIDPrefix);
1230 // call subdatastore to generate commands
1231 finished=fCurrentGenDSPos->fDatastoreLinkP->engGenerateSyncCommands(
1232 aNextMessageCommands,
1233 aInterruptedCommandP,
1234 prefix.c_str()
1235 );
1236 // exit if not yet finished with generating commands for this datastore
1237 if (!finished) break;
1238 // done with this datastore, switch to next if any
1239 fCurrentGenDSPos++;
1240 } // while not aborted
1241 // finished when state is dss_syncdone
1242 PDEBUGPRINTFX(DBG_DATA,({ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "superdatastore's engGenerateSyncCommands ended, state='%s', sync generation %sdone"
, getDSStateName(), dbgTestState(dssta_syncgendone,true) ? ""
: "NOT " ); }
1243 "superdatastore's engGenerateSyncCommands ended, state='%s', sync generation %sdone",{ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "superdatastore's engGenerateSyncCommands ended, state='%s', sync generation %sdone"
, getDSStateName(), dbgTestState(dssta_syncgendone,true) ? ""
: "NOT " ); }
1244 getDSStateName(),{ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "superdatastore's engGenerateSyncCommands ended, state='%s', sync generation %sdone"
, getDSStateName(), dbgTestState(dssta_syncgendone,true) ? ""
: "NOT " ); }
1245 dbgTestState(dssta_syncgendone,true) ? "" : "NOT "{ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "superdatastore's engGenerateSyncCommands ended, state='%s', sync generation %sdone"
, getDSStateName(), dbgTestState(dssta_syncgendone,true) ? ""
: "NOT " ); }
1246 )){ if (((0x00000080) & getDbgMask()) == (0x00000080)) getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "superdatastore's engGenerateSyncCommands ended, state='%s', sync generation %sdone"
, getDSStateName(), dbgTestState(dssta_syncgendone,true) ? ""
: "NOT " ); }
;
1247 PDEBUGENDBLOCK("SuperSyncGen")getDbgLogger()->DebugCloseBlock( "SuperSyncGen");
1248 // also finished with this datastore when aborted
1249 return (isAborted() || testState(dssta_syncgendone,true));
1250} // TSuperDataStore::generateSyncCommands
1251
1252
1253#ifdef SYSYNC_CLIENT1
1254
1255// Client only: initialize Sync alert for datastore according to Parameters set with dsSetClientSyncParams()
1256localstatus TSuperDataStore::engPrepareClientSyncAlert(void)
1257{
1258 localstatus sta;
1259
1260 // not resuming by default
1261 fResuming = false;
1262 fResumeAlertCode = 0;
1263 // prepare all subdatastores that were parametrized to participate in a sync by dsSetClientSyncParams()
1264 TSubDSLinkList::iterator pos;
1265 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
1266 TLocalEngineDS *dsP = pos->fDatastoreLinkP;
1267 if (dsP->testState(dssta_clientparamset)) {
1268 // configured for sync, prepare for alert
1269 sta = dsP->engPrepareClientDSForAlert();
1270 if (sta!=LOCERR_OK)
1271 return sta; // error
1272 // collect slow sync status
1273 fSlowSync = fSlowSync || dsP->fSlowSync;
1274 // collect resume alert code
1275 if (dsP->fResuming) {
1276 // subdatastore would like to resume
1277 if (fResumeAlertCode!=0 && fResumeAlertCode!=dsP->fResumeAlertCode) {
1278 // different idea about what to resume -> can't resume
1279 PDEBUGPRINTFX(DBG_ERROR,("subdatastores differ in resume alert code -> cancel resume of superdatastore")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("subdatastores differ in resume alert code -> cancel resume of superdatastore"
); }
;
1280 fResuming = false;
1281 }
1282 else {
1283 // resume is possible (but might be cancelled if another subdatastore disagrees
1284 fResumeAlertCode = dsP->fResumeAlertCode;
1285 fResuming = true;
1286 }
1287 }
1288 }
1289 }
1290 // now init my own anchors and firstsync state, which are a combination of my subdatastore's
1291 sta = engInitSyncAnchors(NULL__null,NULL__null);
1292 if (sta!=LOCERR_OK)
1293 return sta; // error
1294 // determine final resume state
1295 if (fResuming) {
1296 PDEBUGPRINTFX(DBG_PROTO,("Found suspended session with Alert Code = %hd for all subdatastores",fResumeAlertCode)){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger
()->setNextMask(0x00000010).DebugPrintfLastMask ("Found suspended session with Alert Code = %hd for all subdatastores"
,fResumeAlertCode); }
;
1297 }
1298 else {
1299 // superdatastore can't resume, cancel all subdatastore's resumes that might be set
1300 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
1301 pos->fDatastoreLinkP->fResuming = false;
1302 }
1303 }
1304 // all successful
1305 return LOCERR_OK;
1306} // TSuperDataStore::engPrepareClientSyncAlert
1307
1308
1309
1310// Init engine for client sync
1311// - determine types to exchange
1312// - make sync set ready
1313localstatus TSuperDataStore::engInitForClientSync(void)
1314{
1315 localstatus sta = LOCERR_OK;
1316 // first let all subdatastores init for sync
1317 TSubDSLinkList::iterator pos;
1318 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
1319 sta = pos->fDatastoreLinkP->engInitDSForClientSync();
1320 if (sta!=LOCERR_OK)
1321 return sta;
1322 }
1323 // now change my own state
1324 return inherited::engInitDSForClientSync();
1325} // TSuperDataStore::engInitForClientSync
1326
1327
1328
1329
1330
1331
1332// Client only: returns number of unsent map items
1333sInt32 TSuperDataStore::numUnsentMaps(void)
1334{
1335 // add maps from all subdatastores
1336 uInt32 num=0;
1337 TSubDSLinkList::iterator pos;
1338 for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
1339 num+=pos->fDatastoreLinkP->numUnsentMaps();
1340 }
1341 return num;
1342} // TSuperDataStore::numUnsentMaps
1343
1344
1345// called to mark maps confirmed, that is, we have received ok status for them
1346void TSuperDataStore::engMarkMapConfirmed(cAppCharP aLocalID, cAppCharP aRemoteID)
1347{
1348 // we must detect the subdatastore by prefix
1349 TSubDatastoreLink *linkP = findSubLinkByLocalID(aLocalID);
1350 if (linkP) {
1351 // pass to subdatastore with prefix removed
1352 linkP->fDatastoreLinkP->engMarkMapConfirmed(aLocalID+linkP->fDSLinkConfigP->fGUIDPrefix.size(),aRemoteID);
1353 }
1354} // TSuperDataStore::engMarkMapConfirmed
1355
1356
1357// - client only: called to generate Map items
1358// Returns true if now finished for this datastore
1359// also sets fState to dss_done when finished
1360bool TSuperDataStore::engGenerateMapItems(TMapCommand *aMapCommandP, cAppCharP aLocalIDPrefix)
1361{
1362 TSubDSLinkList::iterator pos=fSubDSLinks.begin();
1363 bool ok;
1364 string prefix;
1365
1366 PDEBUGBLOCKDESC("SuperMapGenerate","TSuperDataStore: Generating Map items...")getDbgLogger()->DebugOpenBlock( "SuperMapGenerate","TSuperDataStore: Generating Map items..."
)
;
1367 do {
1368 // check if already done
1369 if (pos==fSubDSLinks.end()) break; // done
1370 // create current prefix
1371 AssignString(prefix,aLocalIDPrefix);
1372 prefix.append(pos->fDSLinkConfigP->fGUIDPrefix);
1373 // generate Map items
1374 ok=pos->fDatastoreLinkP->engGenerateMapItems(aMapCommandP,prefix.c_str());
1375 // exit if not yet finished with generating map items for this datastore
1376 if (!ok) {
1377 PDEBUGENDBLOCK("MapGenerate")getDbgLogger()->DebugCloseBlock( "MapGenerate");
1378 return false; // not all map items generated
1379 }
1380 // next datastore
1381 pos++;
1382 } while(true);
1383 // done
1384 // we are done if state is syncdone (no more sync commands will occur)
1385 if (testState(dssta_dataaccessdone)) {
1386 changeState(dssta_clientmapssent,true);
1387 PDEBUGPRINTFX(DBG_PROTO,("TSuperDataStore: Finished generating Map items, server has finished <sync>, we are done now")){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger
()->setNextMask(0x00000010).DebugPrintfLastMask ("TSuperDataStore: Finished generating Map items, server has finished <sync>, we are done now"
); }
1388 }
1389 #ifdef SYDEBUG2
1390 // else if we are not yet dssta_syncgendone -> this is the end of a early pending map send
1391 else if (!dbgTestState(dssta_syncgendone)) {
1392 PDEBUGPRINTFX(DBG_PROTO,("TSuperDataStore: Finished sending cached Map items from last session")){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger
()->setNextMask(0x00000010).DebugPrintfLastMask ("TSuperDataStore: Finished sending cached Map items from last session"
); }
1393 }
1394 // otherwise, we are not really finished with the maps yet (but with the current map command)
1395 else {
1396 PDEBUGPRINTFX(DBG_PROTO,("TSuperDataStore: Finished generating Map items for now, but server still sending <Sync>")){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger
()->setNextMask(0x00000010).DebugPrintfLastMask ("TSuperDataStore: Finished generating Map items for now, but server still sending <Sync>"
); }
1397 }
1398 #endif
1399 PDEBUGENDBLOCK("MapGenerate")getDbgLogger()->DebugCloseBlock( "MapGenerate");
1400 return true;
1401} // TSuperDataStore::engGenerateMapItems
1402
1403
1404#endif // SYSYNC_CLIENT
1405
1406
1407/* end of TSuperDataStore implementation */
1408
1409#endif // SUPERDATASTORES
1410
1411// eof