if SAP Mobile Server is restored to a point in time of previous application synchronization, the client synchronization gets Sybase.Persistence.SynchronizeException with error code SQLE_UPLOAD_FAILED_AT_SERVER. This error code indicates the need to recover the client database.
Time1: application registered and has not synchronized. Time2: application synchronized for the first time. Time3: application synchronized for the second time. Time4: application synchronized for the last time.If SAP Mobile Server is restored to time1 or time4, the client can synchronize successfully. If SAP Mobile Server is restored to time2 or time3, client synchronization fails with the exception. There are three ways to recover the client database and successfully synchronize. Before synchronization recovery, the application needs to complete application registration recovery if nessasary. Once the client application starts (startup), the application should check if the last recovery failed by checking the saved flag. If the last recovery failed, the application needs to resume the recovery first. The user can mark the recovery state any number of ways, for example, the application can save the recovery state to a file. As illustrated in example two below, copy the old client database and use it as a recovery state flag.
@try { [end2end_rdbEnd2end_rdbDB synchronize]; } @catch (SUPSynchronizeException *ex) { if (ex.errorCode == SYNC_UPLOAD_FAILED_AT_SERVER) { [self recoverClientDatabase]; } else { @throw ex; } } - (void) recoverClientDatabase { [self setRecoveringInPlaceFlag]; // Such as saving a flag in application sandbox. [end2end_rdbEnd2end_rdbDB closeConnection]; [end2end_rdbEnd2end_rdbDB deleteDatabase]; [self clearRecoveringInPlaceFlag]; }
if([self isRecoverFailed]) { [self recoverClientDatabase]; } else { @try { [end2end_rdbEnd2end_rdbDB synchronize]; } @catch (SUPPersistenceException *ex) { if (ex.errorCode == SYNC_UPLOAD_FAILED_AT_SERVER) { [self recoverClientDatabase]; } else { @throw ex; } } } - (BOOL)isRecoverFailed { NSString* dbFile = [end2end_rdbEnd2end_rdbDB getDbPath]; NSString* recoverDbFile = [NSString stringWithFormat:@"%@.recover.udb", dbFile]; NSFileManager *fm = [NSFileManager defaultManager]; BOOL ok = YES; if ([fm isReadableFileAtPath:recoverDbFile]) { // Recover DB exists, indicating the last recover was not finished // need to copy back the DB file and do recovery. if ([fm isReadableFileAtPath:dbFile]) { if (![fm removeItemAtPath:dbFile error:nil]) { ok = NO; } } if (ok && [fm copyItemAtPath:recoverDbFile toPath:dbFile error:nil]) { return YES; } else { @throw [NSException exceptionWithName:@"NSException" reason:@"Failed to copy the recover database back." userInfo:nil]; } } return NO; } - (void) recoverClientDatabase { NSString* dbFile = [end2end_rdbEnd2end_rdbDB getDbPath]; NSString* recoverDbFile = [NSString stringWithFormat:@"%@.recover.udb", dbFile]; NSFileManager *fm = [NSFileManager defaultManager]; if (![fm copyItemAtPath:dbFile toPath:recoverDbFile error:nil]) { @throw [NSException exceptionWithName:@"NSException" reason:@"Failed to copy the recover database." userInfo:nil]; } //retrieve all the subscriptions from client database SUPObjectList *customerWithParamSubscriptions = [end2end_rdbCustomerWithParam getSubscriptions]; SUPObjectList *sisSubscriptions = [[end2end_rdbSISSubscription getInstance] findAll]; NSMutableArray *syncedPublications = [NSMutableArray arrayWithCapacity:2]; // check all the synchronization group, if is synchronized, add to new sync group to synchronize if ([end2end_rdbEnd2end_rdbDB isSynchronized:@"synchronizationGroup"]) { [syncedPublications addObject:@"synchronizationGroup"]; } //retrieve all local MBO from client database SUPObjectList* localBookList = [end2end_rdbLocalBook findAll]; // Done with saving information, close connection and delete the database [end2end_rdbEnd2end_rdbDB closeConnection]; [end2end_rdbEnd2end_rdbDB deleteDatabase]; // new subscription [end2end_rdbEnd2end_rdbDB subscribe]; // merge old local BO data to new database for (id lbo in localBookList) { end2end_rdbLocalBook *savedLocalBook = (end2end_rdbLocalBook*)lbo; end2end_rdbLocalBook *localBook = [end2end_rdbLocalBook getInstance]; [localBook copyAll:savedLocalBook]; [localBook create]; } // add all the subscriptions from old database to new database for (id sub in customerWithParamSubscriptions) { end2end_rdbCustomerWithParamSubscription *csub = (end2end_rdbCustomerWithParamSubscription*)sub; [end2end_rdbCustomerWithParam addSubscription:csub]; } for (id sub in sisSubscriptions) { end2end_rdbSISSubscription* ssub = (end2end_rdbSISSubscription*)sub; id<SUPSynchronizationGroup> sg = [end2end_rdbEnd2end_rdbDB getSynchronizationGroup:ssub.syncGroup]; sg.enableSIS = ssub.enable; [sg save]; } // synchronize for the synchronized publications NSString* syncGroups = [syncedPublications componentsJoinedByString:@","]; [end2end_rdbEnd2end_rdbDB synchronize:syncGroups]; // finally delete the backup recover database file if (![fm removeItemAtPath:recoverDbFile error:nil]) { @throw [NSException exceptionWithName:@"NSException" reason:@"Failed to remove the recover database." userInfo:nil]; } }
I. 2013-04-14 14:13:39. <3> The sync sequence ID in the consolidated database: 95bd47691098419cbf8539e8151bcf00; the remote previous sequence ID: 95bd47691098419cbf8539e8151bcf97, and the current sequence ID: 401be536e6e7417fb01b196276ec11c2E. 2013-04-14 14:13:39. <3> [-10400] Invalid sync sequence ID for remote ID 'ed2ae448-a597-4f17-ad72-c6c61a6075a5'