Automated import from //branches/master/...@141380,141380
This commit is contained in:
committed by
The Android Open Source Project
parent
ef0996ffa3
commit
22f711423e
@@ -164,304 +164,301 @@ public abstract class AbstractTableMerger
|
||||
mDb.update(mDeletedTable, mSyncMarkValues, null, null);
|
||||
}
|
||||
|
||||
// load the local database entries, so we can merge them with the server
|
||||
final String[] accountSelectionArgs = new String[]{account};
|
||||
Cursor localCursor = mDb.query(mTable, syncDirtyProjection,
|
||||
SELECT_MARKED, accountSelectionArgs, null, null,
|
||||
mTable + "." + _SYNC_ID);
|
||||
Cursor deletedCursor;
|
||||
if (mDeletedTable != null) {
|
||||
deletedCursor = mDb.query(mDeletedTable, syncIdAndVersionProjection,
|
||||
Cursor localCursor = null;
|
||||
Cursor deletedCursor = null;
|
||||
Cursor diffsCursor = null;
|
||||
try {
|
||||
// load the local database entries, so we can merge them with the server
|
||||
final String[] accountSelectionArgs = new String[]{account};
|
||||
localCursor = mDb.query(mTable, syncDirtyProjection,
|
||||
SELECT_MARKED, accountSelectionArgs, null, null,
|
||||
mDeletedTable + "." + _SYNC_ID);
|
||||
} else {
|
||||
deletedCursor =
|
||||
mDb.rawQuery("select 'a' as _sync_id, 'b' as _sync_version limit 0", null);
|
||||
}
|
||||
|
||||
// Apply updates and insertions from the server
|
||||
Cursor diffsCursor = serverDiffs.query(mTableURL,
|
||||
null, null, null, mTable + "." + _SYNC_ID);
|
||||
int deletedSyncIDColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_ID);
|
||||
int deletedSyncVersionColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_VERSION);
|
||||
int serverSyncIDColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_ID);
|
||||
int serverSyncVersionColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_VERSION);
|
||||
int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID);
|
||||
|
||||
String lastSyncId = null;
|
||||
int diffsCount = 0;
|
||||
int localCount = 0;
|
||||
localCursor.moveToFirst();
|
||||
deletedCursor.moveToFirst();
|
||||
while (diffsCursor.moveToNext()) {
|
||||
if (mIsMergeCancelled) {
|
||||
localCursor.close();
|
||||
deletedCursor.close();
|
||||
diffsCursor.close();
|
||||
return;
|
||||
}
|
||||
mDb.yieldIfContended();
|
||||
String serverSyncId = diffsCursor.getString(serverSyncIDColumn);
|
||||
String serverSyncVersion = diffsCursor.getString(serverSyncVersionColumn);
|
||||
long localRowId = 0;
|
||||
String localSyncVersion = null;
|
||||
|
||||
diffsCount++;
|
||||
context.setStatusText("Processing " + diffsCount + "/"
|
||||
+ diffsCursor.getCount());
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "processing server entry " +
|
||||
diffsCount + ", " + serverSyncId);
|
||||
|
||||
if (TRACE) {
|
||||
if (diffsCount == 10) {
|
||||
Debug.startMethodTracing("atmtrace");
|
||||
}
|
||||
if (diffsCount == 20) {
|
||||
Debug.stopMethodTracing();
|
||||
}
|
||||
mTable + "." + _SYNC_ID);
|
||||
if (mDeletedTable != null) {
|
||||
deletedCursor = mDb.query(mDeletedTable, syncIdAndVersionProjection,
|
||||
SELECT_MARKED, accountSelectionArgs, null, null,
|
||||
mDeletedTable + "." + _SYNC_ID);
|
||||
} else {
|
||||
deletedCursor =
|
||||
mDb.rawQuery("select 'a' as _sync_id, 'b' as _sync_version limit 0", null);
|
||||
}
|
||||
|
||||
boolean conflict = false;
|
||||
boolean update = false;
|
||||
boolean insert = false;
|
||||
// Apply updates and insertions from the server
|
||||
diffsCursor = serverDiffs.query(mTableURL,
|
||||
null, null, null, mTable + "." + _SYNC_ID);
|
||||
int deletedSyncIDColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_ID);
|
||||
int deletedSyncVersionColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_VERSION);
|
||||
int serverSyncIDColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_ID);
|
||||
int serverSyncVersionColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_VERSION);
|
||||
int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID);
|
||||
|
||||
String lastSyncId = null;
|
||||
int diffsCount = 0;
|
||||
int localCount = 0;
|
||||
localCursor.moveToFirst();
|
||||
deletedCursor.moveToFirst();
|
||||
while (diffsCursor.moveToNext()) {
|
||||
if (mIsMergeCancelled) {
|
||||
return;
|
||||
}
|
||||
mDb.yieldIfContended();
|
||||
String serverSyncId = diffsCursor.getString(serverSyncIDColumn);
|
||||
String serverSyncVersion = diffsCursor.getString(serverSyncVersionColumn);
|
||||
long localRowId = 0;
|
||||
String localSyncVersion = null;
|
||||
|
||||
diffsCount++;
|
||||
context.setStatusText("Processing " + diffsCount + "/"
|
||||
+ diffsCursor.getCount());
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "processing server entry " +
|
||||
diffsCount + ", " + serverSyncId);
|
||||
|
||||
if (TRACE) {
|
||||
if (diffsCount == 10) {
|
||||
Debug.startMethodTracing("atmtrace");
|
||||
}
|
||||
if (diffsCount == 20) {
|
||||
Debug.stopMethodTracing();
|
||||
}
|
||||
}
|
||||
|
||||
boolean conflict = false;
|
||||
boolean update = false;
|
||||
boolean insert = false;
|
||||
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "found event with serverSyncID " + serverSyncId);
|
||||
}
|
||||
if (TextUtils.isEmpty(serverSyncId)) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.e(TAG, "server entry doesn't have a serverSyncID");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// It is possible that the sync adapter wrote the same record multiple times,
|
||||
// e.g. if the same record came via multiple feeds. If this happens just ignore
|
||||
// the duplicate records.
|
||||
if (serverSyncId.equals(lastSyncId)) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "skipping record with duplicate remote server id " + lastSyncId);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
lastSyncId = serverSyncId;
|
||||
|
||||
String localSyncID = null;
|
||||
boolean localSyncDirty = false;
|
||||
|
||||
while (!localCursor.isAfterLast()) {
|
||||
if (mIsMergeCancelled) {
|
||||
return;
|
||||
}
|
||||
localCount++;
|
||||
localSyncID = localCursor.getString(2);
|
||||
|
||||
// If the local record doesn't have a _sync_id then
|
||||
// it is new. Ignore it for now, we will send an insert
|
||||
// the the server later.
|
||||
if (TextUtils.isEmpty(localSyncID)) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "local record " +
|
||||
localCursor.getLong(1) +
|
||||
" has no _sync_id, ignoring");
|
||||
}
|
||||
localCursor.moveToNext();
|
||||
localSyncID = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
int comp = serverSyncId.compareTo(localSyncID);
|
||||
|
||||
// the local DB has a record that the server doesn't have
|
||||
if (comp > 0) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "local record " +
|
||||
localCursor.getLong(1) +
|
||||
" has _sync_id " + localSyncID +
|
||||
" that is < server _sync_id " + serverSyncId);
|
||||
}
|
||||
if (diffsArePartial) {
|
||||
localCursor.moveToNext();
|
||||
} else {
|
||||
deleteRow(localCursor);
|
||||
if (mDeletedTable != null) {
|
||||
mDb.delete(mDeletedTable, _SYNC_ID +"=?", new String[] {localSyncID});
|
||||
}
|
||||
syncResult.stats.numDeletes++;
|
||||
mDb.yieldIfContended();
|
||||
}
|
||||
localSyncID = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
// the server has a record that the local DB doesn't have
|
||||
if (comp < 0) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "local record " +
|
||||
localCursor.getLong(1) +
|
||||
" has _sync_id " + localSyncID +
|
||||
" that is > server _sync_id " + serverSyncId);
|
||||
}
|
||||
localSyncID = null;
|
||||
}
|
||||
|
||||
// the server and the local DB both have this record
|
||||
if (comp == 0) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "local record " +
|
||||
localCursor.getLong(1) +
|
||||
" has _sync_id " + localSyncID +
|
||||
" that matches the server _sync_id");
|
||||
}
|
||||
localSyncDirty = localCursor.getInt(0) != 0;
|
||||
localRowId = localCursor.getLong(1);
|
||||
localSyncVersion = localCursor.getString(3);
|
||||
localCursor.moveToNext();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// If this record is in the deleted table then update the server version
|
||||
// in the deleted table, if necessary, and then ignore it here.
|
||||
// We will send a deletion indication to the server down a
|
||||
// little further.
|
||||
if (findInCursor(deletedCursor, deletedSyncIDColumn, serverSyncId)) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "remote record " + serverSyncId + " is in the deleted table");
|
||||
}
|
||||
final String deletedSyncVersion = deletedCursor.getString(deletedSyncVersionColumn);
|
||||
if (!TextUtils.equals(deletedSyncVersion, serverSyncVersion)) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "setting version of deleted record " + serverSyncId + " to "
|
||||
+ serverSyncVersion);
|
||||
}
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(_SYNC_VERSION, serverSyncVersion);
|
||||
mDb.update(mDeletedTable, values, "_sync_id=?", new String[]{serverSyncId});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the _sync_local_id is present in the diffsCursor
|
||||
// then this record corresponds to a local record that was just
|
||||
// inserted into the server and the _sync_local_id is the row id
|
||||
// of the local record. Set these fields so that the next check
|
||||
// treats this record as an update, which will allow the
|
||||
// merger to update the record with the server's sync id
|
||||
if (!diffsCursor.isNull(serverSyncLocalIdColumn)) {
|
||||
localRowId = diffsCursor.getLong(serverSyncLocalIdColumn);
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "the remote record with sync id " + serverSyncId
|
||||
+ " has a local sync id, " + localRowId);
|
||||
}
|
||||
localSyncID = serverSyncId;
|
||||
localSyncDirty = false;
|
||||
localSyncVersion = null;
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(localSyncID)) {
|
||||
// An existing server item has changed
|
||||
boolean recordChanged = (localSyncVersion == null) ||
|
||||
!serverSyncVersion.equals(localSyncVersion);
|
||||
if (recordChanged) {
|
||||
if (localSyncDirty) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "remote record " + serverSyncId
|
||||
+ " conflicts with local _sync_id " + localSyncID
|
||||
+ ", local _id " + localRowId);
|
||||
}
|
||||
conflict = true;
|
||||
} else {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG,
|
||||
"remote record " +
|
||||
serverSyncId +
|
||||
" updates local _sync_id " +
|
||||
localSyncID + ", local _id " +
|
||||
localRowId);
|
||||
}
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// the local db doesn't know about this record so add it
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "remote record " + serverSyncId + " is new, inserting");
|
||||
}
|
||||
insert = true;
|
||||
}
|
||||
|
||||
if (update) {
|
||||
updateRow(localRowId, serverDiffs, diffsCursor);
|
||||
syncResult.stats.numUpdates++;
|
||||
} else if (conflict) {
|
||||
resolveRow(localRowId, serverSyncId, serverDiffs, diffsCursor);
|
||||
syncResult.stats.numUpdates++;
|
||||
} else if (insert) {
|
||||
insertRow(serverDiffs, diffsCursor);
|
||||
syncResult.stats.numInserts++;
|
||||
}
|
||||
}
|
||||
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "found event with serverSyncID " + serverSyncId);
|
||||
}
|
||||
if (TextUtils.isEmpty(serverSyncId)) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.e(TAG, "server entry doesn't have a serverSyncID");
|
||||
}
|
||||
continue;
|
||||
Log.v(TAG, "processed " + diffsCount + " server entries");
|
||||
}
|
||||
|
||||
// It is possible that the sync adapter wrote the same record multiple times,
|
||||
// e.g. if the same record came via multiple feeds. If this happens just ignore
|
||||
// the duplicate records.
|
||||
if (serverSyncId.equals(lastSyncId)) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "skipping record with duplicate remote server id " + lastSyncId);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
lastSyncId = serverSyncId;
|
||||
|
||||
String localSyncID = null;
|
||||
boolean localSyncDirty = false;
|
||||
|
||||
while (!localCursor.isAfterLast()) {
|
||||
if (mIsMergeCancelled) {
|
||||
localCursor.deactivate();
|
||||
deletedCursor.deactivate();
|
||||
diffsCursor.deactivate();
|
||||
return;
|
||||
}
|
||||
localCount++;
|
||||
localSyncID = localCursor.getString(2);
|
||||
|
||||
// If the local record doesn't have a _sync_id then
|
||||
// it is new. Ignore it for now, we will send an insert
|
||||
// the the server later.
|
||||
if (TextUtils.isEmpty(localSyncID)) {
|
||||
// If tombstones aren't in use delete any remaining local rows that
|
||||
// don't have corresponding server rows. Keep the rows that don't
|
||||
// have a sync id since those were created locally and haven't been
|
||||
// synced to the server yet.
|
||||
if (!diffsArePartial) {
|
||||
while (!localCursor.isAfterLast() && !TextUtils.isEmpty(localCursor.getString(2))) {
|
||||
if (mIsMergeCancelled) {
|
||||
return;
|
||||
}
|
||||
localCount++;
|
||||
final String localSyncId = localCursor.getString(2);
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "local record " +
|
||||
localCursor.getLong(1) +
|
||||
" has no _sync_id, ignoring");
|
||||
Log.v(TAG,
|
||||
"deleting local record " +
|
||||
localCursor.getLong(1) +
|
||||
" _sync_id " + localSyncId);
|
||||
}
|
||||
localCursor.moveToNext();
|
||||
localSyncID = null;
|
||||
continue;
|
||||
deleteRow(localCursor);
|
||||
if (mDeletedTable != null) {
|
||||
mDb.delete(mDeletedTable, _SYNC_ID + "=?", new String[] {localSyncId});
|
||||
}
|
||||
syncResult.stats.numDeletes++;
|
||||
mDb.yieldIfContended();
|
||||
}
|
||||
|
||||
int comp = serverSyncId.compareTo(localSyncID);
|
||||
|
||||
// the local DB has a record that the server doesn't have
|
||||
if (comp > 0) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "local record " +
|
||||
localCursor.getLong(1) +
|
||||
" has _sync_id " + localSyncID +
|
||||
" that is < server _sync_id " + serverSyncId);
|
||||
}
|
||||
if (diffsArePartial) {
|
||||
localCursor.moveToNext();
|
||||
} else {
|
||||
deleteRow(localCursor);
|
||||
if (mDeletedTable != null) {
|
||||
mDb.delete(mDeletedTable, _SYNC_ID +"=?", new String[] {localSyncID});
|
||||
}
|
||||
syncResult.stats.numDeletes++;
|
||||
mDb.yieldIfContended();
|
||||
}
|
||||
localSyncID = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
// the server has a record that the local DB doesn't have
|
||||
if (comp < 0) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "local record " +
|
||||
localCursor.getLong(1) +
|
||||
" has _sync_id " + localSyncID +
|
||||
" that is > server _sync_id " + serverSyncId);
|
||||
}
|
||||
localSyncID = null;
|
||||
}
|
||||
|
||||
// the server and the local DB both have this record
|
||||
if (comp == 0) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "local record " +
|
||||
localCursor.getLong(1) +
|
||||
" has _sync_id " + localSyncID +
|
||||
" that matches the server _sync_id");
|
||||
}
|
||||
localSyncDirty = localCursor.getInt(0) != 0;
|
||||
localRowId = localCursor.getLong(1);
|
||||
localSyncVersion = localCursor.getString(3);
|
||||
localCursor.moveToNext();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// If this record is in the deleted table then update the server version
|
||||
// in the deleted table, if necessary, and then ignore it here.
|
||||
// We will send a deletion indication to the server down a
|
||||
// little further.
|
||||
if (findInCursor(deletedCursor, deletedSyncIDColumn, serverSyncId)) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "remote record " + serverSyncId + " is in the deleted table");
|
||||
}
|
||||
final String deletedSyncVersion = deletedCursor.getString(deletedSyncVersionColumn);
|
||||
if (!TextUtils.equals(deletedSyncVersion, serverSyncVersion)) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "setting version of deleted record " + serverSyncId + " to "
|
||||
+ serverSyncVersion);
|
||||
}
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(_SYNC_VERSION, serverSyncVersion);
|
||||
mDb.update(mDeletedTable, values, "_sync_id=?", new String[]{serverSyncId});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the _sync_local_id is present in the diffsCursor
|
||||
// then this record corresponds to a local record that was just
|
||||
// inserted into the server and the _sync_local_id is the row id
|
||||
// of the local record. Set these fields so that the next check
|
||||
// treats this record as an update, which will allow the
|
||||
// merger to update the record with the server's sync id
|
||||
if (!diffsCursor.isNull(serverSyncLocalIdColumn)) {
|
||||
localRowId = diffsCursor.getLong(serverSyncLocalIdColumn);
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "the remote record with sync id " + serverSyncId
|
||||
+ " has a local sync id, " + localRowId);
|
||||
}
|
||||
localSyncID = serverSyncId;
|
||||
localSyncDirty = false;
|
||||
localSyncVersion = null;
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(localSyncID)) {
|
||||
// An existing server item has changed
|
||||
boolean recordChanged = (localSyncVersion == null) ||
|
||||
!serverSyncVersion.equals(localSyncVersion);
|
||||
if (recordChanged) {
|
||||
if (localSyncDirty) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "remote record " + serverSyncId
|
||||
+ " conflicts with local _sync_id " + localSyncID
|
||||
+ ", local _id " + localRowId);
|
||||
}
|
||||
conflict = true;
|
||||
} else {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG,
|
||||
"remote record " +
|
||||
serverSyncId +
|
||||
" updates local _sync_id " +
|
||||
localSyncID + ", local _id " +
|
||||
localRowId);
|
||||
}
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// the local db doesn't know about this record so add it
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "remote record " + serverSyncId + " is new, inserting");
|
||||
}
|
||||
insert = true;
|
||||
}
|
||||
|
||||
if (update) {
|
||||
updateRow(localRowId, serverDiffs, diffsCursor);
|
||||
syncResult.stats.numUpdates++;
|
||||
} else if (conflict) {
|
||||
resolveRow(localRowId, serverSyncId, serverDiffs, diffsCursor);
|
||||
syncResult.stats.numUpdates++;
|
||||
} else if (insert) {
|
||||
insertRow(serverDiffs, diffsCursor);
|
||||
syncResult.stats.numInserts++;
|
||||
}
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "checked " + localCount +
|
||||
" local entries");
|
||||
} finally {
|
||||
if (diffsCursor != null) diffsCursor.close();
|
||||
if (localCursor != null) localCursor.close();
|
||||
if (deletedCursor != null) deletedCursor.close();
|
||||
}
|
||||
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "processed " + diffsCount + " server entries");
|
||||
}
|
||||
|
||||
// If tombstones aren't in use delete any remaining local rows that
|
||||
// don't have corresponding server rows. Keep the rows that don't
|
||||
// have a sync id since those were created locally and haven't been
|
||||
// synced to the server yet.
|
||||
if (!diffsArePartial) {
|
||||
while (!localCursor.isAfterLast() && !TextUtils.isEmpty(localCursor.getString(2))) {
|
||||
if (mIsMergeCancelled) {
|
||||
localCursor.deactivate();
|
||||
deletedCursor.deactivate();
|
||||
diffsCursor.deactivate();
|
||||
return;
|
||||
}
|
||||
localCount++;
|
||||
final String localSyncId = localCursor.getString(2);
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG,
|
||||
"deleting local record " +
|
||||
localCursor.getLong(1) +
|
||||
" _sync_id " + localSyncId);
|
||||
}
|
||||
deleteRow(localCursor);
|
||||
if (mDeletedTable != null) {
|
||||
mDb.delete(mDeletedTable, _SYNC_ID + "=?", new String[] {localSyncId});
|
||||
}
|
||||
syncResult.stats.numDeletes++;
|
||||
mDb.yieldIfContended();
|
||||
}
|
||||
}
|
||||
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "checked " + localCount +
|
||||
" local entries");
|
||||
diffsCursor.deactivate();
|
||||
localCursor.deactivate();
|
||||
deletedCursor.deactivate();
|
||||
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "applying deletions from the server");
|
||||
|
||||
// Apply deletions from the server
|
||||
if (mDeletedTableURL != null) {
|
||||
diffsCursor = serverDiffs.query(mDeletedTableURL, null, null, null, null);
|
||||
|
||||
while (diffsCursor.moveToNext()) {
|
||||
if (mIsMergeCancelled) {
|
||||
diffsCursor.deactivate();
|
||||
return;
|
||||
try {
|
||||
while (diffsCursor.moveToNext()) {
|
||||
if (mIsMergeCancelled) {
|
||||
return;
|
||||
}
|
||||
// delete all rows that match each element in the diffsCursor
|
||||
fullyDeleteMatchingRows(diffsCursor, account, syncResult);
|
||||
mDb.yieldIfContended();
|
||||
}
|
||||
// delete all rows that match each element in the diffsCursor
|
||||
fullyDeleteMatchingRows(diffsCursor, account, syncResult);
|
||||
mDb.yieldIfContended();
|
||||
} finally {
|
||||
diffsCursor.close();
|
||||
}
|
||||
diffsCursor.deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,26 +468,26 @@ public abstract class AbstractTableMerger
|
||||
final boolean deleteBySyncId = !diffsCursor.isNull(serverSyncIdColumn);
|
||||
|
||||
// delete the rows explicitly so that the delete operation can be overridden
|
||||
final Cursor c;
|
||||
final String[] selectionArgs;
|
||||
if (deleteBySyncId) {
|
||||
selectionArgs = new String[]{diffsCursor.getString(serverSyncIdColumn), account};
|
||||
c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_SYNC_ID_AND_ACCOUNT,
|
||||
selectionArgs, null, null, null);
|
||||
} else {
|
||||
int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID);
|
||||
selectionArgs = new String[]{diffsCursor.getString(serverSyncLocalIdColumn)};
|
||||
c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_ID, selectionArgs,
|
||||
null, null, null);
|
||||
}
|
||||
Cursor c = null;
|
||||
try {
|
||||
if (deleteBySyncId) {
|
||||
selectionArgs = new String[]{diffsCursor.getString(serverSyncIdColumn), account};
|
||||
c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_SYNC_ID_AND_ACCOUNT,
|
||||
selectionArgs, null, null, null);
|
||||
} else {
|
||||
int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID);
|
||||
selectionArgs = new String[]{diffsCursor.getString(serverSyncLocalIdColumn)};
|
||||
c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_ID, selectionArgs,
|
||||
null, null, null);
|
||||
}
|
||||
c.moveToFirst();
|
||||
while (!c.isAfterLast()) {
|
||||
deleteRow(c); // advances the cursor
|
||||
syncResult.stats.numDeletes++;
|
||||
}
|
||||
} finally {
|
||||
c.deactivate();
|
||||
if (c != null) c.close();
|
||||
}
|
||||
if (deleteBySyncId && mDeletedTable != null) {
|
||||
mDb.delete(mDeletedTable, SELECT_BY_SYNC_ID_AND_ACCOUNT, selectionArgs);
|
||||
@@ -526,25 +523,28 @@ public abstract class AbstractTableMerger
|
||||
|
||||
// Generate the client updates and insertions
|
||||
// Create a cursor for dirty records
|
||||
long numInsertsOrUpdates = 0;
|
||||
Cursor localChangesCursor = mDb.query(mTable, null, SELECT_UNSYNCED, accountSelectionArgs,
|
||||
null, null, null);
|
||||
long numInsertsOrUpdates = localChangesCursor.getCount();
|
||||
while (localChangesCursor.moveToNext()) {
|
||||
if (mIsMergeCancelled) {
|
||||
localChangesCursor.close();
|
||||
return;
|
||||
try {
|
||||
numInsertsOrUpdates = localChangesCursor.getCount();
|
||||
while (localChangesCursor.moveToNext()) {
|
||||
if (mIsMergeCancelled) {
|
||||
return;
|
||||
}
|
||||
if (clientDiffs == null) {
|
||||
clientDiffs = temporaryInstanceFactory.getTemporaryInstance();
|
||||
}
|
||||
mValues.clear();
|
||||
cursorRowToContentValues(localChangesCursor, mValues);
|
||||
mValues.remove("_id");
|
||||
DatabaseUtils.cursorLongToContentValues(localChangesCursor, "_id", mValues,
|
||||
_SYNC_LOCAL_ID);
|
||||
clientDiffs.insert(mTableURL, mValues);
|
||||
}
|
||||
if (clientDiffs == null) {
|
||||
clientDiffs = temporaryInstanceFactory.getTemporaryInstance();
|
||||
}
|
||||
mValues.clear();
|
||||
cursorRowToContentValues(localChangesCursor, mValues);
|
||||
mValues.remove("_id");
|
||||
DatabaseUtils.cursorLongToContentValues(localChangesCursor, "_id", mValues,
|
||||
_SYNC_LOCAL_ID);
|
||||
clientDiffs.insert(mTableURL, mValues);
|
||||
} finally {
|
||||
localChangesCursor.close();
|
||||
}
|
||||
localChangesCursor.close();
|
||||
|
||||
// Generate the client deletions
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "generating client deletions");
|
||||
@@ -555,21 +555,22 @@ public abstract class AbstractTableMerger
|
||||
syncIdAndVersionProjection,
|
||||
_SYNC_ACCOUNT + "=? AND " + _SYNC_ID + " IS NOT NULL", accountSelectionArgs,
|
||||
null, null, mDeletedTable + "." + _SYNC_ID);
|
||||
|
||||
numDeletedEntries = deletedCursor.getCount();
|
||||
while (deletedCursor.moveToNext()) {
|
||||
if (mIsMergeCancelled) {
|
||||
deletedCursor.close();
|
||||
return;
|
||||
try {
|
||||
numDeletedEntries = deletedCursor.getCount();
|
||||
while (deletedCursor.moveToNext()) {
|
||||
if (mIsMergeCancelled) {
|
||||
return;
|
||||
}
|
||||
if (clientDiffs == null) {
|
||||
clientDiffs = temporaryInstanceFactory.getTemporaryInstance();
|
||||
}
|
||||
mValues.clear();
|
||||
DatabaseUtils.cursorRowToContentValues(deletedCursor, mValues);
|
||||
clientDiffs.insert(mDeletedTableURL, mValues);
|
||||
}
|
||||
if (clientDiffs == null) {
|
||||
clientDiffs = temporaryInstanceFactory.getTemporaryInstance();
|
||||
}
|
||||
mValues.clear();
|
||||
DatabaseUtils.cursorRowToContentValues(deletedCursor, mValues);
|
||||
clientDiffs.insert(mDeletedTableURL, mValues);
|
||||
} finally {
|
||||
deletedCursor.close();
|
||||
}
|
||||
deletedCursor.close();
|
||||
}
|
||||
|
||||
if (clientDiffs != null) {
|
||||
|
||||
@@ -211,7 +211,7 @@ public class DatabaseUtils {
|
||||
sb.append(sqlString);
|
||||
sb.append('\'');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* SQL-escape a string.
|
||||
*/
|
||||
@@ -240,7 +240,7 @@ public class DatabaseUtils {
|
||||
appendEscapedSQLString(sql, value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Concatenates two SQL WHERE clauses, handling empty or null values.
|
||||
* @hide
|
||||
@@ -252,12 +252,12 @@ public class DatabaseUtils {
|
||||
if (TextUtils.isEmpty(b)) {
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
return "(" + a + ") AND (" + b + ")";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* return the collation key
|
||||
* return the collation key
|
||||
* @param name
|
||||
* @return the collation key
|
||||
*/
|
||||
@@ -269,7 +269,7 @@ public class DatabaseUtils {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* return the collation key in hex format
|
||||
* @param name
|
||||
@@ -280,7 +280,7 @@ public class DatabaseUtils {
|
||||
char[] keys = Hex.encodeHex(arr);
|
||||
return new String(keys, 0, getKeyLen(arr) * 2);
|
||||
}
|
||||
|
||||
|
||||
private static int getKeyLen(byte[] arr) {
|
||||
if (arr[arr.length - 1] != 0) {
|
||||
return arr.length;
|
||||
@@ -289,16 +289,16 @@ public class DatabaseUtils {
|
||||
return arr.length-1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static byte[] getCollationKeyInBytes(String name) {
|
||||
if (mColl == null) {
|
||||
mColl = Collator.getInstance();
|
||||
mColl.setStrength(Collator.PRIMARY);
|
||||
}
|
||||
return mColl.getCollationKey(name).toByteArray();
|
||||
return mColl.getCollationKey(name).toByteArray();
|
||||
}
|
||||
|
||||
private static Collator mColl = null;
|
||||
|
||||
private static Collator mColl = null;
|
||||
/**
|
||||
* Prints the contents of a Cursor to System.out. The position is restored
|
||||
* after printing.
|
||||
@@ -591,10 +591,12 @@ public class DatabaseUtils {
|
||||
public static long queryNumEntries(SQLiteDatabase db, String table) {
|
||||
Cursor cursor = db.query(table, countProjection,
|
||||
null, null, null, null, null);
|
||||
cursor.moveToFirst();
|
||||
long count = cursor.getLong(0);
|
||||
cursor.deactivate();
|
||||
return count;
|
||||
try {
|
||||
cursor.moveToFirst();
|
||||
return cursor.getLong(0);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -155,14 +155,17 @@ public class SubscribedFeedsIntentService extends IntentService {
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
Cursor c = contentResolver.query(SubscribedFeeds.Accounts.CONTENT_URI,
|
||||
sAccountProjection, null, null, null);
|
||||
while (c.moveToNext()) {
|
||||
String account = c.getString(0);
|
||||
if (TextUtils.isEmpty(account)) {
|
||||
continue;
|
||||
try {
|
||||
while (c.moveToNext()) {
|
||||
String account = c.getString(0);
|
||||
if (TextUtils.isEmpty(account)) {
|
||||
continue;
|
||||
}
|
||||
accounts.add(account);
|
||||
}
|
||||
accounts.add(account);
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
c.deactivate();
|
||||
|
||||
// Clear the auth tokens for all these accounts so that we are sure
|
||||
// they will still be valid until the next time we refresh them.
|
||||
|
||||
Reference in New Issue
Block a user