File: | libsynthesis/src/sysync/superdatastore.cpp |
Warning: | line 724, column 15 Value stored to 'regular' is never read |
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 | |
26 | using namespace sysync; |
27 | |
28 | |
29 | // sub-datastore link config |
30 | // ========================= |
31 | |
32 | |
33 | // config constructor |
34 | TSubDSLinkConfig::TSubDSLinkConfig(TLocalDSConfig *aLocalDSConfigP, TConfigElement *aParentElementP) : |
35 | TConfigElement(aLocalDSConfigP->getName(),aParentElementP) |
36 | { |
37 | clear(); |
38 | fLinkedDSConfigP=aLocalDSConfigP; |
39 | } // TSubDSLinkConfig::TSubDSLinkConfig |
40 | |
41 | |
42 | // config destructor |
43 | TSubDSLinkConfig::~TSubDSLinkConfig() |
44 | { |
45 | clear(); |
46 | } // TSubDSLinkConfig::~TSubDSLinkConfig |
47 | |
48 | |
49 | // init defaults |
50 | void 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 |
63 | bool 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 | |
84 | TSuperDSConfig::TSuperDSConfig(const char* aName, TConfigElement *aParentElement) : |
85 | TLocalDSConfig(aName,aParentElement) |
86 | { |
87 | clear(); |
88 | } // TSuperDSConfig::TSuperDSConfig |
89 | |
90 | |
91 | TSuperDSConfig::~TSuperDSConfig() |
92 | { |
93 | clear(); |
94 | } // TSuperDSConfig::~TSuperDSConfig |
95 | |
96 | |
97 | // init defaults |
98 | void 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 |
114 | bool 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 |
146 | void 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 |
158 | TLocalEngineDS *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 | |
179 | TSuperDataStore::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 | |
201 | void 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 | |
225 | void 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 | |
240 | TSuperDataStore::~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 | |
253 | bool 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 |
265 | uInt32 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 | |
276 | bool 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 | |
287 | void 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 |
317 | TAlertCommand *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 |
401 | bool 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 |
414 | void 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 |
429 | void 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 |
445 | void 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 |
461 | localstatus 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) |
478 | bool 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) |
519 | bool 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 |
541 | localstatus 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 | ); |
557 | done: |
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!). |
572 | bool 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 |
792 | nods: |
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; |
800 | done: |
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 |
813 | bool 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) |
827 | void 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 |
842 | bool 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) |
857 | void 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 |
881 | localstatus 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) |
936 | bool 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. |
950 | bool 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 |
967 | cAppCharP 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 |
989 | TSubDatastoreLink *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 |
1007 | TSubDatastoreLink *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 |
1025 | bool 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 |
1038 | bool 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) |
1054 | bool 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 |
1068 | sInt32 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 |
1084 | void 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 |
1115 | bool 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" |
1128 | localstatus 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 |
1180 | void 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 |
1210 | bool 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() |
1256 | localstatus 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 |
1313 | localstatus 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 |
1333 | sInt32 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 |
1346 | void 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 |
1360 | bool 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 |