Bug Summary

File:libsynthesis/src/sysync/binfileimplds.cpp
Warning:line 1588, column 15
Access to field 'flags' results in a dereference of a null pointer (loaded from variable 'chglogP')

Annotated Source Code

1/**
2 * @File binfileimplds.cpp
3 *
4 * @Author Lukas Zeller (luz@plan44.ch)
5 *
6 * @brief TBinfileImplDS
7 * Represents a client datastore implementation which has target management
8 * (and optionally change log) based on binary files
9 *
10 * Copyright (c) 2003-2011 by Synthesis AG + plan44.ch
11 *
12 * @Date 2005-09-30 : luz : created from TBinfileImplDS
13 */
14/*
15 */
16
17// includes
18#include "prefix_file.h"
19#include "sysync.h"
20#include "binfileimplclient.h"
21#include "binfileimplds.h"
22#include <cstddef>
23
24#if defined(BINFILE_ALWAYS_ACTIVE) && defined(SYSYNC_SERVER1)
25 #error "BINFILE_ALWAYS_ACTIVE is not compatible with server-enabled builds"
26#endif
27
28
29namespace sysync {
30
31
32#ifdef SCRIPT_SUPPORT1
33
34// Script Functions
35// ================
36
37
38class TBFDSfuncs {
39public:
40
41 static TItemField *fieldFromStructField(cAppCharP aFieldName, const TStructFieldInfo *aStructFieldInfos, sInt32 aNumFields, uInt8P aStructAddr, TScriptContext *aFuncContextP)
42 {
43 TItemField *fldP = NULL__null;
44 // search for name
45 for (sInt32 i=0; i<aNumFields; i++) {
46 const TStructFieldInfo *info = &aStructFieldInfos[i];
47 if (strucmp(info->valName, aFieldName)==0 && info->valSiz>0) {
48 // found field
49 if (info->valType==VALTYPE_TEXT) {
50 // text
51 fldP = newItemField(fty_string, aFuncContextP->getSessionZones());
52 fldP->setAsString((cAppCharP)(aStructAddr+info->fieldOffs));
53 return fldP;
54 }
55 else if (info->valType==VALTYPE_TIME64) {
56 // timestamp
57 fldP = newItemField(fty_timestamp, aFuncContextP->getSessionZones());
58 static_cast<TTimestampField *>(fldP)->setTimestampAndContext(
59 *((lineartime_t *)(aStructAddr+info->fieldOffs)),
60 TCTX_UTC((timecontext_t) ((tctx_tz_UTC) | TCTX_SYMBOLIC_TZ)) // internal timestamps are UTC
61 );
62 return fldP;
63 }
64 else {
65 // all other types are treated as integers
66 fieldinteger_t fint = 0;
67 switch(info->valSiz) {
68 case 1 : fint = *((uInt8 *)(aStructAddr+info->fieldOffs)); break;
69 case 2 : fint = *((uInt16 *)(aStructAddr+info->fieldOffs)); break;
70 case 4 : fint = *((uInt32 *)(aStructAddr+info->fieldOffs)); break;
71 case 8 : fint = *((uInt64 *)(aStructAddr+info->fieldOffs)); break;
72 }
73 fldP = newItemField(fty_integer, aFuncContextP->getSessionZones());
74 fldP->setAsInteger(fint);
75 return fldP;
76 }
77 }
78 }
79 // no such field, return an unassigned field
80 fldP=newItemField(fty_none, aFuncContextP->getSessionZones());
81 fldP->unAssign(); // make it (already is...) unassigned
82 return fldP;
83 } // fieldFromStructField
84
85
86 // variant PROFILESETTING(string settingsfieldname)
87 // returns data from profile settings (like /profiles/n does)
88 static void func_ProfileSetting(TItemField *&aTermP, TScriptContext *aFuncContextP)
89 {
90 string varname;
91 TBinfileImplDS *dsP = static_cast<TBinfileImplDS *>(aFuncContextP->getCallerContext());
92 // get name
93 aFuncContextP->getLocalVar(0)->getAsString(varname);
94 // get value
95 aTermP = fieldFromStructField(
96 varname.c_str(),
97 ProfileFieldInfos, numProfileFieldInfos,
98 (uInt8P)&(static_cast<TBinfileImplClient *>(dsP->getSession())->fProfile),
99 aFuncContextP
100 );
101 }; // func_ProfileSetting
102
103
104 // variant TARGETSETTING(string settingsfieldname)
105 // returns data from target settings (like /profiles/n/targets/dbid/settingsfieldname does)
106 static void func_TargetSetting(TItemField *&aTermP, TScriptContext *aFuncContextP)
107 {
108 string varname;
109 TBinfileImplDS *dsP = static_cast<TBinfileImplDS *>(aFuncContextP->getCallerContext());
110 // get name
111 aFuncContextP->getLocalVar(0)->getAsString(varname);
112 // get value
113 aTermP = fieldFromStructField(
114 varname.c_str(),
115 TargetFieldInfos, numTargetFieldInfos,
116 (uInt8P)&(dsP->fTarget),
117 aFuncContextP
118 );
119 }; // func_TargetSetting
120
121
122}; // TBFDSfuncs
123
124
125const uInt8 param_OneStr[] = { VAL(fty_string)( (uInt8)fty_string) };
126
127const TBuiltInFuncDef BinfileDBFuncDefs[] = {
128 { "TARGETSETTING", TBFDSfuncs::func_TargetSetting, fty_none, 1, param_OneStr },
129 { "PROFILESETTING", TBFDSfuncs::func_ProfileSetting, fty_none, 1, param_OneStr },
130};
131
132
133// chain to general ClientDB functions
134static void *BinfileClientDBChainFunc(void *&aCtx)
135{
136 // caller context remains unchanged
137 // -> no change needed
138 // next table is general ClientDB func table
139 return (void *)&ClientDBFuncTable;
140} // BinfileClientDBChainFunc
141
142
143// function table for client-only script functions
144const TFuncTable BinfileClientDBFuncTable = {
145 sizeof(BinfileDBFuncDefs) / sizeof(TBuiltInFuncDef), // size of table
146 BinfileDBFuncDefs, // table pointer
147 BinfileClientDBChainFunc // chain to general agent funcs.
148};
149
150
151#endif // SCRIPT_SUPPORT
152
153
154// Config
155// ======
156
157TBinfileDSConfig::TBinfileDSConfig(const char* aName, TConfigElement *aParentElement) :
158 TLocalDSConfig(aName,aParentElement)
159{
160 // nop so far
161 clear();
162} // TBinfileDSConfig::TBinfileDSConfig
163
164
165TBinfileDSConfig::~TBinfileDSConfig()
166{
167 // nop so far
168} // TBinfileDSConfig::~TBinfileDSConfig
169
170
171// init defaults
172void TBinfileDSConfig::clear(void)
173{
174 // Only active in clients by default
175 fBinfileDSActive = IS_CLIENT(!getSyncAppBase()->isServer());
176 // change detection by CRC is enabled by default only for builds that CAN'T have DB-side detection
177 #ifdef CHANGEDETECTION_AVAILABLE1
178 fCRCChangeDetection = false; // normally, DB can report changes. CRC checking can be enabled as an option
179 fCRCPseudoChangeDetection = false; // normally, DB reports changes correctly. Verifying changes can be enabled as an option
180 #endif
181 // init defaults
182 fLocalDBPath.erase();
183 fDSAvailFlag=0;
184 // set default according to former build-time target setting
185 #ifdef SYNCTIME_IS_ENDOFSESSION
186 fCmpRefTimeStampAtEnd = true;
187 #else
188 fCmpRefTimeStampAtEnd = false;
189 #endif
190 // clear inherited
191 inherited::clear();
192} // TBinfileDSConfig::clear
193
194
195#ifndef HARDCODED_CONFIG
196
197// config element parsing
198bool TBinfileDSConfig::localStartElement(const char *aElementName, const char **aAttributes, sInt32 aLine)
199{
200 // checking the elements
201 if (strucmp(aElementName,"dbpath")==0)
202 expectString(fLocalDBPath);
203 else if (strucmp(aElementName,"dsavailflag")==0)
204 expectUInt16(fDSAvailFlag);
205 else if (strucmp(aElementName,"cmptimestampatend")==0)
206 expectBool(fCmpRefTimeStampAtEnd);
207 else if (strucmp(aElementName,"binfiledsactive")==0)
208 expectBool(fBinfileDSActive);
209 #ifdef CHANGEDETECTION_AVAILABLE1
210 else if (strucmp(aElementName,"crcchangedetection")==0)
211 expectBool(fCRCChangeDetection);
212 else if (strucmp(aElementName,"pseudochangedetection")==0)
213 expectBool(fCRCPseudoChangeDetection);
214 #endif
215 // - none known here
216 else
217 return TLocalDSConfig::localStartElement(aElementName,aAttributes,aLine);
218 // ok
219 return true;
220} // TBinfileDSConfig::localStartElement
221
222#endif
223
224// resolve
225void TBinfileDSConfig::localResolve(bool aLastPass)
226{
227 if (aLastPass) {
228 // check for required settings
229 #ifdef CHANGEDETECTION_AVAILABLE1
230 // - pseudochange detection would interfere with regular CRC based change detection and is also completely useless then
231 if (fCRCChangeDetection) fCRCPseudoChangeDetection = false; // just switch it off, makes no sense
232 #endif
233 }
234 // resolve inherited
235 inherited::localResolve(aLastPass);
236} // TBinfileDSConfig::localResolve
237
238
239
240// checks if datastore is available for given profile. If aProfileP is NULL,
241// general availability is checked (profile might allow more or less)
242bool TBinfileDSConfig::isAvailable(TBinfileDBSyncProfile *aProfileP)
243{
244 #ifndef DSFLAGS_ALWAYS_AVAILABLE
245 // all datastores are always available
246 return true;
247 #else
248 // check if available
249 // - %%%later: check if license allows using this datastore
250 // %%%
251 // - if it's one of the always available datastores, always return true
252 if (fDSAvailFlag & DSFLAGS_ALWAYS_AVAILABLE) return true;
253 // - check if it's enabled in the profile
254 if (aProfileP==NULL__null) return false; // no profile
255 return (aProfileP->dsAvailFlags & fDSAvailFlag)!=0;
256 #endif
257} // TBinfileDSConfig::isAvailable
258
259
260
261#ifndef DEFAULT_SYNCMODEsmo_twoway
262#define DEFAULT_SYNCMODEsmo_twoway smo_twoway
263#endif
264
265// init default target for datastore
266void TBinfileDSConfig::initTarget(
267 TBinfileDBSyncTarget &aTarget,
268 uInt32 aRemotepartyID,
269 const char *aRemoteName, // defaults to name of datastore
270 bool aEnabled // enabled?
271)
272{
273 //set to zeros to avoid memory warnings
274 memset(&aTarget, 0, sizeof(aTarget));
275 // link to the profile
276 aTarget.remotepartyID=aRemotepartyID;
277 // enabled or not?
278 aTarget.enabled=aEnabled;
279 // force slow sync (slow sync is used anyway, but shows this to user)
280 aTarget.forceSlowSync=true;
281 // sync mode
282 aTarget.syncmode=DEFAULT_SYNCMODEsmo_twoway;
283 // reset all options
284 aTarget.limit1=0;
285 aTarget.limit2=0;
286 aTarget.extras=0;
287 // database identification
288 aTarget.localDBTypeID=fLocalDBTypeID; // what target database
289 AssignCString(aTarget.localDBPath,fLocalDBPath.c_str(),localDBpathMaxLen);
290 #if defined(DESKTOP_CLIENT1) || TARGETS_DB_VERSION6>4
291 AssignCString(aTarget.localContainerName,NULL__null,localDBpathMaxLen);
292 #endif
293 // link to configuration is by datastore name
294 AssignCString(aTarget.dbname,getName(),dbnamelen);
295 // default name for remote datastore is same as local one
296 if (!aRemoteName) aRemoteName=getName();
297 AssignCString(aTarget.remoteDBpath,aRemoteName,remoteDBpathMaxLen);
298 // - init new target record's variables (will be updated after sync)
299 aTarget.lastSync=0; // no last sync date yet
300 aTarget.lastChangeCheck=0;
301 aTarget.lastSuspendModCount=0; /// @note: before DS 1.2 enginem this was used as "lastModCount"
302 aTarget.resumeAlertCode=0; // no resume yet
303 aTarget.lastTwoWayModCount=0;
304 aTarget.remoteAnchor[0]=0; // no anchor yet
305 // Version 6 and later
306 #if TARGETS_DB_VERSION6>5
307 aTarget.dummyIdentifier1[0]=0;
308 aTarget.dummyIdentifier2[0]=0;
309 AssignCString(aTarget.remoteDBdispName, getName(), dispNameMaxLen); // default to local name
310 aTarget.filterCapDesc[0]=0;
311 aTarget.remoteFilters[0]=0;
312 aTarget.localFilters[0]=0;
313 #endif
314} // initTarget
315
316
317
318
319/*
320 * Implementation of TBinfileImplDS
321 */
322
323TBinfileImplDS::TBinfileImplDS(
324 TBinfileDSConfig *aConfigP,
325 sysync::TSyncSession *aSessionP,
326 const char *aName,
327 uInt32 aCommonSyncCapMask
328) :
329 TStdLogicDS(aConfigP, aSessionP, aName, aCommonSyncCapMask)
330{
331 // no changelog loaded yet (needed here because InternalResetDataStore will test it)
332 fLoadedChangeLog=NULL__null;
333 fLoadedChangeLogEntries=0; // just to make sure
334 fHasPendingChanges=false;
335 fPreviousToRemoteModCount=0;
336 fPreviousSuspendModCount=0;
337 fCurrentModCount=0;
338 // now do internal reset
339 InternalResetDataStore();
340 // save config pointer
341 fConfigP=aConfigP;
342 // no target loaded yet
343 fTargetIndex=-1;
344} // TBinfileImplDS::TBinfileImplDS
345
346
347
348void TBinfileImplDS::dsResetDataStore(void)
349{
350 // Do my normal internal reset
351 InternalResetDataStore();
352 // Let ancestor initialize
353 inherited::dsResetDataStore();
354 if (binfileDSActive()) {
355 // And now force MaxGUIDSize to what this datastore can handle
356 fMaxGUIDSize=BINFILE_MAXGUIDSIZE63;
357 }
358} // TBinfileImplDS::dsResetDataStore
359
360
361void TBinfileImplDS::InternalResetDataStore(void)
362{
363 // forget preflight
364 fPreflighted=false;
365 // forget loaded changelog
366 forgetChangeLog();
367 // no pending changes known yet
368 fHasPendingChanges=0;
369 // unknown number of changes
370 fNumberOfLocalChanges=-1;
371} // TBinfileImplDS::InternalResetDataStore
372
373
374TBinfileImplDS::~TBinfileImplDS()
375{
376 InternalResetDataStore();
377} // TBinfileImplDS::~TBinfileImplDS
378
379
380// called when message processing (and probably thread) ends
381// (can be used to finalize things that cannot continue until next request
382// such as code that cannot be called from different threads)
383void TBinfileImplDS::dsEndOfMessage(void)
384{
385 // %%% save between messages in debug
386 #ifdef SYDEBUG2
387 //endWrite();
388 #endif
389 // let ancestor do things
390 inherited::dsEndOfMessage();
391} // TBinfileImplDS::dsEndOfMessage
392
393
394/// inform logic of coming state change
395localstatus TBinfileImplDS::dsBeforeStateChange(TLocalEngineDSState aOldState,TLocalEngineDSState aNewState)
396{
397 return inherited::dsBeforeStateChange(aOldState, aNewState);
398} // TBinfileImplDS::dsBeforeStateChange
399
400
401/// inform logic of happened state change
402localstatus TBinfileImplDS::dsAfterStateChange(TLocalEngineDSState aOldState,TLocalEngineDSState aNewState)
403{
404 if (aNewState == dssta_completed) {
405 // free resources which are not valid when restarting,
406 // in particular the change log
407 InternalResetDataStore();
408 }
409 return inherited::dsAfterStateChange(aOldState, aNewState);
410} // TBinfileImplDS::dsAfterStateChange
411
412
413// - init Sync Parameters for datastore
414// Derivates might override this to pre-process and modify parameters
415// (such as adding client settings as CGI to remoteDBPath)
416bool TBinfileImplDS::dsSetClientSyncParams(
417 TSyncModes aSyncMode,
418 bool aSlowSync,
419 const char *aRemoteDBPath,
420 const char *aDBUser,
421 const char *aDBPassword,
422 const char *aLocalPathExtension,
423 const char *aRecordFilterQuery,
424 bool aFilterInclusive
425)
426{
427 if (binfileDSActive()) {
428 #ifdef AUTOSYNC_SUPPORT
429 string s;
430 bool cgi=false;
431 // add autosync options if this is an autosync
432 if (fConfigP->fAutosyncAlerted || fConfigP->fAutosyncForced) {
433 if (!fConfigP->fAutosyncPathCGI.empty()) {
434 s=aRemoteDBPath;
435 cgi = s.find('?')!=string::npos;
436 if (!cgi) { s+='?'; cgi=true; }
437 s += fConfigP->fAutosyncPathCGI;
438 aRemoteDBPath=s.c_str();
439 }
440 }
441 #endif
442 }
443 return inherited::dsSetClientSyncParams(aSyncMode,aSlowSync,aRemoteDBPath,aDBUser,aDBPassword,aLocalPathExtension,aRecordFilterQuery,aFilterInclusive);
444} // TBinfileImplDS::dsSetClientSyncParams
445
446
447
448// BinFile DB implementation specific routines
449// ===========================================
450
451
452// clean up change log
453// - removes chgl_deleted entries that are older or
454// same age as indicated by aOldestSyncModCount)
455// - finalizes localids
456localstatus TBinfileImplDS::changeLogPostflight(uInt32 aOldestSyncModCount)
457{
458 // review all logentries
459 TChangeLogEntry logentry;
460 uInt32 logindex=0;
461 while (true) {
462 if (fChangeLog.readRecord(logindex,&logentry)!=BFE_OK0) break; // seen all
463 if (
464 (logentry.flags & chgl_deleted) &&
465 (logentry.modcount<=aOldestSyncModCount)
466 ) {
467 // all peers (in all profiles related to this changelog, which is only one with the separated changelogs!)
468 // have seen this delete already, so this one should be deleted
469 // - delete the record, another one will appear at this index
470 fChangeLog.deleteRecord(logindex);
471 }
472 else {
473 // no delete, finalize localid (possible only with string localIDs)
474 #ifndef NUMERIC_LOCALIDS
475 localid_out_t locID = logentry.dbrecordid;
476 if (dsFinalizeLocalID(locID)) {
477 // update log entry
478 ASSIGN_LOCALID_TO_FLD(logentry.dbrecordid,LOCALID_OUT_TO_IN(locID))AssignCString(logentry.dbrecordid,((char *)locID.c_str()),maxidlen
)
;
479 fChangeLog.updateRecord(logindex, &logentry);
480 }
481 #endif
482 // no delete, advance index
483 logindex++;
484 }
485 }
486 return LOCERR_OK;
487} // TBinfileImplDS::changeLogPostflight
488
489
490// zap changelog. Should be called if datastore as a entiety was replaced
491// by another datatstore (or created new)
492void TBinfileImplDS::zapChangeLog(void)
493{
494 // forget cached changelog if any
495 forgetChangeLog();
496 // make sure changelog file is open
497 if (openChangeLog()) {
498 // kill all entries
499 fChangeLog.truncate(0);
500 // reset modcount
501 fChgLogHeader.modcount = 0;
502 fChgLogHeader.lastChangeCheckIdentifier[0] = 0;
503 fChgLogHeader.lastChangeCheck = noLinearTime;
504 // make sure header is written
505 fChangeLog.setExtraHeaderDirty();
506 fChangeLog.flushHeader();
507 }
508 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("zapChangeLog: erased changelog")){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("zapChangeLog: erased changelog"); }
;
509} // TBinfileImplDS::zapChangeLog
510
511
512
513
514// update change log record contents
515static uInt32 changelogUpdateFunc(uInt32 aOldVersion, uInt32 aNewVersion, void *aOldRecordData, void *aNewRecordData, uInt32 aOldSize)
516{
517 if (aOldVersion<LOWEST_CHANGELOG_DB_VERSION2 || aOldVersion>CHANGELOG_DB_VERSION5) return 0; // unknown old version or too new version, cannot update
518 if (aNewVersion!=CHANGELOG_DB_VERSION5) return 0; // cannot update to other version than current
519 // create default values for profile
520 if (aOldRecordData && aNewRecordData) {
521 // update records
522 TChangeLogEntry *chglogEntryP = (TChangeLogEntry *)aNewRecordData;
523 // check for special case that old record is V2 or V3 and was compiled without CHANGEDETECTION_AVAILABLE
524 uInt16 crc = 0;
525 if ((aOldVersion==2 || aOldVersion==3) && aOldSize!=offsetof(TChangeLogEntry,modcount_created)__builtin_offsetof(TChangeLogEntry, modcount_created)) {
526 // this means that the records were compiled without CHANGEDETECTION_AVAILABLE and had a
527 // dataCRC field between modcount and flags
528 //#if defined(WINCE) ||
529 #if defined(__PALM_OS__)
530 #error "This code must be verified to check if upgrade works as intended with targets that did not have CHANGEDETECTION_AVAILABLE"
531 #endif
532 // - offset of the CRC field we already have
533 int o = offsetof(TChangeLogEntry,flags)__builtin_offsetof(TChangeLogEntry, flags);
534 // - copy up to the CRC which is already there
535 memcpy(aNewRecordData,aOldRecordData,o);
536 // - get the CRC which is already there to init the new V5 DB field below
537 crc = *((uInt16 *)((uInt8 *)aOldRecordData+o));
538 // - also copy the flags
539 chglogEntryP->flags = *((uInt8 *)((uInt8 *)aOldRecordData+o+sizeof(uInt16))); // next after dataCRC
540 chglogEntryP->dummy = *((uInt8 *)((uInt8 *)aOldRecordData+o+sizeof(uInt16)+sizeof(uInt8))); // next after flags
541 }
542 else {
543 // copy old data - beginning of record is identical
544 memcpy(aNewRecordData,aOldRecordData,aOldSize);
545 }
546 // now initialize fields that old version didn't have
547 if (aOldVersion<4) {
548 // init new version 4 fields
549 chglogEntryP->modcount_created = 0; // assume created before changelogging history started
550 }
551 if (aOldVersion<5) {
552 // init new V5 dataCRC; if we are updating from V2 or V3 (which is handled above) we'll assign the previous CRC here, 0 otherwise
553 chglogEntryP->dataCRC = crc;
554 }
555 }
556 else if (aNewRecordData) {
557 // update extra header
558 TChangeLogHeader *extraHeaderP = (TChangeLogHeader *)aNewRecordData;
559 if (aOldVersion<3) {
560 // header has got new fields between v2 and v3
561 // Note: these will be updated with data from target fields after actually opening the changelog
562 // Just init them now
563 extraHeaderP->lastChangeCheckIdentifier[0] = 0;
564 extraHeaderP->lastChangeCheck = noLinearTime;
565 }
566 // updated header ok
567 return sizeof(TChangeLogHeader);
568 }
569 // updated ok (or updateable ok if no data pointers provided)
570 // - return size of new record
571 return sizeof(TChangeLogEntry);
572} // changelogUpdateFunc
573
574
575// returns true if we had a valid changelog
576bool TBinfileImplDS::openChangeLog(void)
577{
578 if (fChangeLog.isOpen()) return true; // was already open
579 // open and possibly migrate the changelog
580 TBinfileImplClient *bfcP = static_cast<TBinfileImplClient *>(fSessionP);
581 TBinfileClientConfig *bfcfgP = static_cast<TBinfileClientConfig *>(fSessionP->getSessionConfig());
582 // open changelog. Name is datastore name with _clg.bfi suffix
583 string changelogname = bfcfgP->relatedDBNameBase(getName(), bfcP->fRemotepartyID);
584 changelogname += CHANGELOG_DB_SUFFIX"_clg_" "sysynclib_" ".bfi";
585 fChangeLog.setFileInfo(changelogname.c_str(),CHANGELOG_DB_VERSION5,CHANGELOG_DB_ID4,sizeof(TChangeLogEntry));
586 if (fChangeLog.open(sizeof(TChangeLogHeader),&fChgLogHeader,changelogUpdateFunc)!=BFE_OK0) {
587 // can't open changelog - check if we might need need migration from united changelogs to separated
588 if (bfcfgP->fSeparateChangelogs) {
589 // check if we have the old united changelog and migrate everything if so
590 string unitedchangelogname = bfcfgP->relatedDBNameBase(getName(), -1); // united name
591 unitedchangelogname += CHANGELOG_DB_SUFFIX"_clg_" "sysynclib_" ".bfi";
592 fChangeLog.setFileInfo(unitedchangelogname.c_str(),CHANGELOG_DB_VERSION5,CHANGELOG_DB_ID4,sizeof(TChangeLogEntry));
593 if (fChangeLog.open(sizeof(TChangeLogHeader),&fChgLogHeader,changelogUpdateFunc)==BFE_OK0) {
594 // the old unified changelog is there - we need to do a full migration now
595 // - close it
596 fChangeLog.close();
597 // - perform migration for this DB
598 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("openChangeLog: auto-migrating from common to profile-separated changelog for this datastore")){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("openChangeLog: auto-migrating from common to profile-separated changelog for this datastore"
); }
;
599 bfcfgP->separateChangeLogsAndRelated(getName());
600 // - recursively call myself, now the profile specific log should be there
601 return openChangeLog();
602 }
603 // we're not migrating (we could not open the changelog because this is a new profile!)
604 // - restore the per-profile name for creation of new log below
605 fChangeLog.setFileInfo(changelogname.c_str(),CHANGELOG_DB_VERSION5,CHANGELOG_DB_ID4,sizeof(TChangeLogEntry));
606 }
607 // create new change log or overwrite incompatible one
608 // - init changelog header fields
609 fChgLogHeader.modcount=0;
610 //set all bytes to zero to avoid memory warnings
611 memset(fChgLogHeader.lastChangeCheckIdentifier, 0, changeIndentifierMaxLen);
612 fChgLogHeader.lastChangeCheck = noLinearTime;
613 // - create new changelog
614 fChangeLog.create(sizeof(TChangeLogEntry),sizeof(TChangeLogHeader),&fChgLogHeader,true);
615 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("openChangeLog: changelog did not exist (or bad version) -> created new")){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("openChangeLog: changelog did not exist (or bad version) -> created new"
); }
;
616 return false; // changelog is new, so we need a slow sync
617 }
618 else {
619 // check if opening was an upgrade from version 2
620 if (fChangeLog.getFoundVersion()<3) {
621 // version 3 has introduced saving the last-check date/identifiers in the changelog header,
622 // before that the identifiers used where (wrongly) those of the target. So copy
623 // the target info to the new header now. This gives perfect results only for single
624 // profile use, but existing products before update to v3 were single profile so we can
625 // safely assume this will give a smooth transition (without re-send-everything effects).
626 #if TARGETS_DB_VERSION6>5
627 // - dummyIdentifier1 is the former lastSyncIdentifier and contains the token from the
628 // last change check towards the DB (in case sync identifiers are available at all)
629 AssignCString(fChgLogHeader.lastChangeCheckIdentifier,fTarget.dummyIdentifier1,changeIndentifierMaxLen);
630 #endif
631 // - lastChangeCheck is the former lastTwoWaySync and contains the timestamp of the last change check towards the DB
632 fChgLogHeader.lastChangeCheck = fTarget.lastChangeCheck;
633 // - make sure it gets written back
634 fChangeLog.setExtraHeaderDirty();
635 fChangeLog.flushHeader();
636 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("openChangeLog: upgraded changelog from V2 to V4 (new header, new modcount_created)")){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("openChangeLog: upgraded changelog from V2 to V4 (new header, new modcount_created)"
); }
;
637 }
638 }
639 return true; // changelog already existed, so we assume it's up-to-date
640} // TBinfileImplDS::openChangeLog
641
642
643// returns true if we had a valid pending map file
644bool TBinfileImplDS::openPendingMaps(void)
645{
646 if (fPendingMaps.isOpen()) return true; // was already open
647 openChangeLog(); // must be open, because it checks for migration of pendingmaps as well
648 string pendingmapsname = static_cast<TBinfileClientConfig *>(fSessionP->getSessionConfig())->relatedDBNameBase(getName(), fTarget.remotepartyID);
649 pendingmapsname += PENDINGMAP_DB_SUFFIX"_pmap_" "sysynclib_" ".bfi";
650 fPendingMaps.setFileInfo(pendingmapsname.c_str(),PENDINGMAP_DB_VERSION1,PENDINGMAP_DB_ID7, sizeof(TPendingMapEntry));
651 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,("openPendingMaps: file name='%s'",pendingmapsname.c_str())){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
("openPendingMaps: file name='%s'",pendingmapsname.c_str());
}
;
652 if (fPendingMaps.open(sizeof(TPendingMapHeader),&fPendingMapHeader)!=BFE_OK0) {
653 // create new pending maps or overwrite incompatible one
654 // - bind to remote party (in case of combined changelog, we only have a single pendingmap file, and it is valid only for ONE remote party)
655 fPendingMapHeader.remotepartyID = static_cast<TBinfileImplClient *>(fSessionP)->fRemotepartyID;
656 // - create new changelog
657 fPendingMaps.create(sizeof(TPendingMapEntry),sizeof(TPendingMapHeader),&fPendingMapHeader,true);
658 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("openPendingMaps: pending maps did not exist (or bad version) -> created new")){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("openPendingMaps: pending maps did not exist (or bad version) -> created new"
); }
;
659 return false; // pending map file is new, so we have no already pending maps
660 }
661 return true; // pending map file already existed, so we assume it's up-to-date
662} // TBinfileImplDS::openPendingMaps
663
664
665// get reference time to be used as reference date for this sync's modifications
666// Note: this time marks the beginning of the sync session. If possible
667// datastore should mark all modifications with this time, even if
668// they occur later during the sync session. Only if setting the
669// modified date explicitly is not possible, setting fCmpRefTimeStampAtEnd
670// (default = defined(SYNCTIME_IS_ENDOFSESSION)) can be used to make sure
671// that modifications made during the session are not detected as changed
672// for the next session.
673lineartime_t TBinfileImplDS::getThisSyncModRefTime(void)
674{
675 return
676 #ifdef SYNCTIME_IS_LOCALTIME
677 makeLocalTimestamp(fCurrentSyncTime); // make local time for comparison
678 #else
679 fCurrentSyncTime;
680 #endif
681} // TBinfileImplDS::getThisSyncModRefTime
682
683
684// get reference time to be used in case datastore implementation wants to compare
685// with the time of last sync (last two-way sync, that is!)
686lineartime_t TBinfileImplDS::getLastSyncModRefTime(void)
687{
688 return
689 #ifdef SYNCTIME_IS_LOCALTIME
690 makeLocalTimestamp(fPreviousSyncTime); // make local time for comparison
691 #else
692 fPreviousSyncTime;
693 #endif
694} // TBinfileImplDS::getLastSyncModRefTime
695
696
697
698// update change log using CRC checksum comparison before syncing
699// Note: Don't call before types are ok (we need TSyncItems)
700localstatus TBinfileImplDS::changeLogPreflight(bool &aValidChangelog)
701{
702 localstatus sta = LOCERR_OK;
703 aValidChangelog = false;
704 bferr err = BFE_OK0;
705 TChangeLogEntry *existingentries = NULL__null; // none yet
706 uInt32 numexistinglogentries;
707 bool foundone;
708 uInt32 seen = 0;
709 uInt32 logindex;
710 TChangeLogEntry newentry;
711 //set zeros to avoid memory warnings
712 memset(&newentry, 0, sizeof(newentry));
713 TSyncItem *itemP = NULL__null;
714 localid_out_t itemLocalID;
715 uInt16 dataCRC = 0;
716 bool itemIsModified = false;
717
718 // just in case: make sure we don't have a changelog loaded here
719 forgetChangeLog();
720 // no changes detected yet
721 fNumberOfLocalChanges=0;
722 // make sure we have the change log DB open
723 openChangeLog();
724 // - get saved modcount for this database and increment for this preflight
725 fChgLogHeader.modcount += 1;
726 fCurrentModCount = fChgLogHeader.modcount;
727 // - update date of last check to start of sync - everything happening during or after this sync is for next session
728 // Note: this is used only if not CRC_CHANGE_DETECTION
729 fChgLogHeader.lastChangeCheck = fCurrentSyncTime;
730 // change log header is dirty
731 fChangeLog.setExtraHeaderDirty();
732 PDEBUGBLOCKCOLL("changeLogPreflight")getDbgLogger()->DebugOpenBlock( "changeLogPreflight",__null
,true)
;
733 #ifdef SYDEBUG2
734 string lsd;
735 StringObjTimestamp(lsd,fPreviousSyncTime);
736 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,({ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "changeLogPreflight: %sfCurrentModCount=%ld, fPreviousToRemoteModCount=%ld, fPreviousSyncTime(UTC)=%s"
, isResuming() ? "RESUMING, " : "", (long)fCurrentModCount, (
long)fPreviousToRemoteModCount, lsd.c_str() ); }
737 "changeLogPreflight: %sfCurrentModCount=%ld, fPreviousToRemoteModCount=%ld, fPreviousSyncTime(UTC)=%s",{ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "changeLogPreflight: %sfCurrentModCount=%ld, fPreviousToRemoteModCount=%ld, fPreviousSyncTime(UTC)=%s"
, isResuming() ? "RESUMING, " : "", (long)fCurrentModCount, (
long)fPreviousToRemoteModCount, lsd.c_str() ); }
738 isResuming() ? "RESUMING, " : "",{ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "changeLogPreflight: %sfCurrentModCount=%ld, fPreviousToRemoteModCount=%ld, fPreviousSyncTime(UTC)=%s"
, isResuming() ? "RESUMING, " : "", (long)fCurrentModCount, (
long)fPreviousToRemoteModCount, lsd.c_str() ); }
739 (long)fCurrentModCount,{ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "changeLogPreflight: %sfCurrentModCount=%ld, fPreviousToRemoteModCount=%ld, fPreviousSyncTime(UTC)=%s"
, isResuming() ? "RESUMING, " : "", (long)fCurrentModCount, (
long)fPreviousToRemoteModCount, lsd.c_str() ); }
740 (long)fPreviousToRemoteModCount,{ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "changeLogPreflight: %sfCurrentModCount=%ld, fPreviousToRemoteModCount=%ld, fPreviousSyncTime(UTC)=%s"
, isResuming() ? "RESUMING, " : "", (long)fCurrentModCount, (
long)fPreviousToRemoteModCount, lsd.c_str() ); }
741 lsd.c_str(){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "changeLogPreflight: %sfCurrentModCount=%ld, fPreviousToRemoteModCount=%ld, fPreviousSyncTime(UTC)=%s"
, isResuming() ? "RESUMING, " : "", (long)fCurrentModCount, (
long)fPreviousToRemoteModCount, lsd.c_str() ); }
742 )){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "changeLogPreflight: %sfCurrentModCount=%ld, fPreviousToRemoteModCount=%ld, fPreviousSyncTime(UTC)=%s"
, isResuming() ? "RESUMING, " : "", (long)fCurrentModCount, (
long)fPreviousToRemoteModCount, lsd.c_str() ); }
;
743 #endif
744 // - force saving of header only if some entry changes
745 bool modified=false;
746 string origentries;
747 // - we don't need the changelog to be updated when all we do is refresh from server
748 if (isRefreshOnly()) goto done; // done ok
749 // - load entire existing changelog into memory
750 numexistinglogentries = fChangeLog.getNumRecords(); // logentries that are already there
751 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("changeLogPreflight: at start, changelog has %ld entries",(long)numexistinglogentries)){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("changeLogPreflight: at start, changelog has %ld entries"
,(long)numexistinglogentries); }
;
752 if (numexistinglogentries>0) {
753 // - allocate array for all existing entries (use sysync_malloc because e.g. on PalmOS this uses special funcs to allow > 64k)
754 size_t entriessize = sizeof(TChangeLogEntry)*numexistinglogentries;
755 existingentries = (TChangeLogEntry *)sysync_malloc(entriessize)malloc(entriessize);
756 if (!existingentries) { err=BFE_MEMORY9; goto done; } // not enough memory
757 // - read all entries
758 fChangeLog.readRecord(0,existingentries,numexistinglogentries);
759 origentries.assign((char *)existingentries, entriessize);
760 // Mark all not-yet-deleted in the log as delete candidate
761 // (those that still exist will be get the candidate mark removed below)
762 for (logindex=0;logindex<numexistinglogentries;logindex++) {
763 // set as delete candidate if not already marked deleted
764 if (!(existingentries[logindex].flags & chgl_deleted))
765 existingentries[logindex].flags = existingentries[logindex].flags | chgl_delete_candidate; // mark as delete candidate
766 }
767 }
768 // Now update the changelog using CRC checks
769 // loop through entire database
770 if (CRC_CHANGE_DETECTION(fConfigP->fCRCChangeDetection)) {
771 // we do change detection via CRC comparison
772 #ifdef RECORDHASH_FROM_DBAPI
773 // - DB can deliver CRC directly
774 foundone = getFirstItemCRC(itemLocalID,dataCRC);
775 #else
776 // - We need to get the item and calculate the CRC here
777 foundone = getFirstItem(itemP);
778 #endif
779 }
780 else {
781 #ifdef CHANGEDETECTION_AVAILABLE1
782 // - the DB layer can report changes directly
783 foundone = getFirstItemInfo(itemLocalID,itemIsModified);
784 #else
785 // error, should never happen because without CHANGEDETECTION_AVAILABLE, CRC_CHANGE_DETECTION should be true
786 return LOCERR_WRONGUSAGE;
787 #endif
788 }
789 while (foundone) {
790 // report event to allow progress display, use existing number as approx for total # of items
791 ++seen;
792 DB_PROGRESS_EVENT(this,pev_preparing,seen,numexistinglogentries,0)this->getSession()->NotifySessionProgressEvent(pev_preparing
,this->getDSConfig(),seen,numexistinglogentries,0)
;
793 // process now
794 // - get local ID
795 localid_t localid;
796 #ifdef RECORDHASH_FROM_DBAPI
797 // with or without CRC, we have got the ID into itemLocalID already
798 localid=LOCALID_OUT_TO_IN(itemLocalID)((char *)itemLocalID.c_str());
799 #else
800 if (CRC_CHANGE_DETECTION(fConfigP->fCRCChangeDetection)) {
801 // with CRC, we have got the entire item, so we need to get the ID out of that
802 STR_TO_LOCALID(itemP->getLocalID(),localid)(localid=(char *)itemP->getLocalID());
803 }
804 else {
805 // without CRC, we have got the ID into itemLocalID already
806 localid=LOCALID_OUT_TO_IN(itemLocalID)((char *)itemLocalID.c_str());
807 }
808 #endif // not RECORDHASH_FROM_DBAPI
809 // show item info found in DB
810 #ifdef SYDEBUG2
811 string sl;
812 LOCALID_TO_STRING(localid,sl)sl=localid;
813 if (CRC_CHANGE_DETECTION(fConfigP->fCRCChangeDetection)) {
814 #ifdef RECORDHASH_FROM_DBAPI
815 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("changeLogPreflight: item #%ld : localid=%s, dataCRC=0x%04hX, NOC=%ld ",(long)seen,sl.c_str(),(long)fNumberOfLocalChanges,dataCRC)){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("changeLogPreflight: item #%ld : localid=%s, dataCRC=0x%04hX, NOC=%ld "
,(long)seen,sl.c_str(),(long)fNumberOfLocalChanges,dataCRC); }
;
816 #else
817 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("changeLogPreflight: item #%ld : localid=%s, NOC=%ld ",(long)seen,sl.c_str(),(long)fNumberOfLocalChanges)){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("changeLogPreflight: item #%ld : localid=%s, NOC=%ld "
,(long)seen,sl.c_str(),(long)fNumberOfLocalChanges); }
;
818 #endif
819 }
820 else {
821 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,({ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "changeLogPreflight: item #%ld : localid=%s, database says item %s modified"
, (long)seen,sl.c_str(), itemIsModified ? "IS" : "is NOT" ); }
822 "changeLogPreflight: item #%ld : localid=%s, database says item %s modified",{ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "changeLogPreflight: item #%ld : localid=%s, database says item %s modified"
, (long)seen,sl.c_str(), itemIsModified ? "IS" : "is NOT" ); }
823 (long)seen,sl.c_str(),{ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "changeLogPreflight: item #%ld : localid=%s, database says item %s modified"
, (long)seen,sl.c_str(), itemIsModified ? "IS" : "is NOT" ); }
824 itemIsModified ? "IS" : "is NOT"{ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "changeLogPreflight: item #%ld : localid=%s, database says item %s modified"
, (long)seen,sl.c_str(), itemIsModified ? "IS" : "is NOT" ); }
825 )){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "changeLogPreflight: item #%ld : localid=%s, database says item %s modified"
, (long)seen,sl.c_str(), itemIsModified ? "IS" : "is NOT" ); }
;
826 }
827 #endif // SYDEBUG
828 // - search for already existing changelog entry for this uniqueID
829 // (prevent searching those that we have created in this preflight)
830 bool chgentryexists=false; // none found yet
831 TChangeLogEntry *currentEntryP = NULL__null; // no entry yet
832 for (logindex=0; logindex<numexistinglogentries; logindex++) {
833 if (LOCALID_EQUAL(existingentries[logindex].dbrecordid,localid)(strnncmp(existingentries[logindex].dbrecordid,localid,maxidlen
)==0)
) {
834 // found
835 chgentryexists = true;
836 currentEntryP = &(existingentries[logindex]);
837 // - remove the deletion candidate flag if it was set
838 if (currentEntryP->flags & chgl_delete_candidate) {
839 currentEntryP->flags &= ~chgl_delete_candidate; // remove candidate flag
840 }
841 // found
842 if (CRC_CHANGE_DETECTION(fConfigP->fCRCChangeDetection)) {
843 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- found in changelog at index=%ld, flags=0x%02hX, modcount=%ld, modcount_created=%ld, saved CRC=0x%04hX"
, (long)logindex, (uInt16)currentEntryP->flags, (long)currentEntryP
->modcount, (long)currentEntryP->modcount_created, currentEntryP
->dataCRC ); }
844 "- found in changelog at index=%ld, flags=0x%02hX, modcount=%ld, modcount_created=%ld, saved CRC=0x%04hX",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- found in changelog at index=%ld, flags=0x%02hX, modcount=%ld, modcount_created=%ld, saved CRC=0x%04hX"
, (long)logindex, (uInt16)currentEntryP->flags, (long)currentEntryP
->modcount, (long)currentEntryP->modcount_created, currentEntryP
->dataCRC ); }
845 (long)logindex,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- found in changelog at index=%ld, flags=0x%02hX, modcount=%ld, modcount_created=%ld, saved CRC=0x%04hX"
, (long)logindex, (uInt16)currentEntryP->flags, (long)currentEntryP
->modcount, (long)currentEntryP->modcount_created, currentEntryP
->dataCRC ); }
846 (uInt16)currentEntryP->flags,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- found in changelog at index=%ld, flags=0x%02hX, modcount=%ld, modcount_created=%ld, saved CRC=0x%04hX"
, (long)logindex, (uInt16)currentEntryP->flags, (long)currentEntryP
->modcount, (long)currentEntryP->modcount_created, currentEntryP
->dataCRC ); }
847 (long)currentEntryP->modcount,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- found in changelog at index=%ld, flags=0x%02hX, modcount=%ld, modcount_created=%ld, saved CRC=0x%04hX"
, (long)logindex, (uInt16)currentEntryP->flags, (long)currentEntryP
->modcount, (long)currentEntryP->modcount_created, currentEntryP
->dataCRC ); }
848 (long)currentEntryP->modcount_created,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- found in changelog at index=%ld, flags=0x%02hX, modcount=%ld, modcount_created=%ld, saved CRC=0x%04hX"
, (long)logindex, (uInt16)currentEntryP->flags, (long)currentEntryP
->modcount, (long)currentEntryP->modcount_created, currentEntryP
->dataCRC ); }
849 currentEntryP->dataCRC{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- found in changelog at index=%ld, flags=0x%02hX, modcount=%ld, modcount_created=%ld, saved CRC=0x%04hX"
, (long)logindex, (uInt16)currentEntryP->flags, (long)currentEntryP
->modcount, (long)currentEntryP->modcount_created, currentEntryP
->dataCRC ); }
850 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- found in changelog at index=%ld, flags=0x%02hX, modcount=%ld, modcount_created=%ld, saved CRC=0x%04hX"
, (long)logindex, (uInt16)currentEntryP->flags, (long)currentEntryP
->modcount, (long)currentEntryP->modcount_created, currentEntryP
->dataCRC ); }
;
851 }
852 else {
853 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- found in changelog at index=%ld, flags=0x%02hX, modcount=%ld, modcount_created=%ld"
, (long)logindex, (uInt16)currentEntryP->flags, (long)currentEntryP
->modcount, (long)currentEntryP->modcount_created ); }
854 "- found in changelog at index=%ld, flags=0x%02hX, modcount=%ld, modcount_created=%ld",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- found in changelog at index=%ld, flags=0x%02hX, modcount=%ld, modcount_created=%ld"
, (long)logindex, (uInt16)currentEntryP->flags, (long)currentEntryP
->modcount, (long)currentEntryP->modcount_created ); }
855 (long)logindex,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- found in changelog at index=%ld, flags=0x%02hX, modcount=%ld, modcount_created=%ld"
, (long)logindex, (uInt16)currentEntryP->flags, (long)currentEntryP
->modcount, (long)currentEntryP->modcount_created ); }
856 (uInt16)currentEntryP->flags,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- found in changelog at index=%ld, flags=0x%02hX, modcount=%ld, modcount_created=%ld"
, (long)logindex, (uInt16)currentEntryP->flags, (long)currentEntryP
->modcount, (long)currentEntryP->modcount_created ); }
857 (long)currentEntryP->modcount,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- found in changelog at index=%ld, flags=0x%02hX, modcount=%ld, modcount_created=%ld"
, (long)logindex, (uInt16)currentEntryP->flags, (long)currentEntryP
->modcount, (long)currentEntryP->modcount_created ); }
858 (long)currentEntryP->modcount_created{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- found in changelog at index=%ld, flags=0x%02hX, modcount=%ld, modcount_created=%ld"
, (long)logindex, (uInt16)currentEntryP->flags, (long)currentEntryP
->modcount, (long)currentEntryP->modcount_created ); }
859 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- found in changelog at index=%ld, flags=0x%02hX, modcount=%ld, modcount_created=%ld"
, (long)logindex, (uInt16)currentEntryP->flags, (long)currentEntryP
->modcount, (long)currentEntryP->modcount_created ); }
;
860 }
861 break;
862 }
863 }
864 // - create new record
865 if (!chgentryexists) {
866 // set unique ID, init other fields
867 ASSIGN_LOCALID_TO_FLD(newentry.dbrecordid,localid)AssignCString(newentry.dbrecordid,localid,maxidlen);
868 // - just init these, will be updated with real values below
869 newentry.flags = 0;
870 newentry.dataCRC = 0;
871 newentry.modcount = 0;
872 newentry.modcount_created = 0;
873 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,("- does not yet exist in changelog, created new")){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
("- does not yet exist in changelog, created new"); }
;
874 // new entry is now current entry
875 currentEntryP = &newentry;
876 }
877 // now check what to do
878 if (CRC_CHANGE_DETECTION(fConfigP->fCRCChangeDetection)) {
879 #ifndef RECORDHASH_FROM_DBAPI
880 // we need a CRC but don't have it precalculated from the DB layer
881 dataCRC=itemP->getDataCRC(0,true); // start new CRC, do not include eqm_none fields
882 #endif // not RECORDHASH_FROM_DBAPI
883 }
884 // - check if new or changed
885 if (chgentryexists && !(currentEntryP->flags & chgl_deleted)) {
886 // entry exists (and is not a deleted one), could be changed
887 if (CRC_CHANGE_DETECTION(fConfigP->fCRCChangeDetection)) {
888 // - check CRC to calculate itemIsModified
889 itemIsModified = existingentries[logindex].dataCRC!=dataCRC;
890 if (itemIsModified) {
891 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- item has changed (current CRC=0x%04hX, old CRC=0x%04hX)"
, dataCRC, currentEntryP->dataCRC ); }
892 "- item has changed (current CRC=0x%04hX, old CRC=0x%04hX)",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- item has changed (current CRC=0x%04hX, old CRC=0x%04hX)"
, dataCRC, currentEntryP->dataCRC ); }
893 dataCRC,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- item has changed (current CRC=0x%04hX, old CRC=0x%04hX)"
, dataCRC, currentEntryP->dataCRC ); }
894 currentEntryP->dataCRC{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- item has changed (current CRC=0x%04hX, old CRC=0x%04hX)"
, dataCRC, currentEntryP->dataCRC ); }
895 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "- item has changed (current CRC=0x%04hX, old CRC=0x%04hX)"
, dataCRC, currentEntryP->dataCRC ); }
;
896 // has changed since last time checked by preflight (but only those! There might be more items
897 // changed since last sync or resume, but these ALREADY have a modcount in the changelog that
898 // flags them such).
899 // So this is the place to reset chgl_modbysync (which marks items changed by a sync and not from outside)
900 currentEntryP->flags &= ~chgl_modbysync; // detecting a real change here cancels the mod-by-sync flag set for sync-added/changed entries
901 // update CRC and modification count
902 currentEntryP->dataCRC=dataCRC;
903 currentEntryP->modcount=fCurrentModCount; // update modification count
904 // this is a local change for this session
905 fNumberOfLocalChanges++; // for suspend: those that detect a change here were modified AFTER last suspend, so always count them
906
907 }
908 }
909 else {
910 // - DB has reported change status into itemIsModified already
911 if (itemIsModified) {
912 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,("- item has changed (according to what database says)")){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
("- item has changed (according to what database says)"); }
;
913 // has changed since last time checked by preflight (but only those! There might be more items
914 // changed since last sync or resume, but these ALREADY have a modcount in the changelog that
915 // flags them such).
916 // So this is the place to reset chgl_modbysync (which marks items changed by a sync and not from outside)
917 currentEntryP->flags &= ~chgl_modbysync; // detecting a real change here cancels the mod-by-sync flag set for sync-added/changed entries
918 // update modification count
919 currentEntryP->modcount=fCurrentModCount;
920 // this is a local change for this session
921 fNumberOfLocalChanges++; // for suspend: those that detect a change here were modified AFTER last suspend, so always count them
922 }
923 }
924 if (!itemIsModified) {
925 // no change detected since last preflight (but still, this could be a change to report to the server)
926 if (isResuming()) {
927 // if resuming - only those count that are marked for resume
928 if (currentEntryP->flags & chgl_markedforresume)
929 fNumberOfLocalChanges++; // in resumes: only count those that are actually marked for resume
930 }
931 else {
932 // not resuming - all existing ones count if this is a slow sync,
933 // otherwise, those modified since last to-remote-sync count as well (although not modified since last preflight!)
934 if (fSlowSync || currentEntryP->modcount>fPreviousToRemoteModCount) fNumberOfLocalChanges++;
935 }
936 }
937 }
938 else {
939 // entry does not exist (or existed as deleted entry) -> means that this record was (maybe: re-)added new
940 // (since last preflight, which always means also AFTER last suspend!)
941 // - is modified now
942 currentEntryP->modcount = fCurrentModCount;
943 // - is (re)created now: set the creation modcount, this is used to detect a client-side newly added item
944 currentEntryP->modcount_created = fCurrentModCount;
945 // - no flags set
946 currentEntryP->flags = 0;
947 // - update CRC to current value if CRC is in use
948 if (CRC_CHANGE_DETECTION(fConfigP->fCRCChangeDetection)) {
949 currentEntryP->dataCRC = dataCRC;
950 }
951 else {
952 currentEntryP->dataCRC = 0; // clean it for cosmetic reasons only
953 }
954 // create if entry is new
955 if (!chgentryexists) {
956 // this is a new, additional entry (and not a resurrected deleted one)
957 modified=true;
958 fChangeLog.newRecord(currentEntryP);
959 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("- item was newly added (no entry existed in changelog before)")){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("- item was newly added (no entry existed in changelog before)"
); }
;
960 }
961 else {
962 // the entry itself existed, but was a deleted entry. We're now re-using that one
963 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("- item has re-appeared (i.e. item with same local uniqueID that was once before deleted is now here again)")){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("- item has re-appeared (i.e. item with same local uniqueID that was once before deleted is now here again)"
); }
;
964 }
965 // this is a local change for this session (even for resume - we need to add newly added ones in resume!)
966 fNumberOfLocalChanges++;
967 }
968 // Next item
969 if (CRC_CHANGE_DETECTION(fConfigP->fCRCChangeDetection)) {
970 #ifdef RECORDHASH_FROM_DBAPI
971 foundone = getNextItemCRC(itemLocalID,dataCRC);
972 #else
973 // forget this one
974 delete itemP;
975 // check next
976 foundone = getNextItem(itemP);
977 #endif
978 }
979 else {
980 #ifdef CHANGEDETECTION_AVAILABLE1
981 foundone = getNextItemInfo(itemLocalID,itemIsModified);
982 #endif
983 }
984 } // while all records in DB
985 // check that we've terminated the list because we've really seen all items and not
986 // because of an error reading an item (which would cause false deletes)
987 if (isDBError(lastDBError())) {
988 sta=510; // database error
989 goto error;
990 }
991 // now find and update delete candidates
992 // (That is, all entries in the log that have no DB record associated any more)
993 // Note: we only search logentries that were here already before the preflight,
994 // because new ones never are delete candidates
995 for (logindex=0;logindex<numexistinglogentries;logindex++) {
996 // check if delete candidate
997 if (existingentries[logindex].flags & chgl_delete_candidate) {
998 // Note: delete candidates are never already chgl_deleted
999 // - update entry
1000 existingentries[logindex].flags &= ~chgl_delete_candidate; // no candidate...
1001 existingentries[logindex].flags |= chgl_deleted; // ..but really deleted
1002 existingentries[logindex].dataCRC=0; // no CRC any more
1003 existingentries[logindex].modcount=fCurrentModCount; // deletion detected now
1004 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("changeLogPreflight: item with logindex=%ld was not found in datastore -> mark deleted",(long)logindex)){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("changeLogPreflight: item with logindex=%ld was not found in datastore -> mark deleted"
,(long)logindex); }
;
1005 // this is a local change for this session
1006 if (!isResuming() || (existingentries[logindex].flags & chgl_markedforresume))
1007 fNumberOfLocalChanges++; // in resumes: only count those that are actually marked for resume
1008 }
1009 }
1010 // successfully updated in memory, now write changed entries back to binfile
1011 // Note: entries created during this preflight are already saved. Only in-memory modifications to pre-existing ones need to be saved.
1012 #ifdef SYDEBUG2
1013 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,("changeLogPreflight: saving %ld existing entries",(long)numexistinglogentries)){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
("changeLogPreflight: saving %ld existing entries",(long)numexistinglogentries
); }
;
1014 if (DEBUGTEST(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC)(((0x00000040 +0x02000000 +0x80000000) & getDbgMask()) ==
(0x00000040 +0x02000000 +0x80000000))
) {
1015 for (uInt32 si=0; si<numexistinglogentries; si++) {
1016 #ifdef NUMERIC_LOCALIDS
1017 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, existingentries[si].dbrecordid, (int)existingentries
[si].flags, (long)existingentries[si].modcount, (long)existingentries
[si].modcount_created ); }
1018 "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, existingentries[si].dbrecordid, (int)existingentries
[si].flags, (long)existingentries[si].modcount, (long)existingentries
[si].modcount_created ); }
1019 (long)si,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, existingentries[si].dbrecordid, (int)existingentries
[si].flags, (long)existingentries[si].modcount, (long)existingentries
[si].modcount_created ); }
1020 existingentries[si].dbrecordid,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, existingentries[si].dbrecordid, (int)existingentries
[si].flags, (long)existingentries[si].modcount, (long)existingentries
[si].modcount_created ); }
1021 (int)existingentries[si].flags,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, existingentries[si].dbrecordid, (int)existingentries
[si].flags, (long)existingentries[si].modcount, (long)existingentries
[si].modcount_created ); }
1022 (long)existingentries[si].modcount,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, existingentries[si].dbrecordid, (int)existingentries
[si].flags, (long)existingentries[si].modcount, (long)existingentries
[si].modcount_created ); }
1023 (long)existingentries[si].modcount_created{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, existingentries[si].dbrecordid, (int)existingentries
[si].flags, (long)existingentries[si].modcount, (long)existingentries
[si].modcount_created ); }
1024 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, existingentries[si].dbrecordid, (int)existingentries
[si].flags, (long)existingentries[si].modcount, (long)existingentries
[si].modcount_created ); }
;
1025 #else
1026 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, existingentries[si].dbrecordid, (int)existingentries
[si].flags, (long)existingentries[si].modcount, (long)existingentries
[si].modcount_created ); }
1027 "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, existingentries[si].dbrecordid, (int)existingentries
[si].flags, (long)existingentries[si].modcount, (long)existingentries
[si].modcount_created ); }
1028 (long)si,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, existingentries[si].dbrecordid, (int)existingentries
[si].flags, (long)existingentries[si].modcount, (long)existingentries
[si].modcount_created ); }
1029 existingentries[si].dbrecordid,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, existingentries[si].dbrecordid, (int)existingentries
[si].flags, (long)existingentries[si].modcount, (long)existingentries
[si].modcount_created ); }
1030 (int)existingentries[si].flags,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, existingentries[si].dbrecordid, (int)existingentries
[si].flags, (long)existingentries[si].modcount, (long)existingentries
[si].modcount_created ); }
1031 (long)existingentries[si].modcount,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, existingentries[si].dbrecordid, (int)existingentries
[si].flags, (long)existingentries[si].modcount, (long)existingentries
[si].modcount_created ); }
1032 (long)existingentries[si].modcount_created{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, existingentries[si].dbrecordid, (int)existingentries
[si].flags, (long)existingentries[si].modcount, (long)existingentries
[si].modcount_created ); }
1033 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, existingentries[si].dbrecordid, (int)existingentries
[si].flags, (long)existingentries[si].modcount, (long)existingentries
[si].modcount_created ); }
;
1034 #endif
1035 }
1036 }
1037 #endif
1038 // - write back all existing entries
1039 if (existingentries &&
1040 memcmp(existingentries, origentries.c_str(), origentries.size())) {
1041 fChangeLog.updateRecord(0,existingentries,numexistinglogentries);
1042 modified=true;
1043 }
1044
1045 // Also write updated header if (and only if) something changed.
1046 if (modified) {
1047 err = fChangeLog.flushHeader();
1048 if (err!=BFE_OK0) goto done;
1049 }
1050
1051 // - now we can confirm we have a valid changelog
1052 aValidChangelog=true;
1053 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,("changeLogPreflight: seen=%ld, fNumberOfLocalChanges=%ld",(long)seen,(long)fNumberOfLocalChanges)){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
("changeLogPreflight: seen=%ld, fNumberOfLocalChanges=%ld",(
long)seen,(long)fNumberOfLocalChanges); }
;
1054done:
1055 sta = err==BFE_OK0 ? LOCERR_OK : (err==BFE_MEMORY9 ? LOCERR_OUTOFMEM : LOCERR_UNDEFINED);
1056error:
1057 // release buffered changelog
1058 if (existingentries) sysync_free(existingentries)free(existingentries);
1059 // return state
1060 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("changeLogPreflight: numberOfLocalChanges=%ld, status=%hd (binfileerr=%hd)%s",(long)fNumberOfLocalChanges,sta,err,lastDBErrorText().c_str())){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("changeLogPreflight: numberOfLocalChanges=%ld, status=%hd (binfileerr=%hd)%s"
,(long)fNumberOfLocalChanges,sta,err,lastDBErrorText().c_str(
)); }
;
1061 PDEBUGENDBLOCK("changeLogPreflight")getDbgLogger()->DebugCloseBlock( "changeLogPreflight");
1062 return sta;
1063} // TBinfileImplDS::changeLogPreflight
1064
1065
1066
1067// Simple DB access interface methods
1068// ==================================
1069
1070// load target settings record for this datastore
1071localstatus TBinfileImplDS::loadTarget(bool aCreateIfMissing, cAppCharP aRemoteDBID)
1072{
1073 uInt32 remotepartyID = static_cast<TBinfileImplClient *>(fSessionP)->fRemotepartyID;
1074 TBinFile *targetsBinFileP = &(static_cast<TBinfileImplClient *>(fSessionP)->fConfigP->fTargetsBinFile);
1075 // for server or version with syncrequests in config, we must try to load
1076 // the target record or create one if it is missing
1077 if (fTargetIndex<0) {
1078 // try to find target by fRemotepartyID and targetDB code/name
1079 uInt32 maxidx=targetsBinFileP->getNumRecords();
1080 uInt32 recidx;
1081 for (recidx=0; recidx<maxidx; recidx++) {
1082 // - get record
1083 if (targetsBinFileP->readRecord(recidx,&fTarget)==BFE_OK0) {
1084 // check if this is my target
1085 if (
1086 fTarget.remotepartyID == remotepartyID &&
1087 fTarget.localDBTypeID == fConfigP->fLocalDBTypeID &&
1088 strucmp(fTarget.localDBPath,fConfigP->fLocalDBPath.c_str(),localDBpathMaxLen)==0
1089 ) {
1090 // this is the target record for our DB, now get it (mark it busy)
1091 fTargetIndex=recidx;
1092 return LOCERR_OK; // target found
1093 }
1094 }
1095 }
1096 // target not found
1097 if (aCreateIfMissing) {
1098 // create new target record
1099 // - init with defaults
1100 fConfigP->initTarget(fTarget,remotepartyID,aRemoteDBID,true); // enabled if created here!
1101 // - save new record
1102 uInt32 ti;
1103 targetsBinFileP->newRecord(ti,&fTarget);
1104 fTargetIndex = ti;
1105 return LOCERR_OK; // created and loaded now
1106 }
1107 return 404; // not found
1108 }
1109 return LOCERR_OK; // already loaded
1110} // TBinfileImplDS::loadTarget
1111
1112
1113
1114// - called for SyncML 1.1 if remote wants number of changes.
1115// Must return -1 if no NOC value can be returned
1116// NOTE: we implement it here only for server, as it is not really needed
1117// for clients normally - if it is needed, client's agent must provide
1118// it in derived class as StdLogicDS has no own list it can use to count
1119// in client case.
1120sInt32 TBinfileImplDS::getNumberOfChanges(void)
1121{
1122 if (binfileDSActive() && IS_CLIENT(!getSyncAppBase()->isServer())) {
1123 // for client case with active binfile, we return the locally computed count
1124 // (for server, the entire list of changes is loaded by the baseclass
1125 // before NOC is needed, so the baseclass has the more accurate count
1126 // which takes filtering etc. into account).
1127 return fNumberOfLocalChanges;
1128 }
1129 // otherwise, let base class handle it (server and client w/o binfile)
1130 return inherited::getNumberOfChanges();
1131}
1132
1133bool TBinfileImplDS::hasPendingChangesForNextSync()
1134{
1135 if (binfileDSActive() && IS_CLIENT(!getSyncAppBase()->isServer())) {
1136 // shortcut?
1137 if (fHasPendingChanges) {
1138 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,("sync session known to be incomplete")){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
("sync session known to be incomplete"); }
;
1139 return true;
1140 }
1141 // also check change log, just to be sure;
1142 // note that new entries in the change log that were
1143 // added during the current sync session are not yet loaded,
1144 // and that entries in memory may still need to be flushed
1145 // to disk
1146 if (fLoadedChangeLog) {
1147 for (uInt32 si=0; si<fLoadedChangeLogEntries; si++) {
1148 if (fLoadedChangeLog[si].modcount > fCurrentModCount) {
1149#ifdef NUMERIC_LOCALIDS
1150 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld => pending change"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
1151 "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld => pending change",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld => pending change"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
1152 (long)si,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld => pending change"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
1153 fLoadedChangeLog[si].dbrecordid,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld => pending change"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
1154 (int)fLoadedChangeLog[si].flags,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld => pending change"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
1155 (long)fLoadedChangeLog[si].modcount,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld => pending change"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
1156 (long)fLoadedChangeLog[si].modcount_created{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld => pending change"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
1157 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld => pending change"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
;
1158#else
1159 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld => pending change"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
1160 "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld => pending change",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld => pending change"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
1161 (long)si,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld => pending change"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
1162 fLoadedChangeLog[si].dbrecordid,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld => pending change"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
1163 (int)fLoadedChangeLog[si].flags,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld => pending change"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
1164 (long)fLoadedChangeLog[si].modcount,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld => pending change"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
1165 (long)fLoadedChangeLog[si].modcount_created{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld => pending change"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
1166 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld => pending change"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
;
1167#endif
1168 return true;
1169 }
1170 }
1171 }
1172 return false;
1173 }
1174 return inherited::getNumberOfChanges();
1175}
1176
1177
1178
1179/// sync login (into this database)
1180/// @note might be called several times (auth retries at beginning of session)
1181/// @note must update the following saved AND current state variables
1182/// - in TLocalEngineDS: fLastRemoteAnchor, (fLastLocalAnchor), fResumeAlertCode, fFirstTimeSync
1183/// - for client: fPendingAddMaps
1184/// - in TStdLogicDS: fPreviousSyncTime, fCurrentSyncTime
1185/// - in TBinfileImplDS: ??? /// @todo document these
1186/// - in derived classes: whatever else belongs to dsSavedAdmin and dsCurrentAdmin state
1187localstatus TBinfileImplDS::implMakeAdminReady(
1188 cAppCharP aDeviceID, // remote device URI (device ID)
1189 cAppCharP aDatabaseID, // database ID
1190 cAppCharP aRemoteDBID // database ID of remote device
1191)
1192{
1193 if (!binfileDSActive()) return LOCERR_WRONGUSAGE; // must be active when called at all
1194
1195 localstatus sta=LOCERR_OK; // assume ok
1196
1197 PDEBUGBLOCKDESCCOLL("implMakeAdminReady","Loading target info and pending maps")getDbgLogger()->DebugOpenBlock( "implMakeAdminReady","Loading target info and pending maps"
,true)
;
1198 // - init defaults
1199 fLastRemoteAnchor.erase();
1200 fPreviousSyncTime=0;
1201 fFirstTimeSync=false; // assume not first time
1202
1203
1204 #if !defined(PRECONFIGURED_SYNCREQUESTS)
1205 // when sync params are in binfiles, target must be present by now - make sure it is loaded
1206 sta=loadTarget(false);
1207 // target info must already be present by now (loaded at session's SelectProfile)
1208 if (sta!=LOCERR_OK || fTargetIndex<0) {
1209 // problem loading target record
1210 sta = sta ? sta : 404;
1211 PDEBUGPRINTFX(DBG_ERROR,("Error %d loading target record",sta)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("Error %d loading target record"
,sta); }
;
1212 PDEBUGENDBLOCK("implMakeAdminReady")getDbgLogger()->DebugCloseBlock( "implMakeAdminReady");
1213 return sta;
1214 }
1215 // we have the target in the fTarget member
1216 #else
1217 // e.g. for clients without syncrequests in config, target record might not exist here, so we allow creating it
1218 sta=loadTarget(true, aRemoteDBID);
1219 #endif
1220 // Now fTarget has valid target info
1221 // - if we don't have any remote anchor stored, this must be a first time sync
1222 if (*(fTarget.remoteAnchor)==0)
1223 fFirstTimeSync=true;
1224 // - get last anchor
1225 if (fTarget.forceSlowSync) {
1226 // - forget last anchor
1227 fLastRemoteAnchor.erase(); // make sure we get a slow sync
1228 }
1229 else {
1230 // - get last anchor
1231 fLastRemoteAnchor.assign(fTarget.remoteAnchor);
1232 }
1233 // - get last resume info
1234 fPreviousSuspendModCount = fTarget.lastSuspendModCount; /// @note: before DS 1.2 engine this was used as "lastModCount"
1235 fResumeAlertCode = fTarget.resumeAlertCode;
1236 // - get last sync time and changelog cursor
1237 fPreviousToRemoteModCount = fTarget.lastTwoWayModCount; // reference is when we've last full-synced!
1238 fPreviousSyncTime = fTarget.lastSync;
1239 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,({ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "implMakeAdminReady(binfile): ResumeAlertCode=%hd, PreviousSuspendModCount=%ld, PreviousToRemoteModCount=%ld, LastRemoteAnchor='%s'"
, fResumeAlertCode, (long)fPreviousSuspendModCount, (long)fPreviousToRemoteModCount
, fLastRemoteAnchor.c_str() ); }
1240 "implMakeAdminReady(binfile): ResumeAlertCode=%hd, PreviousSuspendModCount=%ld, PreviousToRemoteModCount=%ld, LastRemoteAnchor='%s'",{ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "implMakeAdminReady(binfile): ResumeAlertCode=%hd, PreviousSuspendModCount=%ld, PreviousToRemoteModCount=%ld, LastRemoteAnchor='%s'"
, fResumeAlertCode, (long)fPreviousSuspendModCount, (long)fPreviousToRemoteModCount
, fLastRemoteAnchor.c_str() ); }
1241 fResumeAlertCode,{ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "implMakeAdminReady(binfile): ResumeAlertCode=%hd, PreviousSuspendModCount=%ld, PreviousToRemoteModCount=%ld, LastRemoteAnchor='%s'"
, fResumeAlertCode, (long)fPreviousSuspendModCount, (long)fPreviousToRemoteModCount
, fLastRemoteAnchor.c_str() ); }
1242 (long)fPreviousSuspendModCount,{ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "implMakeAdminReady(binfile): ResumeAlertCode=%hd, PreviousSuspendModCount=%ld, PreviousToRemoteModCount=%ld, LastRemoteAnchor='%s'"
, fResumeAlertCode, (long)fPreviousSuspendModCount, (long)fPreviousToRemoteModCount
, fLastRemoteAnchor.c_str() ); }
1243 (long)fPreviousToRemoteModCount,{ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "implMakeAdminReady(binfile): ResumeAlertCode=%hd, PreviousSuspendModCount=%ld, PreviousToRemoteModCount=%ld, LastRemoteAnchor='%s'"
, fResumeAlertCode, (long)fPreviousSuspendModCount, (long)fPreviousToRemoteModCount
, fLastRemoteAnchor.c_str() ); }
1244 fLastRemoteAnchor.c_str(){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "implMakeAdminReady(binfile): ResumeAlertCode=%hd, PreviousSuspendModCount=%ld, PreviousToRemoteModCount=%ld, LastRemoteAnchor='%s'"
, fResumeAlertCode, (long)fPreviousSuspendModCount, (long)fPreviousToRemoteModCount
, fLastRemoteAnchor.c_str() ); }
1245 )){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ( "implMakeAdminReady(binfile): ResumeAlertCode=%hd, PreviousSuspendModCount=%ld, PreviousToRemoteModCount=%ld, LastRemoteAnchor='%s'"
, fResumeAlertCode, (long)fPreviousSuspendModCount, (long)fPreviousToRemoteModCount
, fLastRemoteAnchor.c_str() ); }
;
1246 // determine time of this sync (will be overridden in case of BASED_ON_BINFILE_CLIENT)
1247 fCurrentSyncTime=getSession()->getSystemNowAs(TCTX_UTC((timecontext_t) ((tctx_tz_UTC) | TCTX_SYMBOLIC_TZ))); // NOW !
1248 // do some more things if we are starting sync now
1249 if (!fPreflighted) {
1250 if (!openChangeLog()) {
1251 // changelog did not exist yet
1252 // - force slow sync
1253 fTarget.forceSlowSync=true; // set target flag to force slowsync even if we repeat this
1254 fLastRemoteAnchor.erase();
1255 fPreviousSyncTime = noLinearTime;
1256 fPreviousToRemoteModCount = 0;
1257 fPreviousSuspendModCount = 0;
1258 // - no compare references yet
1259 fPreviousToRemoteSyncCmpRef = noLinearTime;
1260 fPreviousSuspendIdentifier.erase();
1261 }
1262 else {
1263 // Get token and date representing last update of this changelog (last preflight)
1264 // Note: towards the database, we only check for changes since the last preflight (the fPreviousToRemoteSyncCmpRef is semantically
1265 // incorrect when TCustomImplDS is used with BASED_ON_BINFILE_CLIENT on top of binfile).
1266 // The separation between changes since last-to-remote sync and last resume is done based on the changelog modcounts.
1267 // - get date of last check
1268 fPreviousToRemoteSyncCmpRef=fChgLogHeader.lastChangeCheck;
1269 fPreviousSuspendCmpRef=fPreviousToRemoteSyncCmpRef; // DB on top of binfile only needs one reference time, which is the last changelog check time.
1270 #ifdef SYDEBUG2
1271 string lsd;
1272 StringObjTimestamp(lsd,fPreviousToRemoteSyncCmpRef);
1273 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("- last preflight update (fPreviousToRemoteSyncCmpRef) at %s",lsd.c_str())){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("- last preflight update (fPreviousToRemoteSyncCmpRef) at %s"
,lsd.c_str()); }
;
1274 #endif // SYDEBUG
1275 #if TARGETS_DB_VERSION6>=6
1276 // - DB api level change detection identifiers
1277 fPreviousToRemoteSyncIdentifier.assign(fChgLogHeader.lastChangeCheckIdentifier);
1278 fPreviousSuspendIdentifier = fPreviousToRemoteSyncIdentifier; // DB on top of binfile only needs one reference time, which is the last changelog check time.
1279 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("- last preflight update (fPreviousToRemoteSyncIdentifier) is '%s'",fPreviousToRemoteSyncIdentifier.c_str())){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("- last preflight update (fPreviousToRemoteSyncIdentifier) is '%s'"
,fPreviousToRemoteSyncIdentifier.c_str()); }
;
1280 #endif // TARGETS_DB_VERSION>=6
1281 }
1282 }
1283 // get pending maps anyway (even if not resuming there might be pending maps)
1284 if(openPendingMaps()) {
1285 // there is a pending map file, check if these are really our maps
1286 // Note: with separated changelogs, this should be always the case!
1287 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMakeAdminReady: remotePartyID of pendingmaps=%ld, current profile's remotepartyID=%ld"
, (long)fPendingMapHeader.remotepartyID, (long)static_cast<
TBinfileImplClient *>(fSessionP)->fRemotepartyID ); }
1288 "implMakeAdminReady: remotePartyID of pendingmaps=%ld, current profile's remotepartyID=%ld",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMakeAdminReady: remotePartyID of pendingmaps=%ld, current profile's remotepartyID=%ld"
, (long)fPendingMapHeader.remotepartyID, (long)static_cast<
TBinfileImplClient *>(fSessionP)->fRemotepartyID ); }
1289 (long)fPendingMapHeader.remotepartyID,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMakeAdminReady: remotePartyID of pendingmaps=%ld, current profile's remotepartyID=%ld"
, (long)fPendingMapHeader.remotepartyID, (long)static_cast<
TBinfileImplClient *>(fSessionP)->fRemotepartyID ); }
1290 (long)static_cast<TBinfileImplClient *>(fSessionP)->fRemotepartyID{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMakeAdminReady: remotePartyID of pendingmaps=%ld, current profile's remotepartyID=%ld"
, (long)fPendingMapHeader.remotepartyID, (long)static_cast<
TBinfileImplClient *>(fSessionP)->fRemotepartyID ); }
1291 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMakeAdminReady: remotePartyID of pendingmaps=%ld, current profile's remotepartyID=%ld"
, (long)fPendingMapHeader.remotepartyID, (long)static_cast<
TBinfileImplClient *>(fSessionP)->fRemotepartyID ); }
;
1292 if (fPendingMapHeader.remotepartyID == static_cast<TBinfileImplClient *>(fSessionP)->fRemotepartyID) {
1293 // these are our maps, load them
1294 TPendingMapEntry pme;
1295 string localid;
1296 for (uInt32 i=0; i<fPendingMaps.getNumRecords(); i++) {
1297 fPendingMaps.readRecord(i,&pme);
1298 // store in localEngineDS' list
1299 LOCALID_TO_STRING(pme.dbrecordid,localid)localid=pme.dbrecordid;
1300 fPendingAddMaps[localid]=pme.remoteID;
1301 }
1302 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("implMakeAdminReady: loaded %ld pending add maps",(long)fPendingMaps.getNumRecords())){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("implMakeAdminReady: loaded %ld pending add maps"
,(long)fPendingMaps.getNumRecords()); }
;
1303 }
1304 }
1305 if (fResumeAlertCode) {
1306 // get pending item only if we have a resume state
1307 // - prep file
1308 TBinFile pendingItemFile;
1309 TPendingItemHeader pendingItemHeader;
1310 string fname = static_cast<TBinfileClientConfig *>(fSessionP->getSessionConfig())->relatedDBNameBase(getName(), fTarget.remotepartyID);
1311 fname += PENDINGITEM_DB_SUFFIX"_pitm_" "sysynclib_" ".bfi";
1312 pendingItemFile.setFileInfo(fname.c_str(),PENDINGITEM_DB_VERSION1,PENDINGITEM_DB_ID8,0); // no expected record size
1313 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "opening pending item file: file name='%s'", fname.c_str()
); }
1314 "opening pending item file: file name='%s'",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "opening pending item file: file name='%s'", fname.c_str()
); }
1315 fname.c_str(){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "opening pending item file: file name='%s'", fname.c_str()
); }
1316 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "opening pending item file: file name='%s'", fname.c_str()
); }
;
1317 if (pendingItemFile.open(sizeof(TPendingItemHeader),&pendingItemHeader)==BFE_OK0) {
1318 // we have a pending item file
1319 if (pendingItemHeader.remotepartyID == static_cast<TBinfileImplClient *>(fSessionP)->fRemotepartyID) {
1320 // this is our pending item, load it
1321 // - transfer header data
1322 fPartialItemState = pendingItemHeader.piState; // note: we always have the pi_state_loaded... state here
1323 fLastItemStatus = pendingItemHeader.lastItemStatus;
1324 fLastSourceURI = pendingItemHeader.lastSourceURI;
1325 fLastTargetURI = pendingItemHeader.lastTargetURI;
1326 fPITotalSize = pendingItemHeader.totalSize;
1327 fPIUnconfirmedSize = pendingItemHeader.unconfirmedSize;
1328 fPIStoredSize = pendingItemHeader.storedSize;
1329 // - load the data if any
1330 if (fPIStoredDataP && fPIStoredDataAllocated) smlLibFree(fPIStoredDataP);
1331 fPIStoredDataP=NULL__null;
1332 fPIStoredDataAllocated=false;
1333 if (fPIStoredSize) {
1334 fPIStoredDataP=smlLibMalloc(fPIStoredSize+1); // one for safety null terminator
1335 if (fPIStoredDataP) {
1336 fPIStoredDataAllocated=true;
1337 // get the data
1338 pendingItemFile.readRecord(0,fPIStoredDataP,1);
1339 *((uInt8 *)fPIStoredDataP+fPIStoredSize)=0; // safety null terminator
1340 }
1341 else {
1342 PDEBUGPRINTFX(DBG_ERROR,("Cannot allocate buffer (%ld bytes) for pendingitem",(long)fPIStoredSize)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("Cannot allocate buffer (%ld bytes) for pendingitem"
,(long)fPIStoredSize); }
;
1343 fPIStoredSize=0;
1344 }
1345 }
1346 }
1347 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("implMakeAdminReady: loaded pending item with %ld data bytes",(long)fPIStoredSize)){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("implMakeAdminReady: loaded pending item with %ld data bytes"
,(long)fPIStoredSize); }
;
1348 // done
1349 pendingItemFile.close();
1350 }
1351 }
1352 // done
1353 PDEBUGENDBLOCK("implMakeAdminReady")getDbgLogger()->DebugCloseBlock( "implMakeAdminReady");
1354 return sta;
1355} // TBinfileImplDS::implMakeAdminReady
1356
1357
1358localstatus TBinfileImplDS::implStartDataRead()
1359{
1360 if (!binfileDSActive()) return LOCERR_WRONGUSAGE; // must be active when called at all
1361
1362 // init reading of all records
1363 // - start at beginning of log
1364 fLogEntryIndex=0;
1365 return LOCERR_OK;
1366} // TBinfileImplDS::implStartDataRead
1367
1368
1369/* %%% seems obsolete - never called from anywhere
1370
1371#ifdef OBJECT_FILTERING
1372
1373// Test Filters
1374bool TBinfileImplDS::testFilters(TMultiFieldItem *aItemP)
1375{
1376 return
1377 // generally suitable item for this datastore
1378 aItemP->testFilter(fLocalDBFilter.c_str()) &&
1379 // and passing current sync set filter
1380 aItemP->testFilter(fSyncSetFilter.c_str()) &&
1381 // and not invisible
1382 (
1383 getDSConfig()->fInvisibleFilter.empty() || // no invisible filter means visible
1384 !aItemP->testFilter(getDSConfig()->fInvisibleFilter.c_str()) // failing invisible filter means visible too
1385 );
1386} // TBinfileImplDS::testFilters
1387
1388#endif
1389
1390*/
1391
1392/// @brief called to have all non-yet-generated sync commands as "to-be-resumed"
1393void TBinfileImplDS::implMarkOnlyUngeneratedForResume(void)
1394{
1395 if (!binfileDSActive()) return; // must be active when called at all
1396
1397 TChangeLogEntry *chglogP;
1398
1399 // simply return aEof when just refreshing
1400 if (fRefreshOnly) return;
1401 // make sure we have the changelog in memory
1402 loadChangeLog();
1403 // check if more records
1404 uInt32 logEntryIndex=fLogEntryIndex;
1405 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,("implMarkOnlyUngeneratedForResume: total=%ld, already generated=%ld",(long)fLoadedChangeLogEntries,(long)logEntryIndex)){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
("implMarkOnlyUngeneratedForResume: total=%ld, already generated=%ld"
,(long)fLoadedChangeLogEntries,(long)logEntryIndex); }
;
1406 // Note: already generated entries had their flag cleared when they were generated.
1407 // Some of them might already be marked now again by early markItemForResume() due to unsuccessful status
1408 // for all remaining records, check if they must be marked or not
1409 // (depends on current marked state as well if this is a resumed session already)
1410 while (logEntryIndex<fLoadedChangeLogEntries) {
1411 bool markforresume=true; // assume we must mark it
1412 // get ptr to entry
1413 chglogP=&fLoadedChangeLog[logEntryIndex];
1414 // advance to next
1415 logEntryIndex++;
1416 // if resuming, check if we must include this item at all
1417 if (isResuming()) {
1418 // we are resuming, only report those that have the mark-for-resume flag set
1419 if (!(chglogP->flags & chgl_markedforresume)) {
1420 // not marked for resume, but check if it has changed after the last suspend
1421 if (chglogP->modcount<=fPreviousSuspendModCount) {
1422 // is not marked for resume AND has not changed since last suspend
1423 markforresume=false; // not to be included in resume
1424 }
1425 }
1426 }
1427 if (markforresume) {
1428 // this item would have been reported in THIS session
1429 // now check if this should be marked for resume for NEXT session
1430 if (fSlowSync) {
1431 // slow sync mode
1432 if (chglogP->flags & chgl_deleted) {
1433 // skip deleted in slow sync
1434 markforresume=false; // not to be included in resume
1435 }
1436 }
1437 else if (!fSlowSync) {
1438 // prevent ANY reporting of items marked as receiveOnly in normal sync (but send them in slow sync!)
1439 if (chglogP->flags & chgl_receive_only) {
1440 // skip receive-only items in normal sync. So deleting or changing them locally will not send them
1441 // to the server. However after a slow sync, existing local items will be send (and possibly added,
1442 // if not already there) to the server
1443 markforresume=false; // not to be included in resume
1444 }
1445 else {
1446 // mark for resume if change to be reported
1447 markforresume=chglogP->modcount>fPreviousToRemoteModCount;
1448 }
1449 }
1450 }
1451 // now apply change of chgl_markedforresume to actual changelog entry
1452 #ifdef NUMERIC_LOCALIDS
1453 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkOnlyUngeneratedForResume: localID=%ld new markforresume=%d, old markforresume=%d"
, (long)chglogP->dbrecordid, (int)markforresume, (int)((chglogP
->flags & chgl_markedforresume)!=0) ); }
1454 "implMarkOnlyUngeneratedForResume: localID=%ld new markforresume=%d, old markforresume=%d",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkOnlyUngeneratedForResume: localID=%ld new markforresume=%d, old markforresume=%d"
, (long)chglogP->dbrecordid, (int)markforresume, (int)((chglogP
->flags & chgl_markedforresume)!=0) ); }
1455 (long)chglogP->dbrecordid,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkOnlyUngeneratedForResume: localID=%ld new markforresume=%d, old markforresume=%d"
, (long)chglogP->dbrecordid, (int)markforresume, (int)((chglogP
->flags & chgl_markedforresume)!=0) ); }
1456 (int)markforresume,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkOnlyUngeneratedForResume: localID=%ld new markforresume=%d, old markforresume=%d"
, (long)chglogP->dbrecordid, (int)markforresume, (int)((chglogP
->flags & chgl_markedforresume)!=0) ); }
1457 (int)((chglogP->flags & chgl_markedforresume)!=0){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkOnlyUngeneratedForResume: localID=%ld new markforresume=%d, old markforresume=%d"
, (long)chglogP->dbrecordid, (int)markforresume, (int)((chglogP
->flags & chgl_markedforresume)!=0) ); }
1458 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkOnlyUngeneratedForResume: localID=%ld new markforresume=%d, old markforresume=%d"
, (long)chglogP->dbrecordid, (int)markforresume, (int)((chglogP
->flags & chgl_markedforresume)!=0) ); }
;
1459 #else
1460 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkOnlyUngeneratedForResume: localID='%s' new markforresume=%d, old markforresume=%d"
, chglogP->dbrecordid, (int)markforresume, (int)((chglogP->
flags & chgl_markedforresume)!=0) ); }
1461 "implMarkOnlyUngeneratedForResume: localID='%s' new markforresume=%d, old markforresume=%d",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkOnlyUngeneratedForResume: localID='%s' new markforresume=%d, old markforresume=%d"
, chglogP->dbrecordid, (int)markforresume, (int)((chglogP->
flags & chgl_markedforresume)!=0) ); }
1462 chglogP->dbrecordid,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkOnlyUngeneratedForResume: localID='%s' new markforresume=%d, old markforresume=%d"
, chglogP->dbrecordid, (int)markforresume, (int)((chglogP->
flags & chgl_markedforresume)!=0) ); }
1463 (int)markforresume,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkOnlyUngeneratedForResume: localID='%s' new markforresume=%d, old markforresume=%d"
, chglogP->dbrecordid, (int)markforresume, (int)((chglogP->
flags & chgl_markedforresume)!=0) ); }
1464 (int)((chglogP->flags & chgl_markedforresume)!=0){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkOnlyUngeneratedForResume: localID='%s' new markforresume=%d, old markforresume=%d"
, chglogP->dbrecordid, (int)markforresume, (int)((chglogP->
flags & chgl_markedforresume)!=0) ); }
1465 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkOnlyUngeneratedForResume: localID='%s' new markforresume=%d, old markforresume=%d"
, chglogP->dbrecordid, (int)markforresume, (int)((chglogP->
flags & chgl_markedforresume)!=0) ); }
;
1466 #endif
1467 // update flag
1468 if (markforresume)
1469 chglogP->flags |= chgl_markedforresume;
1470 else
1471 chglogP->flags &= ~chgl_markedforresume;
1472 // Note: changelog will be saved at SaveAdminData
1473 }
1474} // TBinfileImplDS::implMarkOnlyUngeneratedForResume
1475
1476
1477// called to mark an already generated (but unsent or sent but not yet statused) item
1478// as "to-be-resumed", by localID or remoteID (latter only in server case).
1479void TBinfileImplDS::implMarkItemForResume(cAppCharP aLocalID, cAppCharP aRemoteID, bool aUnSent)
1480{
1481 if (!binfileDSActive()) return; // must be active when called at all
1482
1483 // make sure we have the changelog in memory
1484 loadChangeLog();
1485 localid_out_t locID;
1486 STR_TO_LOCALID(aLocalID,locID)(locID=(char *)aLocalID);
1487 // search for item by localID
1488 uInt32 i;
1489 for (i=0; i<fLoadedChangeLogEntries; i++) {
1490 if (LOCALID_EQUAL(fLoadedChangeLog[i].dbrecordid,LOCALID_OUT_TO_IN(locID))(strnncmp(fLoadedChangeLog[i].dbrecordid,((char *)locID.c_str
()),maxidlen)==0)
) {
1491 // found - mark it for resume
1492 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkItemForResume: localID='%s': marking changelog entry for resume=1, old markforresume=%d"
, aLocalID, (int)((fLoadedChangeLog[i].flags & chgl_markedforresume
)!=0) ); }
1493 "implMarkItemForResume: localID='%s': marking changelog entry for resume=1, old markforresume=%d",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkItemForResume: localID='%s': marking changelog entry for resume=1, old markforresume=%d"
, aLocalID, (int)((fLoadedChangeLog[i].flags & chgl_markedforresume
)!=0) ); }
1494 aLocalID,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkItemForResume: localID='%s': marking changelog entry for resume=1, old markforresume=%d"
, aLocalID, (int)((fLoadedChangeLog[i].flags & chgl_markedforresume
)!=0) ); }
1495 (int)((fLoadedChangeLog[i].flags & chgl_markedforresume)!=0){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkItemForResume: localID='%s': marking changelog entry for resume=1, old markforresume=%d"
, aLocalID, (int)((fLoadedChangeLog[i].flags & chgl_markedforresume
)!=0) ); }
1496 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkItemForResume: localID='%s': marking changelog entry for resume=1, old markforresume=%d"
, aLocalID, (int)((fLoadedChangeLog[i].flags & chgl_markedforresume
)!=0) ); }
;
1497 fLoadedChangeLog[i].flags |= chgl_markedforresume;
1498 break;
1499 }
1500 }
1501 #ifdef SYDEBUG2
1502 if (i>=fLoadedChangeLogEntries) {
1503 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkItemForResume: localID='%s': changelog entry not found"
, aLocalID ); }
1504 "implMarkItemForResume: localID='%s': changelog entry not found",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkItemForResume: localID='%s': changelog entry not found"
, aLocalID ); }
1505 aLocalID{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkItemForResume: localID='%s': changelog entry not found"
, aLocalID ); }
1506 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkItemForResume: localID='%s': changelog entry not found"
, aLocalID ); }
1507 }
1508 #endif
1509} // TBinfileImplDS::implMarkItemForResume
1510
1511
1512// called to mark an already sent item as "to-be-resent", e.g. due to temporary
1513// error status conditions, by localID or remoteID (latter only in server case).
1514void TBinfileImplDS::implMarkItemForResend(cAppCharP aLocalID, cAppCharP aRemoteID)
1515{
1516 if (!binfileDSActive()) return; // must be active when called at all
1517
1518 // make sure we have the changelog in memory
1519 loadChangeLog();
1520 localid_out_t locID;
1521 STR_TO_LOCALID(aLocalID,locID)(locID=(char *)aLocalID);
1522 // search for item by localID
1523 uInt32 i;
1524 for (i=0; i<fLoadedChangeLogEntries; i++) {
1525 if (LOCALID_EQUAL(fLoadedChangeLog[i].dbrecordid,LOCALID_OUT_TO_IN(locID))(strnncmp(fLoadedChangeLog[i].dbrecordid,((char *)locID.c_str
()),maxidlen)==0)
) {
1526 // found - mark it for resume
1527 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkItemForResend: localID='%s': marking changelog entry for resend"
, aLocalID ); }
1528 "implMarkItemForResend: localID='%s': marking changelog entry for resend",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkItemForResend: localID='%s': marking changelog entry for resend"
, aLocalID ); }
1529 aLocalID{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkItemForResend: localID='%s': marking changelog entry for resend"
, aLocalID ); }
1530 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkItemForResend: localID='%s': marking changelog entry for resend"
, aLocalID ); }
;
1531 fLoadedChangeLog[i].flags |= chgl_resend;
1532 break;
1533 }
1534 }
1535 #ifdef SYDEBUG2
1536 if (i>=fLoadedChangeLogEntries) {
1537 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkItemForResend: localID='%s': changelog entry not found"
, aLocalID ); }
1538 "implMarkItemForResend: localID='%s': changelog entry not found",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkItemForResend: localID='%s': changelog entry not found"
, aLocalID ); }
1539 aLocalID{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkItemForResend: localID='%s': changelog entry not found"
, aLocalID ); }
1540 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "implMarkItemForResend: localID='%s': changelog entry not found"
, aLocalID ); }
1541 }
1542 #endif
1543} // TBinfileImplDS::implMarkItemForResend
1544
1545
1546
1547
1548// Get next item from database
1549localstatus TBinfileImplDS::implGetItem(
1550 bool &aEof,
1551 bool &aChanged, // if set on entry, only changed ones will be reported, otherwise all will be returned and aChanged contains flag if entry has changed or not
1552 TSyncItem* &aSyncItemP
1553)
1554{
1555 if (!binfileDSActive()) return LOCERR_WRONGUSAGE; // must be active when called at all
1
Assuming the condition is false
2
Taking false branch
1556
1557 localstatus sta=LOCERR_OK;
1558 TSyncItem *myitemP=NULL__null;
1559 TChangeLogEntry *chglogP;
1560 bool onlyChanged = aChanged;
1561
1562 aEof=true;
1563
1564 // Update change log
1565 // Note: we cannot do it earlier as we need item types setup correctly
1566 // which is not the case before here!
1567 if (!fPreflighted) {
3
Assuming the condition is false
4
Taking false branch
1568 fPreflighted=true;
1569 // find and update (if not refreshing) changelog for this database
1570 bool normal=false;
1571 sta=changeLogPreflight(normal);
1572 if (sta!=LOCERR_OK)
1573 return sta; // database error
1574 }
1575 // simply return aEof when just refreshing
1576 if (fRefreshOnly) return LOCERR_OK;
5
Assuming the condition is false
6
Taking false branch
1577 // make sure we have the changelog in memory
1578 loadChangeLog();
1579 do {
1580 if (fLogEntryIndex<fLoadedChangeLogEntries) {
7
Taking true branch
1581 // there is a log entry, get it
1582 chglogP = &fLoadedChangeLog[fLogEntryIndex];
8
Null pointer value stored to 'chglogP'
1583 // advance to next
1584 fLogEntryIndex++;
1585 // if resuming, check if we must include this item at all
1586 if (isResuming()) {
9
Assuming the condition is true
10
Taking true branch
1587 // we are resuming, only report those that have the mark-for-resume flag set
1588 if (!(chglogP->flags & chgl_markedforresume)) {
11
Access to field 'flags' results in a dereference of a null pointer (loaded from variable 'chglogP')
1589 // not marked for resume, but check if it has changed after the last suspend
1590 // NOTE: this catches those added after last suspend as well, which is IMPORTANT
1591 // (otherwise, they would not get detected later, as we do not differentiate
1592 // adds and replaces (unlike in server, where new adds will be shown in the
1593 // next session after the resumed one)
1594 if (chglogP->modcount<=fPreviousSuspendModCount) {
1595 // is not marked for resume AND has not changed (or was added) since last suspend
1596 continue; // not for resume - check next
1597 }
1598 else {
1599 // New behaviour here from 3.1.5.2 onwards:
1600 // SyncML DS 1.2.1 explicitly FORBIDS that changes happening after suspending
1601 // are included in a resume. So we have to post-pone these. For that we must artificially
1602 // mark them changed such that they will be detected in next non-resume (but not before).
1603 // Note that this also affects other profiles as there is only one single changelog -
1604 // however, this is not a problem because the records detected new or changed now
1605 // will inevitably be new or changed in all other profiles as well. So we can
1606 // safely touch these record's modcount w/o any noticeable side effects in other profiles.
1607 PDEBUGPRINTFX(DBG_ADMIN+DBG_EXOTIC,("Detected item changed/added after suspend -> postpone reporting it for next non-resumed session")){ if (((0x00000040 +0x80000000) & getDbgMask()) == (0x00000040
+0x80000000)) getDbgLogger()->setNextMask(0x00000040 +0x80000000
).DebugPrintfLastMask ("Detected item changed/added after suspend -> postpone reporting it for next non-resumed session"
); }
;
1608 // - update the mod count such that this record will be detected again in the next non-resumed session
1609 // (fCurrentModCount marks entries changed in this session, +1 makes sure these will be detected in the NEXT session)
1610 chglogP->modcount=fCurrentModCount+1;
1611 // also update the creation stamp for new added item
1612 if(chglogP->modcount_created > fPreviousToRemoteModCount) {
1613 chglogP->modcount_created=fCurrentModCount+1;
1614 }
1615 // - mark it "modified by sync" to prevent it being sent during resume
1616 chglogP->flags |= chgl_modbysync;
1617 }
1618 }
1619 /* NOTE: 2007-12-17, luz: I initially added chgl_modbysync just to prevent that adds from server
1620 occurred in a suspended part of the session would be sent back to the
1621 server in the resume (as these DO get marked for resume). However, this
1622 is not a good strategy because the server cannot know which of its adds
1623 were actually successful, so the client MUST send them back to the
1624 server so the server can tell which items must be sent (possibly again)
1625 and which are definitely already stored in the client.
1626 See correspondence with Faisal from Oracle around 2007-12-17.
1627 So the chgl_modbysync flag is maintained for now, but not used
1628 for anything. */
1629 /* NOTE: 2008-01-11, luz: THE ABOVE IS WRONG! The server CAN know which adds were
1630 successful: those for which it has received a map in the suspended session
1631 or a begin-of-session-map in the current session (or both). So we SHOULD
1632 suppress those items that have chgl_modbysync set. */
1633 // we are resuming, prevent reporting those back that were added or changed
1634 // by one of the suspended earlier parts of this session
1635 if (chglogP->flags & chgl_modbysync) {
1636 PDEBUGPRINTFX(DBG_ADMIN+DBG_HOT,("Item not sent because it was added/changed by remote in suspended previous session or by user on device after suspend")){ if (((0x00000040 +0x00000001) & getDbgMask()) == (0x00000040
+0x00000001)) getDbgLogger()->setNextMask(0x00000040 +0x00000001
).DebugPrintfLastMask ("Item not sent because it was added/changed by remote in suspended previous session or by user on device after suspend"
); }
;
1637 continue; // these must NOT be reported back during a resumed sync
1638 }
1639 }
1640 else {
1641 // make sure we clear the resume mark on ALL entries, even those not reported
1642 // (as the marks are all invalid)
1643 chglogP->flags &= ~chgl_markedforresume;
1644 // for a non-resumed slow sync, also clear all resend flags
1645 if (fSlowSync) chglogP->flags &= ~chgl_resend;
1646 }
1647 // At this point, the current entry is a candidate for being reported
1648 // (not excplicitly excluded)
1649 // - now check if and how to report it
1650 if (fSlowSync) {
1651 // slow sync mode
1652 // - skip deleted in slow sync, but report all others
1653 if (chglogP->flags & chgl_deleted) {
1654 continue; // check next
1655 }
1656 }
1657 else {
1658 // prevent ANY reporting of items marked as receiveOnly in normal sync (but send them in slow sync!)
1659 if (chglogP->flags & chgl_receive_only) {
1660 // skip receive-only items in normal sync. So deleting or changing them locally will not send them
1661 // to the server. However after a slow sync, existing local items will be send (and possibly added,
1662 // if not already there) to the server
1663 continue;
1664 }
1665 // mark those as "changed" which have really changed or have the resend flag set
1666 bool hasChanged=
1667 (chglogP->modcount>fPreviousToRemoteModCount) || // change detected
1668 (chglogP->flags & chgl_resend); // or marked for resend e.g. due to error in last session
1669 #ifdef SYDEBUG2
1670 if (chglogP->flags & chgl_resend) {
1671 PDEBUGPRINTFX(DBG_ADMIN+DBG_HOT,({ if (((0x00000040 +0x00000001) & getDbgMask()) == (0x00000040
+0x00000001)) getDbgLogger()->setNextMask(0x00000040 +0x00000001
).DebugPrintfLastMask ( "Item treated as changed because resend-flag was set"
); }
1672 "Item treated as changed because resend-flag was set"{ if (((0x00000040 +0x00000001) & getDbgMask()) == (0x00000040
+0x00000001)) getDbgLogger()->setNextMask(0x00000040 +0x00000001
).DebugPrintfLastMask ( "Item treated as changed because resend-flag was set"
); }
1673 )){ if (((0x00000040 +0x00000001) & getDbgMask()) == (0x00000040
+0x00000001)) getDbgLogger()->setNextMask(0x00000040 +0x00000001
).DebugPrintfLastMask ( "Item treated as changed because resend-flag was set"
); }
;
1674 }
1675 #endif
1676 // clear resend flag now - it is processed
1677 chglogP->flags &= ~chgl_resend;
1678 // skip unchanged ones if only changed ones are to be reported
1679 if (!hasChanged && onlyChanged)
1680 continue; // unchanged, do not report
1681 // always report changed status in aChanged
1682 aChanged=hasChanged;
1683 }
1684 // this entry is to be reported
1685 // - now check how to report
1686 if (chglogP->flags & chgl_deleted) {
1687 // deleted: only report if it is also changed (i.e. delete detected since last sync)
1688 // Note: this can only happen when caller requests to see all records, not only changed,
1689 // which usually only occurs in slowsync where deletes are NOT reported anyway.
1690 // However: when caller must dynamically filter the syncset, it will request all records
1691 // even in normal syncs and then this can happen.
1692 if (!aChanged)
1693 continue; // delete was reported earlier, don't report it again
1694 // deleted, we cannot get it from the DB, create a empty item
1695 myitemP = new TSyncItem();
1696 // add ID
1697 ASSIGN_LOCALID_TO_ITEM(*myitemP,chglogP->dbrecordid)(*myitemP).setLocalID(chglogP->dbrecordid);
1698 // deleted, syncop is delete
1699 myitemP->setSyncOp(sop_delete);
1700 }
1701 else {
1702 // get contents from the DB
1703 myitemP=NULL__null; // in case getItemByID should abort before pointer assigned
1704 sta = getItemByID(chglogP->dbrecordid,myitemP);
1705 if ((sta!=LOCERR_OK) || !myitemP) {
1706 // error getting record
1707 if (sta==404) {
1708 // record seems to have vanished between preflight and now
1709 PDEBUGPRINTFX(DBG_ERROR,("Record does not exist any more in database%s -> ignore",lastDBErrorText().c_str())){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("Record does not exist any more in database%s -> ignore"
,lastDBErrorText().c_str()); }
;
1710 // simply don't include in sync set - next preflight will detect it deleted
1711 if (myitemP) delete myitemP; // delete in case we have some half-filled record here
1712 continue; // try next
1713 }
1714 else {
1715 // record does not exist
1716 PDEBUGPRINTFX(DBG_ERROR,("Error getting Record from DB%s -> Status %hd",lastDBErrorText().c_str(),sta)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("Error getting Record from DB%s -> Status %hd"
,lastDBErrorText().c_str(),sta); }
;
1717 goto error;
1718 }
1719 }
1720 // detect wheter the item is new added or changed
1721 if(chglogP->modcount_created > fPreviousToRemoteModCount) {
1722 // Added
1723 myitemP->setSyncOp(sop_add);
1724 }
1725 else {
1726 // Not added (changed or just reported because we want all records reported)
1727 // - if enabled, also verify change by checking CRC before reporting it (unless this is a slow sync)
1728 if (CRC_DETECT_PSEUDOCHANGES(fConfigP->fCRCPseudoChangeDetection) && aChanged) {
1729 // check if really changed using CRC, but only...
1730 // ...if not slow sync (all items must be reported)
1731 // ...if change was detected in this session's preflight. If the change was detected earlier and is still
1732 // pending (i.e. newer than the last sync), this means that this change might have failed to be applied
1733 // in a previous sync and thus must be reported again (but as CRC was updated in the last run,
1734 // it would be suppressed). This is a compromise that minimizes pseudochanges normally, but cannot
1735 // entirely prevent them. In other words: the first attempt to report a pseudo-change is
1736 // suppressed, but in case this sync fails, subsequent syncs will report it.
1737 uInt16 newDataCRC = myitemP->getDataCRC(0,true);
1738 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "CRC comparison for pseudo-change detection: old CRC=0x%hX, new CRC=0x%hX, recordModCount=%u, currentModCount=%u"
, chglogP->dataCRC, newDataCRC, chglogP->modcount, fCurrentModCount
); }
1739 "CRC comparison for pseudo-change detection: old CRC=0x%hX, new CRC=0x%hX, recordModCount=%u, currentModCount=%u",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "CRC comparison for pseudo-change detection: old CRC=0x%hX, new CRC=0x%hX, recordModCount=%u, currentModCount=%u"
, chglogP->dataCRC, newDataCRC, chglogP->modcount, fCurrentModCount
); }
1740 chglogP->dataCRC, newDataCRC, chglogP->modcount, fCurrentModCount{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "CRC comparison for pseudo-change detection: old CRC=0x%hX, new CRC=0x%hX, recordModCount=%u, currentModCount=%u"
, chglogP->dataCRC, newDataCRC, chglogP->modcount, fCurrentModCount
); }
1741 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "CRC comparison for pseudo-change detection: old CRC=0x%hX, new CRC=0x%hX, recordModCount=%u, currentModCount=%u"
, chglogP->dataCRC, newDataCRC, chglogP->modcount, fCurrentModCount
); }
;
1742 if (chglogP->dataCRC==newDataCRC && !fSlowSync && chglogP->modcount==fCurrentModCount) {
1743 // none of the relevant fields have changed -> don't report the item
1744 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("Not reporting localID='%s' as changed because CRC detected this as a pseudo-change.",myitemP->getLocalID())){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("Not reporting localID='%s' as changed because CRC detected this as a pseudo-change."
,myitemP->getLocalID()); }
;
1745 aChanged = false; // even if it gets reported, it does not count as changed any more
1746 if (onlyChanged) {
1747 // we don't need to report this at all, as we only report changed ones
1748 delete myitemP; // delete the item
1749 continue; // don't report, try next
1750 }
1751 // report as unchanged
1752 }
1753 else {
1754 // change will now be reported, so update CRC to what we report now
1755 // Note: the problem with this is that in case the sync does not succeed now, the CRC is already updated and would
1756 // trigger pseudo-change detection in the next session. Therefore, pseudo-change detection is only active for
1757 // changes newly detected during this sync.
1758 chglogP->dataCRC = newDataCRC;
1759 }
1760 } // CRC_DETECT_PSEUDOCHANGES
1761 // - report as replace (changed or not)
1762 myitemP->setSyncOp(sop_replace);
1763 }
1764 // make sure item has the localid which was used to retrieve it
1765 ASSIGN_LOCALID_TO_ITEM(*myitemP,chglogP->dbrecordid)(*myitemP).setLocalID(chglogP->dbrecordid);
1766 }
1767 // - make sure IDs are ok
1768 myitemP->clearRemoteID(); // client never has a remote ID
1769 // record found
1770 // - items that do go out into the engine must not any longer be marked for resume (from this session)
1771 // Note: they may get marked by receiving unsuccessful status for them before session ends!
1772 chglogP->flags &= ~chgl_markedforresume;
1773 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,("Reporting localID='%s', flags=0x%x as sop=%s",myitemP->getLocalID(),(int)chglogP->flags,SyncOpNames[myitemP->getSyncOp()])){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
("Reporting localID='%s', flags=0x%x as sop=%s",myitemP->
getLocalID(),(int)chglogP->flags,SyncOpNames[myitemP->getSyncOp
()]); }
;
1774 aEof=false;
1775 break;
1776 }
1777 else {
1778 // no more records
1779 break;
1780 }
1781 } while(true); // loop until record found or EOF
1782 // set item to return
1783 aSyncItemP = myitemP;
1784 // ok
1785 return LOCERR_OK;
1786error:
1787 // general database error
1788 PDEBUGPRINTFX(DBG_ERROR,("implGetItem error %hd%s",sta,lastDBErrorText().c_str())){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("implGetItem error %hd%s"
,sta,lastDBErrorText().c_str()); }
;
1789 aSyncItemP=NULL__null;
1790 return sta;
1791} // TBinfileImplDS::implGetItem
1792
1793
1794// end of read
1795localstatus TBinfileImplDS::implEndDataRead(void)
1796{
1797 if (!binfileDSActive()) return LOCERR_WRONGUSAGE; // must be active when called at all
1798
1799 // pass it on to the DB api (usually dummy for traditional binfile derivates, but
1800 // needed for customimplds)
1801 return apiEndDataRead();
1802} // TBinfileImplDS::implEndDataRead
1803
1804
1805
1806
1807/// forget changelog in memory
1808void TBinfileImplDS::forgetChangeLog(void)
1809{
1810 if (fLoadedChangeLog==NULL__null) return; // ok, already gone
1811 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,("forgetChangeLog: DISCARDING already loaded changelog with %ld entries",(long)fLoadedChangeLogEntries)){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
("forgetChangeLog: DISCARDING already loaded changelog with %ld entries"
,(long)fLoadedChangeLogEntries); }
;
1812 sysync_free(fLoadedChangeLog)free(fLoadedChangeLog);
1813 fLoadedChangeLog=NULL__null;
1814 fLoadedChangeLogEntries=0;
1815} // TBinfileImplDS::forgetChangeLog
1816
1817
1818/// load changelog into memory for quick access
1819void TBinfileImplDS::loadChangeLog(void)
1820{
1821 // if already loaded, simply return
1822 if (fLoadedChangeLog) return; // ok, already there
1823 // allocate memory for it
1824 fLoadedChangeLogEntries=fChangeLog.getNumRecords();
1825 if (fLoadedChangeLogEntries>0) {
1826 // (use sysync_malloc because e.g. on PalmOS this uses special funcs to allow > 64k)
1827 fLoadedChangeLog =
1828 (TChangeLogEntry *)sysync_malloc(sizeof(TChangeLogEntry)*fLoadedChangeLogEntries)malloc(sizeof(TChangeLogEntry)*fLoadedChangeLogEntries);
1829 if (fLoadedChangeLog) {
1830 // now load it
1831 if (fChangeLog.readRecord(0,fLoadedChangeLog,fLoadedChangeLogEntries)==BFE_OK0) {
1832 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,("loadChangeLog: loaded changelog with %ld entries",(long)fLoadedChangeLogEntries)){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
("loadChangeLog: loaded changelog with %ld entries",(long)fLoadedChangeLogEntries
); }
;
1833 }
1834 else {
1835 // cannot load from file, discard allocated buffer
1836 forgetChangeLog();
1837 }
1838 }
1839 else {
1840 // not enough memory, cannot load
1841 fLoadedChangeLogEntries=0;
1842 }
1843 }
1844} // TBinfileImplDS::loadChangeLog
1845
1846
1847#define ZAP_FORCES_SLOWSYNC1 1
1848
1849// start of write
1850localstatus TBinfileImplDS::implStartDataWrite(void)
1851{
1852 if (!binfileDSActive()) return LOCERR_WRONGUSAGE; // must be active when called at all
1853
1854 localstatus sta = LOCERR_OK;
1855
1856 // latest chance to do preflight in case GetItem was never called
1857 if (!fPreflighted) {
1858 fPreflighted=true;
1859 // find and update (if not refreshing) changelog for this database
1860 bool normal=false;
1861 changeLogPreflight(normal);
1862 if (!normal) return LOCERR_UNDEFINED; // failure
1863 }
1864 // let api layer do it's stuff
1865 sta = apiStartDataWrite();
1866 if (sta!=LOCERR_OK) return sta; // failed
1867 // check if we need to zap the datastore first
1868 // Note: only do it if not resuming!
1869 if (fSlowSync && fRefreshOnly && !isResuming()) {
1870 // yes, zap data
1871 sta = zapDatastore();
1872 if (sta!=LOCERR_OK) {
1873 preventResuming(); // only half-zapped, prevent resuming (we must retry zapping ALL and then do a full slow sync anyway)
1874 return sta; // failed
1875 }
1876 // now, either zap the changelog and set this datastore to slowsync in all
1877 // other profiles or flag all entries as deleted during this sync.
1878 #ifdef ZAP_FORCES_SLOWSYNC1
1879 // we force a slowsync, zap the changelog
1880 fChangeLog.truncate(0);
1881 // forget the anchor to force a slow sync anyway
1882 fTarget.remoteAnchor[0]=0; // (only to make sure. If sync completes successfully, this will be updated anyway in SaveAnchor)
1883 // for combined changelog, we need to take care of other profiles
1884 if (!static_cast<TBinfileClientConfig *>(fSessionP->getSessionConfig())->fSeparateChangelogs) {
1885 // zap the anchors in all other profiles for this datastore
1886 // because we have deleted the (common) changelog. Note that this also resets our own
1887 // target's anchor (again)
1888 // get target DB
1889 TBinFile *targetsBinFileP = &(static_cast<TBinfileImplClient *>(fSessionP)->fConfigP->fTargetsBinFile);
1890 TBinfileDBSyncTarget target;
1891 // - loop trough all targets
1892 for (uInt32 ti=0; ti<targetsBinFileP->getNumRecords(); ti++) {
1893 targetsBinFileP->readRecord(ti,&target);
1894 if (
1895 (target.localDBTypeID == fTarget.localDBTypeID) && // same datastoreID
1896 (strucmp(target.localDBPath,fTarget.localDBPath)==0) // ..and name
1897 ) {
1898 // this is a target of this datastore, remove saved anchor
1899 // to irreversibely force a slowsync next time
1900 target.remoteAnchor[0]=0;
1901 targetsBinFileP->updateRecord(ti,&target);
1902 }
1903 }
1904 } // if combined changelog
1905 #endif
1906 }
1907 // Load changelog as we need quick access
1908 loadChangeLog();
1909 #ifndef ZAP_FORCES_SLOWSYNC1
1910 if (fLoadedChangeLogEntries>0) {
1911 if (fSlowSync && fRefreshOnly) {
1912 // database was zapped, all existing changelog entries must be set to deleted
1913 // by this sync session.
1914 // (This is important for combined changelog, for separate changelog these entries
1915 // get obsolete anyway after this sync, but updating them for consistency is still good)
1916 for (uInt32 k=0; k<fLoadedChangeLogEntries; k++) {
1917 fLoadedChangeLog[k].modcount=fCurrentModCount;
1918 fLoadedChangeLog[k].dataCRC=0;
1919 fLoadedChangeLog[k].flags=chgl_deleted;
1920 }
1921 }
1922 }
1923 #endif
1924 // done
1925 return sta;
1926} // TBinfileImplDS::implStartDataWrite
1927
1928
1929// - retrieve specified item from database
1930bool TBinfileImplDS::implRetrieveItemByID(
1931 TSyncItem &aItem, // the item
1932 TStatusCommand &aStatusCommand
1933)
1934{
1935 if (!binfileDSActive()) return false; // must be active when called at all
1936 // %%% not so nice as we need to copy it once
1937 TSyncItem *itemP=NULL__null;
1938 // read item by local ID
1939 localid_t localid;
1940 localstatus sta;
1941 STR_TO_LOCALID(aItem.getLocalID(),localid)(localid=(char *)aItem.getLocalID());
1942 // get item now
1943 if ((sta=getItemByID(localid,itemP))!=LOCERR_OK) {
1944 aStatusCommand.setStatusCode(sta); // report status
1945 aStatusCommand.addItemString(lastDBErrorText().c_str());
1946 DEBUGPRINTFX(DBG_ERROR,("Item not found in database")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("Item not found in database"
); }
;
1947 return false;
1948 }
1949 if (itemP) {
1950 // make sure item has the localid which was used to retrieve it
1951 ASSIGN_LOCALID_TO_ITEM(*itemP,localid)(*itemP).setLocalID(localid);
1952 // and also the same syncop
1953 itemP->setSyncOp(aItem.getSyncOp());
1954 // now copy retrieved contents to original item
1955 aItem = *itemP;
1956 delete itemP;
1957 }
1958 // ok
1959 return true;
1960} // TBinfileImplDS::implRetrieveItemByID
1961
1962
1963// process single item (but does not consume it)
1964bool TBinfileImplDS::implProcessItem(
1965 TSyncItem *aItemP, // the item
1966 TStatusCommand &aStatusCommand
1967)
1968{
1969 if (!binfileDSActive()) return false; // must be active when called at all
1970
1971 localid_out_t newid;
1972 TSyError statuscode;
1973 localstatus sta;
1974 bool ok;
1975 bool receiveOnly=false; // default to normal two-way
1976 bool reportAsChangedInNextSync=false;
1977 bool reportAsDeletedInNextSync=false;
1978 TMultiFieldItem *augmentedItemP = NULL__null;
1979
1980 SYSYNC_TRYtry {
1981 // - get op
1982 TSyncOperation sop = aItemP->getSyncOp();
1983 // - get localid
1984 localid_t localid;
1985 STR_TO_LOCALID(aItemP->getLocalID(),localid)(localid=(char *)aItemP->getLocalID());
1986 // - now perform op
1987 switch (sop) {
1988 // %%% note: sop_copy is now implemented by read/add sequence
1989 // in localdatatstore, but will be moved here later possibly
1990 case sop_add :
1991 // add record
1992 if ((sta=createItem(aItemP,newid,receiveOnly))!=LOCERR_OK) {
1993 if (sta != LOCERR_AGAIN) {
1994 PDEBUGPRINTFX(DBG_ERROR,("cannot create record in database (sta=%hd)",sta)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("cannot create record in database (sta=%hd)"
,sta); }
;
1995 }
1996 // check special "needs merge" case
1997 if (sta==DB_Conflict) {
1998 // DB has detected item conflicts with data already stored in the database and
1999 // request merging current data from the backend with new data before storing.
2000 // - get the ID of the record to merge with
2001 localid = LOCALID_OUT_TO_IN(newid)((char *)newid.c_str());
2002 ASSIGN_LOCALID_TO_ITEM(*aItemP,localid)(*aItemP).setLocalID(localid);
2003 // - merge with database contents
2004 bool changedDBVersion, changedNewVersion;
2005 augmentedItemP = mergeWithDatabaseVersion(aItemP, changedDBVersion, changedNewVersion);
2006 if (augmentedItemP==NULL__null)
2007 sta = DB_Error; // no item found, DB error
2008 else {
2009 // store augmented version back to DB only if modified
2010 if (changedDBVersion) {
2011 STR_TO_LOCALID(augmentedItemP->getLocalID(),localid)(localid=(char *)augmentedItemP->getLocalID());
2012 sta = updateItemByID(localid,augmentedItemP);
2013 // we'll need to sync it back in the next session,
2014 // because the server's copy is now older than the
2015 // client's copy
2016 if (sta == LOCERR_OK) reportAsChangedInNextSync = true;
2017 }
2018 else {
2019 sta = LOCERR_OK;
2020 }
2021 }
2022 // The server now has two items where the client only has
2023 // one. If we were to tell the server the same local ID
2024 // for both of the server's items, it would get confused.
2025 // For example, the Synthesis engine then sent a Delete
2026 // request with empty client and server ID.
2027 //
2028 // Instead, let the rest of the code below proceed (to get
2029 // the state of the existing local item right), and then
2030 // create a unique, fake local ID that we assign to the
2031 // item and copy into the change log as "deleted item".
2032 if (sta == LOCERR_OK) reportAsDeletedInNextSync = true;
2033 }
2034 else {
2035 statuscode=sta;
2036 goto error; // check errors
2037 }
2038 }
2039 // set status
2040 statuscode=201; // added
2041 // set new localID into item
2042 localid = LOCALID_OUT_TO_IN(newid)((char *)newid.c_str());
2043 ASSIGN_LOCALID_TO_ITEM(*aItemP,localid)(*aItemP).setLocalID(localid);
2044 break;
2045 case sop_replace :
2046 // change record
2047 if ((sta=updateItemByID(localid,aItemP))!=LOCERR_OK) {
2048 if (sta != LOCERR_AGAIN) {
2049 PDEBUGPRINTFX(DBG_ERROR,("cannot update record in database (sta=%hd)",sta)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("cannot update record in database (sta=%hd)"
,sta); }
;
2050 }
2051 statuscode=sta;
2052 goto error; // check errors
2053 }
2054 // set status
2055 statuscode=200; // replaced
2056 break;
2057 case sop_delete :
2058 // delete record
2059 if ((sta=deleteItemByID(localid))!=LOCERR_OK) {
2060 if (sta != LOCERR_AGAIN) {
2061 PDEBUGPRINTFX(DBG_ERROR,("cannot delete record in database (sta=%hd)",sta)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("cannot delete record in database (sta=%hd)"
,sta); }
;
2062 }
2063 statuscode=sta; // not found
2064 goto error; // check errors
2065 }
2066 // set status
2067 statuscode=200;
2068 break;
2069 default :
2070 PDEBUGPRINTFX(DBG_ERROR,("Unknown sync-op in TBinfileImplDS::ProcessItem")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("Unknown sync-op in TBinfileImplDS::ProcessItem"
); }
;
2071 statuscode=501; // not implemented
2072 goto error;
2073 } // switch(sop)
2074 // update changelog
2075 uInt16 crc=0; // none unless we need it
2076 if (CRC_CHANGE_DETECTION(fConfigP->fCRCChangeDetection) || CRC_DETECT_PSEUDOCHANGES(fConfigP->fCRCPseudoChangeDetection)) {
2077 // - calc new data CRC if not deleted record
2078 if (sop!=sop_delete) {
2079 // - get new CRC. Note: to avoid differences in written and readback
2080 // data to cause "changed" records, we read the item from the DB again
2081 // altough this needs a little extra CPU performance
2082 #ifdef RECORDHASH_FROM_DBAPI
2083 if (getItemCRCByID(localid,crc)!=LOCERR_OK) {
2084 // we don't find the item with that localID.
2085 // Probably it has got another localID due to DB-internal reasons
2086 // (such as POOM changing a recurring appointment)
2087 // - handle this as if it was ok. Next session's preflight will find
2088 // that the item is gone and will send a delete to server, and
2089 // will also find a new item (this one under new localid) and add
2090 // this to the server.
2091 crc=0;
2092 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("Item has probably changed its localid during replace, CRC gets invalid")){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("Item has probably changed its localid during replace, CRC gets invalid"
); }
;
2093 }
2094 #else
2095 TSyncItem *readbackItemP=NULL__null;
2096 if (getItemByID(localid,readbackItemP)!=LOCERR_OK) {
2097 // we don't find the item with that localID.
2098 // Probably it has got another localID due to DB-internal reasons
2099 // (such as POOM changing a recurring appointment)
2100 // - handle this as if it was ok. Next session's preflight will find
2101 // that the item is gone and will send a delete to server, and
2102 // will also find a new item (this one under new localid) and add
2103 // this to the server.
2104 crc=0;
2105 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("Item has probably changed its localid during replace, CRC gets invalid")){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("Item has probably changed its localid during replace, CRC gets invalid"
); }
;
2106 }
2107 else {
2108 // Note: we don't need to set localID in item as it is not used in the CRC
2109 crc = readbackItemP->getDataCRC(0,true); // start new CRC, do not include eqm_none fields
2110 }
2111 if (readbackItemP) delete readbackItemP;
2112 #endif // not RECORDHASH_FROM_DBAPI
2113 }
2114 }
2115 // - search changelog entry
2116 sInt32 logindex=-1;
2117 TChangeLogEntry newentry;
2118 TChangeLogEntry *affectedentryP = &newentry;
2119 memset(&newentry, 0, sizeof(newentry));
2120 for (uInt32 i=0; i<fLoadedChangeLogEntries; i++) {
2121 if (LOCALID_EQUAL(fLoadedChangeLog[i].dbrecordid,localid)(strnncmp(fLoadedChangeLog[i].dbrecordid,localid,maxidlen)==0
)
) {
2122 logindex=i;
2123 affectedentryP=&(fLoadedChangeLog[i]);
2124 break;
2125 }
2126 }
2127 // now affectedentryP points to where we need to apply the changed crc and modcount
2128 // if logindex<0 we need to add the entry to the dbfile afterwards
2129 affectedentryP->dataCRC=crc;
2130 if (reportAsChangedInNextSync) {
2131 // make sure NEXT sync will catch this again, as stored version is different
2132 // from what we received (merged with pre-existing duplicate)
2133 affectedentryP->modcount=fCurrentModCount+1;
2134 fHasPendingChanges=true;
2135 }
2136 else {
2137 // just current mod count
2138 affectedentryP->modcount=fCurrentModCount;
2139 }
2140 if (sop==sop_delete)
2141 affectedentryP->flags |= chgl_deleted;
2142 // set receiveOnly flag if needed. Note that this flag, once set, is never deleted (so item stays write only)
2143 if (receiveOnly)
2144 affectedentryP->flags |= chgl_receive_only;
2145 // set special flag which prevents that this change gets sent back in a resume as a
2146 // "modified or added after last suspend" type record (which it technically is, but we
2147 // use the flag to prevent that it is sent back if this session is suspended and resumed later.
2148 // Note that real adds and changes happening during suspend will also get this flag set
2149 // (but also receive a modcount>fCurrentModCount that makes sure these will be reported in
2150 // the next non-resumed session).
2151 affectedentryP->flags |= chgl_modbysync;
2152 // add to changelog DB if needed
2153 if (logindex<0) {
2154 // new added item
2155 ASSIGN_LOCALID_TO_FLD(affectedentryP->dbrecordid,localid)AssignCString(affectedentryP->dbrecordid,localid,maxidlen);
2156 // also record the time this entry was created
2157 affectedentryP->modcount_created=fCurrentModCount;
2158 // save it
2159 #ifdef NUMERIC_LOCALIDS
2160 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), affectedentryP->dbrecordid
, (int)affectedentryP->flags, (long)affectedentryP->modcount
, affectedentryP->dataCRC ); }
2161 "new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), affectedentryP->dbrecordid
, (int)affectedentryP->flags, (long)affectedentryP->modcount
, affectedentryP->dataCRC ); }
2162 (long)fChangeLog.getNumRecords(),{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), affectedentryP->dbrecordid
, (int)affectedentryP->flags, (long)affectedentryP->modcount
, affectedentryP->dataCRC ); }
2163 affectedentryP->dbrecordid,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), affectedentryP->dbrecordid
, (int)affectedentryP->flags, (long)affectedentryP->modcount
, affectedentryP->dataCRC ); }
2164 (int)affectedentryP->flags,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), affectedentryP->dbrecordid
, (int)affectedentryP->flags, (long)affectedentryP->modcount
, affectedentryP->dataCRC ); }
2165 (long)affectedentryP->modcount,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), affectedentryP->dbrecordid
, (int)affectedentryP->flags, (long)affectedentryP->modcount
, affectedentryP->dataCRC ); }
2166 affectedentryP->dataCRC{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), affectedentryP->dbrecordid
, (int)affectedentryP->flags, (long)affectedentryP->modcount
, affectedentryP->dataCRC ); }
2167 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), affectedentryP->dbrecordid
, (int)affectedentryP->flags, (long)affectedentryP->modcount
, affectedentryP->dataCRC ); }
;
2168 #else
2169 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), affectedentryP->dbrecordid
, (int)affectedentryP->flags, (long)affectedentryP->modcount
, affectedentryP->dataCRC ); }
2170 "new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), affectedentryP->dbrecordid
, (int)affectedentryP->flags, (long)affectedentryP->modcount
, affectedentryP->dataCRC ); }
2171 (long)fChangeLog.getNumRecords(),{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), affectedentryP->dbrecordid
, (int)affectedentryP->flags, (long)affectedentryP->modcount
, affectedentryP->dataCRC ); }
2172 affectedentryP->dbrecordid,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), affectedentryP->dbrecordid
, (int)affectedentryP->flags, (long)affectedentryP->modcount
, affectedentryP->dataCRC ); }
2173 (int)affectedentryP->flags,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), affectedentryP->dbrecordid
, (int)affectedentryP->flags, (long)affectedentryP->modcount
, affectedentryP->dataCRC ); }
2174 (long)affectedentryP->modcount,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), affectedentryP->dbrecordid
, (int)affectedentryP->flags, (long)affectedentryP->modcount
, affectedentryP->dataCRC ); }
2175 affectedentryP->dataCRC{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), affectedentryP->dbrecordid
, (int)affectedentryP->flags, (long)affectedentryP->modcount
, affectedentryP->dataCRC ); }
2176 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), affectedentryP->dbrecordid
, (int)affectedentryP->flags, (long)affectedentryP->modcount
, affectedentryP->dataCRC ); }
;
2177 #endif
2178 // Note: changeLogPostflight() will check these for temporary localids and finalize them when needed
2179 fChangeLog.newRecord(affectedentryP);
2180 }
2181 if (reportAsDeletedInNextSync) {
2182 fHasPendingChanges=true;
2183 #ifdef NUMERIC_LOCALIDS
2184 // assumes that valid local IDs are positive
2185 // and can hold values in the range of -1 to -RAND_MAX-1
2186 localid_t fakelocalid = -(rand() & 0x7FFFFFFF) - 1;
2187 #else
2188 char fakelocalid[STRING_LOCALID_MAXLEN256];
2189 static unsigned int fakeidcounter;
2190 sprintf(fakelocalid, "fake-%u-%d", ++fakeidcounter, rand());
2191 #endif
2192 // Checking for collisions with other fake IDs would be nice,
2193 // but isn't easy because new entries in fChangeLog are not
2194 // in memory. We have to trust the random number generator
2195 // and the sequence counter (for string IDs).
2196 memset(&newentry, 0, sizeof(newentry));
2197 ASSIGN_LOCALID_TO_FLD(newentry.dbrecordid,fakelocalid)AssignCString(newentry.dbrecordid,fakelocalid,maxidlen);
2198 ASSIGN_LOCALID_TO_ITEM(*aItemP,fakelocalid)(*aItemP).setLocalID(fakelocalid);
2199 newentry.flags = chgl_deleted;
2200 // send during next sync
2201 newentry.modcount_created =
2202 newentry.modcount = fCurrentModCount+1;
2203 #ifdef NUMERIC_LOCALIDS
2204 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "fake new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), newentry.dbrecordid, (int
)newentry.flags, (long)newentry.modcount, newentry.dataCRC );
}
2205 "fake new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "fake new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), newentry.dbrecordid, (int
)newentry.flags, (long)newentry.modcount, newentry.dataCRC );
}
2206 (long)fChangeLog.getNumRecords(),{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "fake new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), newentry.dbrecordid, (int
)newentry.flags, (long)newentry.modcount, newentry.dataCRC );
}
2207 newentry.dbrecordid,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "fake new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), newentry.dbrecordid, (int
)newentry.flags, (long)newentry.modcount, newentry.dataCRC );
}
2208 (int)newentry.flags,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "fake new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), newentry.dbrecordid, (int
)newentry.flags, (long)newentry.modcount, newentry.dataCRC );
}
2209 (long)newentry.modcount,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "fake new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), newentry.dbrecordid, (int
)newentry.flags, (long)newentry.modcount, newentry.dataCRC );
}
2210 newentry.dataCRC{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "fake new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), newentry.dbrecordid, (int
)newentry.flags, (long)newentry.modcount, newentry.dataCRC );
}
2211 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "fake new entry %ld : localID=%ld, flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), newentry.dbrecordid, (int
)newentry.flags, (long)newentry.modcount, newentry.dataCRC );
}
;
2212 #else
2213 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "fake new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), newentry.dbrecordid, (int
)newentry.flags, (long)newentry.modcount, newentry.dataCRC );
}
2214 "fake new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "fake new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), newentry.dbrecordid, (int
)newentry.flags, (long)newentry.modcount, newentry.dataCRC );
}
2215 (long)fChangeLog.getNumRecords(),{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "fake new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), newentry.dbrecordid, (int
)newentry.flags, (long)newentry.modcount, newentry.dataCRC );
}
2216 newentry.dbrecordid,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "fake new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), newentry.dbrecordid, (int
)newentry.flags, (long)newentry.modcount, newentry.dataCRC );
}
2217 (int)newentry.flags,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "fake new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), newentry.dbrecordid, (int
)newentry.flags, (long)newentry.modcount, newentry.dataCRC );
}
2218 (long)newentry.modcount,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "fake new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), newentry.dbrecordid, (int
)newentry.flags, (long)newentry.modcount, newentry.dataCRC );
}
2219 newentry.dataCRC{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "fake new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), newentry.dbrecordid, (int
)newentry.flags, (long)newentry.modcount, newentry.dataCRC );
}
2220 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "fake new entry %ld : localID='%s', flags=0x%X, modcount=modcount_created=%ld, new dataCRC=0x%hX"
, (long)fChangeLog.getNumRecords(), newentry.dbrecordid, (int
)newentry.flags, (long)newentry.modcount, newentry.dataCRC );
}
;
2221 #endif
2222 fChangeLog.newRecord(&newentry);
2223 }
2224 // done
2225 ok=true;
2226 goto done;
2227 }
2228 SYSYNC_CATCH (exception &e)catch(exception &e) {
2229 statuscode=500;
2230 DEBUGPRINTFX(DBG_ERROR,("******** Exception in TBinfileImplDS::ProcessItem: %s (status=%ld)",e.what(), (long)statuscode)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("******** Exception in TBinfileImplDS::ProcessItem: %s (status=%ld)"
,e.what(), (long)statuscode); }
;
2231 ok=false;
2232 goto done;
2233 SYSYNC_ENDCATCH}
2234 SYSYNC_CATCH (...)catch(...) {
2235 DEBUGPRINTFX(DBG_ERROR,("******** Exception in TBinfileImplDS::ProcessItem")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("******** Exception in TBinfileImplDS::ProcessItem"
); }
;
2236 statuscode=500;
2237 ok=false;
2238 goto done;
2239 SYSYNC_ENDCATCH}
2240error:
2241 // report OS specific error codes as item text back to the originator
2242 ok=false;
2243 if (statuscode != LOCERR_AGAIN) {
2244 PDEBUGPRINTFX(DBG_ERROR,("Database Error --> SyncML status %ld%s",(long)statuscode,lastDBErrorText().c_str())){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("Database Error --> SyncML status %ld%s"
,(long)statuscode,lastDBErrorText().c_str()); }
;
2245 }
2246 //aStatusCommand.addItemString(lastDBErrorDbgText().c_str());
2247done:
2248 delete augmentedItemP;
2249 aStatusCommand.setStatusCode(statuscode);
2250 return ok;
2251} // TBinfileImplDS::implProcessItem
2252
2253
2254// called to confirm a sync operation's completion (status from remote received)
2255// @note aSyncOp passed not necessarily reflects what was sent to remote, but what actually happened
2256void TBinfileImplDS::dsConfirmItemOp(TSyncOperation aSyncOp, cAppCharP aLocalID, cAppCharP aRemoteID, bool aSuccess, localstatus aErrorStatus)
2257{
2258 if (binfileDSActive()) {
2259 // Nothing to do here, even successful deletes must not delete changelog entry (this will be done
2260 // by changeLogPostFlight() for those enties that have been reported as deleted in all profiles!)
2261 }
2262 // - let inherited know as well
2263 inherited::dsConfirmItemOp(aSyncOp, aLocalID, aRemoteID, aSuccess, aErrorStatus);
2264} // TBinfileImplDS::confirmItemOp
2265
2266
2267// - save status information required to possibly perform a resume (as passed to datastore with
2268// implMarkOnlyUngeneratedForResume() and implMarkItemForResume())
2269// (or, in case the session is really complete, make sure that no resume state is left)
2270localstatus TBinfileImplDS::implSaveResumeMarks(void)
2271{
2272 if (!binfileDSActive()) return LOCERR_WRONGUSAGE; // must be active when called at all
2273
2274 // update modcount reference of last suspend
2275 fPreviousSuspendModCount = fCurrentModCount;
2276 // save admin data now
2277 return SaveAdminData(true,false); // end of session, but not successful
2278} // TBinfileImplDS::implSaveResumeMarks
2279
2280
2281
2282// log datastore sync result
2283// - Called at end of sync with this datastore
2284void TBinfileImplDS::dsLogSyncResult(void)
2285{
2286 // Note: binfile logs can be active even if binfiles layer otherwise is not active
2287 TBinfileClientConfig *clientCfgP = static_cast<TBinfileClientConfig *>(fSessionP->getSessionConfig());
2288 if (clientCfgP->fBinFileLog) {
2289 // writing binfile logs enabled
2290 TBinFile logFile;
2291 // Open logfile
2292 // - get base path
2293 string filepath;
2294 clientCfgP->getBinFilesPath(filepath);
2295 filepath += LOGFILE_DB_NAME"sysynclib_" "log.bfi";
2296 // - open or create
2297 logFile.setFileInfo(filepath.c_str(),LOGFILE_DB_VERSION3,LOGFILE_DB_ID8,sizeof(TLogFileEntry));
2298 if (logFile.open(0,NULL__null,NULL__null)!=BFE_OK0) {
2299 // create new one or overwrite incompatible one
2300 logFile.create(sizeof(TLogFileEntry),0,NULL__null,true);
2301 }
2302 // append new record
2303 // - create record
2304 TLogFileEntry logInfo;
2305 logInfo.time = fCurrentSyncTime; // current sync's time
2306 logInfo.status = getAbortStatusCode(); // reason for abort (0 if ok)
2307 logInfo.mode =
2308 (fSlowSync ? (fFirstTimeSync ? 2 : 1) : 0) +
2309 (fResuming ? 10 : 0);
2310 logInfo.dirmode = fSyncMode; // sync direction mode
2311 logInfo.infoID = 0; // none
2312 logInfo.dbID = fConfigP->fLocalDBTypeID; // ID of DB (to allow fetching name)
2313 logInfo.profileID = static_cast<TBinfileImplClient *>(fSessionP)->fRemotepartyID; // ID of profile (to allow fetching name)
2314 logInfo.locAdded = fLocalItemsAdded;
2315 logInfo.locUpdated = fLocalItemsUpdated;
2316 logInfo.locDeleted = fLocalItemsDeleted;
2317 logInfo.remAdded = fRemoteItemsAdded;
2318 logInfo.remUpdated = fRemoteItemsUpdated;
2319 logInfo.remDeleted = fRemoteItemsDeleted;
2320 logInfo.inBytes = fIncomingDataBytes;
2321 logInfo.outBytes = fOutgoingDataBytes;
2322 logInfo.locRejected = fLocalItemsError;
2323 logInfo.remRejected = fRemoteItemsError;
2324 // - save it
2325 logFile.newRecord(&logInfo);
2326 // close the logfile again
2327 logFile.close();
2328 }
2329} // TBinfileImplDS::dsLogSyncResult
2330
2331
2332// save end of session state
2333// Note that in BASED_ON_BINFILE_CLIENT case, this is derived in customimplds and will
2334// be called by the derivate after doing customimpl specific stuff.
2335localstatus TBinfileImplDS::implSaveEndOfSession(bool aUpdateAnchors)
2336{
2337 if (!binfileDSActive()) return LOCERR_WRONGUSAGE; // must be active when called at all
2338
2339 // update TCustomImplDS dsSavedAdmin variables (other levels have already updated their variables
2340 if (aUpdateAnchors) {
2341 if (!fRefreshOnly || fSlowSync) {
2342 // This was really a two-way sync or we implicitly know that
2343 // we are now in sync with remote (like after one-way-from-remote refresh = reload local)
2344 fPreviousToRemoteModCount = fCurrentModCount;
2345 }
2346 // updating anchor means invalidating last Suspend
2347 fPreviousSuspendCmpRef = fPreviousToRemoteSyncCmpRef; // setting to current reference can do less harm than setting it to zero
2348 fPreviousSuspendModCount=0;
2349 }
2350 // save admin data now
2351 localstatus sta=SaveAdminData(true,aUpdateAnchors); // end of session
2352 if (sta==LOCERR_OK) {
2353 // finalize admin data stuff now
2354 uInt32 oldestmodcount=0xFFFFFFFF;
2355 // do a postFlight to remove unused entries from the changelog
2356 if (static_cast<TBinfileClientConfig *>(fSessionP->getSessionConfig())->fSeparateChangelogs) {
2357 // Each profile has it's own changelog, so just delete entries that are older than this profile's last sync or resume
2358 if (fTarget.lastSuspendModCount!=0)
2359 oldestmodcount = fTarget.lastSuspendModCount;
2360 if (fTarget.lastTwoWayModCount!=0 && fTarget.lastTwoWayModCount<oldestmodcount)
2361 oldestmodcount = fTarget.lastTwoWayModCount;
2362 }
2363 else {
2364 // Combined changelog for all profiles, need to keep deleted markers for other profiles
2365 // - find oldest sync modcount
2366 TBinFile *targetsBinFileP = &(static_cast<TBinfileImplClient *>(fSessionP)->fConfigP->fTargetsBinFile);
2367 uInt32 maxidx = targetsBinFileP->getNumRecords();
2368 uInt32 idx;
2369 TBinfileDBSyncTarget target;
2370 for (idx=0; idx<maxidx; idx++) {
2371 targetsBinFileP->readRecord(idx,&target);
2372 if (
2373 // Note: %%% this is same mechanism as for changelog filenames
2374 // Not ok if multiple databases go with the same datastore.getName()
2375 strucmp(target.dbname,getName())==0
2376 ) {
2377 // target for this database found, check if modcount is older
2378 if (target.lastSuspendModCount!=0 && target.lastSuspendModCount<oldestmodcount)
2379 oldestmodcount=target.lastSuspendModCount; // older one found
2380 if (target.lastTwoWayModCount!=0 && target.lastTwoWayModCount<oldestmodcount)
2381 oldestmodcount=target.lastTwoWayModCount; // older one found
2382 }
2383 }
2384 } // combined changelog
2385 // For both types: Now do cleanup of all deleted entries that we don't need any more
2386 sta=changeLogPostflight(oldestmodcount);
2387 }
2388 // done
2389 return sta;
2390} // TBinfileImplDS::implSaveEndOfSession
2391
2392
2393// - end write with commit
2394bool TBinfileImplDS::implEndDataWrite(void)
2395{
2396 if (!binfileDSActive()) return false; // must be active when called at all
2397
2398 // Call apiEndDataWrite variant which is possibly implemented in
2399 // datastores which were designed as direct derivates of binfileds.
2400 // Note that in BASED_ON_BINFILE_CLIENT case, implEndDataWrite() is
2401 // derived by customimplds and will call the other apiEndDataWrite(cmpRef)
2402 // variant, and then call this inherited method.
2403 return apiEndDataWrite()!=LOCERR_OK;
2404} // TBinfileImplDS::implEndDataWrite
2405
2406
2407
2408// private helper to prepare for apiSaveAdminData()
2409localstatus TBinfileImplDS::SaveAdminData(bool aSessionFinished, bool aSuccessful)
2410{
2411 PDEBUGBLOCKDESCCOLL("SaveAdminData","Saving changelog, target and map info")getDbgLogger()->DebugOpenBlock( "SaveAdminData","Saving changelog, target and map info"
,true)
;
2412 // save and free cached changelog anyway
2413 if (fLoadedChangeLog) {
2414 #ifdef SYDEBUG2
2415 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,("SaveAdminData: saving changelog with %ld entries",(long)fLoadedChangeLogEntries)){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
("SaveAdminData: saving changelog with %ld entries",(long)fLoadedChangeLogEntries
); }
;
2416 if (DEBUGTEST(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC)(((0x00000040 +0x02000000 +0x80000000) & getDbgMask()) ==
(0x00000040 +0x02000000 +0x80000000))
) {
2417 for (uInt32 si=0; si<fLoadedChangeLogEntries; si++) {
2418 #ifdef NUMERIC_LOCALIDS
2419 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
2420 "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
2421 (long)si,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
2422 fLoadedChangeLog[si].dbrecordid,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
2423 (int)fLoadedChangeLog[si].flags,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
2424 (long)fLoadedChangeLog[si].modcount,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
2425 (long)fLoadedChangeLog[si].modcount_created{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
2426 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID=%ld, flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
;
2427 #else
2428 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
2429 "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
2430 (long)si,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
2431 fLoadedChangeLog[si].dbrecordid,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
2432 (int)fLoadedChangeLog[si].flags,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
2433 (long)fLoadedChangeLog[si].modcount,{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
2434 (long)fLoadedChangeLog[si].modcount_created{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
2435 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "%ld : localID='%s', flags=0x%X, modcount=%ld, modcount_created=%ld"
, (long)si, fLoadedChangeLog[si].dbrecordid, (int)fLoadedChangeLog
[si].flags, (long)fLoadedChangeLog[si].modcount, (long)fLoadedChangeLog
[si].modcount_created ); }
;
2436 #endif
2437 }
2438 }
2439 #endif
2440 fChangeLog.updateRecord(0,fLoadedChangeLog,fLoadedChangeLogEntries);
2441 forgetChangeLog();
2442 }
2443 // save the "last changelog update" identifier into the changelog header
2444 // Note: fPreviousToRemoteSyncCmpRef/fPreviousToRemoteSyncIdentifier represent last update of changelog
2445 // in binfileds, rather than last to-remote-sync as in non-binfile based setups.
2446 // - update the identifier (token for StartDataRead)
2447 AssignCString(fChgLogHeader.lastChangeCheckIdentifier, fPreviousToRemoteSyncIdentifier.c_str(),changeIndentifierMaxLen);
2448 // - update compare reference time for next preflight if fCmpRefTimeStampAtEnd is set (default = defined(SYNCTIME_IS_ENDOFSESSION))
2449 // Note: preflight has already set fChgLogHeader.lastChangeCheck to the beginning of the sync
2450 // Update it here only if synctime must be end of session.
2451 if (fConfigP->fCmpRefTimeStampAtEnd) {
2452 fChgLogHeader.lastChangeCheck = getSession()->getSystemNowAs(TCTX_UTC((timecontext_t) ((tctx_tz_UTC) | TCTX_SYMBOLIC_TZ))); // NOW ! (again);
2453 }
2454 fChangeLog.setExtraHeaderDirty();
2455 fChangeLog.flushHeader();
2456 // save other admin data
2457 TBinFile *targetsBinFileP = &(static_cast<TBinfileImplClient *>(fSessionP)->fConfigP->fTargetsBinFile);
2458 // update target fields
2459 // - update anchor
2460 AssignCString(fTarget.remoteAnchor,fLastRemoteAnchor.c_str(),remoteAnchorMaxLen);
2461 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("SaveAdminData: saving remote anchor = '%s'",fLastRemoteAnchor.c_str())){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("SaveAdminData: saving remote anchor = '%s'"
,fLastRemoteAnchor.c_str()); }
;
2462 // - update this sync time (last sync field in DB) and modcount
2463 fTarget.lastSync=fPreviousSyncTime;
2464 fTarget.lastTwoWayModCount=fPreviousToRemoteModCount;
2465 // Note: compare times and identifiers are not needed any more (these are now in the changelog),
2466 // But we assigne some for dbg purposes.
2467 // - update the last changelog check time.
2468 fTarget.lastChangeCheck=fPreviousToRemoteSyncCmpRef;
2469 #if TARGETS_DB_VERSION6>=6
2470 // - identifiers (tokens for StartDataRead)
2471 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,("SaveAdminData: saving target sync token %s", fPreviousToRemoteSyncIdentifier.c_str())){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
("SaveAdminData: saving target sync token %s", fPreviousToRemoteSyncIdentifier
.c_str()); }
;
2472 AssignCString(fTarget.dummyIdentifier1,fPreviousToRemoteSyncIdentifier.c_str(),remoteAnchorMaxLen); // former lastSyncIdentifier
2473 AssignCString(fTarget.dummyIdentifier2,NULL__null,remoteAnchorMaxLen); // former lastSuspendIdentifier, not needed, make empty
2474 // store remote datastore's display name (is empty if we haven't got one from the remote via devInf)
2475 if (getRemoteDatastore()) {
2476 AssignCString(fTarget.remoteDBdispName,getRemoteDatastore()->getDisplayName(),dispNameMaxLen);
2477 }
2478 #endif
2479 // check for other target record updates needed at end of session
2480 if (aSessionFinished && aSuccessful) {
2481 // - reset mode back to normal, that is after a forced reload of client OR server
2482 // we assume that two-way sync will be what we want next.
2483 if (fTarget.forceSlowSync) {
2484 fTarget.syncmode = smo_twoway;
2485 }
2486 fTarget.forceSlowSync=false;
2487 }
2488 // special operations needed depending on suspend state
2489 fTarget.resumeAlertCode=fResumeAlertCode;
2490 if (fResumeAlertCode==0) {
2491 fTarget.lastSuspendModCount = 0;
2492 }
2493 else {
2494 /// @note: lastSuspendModCount is the same target field that previously was called "lastModCount"
2495 fTarget.lastSuspendModCount = fPreviousSuspendModCount;
2496 if (!static_cast<TBinfileClientConfig *>(fSessionP->getSessionConfig())->fSeparateChangelogs) {
2497 // Combined changelogs: make sure that resume alert codes of all other profile's targets for this datastore are erased
2498 // (because in a single changelog there is only one set of markforresume flags and single pendingmap+pendingitem files)
2499 TBinfileDBSyncTarget otherTarget;
2500 memset(&otherTarget, 0, sizeof(otherTarget));
2501 for (sInt32 ti=0; ti<sInt32(targetsBinFileP->getNumRecords()); ti++) {
2502 if (ti!=fTargetIndex) {
2503 // get that target
2504 targetsBinFileP->readRecord(ti,&otherTarget);
2505 if (
2506 (otherTarget.localDBTypeID == fTarget.localDBTypeID) && // same datastoreID
2507 (strucmp(otherTarget.localDBPath,fTarget.localDBPath)==0) && // ..and name
2508 (otherTarget.resumeAlertCode!=0) // ..and has a saved suspend state
2509 ) {
2510 // same datastore, but different profile is also suspended -> new suspend cancels old one
2511 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,("SaveAdminData: cancelled resumeAlertCode in profile=%ld",(long)otherTarget.remotepartyID)){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
("SaveAdminData: cancelled resumeAlertCode in profile=%ld",(
long)otherTarget.remotepartyID); }
;
2512 otherTarget.resumeAlertCode=0;
2513 otherTarget.lastSuspendModCount=0;
2514 targetsBinFileP->updateRecord(ti,&otherTarget);
2515 }
2516 }
2517 }
2518 }
2519 }
2520 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI,("SaveAdminData: lastTwoWayModCount = %ld, lastSuspendModCount = %ld", (long)fPreviousToRemoteModCount, (long)fPreviousSuspendModCount)){ if (((0x00000040 +0x02000000) & getDbgMask()) == (0x00000040
+0x02000000)) getDbgLogger()->setNextMask(0x00000040 +0x02000000
).DebugPrintfLastMask ("SaveAdminData: lastTwoWayModCount = %ld, lastSuspendModCount = %ld"
, (long)fPreviousToRemoteModCount, (long)fPreviousSuspendModCount
); }
;
2521 // save pending maps (anyway, even if not suspended)
2522 openPendingMaps(); // make sure we have the pendingmap file open now
2523 fPendingMaps.truncate(0); // delete current contents
2524 TStringToStringMap::iterator spos;
2525 TPendingMapEntry pme;
2526 localid_t localid;
2527 // - pending maps now belong to us!
2528 // Note: they always do with separated changelogs
2529 fPendingMapHeader.remotepartyID = static_cast<TBinfileImplClient *>(fSessionP)->fRemotepartyID;
2530 fPendingMaps.setExtraHeaderDirty();
2531 // - now pending maps (unsent ones)
2532 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_DETAILS,("SaveAdminData: saving %ld entries from fPendingAddMaps to fPendingMaps binfile",(long)fPendingAddMaps.size())){ if (((0x00000040 +0x02000000 +0x40000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x40000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x40000000).DebugPrintfLastMask
("SaveAdminData: saving %ld entries from fPendingAddMaps to fPendingMaps binfile"
,(long)fPendingAddMaps.size()); }
;
2533 for (spos=fPendingAddMaps.begin();spos!=fPendingAddMaps.end();spos++) {
2534 string locID = (*spos).first;
2535 dsFinalizeLocalID(locID); // pending maps might have non-final ID, so give datastore implementation to return finalized version
2536 STR_TO_LOCALID(locID.c_str(),localid)(localid=(char *)locID.c_str()); ASSIGN_LOCALID_TO_FLD(pme.dbrecordid,localid)AssignCString(pme.dbrecordid,localid,maxidlen);
2537 AssignCString(pme.remoteID,(*spos).second.c_str(),BINFILE_MAXGUIDSIZE63+1);
2538 fPendingMaps.newRecord(&pme);
2539 }
2540 // - now pending maps (sent, but not seen status yet)
2541 DEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_DETAILS,("SaveAdminData: saving %ld entries from fUnconfirmedMaps to fPendingMaps binfile",(long)fUnconfirmedMaps.size())){ if (((0x00000040 +0x02000000 +0x40000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x40000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x40000000).DebugPrintfLastMask
("SaveAdminData: saving %ld entries from fUnconfirmedMaps to fPendingMaps binfile"
,(long)fUnconfirmedMaps.size()); }
;
2542 for (spos=fUnconfirmedMaps.begin();spos!=fUnconfirmedMaps.end();spos++) {
2543 STR_TO_LOCALID((*spos).first.c_str(),localid)(localid=(char *)(*spos).first.c_str()); ASSIGN_LOCALID_TO_FLD(pme.dbrecordid,localid)AssignCString(pme.dbrecordid,localid,maxidlen);
2544 AssignCString(pme.remoteID,(*spos).second.c_str(),BINFILE_MAXGUIDSIZE63+1);
2545 fPendingMaps.newRecord(&pme);
2546 }
2547 // - save them
2548 fPendingMaps.close();
2549 // Save last item info and possibly partial item data
2550 TPendingItemHeader pendingItemHeader;
2551 memset((void*)&pendingItemHeader,0,sizeof(pendingItemHeader)); // make nicely empty by default
2552 bool saveit=false;
2553 // - profile ID where this pending item belongs to
2554 pendingItemHeader.remotepartyID = static_cast<TBinfileImplClient *>(fSessionP)->fRemotepartyID;
2555 // determine if and what to save
2556 if (fPartialItemState==pi_state_none) {
2557 pendingItemHeader.piState = pi_state_none;
2558 pendingItemHeader.storedSize=0; // no data to store
2559 saveit=true;
2560 }
2561 else if (fPartialItemState==pi_state_save_incoming || fPartialItemState==pi_state_save_outgoing) {
2562 // - last item info
2563 pendingItemHeader.lastItemStatus = fLastItemStatus;
2564 AssignCString(pendingItemHeader.lastSourceURI,fLastSourceURI.c_str(),BINFILE_MAXGUIDSIZE63+1);
2565 AssignCString(pendingItemHeader.lastTargetURI,fLastTargetURI.c_str(),BINFILE_MAXGUIDSIZE63+1);
2566 // - partial item info
2567 pendingItemHeader.totalSize = fPITotalSize;
2568 pendingItemHeader.unconfirmedSize = fPIUnconfirmedSize;
2569 if (fPartialItemState==pi_state_save_incoming) {
2570 // store incoming
2571 pendingItemHeader.piState = pi_state_loaded_incoming;
2572 pendingItemHeader.storedSize=fPIStoredSize;
2573 }
2574 else if (fPartialItemState==pi_state_save_outgoing) {
2575 // store outgoing
2576 pendingItemHeader.piState = pi_state_loaded_outgoing;
2577 pendingItemHeader.storedSize=fPIStoredSize;
2578 }
2579 else
2580 pendingItemHeader.storedSize=0; // nothing to store
2581 saveit=true;
2582 }
2583 if (saveit) {
2584 TBinFile pendingItemFile;
2585 string fname = static_cast<TBinfileClientConfig *>(fSessionP->getSessionConfig())->relatedDBNameBase(getName(), fTarget.remotepartyID);
2586 fname += PENDINGITEM_DB_SUFFIX"_pitm_" "sysynclib_" ".bfi";
2587 pendingItemFile.setFileInfo(fname.c_str(),PENDINGITEM_DB_VERSION1,PENDINGITEM_DB_ID8,0);
2588 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_EXOTIC,({ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "SaveAdminData: creating pending item file: file name='%s', storing %ld bytes"
, fname.c_str(), (long)pendingItemHeader.storedSize ); }
2589 "SaveAdminData: creating pending item file: file name='%s', storing %ld bytes",{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "SaveAdminData: creating pending item file: file name='%s', storing %ld bytes"
, fname.c_str(), (long)pendingItemHeader.storedSize ); }
2590 fname.c_str(),{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "SaveAdminData: creating pending item file: file name='%s', storing %ld bytes"
, fname.c_str(), (long)pendingItemHeader.storedSize ); }
2591 (long)pendingItemHeader.storedSize{ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "SaveAdminData: creating pending item file: file name='%s', storing %ld bytes"
, fname.c_str(), (long)pendingItemHeader.storedSize ); }
2592 )){ if (((0x00000040 +0x02000000 +0x80000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x80000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x80000000).DebugPrintfLastMask
( "SaveAdminData: creating pending item file: file name='%s', storing %ld bytes"
, fname.c_str(), (long)pendingItemHeader.storedSize ); }
;
2593 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_DETAILS,({ if (((0x00000040 +0x02000000 +0x40000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x40000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x40000000).DebugPrintfLastMask
( "SaveAdminData: saved pending item: src='%s', targ='%s', laststatus=%hd, pistate=%d, total=%ld, unconfirmed=%ld, stored=%ld"
, pendingItemHeader.lastSourceURI, pendingItemHeader.lastTargetURI
, pendingItemHeader.lastItemStatus, pendingItemHeader.piState
, (long)pendingItemHeader.totalSize, (long)pendingItemHeader.
unconfirmedSize, (long)pendingItemHeader.storedSize ); }
2594 "SaveAdminData: saved pending item: src='%s', targ='%s', laststatus=%hd, pistate=%d, total=%ld, unconfirmed=%ld, stored=%ld",{ if (((0x00000040 +0x02000000 +0x40000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x40000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x40000000).DebugPrintfLastMask
( "SaveAdminData: saved pending item: src='%s', targ='%s', laststatus=%hd, pistate=%d, total=%ld, unconfirmed=%ld, stored=%ld"
, pendingItemHeader.lastSourceURI, pendingItemHeader.lastTargetURI
, pendingItemHeader.lastItemStatus, pendingItemHeader.piState
, (long)pendingItemHeader.totalSize, (long)pendingItemHeader.
unconfirmedSize, (long)pendingItemHeader.storedSize ); }
2595 pendingItemHeader.lastSourceURI,{ if (((0x00000040 +0x02000000 +0x40000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x40000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x40000000).DebugPrintfLastMask
( "SaveAdminData: saved pending item: src='%s', targ='%s', laststatus=%hd, pistate=%d, total=%ld, unconfirmed=%ld, stored=%ld"
, pendingItemHeader.lastSourceURI, pendingItemHeader.lastTargetURI
, pendingItemHeader.lastItemStatus, pendingItemHeader.piState
, (long)pendingItemHeader.totalSize, (long)pendingItemHeader.
unconfirmedSize, (long)pendingItemHeader.storedSize ); }
2596 pendingItemHeader.lastTargetURI,{ if (((0x00000040 +0x02000000 +0x40000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x40000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x40000000).DebugPrintfLastMask
( "SaveAdminData: saved pending item: src='%s', targ='%s', laststatus=%hd, pistate=%d, total=%ld, unconfirmed=%ld, stored=%ld"
, pendingItemHeader.lastSourceURI, pendingItemHeader.lastTargetURI
, pendingItemHeader.lastItemStatus, pendingItemHeader.piState
, (long)pendingItemHeader.totalSize, (long)pendingItemHeader.
unconfirmedSize, (long)pendingItemHeader.storedSize ); }
2597 pendingItemHeader.lastItemStatus,{ if (((0x00000040 +0x02000000 +0x40000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x40000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x40000000).DebugPrintfLastMask
( "SaveAdminData: saved pending item: src='%s', targ='%s', laststatus=%hd, pistate=%d, total=%ld, unconfirmed=%ld, stored=%ld"
, pendingItemHeader.lastSourceURI, pendingItemHeader.lastTargetURI
, pendingItemHeader.lastItemStatus, pendingItemHeader.piState
, (long)pendingItemHeader.totalSize, (long)pendingItemHeader.
unconfirmedSize, (long)pendingItemHeader.storedSize ); }
2598 pendingItemHeader.piState,{ if (((0x00000040 +0x02000000 +0x40000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x40000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x40000000).DebugPrintfLastMask
( "SaveAdminData: saved pending item: src='%s', targ='%s', laststatus=%hd, pistate=%d, total=%ld, unconfirmed=%ld, stored=%ld"
, pendingItemHeader.lastSourceURI, pendingItemHeader.lastTargetURI
, pendingItemHeader.lastItemStatus, pendingItemHeader.piState
, (long)pendingItemHeader.totalSize, (long)pendingItemHeader.
unconfirmedSize, (long)pendingItemHeader.storedSize ); }
2599 (long)pendingItemHeader.totalSize,{ if (((0x00000040 +0x02000000 +0x40000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x40000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x40000000).DebugPrintfLastMask
( "SaveAdminData: saved pending item: src='%s', targ='%s', laststatus=%hd, pistate=%d, total=%ld, unconfirmed=%ld, stored=%ld"
, pendingItemHeader.lastSourceURI, pendingItemHeader.lastTargetURI
, pendingItemHeader.lastItemStatus, pendingItemHeader.piState
, (long)pendingItemHeader.totalSize, (long)pendingItemHeader.
unconfirmedSize, (long)pendingItemHeader.storedSize ); }
2600 (long)pendingItemHeader.unconfirmedSize,{ if (((0x00000040 +0x02000000 +0x40000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x40000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x40000000).DebugPrintfLastMask
( "SaveAdminData: saved pending item: src='%s', targ='%s', laststatus=%hd, pistate=%d, total=%ld, unconfirmed=%ld, stored=%ld"
, pendingItemHeader.lastSourceURI, pendingItemHeader.lastTargetURI
, pendingItemHeader.lastItemStatus, pendingItemHeader.piState
, (long)pendingItemHeader.totalSize, (long)pendingItemHeader.
unconfirmedSize, (long)pendingItemHeader.storedSize ); }
2601 (long)pendingItemHeader.storedSize{ if (((0x00000040 +0x02000000 +0x40000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x40000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x40000000).DebugPrintfLastMask
( "SaveAdminData: saved pending item: src='%s', targ='%s', laststatus=%hd, pistate=%d, total=%ld, unconfirmed=%ld, stored=%ld"
, pendingItemHeader.lastSourceURI, pendingItemHeader.lastTargetURI
, pendingItemHeader.lastItemStatus, pendingItemHeader.piState
, (long)pendingItemHeader.totalSize, (long)pendingItemHeader.
unconfirmedSize, (long)pendingItemHeader.storedSize ); }
2602 )){ if (((0x00000040 +0x02000000 +0x40000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x40000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x40000000).DebugPrintfLastMask
( "SaveAdminData: saved pending item: src='%s', targ='%s', laststatus=%hd, pistate=%d, total=%ld, unconfirmed=%ld, stored=%ld"
, pendingItemHeader.lastSourceURI, pendingItemHeader.lastTargetURI
, pendingItemHeader.lastItemStatus, pendingItemHeader.piState
, (long)pendingItemHeader.totalSize, (long)pendingItemHeader.
unconfirmedSize, (long)pendingItemHeader.storedSize ); }
;
2603 bferr bfe=pendingItemFile.create(
2604 pendingItemHeader.storedSize, // record size = size of data chunk to be buffered
2605 sizeof(TPendingItemHeader), // extra header size
2606 &pendingItemHeader, // extra header data
2607 true // overwrite existing
2608 );
2609 if (bfe==BFE_OK0) {
2610 // created successfully, store data if any
2611 if (pendingItemHeader.storedSize && fPIStoredDataP) {
2612 // we have data to store
2613 uInt32 newIndex;
2614 bfe=pendingItemFile.newRecord(newIndex,fPIStoredDataP);
2615 }
2616 // close file
2617 pendingItemFile.close();
2618 }
2619 if (bfe!=BFE_OK0) {
2620 PDEBUGPRINTFX(DBG_ERROR,("Error writing pending item file, bferr=%hd",bfe)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("Error writing pending item file, bferr=%hd"
,bfe); }
;
2621 }
2622 }
2623 PDEBUGPRINTFX(DBG_ADMIN+DBG_DBAPI+DBG_DETAILS,("SaveAdminData: fTargetIndex %d resumeAlertCode = %hd, lastSuspendModCount = %ld",fTargetIndex,fResumeAlertCode,(long)fTarget.lastSuspendModCount)){ if (((0x00000040 +0x02000000 +0x40000000) & getDbgMask(
)) == (0x00000040 +0x02000000 +0x40000000)) getDbgLogger()->
setNextMask(0x00000040 +0x02000000 +0x40000000).DebugPrintfLastMask
("SaveAdminData: fTargetIndex %d resumeAlertCode = %hd, lastSuspendModCount = %ld"
,fTargetIndex,fResumeAlertCode,(long)fTarget.lastSuspendModCount
); }
;
2624 // update the target record
2625 if (fTargetIndex>=0) {
2626 targetsBinFileP->updateRecord(fTargetIndex,&fTarget);
2627 fTargetIndex=-1; // invalid now
2628 }
2629 PDEBUGENDBLOCK("SaveAdminData")getDbgLogger()->DebugCloseBlock( "SaveAdminData");
2630 // ok
2631 return LOCERR_OK;
2632} // TBinfileImplDS::SaveAdminData
2633
2634
2635/* end of TBinfileImplDS implementation */
2636
2637} // namespace sysync
2638// eof