Bug 1131491 - Remove browser.places.useAsyncTransactions preference - async transactions are now the only version. r?mak draft
authorMark Banner <standard8@mozilla.com>
Mon, 22 Jan 2018 13:36:41 +0000
changeset 723437 e4261f4f8300ae09444d3bd1c15eaa6e6d0d405b
parent 723173 1ec6077296c95cc68489bf05b4f64850af03f9b0
child 723438 170ad5b602421218d9906f4a51cbbc9362015a9a
push id96427
push userbmo:standard8@mozilla.com
push dateTue, 23 Jan 2018 08:57:46 +0000
reviewersmak
bugs1131491
milestone60.0a1
Bug 1131491 - Remove browser.places.useAsyncTransactions preference - async transactions are now the only version. r?mak MozReview-Commit-ID: 9EKNvA8Q9jo
browser/app/profile/firefox.js
browser/base/content/browser-places.js
browser/components/places/PlacesUIUtils.jsm
browser/components/places/content/bookmarkProperties.js
browser/components/places/content/controller.js
browser/components/places/content/editBookmarkOverlay.js
browser/components/places/content/treeView.js
browser/components/places/tests/browser/browser.ini
browser/components/places/tests/browser/browser_bookmarkProperties_cancel.js
browser/components/places/tests/browser/browser_controller_onDrop.js
browser/components/places/tests/browser/browser_controller_onDrop_tagFolder.js
browser/components/places/tests/browser/browser_copy_folder_tree.js
browser/components/places/tests/unit/test_PUIU_makeTransaction.js
browser/components/places/tests/unit/xpcshell.ini
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -910,19 +910,16 @@ pref("browser.sessionstore.cleanup.forge
 // Maximum number of bytes of DOMSessionStorage data we collect per origin.
 pref("browser.sessionstore.dom_storage_limit", 2048);
 // Amount of failed SessionFile writes until we restart the worker.
 pref("browser.sessionstore.max_write_failures", 5);
 
 // allow META refresh by default
 pref("accessibility.blockautorefresh", false);
 
-// Whether useAsyncTransactions is enabled or not.
-pref("browser.places.useAsyncTransactions", true);
-
 // Whether history is enabled or not.
 pref("places.history.enabled", true);
 
 // the (maximum) number of the recent visits to sample
 // when calculating frecency
 pref("places.frecency.numVisits", 10);
 
 // buckets (in days) for frecency calculation
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -6,18 +6,16 @@
 /* eslint-env mozilla/browser-window */
 
 XPCOMUtils.defineLazyScriptGetter(this, ["PlacesToolbar", "PlacesMenu",
                                          "PlacesPanelview", "PlacesPanelMenuView"],
                                   "chrome://browser/content/places/browserPlacesViews.js");
 
 var StarUI = {
   _itemGuids: null,
-  // TODO (bug 1131491): _itemIdsMap is only used for the old transactions manager.
-  _itemIdsMap: null,
   _batching: false,
   _isNewBookmark: false,
   _isComposing: false,
   _autoCloseTimer: 0,
   // The autoclose timer is diasbled if the user interacts with the
   // popup, such as making a change through typing or clicking on
   // the popup.
   _autoCloseTimerEnabled: true,
@@ -91,46 +89,30 @@ var StarUI = {
 
           if (this._anchorToolbarButton) {
             this._anchorToolbarButton.removeAttribute("open");
             this._anchorToolbarButton = null;
           }
           this._restoreCommandsState();
           let removeBookmarksOnPopupHidden = this._removeBookmarksOnPopupHidden;
           this._removeBookmarksOnPopupHidden = false;
-          let idsForRemoval = this._itemIdsMap;
           let guidsForRemoval = this._itemGuids;
           this._itemGuids = null;
-          this._itemIdsMap = null;
 
           if (this._batching) {
             this.endBatch();
           }
 
           if (removeBookmarksOnPopupHidden && guidsForRemoval) {
             if (this._isNewBookmark) {
-              if (!PlacesUIUtils.useAsyncTransactions) {
-                PlacesUtils.transactionManager.undoTransaction();
-                break;
-              }
               PlacesTransactions.undo().catch(Cu.reportError);
               break;
             }
             // Remove all bookmarks for the bookmark's url, this also removes
             // the tags for the url.
-            if (!PlacesUIUtils.useAsyncTransactions) {
-              if (idsForRemoval) {
-                for (let itemId of idsForRemoval.values()) {
-                  let txn = new PlacesRemoveItemTransaction(itemId);
-                  PlacesUtils.transactionManager.doTransaction(txn);
-                }
-              }
-              break;
-            }
-
             PlacesTransactions.Remove(guidsForRemoval)
                               .transact().catch(Cu.reportError);
           } else if (this._isNewBookmark) {
             LibraryUI.triggerLibraryAnimation("bookmark");
           }
         }
         break;
       }
@@ -225,17 +207,16 @@ var StarUI = {
     // Slow double-clicks (not true double-clicks) shouldn't
     // cause the panel to flicker.
     if (this.panel.state == "showing" ||
         this.panel.state == "open") {
       return;
     }
 
     this._isNewBookmark = aIsNewBookmark;
-    this._itemIdsMap = null;
     this._itemGuids = null;
     // TODO (bug 1131491): Deprecate this once async transactions are enabled
     // and the legacy transactions code is gone.
     if (typeof(aNode) == "number") {
       let itemId = aNode;
       let guid = await PlacesUtils.promiseItemGuid(itemId);
       aNode = await PlacesUIUtils.fetchNodeLike(guid);
     }
@@ -286,19 +267,16 @@ var StarUI = {
 
     // The label of the remove button differs if the URI is bookmarked
     // multiple times.
     this._itemGuids = [];
 
     await PlacesUtils.bookmarks.fetch({url: aUrl},
       bookmark => this._itemGuids.push(bookmark.guid));
 
-    if (!PlacesUIUtils.useAsyncTransactions) {
-      this._itemIdsMap = await PlacesUtils.promiseManyItemIds(this._itemGuids);
-    }
     let forms = gNavigatorBundle.getString("editBookmark.removeBookmarks.label");
     let bookmarksCount = this._itemGuids.length;
     let label = PluralForm.get(bookmarksCount, forms)
                           .replace("#1", bookmarksCount);
     this._element("editBookmarkPanelRemoveButton").label = label;
 
     this.beginBatch();
 
@@ -360,37 +338,29 @@ var StarUI = {
   // editBookmarkOverlay so that all of the actions done in the panel
   // are treated by PlacesTransactions as a single batch.  To do so,
   // we start a PlacesTransactions batch when the star UI panel is shown, and
   // we keep the batch ongoing until the panel is hidden.
   _batchBlockingDeferred: null,
   beginBatch() {
     if (this._batching)
       return;
-    if (PlacesUIUtils.useAsyncTransactions) {
-      this._batchBlockingDeferred = PromiseUtils.defer();
-      PlacesTransactions.batch(async () => {
-        await this._batchBlockingDeferred.promise;
-      });
-    } else {
-      PlacesUtils.transactionManager.beginBatch(null);
-    }
+    this._batchBlockingDeferred = PromiseUtils.defer();
+    PlacesTransactions.batch(async () => {
+      await this._batchBlockingDeferred.promise;
+    });
     this._batching = true;
   },
 
   endBatch() {
     if (!this._batching)
       return;
 
-    if (PlacesUIUtils.useAsyncTransactions) {
-      this._batchBlockingDeferred.resolve();
-      this._batchBlockingDeferred = null;
-    } else {
-      PlacesUtils.transactionManager.endBatch(false);
-    }
+    this._batchBlockingDeferred.resolve();
+    this._batchBlockingDeferred = null;
     this._batching = false;
   }
 };
 
 // Checks if an element is visible without flushing layout changes.
 function isVisible(element) {
   let windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
                           .getInterface(Ci.nsIDOMWindowUtils);
@@ -408,85 +378,16 @@ var PlacesCommandHook = {
    *        whether or not to show the edit-bookmark UI for the bookmark item
    * @param [optional] aUrl
    *        Option to provide a URL to bookmark rather than the current page
    * @param [optional] aTitle
    *        Option to provide a title for a bookmark to use rather than the
    *        getting the current page's title
    */
   async bookmarkPage(aBrowser, aShowEditUI, aUrl = null, aTitle = null) {
-    if (PlacesUIUtils.useAsyncTransactions) {
-      await this._bookmarkPagePT(aBrowser, aShowEditUI, aUrl, aTitle);
-      return;
-    }
-
-    // If aUrl is provided, we want to bookmark that url rather than the
-    // the current page
-    var uri = aUrl ? Services.io.newURI(aUrl) : aBrowser.currentURI;
-    var itemId = PlacesUtils.getMostRecentBookmarkForURI(uri);
-    let isNewBookmark = itemId == -1;
-    if (isNewBookmark) {
-      // Bug 1148838 - Make this code work for full page plugins.
-      var title;
-      var description;
-      var charset;
-
-      let docInfo = aUrl ? {} : await this._getPageDetails(aBrowser);
-
-      try {
-        title = aTitle ||
-                (docInfo.isErrorPage ? PlacesUtils.history.getPageTitle(uri)
-                                     : aBrowser.contentTitle) ||
-                uri.displaySpec;
-        description = docInfo.description;
-        charset = aUrl ? null : aBrowser.characterSet;
-      } catch (e) { }
-
-      if (aShowEditUI) {
-        // If we bookmark the page here but open right into a cancelable
-        // state (i.e. new bookmark in Library), start batching here so
-        // all of the actions can be undone in a single undo step.
-        StarUI.beginBatch();
-      }
-
-      var descAnno = { name: PlacesUIUtils.DESCRIPTION_ANNO, value: description };
-      var txn = new PlacesCreateBookmarkTransaction(uri,
-                                                    PlacesUtils.unfiledBookmarksFolderId,
-                                                    PlacesUtils.bookmarks.DEFAULT_INDEX,
-                                                    title, null, [descAnno]);
-      PlacesUtils.transactionManager.doTransaction(txn);
-      itemId = txn.item.id;
-      // Set the character-set.
-      if (charset && !PrivateBrowsingUtils.isBrowserPrivate(aBrowser))
-        PlacesUtils.setCharsetForURI(uri, charset);
-    }
-
-    // Revert the contents of the location bar
-    gURLBar.handleRevert();
-
-    // If it was not requested to open directly in "edit" mode, we are done.
-    if (!aShowEditUI)
-      return;
-
-    let anchor = BookmarkingUI.anchor;
-    if (anchor) {
-      await StarUI.showEditBookmarkPopup(itemId, anchor,
-                                         "bottomcenter topright", isNewBookmark,
-                                         uri);
-      return;
-    }
-
-    // Fall back to showing the panel over the content area.
-    await StarUI.showEditBookmarkPopup(itemId, aBrowser, "overlap",
-                                       isNewBookmark, uri);
-  },
-
-  // TODO: Replace bookmarkPage code with this function once legacy
-  // transactions are removed.
-  async _bookmarkPagePT(aBrowser, aShowEditUI, aUrl, aTitle) {
     // If aUrl is provided, we want to bookmark that url rather than the
     // the current page
     let url = aUrl ? new URL(aUrl) : new URL(aBrowser.currentURI.spec);
     let info = await PlacesUtils.bookmarks.fetch({ url });
     let isNewBookmark = !info;
     if (!info) {
       let parentGuid = PlacesUtils.bookmarks.unfiledGuid;
       info = { url, parentGuid };
--- a/browser/components/places/PlacesUIUtils.jsm
+++ b/browser/components/places/PlacesUIUtils.jsm
@@ -6,21 +6,18 @@
 this.EXPORTED_SYMBOLS = ["PlacesUIUtils"];
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Timer.jsm");
 
-// PlacesUtils exposes multiple symbols, so we can't use defineLazyModuleGetter
-// until we remove legacy transactions (Bug 1131491).
-Cu.import("resource://gre/modules/PlacesUtils.jsm");
-
 XPCOMUtils.defineLazyModuleGetters(this, {
+  PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
   PluralForm: "resource://gre/modules/PluralForm.jsm",
   PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
   RecentWindow: "resource:///modules/RecentWindow.jsm",
   PromiseUtils: "resource://gre/modules/PromiseUtils.jsm",
   PlacesTransactions: "resource://gre/modules/PlacesTransactions.jsm",
   Weave: "resource://services-sync/main.js",
 });
 
@@ -264,261 +261,16 @@ this.PlacesUIUtils = {
     return [
       this.DESCRIPTION_ANNO,
       this.LOAD_IN_SIDEBAR_ANNO,
       PlacesUtils.READ_ONLY_ANNO,
     ];
   },
 
   /**
-   * Get a transaction for copying a uri item (either a bookmark or a history
-   * entry) from one container to another.
-   *
-   * @param   aData
-   *          JSON object of dropped or pasted item properties
-   * @param   aContainer
-   *          The container being copied into
-   * @param   aIndex
-   *          The index within the container the item is copied to
-   * @return A nsITransaction object that performs the copy.
-   *
-   * @note Since a copy creates a completely new item, only some internal
-   *       annotations are synced from the old one.
-   * @see this._copyableAnnotations for the list of copyable annotations.
-   */
-  _getURIItemCopyTransaction:
-  function PUIU__getURIItemCopyTransaction(aData, aContainer, aIndex) {
-    let transactions = [];
-    if (aData.dateAdded) {
-      transactions.push(
-        new PlacesEditItemDateAddedTransaction(null, aData.dateAdded)
-      );
-    }
-    if (aData.lastModified) {
-      transactions.push(
-        new PlacesEditItemLastModifiedTransaction(null, aData.lastModified)
-      );
-    }
-
-    let annos = [];
-    if (aData.annos) {
-      annos = aData.annos.filter(function(aAnno) {
-        return this._copyableAnnotations.includes(aAnno.name);
-      }, this);
-    }
-
-    // There's no need to copy the keyword since it's bound to the bookmark url.
-    return new PlacesCreateBookmarkTransaction(PlacesUtils._uri(aData.uri),
-                                               aContainer, aIndex, aData.title,
-                                               null, annos, transactions);
-  },
-
-  /**
-   * Gets a transaction for copying (recursively nesting to include children)
-   * a folder (or container) and its contents from one folder to another.
-   *
-   * @param   aData
-   *          Unwrapped dropped folder data - Obj containing folder and children
-   * @param   aContainer
-   *          The container we are copying into
-   * @param   aIndex
-   *          The index in the destination container to insert the new items
-   * @return A nsITransaction object that will perform the copy.
-   *
-   * @note Since a copy creates a completely new item, only some internal
-   *       annotations are synced from the old one.
-   * @see this._copyableAnnotations for the list of copyable annotations.
-   */
-  _getFolderCopyTransaction(aData, aContainer, aIndex) {
-    function getChildItemsTransactions(aRoot) {
-      let transactions = [];
-      let index = aIndex;
-      for (let i = 0; i < aRoot.childCount; ++i) {
-        let child = aRoot.getChild(i);
-        // Temporary hacks until we switch to PlacesTransactions.jsm.
-        let isLivemark =
-          PlacesUtils.annotations.itemHasAnnotation(child.itemId,
-                                                    PlacesUtils.LMANNO_FEEDURI);
-        let [node] = PlacesUtils.unwrapNodes(
-          PlacesUtils.wrapNode(child, PlacesUtils.TYPE_X_MOZ_PLACE, isLivemark),
-          PlacesUtils.TYPE_X_MOZ_PLACE
-        );
-
-        // Make sure that items are given the correct index, this will be
-        // passed by the transaction manager to the backend for the insertion.
-        // Insertion behaves differently for DEFAULT_INDEX (append).
-        if (aIndex != PlacesUtils.bookmarks.DEFAULT_INDEX) {
-          index = i;
-        }
-
-        if (node.type == PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER) {
-          if (node.livemark && node.annos) {
-            transactions.push(
-              PlacesUIUtils._getLivemarkCopyTransaction(node, aContainer, index)
-            );
-          } else {
-            transactions.push(
-              PlacesUIUtils._getFolderCopyTransaction(node, aContainer, index)
-            );
-          }
-        } else if (node.type == PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR) {
-          transactions.push(new PlacesCreateSeparatorTransaction(-1, index));
-        } else if (node.type == PlacesUtils.TYPE_X_MOZ_PLACE) {
-          transactions.push(
-            PlacesUIUtils._getURIItemCopyTransaction(node, -1, index)
-          );
-        } else {
-          throw new Error("Unexpected item under a bookmarks folder");
-        }
-      }
-      return transactions;
-    }
-
-    if (aContainer == PlacesUtils.tagsFolderId) { // Copying into a tag folder.
-      let transactions = [];
-      if (!aData.livemark && aData.type == PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER) {
-        let {root} = PlacesUtils.getFolderContents(aData.id, false, false);
-        let urls = PlacesUtils.getURLsForContainerNode(root);
-        root.containerOpen = false;
-        for (let { uri } of urls) {
-          transactions.push(
-            new PlacesTagURITransaction(Services.io.newURI(uri), [aData.title])
-          );
-        }
-      }
-      return new PlacesAggregatedTransaction("addTags", transactions);
-    }
-
-    if (aData.livemark && aData.annos) { // Copying a livemark.
-      return this._getLivemarkCopyTransaction(aData, aContainer, aIndex);
-    }
-
-    let {root} = PlacesUtils.getFolderContents(aData.id, false, false);
-    let transactions = getChildItemsTransactions(root);
-    root.containerOpen = false;
-
-    if (aData.dateAdded) {
-      transactions.push(
-        new PlacesEditItemDateAddedTransaction(null, aData.dateAdded)
-      );
-    }
-    if (aData.lastModified) {
-      transactions.push(
-        new PlacesEditItemLastModifiedTransaction(null, aData.lastModified)
-      );
-    }
-
-    let annos = [];
-    if (aData.annos) {
-      annos = aData.annos.filter(function(aAnno) {
-        return this._copyableAnnotations.includes(aAnno.name);
-      }, this);
-    }
-
-    return new PlacesCreateFolderTransaction(aData.title, aContainer, aIndex,
-                                             annos, transactions);
-  },
-
-  /**
-   * Gets a transaction for copying a live bookmark item from one container to
-   * another.
-   *
-   * @param   aData
-   *          Unwrapped live bookmarkmark data
-   * @param   aContainer
-   *          The container we are copying into
-   * @param   aIndex
-   *          The index in the destination container to insert the new items
-   * @return A nsITransaction object that will perform the copy.
-   *
-   * @note Since a copy creates a completely new item, only some internal
-   *       annotations are synced from the old one.
-   * @see this._copyableAnnotations for the list of copyable annotations.
-   */
-  _getLivemarkCopyTransaction:
-  function PUIU__getLivemarkCopyTransaction(aData, aContainer, aIndex) {
-    if (!aData.livemark || !aData.annos) {
-      throw new Error("node is not a livemark");
-    }
-
-    let feedURI, siteURI;
-    let annos = [];
-    if (aData.annos) {
-      annos = aData.annos.filter(function(aAnno) {
-        if (aAnno.name == PlacesUtils.LMANNO_FEEDURI) {
-          feedURI = PlacesUtils._uri(aAnno.value);
-        } else if (aAnno.name == PlacesUtils.LMANNO_SITEURI) {
-          siteURI = PlacesUtils._uri(aAnno.value);
-        }
-        return this._copyableAnnotations.includes(aAnno.name);
-      }, this);
-    }
-
-    return new PlacesCreateLivemarkTransaction(feedURI, siteURI, aData.title,
-                                               aContainer, aIndex, annos);
-  },
-
-  /**
-   * Constructs a Transaction for the drop or paste of a blob of data into
-   * a container.
-   * @param   data
-   *          The unwrapped data blob of dropped or pasted data.
-   * @param   type
-   *          The content type of the data
-   * @param   container
-   *          The container the data was dropped or pasted into
-   * @param   index
-   *          The index within the container the item was dropped or pasted at
-   * @param   copy
-   *          The drag action was copy, so don't move folders or links.
-   * @return An object implementing nsITransaction that can perform
-   *         the move/insert.
-   */
-  makeTransaction:
-  function PUIU_makeTransaction(data, type, container, index, copy) {
-    switch (data.type) {
-      case PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER:
-        if (copy) {
-          return this._getFolderCopyTransaction(data, container, index);
-        }
-
-        // Otherwise move the item.
-        return new PlacesMoveItemTransaction(data.id, container, index);
-      case PlacesUtils.TYPE_X_MOZ_PLACE:
-        if (copy || data.id == -1) { // Id is -1 if the place is not bookmarked.
-          return this._getURIItemCopyTransaction(data, container, index);
-        }
-
-        // Otherwise move the item.
-        return new PlacesMoveItemTransaction(data.id, container, index);
-      case PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR:
-        if (copy) {
-          // There is no data in a separator, so copying it just amounts to
-          // inserting a new separator.
-          return new PlacesCreateSeparatorTransaction(container, index);
-        }
-
-        // Otherwise move the item.
-        return new PlacesMoveItemTransaction(data.id, container, index);
-      default:
-        if (type == PlacesUtils.TYPE_X_MOZ_URL ||
-            type == PlacesUtils.TYPE_UNICODE ||
-            type == TAB_DROP_TYPE) {
-          let title = type != PlacesUtils.TYPE_UNICODE ? data.title
-                                                       : data.uri;
-          return new PlacesCreateBookmarkTransaction(PlacesUtils._uri(data.uri),
-                                                     container, index, title);
-        }
-    }
-    return null;
-  },
-
-  /**
-   * ********* PlacesTransactions version of the function defined above ********
-   *
    * Constructs a Places Transaction for the drop or paste of a blob of data
    * into a container.
    *
    * @param   aData
    *          The unwrapped data blob of dropped or pasted data.
    * @param   aNewParentGuid
    *          GUID of the container the data was dropped or pasted into.
    * @param   aIndex
@@ -591,36 +343,32 @@ this.PlacesUIUtils = {
                     "chrome://browser/content/places/bookmarkProperties2.xul" :
                     "chrome://browser/content/places/bookmarkProperties.xul";
 
     let features = "centerscreen,chrome,modal,resizable=yes";
 
     let topUndoEntry;
     let batchBlockingDeferred;
 
-    if (this.useAsyncTransactions) {
-      // Set the transaction manager into batching mode.
-      topUndoEntry = PlacesTransactions.topUndoEntry;
-      batchBlockingDeferred = PromiseUtils.defer();
-      PlacesTransactions.batch(async () => {
-        await batchBlockingDeferred.promise;
-      });
-    }
+    // Set the transaction manager into batching mode.
+    topUndoEntry = PlacesTransactions.topUndoEntry;
+    batchBlockingDeferred = PromiseUtils.defer();
+    PlacesTransactions.batch(async () => {
+      await batchBlockingDeferred.promise;
+    });
 
     aParentWindow.openDialog(dialogURL, "", features, aInfo);
 
     let performed = ("performed" in aInfo && aInfo.performed);
 
-    if (this.useAsyncTransactions) {
-      batchBlockingDeferred.resolve();
+    batchBlockingDeferred.resolve();
 
-      if (!performed &&
-          topUndoEntry != PlacesTransactions.topUndoEntry) {
-        PlacesTransactions.undo().catch(Components.utils.reportError);
-      }
+    if (!performed &&
+        topUndoEntry != PlacesTransactions.topUndoEntry) {
+      PlacesTransactions.undo().catch(Components.utils.reportError);
     }
 
     return performed;
   },
 
   /**
    * set and fetch a favicon. Can only be used from the parent process.
    * @param browser   {Browser}   The XUL browser element for which we're fetching a favicon.
@@ -1525,16 +1273,14 @@ PlacesUIUtils.URI_FLAVORS = [PlacesUtils
 PlacesUIUtils.SUPPORTED_FLAVORS = [...PlacesUIUtils.PLACES_FLAVORS,
                                    ...PlacesUIUtils.URI_FLAVORS];
 
 XPCOMUtils.defineLazyGetter(PlacesUIUtils, "ellipsis", function() {
   return Services.prefs.getComplexValue("intl.ellipsis",
                                         Ci.nsIPrefLocalizedString).data;
 });
 
-XPCOMUtils.defineLazyPreferenceGetter(PlacesUIUtils, "useAsyncTransactions",
-                                      "browser.places.useAsyncTransactions", false);
 XPCOMUtils.defineLazyPreferenceGetter(PlacesUIUtils, "loadBookmarksInBackground",
                                       PREF_LOAD_BOOKMARKS_IN_BACKGROUND, false);
 XPCOMUtils.defineLazyPreferenceGetter(PlacesUIUtils, "loadBookmarksInTabs",
                                       PREF_LOAD_BOOKMARKS_IN_TABS, false);
 XPCOMUtils.defineLazyPreferenceGetter(PlacesUIUtils, "openInTabClosesMenu",
   "browser.bookmarks.openInTabClosesMenu", false);
--- a/browser/components/places/content/bookmarkProperties.js
+++ b/browser/components/places/content/bookmarkProperties.js
@@ -94,17 +94,16 @@ var BookmarkPropertiesPanel = {
   _keyword: "",
   _postData: null,
   _charSet: "",
   _feedURI: null,
   _siteURI: null,
 
   _defaultInsertionPoint: null,
   _hiddenRows: [],
-  _batching: false,
 
   /**
    * This method returns the correct label for the dialog's "accept"
    * button based on the variant of the dialog.
    */
   _getAcceptLabel: function BPP__getAcceptLabel() {
     if (this._action == ACTION_ADD) {
       if (this._URIs.length)
@@ -299,18 +298,16 @@ var BookmarkPropertiesPanel = {
                                    { subtree: true,
                                      attributeOldValue: true,
                                      attributeFilter: ["collapsed"] });
 
     // Some controls are flexible and we want to update their cached size when
     // the dialog is resized.
     window.addEventListener("resize", this);
 
-    this._beginBatch();
-
     switch (this._action) {
       case ACTION_EDIT:
         gEditItemOverlay.initPanel({ node: this._node,
                                      hiddenRows: this._hiddenRows,
                                      focusedElement: "first" });
         acceptButtonDisabled = gEditItemOverlay.readOnly;
         break;
       case ACTION_ADD:
@@ -367,39 +364,16 @@ var BookmarkPropertiesPanel = {
           let newHeight = document.getElementById(id).boxObject.height;
           this._height += -oldHeight + newHeight;
           elementsHeight.set(id, newHeight);
         }
         break;
     }
   },
 
-  // Hack for implementing batched-Undo around the editBookmarkOverlay
-  // instant-apply code. For all the details see the comment above beginBatch
-  // in browser-places.js
-  _batchBlockingDeferred: null,
-  _beginBatch() {
-    if (this._batching)
-      return;
-    if (!PlacesUIUtils.useAsyncTransactions) {
-      PlacesUtils.transactionManager.beginBatch(null);
-    }
-    this._batching = true;
-  },
-
-  _endBatch() {
-    if (!this._batching)
-      return;
-
-    if (!PlacesUIUtils.useAsyncTransactions) {
-      PlacesUtils.transactionManager.endBatch(false);
-    }
-    this._batching = false;
-  },
-
   // nsISupports
   QueryInterface: function BPP_QueryInterface(aIID) {
     if (aIID.equals(Ci.nsIDOMEventListener) ||
         aIID.equals(Ci.nsISupports))
       return this;
 
     throw Cr.NS_NOINTERFACE;
   },
@@ -419,32 +393,26 @@ var BookmarkPropertiesPanel = {
     // currently registered EventListener on the EventTarget has no effect.
     this._element("locationField")
         .removeEventListener("input", this);
   },
 
   onDialogAccept() {
     // We must blur current focused element to save its changes correctly
     document.commandDispatcher.focusedElement.blur();
-    // The order here is important! We have to uninit the panel first, otherwise
-    // late changes could force it to commit more transactions.
+    // We have to uninit the panel first, otherwise late changes could force it
+    // to commit more transactions.
     gEditItemOverlay.uninitPanel(true);
-    this._endBatch();
     window.arguments[0].performed = true;
   },
 
   onDialogCancel() {
-    // The order here is important! We have to uninit the panel first, otherwise
-    // changes done as part of Undo may change the panel contents and by
-    // that force it to commit more transactions.
+    // We have to uninit the panel first, otherwise late changes could force it
+    // to commit more transactions.
     gEditItemOverlay.uninitPanel(true);
-    this._endBatch();
-    if (!PlacesUIUtils.useAsyncTransactions) {
-      PlacesUtils.transactionManager.undoTransaction();
-    }
     window.arguments[0].performed = false;
   },
 
   /**
    * This method checks to see if the input fields are in a valid state.
    *
    * @returns  true if the input is valid, false otherwise
    */
@@ -488,142 +456,17 @@ var BookmarkPropertiesPanel = {
   async _getInsertionPointDetails() {
     return [
       this._defaultInsertionPoint.itemId,
       await this._defaultInsertionPoint.getIndex(),
       this._defaultInsertionPoint.guid,
     ];
   },
 
-  /**
-   * Returns a transaction for creating a new bookmark item representing the
-   * various fields and opening arguments of the dialog.
-   */
-  _getCreateNewBookmarkTransaction:
-  function BPP__getCreateNewBookmarkTransaction(aContainer, aIndex) {
-    var annotations = [];
-    var childTransactions = [];
-
-    if (this._description) {
-      let annoObj = { name: PlacesUIUtils.DESCRIPTION_ANNO,
-                      type: Ci.nsIAnnotationService.TYPE_STRING,
-                      flags: 0,
-                      value: this._description,
-                      expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
-      let editItemTxn = new PlacesSetItemAnnotationTransaction(-1, annoObj);
-      childTransactions.push(editItemTxn);
-    }
-
-    if (this._loadInSidebar) {
-      let annoObj = { name: PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO,
-                      value: true };
-      let setLoadTxn = new PlacesSetItemAnnotationTransaction(-1, annoObj);
-      childTransactions.push(setLoadTxn);
-    }
-
-    // XXX TODO: this should be in a transaction!
-    if (this._charSet && !PrivateBrowsingUtils.isWindowPrivate(window))
-      PlacesUtils.setCharsetForURI(this._uri, this._charSet);
-
-    let createTxn = new PlacesCreateBookmarkTransaction(this._uri,
-                                                        aContainer,
-                                                        aIndex,
-                                                        this._title,
-                                                        this._keyword,
-                                                        annotations,
-                                                        childTransactions,
-                                                        this._postData);
-
-    return new PlacesAggregatedTransaction(this._getDialogTitle(),
-                                           [createTxn]);
-  },
-
-  /**
-   * Returns a childItems-transactions array representing the URIList with
-   * which the dialog has been opened.
-   */
-  _getTransactionsForURIList: function BPP__getTransactionsForURIList() {
-    var transactions = [];
-    for (let uri of this._URIs) {
-      let createTxn =
-        new PlacesCreateBookmarkTransaction(uri.uri, -1,
-                                            PlacesUtils.bookmarks.DEFAULT_INDEX,
-                                            uri.title);
-      transactions.push(createTxn);
-    }
-    return transactions;
-  },
-
-  /**
-   * Returns a transaction for creating a new folder item representing the
-   * various fields and opening arguments of the dialog.
-   */
-  _getCreateNewFolderTransaction:
-  function BPP__getCreateNewFolderTransaction(aContainer, aIndex) {
-    var annotations = [];
-    var childItemsTransactions;
-    if (this._URIs.length)
-      childItemsTransactions = this._getTransactionsForURIList();
-
-    if (this._description)
-      annotations.push(this._getDescriptionAnnotation(this._description));
-
-    return new PlacesCreateFolderTransaction(this._title, aContainer,
-                                             aIndex, annotations,
-                                             childItemsTransactions);
-  },
-
-  async _createNewItem() {
-    let [container, index] = await this._getInsertionPointDetails();
-    let txn;
-    switch (this._itemType) {
-      case BOOKMARK_FOLDER:
-        txn = this._getCreateNewFolderTransaction(container, index);
-        break;
-      case LIVEMARK_CONTAINER:
-        txn = new PlacesCreateLivemarkTransaction(this._feedURI, this._siteURI,
-                                                  this._title, container, index);
-        break;
-      default: // BOOKMARK_ITEM
-        txn = this._getCreateNewBookmarkTransaction(container, index);
-    }
-
-    PlacesUtils.transactionManager.doTransaction(txn);
-    // This is a temporary hack until we use PlacesTransactions.jsm
-    if (txn._promise) {
-      await txn._promise;
-    }
-
-    let folderGuid = await PlacesUtils.promiseItemGuid(container);
-    let bm = await PlacesUtils.bookmarks.fetch({
-      parentGuid: folderGuid,
-      index
-    });
-    this._itemId = await PlacesUtils.promiseItemId(bm.guid);
-
-    return Object.freeze({
-      itemId: this._itemId,
-      bookmarkGuid: bm.guid,
-      title: this._title,
-      uri: this._uri ? this._uri.spec : "",
-      type: this._itemType == BOOKMARK_ITEM ?
-              Ci.nsINavHistoryResultNode.RESULT_TYPE_URI :
-              Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER,
-      parent: {
-        itemId: container,
-        bookmarkGuid: await PlacesUtils.promiseItemGuid(container),
-        type: Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER
-      }
-    });
-  },
-
   async _promiseNewItem() {
-    if (!PlacesUIUtils.useAsyncTransactions)
-      return this._createNewItem();
-
     let [containerId, index, parentGuid] = await this._getInsertionPointDetails();
     let annotations = [];
     if (this._description) {
       annotations.push({ name: PlacesUIUtils.DESCRIPTION_ANNO,
                          value: this._description });
     }
     if (this._loadInSidebar) {
       annotations.push({ name: PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO,
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -115,24 +115,18 @@ PlacesController.prototype = {
     // filters out other commands that we do _not_ support (see 329587).
     const CMD_PREFIX = "placesCmd_";
     return (aCommand.substr(0, CMD_PREFIX.length) == CMD_PREFIX);
   },
 
   isCommandEnabled: function PC_isCommandEnabled(aCommand) {
     switch (aCommand) {
     case "cmd_undo":
-      if (!PlacesUIUtils.useAsyncTransactions)
-        return PlacesUtils.transactionManager.numberOfUndoItems > 0;
-
       return PlacesTransactions.topUndoEntry != null;
     case "cmd_redo":
-      if (!PlacesUIUtils.useAsyncTransactions)
-        return PlacesUtils.transactionManager.numberOfRedoItems > 0;
-
       return PlacesTransactions.topRedoEntry != null;
     case "cmd_cut":
     case "placesCmd_cut":
       for (let node of this._view.selectedNodes) {
         // If selection includes history nodes or tags-as-bookmark, disallow
         // cutting.
         if (node.itemId == -1 ||
             (node.parent && PlacesUtils.nodeIsTagQuery(node.parent))) {
@@ -196,27 +190,19 @@ PlacesController.prototype = {
     default:
       return false;
     }
   },
 
   doCommand: function PC_doCommand(aCommand) {
     switch (aCommand) {
     case "cmd_undo":
-      if (!PlacesUIUtils.useAsyncTransactions) {
-        PlacesUtils.transactionManager.undoTransaction();
-        return;
-      }
       PlacesTransactions.undo().catch(Components.utils.reportError);
       break;
     case "cmd_redo":
-      if (!PlacesUIUtils.useAsyncTransactions) {
-        PlacesUtils.transactionManager.redoTransaction();
-        return;
-      }
       PlacesTransactions.redo().catch(Components.utils.reportError);
       break;
     case "cmd_cut":
     case "placesCmd_cut":
       this.cut();
       break;
     case "cmd_copy":
     case "placesCmd_copy":
@@ -742,43 +728,27 @@ PlacesController.prototype = {
    * Create a new Bookmark separator somewhere.
    */
   async newSeparator() {
     var ip = this._view.insertionPoint;
     if (!ip)
       throw Cr.NS_ERROR_NOT_AVAILABLE;
 
     let index = await ip.getIndex();
-    if (!PlacesUIUtils.useAsyncTransactions) {
-      let txn = new PlacesCreateSeparatorTransaction(ip.itemId, index);
-      PlacesUtils.transactionManager.doTransaction(txn);
-      // Select the new item.
-      let insertedNodeId = PlacesUtils.bookmarks
-                                      .getIdForItemAt(ip.itemId, index);
-      this._view.selectItems([insertedNodeId], false);
-      return;
-    }
-
     let txn = PlacesTransactions.NewSeparator({ parentGuid: ip.guid, index });
     let guid = await txn.transact();
     // Select the new item.
     this._view.selectItems([guid], false);
   },
 
   /**
    * Sort the selected folder by name
    */
   async sortFolderByName() {
-    let itemId = PlacesUtils.getConcreteItemId(this._view.selectedNode);
-    if (!PlacesUIUtils.useAsyncTransactions) {
-      var txn = new PlacesSortFolderByNameTransaction(itemId);
-      PlacesUtils.transactionManager.doTransaction(txn);
-      return;
-    }
-    let guid = await PlacesUtils.promiseItemGuid(itemId);
+    let guid = PlacesUtils.getConcreteItemGuid(this._view.selectedNode);
     await PlacesTransactions.SortByName(guid).transact();
   },
 
   /**
    * Walk the list of folders we're removing in this delete operation, and
    * see if the selected node specified is already implicitly being removed
    * because it is a child of that folder.
    * @param   node
@@ -837,47 +807,35 @@ PlacesController.prototype = {
       if (this._shouldSkipNode(node, removedFolders))
         continue;
 
       totalItems++;
 
       if (PlacesUtils.nodeIsTagQuery(node.parent)) {
         // This is a uri node inside a tag container.  It needs a special
         // untag transaction.
-        var tagItemId = PlacesUtils.getConcreteItemId(node.parent);
-        var uri = NetUtil.newURI(node.uri);
-        if (PlacesUIUtils.useAsyncTransactions) {
-          let tag = node.parent.title;
-          if (!tag) {
-            let tagGuid = await PlacesUtils.promiseItemGuid(tagItemId);
-            tag = (await PlacesUtils.bookmarks.fetch(tagGuid)).title;
-          }
-          transactions.push(PlacesTransactions.Untag({ urls: [uri], tag }));
-        } else {
-          let txn = new PlacesUntagURITransaction(uri, [tagItemId]);
-          transactions.push(txn);
+        let tag = node.parent.title;
+        if (!tag) {
+          // TODO: Bug 1432405 Try using getConcreteItemGuid.
+          let tagItemId = PlacesUtils.getConcreteItemId(node.parent);
+          let tagGuid = await PlacesUtils.promiseItemGuid(tagItemId);
+          tag = (await PlacesUtils.bookmarks.fetch(tagGuid)).title;
         }
+        transactions.push(PlacesTransactions.Untag({ urls: [node.uri], tag }));
       } else if (PlacesUtils.nodeIsTagQuery(node) && node.parent &&
                PlacesUtils.nodeIsQuery(node.parent) &&
                PlacesUtils.asQuery(node.parent).queryOptions.resultType ==
                  Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_QUERY) {
         // This is a tag container.
         // Untag all URIs tagged with this tag only if the tag container is
         // child of the "Tags" query in the library, in all other places we
         // must only remove the query node.
         let tag = node.title;
         let URIs = PlacesUtils.tagging.getURIsForTag(tag);
-        if (PlacesUIUtils.useAsyncTransactions) {
-          transactions.push(PlacesTransactions.Untag({ tag, urls: URIs }));
-        } else {
-          for (var j = 0; j < URIs.length; j++) {
-            let txn = new PlacesUntagURITransaction(URIs[j], [tag]);
-            transactions.push(txn);
-          }
-        }
+        transactions.push(PlacesTransactions.Untag({ tag, urls: URIs }));
       } else if (PlacesUtils.nodeIsURI(node) &&
                PlacesUtils.nodeIsQuery(node.parent) &&
                PlacesUtils.asQuery(node.parent).queryOptions.queryType ==
                  Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY) {
         // This is a uri node inside an history query.
         PlacesUtils.history.remove(node.uri).catch(Components.utils.reportError);
         // History deletes are not undoable, so we don't have a transaction.
       } else if (node.itemId == -1 &&
@@ -891,22 +849,17 @@ PlacesController.prototype = {
         // History deletes are not undoable, so we don't have a transaction.
       } else {
         // This is a common bookmark item.
         if (PlacesUtils.nodeIsFolder(node)) {
           // If this is a folder we add it to our array of folders, used
           // to skip nodes that are children of an already removed folder.
           removedFolders.push(node);
         }
-        if (PlacesUIUtils.useAsyncTransactions) {
-          bmGuidsToRemove.push(node.bookmarkGuid);
-        } else {
-          let txn = new PlacesRemoveItemTransaction(node.itemId);
-          transactions.push(txn);
-        }
+        bmGuidsToRemove.push(node.bookmarkGuid);
       }
     }
     if (bmGuidsToRemove.length) {
       transactions.push(PlacesTransactions.Remove({ guids: bmGuidsToRemove }));
     }
     return totalItems;
   },
 
@@ -921,24 +874,19 @@ PlacesController.prototype = {
     let removedFolders = [];
     let totalItems = 0;
 
     for (let range of ranges) {
       totalItems += await this._removeRange(range, transactions, removedFolders);
     }
 
     if (transactions.length > 0) {
-      if (PlacesUIUtils.useAsyncTransactions) {
-        await PlacesUIUtils.batchUpdatesForNode(this._view.result, totalItems, async () => {
-          await PlacesTransactions.batch(transactions);
-        });
-      } else {
-        var txn = new PlacesAggregatedTransaction(txnName, transactions);
-        PlacesUtils.transactionManager.doTransaction(txn);
-      }
+      await PlacesUIUtils.batchUpdatesForNode(this._view.result, totalItems, async () => {
+        await PlacesTransactions.batch(transactions);
+      });
     }
   },
 
   /**
    * Removes the set of selected ranges from history, asynchronously.
    *
    * @note history deletes are not undoable.
    */
@@ -995,27 +943,21 @@ PlacesController.prototype = {
     if (!this._hasRemovableSelection())
       return;
 
     NS_ASSERT(aTxnName !== undefined, "Must supply Transaction Name");
 
     var root = this._view.result.root;
 
     if (PlacesUtils.nodeIsFolder(root)) {
-      if (PlacesUIUtils.useAsyncTransactions)
-        await this._removeRowsFromBookmarks(aTxnName);
-      else
-        this._removeRowsFromBookmarks(aTxnName);
+      await this._removeRowsFromBookmarks(aTxnName);
     } else if (PlacesUtils.nodeIsQuery(root)) {
       var queryType = PlacesUtils.asQuery(root).queryOptions.queryType;
       if (queryType == Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS) {
-        if (PlacesUIUtils.useAsyncTransactions)
-          await this._removeRowsFromBookmarks(aTxnName);
-        else
-          this._removeRowsFromBookmarks(aTxnName);
+        await this._removeRowsFromBookmarks(aTxnName);
       } else if (queryType == Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY) {
         this._removeRowsFromHistory();
       } else {
         NS_ASSERT(false, "implement support for QUERY_TYPE_UNIFIED");
       }
     } else
       NS_ASSERT(false, "unexpected root");
   },
@@ -1256,60 +1198,18 @@ PlacesController.prototype = {
       data = data.value.QueryInterface(Ci.nsISupportsString).data;
       type = type.value;
       items = PlacesUtils.unwrapNodes(data, type);
     } catch (ex) {
       // No supported data exists or nodes unwrap failed, just bail out.
       return;
     }
 
-    let itemsToSelect = [];
-    if (PlacesUIUtils.useAsyncTransactions) {
-      let doCopy = action == "copy";
-      itemsToSelect = await handleTransferItems(items, ip, doCopy, this._view);
-    } else {
-      let transactions = [];
-      let insertionIndex = await ip.getIndex();
-      for (let index = insertionIndex, i = 0; i < items.length; ++i) {
-        if (ip.isTag) {
-          // Pasting into a tag container means tagging the item, regardless of
-          // the requested action.
-          let tagTxn = new PlacesTagURITransaction(NetUtil.newURI(items[i].uri),
-                                                   [ip.itemId]);
-          transactions.push(tagTxn);
-          continue;
-        }
-
-        // Adjust index to make sure items are pasted in the correct position.
-        // If index is DEFAULT_INDEX, items are just appended.
-        if (index != PlacesUtils.bookmarks.DEFAULT_INDEX)
-          index += i;
-
-        // If this is not a copy, check for safety that we can move the source,
-        // otherwise report an error and fallback to a copy.
-        if (action != "copy" && !PlacesControllerDragHelper.canMoveUnwrappedNode(items[i])) {
-          Components.utils.reportError("Tried to move an unmovable Places " +
-                                       "node, reverting to a copy operation.");
-          action = "copy";
-        }
-        transactions.push(
-          PlacesUIUtils.makeTransaction(items[i], type, ip.itemId,
-                                        index, action == "copy")
-        );
-      }
-
-      let aggregatedTxn = new PlacesAggregatedTransaction("Paste", transactions);
-      PlacesUtils.transactionManager.doTransaction(aggregatedTxn);
-
-      for (let i = 0; i < transactions.length; ++i) {
-        itemsToSelect.push(
-          PlacesUtils.bookmarks.getIdForItemAt(ip.itemId, insertionIndex + i)
-        );
-      }
-    }
+    let doCopy = action == "copy";
+    let itemsToSelect = await handleTransferItems(items, ip, doCopy, this._view);
 
     // Cut/past operations are not repeatable, so clear the clipboard.
     if (action == "cut") {
       this._clearClipboard();
     }
 
     if (itemsToSelect.length > 0)
       this._view.selectItems(itemsToSelect, false);
@@ -1538,19 +1438,17 @@ var PlacesControllerDragHelper = {
    *                                be dropped.
    * @param {Object} dt             The dataTransfer information for the drop.
    * @param {Object} view           The view or the tree element. This allows
    *                                batching to take place.
    */
   async onDrop(insertionPoint, dt, view) {
     let doCopy = ["copy", "link"].includes(dt.dropEffect);
 
-    let transactions = [];
     let dropCount = dt.mozItemCount;
-    let parentGuid = insertionPoint.guid;
 
     // Following flavors may contain duplicated data.
     let duplicable = new Map();
     duplicable.set(PlacesUtils.TYPE_UNICODE, new Set());
     duplicable.set(PlacesUtils.TYPE_X_MOZ_URL, new Set());
 
     // Collect all data from the DataTransfer before processing it, as the
     // DataTransfer is only valid during the synchronous handling of the `drop`
@@ -1566,107 +1464,37 @@ var PlacesControllerDragHelper = {
         let handled = duplicable.get(flavor);
         if (handled.has(data))
           continue;
         handled.add(data);
       }
       dtItems.push({flavor, data});
     }
 
-    if (PlacesUIUtils.useAsyncTransactions) {
-      let nodes = [];
-      // TODO: When sync transactions are removed, merge the for loop here into the
-      // one above.
-      for (let {flavor, data} of dtItems) {
-        if (flavor != TAB_DROP_TYPE) {
-          nodes = [...nodes, ...PlacesUtils.unwrapNodes(data, flavor)];
-        } else if (data instanceof XULElement && data.localName == "tab" &&
-                 data.ownerGlobal.isChromeWindow) {
-          let uri = data.linkedBrowser.currentURI;
-          let spec = uri ? uri.spec : "about:blank";
-          nodes.push({
-            uri: spec,
-            title: data.label,
-            type: PlacesUtils.TYPE_X_MOZ_URL
-          });
-        } else {
-          throw new Error("bogus data was passed as a tab");
-        }
-      }
-
-      await handleTransferItems(nodes, insertionPoint, doCopy, view);
-    } else {
-      for (let {flavor, data} of dtItems) {
-        let nodes;
-        if (flavor != TAB_DROP_TYPE) {
-          nodes = PlacesUtils.unwrapNodes(data, flavor);
-        } else if (data instanceof XULElement && data.localName == "tab" &&
-                 data.ownerGlobal.isChromeWindow) {
-          let uri = data.linkedBrowser.currentURI;
-          let spec = uri ? uri.spec : "about:blank";
-          nodes = [{ uri: spec,
-                     title: data.label,
-                     type: PlacesUtils.TYPE_X_MOZ_URL}];
-        } else {
-          throw new Error("bogus data was passed as a tab");
-        }
-
-        let movedCount = 0;
-        for (let unwrapped of nodes) {
-          let index = await insertionPoint.getIndex();
-
-          if (index != -1 && unwrapped.itemGuid) {
-            // Note: we use the parent from the existing bookmark as the sidebar
-            // gives us an unwrapped.parent that is actually a query and not the real
-            // parent.
-            let existingBookmark = await PlacesUtils.bookmarks.fetch(unwrapped.itemGuid);
-
-            // If we're dropping on the same folder, then we may need to adjust
-            // the index to insert at the correct place.
-            if (existingBookmark && parentGuid == existingBookmark.parentGuid) {
-              // Sync Transactions. Adjust insertion index to prevent reversal
-              // of dragged items. When you drag multiple elts upward: need to
-              // increment index or each successive elt will be inserted at the
-              // same index, each above the previous.
-              if (index < existingBookmark.index) { // eslint-disable-line no-lonely-if
-                index += movedCount++;
-              }
-            }
-          }
-
-          // If dragging over a tag container we should tag the item.
-          // eslint-disable-next-line no-lonely-if
-          if (insertionPoint.isTag) {
-            let uri = NetUtil.newURI(unwrapped.uri);
-            let tagItemId = insertionPoint.itemId;
-            transactions.push(new PlacesTagURITransaction(uri, [tagItemId]));
-          } else {
-            // If this is not a copy, check for safety that we can move the
-            // source, otherwise report an error and fallback to a copy.
-            if (!doCopy && !PlacesControllerDragHelper.canMoveUnwrappedNode(unwrapped)) {
-              Components.utils.reportError("Tried to move an unmovable Places " +
-                                           "node, reverting to a copy operation.");
-              doCopy = true;
-            }
-            transactions.push(PlacesUIUtils.makeTransaction(unwrapped,
-                                flavor, insertionPoint.itemId,
-                                index, doCopy));
-          }
-        }
-
-        // Check if we actually have something to add, if we don't it probably wasn't
-        // valid, or it was moving to the same location, so just ignore it.
-        if (!transactions.length) {
-          return;
-        }
-
-        let txn = new PlacesAggregatedTransaction("DropItems", transactions);
-        PlacesUtils.transactionManager.doTransaction(txn);
+    let nodes = [];
+    // TODO: Bug 1432407. When sync transactions are removed, merge the for loop
+    // here into the one above.
+    for (let {flavor, data} of dtItems) {
+      if (flavor != TAB_DROP_TYPE) {
+        nodes = [...nodes, ...PlacesUtils.unwrapNodes(data, flavor)];
+      } else if (data instanceof XULElement && data.localName == "tab" &&
+               data.ownerGlobal.isChromeWindow) {
+        let uri = data.linkedBrowser.currentURI;
+        let spec = uri ? uri.spec : "about:blank";
+        nodes.push({
+          uri: spec,
+          title: data.label,
+          type: PlacesUtils.TYPE_X_MOZ_URL
+        });
+      } else {
+        throw new Error("bogus data was passed as a tab");
       }
     }
+
+    await handleTransferItems(nodes, insertionPoint, doCopy, view);
   },
 
   /**
    * Checks if we can insert into a container.
    * @param   aContainer
    *          The container were we are want to drop
    * @param   aView
    *          The view generating the request
--- a/browser/components/places/content/editBookmarkOverlay.js
+++ b/browser/components/places/content/editBookmarkOverlay.js
@@ -537,30 +537,16 @@ var gEditItemOverlay = {
   },
 
   // Adds and removes tags for one or more uris.
   _setTagsFromTagsInputField(aCurrentTags, aURIs) {
     let { removedTags, newTags } = this._getTagsChanges(aCurrentTags);
     if (removedTags.length + newTags.length == 0)
       return false;
 
-    if (!PlacesUIUtils.useAsyncTransactions) {
-      let txns = [];
-      for (let uri of aURIs) {
-        if (removedTags.length > 0)
-          txns.push(new PlacesUntagURITransaction(uri, removedTags));
-        if (newTags.length > 0)
-          txns.push(new PlacesTagURITransaction(uri, newTags));
-      }
-
-      PlacesUtils.transactionManager.doTransaction(
-        new PlacesAggregatedTransaction("Update tags", txns));
-      return true;
-    }
-
     let setTags = async function() {
       if (removedTags.length > 0) {
         await PlacesTransactions.Untag({ urls: aURIs, tags: removedTags })
                                 .transact();
       }
       if (newTags.length > 0) {
         await PlacesTransactions.Tag({ urls: aURIs, tags: newTags })
                                 .transact();
@@ -625,45 +611,32 @@ var gEditItemOverlay = {
 
     // Here we update either the item title or its cached static title
     let newTitle = this._namePicker.value;
     if (!newTitle && this._paneInfo.isTag) {
       // We don't allow setting an empty title for a tag, restore the old one.
       this._initNamePicker();
     } else {
       this._mayUpdateFirstEditField("namePicker");
-      if (!PlacesUIUtils.useAsyncTransactions) {
-        let txn = new PlacesEditItemTitleTransaction(this._paneInfo.itemId,
-                                                     newTitle);
-        PlacesUtils.transactionManager.doTransaction(txn);
-        return;
-      }
 
       let guid = this._paneInfo.isTag
                   ? (await PlacesUtils.promiseItemGuid(this._paneInfo.itemId))
                   : this._paneInfo.itemGuid;
       await PlacesTransactions.EditTitle({ guid, title: newTitle }).transact();
     }
   },
 
   onDescriptionFieldChange() {
     if (this.readOnly || !this._paneInfo.isItem)
       return;
 
-    let itemId = this._paneInfo.itemId;
     let description = this._element("descriptionField").value;
     if (description != PlacesUIUtils.getItemDescription(this._paneInfo.itemId)) {
       let annotation =
         { name: PlacesUIUtils.DESCRIPTION_ANNO, value: description };
-      if (!PlacesUIUtils.useAsyncTransactions) {
-        let txn = new PlacesSetItemAnnotationTransaction(itemId,
-                                                         annotation);
-        PlacesUtils.transactionManager.doTransaction(txn);
-        return;
-      }
       let guid = this._paneInfo.itemGuid;
       PlacesTransactions.Annotate({ guid, annotation })
                         .transact().catch(Components.utils.reportError);
     }
   },
 
   onLocationFieldChange() {
     if (this.readOnly || !this._paneInfo.isBookmark)
@@ -675,62 +648,41 @@ var gEditItemOverlay = {
     } catch (ex) {
       // TODO: Bug 1089141 - Provide some feedback about the invalid url.
       return;
     }
 
     if (this._paneInfo.uri.equals(newURI))
       return;
 
-    if (!PlacesUIUtils.useAsyncTransactions) {
-      let txn = new PlacesEditBookmarkURITransaction(this._paneInfo.itemId, newURI);
-      PlacesUtils.transactionManager.doTransaction(txn);
-      return;
-    }
     let guid = this._paneInfo.itemGuid;
     PlacesTransactions.EditUrl({ guid, url: newURI })
                       .transact().catch(Components.utils.reportError);
   },
 
   onKeywordFieldChange() {
     if (this.readOnly || !this._paneInfo.isBookmark)
       return;
 
-    let itemId = this._paneInfo.itemId;
     let oldKeyword = this._keyword;
     let keyword = this._keyword = this._keywordField.value;
     let postData = this._paneInfo.postData;
-    if (!PlacesUIUtils.useAsyncTransactions) {
-      let txn = new PlacesEditBookmarkKeywordTransaction(itemId,
-                                                         keyword,
-                                                         postData,
-                                                         oldKeyword);
-      PlacesUtils.transactionManager.doTransaction(txn);
-      return;
-    }
     let guid = this._paneInfo.itemGuid;
     PlacesTransactions.EditKeyword({ guid, keyword, postData, oldKeyword })
                       .transact().catch(Components.utils.reportError);
   },
 
   onLoadInSidebarCheckboxCommand() {
     if (!this.initialized || !this._paneInfo.isBookmark)
       return;
 
     let annotation = { name: PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO };
     if (this._loadInSidebarCheckbox.checked)
       annotation.value = true;
 
-    if (!PlacesUIUtils.useAsyncTransactions) {
-      let itemId = this._paneInfo.itemId;
-      let txn = new PlacesSetItemAnnotationTransaction(itemId,
-                                                       annotation);
-      PlacesUtils.transactionManager.doTransaction(txn);
-      return;
-    }
     let guid = this._paneInfo.itemGuid;
     PlacesTransactions.Annotate({ guid, annotation })
                       .transact().catch(Components.utils.reportError);
   },
 
   toggleFolderTreeVisibility() {
     var expander = this._element("foldersExpander");
     var folderTreeRow = this._element("folderTreeRow");
@@ -808,26 +760,19 @@ var gEditItemOverlay = {
       setTimeout(() => this.toggleFolderTreeVisibility(), 100);
       return;
     }
 
     // Move the item
     let containerId = this._folderMenuList.selectedItem.folderId;
     if (this._paneInfo.parentId != containerId &&
         this._paneInfo.itemId != containerId) {
-      if (PlacesUIUtils.useAsyncTransactions) {
-        let newParentGuid = await PlacesUtils.promiseItemGuid(containerId);
-        let guid = this._paneInfo.itemGuid;
-        await PlacesTransactions.Move({ guid, newParentGuid }).transact();
-      } else {
-        let txn = new PlacesMoveItemTransaction(this._paneInfo.itemId,
-                                                containerId,
-                                                PlacesUtils.bookmarks.DEFAULT_INDEX);
-        PlacesUtils.transactionManager.doTransaction(txn);
-      }
+      let newParentGuid = await PlacesUtils.promiseItemGuid(containerId);
+      let guid = this._paneInfo.itemGuid;
+      await PlacesTransactions.Move({ guid, newParentGuid }).transact();
 
       // Mark the containing folder as recently-used if it isn't in the
       // static list
       if (containerId != PlacesUtils.unfiledBookmarksFolderId &&
           containerId != PlacesUtils.toolbarFolderId &&
           containerId != PlacesUtils.bookmarksMenuFolderId) {
         this._markFolderAsRecentlyUsed(containerId)
             .catch(Components.utils.reportError);
@@ -864,40 +809,16 @@ var gEditItemOverlay = {
       return;
 
     var folderItem = this._getFolderMenuItem(folderId, selectedNode.title);
     this._folderMenuList.selectedItem = folderItem;
     folderItem.doCommand();
   },
 
   async _markFolderAsRecentlyUsed(aFolderId) {
-    if (!PlacesUIUtils.useAsyncTransactions) {
-      let txns = [];
-
-      // Expire old unused recent folders.
-      let annotation = this._getLastUsedAnnotationObject(false);
-      while (this._recentFolders.length > MAX_FOLDER_ITEM_IN_MENU_LIST) {
-        let folderId = this._recentFolders.pop().folderId;
-        let annoTxn = new PlacesSetItemAnnotationTransaction(folderId,
-                                                             annotation);
-        txns.push(annoTxn);
-      }
-
-      // Mark folder as recently used
-      annotation = this._getLastUsedAnnotationObject(true);
-      let annoTxn = new PlacesSetItemAnnotationTransaction(aFolderId,
-                                                           annotation);
-      txns.push(annoTxn);
-
-      let aggregate =
-        new PlacesAggregatedTransaction("Update last used folders", txns);
-      PlacesUtils.transactionManager.doTransaction(aggregate);
-      return;
-    }
-
     // Expire old unused recent folders.
     let guids = [];
     while (this._recentFolders.length > MAX_FOLDER_ITEM_IN_MENU_LIST) {
       let folderId = this._recentFolders.pop().folderId;
       let guid = await PlacesUtils.promiseItemGuid(folderId);
       guids.push(guid);
     }
     if (guids.length > 0) {
@@ -1011,24 +932,19 @@ var gEditItemOverlay = {
       ip = new InsertionPoint({
         parentId: PlacesUtils.bookmarksMenuFolderId,
         parentGuid: PlacesUtils.bookmarks.menuGuid
       });
     }
 
     // XXXmano: add a separate "New Folder" string at some point...
     let title = this._element("newFolderButton").label;
-    if (PlacesUIUtils.useAsyncTransactions) {
-      await PlacesTransactions.NewFolder({ parentGuid: ip.guid, title,
-                                           index: await ip.getIndex() })
-                              .transact().catch(Components.utils.reportError);
-    } else {
-      let txn = new PlacesCreateFolderTransaction(title, ip.itemId, await ip.getIndex());
-      PlacesUtils.transactionManager.doTransaction(txn);
-    }
+    await PlacesTransactions.NewFolder({ parentGuid: ip.guid, title,
+                                         index: await ip.getIndex() })
+                            .transact().catch(Components.utils.reportError);
 
     this._folderTree.focus();
     this._folderTree.selectItems([ip.itemId]);
     PlacesUtils.asContainer(this._folderTree.selectedNode).containerOpen = true;
     this._folderTree.selectItems([this._lastNewItem]);
     this._folderTree.startEditing(this._folderTree.view.selection.currentIndex,
                                   this._folderTree.columns.getFirstColumn());
   },
--- a/browser/components/places/content/treeView.js
+++ b/browser/components/places/content/treeView.js
@@ -1784,21 +1784,16 @@ PlacesTreeView.prototype = {
 
     return true;
   },
 
   setCellText: function PTV_setCellText(aRow, aColumn, aText) {
     // We may only get here if the cell is editable.
     let node = this._rows[aRow];
     if (node.title != aText) {
-      if (!PlacesUIUtils.useAsyncTransactions) {
-        let txn = new PlacesEditItemTitleTransaction(node.itemId, aText);
-        PlacesUtils.transactionManager.doTransaction(txn);
-        return;
-      }
       PlacesTransactions.EditTitle({ guid: node.bookmarkGuid, title: aText })
                         .transact().catch(Cu.reportError);
     }
   },
 
   toggleCutNode: function PTV_toggleCutNode(aNode, aValue) {
     let currentVal = this._cuttingNodes.has(aNode);
     if (currentVal != aValue) {
--- a/browser/components/places/tests/browser/browser.ini
+++ b/browser/components/places/tests/browser/browser.ini
@@ -38,17 +38,16 @@ skip-if = (os == 'win' && ccov) # Bug 14
 skip-if = (os == 'win' && ccov) # Bug 1423667
 [browser_check_correct_controllers.js]
 skip-if = (os == 'win' && ccov) # Bug 1423667
 [browser_click_bookmarks_on_toolbar.js]
 [browser_controller_onDrop_tagFolder.js]
 skip-if = (os == 'win' && ccov) # Bug 1423667
 [browser_controller_onDrop.js]
 skip-if = (os == 'win' && ccov) # Bug 1423667
-[browser_copy_folder_tree.js]
 [browser_copy_query_without_tree.js]
 skip-if = (os == 'win' && ccov) # Bug 1423667
 subsuite = clipboard
 [browser_cutting_bookmarks.js]
 skip-if = (os == 'win' && ccov) # Bug 1423667
 subsuite = clipboard
 [browser_drag_bookmarks_on_toolbar.js]
 [browser_forgetthissite_single.js]
--- a/browser/components/places/tests/browser/browser_bookmarkProperties_cancel.js
+++ b/browser/components/places/tests/browser/browser_bookmarkProperties_cancel.js
@@ -29,21 +29,16 @@ add_task(async function setup() {
   // Undo is called asynchronously - and not waited for. Since we're not
   // expecting undo to be called, we can only tell this by stubbing it.
   sandbox.stub(PlacesTransactions, "undo").returns(Promise.resolve());
 });
 
 // Tests for bug 1391393 - Ensures that if the user cancels the bookmark properties
 // dialog without having done any changes, then no undo is called.
 add_task(async function test_cancel_with_no_changes() {
-  if (!PlacesUIUtils.useAsyncTransactions) {
-    Assert.ok(true, "Skipping test as async transactions are turned off");
-    return;
-  }
-
   await withSidebarTree("bookmarks", async (tree) => {
     tree.selectItems([bookmarks[0].guid]);
 
     // Delete the bookmark to put something in the undo history.
     // Rather than calling cmd_delete, we call the remove directly, so that we
     // can await on it finishing, and be guaranteed that there's something
     // in the history.
     await tree.controller.remove("Remove Selection");
@@ -70,21 +65,16 @@ add_task(async function test_cancel_with
     Assert.ok(await PlacesUtils.bookmarks.fetch(bookmarks[1].guid),
       "The second bookmark should still exist");
 
     Assert.ok(PlacesTransactions.undo.notCalled, "undo should not have been called");
   });
 });
 
 add_task(async function test_cancel_with_changes() {
-  if (!PlacesUIUtils.useAsyncTransactions) {
-    Assert.ok(true, "Skipping test as async transactions are turned off");
-    return;
-  }
-
   await withSidebarTree("bookmarks", async (tree) => {
     tree.selectItems([bookmarks[1].guid]);
 
     // Now open the bookmarks dialog and cancel it.
     await withBookmarksDialog(
       true,
       function openDialog() {
         tree.controller.doCommand("placesCmd_show:info");
--- a/browser/components/places/tests/browser/browser_controller_onDrop.js
+++ b/browser/components/places/tests/browser/browser_controller_onDrop.js
@@ -54,21 +54,16 @@ add_task(async function setup() {
     bookmarks[0].guid,
     bookmarks[1].guid,
     bookmarks[2].guid,
   ]);
 });
 
 async function run_drag_test(startBookmarkIndex, insertionIndex, newParentGuid,
                              expectedInsertionIndex, expectTransactionCreated = true) {
-  if (!PlacesUIUtils.useAsyncTransactions) {
-    Assert.ok(true, "Skipping test as async transactions are turned off");
-    return;
-  }
-
   if (!newParentGuid) {
     newParentGuid = PlacesUtils.bookmarks.unfiledGuid;
   }
 
   // Reset the stubs so that previous test runs don't count against us.
   PlacesUIUtils.getTransactionForData.reset();
   PlacesTransactions.batch.reset();
 
--- a/browser/components/places/tests/browser/browser_controller_onDrop_tagFolder.js
+++ b/browser/components/places/tests/browser/browser_controller_onDrop_tagFolder.js
@@ -34,21 +34,16 @@ add_task(async function setup() {
       url: "http://example2.com",
       tags: [TAG_NAME]
     }]
   });
   bookmarkId = await PlacesUtils.promiseItemId(bookmarks[0].guid);
 });
 
 async function run_drag_test(startBookmarkIndex, newParentGuid) {
-  if (!PlacesUIUtils.useAsyncTransactions) {
-    Assert.ok(true, "Skipping test as async transactions are turned off");
-    return;
-  }
-
   if (!newParentGuid) {
     newParentGuid = PlacesUtils.bookmarks.unfiledGuid;
   }
 
   // Reset the stubs so that previous test runs don't count against us.
   PlacesTransactions.Tag.reset();
   PlacesTransactions.batch.reset();
 
deleted file mode 100644
--- a/browser/components/places/tests/browser/browser_copy_folder_tree.js
+++ /dev/null
@@ -1,123 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-/*
- Deep copy of bookmark data, using the front-end codepath:
-
- - create test folder A
- - add a subfolder to folder A, and add items to it
- - validate folder A (sanity check)
- - copy folder A, creating new folder B, using the front-end path
- - validate folder B
- - undo copy transaction
- - validate folder B (empty)
- - redo copy transaction
- - validate folder B's contents
-*/
-
-add_task(async function() {
-  let toolbarId = PlacesUtils.toolbarFolderId;
-  let toolbarNode = PlacesUtils.getFolderContents(toolbarId).root;
-
-  let oldCount = toolbarNode.childCount;
-  let testRoot = await PlacesUtils.bookmarks.insert({
-    parentGuid: PlacesUtils.bookmarks.toolbarGuid,
-    type: PlacesUtils.bookmarks.TYPE_FOLDER,
-    title: "test root"
-  });
-  is(toolbarNode.childCount, oldCount + 1, "confirm test root node is a container, and is empty");
-
-  let testRootNode = toolbarNode.getChild(toolbarNode.childCount - 1);
-  testRootNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
-  testRootNode.containerOpen = true;
-  is(testRootNode.childCount, 0, "confirm test root node is a container, and is empty");
-
-  // create folder A, fill it, validate its contents
-  let folderA = await PlacesUtils.bookmarks.insert({
-    type: PlacesUtils.bookmarks.TYPE_FOLDER,
-    parentGuid: testRoot.guid,
-    title: "A"
-  });
-
-  await populate(folderA);
-
-  let folderAId = await PlacesUtils.promiseItemId(folderA.guid);
-  let folderANode = PlacesUtils.getFolderContents(folderAId).root;
-  validate(folderANode);
-  is(testRootNode.childCount, 1, "create test folder");
-
-  // copy it, using the front-end helper functions
-  let serializedNode = PlacesUtils.wrapNode(folderANode, PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER);
-  let rawNode = PlacesUtils.unwrapNodes(serializedNode, PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER).shift();
-  // confirm serialization
-  ok(rawNode.type, "confirm json node");
-  folderANode.containerOpen = false;
-
-  let testRootId = await PlacesUtils.promiseItemId(testRoot.guid);
-  let transaction = PlacesUIUtils.makeTransaction(rawNode,
-                                                  PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
-                                                  testRootId,
-                                                  -1,
-                                                  true);
-  ok(transaction, "create transaction");
-  PlacesUtils.transactionManager.doTransaction(transaction);
-  // confirm copy
-  is(testRootNode.childCount, 2, "create test folder via copy");
-
-  // validate the copy
-  let folderBNode = testRootNode.getChild(1);
-  validate(folderBNode);
-
-  // undo the transaction, confirm the removal
-  PlacesUtils.transactionManager.undoTransaction();
-  is(testRootNode.childCount, 1, "confirm undo removed the copied folder");
-
-  // redo the transaction
-  PlacesUtils.transactionManager.redoTransaction();
-  is(testRootNode.childCount, 2, "confirm redo re-copied the folder");
-  folderBNode = testRootNode.getChild(1);
-  validate(folderBNode);
-
-  // Close containers, cleaning up their observers.
-  testRootNode.containerOpen = false;
-  toolbarNode.containerOpen = false;
-
-  // clean up
-  PlacesUtils.transactionManager.undoTransaction();
-  await PlacesUtils.bookmarks.remove(folderA.guid);
-});
-
-var populate = async function(parentFolder) {
-  let folder = await PlacesUtils.bookmarks.insert({
-    type: PlacesUtils.bookmarks.TYPE_FOLDER,
-    parentGuid: parentFolder.guid,
-    title: "test folder"
-  });
-
-  await PlacesUtils.bookmarks.insert({
-    type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
-    parentGuid: folder.guid,
-    title: "test bookmark",
-    url: "http://foo"
-  });
-
-  await PlacesUtils.bookmarks.insert({
-    type: PlacesUtils.bookmarks.TYPE_SEPARATOR,
-    parentGuid: folder.guid
-  });
-};
-
-function validate(aNode) {
-  PlacesUtils.asContainer(aNode);
-  aNode.containerOpen = true;
-  is(aNode.childCount, 1, "confirm child count match");
-  var folderNode = aNode.getChild(0);
-  is(folderNode.title, "test folder", "confirm folder title");
-  PlacesUtils.asContainer(folderNode);
-  folderNode.containerOpen = true;
-  is(folderNode.childCount, 2, "confirm child count match");
-  folderNode.containerOpen = false;
-  aNode.containerOpen = false;
-}
deleted file mode 100644
--- a/browser/components/places/tests/unit/test_PUIU_makeTransaction.js
+++ /dev/null
@@ -1,330 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-function waitForBookmarkNotification(aNotification, aCallback, aProperty) {
-  PlacesUtils.bookmarks.addObserver({
-    validate(aMethodName, aData) {
-      if (aMethodName == aNotification &&
-          (!aProperty || aProperty == aData.property)) {
-        PlacesUtils.bookmarks.removeObserver(this);
-        aCallback(aData);
-      }
-    },
-
-    // nsINavBookmarkObserver
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver]),
-    onBeginUpdateBatch: function onBeginUpdateBatch() {
-      return this.validate("onBeginUpdateBatch", arguments);
-    },
-    onEndUpdateBatch: function onEndUpdateBatch() {
-      return this.validate("onEndUpdateBatch", arguments);
-    },
-    onItemAdded: function onItemAdded(aItemId, aParentId, aIndex, aItemType,
-                                      aURI, aTitle) {
-      return this.validate("onItemAdded", { id: aItemId,
-                                                    index: aIndex,
-                                                    type: aItemType,
-                                                    url: aURI ? aURI.spec : null,
-                                                    title: aTitle });
-    },
-    onItemRemoved: function onItemRemoved() {
-      return this.validate("onItemRemoved", arguments);
-    },
-    onItemChanged: function onItemChanged(id, property, aIsAnno,
-                                          aNewValue, aLastModified, type) {
-      return this.validate("onItemChanged",
-                           { id,
-                             get index() {
-                               return PlacesUtils.bookmarks.getItemIndex(this.id);
-                             },
-                             type,
-                             property,
-                             get url() {
-                               return type == PlacesUtils.bookmarks.TYPE_BOOKMARK ?
-                                      PlacesUtils.bookmarks.getBookmarkURI(this.id).spec :
-                                      null;
-                             },
-                             get title() {
-                               return PlacesUtils.bookmarks.getItemTitle(this.id);
-                             },
-                           });
-    },
-    onItemVisited: function onItemVisited() {
-      return this.validate("onItemVisited", arguments);
-    },
-    onItemMoved: function onItemMoved(aItemId, aOldParentId, aOldIndex,
-                                      aNewParentId, aNewIndex, aItemType) {
-      this.validate("onItemMoved", { id: aItemId,
-                                             index: aNewIndex,
-                                             type: aItemType });
-    }
-  });
-}
-
-function wrapNodeByIdAndParent(aItemId, aParentId) {
-  let wrappedNode;
-  let root = PlacesUtils.getFolderContents(aParentId, false, false).root;
-  for (let i = 0; i < root.childCount; ++i) {
-    let node = root.getChild(i);
-    if (node.itemId == aItemId) {
-      let type;
-      if (PlacesUtils.nodeIsContainer(node)) {
-        type = PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER;
-      } else if (PlacesUtils.nodeIsURI(node)) {
-        type = PlacesUtils.TYPE_X_MOZ_PLACE;
-      } else if (PlacesUtils.nodeIsSeparator(node)) {
-        type = PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR;
-      } else {
-        do_throw("Unknown node type");
-      }
-      wrappedNode = PlacesUtils.wrapNode(node, type);
-    }
-  }
-  root.containerOpen = false;
-  return JSON.parse(wrappedNode);
-}
-
-add_test(function test_text_paste() {
-  const TEST_URL = "http://places.moz.org/";
-  const TEST_TITLE = "Places bookmark";
-
-  waitForBookmarkNotification("onItemAdded", function(aData) {
-    Assert.equal(aData.title, TEST_TITLE);
-    Assert.equal(aData.url, TEST_URL);
-    Assert.equal(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
-    Assert.equal(aData.index, 0);
-    run_next_test();
-  });
-
-  let txn = PlacesUIUtils.makeTransaction(
-    { title: TEST_TITLE, uri: TEST_URL },
-    PlacesUtils.TYPE_X_MOZ_URL,
-    PlacesUtils.unfiledBookmarksFolderId,
-    PlacesUtils.bookmarks.DEFAULT_INDEX,
-    true // Unused for text.
-  );
-  PlacesUtils.transactionManager.doTransaction(txn);
-});
-
-add_test(function test_container() {
-  const TEST_TITLE = "Places folder";
-
-  waitForBookmarkNotification("onItemChanged", function(aChangedData) {
-    Assert.equal(aChangedData.title, TEST_TITLE);
-    Assert.equal(aChangedData.type, PlacesUtils.bookmarks.TYPE_FOLDER);
-    Assert.equal(aChangedData.index, 1);
-
-    waitForBookmarkNotification("onItemAdded", function(aAddedData) {
-      Assert.equal(aAddedData.title, TEST_TITLE);
-      Assert.equal(aAddedData.type, PlacesUtils.bookmarks.TYPE_FOLDER);
-      Assert.equal(aAddedData.index, 2);
-      let id = aAddedData.id;
-
-      waitForBookmarkNotification("onItemMoved", function(aMovedData) {
-        Assert.equal(aMovedData.id, id);
-        Assert.equal(aMovedData.type, PlacesUtils.bookmarks.TYPE_FOLDER);
-        Assert.equal(aMovedData.index, 1);
-
-        run_next_test();
-      });
-
-      let txn = PlacesUIUtils.makeTransaction(
-        wrapNodeByIdAndParent(aAddedData.id, PlacesUtils.unfiledBookmarksFolderId),
-        0, // Unused for real nodes.
-        PlacesUtils.unfiledBookmarksFolderId,
-        1, // Move to position 1.
-        false
-      );
-      PlacesUtils.transactionManager.doTransaction(txn);
-    });
-
-    try {
-    let txn = PlacesUIUtils.makeTransaction(
-      wrapNodeByIdAndParent(aChangedData.id, PlacesUtils.unfiledBookmarksFolderId),
-      0, // Unused for real nodes.
-      PlacesUtils.unfiledBookmarksFolderId,
-      PlacesUtils.bookmarks.DEFAULT_INDEX,
-      true
-    );
-    PlacesUtils.transactionManager.doTransaction(txn);
-    } catch (ex) {
-      do_throw(ex);
-    }
-  }, "random-anno");
-
-  let id = PlacesUtils.bookmarks.createFolder(PlacesUtils.unfiledBookmarksFolderId,
-                                              TEST_TITLE,
-                                              PlacesUtils.bookmarks.DEFAULT_INDEX);
-  PlacesUtils.annotations.setItemAnnotation(id, PlacesUIUtils.DESCRIPTION_ANNO,
-                                            "description", 0,
-                                            PlacesUtils.annotations.EXPIRE_NEVER);
-  PlacesUtils.annotations.setItemAnnotation(id, "random-anno",
-                                            "random-value", 0,
-                                            PlacesUtils.annotations.EXPIRE_NEVER);
-});
-
-
-add_test(function test_separator() {
-  waitForBookmarkNotification("onItemChanged", function(aChangedData) {
-    Assert.equal(aChangedData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR);
-    Assert.equal(aChangedData.index, 3);
-
-    waitForBookmarkNotification("onItemAdded", function(aAddedData) {
-      Assert.equal(aAddedData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR);
-      Assert.equal(aAddedData.index, 4);
-      let id = aAddedData.id;
-
-      waitForBookmarkNotification("onItemMoved", function(aMovedData) {
-        Assert.equal(aMovedData.id, id);
-        Assert.equal(aMovedData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR);
-        Assert.equal(aMovedData.index, 1);
-
-        run_next_test();
-      });
-
-      let txn = PlacesUIUtils.makeTransaction(
-        wrapNodeByIdAndParent(aAddedData.id, PlacesUtils.unfiledBookmarksFolderId),
-        0, // Unused for real nodes.
-        PlacesUtils.unfiledBookmarksFolderId,
-        1, // Move to position 1.
-        false
-      );
-      PlacesUtils.transactionManager.doTransaction(txn);
-    });
-
-    try {
-    let txn = PlacesUIUtils.makeTransaction(
-      wrapNodeByIdAndParent(aChangedData.id, PlacesUtils.unfiledBookmarksFolderId),
-      0, // Unused for real nodes.
-      PlacesUtils.unfiledBookmarksFolderId,
-      PlacesUtils.bookmarks.DEFAULT_INDEX,
-      true
-    );
-    PlacesUtils.transactionManager.doTransaction(txn);
-    } catch (ex) {
-      do_throw(ex);
-    }
-  }, "random-anno");
-
-  let id = PlacesUtils.bookmarks.insertSeparator(PlacesUtils.unfiledBookmarksFolderId,
-                                                 PlacesUtils.bookmarks.DEFAULT_INDEX);
-  PlacesUtils.annotations.setItemAnnotation(id, "random-anno",
-                                            "random-value", 0,
-                                            PlacesUtils.annotations.EXPIRE_NEVER);
-});
-
-add_test(function test_bookmark() {
-  const TEST_URL = "http://places.moz.org/";
-  const TEST_TITLE = "Places bookmark";
-
-  waitForBookmarkNotification("onItemChanged", function(aChangedData) {
-    Assert.equal(aChangedData.title, TEST_TITLE);
-    Assert.equal(aChangedData.url, TEST_URL);
-    Assert.equal(aChangedData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
-    Assert.equal(aChangedData.index, 5);
-
-    waitForBookmarkNotification("onItemAdded", function(aAddedData) {
-      Assert.equal(aAddedData.title, TEST_TITLE);
-      Assert.equal(aAddedData.url, TEST_URL);
-      Assert.equal(aAddedData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
-      Assert.equal(aAddedData.index, 6);
-      let id = aAddedData.id;
-
-      waitForBookmarkNotification("onItemMoved", function(aMovedData) {
-        Assert.equal(aMovedData.id, id);
-        Assert.equal(aMovedData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
-        Assert.equal(aMovedData.index, 1);
-
-        run_next_test();
-      });
-
-      let txn = PlacesUIUtils.makeTransaction(
-        wrapNodeByIdAndParent(aAddedData.id, PlacesUtils.unfiledBookmarksFolderId),
-        0, // Unused for real nodes.
-        PlacesUtils.unfiledBookmarksFolderId,
-        1, // Move to position 1.
-        false
-      );
-      PlacesUtils.transactionManager.doTransaction(txn);
-    });
-
-    try {
-    let txn = PlacesUIUtils.makeTransaction(
-      wrapNodeByIdAndParent(aChangedData.id, PlacesUtils.unfiledBookmarksFolderId),
-      0, // Unused for real nodes.
-      PlacesUtils.unfiledBookmarksFolderId,
-      PlacesUtils.bookmarks.DEFAULT_INDEX,
-      true
-    );
-    PlacesUtils.transactionManager.doTransaction(txn);
-    } catch (ex) {
-      do_throw(ex);
-    }
-  }, "random-anno");
-
-  let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
-                                                NetUtil.newURI(TEST_URL),
-                                                PlacesUtils.bookmarks.DEFAULT_INDEX,
-                                                TEST_TITLE);
-  PlacesUtils.annotations.setItemAnnotation(id, PlacesUIUtils.DESCRIPTION_ANNO,
-                                            "description", 0,
-                                            PlacesUtils.annotations.EXPIRE_NEVER);
-  PlacesUtils.annotations.setItemAnnotation(id, "random-anno",
-                                            "random-value", 0,
-                                            PlacesUtils.annotations.EXPIRE_NEVER);
-});
-
-add_test(function test_visit() {
-  const TEST_URL = "http://places.moz.org/";
-  const TEST_TITLE = "Places bookmark";
-
-  waitForBookmarkNotification("onItemAdded", function(aAddedData) {
-    Assert.equal(aAddedData.title, TEST_TITLE);
-    Assert.equal(aAddedData.url, TEST_URL);
-    Assert.equal(aAddedData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
-    Assert.equal(aAddedData.index, 7);
-
-    waitForBookmarkNotification("onItemAdded", function(aAddedData2) {
-      Assert.equal(aAddedData2.title, TEST_TITLE);
-      Assert.equal(aAddedData2.url, TEST_URL);
-      Assert.equal(aAddedData2.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
-      Assert.equal(aAddedData2.index, 8);
-      run_next_test();
-    });
-
-    try {
-    let node = wrapNodeByIdAndParent(aAddedData.id, PlacesUtils.unfiledBookmarksFolderId);
-    // Simulate a not-bookmarked node, will copy it to a new bookmark.
-    node.id = -1;
-    let txn = PlacesUIUtils.makeTransaction(
-      node,
-      0, // Unused for real nodes.
-      PlacesUtils.unfiledBookmarksFolderId,
-      PlacesUtils.bookmarks.DEFAULT_INDEX,
-      true
-    );
-    PlacesUtils.transactionManager.doTransaction(txn);
-    } catch (ex) {
-      do_throw(ex);
-    }
-  });
-
-  PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
-                                       NetUtil.newURI(TEST_URL),
-                                       PlacesUtils.bookmarks.DEFAULT_INDEX,
-                                       TEST_TITLE);
-});
-
-add_test(function check_annotations() {
-  // As last step check how many items for each annotation exist.
-
-  // Copies should retain the description annotation.
-  let descriptions =
-    PlacesUtils.annotations.getItemsWithAnnotation(PlacesUIUtils.DESCRIPTION_ANNO, {});
-  Assert.equal(descriptions.length, 4);
-
-  // Only the original bookmarks should have this annotation.
-  let others = PlacesUtils.annotations.getItemsWithAnnotation("random-anno", {});
-  Assert.equal(others.length, 3);
-  run_next_test();
-});
--- a/browser/components/places/tests/unit/xpcshell.ini
+++ b/browser/components/places/tests/unit/xpcshell.ini
@@ -17,10 +17,8 @@ support-files =
 [test_browserGlue_migrate.js]
 [test_browserGlue_prefs.js]
 [test_browserGlue_restore.js]
 [test_browserGlue_smartBookmarks.js]
 [test_browserGlue_urlbar_defaultbehavior_migration.js]
 [test_clearHistory_shutdown.js]
 [test_leftpane_corruption_handling.js]
 [test_PUIU_batchUpdatesForNode.js]
-[test_PUIU_makeTransaction.js]
-skip-if = (os == 'win' && ccov) # Bug 1423667