michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=8 sts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_places_History_h_ michael@0: #define mozilla_places_History_h_ michael@0: michael@0: #include "mozilla/IHistory.h" michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "mozilla/Mutex.h" michael@0: #include "mozIAsyncHistory.h" michael@0: #include "nsIDownloadHistory.h" michael@0: #include "Database.h" michael@0: michael@0: #include "mozilla/dom/Link.h" michael@0: #include "nsTHashtable.h" michael@0: #include "nsString.h" michael@0: #include "nsURIHashKey.h" michael@0: #include "nsTObserverArray.h" michael@0: #include "nsDeque.h" michael@0: #include "nsIMemoryReporter.h" michael@0: #include "nsIObserver.h" michael@0: #include "mozIStorageConnection.h" michael@0: michael@0: namespace mozilla { michael@0: namespace places { michael@0: michael@0: struct VisitData; michael@0: michael@0: #define NS_HISTORYSERVICE_CID \ michael@0: {0x0937a705, 0x91a6, 0x417a, {0x82, 0x92, 0xb2, 0x2e, 0xb1, 0x0d, 0xa8, 0x6c}} michael@0: michael@0: // Max size of History::mRecentlyVisitedURIs michael@0: #define RECENTLY_VISITED_URI_SIZE 8 michael@0: michael@0: class History : public IHistory michael@0: , public nsIDownloadHistory michael@0: , public mozIAsyncHistory michael@0: , public nsIObserver michael@0: , public nsIMemoryReporter michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_IHISTORY michael@0: NS_DECL_NSIDOWNLOADHISTORY michael@0: NS_DECL_MOZIASYNCHISTORY michael@0: NS_DECL_NSIOBSERVER michael@0: NS_DECL_NSIMEMORYREPORTER michael@0: michael@0: History(); michael@0: michael@0: /** michael@0: * Obtains the statement to use to check if a URI is visited or not. michael@0: */ michael@0: mozIStorageAsyncStatement* GetIsVisitedStatement(); michael@0: michael@0: /** michael@0: * Adds an entry in moz_places with the data in aVisitData. michael@0: * michael@0: * @param aVisitData michael@0: * The visit data to use to populate a new row in moz_places. michael@0: */ michael@0: nsresult InsertPlace(const VisitData& aVisitData); michael@0: michael@0: /** michael@0: * Updates an entry in moz_places with the data in aVisitData. michael@0: * michael@0: * @param aVisitData michael@0: * The visit data to use to update the existing row in moz_places. michael@0: */ michael@0: nsresult UpdatePlace(const VisitData& aVisitData); michael@0: michael@0: /** michael@0: * Loads information about the page into _place from moz_places. michael@0: * michael@0: * @param _place michael@0: * The VisitData for the place we need to know information about. michael@0: * @param [out] _exists michael@0: * Whether or the page was recorded in moz_places, false otherwise. michael@0: */ michael@0: nsresult FetchPageInfo(VisitData& _place, bool* _exists); michael@0: michael@0: /** michael@0: * Get the number of bytes of memory this History object is using, michael@0: * including sizeof(*this)) michael@0: */ michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf); michael@0: michael@0: /** michael@0: * Obtains a pointer to this service. michael@0: */ michael@0: static History* GetService(); michael@0: michael@0: /** michael@0: * Obtains a pointer that has had AddRef called on it. Used by the service michael@0: * manager only. michael@0: */ michael@0: static History* GetSingleton(); michael@0: michael@0: template michael@0: already_AddRefed michael@0: GetStatement(const char (&aQuery)[N]) michael@0: { michael@0: mozIStorageConnection* dbConn = GetDBConn(); michael@0: NS_ENSURE_TRUE(dbConn, nullptr); michael@0: return mDB->GetStatement(aQuery); michael@0: } michael@0: michael@0: already_AddRefed michael@0: GetStatement(const nsACString& aQuery) michael@0: { michael@0: mozIStorageConnection* dbConn = GetDBConn(); michael@0: NS_ENSURE_TRUE(dbConn, nullptr); michael@0: return mDB->GetStatement(aQuery); michael@0: } michael@0: michael@0: bool IsShuttingDown() const { michael@0: return mShuttingDown; michael@0: } michael@0: Mutex& GetShutdownMutex() { michael@0: return mShutdownMutex; michael@0: } michael@0: michael@0: /** michael@0: * Helper function to append a new URI to mRecentlyVisitedURIs. See michael@0: * mRecentlyVisitedURIs. michael@0: */ michael@0: void AppendToRecentlyVisitedURIs(nsIURI* aURI); michael@0: michael@0: private: michael@0: virtual ~History(); michael@0: michael@0: void InitMemoryReporter(); michael@0: michael@0: /** michael@0: * Obtains a read-write database connection. michael@0: */ michael@0: mozIStorageConnection* GetDBConn(); michael@0: michael@0: /** michael@0: * The database handle. This is initialized lazily by the first call to michael@0: * GetDBConn(), so never use it directly, or, if you really need, always michael@0: * invoke GetDBConn() before. michael@0: */ michael@0: nsRefPtr mDB; michael@0: michael@0: /** michael@0: * A read-only database connection used for checking if a URI is visited. michael@0: * michael@0: * @note this should only be accessed by GetIsVisistedStatement and Shutdown. michael@0: */ michael@0: nsCOMPtr mReadOnlyDBConn; michael@0: michael@0: /** michael@0: * An asynchronous statement to query if a URI is visited or not. michael@0: * michael@0: * @note this should only be accessed by GetIsVisistedStatement and Shutdown. michael@0: */ michael@0: nsCOMPtr mIsVisitedStatement; michael@0: michael@0: /** michael@0: * Remove any memory references to tasks and do not take on any more. michael@0: */ michael@0: void Shutdown(); michael@0: michael@0: static History* gService; michael@0: michael@0: // Ensures new tasks aren't started on destruction. michael@0: bool mShuttingDown; michael@0: // This mutex guards mShuttingDown. Code running in other threads that might michael@0: // schedule tasks that use the database should grab it and check the value of michael@0: // mShuttingDown. If we are already shutting down, the code must gracefully michael@0: // avoid using the db. If we are not, the lock will prevent shutdown from michael@0: // starting in an unexpected moment. michael@0: Mutex mShutdownMutex; michael@0: michael@0: typedef nsTObserverArray ObserverArray; michael@0: michael@0: class KeyClass : public nsURIHashKey michael@0: { michael@0: public: michael@0: KeyClass(const nsIURI* aURI) michael@0: : nsURIHashKey(aURI) michael@0: { michael@0: } michael@0: KeyClass(const KeyClass& aOther) michael@0: : nsURIHashKey(aOther) michael@0: { michael@0: NS_NOTREACHED("Do not call me!"); michael@0: } michael@0: ObserverArray array; michael@0: }; michael@0: michael@0: /** michael@0: * Helper function for nsTHashtable::SizeOfExcludingThis call in michael@0: * SizeOfIncludingThis(). michael@0: */ michael@0: static size_t SizeOfEntryExcludingThis(KeyClass* aEntry, michael@0: mozilla::MallocSizeOf aMallocSizeOf, michael@0: void*); michael@0: michael@0: nsTHashtable mObservers; michael@0: michael@0: /** michael@0: * mRecentlyVisitedURIs remembers URIs which are recently added to the DB, michael@0: * to avoid saving these locations repeatedly in a short period. michael@0: */ michael@0: typedef nsAutoTArray, RECENTLY_VISITED_URI_SIZE> michael@0: RecentlyVisitedArray; michael@0: RecentlyVisitedArray mRecentlyVisitedURIs; michael@0: RecentlyVisitedArray::index_type mRecentlyVisitedURIsNextIndex; michael@0: michael@0: bool IsRecentlyVisitedURI(nsIURI* aURI); michael@0: }; michael@0: michael@0: } // namespace places michael@0: } // namespace mozilla michael@0: michael@0: #endif // mozilla_places_History_h_