File: | libsynthesis/src/sysync/binfileimplds.cpp |
Warning: | line 802, column 7 Called C++ object pointer is null |
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 |