--- a/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/db/TestBookmarks.java
+++ b/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/db/TestBookmarks.java
@@ -604,17 +604,17 @@ public class TestBookmarks extends Andro
while (iter.hasNext()) {
tracked.add(iter.next());
}
}
finishAndNotify(session);
}
@Override
- public void onRecordStoreSucceeded(String guid) {
+ public void onRecordStoreSucceeded(int count) {
}
@Override
public void onRecordStoreReconciled(String guid, String oldGuid, Integer newVersion) {
}
@Override
public void onStoreFailed(Exception e) {
--- a/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/db/TestFormHistoryRepositorySession.java
+++ b/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/db/TestFormHistoryRepositorySession.java
@@ -317,17 +317,17 @@ public class TestFormHistoryRepositorySe
insertTwoRecords(session);
FormHistoryRecord rec;
// remote regular, local missing => should store.
rec = new FormHistoryRecord("new1", "forms", System.currentTimeMillis(), false);
rec.fieldName = "fieldName1";
rec.fieldValue = "fieldValue1";
- performWait(storeRunnable(session, rec, new ExpectStoredDelegate(rec.guid)));
+ performWait(storeRunnable(session, rec, new ExpectStoredDelegate(1)));
performWait(fetchRunnable(session, new String[] { rec.guid }, new Record[] { rec }));
// remote deleted, local missing => should delete, but at the moment we ignore.
rec = new FormHistoryRecord("new2", "forms", System.currentTimeMillis(), true);
performWait(storeRunnable(session, rec, new ExpectNoStoreDelegate()));
performWait(fetchRunnable(session, new String[] { rec.guid }, new Record[] { }));
session.abort();
@@ -340,29 +340,29 @@ public class TestFormHistoryRepositorySe
long newTimestamp = System.currentTimeMillis();
FormHistoryRecord rec;
// remote regular, local regular, remote newer => should update.
rec = new FormHistoryRecord(regular1.guid, regular1.collection, newTimestamp, false);
rec.fieldName = regular1.fieldName;
rec.fieldValue = regular1.fieldValue + "NEW";
- performWait(storeRunnable(session, rec, new ExpectStoredDelegate(rec.guid)));
+ performWait(storeRunnable(session, rec, new ExpectStoredDelegate(1)));
performWait(fetchRunnable(session, new String[] { regular1.guid }, new Record[] { rec }));
// remote deleted, local regular, remote newer => should delete everything.
rec = new FormHistoryRecord(regular2.guid, regular2.collection, newTimestamp, true);
- performWait(storeRunnable(session, rec, new ExpectStoredDelegate(rec.guid)));
+ performWait(storeRunnable(session, rec, new ExpectStoredDelegate(1)));
performWait(fetchRunnable(session, new String[] { regular2.guid }, new Record[] { }));
// remote regular, local deleted, remote newer => should update.
rec = new FormHistoryRecord(deleted1.guid, deleted1.collection, newTimestamp, false);
rec.fieldName = regular1.fieldName;
rec.fieldValue = regular1.fieldValue + "NEW";
- performWait(storeRunnable(session, rec, new ExpectStoredDelegate(rec.guid)));
+ performWait(storeRunnable(session, rec, new ExpectStoredDelegate(1)));
performWait(fetchRunnable(session, new String[] { deleted1.guid }, new Record[] { rec }));
// remote deleted, local deleted, remote newer => should delete everything.
rec = new FormHistoryRecord(deleted2.guid, deleted2.collection, newTimestamp, true);
performWait(storeRunnable(session, rec, new ExpectNoStoreDelegate()));
performWait(fetchRunnable(session, new String[] { deleted2.guid }, new Record[] { }));
session.abort();
@@ -400,15 +400,15 @@ public class TestFormHistoryRepositorySe
}
public void testStoreDifferentGuid() throws Exception {
final FormHistoryRepositorySession session = createAndBeginSession();
insertTwoRecords(session);
FormHistoryRecord rec = (FormHistoryRecord) regular1.copyWithIDs("distinct", 999);
- performWait(storeRunnable(session, rec, new ExpectStoredDelegate(rec.guid)));
+ performWait(storeRunnable(session, rec, new ExpectStoredDelegate(1)));
// Existing record should take remote record's GUID.
performWait(fetchAllRunnable(session, new Record[] { rec, deleted1 }));
session.abort();
}
}
--- a/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/db/TestPasswordsRepository.java
+++ b/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/db/TestPasswordsRepository.java
@@ -382,17 +382,17 @@ public class TestPasswordsRepository ext
}
private static long updatePassword(String password, PasswordRecord record) {
return updatePassword(password, record, System.currentTimeMillis());
}
// Runnable Helpers.
private static Runnable storeRunnable(final RepositorySession session, final Record record) {
- return storeRunnable(session, record, new ExpectStoredDelegate(record.guid));
+ return storeRunnable(session, record, new ExpectStoredDelegate(1));
}
private static Runnable storeRunnable(final RepositorySession session, final Record record, final RepositorySessionStoreDelegate delegate) {
return new Runnable() {
@Override
public void run() {
session.setStoreDelegate(delegate);
try {
--- a/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/db/ThreadedRepositoryTestCase.java
+++ b/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/db/ThreadedRepositoryTestCase.java
@@ -109,17 +109,17 @@ public abstract class ThreadedRepository
} catch (NoStoreDelegateException e) {
fail("NoStoreDelegateException should not occur.");
}
}
};
}
public static Runnable storeRunnable(final RepositorySession session, final Record record) {
- return storeRunnable(session, record, new ExpectStoredDelegate(record.guid));
+ return storeRunnable(session, record, new ExpectStoredDelegate(1));
}
public static Runnable storeManyRunnable(final RepositorySession session, final Record[] records, final DefaultStoreDelegate delegate) {
return new Runnable() {
@Override
public void run() {
session.setStoreDelegate(delegate);
try {
--- a/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/sync/TestStoreTracking.java
+++ b/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/sync/TestStoreTracking.java
@@ -46,25 +46,23 @@ public class TestStoreTracking extends A
public void doTestStoreRetrieveByGUID(final WBORepository repository,
final RepositorySession session,
final String expectedGUID,
final Record record) {
final SimpleSuccessStoreDelegate storeDelegate = new SimpleSuccessStoreDelegate() {
@Override
- public void onRecordStoreSucceeded(String guid) {
- Logger.debug(getName(), "Stored " + guid);
- assertEq(expectedGUID, guid);
+ public void onRecordStoreSucceeded(int count) {
+ Logger.debug(getName(), "Stored " + count);
}
@Override
public void onRecordStoreReconciled(String guid, String oldGuid, Integer newVersion) {
Logger.debug(getName(), "Reconciled " + guid);
- assertEq(expectedGUID, guid);
}
@Override
public void onStoreCompleted() {
Logger.debug(getName(), "Store completed.");
try {
session.fetch(new String[] { expectedGUID }, new SimpleSuccessFetchDelegate() {
@Override
--- a/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/sync/helpers/DefaultStoreDelegate.java
+++ b/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/sync/helpers/DefaultStoreDelegate.java
@@ -10,17 +10,17 @@ import org.mozilla.gecko.sync.repositori
public class DefaultStoreDelegate extends DefaultDelegate implements RepositorySessionStoreDelegate {
@Override
public void onRecordStoreFailed(Exception ex, String guid) {
performNotify("Record store failed", ex);
}
@Override
- public void onRecordStoreSucceeded(String guid) {
+ public void onRecordStoreSucceeded(int count) {
performNotify("DefaultStoreDelegate used", null);
}
@Override
public void onStoreCompleted() {
performNotify("DefaultStoreDelegate used", null);
}
@@ -38,21 +38,21 @@ public class DefaultStoreDelegate extend
public void onRecordStoreReconciled(String guid, String oldGuid, Integer newVersion) {}
@Override
public RepositorySessionStoreDelegate deferredStoreDelegate(final ExecutorService executor) {
final RepositorySessionStoreDelegate self = this;
return new RepositorySessionStoreDelegate() {
@Override
- public void onRecordStoreSucceeded(final String guid) {
+ public void onRecordStoreSucceeded(final int count) {
executor.execute(new Runnable() {
@Override
public void run() {
- self.onRecordStoreSucceeded(guid);
+ self.onRecordStoreSucceeded(count);
}
});
}
@Override
public void onRecordStoreFailed(final Exception ex, final String guid) {
executor.execute(new Runnable() {
@Override
--- a/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/sync/helpers/ExpectManyStoredDelegate.java
+++ b/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/sync/helpers/ExpectManyStoredDelegate.java
@@ -9,40 +9,31 @@ import static junit.framework.Assert.ass
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicLong;
import junit.framework.AssertionFailedError;
import org.mozilla.gecko.sync.repositories.domain.Record;
public class ExpectManyStoredDelegate extends DefaultStoreDelegate {
- HashSet<String> expectedGUIDs;
+ int expectedStored;
AtomicLong stored;
public ExpectManyStoredDelegate(Record[] records) {
- HashSet<String> s = new HashSet<String>();
- for (Record record : records) {
- s.add(record.guid);
- }
- expectedGUIDs = s;
+ expectedStored = records.length;
stored = new AtomicLong(0);
}
@Override
public void onStoreCompleted() {
try {
- assertEquals(expectedGUIDs.size(), stored.get());
+ assertEquals(expectedStored, stored.get());
performNotify();
} catch (AssertionFailedError e) {
performNotify(e);
}
}
@Override
- public void onRecordStoreSucceeded(String guid) {
- try {
- assertTrue(expectedGUIDs.contains(guid));
- } catch (AssertionFailedError e) {
- performNotify(e);
- }
- stored.incrementAndGet();
+ public void onRecordStoreSucceeded(int count) {
+ stored.addAndGet(count);
}
}
--- a/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/sync/helpers/ExpectNoStoreDelegate.java
+++ b/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/sync/helpers/ExpectNoStoreDelegate.java
@@ -1,11 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
package org.mozilla.gecko.background.sync.helpers;
public class ExpectNoStoreDelegate extends ExpectStoreCompletedDelegate {
@Override
- public void onRecordStoreSucceeded(String guid) {
- performNotify("Should not have stored record " + guid, null);
+ public void onRecordStoreSucceeded(int count) {
+ performNotify("Should not have stored records: " + count, null);
}
}
\ No newline at end of file
--- a/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/sync/helpers/ExpectStoreCompletedDelegate.java
+++ b/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/sync/helpers/ExpectStoreCompletedDelegate.java
@@ -1,17 +1,17 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
package org.mozilla.gecko.background.sync.helpers;
public class ExpectStoreCompletedDelegate extends DefaultStoreDelegate {
@Override
- public void onRecordStoreSucceeded(String guid) {
+ public void onRecordStoreSucceeded(int count) {
// That's fine.
}
@Override
public void onStoreCompleted() {
performNotify();
}
}
--- a/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/sync/helpers/ExpectStoredDelegate.java
+++ b/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/sync/helpers/ExpectStoredDelegate.java
@@ -1,39 +1,30 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
package org.mozilla.gecko.background.sync.helpers;
import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
import junit.framework.AssertionFailedError;
public class ExpectStoredDelegate extends DefaultStoreDelegate {
- String expectedGUID;
- String storedGuid;
-
- public ExpectStoredDelegate(String guid) {
- this.expectedGUID = guid;
+ final int expectedCount;
+ int count;
+ public ExpectStoredDelegate(int expectedCount) {
+ this.expectedCount = expectedCount;
}
@Override
public synchronized void onStoreCompleted() {
try {
- assertNotNull(storedGuid);
+ assertEquals(expectedCount, count);
performNotify();
} catch (AssertionFailedError e) {
- performNotify("GUID " + this.expectedGUID + " was not stored", e);
+ performNotify("Wrong # of GUIDS stored: " + count, e);
}
}
@Override
- public synchronized void onRecordStoreSucceeded(String guid) {
- this.storedGuid = guid;
- try {
- if (this.expectedGUID != null) {
- assertEquals(this.expectedGUID, guid);
- }
- } catch (AssertionFailedError e) {
- performNotify(e);
- }
+ public synchronized void onRecordStoreSucceeded(int count) {
+ this.count += count;
}
}
--- a/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/testhelpers/WBORepository.java
+++ b/mobile/android/services/src/androidTest/java/org/mozilla/gecko/background/testhelpers/WBORepository.java
@@ -128,32 +128,32 @@ public class WBORepository extends Repos
if (stats.storeBegan < 0) {
stats.storeBegan = now;
}
Record existing = wbos.get(record.guid);
Logger.debug(LOG_TAG, "Existing record is " + (existing == null ? "<null>" : (existing.guid + ", " + existing)));
if (existing != null &&
existing.lastModified > record.lastModified) {
Logger.debug(LOG_TAG, "Local record is newer. Not storing.");
- storeDelegate.deferredStoreDelegate(delegateExecutor).onRecordStoreSucceeded(record.guid);
+ storeDelegate.deferredStoreDelegate(delegateExecutor).onRecordStoreSucceeded(1);
return;
}
if (existing != null) {
Logger.debug(LOG_TAG, "Replacing local record.");
}
// Store a copy of the record with an updated modified time.
Record toStore = record.copyWithIDs(record.guid, record.androidID);
if (bumpTimestamps) {
toStore.lastModified = now;
}
wbos.put(record.guid, toStore);
trackRecord(toStore);
- storeDelegate.deferredStoreDelegate(delegateExecutor).onRecordStoreSucceeded(record.guid);
+ storeDelegate.deferredStoreDelegate(delegateExecutor).onRecordStoreSucceeded(1);
}
@Override
public void wipe(final RepositorySessionWipeDelegate delegate) {
if (!isActive()) {
delegate.onWipeFailed(new InactiveSessionException());
return;
}
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/BaseResource.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/BaseResource.java
@@ -302,17 +302,17 @@ public class BaseResource implements Res
connectionManager.shutdown();
}
private void execute() {
HttpResponse response;
try {
response = client.execute(request, context);
Logger.debug(LOG_TAG, "Response: " + response.getStatusLine().toString());
- } catch (ClientProtocolException e) {
+ } catch (ClientProtocolException e) {
delegate.handleHttpProtocolException(e);
return;
} catch (IOException e) {
Logger.debug(LOG_TAG, "I/O exception returned from execute.");
if (!retryOnFailedRequest) {
delegate.handleHttpIOException(e);
} else {
retryRequest();
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/VersioningDelegateHelper.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/VersioningDelegateHelper.java
@@ -182,18 +182,18 @@ public class VersioningDelegateHelper {
// That is why we remove old GUIDs from the map whenever we perform a replacement.
// See Bug 1392716.
localVersionsOfGuids.remove(oldGuid);
localVersionsOfGuids.put(guid, newVersion);
inner.onRecordStoreReconciled(guid, oldGuid, newVersion);
}
@Override
- public void onRecordStoreSucceeded(String guid) {
- inner.onRecordStoreSucceeded(guid);
+ public void onRecordStoreSucceeded(int count) {
+ inner.onRecordStoreSucceeded(count);
}
@Override
public void onStoreCompleted() {
inner.onStoreCompleted();
}
@Override
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/BookmarksDeletionManager.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/BookmarksDeletionManager.java
@@ -205,19 +205,17 @@ public class BookmarksDeletionManager {
}
private void invokeCallbacks(RepositorySessionStoreDelegate delegate,
String[] nonFolderGUIDs) {
if (delegate == null) {
return;
}
Logger.trace(LOG_TAG, "Invoking store callback for " + nonFolderGUIDs.length + " GUIDs.");
- for (String guid : nonFolderGUIDs) {
- delegate.onRecordStoreSucceeded(guid);
- }
+ delegate.onRecordStoreSucceeded(nonFolderGUIDs.length);
}
/**
* Clear state in case of redundancy (e.g., wipe).
*/
public void clear() {
nonFolders.clear();
nonFolderCount = 0;
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/BookmarksSessionHelper.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/BookmarksSessionHelper.java
@@ -326,17 +326,17 @@ import java.util.concurrent.ConcurrentHa
Logger.debug(LOG_TAG, "Inserted folder with guid " + toStore.guid + " as androidID " + toStore.androidID);
updateBookkeeping(toStore);
} catch (Exception e) {
delegate.onRecordStoreFailed(e, record.guid);
return false;
}
session.trackRecord(toStore);
- delegate.onRecordStoreSucceeded(record.guid);
+ delegate.onRecordStoreSucceeded(1);
return true;
}
/**
* Implement method of BookmarksInsertionManager.BookmarkInserter.
*/
@Override
public void bulkInsertNonFolders(RepositorySessionStoreDelegate delegate, Collection<BookmarkRecord> records) {
@@ -368,18 +368,18 @@ import java.util.concurrent.ConcurrentHa
// Success For All!
for (Record succeeded : toStores) {
try {
updateBookkeeping(succeeded);
} catch (Exception e) {
Logger.warn(LOG_TAG, "Got exception updating bookkeeping of non-folder with guid " + succeeded.guid + ".", e);
}
session.trackRecord(succeeded);
- delegate.onRecordStoreSucceeded(succeeded.guid);
}
+ delegate.onRecordStoreSucceeded(toStores.size());
}
@Override
/* package-private */ void doBegin() throws NullCursorException {
// To deal with parent mapping of bookmarks we have to do some
// hairy stuff. Here's the setup for it.
Cursor cur = dbAccessor.getGuidsIDsForFolders();
@@ -451,17 +451,17 @@ import java.util.concurrent.ConcurrentHa
// Note that we don't track records here; deciding that is the job
// of reconcileRecords.
Logger.debug(LOG_TAG, "Calling delegate callback with guid " + replaced.guid +
"(" + replaced.androidID + ")");
// There's book-keeping which needs to happen with versions, and so we need to pass
// along the new localVersion.
delegate.onRecordStoreReconciled(replaced.guid, existingRecord.guid, replaced.localVersion);
- delegate.onRecordStoreSucceeded(replaced.guid);
+ delegate.onRecordStoreSucceeded(1);
return true;
}
@Override
/* package-private */ boolean isLocallyModified(Record record) {
if (record.localVersion == null || record.syncVersion == null) {
throw new IllegalArgumentException("Bookmark session helper received non-versioned record");
}
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/FennecTabsRepository.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/FennecTabsRepository.java
@@ -245,17 +245,17 @@ public class FennecTabsRepository extend
// This is nice and easy: we *always* store.
final String[] selectionArgs = new String[] { tabsRecord.guid };
if (tabsRecord.deleted) {
try {
Logger.debug(LOG_TAG, "Clearing entry for client " + tabsRecord.guid);
clientsProvider.delete(BrowserContractHelpers.CLIENTS_CONTENT_URI,
CLIENT_GUID_IS,
selectionArgs);
- storeDelegate.onRecordStoreSucceeded(record.guid);
+ storeDelegate.onRecordStoreSucceeded(1);
} catch (Exception e) {
storeDelegate.onRecordStoreFailed(e, record.guid);
}
return;
}
// If it exists, update the client record; otherwise insert.
final ContentValues clientsCV = tabsRecord.getClientsContentValues();
@@ -278,17 +278,17 @@ public class FennecTabsRepository extend
// Now insert tabs.
final ContentValues[] tabsArray = tabsRecord.getTabsContentValues();
Logger.debug(LOG_TAG, "Inserting " + tabsArray.length + " tabs for client " + tabsRecord.guid);
tabsProvider.delete(BrowserContractHelpers.TABS_CONTENT_URI, TABS_CLIENT_GUID_IS, selectionArgs);
final int inserted = tabsProvider.bulkInsert(BrowserContractHelpers.TABS_CONTENT_URI, tabsArray);
Logger.trace(LOG_TAG, "Inserted: " + inserted);
- storeDelegate.onRecordStoreSucceeded(record.guid);
+ storeDelegate.onRecordStoreSucceeded(1);
} catch (Exception e) {
Logger.warn(LOG_TAG, "Error storing tabs.", e);
storeDelegate.onRecordStoreFailed(e, record.guid);
}
}
};
storeWorkQueue.execute(command);
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/FormHistoryRepositorySession.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/FormHistoryRepositorySession.java
@@ -549,30 +549,30 @@ public class FormHistoryRepositorySessio
return;
}
boolean locallyModified = existingRecord.lastModified > lastLocalRetrieval;
if (!locallyModified) {
Logger.trace(LOG_TAG, "Remote modified, local not. Deleting.");
deleteExistingRecord(existingRecord);
trackRecord(record);
- storeDelegate.onRecordStoreSucceeded(record.guid);
+ storeDelegate.onRecordStoreSucceeded(1);
return;
}
Logger.trace(LOG_TAG, "Both local and remote records have been modified.");
if (record.lastModified > existingRecord.lastModified) {
Logger.trace(LOG_TAG, "Remote is newer, and deleted. Purging local.");
deleteExistingRecord(existingRecord);
trackRecord(record);
// Note that while this counts as "reconciliation", we're probably over-counting.
// Currently, locallyModified above is _always_ true if a record exists locally,
// and so we'll consider any deletions of already present records as reconciliations.
storeDelegate.onRecordStoreReconciled(record.guid, null, null);
- storeDelegate.onRecordStoreSucceeded(record.guid);
+ storeDelegate.onRecordStoreSucceeded(1);
return;
}
Logger.trace(LOG_TAG, "Remote is older, local is not deleted. Ignoring.");
return;
}
// End deletion logic.
@@ -582,49 +582,49 @@ public class FormHistoryRepositorySessio
existingRecord = findExistingRecordByPayload(record);
}
if (existingRecord == null) {
// The record is new.
Logger.trace(LOG_TAG, "No match. Inserting.");
insertNewRegularRecord(record);
trackRecord(record);
- storeDelegate.onRecordStoreSucceeded(record.guid);
+ storeDelegate.onRecordStoreSucceeded(1);
return;
}
// We found a local duplicate.
Logger.trace(LOG_TAG, "Incoming record " + record.guid + " dupes to local record " + existingRecord.guid);
if (!RepoUtils.stringsEqual(record.guid, existingRecord.guid)) {
// We found a local record that does NOT have the same GUID -- keep the server's version.
Logger.trace(LOG_TAG, "Remote guid different from local guid. Storing to keep remote guid.");
replaceExistingRecordWithRegularRecord(record, existingRecord);
trackRecord(record);
- storeDelegate.onRecordStoreSucceeded(record.guid);
+ storeDelegate.onRecordStoreSucceeded(1);
return;
}
// We found a local record that does have the same GUID -- check modification times.
boolean locallyModified = existingRecord.lastModified > lastLocalRetrieval;
if (!locallyModified) {
Logger.trace(LOG_TAG, "Remote modified, local not. Storing.");
replaceExistingRecordWithRegularRecord(record, existingRecord);
trackRecord(record);
- storeDelegate.onRecordStoreSucceeded(record.guid);
+ storeDelegate.onRecordStoreSucceeded(1);
return;
}
Logger.trace(LOG_TAG, "Both local and remote records have been modified.");
if (record.lastModified > existingRecord.lastModified) {
Logger.trace(LOG_TAG, "Remote is newer, and not deleted. Storing.");
replaceExistingRecordWithRegularRecord(record, existingRecord);
trackRecord(record);
storeDelegate.onRecordStoreReconciled(record.guid, existingRecord.guid, null);
- storeDelegate.onRecordStoreSucceeded(record.guid);
+ storeDelegate.onRecordStoreSucceeded(1);
return;
}
Logger.trace(LOG_TAG, "Remote is older, local is not deleted. Ignoring.");
} catch (Exception e) {
Logger.error(LOG_TAG, "Store failed for " + record.guid, e);
storeDelegate.onRecordStoreFailed(e, record.guid);
return;
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/HistorySessionHelper.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/HistorySessionHelper.java
@@ -52,17 +52,17 @@ import java.util.ArrayList;
* Neither argument will ever be null.
*
* @param record the incoming record. This will be mostly blank, given that it's a deletion.
* @param existingRecord the existing record. Use this to decide how to process the deletion.
*/
@Override
/* package-private */ void storeRecordDeletion(RepositorySessionStoreDelegate storeDelegate, Record record, Record existingRecord) {
dbHelper.purgeGuid(record.guid);
- storeDelegate.onRecordStoreSucceeded(record.guid);
+ storeDelegate.onRecordStoreSucceeded(1);
}
@Override
/* package-private */ boolean shouldIgnore(Record record) {
return shouldIgnoreStatic(record);
}
@VisibleForTesting
@@ -145,17 +145,17 @@ import java.util.ArrayList;
// newRecord should already have suitable androidID and guid.
dbHelper.update(existingRecord.guid, preparedToStore);
updateBookkeeping(preparedToStore);
Logger.debug(LOG_TAG, "replace() returning record " + preparedToStore.guid);
Logger.debug(LOG_TAG, "Calling delegate callback with guid " + preparedToStore.guid +
"(" + preparedToStore.androidID + ")");
delegate.onRecordStoreReconciled(preparedToStore.guid, existingRecord.guid, null);
- delegate.onRecordStoreSucceeded(preparedToStore.guid);
+ delegate.onRecordStoreSucceeded(1);
return true;
}
@Override
boolean isLocallyModified(Record record) {
return record.lastModified > session.getLastSyncTimestamp();
}
@@ -253,12 +253,12 @@ import java.util.ArrayList;
updateBookkeeping(succeeded);
} catch (NoGuidForIdException | ParentNotFoundException e) {
// Should not happen.
throw new NullCursorException(e);
} catch (NullCursorException e) {
throw e;
}
session.trackRecord(succeeded);
- delegate.onRecordStoreSucceeded(succeeded.guid); // At this point, we are really inserted.
}
+ delegate.onRecordStoreSucceeded(outgoing.size()); // At this point, we are really inserted.
}
}
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/PasswordsRepositorySession.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/PasswordsRepositorySession.java
@@ -299,17 +299,17 @@ public class PasswordsRepositorySession
try {
inserted = insert(remoteRecord);
} catch (RemoteException e) {
Logger.debug(LOG_TAG, "Record insert caused a RemoteException.");
storeDelegate.onRecordStoreFailed(e, record.guid);
return;
}
trackRecord(inserted);
- storeDelegate.onRecordStoreSucceeded(inserted.guid);
+ storeDelegate.onRecordStoreSucceeded(1);
return;
}
// We found a local dupe.
trace("Incoming record " + remoteRecord.guid + " dupes to local record " + existingRecord.guid);
Logger.debug(LOG_TAG, "remote " + remoteRecord.guid + " dupes to " + existingRecord.guid);
if (existingRecord.deleted && existingRecord.lastModified > remoteRecord.lastModified) {
@@ -335,17 +335,17 @@ public class PasswordsRepositorySession
return;
}
// Note that we don't track records here; deciding that is the job
// of reconcileRecords.
Logger.debug(LOG_TAG, "Calling delegate callback with guid " + replaced.guid +
"(" + replaced.androidID + ")");
storeDelegate.onRecordStoreReconciled(record.guid, existingRecord.guid, null);
- storeDelegate.onRecordStoreSucceeded(record.guid);
+ storeDelegate.onRecordStoreSucceeded(1);
return;
}
};
storeWorkQueue.execute(storeRunnable);
}
@Override
public void wipe(final RepositorySessionWipeDelegate delegate) {
@@ -593,17 +593,17 @@ public class PasswordsRepositorySession
private void storeRecordDeletion(Record record) {
try {
deleteGUID(record.guid);
} catch (RemoteException e) {
Logger.error(LOG_TAG, "RemoteException in password delete.");
storeDelegate.onRecordStoreFailed(e, record.guid);
return;
}
- storeDelegate.onRecordStoreSucceeded(record.guid);
+ storeDelegate.onRecordStoreSucceeded(1);
}
/**
* Make a PasswordRecord from a Cursor.
* @param cur
* Cursor from query.
* @return
* PasswordRecord populated from Cursor.
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/delegates/DeferredRepositorySessionStoreDelegate.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/delegates/DeferredRepositorySessionStoreDelegate.java
@@ -13,21 +13,21 @@ public class DeferredRepositorySessionSt
public DeferredRepositorySessionStoreDelegate(
RepositorySessionStoreDelegate inner, ExecutorService executor) {
this.inner = inner;
this.executor = executor;
}
@Override
- public void onRecordStoreSucceeded(final String guid) {
+ public void onRecordStoreSucceeded(final int count) {
executor.execute(new Runnable() {
@Override
public void run() {
- inner.onRecordStoreSucceeded(guid);
+ inner.onRecordStoreSucceeded(count);
}
});
}
@Override
public void onRecordStoreFailed(final Exception ex, final String guid) {
executor.execute(new Runnable() {
@Override
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/delegates/RepositorySessionStoreDelegate.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/delegates/RepositorySessionStoreDelegate.java
@@ -17,15 +17,15 @@ public interface RepositorySessionStoreD
void onRecordStoreFailed(Exception ex, String recordGuid);
// Meant for signaling that a record has been reconciled.
// Only makes sense in context of local repositories.
// Further call to onRecordStoreSucceeded is necessary.
void onRecordStoreReconciled(String guid, String oldGuid, Integer newVersion);
// Called with a GUID when store has succeeded.
- void onRecordStoreSucceeded(String guid);
+ void onRecordStoreSucceeded(int count);
void onStoreCompleted();
void onStoreFailed(Exception e);
// Only relevant for store batches, and exists to help us record correct telemetry.
void onBatchCommitted();
RepositorySessionStoreDelegate deferredStoreDelegate(ExecutorService executor);
}
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/uploaders/BatchMeta.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/uploaders/BatchMeta.java
@@ -7,60 +7,50 @@ package org.mozilla.gecko.sync.repositor
import android.support.annotation.Nullable;
import org.mozilla.gecko.background.common.log.Logger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Keeps track of various meta information about a batch series.
*
* NB regarding concurrent access:
* - this class expects access by possibly different, sequentially running threads.
* - concurrent access is not supported.
*/
public class BatchMeta {
private static final String LOG_TAG = "BatchMeta";
private volatile Boolean inBatchingMode;
@Nullable private volatile Long lastModified;
private volatile String token;
- // NB: many of the operations on ConcurrentLinkedQueue are not atomic (toArray, for example),
- // and so use of this queue type is only possible because this class does not support concurrent
- // access.
- private final ConcurrentLinkedQueue<String> successRecordGuids = new ConcurrentLinkedQueue<>();
+ private final AtomicInteger recordSuccessCounter = new AtomicInteger(0);
BatchMeta(@Nullable Long initialLastModified, Boolean initialInBatchingMode) {
lastModified = initialLastModified;
inBatchingMode = initialInBatchingMode;
}
- String[] getSuccessRecordGuids() {
- // NB: This really doesn't play well with concurrent access.
- final String[] guids = new String[this.successRecordGuids.size()];
- this.successRecordGuids.toArray(guids);
- return guids;
+ int getSuccessRecordCount() {
+ return recordSuccessCounter.get();
}
- void recordSucceeded(final String recordGuid) {
- // Sanity check.
- if (recordGuid == null) {
- throw new IllegalStateException("Record guid is unexpectedly null");
- }
-
- successRecordGuids.add(recordGuid);
+ void recordsSucceeded(int count) {
+ recordSuccessCounter.addAndGet(count);
}
- void clearSuccessRecordGuids() {
- successRecordGuids.clear();
+ void clearSuccessRecordCounter() {
+ recordSuccessCounter.set(0);
}
/* package-local */ void setInBatchingMode(boolean inBatchingMode) {
this.inBatchingMode = inBatchingMode;
}
/* package-local */ Boolean getInBatchingMode() {
return inBatchingMode;
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/uploaders/PayloadDispatcher.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/uploaders/PayloadDispatcher.java
@@ -75,30 +75,28 @@ class PayloadDispatcher {
* @param isLastPayload was this a very last payload we'll upload?
*/
void payloadSucceeded(final SyncStorageResponse response, final boolean isCommit, final boolean isLastPayload) {
// Sanity check.
if (batchWhiteboard.getInBatchingMode() == null) {
throw new IllegalStateException("Can't process payload success until we know if we're in a batching mode");
}
- final String[] guids = batchWhiteboard.getSuccessRecordGuids();
+ final int recordsSucceeded = batchWhiteboard.getSuccessRecordCount();
// We consider records to have been committed if we're not in a batching mode or this was a commit.
// If records have been committed, notify our store delegate.
if (!batchWhiteboard.getInBatchingMode() || isCommit) {
- for (String guid : guids) {
- uploader.sessionStoreDelegate.onRecordStoreSucceeded(guid);
- }
+ uploader.sessionStoreDelegate.onRecordStoreSucceeded(recordsSucceeded);
// If we're not in a batching mode, or just committed a batch, uploaded records have
// been applied to the server storage and are now visible to other clients.
// Therefore, we bump our local "last store" timestamp.
bumpTimestampTo(uploadTimestamp, response.normalizedTimestampForHeader(SyncResponse.X_LAST_MODIFIED));
uploader.setLastStoreTimestamp(uploadTimestamp);
- batchWhiteboard.clearSuccessRecordGuids();
+ batchWhiteboard.clearSuccessRecordCounter();
}
if (isCommit || !batchWhiteboard.getInBatchingMode()) {
uploader.sessionStoreDelegate.onBatchCommitted();
}
// If this was our very last commit, we're done storing records.
// Get Last-Modified timestamp from the response, and pass it upstream.
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/uploaders/PayloadUploadDelegate.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/uploaders/PayloadUploadDelegate.java
@@ -136,24 +136,17 @@ class PayloadUploadDelegate implements S
success = body.getArray("success");
} catch (NonArrayJSONException e) {
handleRequestError(e);
return;
}
if (success != null && !success.isEmpty()) {
Logger.trace(LOG_TAG, "Successful records: " + success.toString());
- for (Object o : success) {
- try {
- dispatcher.batchWhiteboard.recordSucceeded((String) o);
- } catch (ClassCastException e) {
- Logger.error(LOG_TAG, "Got exception parsing POST success guid.", e);
- // Not much to be done.
- }
- }
+ dispatcher.batchWhiteboard.recordsSucceeded(success.size());
}
// GC
success = null;
ExtendedJSONObject failed;
try {
failed = body.getObject("failed");
} catch (NonObjectJSONException e) {
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/synchronizer/RecordsChannel.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/synchronizer/RecordsChannel.java
@@ -246,19 +246,19 @@ public class RecordsChannel implements
public void onRecordStoreFailed(Exception ex, String recordGuid) {
Logger.trace(LOG_TAG, "Failed to store record with guid " + recordGuid);
storeFailedCount.incrementAndGet();
storeTracker.onRecordStoreFailed();
delegate.onFlowStoreFailed(this, ex, recordGuid);
}
@Override
- public void onRecordStoreSucceeded(String guid) {
- storeAcceptedCount.incrementAndGet();
- storeTracker.onRecordStoreSucceeded();
+ public void onRecordStoreSucceeded(int count) {
+ storeAcceptedCount.addAndGet(count);
+ storeTracker.onRecordStoreSucceeded(count);
}
@Override
public void onRecordStoreReconciled(String guid, String oldGuid, Integer newVersion) {
storeReconciledCount.incrementAndGet();
}
@Override
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/synchronizer/StoreBatchTracker.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/synchronizer/StoreBatchTracker.java
@@ -62,18 +62,18 @@ public class StoreBatchTracker {
}
onBatchFinished();
}
/* package-local */ void onRecordStoreFailed() {
currentStoreBatchFailed.incrementAndGet();
}
- /* package-local */ void onRecordStoreSucceeded() {
- currentStoreBatchAccepted.incrementAndGet();
+ /* package-local */ void onRecordStoreSucceeded(int count) {
+ currentStoreBatchAccepted.addAndGet(count);
}
/* package-local */ void onRecordStoreAttempted() {
currentStoreBatchAttempted.incrementAndGet();
}
// Note that this finishes the current batch (if any exists).
/* package-local */ ArrayList<Batch> getStoreBatches() {
--- a/mobile/android/services/src/test/java/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionStoreDelegate.java
+++ b/mobile/android/services/src/test/java/org/mozilla/android/sync/test/helpers/ExpectSuccessRepositorySessionStoreDelegate.java
@@ -18,17 +18,17 @@ public class ExpectSuccessRepositorySess
@Override
public void onRecordStoreFailed(Exception ex, String guid) {
log("Record store failed.", ex);
performNotify(new AssertionFailedError("onRecordStoreFailed: record store should not have failed."));
}
@Override
- public void onRecordStoreSucceeded(String guid) {
+ public void onRecordStoreSucceeded(int count) {
log("Record store succeeded.");
}
@Override
public void onStoreCompleted() {
log("Record store completed");
}
--- a/mobile/android/services/src/test/java/org/mozilla/gecko/background/testhelpers/WBORepository.java
+++ b/mobile/android/services/src/test/java/org/mozilla/gecko/background/testhelpers/WBORepository.java
@@ -127,32 +127,32 @@ public class WBORepository extends Repos
if (stats.storeBegan < 0) {
stats.storeBegan = now;
}
Record existing = wbos.get(record.guid);
Logger.debug(LOG_TAG, "Existing record is " + (existing == null ? "<null>" : (existing.guid + ", " + existing)));
if (existing != null &&
existing.lastModified > record.lastModified) {
Logger.debug(LOG_TAG, "Local record is newer. Not storing.");
- storeDelegate.deferredStoreDelegate(delegateExecutor).onRecordStoreSucceeded(record.guid);
+ storeDelegate.deferredStoreDelegate(delegateExecutor).onRecordStoreSucceeded(1);
return;
}
if (existing != null) {
Logger.debug(LOG_TAG, "Replacing local record.");
}
// Store a copy of the record with an updated modified time.
Record toStore = record.copyWithIDs(record.guid, record.androidID);
if (bumpTimestamps) {
toStore.lastModified = now;
}
wbos.put(record.guid, toStore);
trackRecord(toStore);
- storeDelegate.deferredStoreDelegate(delegateExecutor).onRecordStoreSucceeded(record.guid);
+ storeDelegate.deferredStoreDelegate(delegateExecutor).onRecordStoreSucceeded(1);
}
@Override
public void wipe(final RepositorySessionWipeDelegate delegate) {
if (!isActive()) {
delegate.onWipeFailed(new InactiveSessionException());
return;
}
--- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/repositories/uploaders/BatchMetaTest.java
+++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/repositories/uploaders/BatchMetaTest.java
@@ -116,23 +116,16 @@ public class BatchMetaTest {
} catch (BatchingUploader.TokenModifiedException e) {
fail("Should be able to set token to null during onCommit set");
}
assertNull(batchMeta.getToken());
}
@Test
public void testRecordSucceeded() {
- assertEquals(0, batchMeta.getSuccessRecordGuids().length);
-
- batchMeta.recordSucceeded("guid1");
-
- assertEquals(1, batchMeta.getSuccessRecordGuids().length);
- assertEquals("guid1", batchMeta.getSuccessRecordGuids()[0]);
+ assertEquals(0, batchMeta.getSuccessRecordCount());
+ batchMeta.recordsSucceeded(1);
+ assertEquals(1, batchMeta.getSuccessRecordCount());
- try {
- batchMeta.recordSucceeded(null);
- fail();
- } catch (IllegalStateException e) {
- assertTrue("Should not be able to 'succeed' a null guid", true);
- }
+ batchMeta.recordsSucceeded(12);
+ assertEquals(13, batchMeta.getSuccessRecordCount());
}
}
\ No newline at end of file
--- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/repositories/uploaders/BatchingUploaderTest.java
+++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/repositories/uploaders/BatchingUploaderTest.java
@@ -136,18 +136,18 @@ public class BatchingUploaderTest {
@Override
public void onRecordStoreFailed(Exception ex, String recordGuid) {
lastRecordStoreFailedException = ex;
++storeFailed;
}
@Override
- public void onRecordStoreSucceeded(String guid) {
- ++recordStoreSucceeded;
+ public void onRecordStoreSucceeded(int count) {
+ recordStoreSucceeded += count;
}
@Override
public void onStoreCompleted() {
++storeCompleted;
}
@Override
--- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/repositories/uploaders/PayloadUploadDelegateTest.java
+++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/repositories/uploaders/PayloadUploadDelegateTest.java
@@ -58,20 +58,20 @@ public class PayloadUploadDelegateTest {
public int committedGuids = 0;
public MockPayloadDispatcher(final Executor workQueue, final BatchingUploader uploader) {
super(workQueue, uploader, null);
}
@Override
public void payloadSucceeded(final SyncStorageResponse response, final boolean isCommit, final boolean isLastPayload) {
- final String[] guids = batchWhiteboard.getSuccessRecordGuids();
+ final int successCount = batchWhiteboard.getSuccessRecordCount();
successResponses.add(response);
if (!batchWhiteboard.getInBatchingMode() || isCommit) {
- committedGuids += guids.length;
+ committedGuids += successCount;
}
if (isCommit) {
++commitPayloadsSucceeded;
}
if (isLastPayload) {
++lastPayloadsSucceeded;
}
super.payloadSucceeded(response, isCommit, isLastPayload);
@@ -91,27 +91,27 @@ public class PayloadUploadDelegateTest {
public void payloadFailed(Exception e) {
didPayloadFail = true;
super.payloadFailed(e);
}
}
class MockRepositorySessionStoreDelegate implements RepositorySessionStoreDelegate {
Exception storeFailedException;
- ArrayList<String> succeededGuids = new ArrayList<>();
+ int successCount = 0;
HashMap<String, Exception> failedGuids = new HashMap<>();
@Override
public void onRecordStoreFailed(Exception ex, String recordGuid) {
failedGuids.put(recordGuid, ex);
}
@Override
- public void onRecordStoreSucceeded(String guid) {
- succeededGuids.add(guid);
+ public void onRecordStoreSucceeded(int count) {
+ successCount = count;
}
@Override
public void onStoreCompleted() {}
@Override
public void onStoreFailed(Exception e) {
storeFailedException = e;
--- a/mobile/android/services/src/test/java/org/mozilla/gecko/sync/synchronizer/StoreBatchTrackerTest.java
+++ b/mobile/android/services/src/test/java/org/mozilla/gecko/sync/synchronizer/StoreBatchTrackerTest.java
@@ -21,19 +21,17 @@ public class StoreBatchTrackerTest {
public void setUp() throws Exception {
tracker = new StoreBatchTracker();
}
private void recordCounts(int attempted, int succeeded, int failed) {
for (int i = 0; i < attempted; ++i) {
tracker.onRecordStoreAttempted();
}
- for (int i = 0; i < succeeded; ++i) {
- tracker.onRecordStoreSucceeded();
- }
+ tracker.onRecordStoreSucceeded(succeeded);
for (int i = 0; i < failed; ++i) {
tracker.onRecordStoreFailed();
}
}
@Test
public void testSingleBatch() {
{