diff --git a/toolkit/components/places/src/AsyncFaviconHelpers.cpp b/toolkit/components/places/src/AsyncFaviconHelpers.cpp index 84c86f58032..44b00ee14e0 100644 --- a/toolkit/components/places/src/AsyncFaviconHelpers.cpp +++ b/toolkit/components/places/src/AsyncFaviconHelpers.cpp @@ -68,6 +68,7 @@ #define MAX_FAVICON_EXPIRATION ((PRTime)7 * 24 * 60 * 60 * PR_USEC_PER_SEC) using namespace mozilla::places; +using namespace mozilla::storage; namespace { @@ -80,7 +81,7 @@ namespace { * Page that should be fetched. */ nsresult -FetchPageInfo(nsCOMPtr& aDBConn, +FetchPageInfo(StatementCache& aStmtCache, PageData& _page) { NS_PRECONDITION(_page.spec.Length(), "Must have a non-empty spec!"); @@ -117,13 +118,14 @@ FetchPageInfo(nsCOMPtr& aDBConn, nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY ); - nsCOMPtr stmt; - aDBConn->CreateStatement(NS_LITERAL_CSTRING( - "SELECT h.id, h.favicon_id, " - "(") + redirectedBookmarksFragment + NS_LITERAL_CSTRING(") " - "FROM moz_places h WHERE h.url = :page_url" - ), getter_AddRefs(stmt)); + nsCOMPtr stmt = + aStmtCache.GetCachedStatement(NS_LITERAL_CSTRING( + "SELECT h.id, h.favicon_id, " + "(") + redirectedBookmarksFragment + NS_LITERAL_CSTRING(") " + "FROM moz_places h WHERE h.url = :page_url" + )); NS_ENSURE_STATE(stmt); + mozStorageStatementScoper scoper(stmt); nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), _page.spec); @@ -170,7 +172,7 @@ FetchPageInfo(nsCOMPtr& aDBConn, // is different from the requested one, use it. if (!_page.bookmarkedSpec.Equals(_page.spec)) { _page.spec = _page.bookmarkedSpec; - rv = FetchPageInfo(aDBConn, _page); + rv = FetchPageInfo(aStmtCache, _page); NS_ENSURE_SUCCESS(rv, rv); } } @@ -188,19 +190,20 @@ FetchPageInfo(nsCOMPtr& aDBConn, * Icon that should be fetched. */ nsresult -FetchIconInfo(nsCOMPtr& aDBConn, +FetchIconInfo(StatementCache& aStmtCache, IconData& _icon) { NS_PRECONDITION(_icon.spec.Length(), "Must have a non-empty spec!"); NS_PRECONDITION(!NS_IsMainThread(), "This should not be called on the main thread"); - nsCOMPtr stmt; - aDBConn->CreateStatement(NS_LITERAL_CSTRING( - "SELECT id, expiration, data, mime_type " - "FROM moz_favicons WHERE url = :icon_url" - ), getter_AddRefs(stmt)); + nsCOMPtr stmt = + aStmtCache.GetCachedStatement(NS_LITERAL_CSTRING( + "SELECT id, expiration, data, mime_type " + "FROM moz_favicons WHERE url = :icon_url" + )); NS_ENSURE_STATE(stmt); + mozStorageStatementScoper scoper(stmt); nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), _icon.spec); @@ -459,7 +462,7 @@ AsyncFetchAndSetIconForPage::Run() "This should not be called on the main thread"); // Try to fetch the icon from the database. - nsresult rv = FetchIconInfo(mDBConn, mIcon); + nsresult rv = FetchIconInfo(mFaviconSvc->mSyncStatements, mIcon); NS_ENSURE_SUCCESS(rv, rv); bool isInvalidIcon = mIcon.data.IsEmpty() || @@ -700,7 +703,7 @@ AsyncAssociateIconToPage::Run() NS_PRECONDITION(!NS_IsMainThread(), "This should not be called on the main thread"); - nsresult rv = FetchPageInfo(mDBConn, mPage); + nsresult rv = FetchPageInfo(mFaviconSvc->mSyncStatements, mPage); if (rv == NS_ERROR_NOT_AVAILABLE){ // We have never seen this page. If we can add the page to history, // we will try to do it later, otherwise just bail out. @@ -717,14 +720,15 @@ AsyncAssociateIconToPage::Run() // If there is no entry for this icon, or the entry is obsolete, replace it. if (mIcon.id == 0 || (mIcon.status & ICON_STATUS_CHANGED)) { - nsCOMPtr stmt; - mDBConn->CreateStatement(NS_LITERAL_CSTRING( - "INSERT OR REPLACE INTO moz_favicons " - "(id, url, data, mime_type, expiration) " - "VALUES ((SELECT id FROM moz_favicons WHERE url = :icon_url), " - ":icon_url, :data, :mime_type, :expiration) " - ), getter_AddRefs(stmt)); + nsCOMPtr stmt = + mFaviconSvc->mSyncStatements.GetCachedStatement(NS_LITERAL_CSTRING( + "INSERT OR REPLACE INTO moz_favicons " + "(id, url, data, mime_type, expiration) " + "VALUES ((SELECT id FROM moz_favicons WHERE url = :icon_url), " + ":icon_url, :data, :mime_type, :expiration) " + )); NS_ENSURE_STATE(stmt); + mozStorageStatementScoper scoper(stmt); rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), mIcon.spec); NS_ENSURE_SUCCESS(rv, rv); rv = stmt->BindBlobByName(NS_LITERAL_CSTRING("data"), @@ -740,7 +744,7 @@ AsyncAssociateIconToPage::Run() // Get the new icon id. Do this regardless mIcon.id, since other code // could have added a entry before us. Indeed we interrupted the thread // after the previous call to FetchIconInfo. - rv = FetchIconInfo(mDBConn, mIcon); + rv = FetchIconInfo(mFaviconSvc->mSyncStatements, mIcon); NS_ENSURE_SUCCESS(rv, rv); mIcon.status |= ICON_STATUS_SAVED; @@ -748,12 +752,13 @@ AsyncAssociateIconToPage::Run() // If the page does not have an id, try to insert a new one. if (mPage.id == 0) { - nsCOMPtr stmt; - mDBConn->CreateStatement(NS_LITERAL_CSTRING( - "INSERT INTO moz_places (url, rev_host, favicon_id) " - "VALUES (:page_url, :rev_host, :favicon_id) " - ), getter_AddRefs(stmt)); + nsCOMPtr stmt = + mFaviconSvc->mSyncStatements.GetCachedStatement(NS_LITERAL_CSTRING( + "INSERT INTO moz_places (url, rev_host, favicon_id) " + "VALUES (:page_url, :rev_host, :favicon_id) " + )); NS_ENSURE_STATE(stmt); + mozStorageStatementScoper scoper(stmt); rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mPage.spec); NS_ENSURE_SUCCESS(rv, rv); // The rev_host can be null. @@ -770,18 +775,19 @@ AsyncAssociateIconToPage::Run() NS_ENSURE_SUCCESS(rv, rv); // Get the new page id. - rv = FetchPageInfo(mDBConn, mPage); + rv = FetchPageInfo(mFaviconSvc->mSyncStatements, mPage); NS_ENSURE_SUCCESS(rv, rv); mIcon.status |= ICON_STATUS_ASSOCIATED; } // Otherwise just associate the icon to the page, if needed. else if (mPage.iconId != mIcon.id) { - nsCOMPtr stmt; - mDBConn->CreateStatement(NS_LITERAL_CSTRING( - "UPDATE moz_places SET favicon_id = :icon_id WHERE id = :page_id" - ), getter_AddRefs(stmt)); + nsCOMPtr stmt = + mFaviconSvc->mSyncStatements.GetCachedStatement(NS_LITERAL_CSTRING( + "UPDATE moz_places SET favicon_id = :icon_id WHERE id = :page_id" + )); NS_ENSURE_STATE(stmt); + mozStorageStatementScoper scoper(stmt); rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("icon_id"), mIcon.id); NS_ENSURE_SUCCESS(rv, rv); rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), mPage.id); diff --git a/toolkit/components/places/src/Helpers.h b/toolkit/components/places/src/Helpers.h index c00f9a44264..01fb748e447 100644 --- a/toolkit/components/places/src/Helpers.h +++ b/toolkit/components/places/src/Helpers.h @@ -45,6 +45,7 @@ #include "mozilla/storage.h" #include "nsIURI.h" +#include "nsThreadUtils.h" namespace mozilla { namespace places { @@ -198,6 +199,37 @@ void GetReversedHostname(const nsString& aForward, nsString& aRevHost); */ void ReverseString(const nsString& aInput, nsString& aReversed); +/** + * Used to finalize a statementCache on a specified thread. + */ +template +class FinalizeStatementCacheProxy : public nsRunnable +{ +public: + /** + * Constructor. + * + * @param aStatementCache + * The statementCache that should be finalized. + */ + FinalizeStatementCacheProxy( + mozilla::storage::StatementCache& aStatementCache + ) + : mStatementCache(aStatementCache) + { + } + + NS_IMETHOD + Run() + { + mStatementCache.FinalizeStatements(); + return NS_OK; + } + +protected: + mozilla::storage::StatementCache& mStatementCache; +}; + } // namespace places } // namespace mozilla diff --git a/toolkit/components/places/src/nsFaviconService.cpp b/toolkit/components/places/src/nsFaviconService.cpp index 96b643567f3..130f7893994 100644 --- a/toolkit/components/places/src/nsFaviconService.cpp +++ b/toolkit/components/places/src/nsFaviconService.cpp @@ -112,7 +112,8 @@ NS_IMPL_ISUPPORTS1( ) nsFaviconService::nsFaviconService() -: mFaviconsExpirationRunning(false) +: mSyncStatements(mDBConn) +, mFaviconsExpirationRunning(false) , mOptimizedIconDimension(OPTIMIZED_FAVICON_DIMENSION) , mFailedFaviconSerial(0) , mShuttingDown(false) @@ -939,6 +940,14 @@ nsFaviconService::FinalizeStatements() { NS_ENSURE_SUCCESS(rv, rv); } + // Finalize the statementCache on the correct thread. + nsRefPtr> event = + new FinalizeStatementCacheProxy(mSyncStatements); + nsCOMPtr target = do_GetInterface(mDBConn); + NS_ENSURE_TRUE(target, NS_ERROR_OUT_OF_MEMORY); + nsresult rv = target->Dispatch(event, NS_DISPATCH_NORMAL); + NS_ENSURE_SUCCESS(rv, rv); + return NS_OK; } diff --git a/toolkit/components/places/src/nsFaviconService.h b/toolkit/components/places/src/nsFaviconService.h index 11d7f90a04b..cf527efc9a4 100644 --- a/toolkit/components/places/src/nsFaviconService.h +++ b/toolkit/components/places/src/nsFaviconService.h @@ -48,6 +48,7 @@ #include "nsToolkitCompsCID.h" #include "mozilla/storage.h" +#include "mozilla/storage/StatementCache.h" // Favicons bigger than this size should not be saved to the db to avoid // bloating it with large image blobs. @@ -142,6 +143,13 @@ public: void SendFaviconNotifications(nsIURI* aPage, nsIURI* aFaviconURI); + /** + * This cache should be used only for background thread statements. + * + * @pre must be running on the background thread of mDBConn. + */ + mozilla::storage::StatementCache mSyncStatements; + NS_DECL_ISUPPORTS NS_DECL_NSIFAVICONSERVICE