Bug 724739 - Part 3: invoke store callback on deletion. r=nalexander
authorRichard Newman <rnewman@mozilla.com>
Tue, 10 Apr 2012 23:21:51 -0700
changeset 94720 3aef4f7cbd6d00d0d7e77b71f3e6045c74280166
parent 94719 1c2a06f36ba3868f7ce9cd1dcf3b21007e425a2e
child 94721 6cb5a238e20d79a6a72ebe201d52120413e87ba2
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnalexander
bugs724739
milestone14.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 724739 - Part 3: invoke store callback on deletion. r=nalexander
mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java
mobile/android/base/sync/repositories/android/BookmarksDeletionManager.java
mobile/android/base/sync/repositories/delegates/RepositorySessionStoreDelegate.java
--- a/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java
+++ b/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java
@@ -19,16 +19,17 @@ import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
 import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.NoGuidForIdException;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.ParentNotFoundException;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
+import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
 import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
 import android.content.Context;
 import android.database.Cursor;
 
 public class AndroidBrowserBookmarksRepositorySession extends AndroidBrowserRepositorySession {
@@ -559,16 +560,25 @@ public class AndroidBrowserBookmarksRepo
 
       // TODO: handling of failed reparenting.
       // E.g., delegate.onFinishFailed(new BookmarkNeedsReparentingException(null));
     }
     super.finish(delegate);
   };
 
   @Override
+  public void setStoreDelegate(RepositorySessionStoreDelegate delegate) {
+    super.setStoreDelegate(delegate);
+
+    if (deletionManager != null) {
+      deletionManager.setDelegate(delegate);
+    }
+  }
+
+  @Override
   protected Record reconcileRecords(Record remoteRecord, Record localRecord,
                                     long lastRemoteRetrieval,
                                     long lastLocalRetrieval) {
 
     BookmarkRecord reconciled = (BookmarkRecord) super.reconcileRecords(remoteRecord, localRecord,
                                                                         lastRemoteRetrieval,
                                                                         lastLocalRetrieval);
 
--- a/mobile/android/base/sync/repositories/android/BookmarksDeletionManager.java
+++ b/mobile/android/base/sync/repositories/android/BookmarksDeletionManager.java
@@ -6,16 +6,17 @@ package org.mozilla.gecko.sync.repositor
 
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
+import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
 import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
 
 /**
  * Queue up deletions. Process them at the end.
  *
  * Algorithm:
  *
  * * Collect GUIDs as we go. For convenience we partition these into
@@ -44,16 +45,18 @@ import org.mozilla.gecko.sync.repositori
  * Note that this class is not thread safe. This should be fine: call it only
  * from within a store runnable.
  *
  */
 public class BookmarksDeletionManager {
   private static final String LOG_TAG = "BookmarkDelete";
 
   private final AndroidBrowserBookmarksDataAccessor dataAccessor;
+  private RepositorySessionStoreDelegate delegate;
+
   private final int flushThreshold;
 
   private final HashSet<String> folders    = new HashSet<String>();
   private final HashSet<String> nonFolders = new HashSet<String>();
   private int nonFolderCount = 0;
 
   // Records that we need to touch once we've deleted the non-folders.
   private HashSet<String> nonFolderParents = new HashSet<String>();
@@ -70,16 +73,26 @@ public class BookmarksDeletionManager {
    *        When this many non-folder records have been stored for deletion,
    *        an incremental flush occurs.
    */
   public BookmarksDeletionManager(AndroidBrowserBookmarksDataAccessor dataAccessor, int flushThreshold) {
     this.dataAccessor = dataAccessor;
     this.flushThreshold = flushThreshold;
   }
 
+  /**
+   * Set the delegate to use for callbacks.
+   * If not invoked, no callbacks will be submitted.
+   *
+   * @param delegate a delegate, which should already be a delayed delegate.
+   */
+  public void setDelegate(RepositorySessionStoreDelegate delegate) {
+    this.delegate = delegate;
+  }
+
   public void deleteRecord(BookmarkRecord r, boolean isFolder) {
     if (r.guid == null) {
       Logger.warn(LOG_TAG, "Cannot queue deletion of record with no GUID.");
       return;
     }
     Logger.debug(LOG_TAG, "Queuing deletion of " + r.guid);
 
     if (isFolder) {
@@ -142,16 +155,17 @@ public class BookmarksDeletionManager {
       if (moved > 0) {
         dataAccessor.bumpModified(orphanDestination, now);
       }
 
       // We've deleted or moved anything that might be under these folders.
       // Just delete them.
       final String folderWhere = RepoUtils.computeSQLInClause(folders.size(), BrowserContract.Bookmarks.GUID);
       dataAccessor.delete(folderWhere, folderGUIDs);
+      invokeCallbacks(delegate, folderGUIDs);
 
       folderParents.removeAll(folders);
       Logger.debug(LOG_TAG, "Bumping modified times for " + folderParents.size() +
                             " parents of deleted folders.");
       dataAccessor.bumpModifiedByGUID(folderParents, now);
 
       // Clean up.
       folders.clear();
@@ -189,22 +203,38 @@ public class BookmarksDeletionManager {
       return;
     }
 
     Logger.debug(LOG_TAG, "Applying deletion of " + nonFolderCount + " non-folders.");
     final String[] nonFolderGUIDs = nonFolders.toArray(new String[nonFolderCount]);
     final String nonFolderWhere = RepoUtils.computeSQLInClause(nonFolderCount, BrowserContract.Bookmarks.GUID);
     dataAccessor.delete(nonFolderWhere, nonFolderGUIDs);
 
+    invokeCallbacks(delegate, nonFolderGUIDs);
+
     // Discard these.
     // Note that we maintain folderParents and nonFolderParents; we need them later.
     nonFolders.clear();
     nonFolderCount = 0;
   }
 
+  private void invokeCallbacks(RepositorySessionStoreDelegate delegate,
+                               String[] nonFolderGUIDs) {
+    if (delegate == null) {
+      return;
+    }
+    Logger.trace(LOG_TAG, "Invoking store callback for " + nonFolderGUIDs.length + " GUIDs.");
+    final long now = System.currentTimeMillis();
+    BookmarkRecord r = new BookmarkRecord(null, "bookmarks", now, true);
+    for (String guid : nonFolderGUIDs) {
+      r.guid = guid;
+      delegate.onRecordStoreSucceeded(r);
+    }
+  }
+
   /**
    * Clear state in case of redundancy (e.g., wipe).
    */
   public void clear() {
     nonFolders.clear();
     nonFolderCount = 0;
     folders.clear();
     nonFolderParents.clear();
--- a/mobile/android/base/sync/repositories/delegates/RepositorySessionStoreDelegate.java
+++ b/mobile/android/base/sync/repositories/delegates/RepositorySessionStoreDelegate.java
@@ -45,12 +45,15 @@ import org.mozilla.gecko.sync.repositori
  * These methods *must* be invoked asynchronously. Use deferredStoreDelegate if you
  * need help doing this.
  *
  * @author rnewman
  *
  */
 public interface RepositorySessionStoreDelegate {
   public void onRecordStoreFailed(Exception ex);
+
+  // Optionally called with an equivalent (but not necessarily identical) record
+  // when a store has succeeded.
   public void onRecordStoreSucceeded(Record record);
   public void onStoreCompleted(long storeEnd);
   public RepositorySessionStoreDelegate deferredStoreDelegate(ExecutorService executor);
 }