File: | libsynthesis/src/sysync/binfileimplds.cpp |
Warning: | line 1643, column 24 Access to field 'flags' results in a dereference of a null pointer (loaded from variable 'chglogP') |
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 | ||||
29 | namespace sysync { | |||
30 | ||||
31 | ||||
32 | #ifdef SCRIPT_SUPPORT1 | |||
33 | ||||
34 | // Script Functions | |||
35 | // ================ | |||
36 | ||||
37 | ||||
38 | class TBFDSfuncs { | |||
39 | public: | |||
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 | ||||
125 | const uInt8 param_OneStr[] = { VAL(fty_string)( (uInt8)fty_string) }; | |||
126 | ||||
127 | const 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 | |||
134 | static 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 | |||
144 | const 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 | ||||
157 | TBinfileDSConfig::TBinfileDSConfig(const char* aName, TConfigElement *aParentElement) : | |||
158 | TLocalDSConfig(aName,aParentElement) | |||
159 | { | |||
160 | // nop so far | |||
161 | clear(); | |||
162 | } // TBinfileDSConfig::TBinfileDSConfig | |||
163 | ||||
164 | ||||
165 | TBinfileDSConfig::~TBinfileDSConfig() | |||
166 | { | |||
167 | // nop so far | |||
168 | } // TBinfileDSConfig::~TBinfileDSConfig | |||
169 | ||||
170 | ||||
171 | // init defaults | |||
172 | void 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 | |||
198 | bool 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 | |||
225 | void 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) | |||
242 | bool 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 | |||
266 | void 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 | ||||
323 | TBinfileImplDS::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 | ||||
348 | void 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 | ||||
361 | void 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 | ||||
374 | TBinfileImplDS::~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) | |||
383 | void 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 | |||
395 | localstatus 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 | |||
402 | localstatus 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) | |||
416 | bool 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 | |||
456 | localstatus 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) | |||
492 | void 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 | |||
515 | static 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 | |||
576 | bool 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 | |||
644 | bool 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. | |||
673 | lineartime_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!) | |||
686 | lineartime_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) | |||
700 | localstatus 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); }; | |||
1054 | done: | |||
1055 | sta = err==BFE_OK0 ? LOCERR_OK : (err==BFE_MEMORY9 ? LOCERR_OUTOFMEM : LOCERR_UNDEFINED); | |||
1056 | error: | |||
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 | |||
1071 | localstatus 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. | |||
1120 | sInt32 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 | ||||
1133 | bool 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 | |||
1187 | localstatus 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 | ||||
1358 | localstatus 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 | |||
1374 | bool 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" | |||
1393 | void 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). | |||
1479 | void 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). | |||
1514 | void 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 | |||
1549 | localstatus 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 | |||
| ||||
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) { | |||
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; | |||
1577 | // make sure we have the changelog in memory | |||
1578 | loadChangeLog(); | |||
1579 | do { | |||
1580 | if (fLogEntryIndex<fLoadedChangeLogEntries) { | |||
1581 | // there is a log entry, get it | |||
1582 | chglogP = &fLoadedChangeLog[fLogEntryIndex]; | |||
1583 | // advance to next | |||
1584 | fLogEntryIndex++; | |||
1585 | // if resuming, check if we must include this item at all | |||
1586 | if (isResuming()) { | |||
1587 | // we are resuming, only report those that have the mark-for-resume flag set | |||
1588 | if (!(chglogP->flags & chgl_markedforresume)) { | |||
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; | |||
1786 | error: | |||
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 | |||
1795 | localstatus 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 | |||
1808 | void 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 | |||
1819 | void 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 | |||
1850 | localstatus 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 | |||
1930 | bool 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) | |||
1964 | bool 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} | |||
2240 | error: | |||
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()); | |||
2247 | done: | |||
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 | |||
2256 | void 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) | |||
2270 | localstatus 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 | |||
2284 | void 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. | |||
2335 | localstatus 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 | |||
2394 | bool 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() | |||
2409 | localstatus 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 |