Backed out changeset c62d6e8a7407 (bug 1150678) for Windows opt test_bookmark_store.js failures.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 06 Sep 2016 22:10:21 -0400
changeset 350117 3a0fd1bb116a3b79b6f33462a04144818b550ee9
parent 350116 2374ab2d2b77a203efeef432a98f2b04c36f4749
child 350118 4b4cc630c39914a480dc04ef773ee17ed01baf42
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1150678
milestone50.0a2
backs outc62d6e8a740719270dcc4b64148ae8c694343e4a
Backed out changeset c62d6e8a7407 (bug 1150678) for Windows opt test_bookmark_store.js failures.
browser/components/places/content/editBookmarkOverlay.js
toolkit/components/places/Database.cpp
toolkit/components/places/Database.h
toolkit/components/places/PlacesTransactions.jsm
toolkit/components/places/PlacesUtils.jsm
toolkit/components/places/tests/head_common.js
toolkit/components/places/tests/migration/places_v34.sqlite
toolkit/components/places/tests/migration/xpcshell.ini
toolkit/components/places/tests/unit/test_async_transactions.js
toolkit/components/places/tests/unit/test_keywords.js
toolkit/components/places/tests/unit/test_placesTxn.js
--- a/browser/components/places/content/editBookmarkOverlay.js
+++ b/browser/components/places/content/editBookmarkOverlay.js
@@ -126,28 +126,24 @@ var gEditItemOverlay = {
   _initDescriptionField() {
     if (!this._paneInfo.isItem)
       throw new Error("_initDescriptionField called unexpectedly");
 
     this._initTextField(this._descriptionField,
                         PlacesUIUtils.getItemDescription(this._paneInfo.itemId));
   },
 
-  _initKeywordField: Task.async(function* (newKeyword = "") {
-    if (!this._paneInfo.isBookmark) {
+  _initKeywordField: Task.async(function* (aNewKeyword) {
+    if (!this._paneInfo.isBookmark)
       throw new Error("_initKeywordField called unexpectedly");
-    }
 
-    if (!newKeyword) {
-      let entries = [];
-      yield PlacesUtils.keywords.fetch({ url: this._paneInfo.uri.spec },
-                                       e => entries.push(e));
-      if (entries.length > 0) {
-        this._keyword = newKeyword = entries[0].keyword;
-      }
+    let newKeyword = aNewKeyword;
+    if (newKeyword === undefined) {
+      let itemId = this._paneInfo.itemId;
+      newKeyword = PlacesUtils.bookmarks.getKeywordForBookmark(itemId);
     }
     this._initTextField(this._keywordField, newKeyword);
   }),
 
   _initLoadInSidebar: Task.async(function* () {
     if (!this._paneInfo.isBookmark)
       throw new Error("_initLoadInSidebar called unexpectedly");
 
@@ -214,17 +210,17 @@ var gEditItemOverlay = {
     // hide the description field for
     if (showOrCollapse("descriptionRow", isItem && !this.readOnly,
                        "description")) {
       this._initDescriptionField();
       this._descriptionField.readOnly = this.readOnly;
     }
 
     if (showOrCollapse("keywordRow", isBookmark, "keyword")) {
-      this._initKeywordField().catch(Components.utils.reportError);
+      this._initKeywordField();
       this._keywordField.readOnly = this.readOnly;
     }
 
     // Collapse the tag selector if the item does not accept tags.
     if (showOrCollapse("tagsRow", isURI || bulkTagging, "tags"))
       this._initTagsField().catch(Components.utils.reportError);
     else if (!this._element("tagsSelectorRow").collapsed)
       this.toggleTagsSelector().catch(Components.utils.reportError);
@@ -567,17 +563,17 @@ var gEditItemOverlay = {
         return;
       }
       Task.spawn(function* () {
         let guid = this._paneInfo.isTag
                     ? (yield PlacesUtils.promiseItemGuid(this._paneInfo.itemId))
                     : this._paneInfo.itemGuid;
         PlacesTransactions.EditTitle({ guid, title: newTitle })
                           .transact().catch(Components.utils.reportError);
-      }).catch(Components.utils.reportError);
+      }).catch(Cu.reportError);
     }
   },
 
   onDescriptionFieldChange() {
     if (this.readOnly || !this._paneInfo.isItem)
       return;
 
     let itemId = this._paneInfo.itemId;
@@ -624,29 +620,24 @@ var gEditItemOverlay = {
                       .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;
+    let newKeyword = this._keywordField.value;
     if (!PlacesUIUtils.useAsyncTransactions) {
-      let txn = new PlacesEditBookmarkKeywordTransaction(itemId,
-                                                         keyword,
-                                                         postData,
-                                                         oldKeyword);
+      let txn = new PlacesEditBookmarkKeywordTransaction(itemId, newKeyword, this._paneInfo.postData);
       PlacesUtils.transactionManager.doTransaction(txn);
       return;
     }
     let guid = this._paneInfo.itemGuid;
-    PlacesTransactions.EditKeyword({ guid, keyword, postData, oldKeyword })
+    PlacesTransactions.EditKeyword({ guid, keyword: newKeyword })
                       .transact().catch(Components.utils.reportError);
   },
 
   onLoadInSidebarCheckboxCommand() {
     if (!this.initialized || !this._paneInfo.isBookmark)
       return;
 
     let annotation = { name : PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO };
@@ -1090,17 +1081,17 @@ var gEditItemOverlay = {
         if (this._paneInfo.visibleRows.has("tagsRow")) {
           delete this._paneInfo._cachedCommonTags;
           this._onTagsChange(aItemId);
         }
       }
       break;
     case "keyword":
       if (this._paneInfo.visibleRows.has("keywordRow"))
-        this._initKeywordField(aValue).catch(Components.utils.reportError);
+        this._initKeywordField(aValue);
       break;
     case PlacesUIUtils.DESCRIPTION_ANNO:
       if (this._paneInfo.visibleRows.has("descriptionRow"))
         this._initDescriptionField();
       break;
     case PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO:
       if (this._paneInfo.visibleRows.has("loadInSidebarCheckbox"))
         this._initLoadInSidebar();
--- a/toolkit/components/places/Database.cpp
+++ b/toolkit/components/places/Database.cpp
@@ -847,22 +847,17 @@ Database::InitSchema(bool* aDatabaseMigr
 
       // Firefox 49 uses schema version 32.
 
       if (currentSchemaVersion < 33) {
         rv = MigrateV33Up();
         NS_ENSURE_SUCCESS(rv, rv);
       }
 
-      if (currentSchemaVersion < 34) {
-        rv = MigrateV34Up();
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-
-      // Firefox 50 uses schema version 34.
+      // Firefox 50 uses schema version 33.
 
       // Schema Upgrades must add migration code here.
 
       rv = UpdateBookmarkRootTitles();
       // We don't want a broken localization to cause us to think
       // the database is corrupt and needs to be replaced.
       MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
@@ -1813,31 +1808,16 @@ Database::MigrateV33Up() {
 
   // Create an index on url_hash.
   rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_URL_HASH);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
-nsresult
-Database::MigrateV34Up() {
-  MOZ_ASSERT(NS_IsMainThread());
-
-  nsresult rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "DELETE FROM moz_keywords WHERE id IN ( "
-      "SELECT id FROM moz_keywords k "
-      "WHERE NOT EXISTS (SELECT 1 FROM moz_places h WHERE k.place_id = h.id) "
-    ")"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
 void
 Database::Shutdown()
 {
   // As the last step in the shutdown path, finalize the database handle.
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mClosed);
 
   // Break cycles with the shutdown blockers.
--- a/toolkit/components/places/Database.h
+++ b/toolkit/components/places/Database.h
@@ -13,17 +13,17 @@
 #include "mozilla/storage.h"
 #include "mozilla/storage/StatementCache.h"
 #include "mozilla/Attributes.h"
 #include "nsIEventTarget.h"
 #include "Shutdown.h"
 
 // This is the schema version. Update it at any schema change and add a
 // corresponding migrateVxx method below.
-#define DATABASE_SCHEMA_VERSION 34
+#define DATABASE_SCHEMA_VERSION 33
 
 // Fired after Places inited.
 #define TOPIC_PLACES_INIT_COMPLETE "places-init-complete"
 // Fired when initialization fails due to a locked database.
 #define TOPIC_DATABASE_LOCKED "places-database-locked"
 // This topic is received when the profile is about to be lost.  Places does
 // initial shutdown work and notifies TOPIC_PLACES_SHUTDOWN to all listeners.
 // Any shutdown work that requires the Places APIs should happen here.
@@ -264,17 +264,16 @@ protected:
   nsresult MigrateV25Up();
   nsresult MigrateV26Up();
   nsresult MigrateV27Up();
   nsresult MigrateV28Up();
   nsresult MigrateV30Up();
   nsresult MigrateV31Up();
   nsresult MigrateV32Up();
   nsresult MigrateV33Up();
-  nsresult MigrateV34Up();
 
   nsresult UpdateBookmarkRootTitles();
 
   friend class ConnectionShutdownBlocker;
 
 private:
   ~Database();
 
--- a/toolkit/components/places/PlacesTransactions.jsm
+++ b/toolkit/components/places/PlacesTransactions.jsm
@@ -880,17 +880,17 @@ function (aInput, aRequiredProps = [], a
 // Update the documentation at the top of this module if you add or
 // remove properties.
 DefineTransaction.defineInputProps(["url", "feedUrl", "siteUrl"],
                                    DefineTransaction.urlValidate, null);
 DefineTransaction.defineInputProps(["guid", "parentGuid", "newParentGuid"],
                                    DefineTransaction.guidValidate);
 DefineTransaction.defineInputProps(["title"],
                                    DefineTransaction.strOrNullValidate, null);
-DefineTransaction.defineInputProps(["keyword", "oldKeyword", "postData", "tag",
+DefineTransaction.defineInputProps(["keyword", "postData", "tag",
                                     "excludingAnnotation"],
                                    DefineTransaction.strValidate, "");
 DefineTransaction.defineInputProps(["index", "newIndex"],
                                    DefineTransaction.indexValidate,
                                    PlacesUtils.bookmarks.DEFAULT_INDEX);
 DefineTransaction.defineInputProps(["annotation"],
                                    DefineTransaction.annotationObjectValidate);
 DefineTransaction.defineArrayInputProp("guids", "guid");
@@ -995,22 +995,18 @@ function* createItemsFromBookmarksTree(a
     let guid = aRestoring ? aItem.guid : undefined;
     let parentId = yield PlacesUtils.promiseItemId(aParentGuid);
     let annos = aItem.annos ? [...aItem.annos] : [];
     switch (aItem.type) {
       case PlacesUtils.TYPE_X_MOZ_PLACE: {
         let uri = NetUtil.newURI(aItem.uri);
         itemId = PlacesUtils.bookmarks.insertBookmark(
           parentId, uri, aIndex, aItem.title, guid);
-        if ("keyword" in aItem) {
-          yield PlacesUtils.keywords.insert({
-            keyword: aItem.keyword,
-            url: uri.spec
-          });
-        }
+        if ("keyword" in aItem)
+          PlacesUtils.bookmarks.setKeywordForBookmark(itemId, aItem.keyword);
         if ("tags" in aItem) {
           PlacesUtils.tagging.tagURI(uri, aItem.tags.split(","));
         }
         break;
       }
       case PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER: {
         // Either a folder or a livemark
         let [feedURI, siteURI] = extractLivemarkDetails(annos);
@@ -1083,42 +1079,36 @@ var PT = PlacesTransactions;
  */
 PT.NewBookmark = DefineTransaction(["parentGuid", "url"],
                                    ["index", "title", "keyword", "postData",
                                     "annotations", "tags"]);
 PT.NewBookmark.prototype = Object.seal({
   execute: function (aParentGuid, aURI, aIndex, aTitle,
                      aKeyword, aPostData, aAnnos, aTags) {
     return ExecuteCreateItem(this, aParentGuid,
-      function* (parentId, guidToRestore = "") {
+      function (parentId, guidToRestore = "") {
         let itemId = PlacesUtils.bookmarks.insertBookmark(
           parentId, aURI, aIndex, aTitle, guidToRestore);
-
-        if (aKeyword) {
-          yield PlacesUtils.keywords.insert({
-            url: aURI.spec,
-            keyword: aKeyword,
-            postData: aPostData
-          });
-        }
-        if (aAnnos.length) {
+        if (aKeyword)
+          PlacesUtils.bookmarks.setKeywordForBookmark(itemId, aKeyword);
+        if (aPostData)
+          PlacesUtils.setPostDataForBookmark(itemId, aPostData);
+        if (aAnnos.length)
           PlacesUtils.setAnnotationsForItem(itemId, aAnnos);
-        }
         if (aTags.length > 0) {
           let currentTags = PlacesUtils.tagging.getTagsForURI(aURI);
           aTags = aTags.filter(t => !currentTags.includes(t));
           PlacesUtils.tagging.tagURI(aURI, aTags);
         }
 
         return itemId;
       },
       function _additionalOnUndo() {
-        if (aTags.length > 0) {
+        if (aTags.length > 0)
           PlacesUtils.tagging.untagURI(aURI, aTags);
-        }
       });
   }
 });
 
 /**
  * Transaction for creating a folder.
  *
  * Required Input Properties: title, parentGuid.
@@ -1126,17 +1116,17 @@ PT.NewBookmark.prototype = Object.seal({
  *
  * When this transaction is executed, it's resolved to the new folder's GUID.
  */
 PT.NewFolder = DefineTransaction(["parentGuid", "title"],
                                  ["index", "annotations"]);
 PT.NewFolder.prototype = Object.seal({
   execute: function (aParentGuid, aTitle, aIndex, aAnnos) {
     return ExecuteCreateItem(this,  aParentGuid,
-      function* (parentId, guidToRestore = "") {
+      function(parentId, guidToRestore = "") {
         let itemId = PlacesUtils.bookmarks.createFolder(
           parentId, aTitle, aIndex, guidToRestore);
         if (aAnnos.length > 0)
           PlacesUtils.setAnnotationsForItem(itemId, aAnnos);
         return itemId;
       });
   }
 });
@@ -1149,17 +1139,17 @@ PT.NewFolder.prototype = Object.seal({
  *
  * When this transaction is executed, it's resolved to the new separator's
  * GUID.
  */
 PT.NewSeparator = DefineTransaction(["parentGuid"], ["index"]);
 PT.NewSeparator.prototype = Object.seal({
   execute: function (aParentGuid, aIndex) {
     return ExecuteCreateItem(this, aParentGuid,
-      function* (parentId, guidToRestore = "") {
+      function (parentId, guidToRestore = "") {
         let itemId = PlacesUtils.bookmarks.insertSeparator(
           parentId, aIndex, guidToRestore);
         return itemId;
       });
   }
 });
 
 /**
@@ -1341,46 +1331,24 @@ PT.Annotate.prototype = {
   }
 };
 
 /**
  * Transaction for setting the keyword for a bookmark.
  *
  * Required Input Properties: guid, keyword.
  */
-PT.EditKeyword = DefineTransaction(["guid", "keyword"],
-                                   ["postData", "oldKeyword"]);
+PT.EditKeyword = DefineTransaction(["guid", "keyword"]);
 PT.EditKeyword.prototype = Object.seal({
-  execute: function* (aGuid, aKeyword, aPostData, aOldKeyword) {
-    let url;
-    let oldKeywordEntry;
-    if (aOldKeyword) {
-      oldKeywordEntry = yield PlacesUtils.keywords.fetch(aOldKeyword);
-      url = oldKeywordEntry.url;
-      yield PlacesUtils.keywords.remove(aOldKeyword);
-    }
-
-    if (aKeyword) {
-      if (!url) {
-        url = (yield PlacesUtils.bookmarks.fetch(aGuid)).url;
-      }
-      yield PlacesUtils.keywords.insert({
-        url: url,
-        keyword: aKeyword,
-        postData: aPostData || (oldKeywordEntry ? oldKeywordEntry.postData : "")
-      });
-    }
-
-    this.undo = function* () {
-      if (aKeyword) {
-        yield PlacesUtils.keywords.remove(aKeyword);
-      }
-      if (oldKeywordEntry) {
-        yield PlacesUtils.keywords.insert(oldKeywordEntry);
-      }
+  execute: function* (aGuid, aKeyword) {
+    let itemId = yield PlacesUtils.promiseItemId(aGuid),
+        oldKeyword = PlacesUtils.bookmarks.getKeywordForBookmark(itemId);
+    PlacesUtils.bookmarks.setKeywordForBookmark(itemId, aKeyword);
+    this.undo = () => {
+      PlacesUtils.bookmarks.setKeywordForBookmark(itemId, oldKeyword);
     };
   }
 });
 
 /**
  * Transaction for sorting a folder by name.
  *
  * Required Input Properties: guid.
--- a/toolkit/components/places/PlacesUtils.jsm
+++ b/toolkit/components/places/PlacesUtils.jsm
@@ -1660,18 +1660,17 @@ this.PlacesUtils = {
         default:
           Cu.reportError("Unexpected bookmark type");
           break;
       }
       return item;
     }.bind(this);
 
     const QUERY_STR =
-      `/* do not warn (bug no): cannot use an index */
-       WITH RECURSIVE
+      `WITH RECURSIVE
        descendants(fk, level, type, id, guid, parent, parentGuid, position,
                    title, dateAdded, lastModified) AS (
          SELECT b1.fk, 0, b1.type, b1.id, b1.guid, b1.parent,
                 (SELECT guid FROM moz_bookmarks WHERE id = b1.parent),
                 b1.position, b1.title, b1.dateAdded, b1.lastModified
          FROM moz_bookmarks b1 WHERE b1.guid=:item_guid
          UNION ALL
          SELECT b2.fk, level + 1, b2.type, b2.id, b2.guid, b2.parent,
@@ -2182,64 +2181,39 @@ XPCOMUtils.defineLazyGetter(this, "gKeyw
             if (!bookmark) {
               for (let keyword of keywords) {
                 yield PlacesUtils.keywords.remove(keyword);
               }
             }
           }).catch(Cu.reportError);
         },
 
-        onItemChanged(id, prop, isAnno, val, lastMod, itemType, parentId, guid,
-                      parentGuid, oldVal) {
-          if (gIgnoreKeywordNotifications) {
-            return;
-          }
-
-          if (prop == "keyword") {
-            this._onKeywordChanged(guid, val).catch(Cu.reportError);
-          } else if (prop == "uri") {
-            this._onUrlChanged(guid, val, oldVal).catch(Cu.reportError);
-          }
-        },
-
-        _onKeywordChanged: Task.async(function* (guid, keyword) {
-          let bookmark = yield PlacesUtils.bookmarks.fetch(guid);
-          // Due to mixed sync/async operations, by this time the bookmark could
-          // have disappeared and we already handle removals in onItemRemoved.
-          if (!bookmark) {
+        onItemChanged(id, prop, isAnno, val, lastMod, itemType, parentId, guid) {
+          if (gIgnoreKeywordNotifications ||
+              prop != "keyword")
             return;
-          }
-
-          if (keyword.length == 0) {
-            // We are removing a keyword.
-            let keywords = keywordsForHref(bookmark.url.href)
-            for (let kw of keywords) {
-              cache.delete(kw);
+
+          Task.spawn(function* () {
+            let bookmark = yield PlacesUtils.bookmarks.fetch(guid);
+            // By this time the bookmark could have gone, there's nothing we can do.
+            if (!bookmark)
+              return;
+
+            if (val.length == 0) {
+              // We are removing a keyword.
+              let keywords = keywordsForHref(bookmark.url.href)
+              for (let keyword of keywords) {
+                cache.delete(keyword);
+              }
+            } else {
+              // We are adding a new keyword.
+              cache.set(val, { keyword: val, url: bookmark.url });
             }
-          } else {
-            // We are adding a new keyword.
-            cache.set(keyword, { keyword, url: bookmark.url });
-          }
-        }),
-
-        _onUrlChanged: Task.async(function* (guid, url, oldUrl) {
-          // Check if the old url is associated with keywords.
-          let entries = [];
-          yield PlacesUtils.keywords.fetch({ url: oldUrl }, e => entries.push(e));
-          if (entries.length == 0) {
-            return;
-          }
-
-          // Move the keywords to the new url.
-          for (let entry of entries) {
-            yield PlacesUtils.keywords.remove(entry.keyword);
-            entry.url = new URL(url);
-            yield PlacesUtils.keywords.insert(entry);
-          }
-        }),
+          }).catch(Cu.reportError);
+        }
       };
 
       PlacesUtils.bookmarks.addObserver(observer, false);
       PlacesUtils.registerShutdownFunction(() => {
         PlacesUtils.bookmarks.removeObserver(observer);
       });
       return cache;
     })
@@ -3274,87 +3248,50 @@ PlacesSetPageAnnotationTransaction.proto
  * Transaction for editing a bookmark's keyword.
  *
  * @param aItemId
  *        id of the bookmark to edit
  * @param aNewKeyword
  *        new keyword for the bookmark
  * @param aNewPostData [optional]
  *        new keyword's POST data, if available
- * @param aOldKeyword [optional]
- *        old keyword of the bookmark
  *
  * @return nsITransaction object
  */
 this.PlacesEditBookmarkKeywordTransaction =
-  function PlacesEditBookmarkKeywordTransaction(aItemId, aNewKeyword,
-                                                aNewPostData, aOldKeyword) {
+ function PlacesEditBookmarkKeywordTransaction(aItemId, aNewKeyword, aNewPostData)
+{
   this.item = new TransactionItemCache();
   this.item.id = aItemId;
-  this.item.keyword = aOldKeyword;
-  this.item.href = (PlacesUtils.bookmarks.getBookmarkURI(aItemId)).spec;
   this.new = new TransactionItemCache();
   this.new.keyword = aNewKeyword;
   this.new.postData = aNewPostData
 }
 
 PlacesEditBookmarkKeywordTransaction.prototype = {
   __proto__: BaseTransaction.prototype,
 
   doTransaction: function EBKTXN_doTransaction()
   {
-    let done = false;
-    Task.spawn(function* () {
-      if (this.item.keyword) {
-        let oldEntry = yield PlacesUtils.keywords.fetch(this.item.keyword);
-        this.item.postData = oldEntry.postData;
-        yield PlacesUtils.keywords.remove(this.item.keyword);
-      }
-
-      if (this.new.keyword) {
-        yield PlacesUtils.keywords.insert({
-          url: this.item.href,
-          keyword: this.new.keyword,
-          postData: this.new.postData || this.item.postData
-        });
-      }
-    }.bind(this)).catch(Cu.reportError)
-                 .then(() => done = true);
-    // TODO: Until we can move to PlacesTransactions.jsm, we must spin the
-    // events loop :(
-    let thread = Services.tm.currentThread;
-    while (!done) {
-      thread.processNextEvent(true);
-    }
+    // Store the current values.
+    this.item.keyword = PlacesUtils.bookmarks.getKeywordForBookmark(this.item.id);
+    if (this.item.keyword)
+      this.item.postData = PlacesUtils.getPostDataForBookmark(this.item.id);
+
+    // Update the keyword.
+    PlacesUtils.bookmarks.setKeywordForBookmark(this.item.id, this.new.keyword);
+    if (this.new.keyword && this.new.postData)
+      PlacesUtils.setPostDataForBookmark(this.item.id, this.new.postData);
   },
 
   undoTransaction: function EBKTXN_undoTransaction()
   {
-
-    let done = false;
-    Task.spawn(function* () {
-      if (this.new.keyword) {
-        yield PlacesUtils.keywords.remove(this.new.keyword);
-      }
-
-      if (this.item.keyword) {
-        yield PlacesUtils.keywords.insert({
-          url: this.item.href,
-          keyword: this.item.keyword,
-          postData: this.item.postData
-        });
-      }
-    }.bind(this)).catch(Cu.reportError)
-                 .then(() => done = true);
-    // TODO: Until we can move to PlacesTransactions.jsm, we must spin the
-    // events loop :(
-    let thread = Services.tm.currentThread;
-    while (!done) {
-      thread.processNextEvent(true);
-    }
+    PlacesUtils.bookmarks.setKeywordForBookmark(this.item.id, this.item.keyword);
+    if (this.item.postData)
+      PlacesUtils.setPostDataForBookmark(this.item.id, this.item.postData);
   }
 };
 
 
 /**
  * Transaction for editing the post data associated with a bookmark.
  *
  * @param aItemId
--- a/toolkit/components/places/tests/head_common.js
+++ b/toolkit/components/places/tests/head_common.js
@@ -1,14 +1,14 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-const CURRENT_SCHEMA_VERSION = 34;
+const CURRENT_SCHEMA_VERSION = 33;
 const FIRST_UPGRADABLE_SCHEMA_VERSION = 11;
 
 const NS_APP_USER_PROFILE_50_DIR = "ProfD";
 const NS_APP_PROFILE_DIR_STARTUP = "ProfDS";
 
 // Shortcuts to transitions type.
 const TRANSITION_LINK = Ci.nsINavHistoryService.TRANSITION_LINK;
 const TRANSITION_TYPED = Ci.nsINavHistoryService.TRANSITION_TYPED;
deleted file mode 100644
index 474628996f90b85655edcf9a5dface1d122b1088..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/toolkit/components/places/tests/migration/xpcshell.ini
+++ b/toolkit/components/places/tests/migration/xpcshell.ini
@@ -15,17 +15,16 @@ support-files =
   places_v25.sqlite
   places_v26.sqlite
   places_v27.sqlite
   places_v28.sqlite
   places_v30.sqlite
   places_v31.sqlite
   places_v32.sqlite
   places_v33.sqlite
-  places_v34.sqlite
 
 [test_current_from_downgraded.js]
 [test_current_from_v6.js]
 [test_current_from_v11.js]
 [test_current_from_v19.js]
 [test_current_from_v24.js]
 [test_current_from_v25.js]
 [test_current_from_v26.js]
--- a/toolkit/components/places/tests/unit/test_async_transactions.js
+++ b/toolkit/components/places/tests/unit/test_async_transactions.js
@@ -676,22 +676,21 @@ add_task(function* test_remove_folder() 
   yield ensureItemsRemoved(folder_level_2_info, folder_level_2_info);
   observer.reset();
 
   yield PT.clearTransactionsHistory();
   ensureUndoState();
 });
 
 add_task(function* test_add_and_remove_bookmarks_with_additional_info() {
-  const testURI = NetUtil.newURI("http://add.remove.tag");
-  const TAG_1 = "TestTag1";
-  const TAG_2 = "TestTag2";
-  const KEYWORD = "test_keyword";
-  const POST_DATA = "post_data";
-  const ANNO = { name: "TestAnno", value: "TestAnnoValue" };
+  const testURI = NetUtil.newURI("http://add.remove.tag")
+      , TAG_1 = "TestTag1", TAG_2 = "TestTag2"
+      , KEYWORD = "test_keyword"
+      , POST_DATA = "post_data"
+      , ANNO = { name: "TestAnno", value: "TestAnnoValue" };
 
   let folder_info = createTestFolderInfo();
   folder_info.guid = yield PT.NewFolder(folder_info).transact();
   let ensureTags = ensureTagsForURI.bind(null, testURI);
 
   // Check that the NewBookmark transaction preserves tags.
   observer.reset();
   let b1_info = { parentGuid: folder_info.guid, url: testURI, tags: [TAG_1] };
@@ -745,37 +744,28 @@ add_task(function* test_add_and_remove_b
   ensureTags([TAG_1, TAG_2]);
 
   observer.reset();
   yield PT.undo();
   yield ensureItemsRemoved(b2_info);
   ensureTags([TAG_1]);
 
   // Check if Remove correctly restores keywords, tags and annotations.
-  // Since both bookmarks share the same uri, they also share the keyword that
-  // is not removed along with one of the bookmarks.
   observer.reset();
   yield PT.redo();
-  ensureItemsChanged({ guid: b2_info.guid
-                     , isAnnoProperty: true
-                     , property: ANNO.name
-                     , newValue: ANNO.value });
+  ensureItemsChanged(...b2_post_creation_changes);
   ensureTags([TAG_1, TAG_2]);
 
   // Test Remove for multiple items.
   observer.reset();
   yield PT.Remove(b1_info.guid).transact();
   yield PT.Remove(b2_info.guid).transact();
   yield PT.Remove(folder_info.guid).transact();
   yield ensureItemsRemoved(b1_info, b2_info, folder_info);
   ensureTags([]);
-  // There is no keyword removal notification cause all bookmarks are removed
-  // before the keyword itself, so there's no one to notify.
-  let entry = yield PlacesUtils.keywords.fetch(KEYWORD);
-  Assert.equal(entry, null, "keyword has been removed");
 
   observer.reset();
   yield PT.undo();
   yield ensureItemsAdded(folder_info);
   ensureTags([]);
 
   observer.reset();
   yield PT.undo();
@@ -1026,108 +1016,38 @@ add_task(function* test_edit_keyword() {
     ensureItemsChanged({ guid: bm_info.guid
                        , property: "keyword"
                        , newValue: aCurrentKeyword });
   }
 
   bm_info.guid = yield PT.NewBookmark(bm_info).transact();
 
   observer.reset();
-  yield PT.EditKeyword({ guid: bm_info.guid, keyword: KEYWORD, postData: "postData" }).transact();
+  yield PT.EditKeyword({ guid: bm_info.guid, keyword: KEYWORD }).transact();
   ensureKeywordChange(KEYWORD);
-  let entry = yield PlacesUtils.keywords.fetch(KEYWORD);
-  Assert.equal(entry.url.href, bm_info.url.spec);
-  Assert.equal(entry.postData, "postData");
 
   observer.reset();
   yield PT.undo();
   ensureKeywordChange();
-  entry = yield PlacesUtils.keywords.fetch(KEYWORD);
-  Assert.equal(entry, null);
 
   observer.reset();
   yield PT.redo();
   ensureKeywordChange(KEYWORD);
-  entry = yield PlacesUtils.keywords.fetch(KEYWORD);
-  Assert.equal(entry.url.href, bm_info.url.spec);
-  Assert.equal(entry.postData, "postData");
 
   // Cleanup
   observer.reset();
   yield PT.undo();
   ensureKeywordChange();
   yield PT.undo();
   ensureItemsRemoved(bm_info);
 
   yield PT.clearTransactionsHistory();
   ensureUndoState();
 });
 
-add_task(function* test_edit_specific_keyword() {
-  let bm_info = { parentGuid: rootGuid
-                , url: NetUtil.newURI("http://test.edit.keyword") };
-  bm_info.guid = yield PT.NewBookmark(bm_info).transact();
-  function ensureKeywordChange(aCurrentKeyword = "", aPreviousKeyword = "") {
-    ensureItemsChanged({ guid: bm_info.guid
-                       , property: "keyword"
-                       , newValue: aCurrentKeyword
-                       });
-  }
-
-  yield PlacesUtils.keywords.insert({ keyword: "kw1", url: bm_info.url.spec, postData: "postData1" });
-  yield PlacesUtils.keywords.insert({ keyword: "kw2", url: bm_info.url.spec, postData: "postData2" });
-  bm_info.guid = yield PT.NewBookmark(bm_info).transact();
-
-  observer.reset();
-  yield PT.EditKeyword({ guid: bm_info.guid, keyword: "keyword", oldKeyword: "kw2" }).transact();
-  ensureKeywordChange("keyword", "kw2");
-  let entry = yield PlacesUtils.keywords.fetch("kw1");
-  Assert.equal(entry.url.href, bm_info.url.spec);
-  Assert.equal(entry.postData, "postData1");
-  entry = yield PlacesUtils.keywords.fetch("keyword");
-  Assert.equal(entry.url.href, bm_info.url.spec);
-  Assert.equal(entry.postData, "postData2");
-  entry = yield PlacesUtils.keywords.fetch("kw2");
-  Assert.equal(entry, null);
-
-  observer.reset();
-  yield PT.undo();
-  ensureKeywordChange("kw2", "keyword");
-  entry = yield PlacesUtils.keywords.fetch("kw1");
-  Assert.equal(entry.url.href, bm_info.url.spec);
-  Assert.equal(entry.postData, "postData1");
-  entry = yield PlacesUtils.keywords.fetch("kw2");
-  Assert.equal(entry.url.href, bm_info.url.spec);
-  Assert.equal(entry.postData, "postData2");
-  entry = yield PlacesUtils.keywords.fetch("keyword");
-  Assert.equal(entry, null);
-
-  observer.reset();
-  yield PT.redo();
-  ensureKeywordChange("keyword", "kw2");
-  entry = yield PlacesUtils.keywords.fetch("kw1");
-  Assert.equal(entry.url.href, bm_info.url.spec);
-  Assert.equal(entry.postData, "postData1");
-  entry = yield PlacesUtils.keywords.fetch("keyword");
-  Assert.equal(entry.url.href, bm_info.url.spec);
-  Assert.equal(entry.postData, "postData2");
-  entry = yield PlacesUtils.keywords.fetch("kw2");
-  Assert.equal(entry, null);
-
-  // Cleanup
-  observer.reset();
-  yield PT.undo();
-  ensureKeywordChange("kw2");
-  yield PT.undo();
-  ensureItemsRemoved(bm_info);
-
-  yield PT.clearTransactionsHistory();
-  ensureUndoState();
-});
-
 add_task(function* test_tag_uri() {
   // This also tests passing uri specs.
   let bm_info_a = { url: "http://bookmarked.uri"
                   , parentGuid: rootGuid };
   let bm_info_b = { url: NetUtil.newURI("http://bookmarked2.uri")
                   , parentGuid: rootGuid };
   let unbookmarked_uri = NetUtil.newURI("http://un.bookmarked.uri");
 
--- a/toolkit/components/places/tests/unit/test_keywords.js
+++ b/toolkit/components/places/tests/unit/test_keywords.js
@@ -508,29 +508,11 @@ add_task(function* test_oldKeywordsAPI()
   yield PlacesUtils.keywords.insert({ keyword: "keyword", url: "http://example.com" });
   Assert.equal(PlacesUtils.bookmarks.getKeywordForBookmark(itemId), "keyword");
   Assert.equal(PlacesUtils.bookmarks.getURIForKeyword("keyword").spec, "http://example.com/");
   yield PlacesUtils.bookmarks.remove(bookmark);
 
   check_no_orphans();
 });
 
-add_task(function* test_bookmarkURLChange() {
-  let fc1 = yield foreign_count("http://example1.com/");
-  let fc2 = yield foreign_count("http://example2.com/");
-  let bookmark = yield PlacesUtils.bookmarks.insert({ url: "http://example1.com/",
-                                                      type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
-                                                      parentGuid: PlacesUtils.bookmarks.unfiledGuid });
-  yield PlacesUtils.keywords.insert({ keyword: "keyword",
-                                      url: "http://example1.com/" });
-
-  yield check_keyword(true, "http://example1.com/", "keyword");
-  Assert.equal((yield foreign_count("http://example1.com/")), fc1 + 2); // +1 bookmark +1 keyword
-
-  yield PlacesUtils.bookmarks.update({ guid: bookmark.guid,
-                                       url: "http://example2.com/"});
-  yield promiseKeyword("keyword", "http://example2.com/");
-
-  yield check_keyword(false, "http://example1.com/", "keyword");
-  yield check_keyword(true, "http://example2.com/", "keyword");
-  Assert.equal((yield foreign_count("http://example1.com/")), fc1); // -1 bookmark -1 keyword
-  Assert.equal((yield foreign_count("http://example2.com/")), fc2 + 2); // +1 bookmark +1 keyword
-});
+function run_test() {
+  run_next_test();
+}
--- a/toolkit/components/places/tests/unit/test_placesTxn.js
+++ b/toolkit/components/places/tests/unit/test_placesTxn.js
@@ -550,50 +550,16 @@ add_task(function* test_edit_keyword() {
 
   txn.undoTransaction();
   do_check_eq(observer._itemChangedId, testBkmId);
   do_check_eq(observer._itemChangedProperty, "keyword");
   do_check_eq(observer._itemChangedValue, "");
   do_check_eq(PlacesUtils.getPostDataForBookmark(testBkmId), null);
 });
 
-add_task(function* test_edit_specific_keyword() {
-  const KEYWORD = "keyword-test_edit_keyword2";
-
-  let testURI = NetUtil.newURI("http://test_edit_keyword2.com");
-  let testBkmId = bmsvc.insertBookmark(root, testURI, bmsvc.DEFAULT_INDEX, "Test edit keyword");
-  // Add multiple keyword to this uri.
-  yield PlacesUtils.keywords.insert({ keyword: "kw1", url: testURI.spec, postData: "postData1" });
-  yield PlacesUtils.keywords.insert({keyword: "kw2", url: testURI.spec, postData: "postData2" });
-
-  // Try to change only kw2.
-  let txn = new PlacesEditBookmarkKeywordTransaction(testBkmId, KEYWORD, "postData2", "kw2");
-
-  txn.doTransaction();
-  do_check_eq(observer._itemChangedId, testBkmId);
-  do_check_eq(observer._itemChangedProperty, "keyword");
-  do_check_eq(observer._itemChangedValue, KEYWORD);
-  let entry = yield PlacesUtils.keywords.fetch("kw1");
-  Assert.equal(entry.url.href, testURI.spec);
-  Assert.equal(entry.postData, "postData1");
-  yield promiseKeyword(KEYWORD, testURI.spec, "postData2");
-  yield promiseKeyword("kw2", null);
-
-  txn.undoTransaction();
-  do_check_eq(observer._itemChangedId, testBkmId);
-  do_check_eq(observer._itemChangedProperty, "keyword");
-  do_check_eq(observer._itemChangedValue, "kw2");
-  do_check_eq(PlacesUtils.getPostDataForBookmark(testBkmId), "postData1");
-  entry = yield PlacesUtils.keywords.fetch("kw1");
-  Assert.equal(entry.url.href, testURI.spec);
-  Assert.equal(entry.postData, "postData1");
-  yield promiseKeyword("kw2", testURI.spec, "postData2");
-  yield promiseKeyword("keyword", null);
-});
-
 add_task(function* test_LoadInSidebar_transaction() {
   let testURI = NetUtil.newURI("http://test_LoadInSidebar_transaction.com");
   let testBkmId = bmsvc.insertBookmark(root, testURI, bmsvc.DEFAULT_INDEX, "Test LoadInSidebar transaction");
 
   const LOAD_IN_SIDEBAR_ANNO = "bookmarkProperties/loadInSidebar";
   let anno = { name: LOAD_IN_SIDEBAR_ANNO,
                type: Ci.nsIAnnotationService.TYPE_INT32,
                flags: 0,