Bug 1253111 - WIP Part 3: Introduce BatchingAtomicUploader and use it when server supports batching mode r=rnewman
MozReview-Commit-ID: 3RozuZkWE4R
--- a/mobile/android/base/android-services.mozbuild
+++ b/mobile/android/base/android-services.mozbuild
@@ -1009,16 +1009,18 @@ sync_java_files = [TOPSRCDIR + '/mobile/
'sync/repositories/Repository.java',
'sync/repositories/RepositorySession.java',
'sync/repositories/RepositorySessionBundle.java',
'sync/repositories/Server11Repository.java',
'sync/repositories/Server11RepositorySession.java',
'sync/repositories/StoreFailedException.java',
'sync/repositories/StoreTracker.java',
'sync/repositories/StoreTrackingRepositorySession.java',
+ 'sync/repositories/uploaders/BatchingAtomicUploader.java',
+ 'sync/repositories/uploaders/BatchingAtomicUploaderDelegate.java',
'sync/repositories/uploaders/MayUploadProvider.java',
'sync/repositories/uploaders/RecordUploader.java',
'sync/repositories/uploaders/RecordUploadRunnable.java',
'sync/repositories/uploaders/ServerUploader.java',
'sync/repositories/uploaders/UnsafeBatchingUploader.java',
'sync/Server11PreviousPostFailedException.java',
'sync/Server11RecordPostFailedException.java',
'sync/setup/activities/ActivityUtils.java',
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/MozResponse.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/MozResponse.java
@@ -38,17 +38,17 @@ public class MozResponse {
return this.response;
}
public int getStatusCode() {
return this.response.getStatusLine().getStatusCode();
}
public boolean wasSuccessful() {
- return this.getStatusCode() == 200;
+ return this.getStatusCode() == 200 || this.getStatusCode() == 202;
}
public boolean isInvalidAuthentication() {
return this.getStatusCode() == HttpStatus.SC_UNAUTHORIZED;
}
/**
* Fetch the content type of the HTTP response body.
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/ConstrainedServer11Repository.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/ConstrainedServer11Repository.java
@@ -2,31 +2,32 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.sync.repositories;
import java.net.URISyntaxException;
import org.mozilla.gecko.sync.InfoCollections;
+import org.mozilla.gecko.sync.InfoConfiguration;
import org.mozilla.gecko.sync.net.AuthHeaderProvider;
/**
* A kind of Server11Repository that supports explicit setting of limit and sort on operations.
*
* @author rnewman
*
*/
public class ConstrainedServer11Repository extends Server11Repository {
private String sort = null;
private long limit = -1;
- public ConstrainedServer11Repository(String collection, String storageURL, AuthHeaderProvider authHeaderProvider, InfoCollections infoCollections, long limit, String sort) throws URISyntaxException {
- super(collection, storageURL, authHeaderProvider, infoCollections);
+ public ConstrainedServer11Repository(String collection, String storageURL, AuthHeaderProvider authHeaderProvider, InfoCollections infoCollections, InfoConfiguration infoConfiguration, long limit, String sort) throws URISyntaxException {
+ super(collection, storageURL, authHeaderProvider, infoCollections, infoConfiguration);
this.limit = limit;
this.sort = sort;
}
@Override
protected String getDefaultSort() {
return sort;
}
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/Server11Repository.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/Server11Repository.java
@@ -4,57 +4,62 @@
package org.mozilla.gecko.sync.repositories;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import org.mozilla.gecko.sync.InfoCollections;
+import org.mozilla.gecko.sync.InfoConfiguration;
import org.mozilla.gecko.sync.Utils;
import org.mozilla.gecko.sync.net.AuthHeaderProvider;
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
import android.content.Context;
+import android.support.annotation.NonNull;
/**
* A Server11Repository implements fetching and storing against the Sync 1.1 API.
* It doesn't do crypto: that's the job of the middleware.
*
* @author rnewman
*/
public class Server11Repository extends Repository {
protected String collection;
protected URI collectionURI;
protected final AuthHeaderProvider authHeaderProvider;
protected final InfoCollections infoCollections;
+ private final InfoConfiguration infoConfiguration;
+
/**
* Construct a new repository that fetches and stores against the Sync 1.1. API.
*
* @param collection name.
* @param storageURL full URL to storage endpoint.
* @param authHeaderProvider to use in requests; may be null.
* @param infoCollections instance; must not be null.
* @throws URISyntaxException
*/
- public Server11Repository(String collection, String storageURL, AuthHeaderProvider authHeaderProvider, InfoCollections infoCollections) throws URISyntaxException {
+ public Server11Repository(@NonNull String collection, @NonNull String storageURL, AuthHeaderProvider authHeaderProvider, @NonNull InfoCollections infoCollections, @NonNull InfoConfiguration infoConfiguration) throws URISyntaxException {
if (collection == null) {
throw new IllegalArgumentException("collection must not be null");
}
if (storageURL == null) {
throw new IllegalArgumentException("storageURL must not be null");
}
if (infoCollections == null) {
throw new IllegalArgumentException("infoCollections must not be null");
}
this.collection = collection;
this.collectionURI = new URI(storageURL + (storageURL.endsWith("/") ? collection : "/" + collection));
this.authHeaderProvider = authHeaderProvider;
this.infoCollections = infoCollections;
+ this.infoConfiguration = infoConfiguration;
}
@Override
public void createSession(RepositorySessionCreationDelegate delegate,
Context context) {
delegate.onSessionCreated(new Server11RepositorySession(this));
}
@@ -114,9 +119,13 @@ public class Server11Repository extends
public AuthHeaderProvider getAuthHeaderProvider() {
return authHeaderProvider;
}
public boolean updateNeeded(long lastSyncTimestamp) {
return infoCollections.updateNeeded(collection, lastSyncTimestamp);
}
+
+ public InfoConfiguration getInfoConfiguration() {
+ return infoConfiguration;
+ }
}
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/Server11RepositorySession.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/Server11RepositorySession.java
@@ -20,16 +20,17 @@ import org.mozilla.gecko.sync.net.SyncSt
import org.mozilla.gecko.sync.net.SyncStorageResponse;
import org.mozilla.gecko.sync.net.WBOCollectionRequestDelegate;
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionGuidsSinceDelegate;
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
import org.mozilla.gecko.sync.repositories.domain.Record;
import org.mozilla.gecko.sync.repositories.uploaders.RecordUploader;
+import org.mozilla.gecko.sync.repositories.uploaders.BatchingAtomicUploader;
import org.mozilla.gecko.sync.repositories.uploaders.ServerUploader;
import org.mozilla.gecko.sync.repositories.uploaders.UnsafeBatchingUploader;
public class Server11RepositorySession extends RepositorySession {
public static final String LOG_TAG = "Server11Session";
/**
* Used to track outstanding requests, so that we can abort them as needed.
@@ -157,17 +158,21 @@ public class Server11RepositorySession e
}
@Override
public void setStoreDelegate(RepositorySessionStoreDelegate delegate) {
Logger.debug(LOG_TAG, "Setting store delegate to " + delegate);
this.delegate = delegate;
// Now that we have the delegate, we can initialize our uploader.
+ if (serverRepository.getInfoConfiguration().isBatchingModeSupported()) {
+ uploader = new BatchingAtomicUploader(this, storeWorkQueue, delegate);
+ } else {
uploader = new UnsafeBatchingUploader(this, storeWorkQueue, delegate);
+ }
}
private String flattenIDs(String[] guids) {
// Consider using Utils.toDelimitedString if and when the signature changes
// to Collection<String> guids.
if (guids.length == 0) {
return "";
}
new file mode 100644
--- /dev/null
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/uploaders/BatchingAtomicUploader.java
@@ -0,0 +1,162 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.sync.repositories.uploaders;
+
+import android.net.Uri;
+
+import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.sync.ExtendedJSONObject;
+import org.mozilla.gecko.sync.InfoConfiguration;
+import org.mozilla.gecko.sync.Server11RecordPostFailedException;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
+import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
+import org.mozilla.gecko.sync.net.SyncStorageResponse;
+import org.mozilla.gecko.sync.repositories.Server11RepositorySession;
+import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
+import org.mozilla.gecko.sync.repositories.domain.Record;
+
+import java.lang.reflect.Array;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * Uploader which implements batching semantics introduced in Sync 1.5.
+ *
+ * Records are uploaded in batches according to limits defined in InfoConfiguration object.
+ * Batch ID is returned once first post succeeds, and is maintained across uploads, to ensure our
+ * uploads are grouped together. Last batch commits the series (with commit=true GET param).
+ *
+ * Last-Modified header returned with the first post success is maintained across uploads, to guard
+ * against concurrent-modification errors (different uploader commits before we're done).
+ */
+public class BatchingAtomicUploader extends RecordUploader {
+ private static final String LOG_TAG = "BatchingAtomicUploader";
+
+ private static final String QUERY_PARAM_BATCH = "batch";
+ private static final String QUERY_PARAM_TRUE = "true";
+ private static final String QUERY_PARAM_BATCH_COMMIT = "commit";
+
+ private final InfoConfiguration configuration;
+ private final Uri collectionUri;
+
+ // These will be set after a first response from the server.
+ private Integer batchId;
+ private String lastModified;
+
+ private final ArrayList<String> successRecordGuids = new ArrayList<>();
+ private final ArrayList<String> failedRecordGuids = new ArrayList<>();
+
+ public BatchingAtomicUploader(final Server11RepositorySession repositorySession, final ExecutorService workQueue, final RepositorySessionStoreDelegate sessionStoreDelegate) {
+ super(repositorySession, workQueue, sessionStoreDelegate);
+ configuration = repositorySession.getServerRepository().getInfoConfiguration();
+ collectionUri = Uri.parse(repositorySession.getServerRepository().collectionURI().toString());
+ }
+
+ @Override
+ public void flushRecords(final boolean lastBatch) {
+ flush(batchId, lastBatch);
+ }
+
+ @Override
+ public boolean shouldFlush(final int delta, final int byteCount, final ArrayList<byte[]> recordsBuffer) {
+ return (delta + byteCount > configuration.getRequestLimitValue(InfoConfiguration.MAX_POST_BYTES)) ||
+ (recordsBuffer.size() >= configuration.getRequestLimitValue(InfoConfiguration.MAX_POST_RECORDS));
+ }
+
+ private void flush(final Integer batchId, final boolean isLastBatch) {
+ final Uri.Builder uriBuilder = collectionUri.buildUpon();
+
+ if (batchId != null) {
+ uriBuilder.appendQueryParameter(QUERY_PARAM_BATCH, batchId.toString());
+ } else {
+ uriBuilder.appendQueryParameter(QUERY_PARAM_BATCH, QUERY_PARAM_TRUE);
+ }
+
+ if (isLastBatch) {
+ uriBuilder.appendQueryParameter(QUERY_PARAM_BATCH_COMMIT, QUERY_PARAM_TRUE);
+ }
+
+ final URI uriToPost;
+ try {
+ uriToPost = new URI(uriBuilder.build().toString());
+ // Should never happen, Uri.Builder should produce a well-formed URI.
+ } catch (URISyntaxException e) {
+ throw new IllegalArgumentException("Could not create URI for posting a batch, bailing.");
+ }
+
+ final ArrayList<byte[]> outgoing = recordsBuffer;
+ final ArrayList<String> outgoingGuids = recordGuidsBuffer;
+
+ // TODO is there any chance of leaking BatchingAtomicUploaderDelegate through a runnable which could significantly outlive this uploader?
+ workQueue.execute(new RecordUploadRunnable(
+ new BatchingAtomicUploaderMayUploadProvider(),
+ uriToPost,
+ new BatchingAtomicUploaderDelegate(this, outgoingGuids, isLastBatch),
+ outgoing,
+ byteCount
+ ));
+
+ recordsBuffer = new ArrayList<>();
+ recordGuidsBuffer = new ArrayList<>();
+ byteCount = PER_BATCH_OVERHEAD;
+ }
+
+ /**
+ * We've been told by our delegate that our whole batch succeeded. Let's inform store delegate.
+ * @param response success response to our commit post
+ */
+ public void lastBatchSucceeded(final SyncStorageResponse response) {
+ final long normalizedTimestamp = getNormalizedTimestamp(LOG_TAG, response);
+ Logger.trace(LOG_TAG, "Passing back upload X-Weave-Timestamp: " + normalizedTimestamp);
+ bumpUploadTimestamp(normalizedTimestamp);
+
+ for (String guid : successRecordGuids) {
+ sessionStoreDelegate.onRecordStoreSucceeded(guid);
+ }
+ }
+
+ public synchronized Integer getBatchId() {
+ return batchId;
+ }
+
+ public synchronized void setBatchId(Integer batchId) {
+ this.batchId = batchId;
+ }
+
+ public synchronized String getLastModified() {
+ return lastModified;
+ }
+
+ public synchronized void setLastModified(final String lastModified) {
+ this.lastModified = lastModified;
+ }
+
+ public synchronized void recordSucceeded(final String recordGuid) {
+ successRecordGuids.add(recordGuid);
+ }
+
+ public synchronized void recordFailed(final String recordGuid) {
+ recordFailed(new Server11RecordPostFailedException(), recordGuid);
+ }
+
+ public synchronized void recordFailed(final Exception e, final String recordGuid) {
+ // TODO should we keep track of these records?
+ // can we recover from this at all, without bailing out of syncing this stage?
+ sessionStoreDelegate.onRecordStoreFailed(e, recordGuid);
+ }
+
+ public Server11RepositorySession getRepositorySession() {
+ return repositorySession;
+ }
+
+ // TODO keep track of any failed batches, and probably cascade-fail the rest
+ private class BatchingAtomicUploaderMayUploadProvider implements MayUploadProvider {
+ public boolean mayUpload() {
+ return true;
+ }
+ }
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/uploaders/BatchingAtomicUploaderDelegate.java
@@ -0,0 +1,167 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.sync.repositories.uploaders;
+
+import org.json.simple.JSONArray;
+import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.sync.ExtendedJSONObject;
+import org.mozilla.gecko.sync.HTTPFailureException;
+import org.mozilla.gecko.sync.NonArrayJSONException;
+import org.mozilla.gecko.sync.NonObjectJSONException;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
+import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
+import org.mozilla.gecko.sync.net.SyncStorageResponse;
+
+import java.util.ArrayList;
+
+public class BatchingAtomicUploaderDelegate implements SyncStorageRequestDelegate {
+ private static final String LOG_TAG = "BatchingAtomicUploaderDelegate";
+
+ private static final String X_LAST_MODIFIED = "X-Last-Modified";
+ private static final String KEY_BATCH = "batch";
+
+ private final BatchingAtomicUploader uploader;
+ private final ArrayList<String> postedRecordGuids;
+ private final boolean isLastBatch;
+
+ public BatchingAtomicUploaderDelegate(final BatchingAtomicUploader uploader, final ArrayList<String> postedRecordGuids, final boolean isLastBatch) {
+ this.uploader = uploader;
+ this.postedRecordGuids = postedRecordGuids;
+ this.isLastBatch = isLastBatch;
+ }
+
+ @Override
+ public AuthHeaderProvider getAuthHeaderProvider() {
+ return uploader.getRepositorySession().getServerRepository().getAuthHeaderProvider();
+ }
+
+ @Override
+ public String ifUnmodifiedSince() {
+ return uploader.getLastModified();
+ }
+
+ @Override
+ public void handleRequestSuccess(final SyncStorageResponse response) {
+ if (response.getStatusCode() != 202) {
+ handleRequestError(
+ new IllegalStateException("Received non-202 success code while in batching mode")
+ );
+ return;
+ }
+
+ if (!response.httpResponse().containsHeader(X_LAST_MODIFIED)) {
+ handleRequestError(
+ new IllegalStateException("Response did not have a Last-Modified header")
+ );
+ return;
+ }
+
+ final ExtendedJSONObject body;
+ try {
+ body = response.jsonObjectBody(); // jsonObjectBody() throws or returns non-null.
+ } catch (Exception e) {
+ Logger.error(LOG_TAG, "Got exception parsing POST success body.", e);
+ this.handleRequestError(e);
+ return;
+ }
+
+ if (!body.containsKey(KEY_BATCH)) {
+ handleRequestError(
+ new IllegalStateException("Response did not have a batch ID")
+ );
+ return;
+ }
+
+ final Integer currentBatchId = uploader.getBatchId();
+ final Integer newBatchId = body.getIntegerSafely(KEY_BATCH);
+
+ if (currentBatchId == null) {
+ uploader.setBatchId(newBatchId);
+
+ } else if (!currentBatchId.equals(newBatchId)) {
+ handleRequestError(
+ new IllegalStateException("Response had a batch ID different from previous responses")
+ );
+ return;
+ }
+
+ final String currentLastModified = uploader.getLastModified();
+ final String newLastModified = response.httpResponse().getFirstHeader(X_LAST_MODIFIED).getValue();
+
+ if (currentLastModified == null) {
+ uploader.setLastModified(newLastModified);
+
+ } else if (!isLastBatch && !currentLastModified.equals(newLastModified)) {
+ handleRequestError(
+ new IllegalStateException("Last-Modified timestamp changed mid-way through the batch")
+ );
+ return;
+
+ } else if (isLastBatch && currentLastModified.equals(newLastModified)) {
+ handleRequestError(
+ new IllegalStateException("Last-Modified timestamp didn't change after committing")
+ );
+ return;
+ }
+
+ // All looks good up to this point, let's process success/failed arrays now
+
+ JSONArray success;
+ try {
+ success = body.getArray("success");
+ } catch (NonArrayJSONException e) {
+ handleRequestError(e);
+ return;
+ }
+
+ if (success != null && success.size() > 0) {
+ Logger.trace(LOG_TAG, "Successful records: " + success.toString());
+ for (Object o : success) {
+ try {
+ uploader.recordSucceeded((String) o);
+ } catch (ClassCastException e) {
+ Logger.error(LOG_TAG, "Got exception parsing POST success guid.", e);
+ // Not much to be done.
+
+ // TODO this feels off. We should handle this type of validation explicitely.
+ // TODO should we pass these types of errors to handleRequestError?
+ }
+ }
+ }
+ success = null;
+
+ ExtendedJSONObject failed;
+ try {
+ failed = body.getObject("failed");
+ } catch (NonObjectJSONException e) {
+ handleRequestError(e);
+ return;
+ }
+
+ if (failed != null && failed.object.size() > 0) {
+ Logger.debug(LOG_TAG, "Failed records: " + failed.object.toString());
+ for (String guid : failed.keySet()) {
+ uploader.recordFailed(guid);
+ }
+ }
+ failed = null;
+
+ if (isLastBatch) {
+ uploader.lastBatchSucceeded(response);
+ }
+ }
+
+ @Override
+ public void handleRequestFailure(final SyncStorageResponse response) {
+ this.handleRequestError(new HTTPFailureException(response));
+ }
+
+ @Override
+ public void handleRequestError(Exception e) {
+ for (String guid : postedRecordGuids) {
+ uploader.recordFailed(e, guid);
+ }
+ }
+}
\ No newline at end of file
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/AndroidBrowserBookmarksServerSyncStage.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/AndroidBrowserBookmarksServerSyncStage.java
@@ -45,16 +45,17 @@ public class AndroidBrowserBookmarksServ
AuthHeaderProvider authHeaderProvider = session.getAuthHeaderProvider();
final JSONRecordFetcher countsFetcher = new JSONRecordFetcher(session.config.infoCollectionCountsURL(), authHeaderProvider);
String collection = getCollection();
return new SafeConstrainedServer11Repository(
collection,
session.config.storageURL(),
session.getAuthHeaderProvider(),
session.config.infoCollections,
+ session.config.infoConfiguration,
BOOKMARKS_REQUEST_LIMIT,
BOOKMARKS_SORT,
countsFetcher);
}
@Override
protected Repository getLocalRepository() {
return new AndroidBrowserBookmarksRepository();
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/AndroidBrowserHistoryServerSyncStage.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/AndroidBrowserHistoryServerSyncStage.java
@@ -45,16 +45,17 @@ public class AndroidBrowserHistoryServer
@Override
protected Repository getRemoteRepository() throws URISyntaxException {
String collection = getCollection();
return new ConstrainedServer11Repository(
collection,
session.config.storageURL(),
session.getAuthHeaderProvider(),
session.config.infoCollections,
+ session.config.infoConfiguration,
HISTORY_REQUEST_LIMIT,
HISTORY_SORT);
}
@Override
protected RecordFactory getRecordFactory() {
return new HistoryRecordFactory();
}
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/FormHistoryServerSyncStage.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/FormHistoryServerSyncStage.java
@@ -40,16 +40,17 @@ public class FormHistoryServerSyncStage
@Override
protected Repository getRemoteRepository() throws URISyntaxException {
String collection = getCollection();
return new ConstrainedServer11Repository(
collection,
session.config.storageURL(),
session.getAuthHeaderProvider(),
session.config.infoCollections,
+ session.config.infoConfiguration,
FORM_HISTORY_REQUEST_LIMIT,
FORM_HISTORY_SORT);
}
@Override
protected Repository getLocalRepository() {
return new FormHistoryRepositorySession.FormHistoryRepository();
}
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/SafeConstrainedServer11Repository.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/SafeConstrainedServer11Repository.java
@@ -3,16 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.sync.stage;
import java.net.URISyntaxException;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.sync.InfoCollections;
+import org.mozilla.gecko.sync.InfoConfiguration;
import org.mozilla.gecko.sync.InfoCounts;
import org.mozilla.gecko.sync.JSONRecordFetcher;
import org.mozilla.gecko.sync.net.AuthHeaderProvider;
import org.mozilla.gecko.sync.repositories.ConstrainedServer11Repository;
import org.mozilla.gecko.sync.repositories.Repository;
import org.mozilla.gecko.sync.repositories.Server11RepositorySession;
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
@@ -32,21 +33,22 @@ public class SafeConstrainedServer11Repo
// This can be lazily evaluated if we need it.
private final JSONRecordFetcher countFetcher;
public SafeConstrainedServer11Repository(String collection,
String storageURL,
AuthHeaderProvider authHeaderProvider,
InfoCollections infoCollections,
+ InfoConfiguration infoConfiguration,
long limit,
String sort,
JSONRecordFetcher countFetcher)
throws URISyntaxException {
- super(collection, storageURL, authHeaderProvider, infoCollections, limit, sort);
+ super(collection, storageURL, authHeaderProvider, infoCollections, infoConfiguration, limit, sort);
if (countFetcher == null) {
throw new IllegalArgumentException("countFetcher must not be null");
}
this.countFetcher = countFetcher;
}
@Override
public void createSession(RepositorySessionCreationDelegate delegate,
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/ServerSyncStage.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/ServerSyncStage.java
@@ -140,17 +140,18 @@ public abstract class ServerSyncStage ex
protected abstract RecordFactory getRecordFactory();
// Override this in subclasses.
protected Repository getRemoteRepository() throws URISyntaxException {
String collection = getCollection();
return new Server11Repository(collection,
session.config.storageURL(),
session.getAuthHeaderProvider(),
- session.config.infoCollections);
+ session.config.infoCollections,
+ session.config.infoConfiguration);
}
/**
* Return a Crypto5Middleware-wrapped Server11Repository.
*
* @throws NoCollectionKeysSetException
* @throws URISyntaxException
*/