Bug 1436966 - Remove the bookmark-observers & history-observers category listeners. r?mak draft
authorMark Banner <standard8@mozilla.com>
Fri, 09 Feb 2018 11:21:14 +0000
changeset 753129 9b4a5935b6e74227fbc1851339e0d952de063dce
parent 753128 aac7218d86242042f836d6258ff46dc7e4d62df2
push id98483
push userbmo:standard8@mozilla.com
push dateFri, 09 Feb 2018 17:08:31 +0000
reviewersmak
bugs1436966
milestone60.0a1
Bug 1436966 - Remove the bookmark-observers & history-observers category listeners. r?mak MozReview-Commit-ID: 2dsyxZG98IR
toolkit/components/places/nsNavBookmarks.cpp
toolkit/components/places/nsNavBookmarks.h
toolkit/components/places/nsNavHistory.cpp
toolkit/components/places/nsNavHistory.h
toolkit/components/places/nsPlacesExpiration.js
toolkit/components/places/nsPlacesMacros.h
toolkit/components/places/tests/unit/nsDummyObserver.js
toolkit/components/places/tests/unit/nsDummyObserver.manifest
toolkit/components/places/tests/unit/test_bookmark_catobs.js
toolkit/components/places/tests/unit/test_history_catobs.js
toolkit/components/places/tests/unit/xpcshell.ini
toolkit/components/places/toolkitplaces.manifest
--- a/toolkit/components/places/nsNavBookmarks.cpp
+++ b/toolkit/components/places/nsNavBookmarks.cpp
@@ -158,17 +158,16 @@ NeedsTombstone(const BookmarkData& aBook
 nsNavBookmarks::nsNavBookmarks()
   : mRoot(0)
   , mMenuRoot(0)
   , mTagsRoot(0)
   , mUnfiledRoot(0)
   , mToolbarRoot(0)
   , mMobileRoot(0)
   , mCanNotify(false)
-  , mCacheObservers("bookmark-observers")
   , mBatching(false)
 {
   NS_ASSERTION(!gBookmarksService,
                "Attempting to create two instances of the service!");
   gBookmarksService = this;
 }
 
 
@@ -623,17 +622,17 @@ nsNavBookmarks::InsertBookmark(int64_t a
   if (grandParentId != tagsRootId) {
     rv = history->UpdateFrecency(placeId);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
+  NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mObservers,
                              SKIP_TAGS(grandParentId == mTagsRoot),
                              OnItemAdded(*aNewBookmarkId, aFolder, index,
                                          TYPE_BOOKMARK, aURI, title, dateAdded,
                                          guid, folderGuid, aSource));
 
   // If the bookmark has been added to a tag container, notify all
   // bookmark-folder result nodes which contain a bookmark for the new
   // bookmark's url.
@@ -642,18 +641,17 @@ nsNavBookmarks::InsertBookmark(int64_t a
     nsTArray<BookmarkData> bookmarks;
     rv = GetBookmarksForURI(aURI, bookmarks);
     NS_ENSURE_SUCCESS(rv, rv);
 
     for (uint32_t i = 0; i < bookmarks.Length(); ++i) {
       // Check that bookmarks doesn't include the current tag itemId.
       MOZ_ASSERT(bookmarks[i].id != *aNewBookmarkId);
 
-      NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                                 DontSkip,
+      NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mObservers, DontSkip,
                                  OnItemChanged(bookmarks[i].id,
                                                NS_LITERAL_CSTRING("tags"),
                                                false,
                                                EmptyCString(),
                                                bookmarks[i].lastModified,
                                                TYPE_BOOKMARK,
                                                bookmarks[i].parentId,
                                                bookmarks[i].guid,
@@ -753,17 +751,17 @@ nsNavBookmarks::RemoveItem(int64_t aItem
       NS_ENSURE_SUCCESS(rv, rv);
     }
     // A broken url should not interrupt the removal process.
     (void)NS_NewURI(getter_AddRefs(uri), bookmark.url);
     // We cannot assert since some automated tests are checking this path.
     NS_WARNING_ASSERTION(uri, "Invalid URI in RemoveItem");
   }
 
-  NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
+  NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mObservers,
                              SKIP_TAGS(bookmark.parentId == tagsRootId ||
                                        bookmark.grandParentId == tagsRootId),
                              OnItemRemoved(bookmark.id,
                                            bookmark.parentId,
                                            bookmark.position,
                                            bookmark.type,
                                            uri,
                                            bookmark.guid,
@@ -774,18 +772,17 @@ nsNavBookmarks::RemoveItem(int64_t aItem
       uri) {
     // If the removed bookmark was child of a tag container, notify a tags
     // change to all bookmarks for this URI.
     nsTArray<BookmarkData> bookmarks;
     rv = GetBookmarksForURI(uri, bookmarks);
     NS_ENSURE_SUCCESS(rv, rv);
 
     for (uint32_t i = 0; i < bookmarks.Length(); ++i) {
-      NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                                 DontSkip,
+      NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mObservers, DontSkip,
                                  OnItemChanged(bookmarks[i].id,
                                                NS_LITERAL_CSTRING("tags"),
                                                false,
                                                EmptyCString(),
                                                bookmarks[i].lastModified,
                                                TYPE_BOOKMARK,
                                                bookmarks[i].parentId,
                                                bookmarks[i].guid,
@@ -876,17 +873,17 @@ nsNavBookmarks::CreateContainerWithID(in
                           nullptr, aSource, aNewFolder, guid);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
   int64_t tagsRootId = TagsRootId();
 
-  NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
+  NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mObservers,
                              SKIP_TAGS(aParent == tagsRootId),
                              OnItemAdded(*aNewFolder, aParent, index, FOLDER,
                                          nullptr, title, dateAdded, guid,
                                          folderGuid, aSource));
 
   *aIndex = index;
   return NS_OK;
 }
@@ -932,18 +929,17 @@ nsNavBookmarks::InsertSeparator(int64_t 
   rv = InsertBookmarkInDB(-1, SEPARATOR, aParent, index, EmptyCString(), dateAdded,
                           0, folderGuid, grandParentId, nullptr, aSource,
                           aNewItemId, guid);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                             DontSkip,
+  NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mObservers, DontSkip,
                              OnItemAdded(*aNewItemId, aParent, index, TYPE_SEPARATOR,
                                          nullptr, EmptyCString(), dateAdded, guid,
                                          folderGuid, aSource));
 
   return NS_OK;
 }
 
 
@@ -1206,17 +1202,17 @@ nsNavBookmarks::RemoveFolderChildren(int
         NS_ENSURE_SUCCESS(rv, rv);
       }
       // A broken url should not interrupt the removal process.
       (void)NS_NewURI(getter_AddRefs(uri), child.url);
       // We cannot assert since some automated tests are checking this path.
       NS_WARNING_ASSERTION(uri, "Invalid URI in RemoveFolderChildren");
     }
 
-    NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
+    NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mObservers,
                                ((child.grandParentId == tagsRootId) ? SkipTags : SkipDescendants),
                                OnItemRemoved(child.id,
                                              child.parentId,
                                              child.position,
                                              child.type,
                                              uri,
                                              child.guid,
                                              child.parentGuid,
@@ -1227,18 +1223,17 @@ nsNavBookmarks::RemoveFolderChildren(int
       // If the removed bookmark was a child of a tag container, notify all
       // bookmark-folder result nodes which contain a bookmark for the removed
       // bookmark's url.
       nsTArray<BookmarkData> bookmarks;
       rv = GetBookmarksForURI(uri, bookmarks);
       NS_ENSURE_SUCCESS(rv, rv);
 
       for (uint32_t i = 0; i < bookmarks.Length(); ++i) {
-        NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                                   DontSkip,
+        NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mObservers, DontSkip,
                                    OnItemChanged(bookmarks[i].id,
                                                  NS_LITERAL_CSTRING("tags"),
                                                  false,
                                                  EmptyCString(),
                                                  bookmarks[i].lastModified,
                                                  TYPE_BOOKMARK,
                                                  bookmarks[i].parentId,
                                                  bookmarks[i].guid,
@@ -1413,18 +1408,17 @@ nsNavBookmarks::MoveItem(int64_t aItemId
   }
 
   rv = PreventSyncReparenting(bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                   nsINavBookmarkObserver,
+  NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavBookmarkObserver,
                    OnItemMoved(bookmark.id,
                                bookmark.parentId,
                                bookmark.position,
                                aNewParent,
                                newIndex,
                                bookmark.type,
                                bookmark.guid,
                                bookmark.parentGuid,
@@ -1582,18 +1576,17 @@ nsNavBookmarks::SetItemDateAdded(int64_t
     NS_ENSURE_SUCCESS(rv, rv);
   } else {
     rv = SetItemDateInternal(DATE_ADDED, syncChangeDelta, bookmark.id,
                              bookmark.dateAdded);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Note: mDBSetItemDateAdded also sets lastModified to aDateAdded.
-  NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                   nsINavBookmarkObserver,
+  NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavBookmarkObserver,
                    OnItemChanged(bookmark.id,
                                  NS_LITERAL_CSTRING("dateAdded"),
                                  false,
                                  nsPrintfCString("%" PRId64, bookmark.dateAdded),
                                  bookmark.dateAdded,
                                  bookmark.type,
                                  bookmark.parentId,
                                  bookmark.guid,
@@ -1653,18 +1646,17 @@ nsNavBookmarks::SetItemLastModified(int6
     NS_ENSURE_SUCCESS(rv, rv);
   } else {
     rv = SetItemDateInternal(LAST_MODIFIED, syncChangeDelta, bookmark.id,
                              bookmark.lastModified);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Note: mDBSetItemDateAdded also sets lastModified to aDateAdded.
-  NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                   nsINavBookmarkObserver,
+  NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavBookmarkObserver,
                    OnItemChanged(bookmark.id,
                                  NS_LITERAL_CSTRING("lastModified"),
                                  false,
                                  nsPrintfCString("%" PRId64, bookmark.lastModified),
                                  bookmark.lastModified,
                                  bookmark.type,
                                  bookmark.parentId,
                                  bookmark.guid,
@@ -1905,18 +1897,17 @@ nsNavBookmarks::SetItemTitle(int64_t aIt
 
     rv = transaction.Commit();
     NS_ENSURE_SUCCESS(rv, rv);
   } else {
     rv = SetItemTitleInternal(bookmark, title, syncChangeDelta);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                             SKIP_TAGS(isChangingTagFolder),
+  NOTIFY_BOOKMARKS_OBSERVERS(mCanNotify, mObservers, SKIP_TAGS(isChangingTagFolder),
                              OnItemChanged(bookmark.id,
                                            NS_LITERAL_CSTRING("title"),
                                            false,
                                            title,
                                            bookmark.lastModified,
                                            bookmark.type,
                                            bookmark.parentId,
                                            bookmark.guid,
@@ -2452,18 +2443,17 @@ nsNavBookmarks::SetKeywordForBookmark(in
       rv = stmt->Execute();
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     rv = removeTxn.Commit();
     NS_ENSURE_SUCCESS(rv, rv);
 
     for (uint32_t i = 0; i < bookmarks.Length(); ++i) {
-      NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                       nsINavBookmarkObserver,
+      NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavBookmarkObserver,
                        OnItemChanged(bookmarks[i].id,
                                      NS_LITERAL_CSTRING("keyword"),
                                      false,
                                      EmptyCString(),
                                      bookmarks[i].lastModified,
                                      TYPE_BOOKMARK,
                                      bookmarks[i].parentId,
                                      bookmarks[i].guid,
@@ -2509,18 +2499,17 @@ nsNavBookmarks::SetKeywordForBookmark(in
 
   nsCOMPtr<mozIStorageStatement> stmt;
   if (oldUri) {
     // In both cases, notify about the change.
     nsTArray<BookmarkData> bookmarks;
     rv = GetBookmarksForURI(oldUri, bookmarks);
     NS_ENSURE_SUCCESS(rv, rv);
     for (uint32_t i = 0; i < bookmarks.Length(); ++i) {
-      NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                       nsINavBookmarkObserver,
+      NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavBookmarkObserver,
                        OnItemChanged(bookmarks[i].id,
                                      NS_LITERAL_CSTRING("keyword"),
                                      false,
                                      EmptyCString(),
                                      bookmarks[i].lastModified,
                                      TYPE_BOOKMARK,
                                      bookmarks[i].parentId,
                                      bookmarks[i].guid,
@@ -2580,18 +2569,17 @@ nsNavBookmarks::SetKeywordForBookmark(in
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   rv = updateTxn.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // In both cases, notify about the change.
   for (uint32_t i = 0; i < bookmarks.Length(); ++i) {
-    NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                     nsINavBookmarkObserver,
+    NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavBookmarkObserver,
                      OnItemChanged(bookmarks[i].id,
                                    NS_LITERAL_CSTRING("keyword"),
                                    false,
                                    NS_ConvertUTF16toUTF8(keyword),
                                    bookmarks[i].lastModified,
                                    TYPE_BOOKMARK,
                                    bookmarks[i].parentId,
                                    bookmarks[i].guid,
@@ -2693,20 +2681,16 @@ nsNavBookmarks::GetObservers(uint32_t* _
   *_count = 0;
   *_observers = nullptr;
 
   if (!mCanNotify)
     return NS_OK;
 
   nsCOMArray<nsINavBookmarkObserver> observers;
 
-  // First add the category cache observers.
-  mCacheObservers.GetEntries(observers);
-
-  // Then add the other observers.
   for (uint32_t i = 0; i < mObservers.Length(); ++i) {
     const nsCOMPtr<nsINavBookmarkObserver> &observer = mObservers.ElementAt(i).GetValue();
     // Skip nullified weak observers.
     if (observer)
       observers.AppendElement(observer);
   }
 
   if (observers.Count() == 0)
@@ -2722,18 +2706,17 @@ void
 nsNavBookmarks::NotifyItemVisited(const ItemVisitData& aData)
 {
   nsCOMPtr<nsIURI> uri;
   MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), aData.bookmark.url));
   // Notify the visit only if we have a valid uri, otherwise the observer
   // couldn't gather enough data from the notification.
   // This should be false only if there's a bug in the code preceding us.
   if (uri) {
-    NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                     nsINavBookmarkObserver,
+    NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavBookmarkObserver,
                      OnItemVisited(aData.bookmark.id,
                                    aData.visitId,
                                    aData.time,
                                    aData.transitionType,
                                    uri,
                                    aData.bookmark.parentId,
                                    aData.bookmark.guid,
                                    aData.bookmark.parentGuid));
@@ -2749,18 +2732,17 @@ nsNavBookmarks::NotifyItemChanged(const 
   PRTime lastModified = aData.bookmark.lastModified;
   if (aData.updateLastModified) {
     lastModified = RoundedPRNow();
     MOZ_ALWAYS_SUCCEEDS(SetItemDateInternal(
       LAST_MODIFIED, DetermineSyncChangeDelta(aData.source),
       aData.bookmark.id, lastModified));
   }
 
-  NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                   nsINavBookmarkObserver,
+  NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavBookmarkObserver,
                    OnItemChanged(aData.bookmark.id,
                                  aData.property,
                                  aData.isAnnotation,
                                  aData.newValue,
                                  lastModified,
                                  aData.bookmark.type,
                                  aData.bookmark.parentId,
                                  aData.bookmark.guid,
@@ -2789,30 +2771,30 @@ nsNavBookmarks::Observe(nsISupports *aSu
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// nsINavHistoryObserver
 
 NS_IMETHODIMP
 nsNavBookmarks::OnBeginUpdateBatch()
 {
-  NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
+  NOTIFY_OBSERVERS(mCanNotify, mObservers,
                    nsINavBookmarkObserver, OnBeginUpdateBatch());
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsNavBookmarks::OnEndUpdateBatch()
 {
   if (mBatching) {
     mBatching = false;
   }
 
-  NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
+  NOTIFY_OBSERVERS(mCanNotify, mObservers,
                    nsINavBookmarkObserver, OnEndUpdateBatch());
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsNavBookmarks::OnVisits(nsIVisitData** aVisits, uint32_t aVisitsCount)
 {
--- a/toolkit/components/places/nsNavBookmarks.h
+++ b/toolkit/components/places/nsNavBookmarks.h
@@ -455,16 +455,15 @@ private:
     uint16_t mSource;
     MOZ_INIT_OUTSIDE_CTOR int64_t mParent;
     nsCString mTitle;
     MOZ_INIT_OUTSIDE_CTOR int32_t mIndex;
   };
 
   // Used to enable and disable the observer notifications.
   bool mCanNotify;
-  nsCategoryCache<nsINavBookmarkObserver> mCacheObservers;
 
   // Tracks whether we are in batch mode.
   // Note: this is only tracking bookmarks batches, not history ones.
   bool mBatching;
 };
 
 #endif // nsNavBookmarks_h_
--- a/toolkit/components/places/nsNavHistory.cpp
+++ b/toolkit/components/places/nsNavHistory.cpp
@@ -281,17 +281,16 @@ nsNavHistory::nsNavHistory()
   , mEmbedVisits(EMBED_VISITS_INITIAL_CACHE_LENGTH)
   , mHistoryEnabled(true)
   , mNumVisitsForFrecency(10)
   , mTagsFolder(-1)
   , mDaysOfHistory(-1)
   , mLastCachedStartOfDay(INT64_MAX)
   , mLastCachedEndOfDay(0)
   , mCanNotify(true)
-  , mCacheObservers("history-observers")
 #ifdef XP_WIN
   , mCryptoProviderInitialized(false)
 #endif
 {
   NS_ASSERTION(!gHistoryService,
                "Attempting to create two instances of the service!");
 #ifdef XP_WIN
   BOOL cryptoAcquired = CryptAcquireContext(&mCryptoProvider, 0, 0, PROV_RSA_FULL,
@@ -531,50 +530,47 @@ nsNavHistory::NotifyOnVisits(nsIVisitDat
   for (uint32_t i = 0; i < aVisitsCount; ++i) {
     PRTime time;
     MOZ_ALWAYS_SUCCEEDS(aVisits[i]->GetTime(&time));
     if (time > mLastCachedEndOfDay || time < mLastCachedStartOfDay) {
       mDaysOfHistory = -1;
     }
   }
 
-  NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                   nsINavHistoryObserver,
+  NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavHistoryObserver,
                    OnVisits(aVisits, aVisitsCount));
 }
 
 void
 nsNavHistory::NotifyTitleChange(nsIURI* aURI,
                                 const nsString& aTitle,
                                 const nsACString& aGUID)
 {
   MOZ_ASSERT(!aGUID.IsEmpty());
-  NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                   nsINavHistoryObserver, OnTitleChanged(aURI, aTitle, aGUID));
+  NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavHistoryObserver,
+                   OnTitleChanged(aURI, aTitle, aGUID));
 }
 
 void
 nsNavHistory::NotifyFrecencyChanged(nsIURI* aURI,
                                     int32_t aNewFrecency,
                                     const nsACString& aGUID,
                                     bool aHidden,
                                     PRTime aLastVisitDate)
 {
   MOZ_ASSERT(!aGUID.IsEmpty());
-  NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                   nsINavHistoryObserver,
+  NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavHistoryObserver,
                    OnFrecencyChanged(aURI, aNewFrecency, aGUID, aHidden,
                                      aLastVisitDate));
 }
 
 void
 nsNavHistory::NotifyManyFrecenciesChanged()
 {
-  NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                   nsINavHistoryObserver,
+  NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavHistoryObserver,
                    OnManyFrecenciesChanged());
 }
 
 namespace {
 
 class FrecencyNotification : public Runnable
 {
 public:
@@ -2374,19 +2370,16 @@ nsNavHistory::GetObservers(uint32_t* _co
   // changes to history and is now trying to notify them.
   mDaysOfHistory = -1;
 
   if (!mCanNotify)
     return NS_OK;
 
   nsCOMArray<nsINavHistoryObserver> observers;
 
-  // First add the category cache observers.
-  mCacheObservers.GetEntries(observers);
-
   // Then add the other observers.
   for (uint32_t i = 0; i < mObservers.Length(); ++i) {
     const nsCOMPtr<nsINavHistoryObserver> &observer = mObservers.ElementAt(i).GetValue();
     // Skip nullified weak observers.
     if (observer)
       observers.AppendElement(observer);
   }
 
@@ -2403,18 +2396,17 @@ nsNavHistory::GetObservers(uint32_t* _co
 nsresult
 nsNavHistory::BeginUpdateBatch()
 {
   if (mBatchLevel++ == 0) {
     mBatchDBTransaction = new mozStorageTransaction(mDB->MainConn(), false,
                                                     mozIStorageConnection::TRANSACTION_DEFERRED,
                                                     true);
 
-    NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                     nsINavHistoryObserver, OnBeginUpdateBatch());
+    NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavHistoryObserver, OnBeginUpdateBatch());
   }
   return NS_OK;
 }
 
 // nsNavHistory::EndUpdateBatch
 nsresult
 nsNavHistory::EndUpdateBatch()
 {
@@ -2422,18 +2414,17 @@ nsNavHistory::EndUpdateBatch()
     if (mBatchDBTransaction) {
       DebugOnly<nsresult> rv = mBatchDBTransaction->Commit();
       NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                            "Batch failed to commit transaction");
       delete mBatchDBTransaction;
       mBatchDBTransaction = nullptr;
     }
 
-    NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                     nsINavHistoryObserver, OnEndUpdateBatch());
+    NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavHistoryObserver, OnEndUpdateBatch());
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNavHistory::RunInBatchMode(nsINavHistoryBatchCallback* aCallback,
                              nsISupports* aUserData)
 {
@@ -2551,18 +2542,17 @@ nsNavHistory::CleanupPlacesOnVisitsDelet
       }
       filteredPlaceIds.AppendInt(placeId);
       URIs.AppendElement(uri.forget());
       GUIDs.AppendElement(guid);
     }
     else {
       // Notify that we will delete all visits for this page, but not the page
       // itself, since it's bookmarked or a place: query.
-      NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                       nsINavHistoryObserver,
+      NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavHistoryObserver,
                        OnDeleteVisits(uri, 0, guid, nsINavHistoryObserver::REASON_DELETED, 0));
     }
   }
 
   // if the entry is not bookmarked and is not a place: uri
   // then we can remove it from moz_places.
   // Note that we do NOT delete favicons. Any unreferenced favicons will be
   // deleted next time the browser is shut down.
@@ -2599,18 +2589,17 @@ nsNavHistory::CleanupPlacesOnVisitsDelet
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Invalidate frecencies of touched places, since they need recalculation.
   rv = invalidateFrecencies(aPlaceIdsQueryString);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Finally notify about the removed URIs.
   for (int32_t i = 0; i < URIs.Count(); ++i) {
-    NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                     nsINavHistoryObserver,
+    NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavHistoryObserver,
                      OnDeleteURI(URIs[i], GUIDs[i], nsINavHistoryObserver::REASON_DELETED));
   }
 
   return NS_OK;
 }
 
 
 // nsNavHistory::RemovePagesFromHost
@@ -2965,23 +2954,22 @@ nsNavHistory::NotifyOnPageExpired(nsIURI
                                   uint16_t aReason, uint32_t aTransitionType)
 {
   // Invalidate the cached value for whether there's history or not.
   mDaysOfHistory = -1;
 
   MOZ_ASSERT(!aGUID.IsEmpty());
   if (aWholeEntry) {
     // Notify our observers that the page has been removed.
-    NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                     nsINavHistoryObserver, OnDeleteURI(aURI, aGUID, aReason));
+    NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavHistoryObserver,
+                     OnDeleteURI(aURI, aGUID, aReason));
   }
   else {
     // Notify our observers that some visits for the page have been removed.
-    NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                     nsINavHistoryObserver,
+    NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavHistoryObserver,
                      OnDeleteVisits(aURI, aVisitTime, aGUID, aReason,
                                     aTransitionType));
   }
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -4166,18 +4154,17 @@ nsNavHistory::URIToResultNode(nsIURI* aU
 
 void
 nsNavHistory::SendPageChangedNotification(nsIURI* aURI,
                                           uint32_t aChangedAttribute,
                                           const nsAString& aNewValue,
                                           const nsACString& aGUID)
 {
   MOZ_ASSERT(!aGUID.IsEmpty());
-  NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
-                   nsINavHistoryObserver,
+  NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavHistoryObserver,
                    OnPageChanged(aURI, aChangedAttribute, aNewValue, aGUID));
 }
 
 // nsNavHistory::TitleForDomain
 //
 //    This computes the title for a given domain. Normally, this is just the
 //    domain name, but we specially handle empty cases to give you a nice
 //    localized string.
--- a/toolkit/components/places/nsNavHistory.h
+++ b/toolkit/components/places/nsNavHistory.h
@@ -651,17 +651,16 @@ protected:
   int64_t mTagsFolder;
 
   int32_t mDaysOfHistory;
   int64_t mLastCachedStartOfDay;
   int64_t mLastCachedEndOfDay;
 
   // Used to enable and disable the observer notifications
   bool mCanNotify;
-  nsCategoryCache<nsINavHistoryObserver> mCacheObservers;
 
   // Used to cache the call to CryptAcquireContext, which is expensive
   // when called thousands of times
 #ifdef XP_WIN
   HCRYPTPROV mCryptoProvider;
   bool mCryptoProviderInitialized;
 #endif
 };
--- a/toolkit/components/places/nsPlacesExpiration.js
+++ b/toolkit/components/places/nsPlacesExpiration.js
@@ -498,16 +498,22 @@ nsPlacesExpiration.prototype = {
     } else if (aTopic == TOPIC_IDLE_END) {
       // Restart the expiration timer.
       if (!this._timer)
         this._newTimer();
     } else if (aTopic == TOPIC_IDLE_DAILY) {
       this._expireWithActionAndLimit(ACTION.IDLE_DAILY, LIMIT.LARGE);
     } else if (aTopic == TOPIC_TESTING_MODE) {
       this._testingMode = true;
+    } else if (aTopic == PlacesUtils.TOPIC_INIT_COMPLETE) {
+      // Ideally we'd add this observer only when notifications start being
+      // triggered. However, that's difficult to work out, so we do it on
+      // TOPIC_INIT_COMPLETE which means we have to take the hit of initializing
+      // this service slightly earlier.
+      PlacesUtils.history.addObserver(this, true);
     }
   },
 
   // nsINavHistoryObserver
 
   _inBatchMode: false,
   onBeginUpdateBatch: function PEX_onBeginUpdateBatch() {
     this._inBatchMode = true;
--- a/toolkit/components/places/nsPlacesMacros.h
+++ b/toolkit/components/places/nsPlacesMacros.h
@@ -7,37 +7,26 @@
 #include "nsIScriptError.h"
 
 #ifndef __FUNCTION__
 #define __FUNCTION__ __func__
 #endif
 
 // Call a method on each observer in a category cache, then call the same
 // method on the observer array.
-#define NOTIFY_OBSERVERS(canFire, cache, array, type, method)                  \
+#define NOTIFY_OBSERVERS(canFire, array, type, method)                         \
   PR_BEGIN_MACRO                                                               \
   if (canFire) {                                                               \
-    nsCOMArray<type> entries;                                                  \
-    cache.GetEntries(entries);                                                 \
-    for (int32_t idx = 0; idx < entries.Count(); ++idx)                        \
-        entries[idx]->method;                                                  \
     ENUMERATE_WEAKARRAY(array, type, method)                                   \
   }                                                                            \
   PR_END_MACRO;
 
-#define NOTIFY_BOOKMARKS_OBSERVERS(canFire, cache, array, skipIf, method)      \
+#define NOTIFY_BOOKMARKS_OBSERVERS(canFire, array, skipIf, method)             \
   PR_BEGIN_MACRO                                                               \
   if (canFire) {                                                               \
-    nsCOMArray<nsINavBookmarkObserver> entries;                                \
-    cache.GetEntries(entries);                                                 \
-    for (int32_t idx = 0; idx < entries.Count(); ++idx) {                      \
-      if (skipIf(entries[idx]))                                                \
-        continue;                                                              \
-      entries[idx]->method;                                                    \
-    }                                                                          \
     for (uint32_t idx = 0; idx < array.Length(); ++idx) {                      \
       const nsCOMPtr<nsINavBookmarkObserver> &e = array.ElementAt(idx).GetValue(); \
       if (e) {                                                                 \
         if (skipIf(e))                                                         \
             continue;                                                          \
         e->method;                                                             \
       }                                                                        \
     }                                                                          \
deleted file mode 100644
--- a/toolkit/components/places/tests/unit/nsDummyObserver.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/* 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/. */
-
-ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-ChromeUtils.import("resource://gre/modules/Services.jsm");
-
-// Dummy boomark/history observer
-function DummyObserver() {
-  Services.obs.notifyObservers(null, "dummy-observer-created");
-}
-
-DummyObserver.prototype = {
-  // history observer
-  onBeginUpdateBatch() {},
-  onEndUpdateBatch() {},
-  onVisits(aVisits) {
-    Services.obs.notifyObservers(null, "dummy-observer-visited");
-  },
-  onTitleChanged() {},
-  onDeleteURI() {},
-  onClearHistory() {},
-  onPageChanged() {},
-  onDeleteVisits() {},
-
-  // bookmark observer
-  // onBeginUpdateBatch: function() {},
-  // onEndUpdateBatch: function() {},
-  onItemAdded(aItemId, aParentId, aIndex, aItemType, aURI) {
-    Services.obs.notifyObservers(null, "dummy-observer-item-added");
-  },
-  onItemChanged() {},
-  onItemRemoved() {},
-  onItemVisited() {},
-  onItemMoved() {},
-
-  classID: Components.ID("62e221d3-68c3-4e1a-8943-a27beb5005fe"),
-
-  QueryInterface: XPCOMUtils.generateQI([
-    Ci.nsINavBookmarkObserver,
-    Ci.nsINavHistoryObserver,
-  ])
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DummyObserver]);
deleted file mode 100644
--- a/toolkit/components/places/tests/unit/nsDummyObserver.manifest
+++ /dev/null
@@ -1,4 +0,0 @@
-component 62e221d3-68c3-4e1a-8943-a27beb5005fe nsDummyObserver.js
-contract @mozilla.org/places/test/dummy-observer;1 62e221d3-68c3-4e1a-8943-a27beb5005fe
-category bookmark-observers nsDummyObserver @mozilla.org/places/test/dummy-observer;1
-category history-observers nsDummyObserver @mozilla.org/places/test/dummy-observer;1
deleted file mode 100644
--- a/toolkit/components/places/tests/unit/test_bookmark_catobs.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-add_task(async function test_observers() {
-  do_load_manifest("nsDummyObserver.manifest");
-
-  let dummyCreated = false;
-  let dummyReceivedOnItemAdded = false;
-
-  Services.obs.addObserver(function created() {
-    Services.obs.removeObserver(created, "dummy-observer-created");
-    dummyCreated = true;
-  }, "dummy-observer-created");
-  Services.obs.addObserver(function added() {
-    Services.obs.removeObserver(added, "dummy-observer-item-added");
-    dummyReceivedOnItemAdded = true;
-  }, "dummy-observer-item-added");
-
-  // This causes various Async API helpers to be initialised before the main
-  // part of the test runs - the helpers add their own listeners, which we don't
-  // want to count within the test (e.g. gKeywordsCachePromise & GuidHelper).
-  await PlacesUtils.promiseItemId(PlacesUtils.bookmarks.unfiledGuid);
-
-  let initialObservers = PlacesUtils.bookmarks.getObservers();
-
-  // Add a common observer, it should be invoked after the category observer.
-  let notificationsPromised = new Promise((resolve, reject) => {
-    PlacesUtils.bookmarks.addObserver( {
-      __proto__: NavBookmarkObserver.prototype,
-      onItemAdded() {
-        let observers = PlacesUtils.bookmarks.getObservers();
-        Assert.equal(observers.length, initialObservers.length + 1);
-
-        // Check the common observer is the last one.
-        for (let i = 0; i < initialObservers.length; ++i) {
-          Assert.equal(initialObservers[i], observers[i]);
-        }
-
-        PlacesUtils.bookmarks.removeObserver(this);
-        observers = PlacesUtils.bookmarks.getObservers();
-        Assert.equal(observers.length, initialObservers.length);
-
-        // Check the category observer has been invoked before this one.
-        Assert.ok(dummyCreated);
-        Assert.ok(dummyReceivedOnItemAdded);
-        resolve();
-      }
-    });
-  });
-
-  // Add a bookmark
-  await PlacesUtils.bookmarks.insert({
-    parentGuid: PlacesUtils.bookmarks.unfiledGuid,
-    title: "bookmark",
-    url: "http://typed.mozilla.org",
-  });
-
-  await notificationsPromised;
-});
deleted file mode 100644
--- a/toolkit/components/places/tests/unit/test_history_catobs.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-add_task(async function() {
-  do_load_manifest("nsDummyObserver.manifest");
-
-  let promises = [];
-  let resolved = 0;
-  promises.push(TestUtils.topicObserved("dummy-observer-created", () => ++resolved));
-  promises.push(TestUtils.topicObserved("dummy-observer-visited", () => ++resolved));
-
-  let initialObservers = PlacesUtils.history.getObservers();
-
-  // Add a common observer, it should be invoked after the category observer.
-  promises.push(new Promise(resolve => {
-    let observer = new NavHistoryObserver();
-    observer.onVisits = visits => {
-      Assert.equal(visits.length, 1, "Got the right number of visits");
-      let uri = visits[0].uri;
-      info("Got visit for " + uri.spec);
-      let observers = PlacesUtils.history.getObservers();
-      let observersCount = observers.length;
-      Assert.ok(observersCount > initialObservers.length);
-
-      // Check the common observer is the last one.
-      for (let i = 0; i < initialObservers.length; ++i) {
-        Assert.equal(initialObservers[i], observers[i]);
-      }
-
-      PlacesUtils.history.removeObserver(observer);
-      observers = PlacesUtils.history.getObservers();
-      Assert.ok(observers.length < observersCount);
-
-      // Check the category observer has been invoked before this one.
-      Assert.equal(resolved, 2);
-      resolve();
-    };
-    PlacesUtils.history.addObserver(observer);
-  }));
-
-  info("Add a visit");
-  await PlacesTestUtils.addVisits(uri("http://typed.mozilla.org"));
-  await Promise.all(promises);
-});
--- a/toolkit/components/places/tests/unit/xpcshell.ini
+++ b/toolkit/components/places/tests/unit/xpcshell.ini
@@ -9,18 +9,16 @@ support-files =
   bookmarks_html_singleframe.html
   corruptDB.sqlite
   livemark.xml
   mobile_bookmarks_folder_import.json
   mobile_bookmarks_folder_merge.json
   mobile_bookmarks_multiple_folders.json
   mobile_bookmarks_root_import.json
   mobile_bookmarks_root_merge.json
-  nsDummyObserver.js
-  nsDummyObserver.manifest
   places.sparse.sqlite
   sync_utils_bookmarks.html
   sync_utils_bookmarks.json
 
 [test_000_frecency.js]
 [test_317472.js]
 [test_331487.js]
 [test_384370.js]
@@ -55,17 +53,16 @@ skip-if = os == "linux"
 [test_1105866.js]
 [test_adaptive.js]
 [test_adaptive_bug527311.js]
 [test_annotations.js]
 [test_asyncExecuteLegacyQueries.js]
 [test_async_in_batchmode.js]
 [test_async_transactions.js]
 skip-if = (os == "win" && os_version == "5.1") # Bug 1158887
-[test_bookmark_catobs.js]
 [test_bookmarks_json.js]
 skip-if = (os == 'win' && ccov) # Bug 1423667
 [test_bookmarks_json_corrupt.js]
 [test_bookmarks_html.js]
 skip-if = (os == 'win' && ccov) # Bug 1423667
 [test_bookmarks_html_corrupt.js]
 [test_bookmarks_html_escape_entities.js]
 [test_bookmarks_html_import_tags.js]
@@ -79,17 +76,16 @@ skip-if = (os == 'win' && ccov) # Bug 14
 [test_database_replaceOnStartup.js]
 [test_download_history.js]
 [test_frecency.js]
 [test_frecency_decay.js]
 [test_frecency_zero_updated.js]
 [test_getChildIndex.js]
 [test_hash.js]
 [test_history.js]
-[test_history_catobs.js]
 [test_history_clear.js]
 [test_history_notifications.js]
 [test_history_observer.js]
 [test_history_sidebar.js]
 [test_hosts_triggers.js]
 [test_import_mobile_bookmarks.js]
 [test_isPageInDB.js]
 [test_isURIVisited.js]
--- a/toolkit/components/places/toolkitplaces.manifest
+++ b/toolkit/components/places/toolkitplaces.manifest
@@ -6,17 +6,17 @@ contract @mozilla.org/browser/livemark-s
 component {bbc23860-2553-479d-8b78-94d9038334f7} nsTaggingService.js
 contract @mozilla.org/browser/tagging-service;1 {bbc23860-2553-479d-8b78-94d9038334f7}
 component {1dcc23b0-d4cb-11dc-9ad6-479d56d89593} nsTaggingService.js
 contract @mozilla.org/autocomplete/search;1?name=places-tag-autocomplete {1dcc23b0-d4cb-11dc-9ad6-479d56d89593}
 
 # nsPlacesExpiration.js
 component {705a423f-2f69-42f3-b9fe-1517e0dee56f} nsPlacesExpiration.js
 contract @mozilla.org/places/expiration;1 {705a423f-2f69-42f3-b9fe-1517e0dee56f}
-category history-observers nsPlacesExpiration @mozilla.org/places/expiration;1
+category places-init-complete nsPlacesExpiration @mozilla.org/places/expiration;1
 
 # PlacesCategoriesStarter.js
 component {803938d5-e26d-4453-bf46-ad4b26e41114} PlacesCategoriesStarter.js
 contract @mozilla.org/places/categoriesStarter;1 {803938d5-e26d-4453-bf46-ad4b26e41114}
 category idle-daily PlacesCategoriesStarter @mozilla.org/places/categoriesStarter;1
 category places-init-complete PlacesCategoriesStarter @mozilla.org/places/categoriesStarter;1
 
 # ColorAnalyzer.js