diff --git a/toolkit/components/places/src/History.cpp b/toolkit/components/places/src/History.cpp index 7bec2f02282..9268e7318fa 100644 --- a/toolkit/components/places/src/History.cpp +++ b/toolkit/components/places/src/History.cpp @@ -170,7 +170,7 @@ public: // If we are a content process, always remote the request to the // parent process. if (XRE_GetProcessType() == GeckoProcessType_Content) { - mozilla::dom::ContentChild * cpc = + mozilla::dom::ContentChild* cpc = mozilla::dom::ContentChild::GetSingleton(); NS_ASSERTION(cpc, "Content Protocol is NULL!"); (void)cpc->SendStartVisitedQuery(aURI); @@ -178,9 +178,8 @@ public: } #endif - nsNavHistory* navHist = nsNavHistory::GetHistoryService(); - NS_ENSURE_TRUE(navHist, NS_ERROR_FAILURE); - mozIStorageStatement* stmt = navHist->GetStatementById(DB_IS_PAGE_VISITED); + mozIStorageAsyncStatement* stmt = + History::GetService()->GetIsVisitedStatement(); NS_ENSURE_STATE(stmt); // Bind by index for performance. @@ -260,7 +259,7 @@ class FailSafeFinishTask { public: FailSafeFinishTask() - : mAppended(false) + : mAppended(false) { } @@ -952,6 +951,37 @@ History::NotifyVisited(nsIURI* aURI) mObservers.RemoveEntry(aURI); } +mozIStorageAsyncStatement* +History::GetIsVisitedStatement() +{ + if (mIsVisitedStatement) { + return mIsVisitedStatement; + } + + // If we don't yet have a database connection, go ahead and clone it now. + if (!mReadOnlyDBConn) { + nsNavHistory* history = nsNavHistory::GetHistoryService(); + NS_ENSURE_TRUE(history, nsnull); + + nsCOMPtr dbConn; + (void)history->GetDBConnection(getter_AddRefs(dbConn)); + NS_ENSURE_TRUE(dbConn, nsnull); + + (void)dbConn->Clone(PR_TRUE, getter_AddRefs(mReadOnlyDBConn)); + NS_ENSURE_TRUE(mReadOnlyDBConn, nsnull); + } + + // Now we can create our cached statement. + nsresult rv = mReadOnlyDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING( + "SELECT h.id " + "FROM moz_places h " + "WHERE url = ?1 " + "AND EXISTS(SELECT id FROM moz_historyvisits WHERE place_id = h.id LIMIT 1) " + ), getter_AddRefs(mIsVisitedStatement)); + NS_ENSURE_SUCCESS(rv, nsnull); + return mIsVisitedStatement; +} + /* static */ History* History::GetService() @@ -1006,6 +1036,10 @@ History::Shutdown() nsCOMPtr deadTaskWalking = dont_AddRef(static_cast(mPendingVisits.PopFront())); } + + if (mReadOnlyDBConn) { + (void)mReadOnlyDBConn->AsyncClose(nsnull); + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/toolkit/components/places/src/History.h b/toolkit/components/places/src/History.h index 16b44b4f9d8..156ae4c1fdf 100644 --- a/toolkit/components/places/src/History.h +++ b/toolkit/components/places/src/History.h @@ -48,6 +48,7 @@ #include "nsTArray.h" #include "nsDeque.h" #include "nsIObserver.h" +#include "mozIStorageConnection.h" namespace mozilla { namespace places { @@ -71,7 +72,7 @@ public: * @param aURI * The URI to notify about. */ - void NotifyVisited(nsIURI *aURI); + void NotifyVisited(nsIURI* aURI); /** * Append a task to the queue for SQL queries that need to happen @@ -93,19 +94,38 @@ public: */ void CurrentTaskFinished(); + /** + * Obtains the statement to use to check if a URI is visited or not. + */ + mozIStorageAsyncStatement* GetIsVisitedStatement(); + /** * Obtains a pointer to this service. */ - static History *GetService(); + static History* GetService(); /** * Obtains a pointer that has had AddRef called on it. Used by the service * manager only. */ - static History *GetSingleton(); + static History* GetSingleton(); private: - ~History(); + virtual ~History(); + + /** + * A read-only database connection used for checking if a URI is visited. + * + * @note this should only be accessed by GetIsVisistedStatement and Shutdown. + */ + nsCOMPtr mReadOnlyDBConn; + + /** + * An asynchronous statement to query if a URI is visited or not. + * + * @note this should only be accessed by GetIsVisistedStatement. + */ + nsCOMPtr mIsVisitedStatement; /** * Since visits rapidly fire at once, it's very likely to have race @@ -132,21 +152,21 @@ private: */ void Shutdown(); - static History *gService; + static History* gService; // Ensures new tasks aren't started on destruction. bool mShuttingDown; - typedef nsTArray ObserverArray; + typedef nsTArray ObserverArray; class KeyClass : public nsURIHashKey { public: - KeyClass(const nsIURI *aURI) + KeyClass(const nsIURI* aURI) : nsURIHashKey(aURI) { } - KeyClass(const KeyClass &aOther) + KeyClass(const KeyClass& aOther) : nsURIHashKey(aOther) { NS_NOTREACHED("Do not call me!");