// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_BROWSER_HISTORY_EXPIRE_HISTORY_BACKEND_H_ #define CHROME_BROWSER_HISTORY_EXPIRE_HISTORY_BACKEND_H_ #include #include #include #include "base/basictypes.h" #include "base/gtest_prod_util.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "chrome/browser/history/history_types.h" class GURL; class TestingProfile; namespace history { class HistoryClient; class HistoryDatabase; struct HistoryDetails; class ThumbnailDatabase; // Delegate used to broadcast notifications to the main thread. class BroadcastNotificationDelegate { public: // Schedules a broadcast of the given notification on the application main // thread. virtual void BroadcastNotifications(int type, scoped_ptr details) = 0; // Tells typed url sync code to handle URL modifications or deletions. virtual void NotifySyncURLsModified(URLRows* rows) = 0; virtual void NotifySyncURLsDeleted(bool all_history, bool expired, URLRows* rows) = 0; protected: virtual ~BroadcastNotificationDelegate() {} }; // Encapsulates visit expiration criteria and type of visits to expire. class ExpiringVisitsReader { public: virtual ~ExpiringVisitsReader() {} // Populates |visits| from |db|, using provided |end_time| and |max_visits| // cap. virtual bool Read(base::Time end_time, HistoryDatabase* db, VisitVector* visits, int max_visits) const = 0; }; typedef std::vector ExpiringVisitsReaders; // Helper component to HistoryBackend that manages expiration and deleting of // history. // // It will automatically start periodically expiring old history once you call // StartExpiringOldStuff(). class ExpireHistoryBackend { public: // The delegate pointer must be non-NULL. We will NOT take ownership of it. // HistoryClient may be NULL. The HistoryClient is used when expiring URLS so // that we don't remove any URLs or favicons that are bookmarked (visits are // removed though). ExpireHistoryBackend(BroadcastNotificationDelegate* delegate, HistoryClient* history_client); ~ExpireHistoryBackend(); // Completes initialization by setting the databases that this class will use. void SetDatabases(HistoryDatabase* main_db, ThumbnailDatabase* thumb_db); // Begins periodic expiration of history older than the given threshold. This // will continue until the object is deleted. void StartExpiringOldStuff(base::TimeDelta expiration_threshold); // Deletes everything associated with a URL. void DeleteURL(const GURL& url); // Deletes everything associated with each URL in the list. void DeleteURLs(const std::vector& url); // Removes all visits to restrict_urls (or all URLs if empty) in the given // time range, updating the URLs accordingly. void ExpireHistoryBetween(const std::set& restrict_urls, base::Time begin_time, base::Time end_time); // Removes all visits to all URLs with the given times, updating the // URLs accordingly. |times| must be in reverse chronological order // and not contain any duplicates. void ExpireHistoryForTimes(const std::vector& times); // Removes the given list of visits, updating the URLs accordingly (similar to // ExpireHistoryBetween(), but affecting a specific set of visits). void ExpireVisits(const VisitVector& visits); // Expires all visits before and including the given time, updating the URLs // accordingly. Currently only used for testing. void ExpireHistoryBefore(base::Time end_time); // Returns the current cut-off time before which we will start expiring stuff. // Note that this as an absolute time rather than a delta, so the caller // should not save it. base::Time GetCurrentExpirationTime() const { return base::Time::Now() - expiration_threshold_; } private: FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, DeleteFaviconsIfPossible); FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ExpireSomeOldHistory); FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ExpiringVisitsReader); FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ExpireSomeOldHistoryWithSource); friend class ::TestingProfile; struct DeleteEffects { DeleteEffects(); ~DeleteEffects(); // The time range affected. These can be is_null() to be unbounded in one // or both directions. base::Time begin_time, end_time; // The unique URL rows affected by this delete. std::map affected_urls; // The URLs modified, but not deleted, during this operation. URLRows modified_urls; // The URLs deleted during this operation. URLRows deleted_urls; // All favicon IDs that the deleted URLs had. Favicons will be shared // between all URLs with the same favicon, so this is the set of IDs that we // will need to check when the delete operations are complete. std::set affected_favicons; // All favicon urls that were actually deleted from the thumbnail db. std::set deleted_favicons; }; // Deletes the visit-related stuff for all the visits in the given list, and // adds the rows for unique URLs affected to the affected_urls list in // the dependencies structure. void DeleteVisitRelatedInfo(const VisitVector& visits, DeleteEffects* effects); // Finds or deletes dependency information for the given URL. Information that // is specific to this URL (URL row, thumbnails, etc.) is deleted. // // This does not affect the visits! This is used for expiration as well as // deleting from the UI, and they handle visits differently. // // Other information will be collected and returned in the output containers. // This includes some of the things deleted that are needed elsewhere, plus // some things like favicons that could be shared by many URLs, and need to // be checked for deletion (this allows us to delete many URLs with only one // check for shared information at the end). // // Assumes the main_db_ is non-NULL. // // NOTE: If the url is bookmarked only the segments and text db are updated, // everything else is unchanged. This is done so that bookmarks retain their // favicons and thumbnails. void DeleteOneURL(const URLRow& url_row, bool is_bookmarked, DeleteEffects* effects); // Deletes all the URLs in the given vector and handles their dependencies. // This will delete starred URLs void DeleteURLs(const URLRows& urls, DeleteEffects* effects); // Expiration involves removing visits, then propagating the visits out from // there and delete any orphaned URLs. These will be added to the deleted URLs // field of the dependencies and DeleteOneURL will handle deleting out from // there. This function does not handle favicons. // // When a URL is not deleted, the last visit time and the visit and typed // counts will be updated. // // The visits in the given vector should have already been deleted from the // database, and the list of affected URLs already be filled into // |depenencies->affected_urls|. // // Starred URLs will not be deleted. The information in the dependencies that // DeleteOneURL fills in will be updated, and this function will also delete // any now-unused favicons. void ExpireURLsForVisits(const VisitVector& visits, DeleteEffects* effects); // Deletes the favicons listed in |effects->affected_favicons| if they are // unsued. Fails silently (we don't care about favicons so much, so don't want // to stop everything if it fails). Fills |expired_favicons| with the set of // favicon urls that no longer have associated visits and were therefore // expired. void DeleteFaviconsIfPossible(DeleteEffects* effects); // Enum representing what type of action resulted in the history DB deletion. enum DeletionType { // User initiated the deletion from the History UI. DELETION_USER_INITIATED, // History data was automatically expired due to being more than 90 days // old. DELETION_EXPIRED }; // Broadcasts URL modified and deleted notifications. void BroadcastNotifications(DeleteEffects* effects, DeletionType type); // Schedules a call to DoExpireIteration. void ScheduleExpire(); // Calls ExpireSomeOldHistory to expire some amount of old history, according // to the items in work queue, and schedules another call to happen in the // future. void DoExpireIteration(); // Tries to expire the oldest |max_visits| visits from history that are older // than |time_threshold|. The return value indicates if we think there might // be more history to expire with the current time threshold (it does not // indicate success or failure). bool ExpireSomeOldHistory(base::Time end_time, const ExpiringVisitsReader* reader, int max_visits); // Tries to detect possible bad history or inconsistencies in the database // and deletes items. For example, URLs with no visits. void ParanoidExpireHistory(); // Returns the HistoryClient, blocking until the bookmarks are loaded. This // may return NULL during testing. HistoryClient* GetHistoryClient(); // Initializes periodic expiration work queue by populating it with with tasks // for all known readers. void InitWorkQueue(); // Returns the reader for all visits. This method is only used by the unit // tests. const ExpiringVisitsReader* GetAllVisitsReader(); // Returns the reader for AUTO_SUBFRAME visits. This method is only used by // the unit tests. const ExpiringVisitsReader* GetAutoSubframeVisitsReader(); // Non-owning pointer to the notification delegate (guaranteed non-NULL). BroadcastNotificationDelegate* delegate_; // Non-owning pointers to the databases we deal with (MAY BE NULL). HistoryDatabase* main_db_; // Main history database. ThumbnailDatabase* thumb_db_; // Thumbnails and favicons. // Used to generate runnable methods to do timers on this class. They will be // automatically canceled when this class is deleted. base::WeakPtrFactory weak_factory_; // The threshold for "old" history where we will automatically delete it. base::TimeDelta expiration_threshold_; // List of all distinct types of readers. This list is used to populate the // work queue. ExpiringVisitsReaders readers_; // Work queue for periodic expiration tasks, used by DoExpireIteration() to // determine what to do at an iteration, as well as populate it for future // iterations. std::queue work_queue_; // Readers for various types of visits. // TODO(dglazkov): If you are adding another one, please consider reorganizing // into a map. scoped_ptr all_visits_reader_; scoped_ptr auto_subframe_visits_reader_; // The HistoryClient; may be NULL. // // Use GetHistoryClient to access this, which makes sure the bookmarks are // loaded before returning. HistoryClient* history_client_; DISALLOW_COPY_AND_ASSIGN(ExpireHistoryBackend); }; } // namespace history #endif // CHROME_BROWSER_HISTORY_EXPIRE_HISTORY_BACKEND_H_