1
0
mirror of https://github.com/etesync/android synced 2025-02-02 10:51:10 +00:00

SyncManager: Use the last journal id as the ctag, instead of storing it.

We were storing the ctag separately although the data was already
present in the journal. The last entry's ID is always the CTAG.
This could cause issues if sync is aborted exactly at the right time.
I managed to trigger this issue on rare cases.
This commit is contained in:
Tom Hacohen 2017-04-06 23:02:01 +01:00
parent 338dd5e075
commit 4e0cd7f554
6 changed files with 30 additions and 103 deletions

View File

@ -82,6 +82,15 @@ public class JournalModel {
}
return journalEntity;
}
public String getLastUid(EntityDataStore<Persistable> data) {
EntryEntity last = data.select(EntryEntity.class).where(EntryEntity.JOURNAL.eq(this)).orderBy(EntryEntity.ID.desc()).limit(1).get().firstOrNull();
if (last != null) {
return last.getUid();
}
return null;
}
}
@Entity

View File

@ -304,24 +304,6 @@ public class LocalAddressBook extends AndroidAddressBook implements LocalCollect
}
}
@Override
public String getCTag() throws ContactsStorageException {
synchronized (syncState) {
readSyncState();
return syncState.getString(SYNC_STATE_CTAG);
}
}
@Override
public void setCTag(String cTag) throws ContactsStorageException {
synchronized (syncState) {
readSyncState();
syncState.putString(SYNC_STATE_CTAG, cTag);
writeSyncState();
}
}
// HELPERS
public static void onRenameAccount(@NonNull ContentResolver resolver, @NonNull String oldName, @NonNull String newName) throws RemoteException {
@ -334,9 +316,9 @@ public class LocalAddressBook extends AndroidAddressBook implements LocalCollect
}
/** Fix all of the etags of all of the non-dirty contacts to be non-null.
* Currently set to the ctag. */
* Currently set to all ones. */
public void fixEtags() throws ContactsStorageException {
String newEtag = getCTag();
String newEtag = "1111111111111111111111111111111111111111111111111111111111111111";
String where = ContactsContract.RawContacts.DIRTY + "=0 AND " + AndroidContact.COLUMN_ETAG + " IS NULL";
ContentValues values = new ContentValues(1);

View File

@ -160,31 +160,6 @@ public class LocalCalendar extends AndroidCalendar implements LocalCollection {
return dirty.toArray(new LocalResource[dirty.size()]);
}
@Override
@SuppressWarnings("Recycle")
public String getCTag() throws CalendarStorageException {
try {
@Cleanup Cursor cursor = provider.query(calendarSyncURI(), new String[] { COLUMN_CTAG }, null, null, null);
if (cursor != null && cursor.moveToNext())
return cursor.getString(0);
} catch (RemoteException e) {
throw new CalendarStorageException("Couldn't read local (last known) CTag", e);
}
return null;
}
@Override
public void setCTag(String cTag) throws CalendarStorageException, ContactsStorageException {
try {
ContentValues values = new ContentValues(1);
values.put(COLUMN_CTAG, cTag);
provider.update(calendarSyncURI(), values, null, null);
} catch (RemoteException e) {
throw new CalendarStorageException("Couldn't write local (last known) CTag", e);
}
}
@SuppressWarnings("Recycle")
public void processDirtyExceptions() throws CalendarStorageException {
// process deleted exceptions
@ -286,9 +261,9 @@ public class LocalCalendar extends AndroidCalendar implements LocalCollection {
}
/** Fix all of the etags of all of the non-dirty events to be non-null.
* Currently set to the ctag. */
* Currently set to all ones.. */
public void fixEtags() throws CalendarStorageException {
String newEtag = getCTag();
String newEtag = "1111111111111111111111111111111111111111111111111111111111111111";
String where = Events.CALENDAR_ID + "=? AND " + Events.DIRTY + "=0 AND " + LocalEvent.COLUMN_ETAG + " IS NULL";
String whereArgs[] = {String.valueOf(id)};

View File

@ -22,8 +22,5 @@ public interface LocalCollection {
LocalResource getByUid(String uid) throws CalendarStorageException, ContactsStorageException;
String getCTag() throws CalendarStorageException, ContactsStorageException;
void setCTag(String cTag) throws CalendarStorageException, ContactsStorageException;
long count() throws CalendarStorageException, ContactsStorageException;
}

View File

@ -126,31 +126,6 @@ public class LocalTaskList extends AndroidTaskList implements LocalCollection {
}
}
@Override
@SuppressWarnings("Recycle")
public String getCTag() throws CalendarStorageException {
try {
@Cleanup Cursor cursor = provider.client.query(taskListSyncUri(), new String[] { COLUMN_CTAG }, null, null, null);
if (cursor != null && cursor.moveToNext())
return cursor.getString(0);
} catch (RemoteException e) {
throw new CalendarStorageException("Couldn't read local (last known) CTag", e);
}
return null;
}
@Override
public void setCTag(String cTag) throws CalendarStorageException {
try {
ContentValues values = new ContentValues(1);
values.put(COLUMN_CTAG, cTag);
provider.client.update(taskListSyncUri(), values, null, null);
} catch (RemoteException e) {
throw new CalendarStorageException("Couldn't write local (last known) CTag", e);
}
}
// helpers
public static boolean tasksProviderAvailable(@NonNull Context context) {

View File

@ -181,6 +181,8 @@ abstract public class SyncManager {
syncPhase = R.string.sync_phase_post_processing;
App.log.info("Sync phase: " + context.getString(syncPhase));
postProcess();
App.log.info("Finished sync with CTag=" + remoteCTag);
} catch (IOException e) {
App.log.log(Level.WARNING, "I/O exception during sync, trying again later", e);
syncResult.stats.numIoExceptions++;
@ -295,24 +297,20 @@ abstract public class SyncManager {
String strTotal = String.valueOf(remoteEntries.size());
int i = 0;
try {
for (JournalEntryManager.Entry entry : remoteEntries) {
if (Thread.interrupted()) {
throw new InterruptedException();
}
i++;
App.log.info("Processing (" + String.valueOf(i) + "/" + strTotal + ") " + entry.toString());
SyncEntry cEntry = SyncEntry.fromJournalEntry(crypto, entry);
App.log.info("Processing resource for journal entry");
processSyncEntry(cEntry);
persistSyncEntry(entry.getUid(), cEntry);
remoteCTag = entry.getUid();
for (JournalEntryManager.Entry entry : remoteEntries) {
if (Thread.interrupted()) {
throw new InterruptedException();
}
} finally {
saveSyncTag();
i++;
App.log.info("Processing (" + String.valueOf(i) + "/" + strTotal + ") " + entry.toString());
SyncEntry cEntry = SyncEntry.fromJournalEntry(crypto, entry);
App.log.info("Processing resource for journal entry");
processSyncEntry(cEntry);
persistSyncEntry(entry.getUid(), cEntry);
remoteCTag = entry.getUid();
}
}
@ -352,8 +350,6 @@ abstract public class SyncManager {
localDirty = null;
localDeleted = null;
saveSyncTag();
}
}
@ -390,12 +386,12 @@ abstract public class SyncManager {
/**
*/
protected void prepareLocal() throws CalendarStorageException, ContactsStorageException, FileNotFoundException {
remoteCTag = getJournalEntity().getLastUid(data);
localDeleted = processLocallyDeleted();
localDirty = localCollection.getDirty();
// This is done after fetching the local dirty so all the ones we are using will be prepared
prepareDirty();
remoteCTag = localCollection.getCTag();
}
@ -438,11 +434,4 @@ abstract public class SyncManager {
*/
protected void postProcess() throws CalendarStorageException, ContactsStorageException {
}
private void saveSyncTag() throws CalendarStorageException, ContactsStorageException {
App.log.info("Saving CTag=" + remoteCTag);
localCollection.setCTag(remoteCTag);
}
}