TODOs: Faster Start and Restart
The app has been noticeably slow to start up and restart on occasion.
Reason 1: Cannot connect to cloud syncbase to set up its database.
- A shorter timeout alleviates this issue. In the long run, we don't
have to do this in the app, anyway.
Reason 2: Thread.sleep instead of delayed scheduling of syncgroup join
- If the app ever has lists it could not join, Thread.sleep would
delay every single join attempt by 2 seconds. This stacks up fast.
Further, all the work was done on the UI thread, which froze the UI.
- The problem was made a little worse by the cross user collection
sharing bug.
Change-Id: I4c98e877c1b94cfaf1f9ef84be814c8a13dc5ff5
diff --git a/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbaseMain.java b/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbaseMain.java
index e0f8479..d487d33 100644
--- a/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbaseMain.java
+++ b/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbaseMain.java
@@ -10,6 +10,7 @@
import android.util.Log;
import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
@@ -18,6 +19,7 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
@@ -82,24 +84,25 @@
mIdGenerator.registerId(change.getRowName().substring(LISTS_PREFIX.length()));
Log.d(TAG, "Found a list id from userdata watch: " + listId);
- // TODO(alexfandrianto): Exponential backoff on joining this list syncgroup.
- Futures.addCallback(joinListSyncgroup(listId),
- new TrappingCallback<SyncgroupSpec>(getErrorReporter()) {
- @Override
- public void onFailure(@NonNull Throwable t) {
- if (t instanceof SyncgroupJoinFailedException) {
- // Let's try again...
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {}
+ Futures.catchingAsync(joinListSyncgroup(listId),
+ SyncgroupJoinFailedException.class, new
+ AsyncFunction<SyncgroupJoinFailedException, SyncgroupSpec>() {
+ public ListenableFuture<SyncgroupSpec> apply(@Nullable
+ SyncgroupJoinFailedException
+ input) throws
+ Exception {
+ Log.d(TAG, "Join failed. Sleeping and trying again: " + listId);
+ return sExecutor.schedule(new Callable<SyncgroupSpec>() {
+ @Override
+ public SyncgroupSpec call() throws Exception {
+ Log.d(TAG, "Sleep done. Trying again: " + listId);
- // If this errors, then we will not get another chance to see this
- // syncgroup until the app is restarted.
- trap(joinListSyncgroup(listId));
- } else {
- super.onFailure(t);
- }
+ // If this errors, then we will not get another chance to see
+ // this syncgroup until the app is restarted.
+ return joinListSyncgroup(listId).get();
+ }
+ }, RETRY_DELAY, TimeUnit.MILLISECONDS);
}
});
diff --git a/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbasePersistence.java b/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbasePersistence.java
index c8680ed..4ca22e7 100644
--- a/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbasePersistence.java
+++ b/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbasePersistence.java
@@ -19,10 +19,12 @@
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.ListeningScheduledExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
+import org.joda.time.Duration;
+
import java.io.File;
import java.util.concurrent.Executors;
@@ -76,6 +78,9 @@
LIST_COLLECTION_SYNCGROUP_SUFFIX = "/%%sync/list_",
DEFAULT_BLESSING_STRING = "dev.v.io:o:608941808256-43vtfndets79kf5hac8ieujto8837660" +
".apps.googleusercontent.com:";
+ protected static final long
+ SHORT_TIMEOUT = 2500,
+ RETRY_DELAY = 2000;
public static final String
USER_COLLECTION_NAME = "userdata",
MOUNTPOINT = "/ns.dev.v.io:8101/tmp/todos/users/",
@@ -93,8 +98,8 @@
}
});
- protected static final ListeningExecutorService sExecutor =
- MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
+ protected static final ListeningScheduledExecutorService sExecutor =
+ MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(10));
private static final Object sSyncbaseMutex = new Object();
private static VContext sVContext;
@@ -247,7 +252,8 @@
SyncbaseService cloudService = Syncbase.newService(CLOUD_NAME);
Database db = cloudService.getDatabase(sVContext, DATABASE, null);
try {
- VFutures.sync(db.create(sVContext, null));
+ VFutures.sync(db.create(sVContext.withTimeout(Duration.millis(SHORT_TIMEOUT))
+ , null));
} catch (ExistException e) {
// This is acceptable. No need to do it again.
} catch (Exception e) {
@@ -427,6 +433,7 @@
}
});
}
+
VFutures.sync(Futures.dereference(blessings));
ensureSyncbaseStarted(activity);
ensureDatabaseExists();