mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 516940 - Reduce and cleanup Places expiration work at shutdown, r=sdwilsh
This commit is contained in:
parent
53770263be
commit
b6d670967a
@ -21,7 +21,9 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian Ryner <bryner@brianryner.com> (original author)
|
||||
* Dietrich Ayala <dietrich@mozilla.com>
|
||||
* Drew Willcoxon <adw@mozilla.com>
|
||||
* Marco Bonardo <mak77@bonardo.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -3030,15 +3032,6 @@ nsNavBookmarks::RemoveObserver(nsINavBookmarkObserver *aObserver)
|
||||
return mObservers.RemoveWeakElement(aObserver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the History service when shutting down
|
||||
*/
|
||||
nsresult
|
||||
nsNavBookmarks::OnQuit()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsNavBookmarks::nsINavHistoryObserver
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -21,6 +21,8 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian Ryner <bryner@brianryner.com> (original author)
|
||||
* Dietrich Ayala <dietrich@mozilla.com>
|
||||
* Marco Bonardo <mak77@bonardo.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -106,9 +108,6 @@ public:
|
||||
*/
|
||||
PRBool IsRealBookmark(PRInt64 aPlaceId);
|
||||
|
||||
// Called by History service when quitting.
|
||||
nsresult OnQuit();
|
||||
|
||||
nsresult BeginUpdateBatch();
|
||||
nsresult EndUpdateBatch();
|
||||
|
||||
|
@ -47,7 +47,6 @@
|
||||
#include "nsNavHistory.h"
|
||||
#include "nsNavBookmarks.h"
|
||||
#include "nsAnnotationService.h"
|
||||
#include "nsIIdleService.h"
|
||||
#include "nsILivemarkService.h"
|
||||
|
||||
#include "nsPlacesTables.h"
|
||||
@ -187,12 +186,6 @@ using namespace mozilla::places;
|
||||
|
||||
#endif // LAZY_ADD
|
||||
|
||||
// Perform expiration after 5 minutes of idle time, repeating.
|
||||
#define EXPIRE_IDLE_TIME_IN_MSECS (5 * 60 * PR_MSEC_PER_SEC)
|
||||
|
||||
// Amount of items to expire at idle time.
|
||||
#define MAX_EXPIRE_RECORDS_ON_IDLE 200
|
||||
|
||||
// Limit the number of items in the history for performance reasons
|
||||
#define EXPIRATION_CAP_SITES 40000
|
||||
|
||||
@ -428,7 +421,6 @@ nsNavHistory::nsNavHistory() : mBatchLevel(0),
|
||||
mBatchHasTransaction(PR_FALSE),
|
||||
mNowValid(PR_FALSE),
|
||||
mExpireNowTimer(nsnull),
|
||||
mExpire(this),
|
||||
mExpireDaysMin(0),
|
||||
mExpireDaysMax(0),
|
||||
mExpireSites(0),
|
||||
@ -447,7 +439,6 @@ nsNavHistory::nsNavHistory() : mBatchLevel(0),
|
||||
gHistoryService = this;
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistory::~nsNavHistory
|
||||
|
||||
nsNavHistory::~nsNavHistory()
|
||||
@ -501,6 +492,10 @@ nsNavHistory::Init()
|
||||
rv = InitAdditionalDBItems();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Initialize expiration. There's no need to do this before, since just now
|
||||
// we have a valid database and a working connection.
|
||||
mExpire = new nsNavHistoryExpire();
|
||||
|
||||
// Notify we have finished database initialization.
|
||||
// Enqueue the notification, so if we init another service that requires
|
||||
// nsNavHistoryService we don't recursive try to get it.
|
||||
@ -528,9 +523,6 @@ nsNavHistory::Init()
|
||||
mLastSessionID = 1;
|
||||
}
|
||||
|
||||
// initialize idle timer
|
||||
InitializeIdleTimer();
|
||||
|
||||
// recent events hash tables
|
||||
NS_ENSURE_TRUE(mRecentTyped.Init(128), NS_ERROR_OUT_OF_MEMORY);
|
||||
NS_ENSURE_TRUE(mRecentBookmark.Init(128), NS_ERROR_OUT_OF_MEMORY);
|
||||
@ -966,25 +958,6 @@ nsNavHistory::InitAdditionalDBItems()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsNavHistory::InitializeIdleTimer()
|
||||
{
|
||||
if (mIdleTimer) {
|
||||
mIdleTimer->Cancel();
|
||||
mIdleTimer = nsnull;
|
||||
}
|
||||
nsresult rv;
|
||||
mIdleTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRInt32 idleTimerTimeout = EXPIRE_IDLE_TIME_IN_MSECS;
|
||||
rv = mIdleTimer->InitWithFuncCallback(IdleTimerCallback, this,
|
||||
idleTimerTimeout,
|
||||
nsITimer::TYPE_REPEATING_SLACK);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNavHistory::GetDatabaseStatus(PRUint16 *aDatabaseStatus)
|
||||
{
|
||||
@ -4499,7 +4472,7 @@ nsNavHistory::CleanupPlacesOnVisitsDelete(const nsCString& aPlaceIdsQueryString)
|
||||
|
||||
// now that visits have been removed, run annotation expiration.
|
||||
// this will remove all expire-able annotations for these URIs.
|
||||
(void)mExpire.OnDeleteURI();
|
||||
(void)mExpire->OnDeleteVisits();
|
||||
|
||||
// if the entry is not bookmarked and is not a place: uri
|
||||
// then we can remove it from moz_places.
|
||||
@ -4887,7 +4860,7 @@ nsNavHistory::RemoveAllPages()
|
||||
#endif
|
||||
|
||||
// expire everything
|
||||
mExpire.ClearHistory();
|
||||
mExpire->ClearHistory();
|
||||
|
||||
// Compress DB. Currently commented out because compression is very slow.
|
||||
// Deleted data will be overwritten with 0s by sqlite.
|
||||
@ -5498,39 +5471,6 @@ nsNavHistory::AddDocumentRedirect(nsIChannel *aOldChannel,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsNavHistory::OnIdle()
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIIdleService> idleService =
|
||||
do_GetService("@mozilla.org/widget/idleservice;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 idleTime;
|
||||
rv = idleService->GetIdleTime(&idleTime);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// If we've been idle for more than EXPIRE_IDLE_TIME_IN_MSECS
|
||||
// keep the expiration engine chugging along.
|
||||
if (idleTime > EXPIRE_IDLE_TIME_IN_MSECS) {
|
||||
mozStorageTransaction transaction(mDBConn, PR_TRUE);
|
||||
|
||||
PRBool keepGoing; // We don't care about this value.
|
||||
(void)mExpire.ExpireItems(MAX_EXPIRE_RECORDS_ON_IDLE / 2, &keepGoing);
|
||||
|
||||
(void)mExpire.ExpireOrphans(MAX_EXPIRE_RECORDS_ON_IDLE / 2);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void // static
|
||||
nsNavHistory::IdleTimerCallback(nsITimer* aTimer, void* aClosure)
|
||||
{
|
||||
nsNavHistory *history = static_cast<nsNavHistory *>(aClosure);
|
||||
(void)history->OnIdle();
|
||||
}
|
||||
|
||||
// nsIDownloadHistory **********************************************************
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -5638,6 +5578,12 @@ nsNavHistory::NotifyOnPageExpired(nsIURI *aURI, PRTime aVisitTime,
|
||||
{
|
||||
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavHistoryObserver,
|
||||
OnPageExpired(aURI, aVisitTime, aWholeEntry));
|
||||
if (aWholeEntry) {
|
||||
// Notify our observers that the URI has been removed.
|
||||
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
|
||||
nsINavHistoryObserver, OnDeleteURI(aURI))
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -5650,23 +5596,14 @@ nsNavHistory::Observe(nsISupports *aSubject, const char *aTopic,
|
||||
NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread");
|
||||
|
||||
if (strcmp(aTopic, gQuitApplicationGrantedMessage) == 0) {
|
||||
if (mIdleTimer) {
|
||||
mIdleTimer->Cancel();
|
||||
mIdleTimer = nsnull;
|
||||
}
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPrefService> prefService =
|
||||
do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
prefService->SavePrefFile(nsnull);
|
||||
|
||||
// notify expiring system that we're quitting, it may want to do stuff
|
||||
mExpire.OnQuit();
|
||||
|
||||
// notify the bookmarks service we're quitting
|
||||
nsNavBookmarks *bookmarks = nsNavBookmarks::GetBookmarksService();
|
||||
NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
|
||||
(void)bookmarks->OnQuit();
|
||||
// Start shutdown expiration.
|
||||
mExpire->OnQuit();
|
||||
}
|
||||
else if (strcmp(aTopic, gXpcomShutdown) == 0) {
|
||||
nsresult rv;
|
||||
@ -5719,7 +5656,7 @@ nsNavHistory::Observe(nsISupports *aSubject, const char *aTopic,
|
||||
LoadPrefs(PR_FALSE);
|
||||
if (oldDaysMin != mExpireDaysMin || oldDaysMax != mExpireDaysMax ||
|
||||
oldVisits != mExpireSites)
|
||||
mExpire.OnExpirationChanged();
|
||||
mExpire->OnExpirationChanged();
|
||||
}
|
||||
else if (strcmp(aTopic, gIdleDaily) == 0) {
|
||||
// Ensure our connection is still alive. The idle-daily observer is removed
|
||||
|
@ -23,6 +23,7 @@
|
||||
* Brett Wilson <brettw@gmail.com> (original author)
|
||||
* Edward Lee <edward.lee@engineering.uiuc.edu>
|
||||
* Ehsan Akhgari <ehsan.akhgari@gmail.com>
|
||||
* Marco Bonardo <mak77@bonardo.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -528,7 +529,7 @@ protected:
|
||||
|
||||
// expiration
|
||||
friend class nsNavHistoryExpire;
|
||||
nsNavHistoryExpire mExpire;
|
||||
nsNavHistoryExpire *mExpire;
|
||||
|
||||
#ifdef LAZY_ADD
|
||||
// lazy add committing
|
||||
@ -692,15 +693,6 @@ protected:
|
||||
nsCOMArray<nsNavHistoryQuery>* aQueries,
|
||||
nsNavHistoryQueryOptions* aOptions);
|
||||
|
||||
/**
|
||||
* Used to setup the idle timer used to perform various tasks when the user is
|
||||
* idle..
|
||||
*/
|
||||
nsCOMPtr<nsITimer> mIdleTimer;
|
||||
nsresult InitializeIdleTimer();
|
||||
static void IdleTimerCallback(nsITimer* aTimer, void* aClosure);
|
||||
nsresult OnIdle();
|
||||
|
||||
PRInt64 mTagsFolder;
|
||||
|
||||
PRBool mInPrivateBrowsing;
|
||||
|
@ -21,6 +21,8 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brett Wilson <brettw@gmail.com> (original author)
|
||||
* Dietrich Ayala <dietrich@mozilla.com>
|
||||
* Marco Bonardo <mak77@bonardo.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -48,6 +50,7 @@
|
||||
#include "nsIAnnotationService.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsPlacesMacros.h"
|
||||
#include "nsIIdleService.h"
|
||||
|
||||
struct nsNavHistoryExpireRecord {
|
||||
nsNavHistoryExpireRecord(mozIStorageStatement* statement);
|
||||
@ -62,176 +65,169 @@ struct nsNavHistoryExpireRecord {
|
||||
PRBool erased; // set to true if/when the history entry is erased
|
||||
};
|
||||
|
||||
// Number of things we'll expire at once. Runtime of expiration is approximately
|
||||
// linear with the number of things we expire at once. This number was picked so
|
||||
// we expire "several" things at once, but still run quickly. Just doing 3
|
||||
// expirations at once isn't much faster than 6 due to constant overhead of
|
||||
// running the query.
|
||||
#define EXPIRATION_COUNT_PER_RUN 6
|
||||
// The time in ms to wait before kick-off partial expiration after preferences
|
||||
// are changed.
|
||||
#define EXPIRATION_PARTIAL_TIMEOUT 500
|
||||
|
||||
// Larger expiration chunk for idle time and shutdown.
|
||||
#define EXPIRATION_COUNT_PER_RUN_LARGE 50
|
||||
// The time in ms to wait between each partial expiration step.
|
||||
#define EXPIRATION_PARTIAL_SUBSEQUENT_TIMEOUT ((PRUint32)10 * PR_MSEC_PER_SEC)
|
||||
|
||||
// The time in ms to wait after AddURI to try expiration of pages. Short is
|
||||
// actually better. If expiration takes an unusually long period of time, it
|
||||
// will interfere with video playback in the browser, for example. Such a blip
|
||||
// is not likely to be noticeable when the page has just appeared.
|
||||
#define PARTIAL_EXPIRATION_TIMEOUT (3.5 * PR_MSEC_PER_SEC)
|
||||
// Number of pages we'll expire at each partial expiration run. Partial
|
||||
// expiration runs when expiration preferences run.
|
||||
#define EXPIRATION_PAGES_PER_RUN 6
|
||||
|
||||
// The time in ms to wait after the initial expiration run for additional ones
|
||||
#define SUBSEQUENT_EXPIRATION_TIMEOUT (20 * PR_MSEC_PER_SEC)
|
||||
// The time in ms the user should be idle before we run expiration.
|
||||
// This will be repeated till we find enough entries to expire, otherwise
|
||||
// we will wait for a longer timeout before checking again.
|
||||
#define EXPIRATION_IDLE_TIMEOUT ((PRUint32)5 * 60 * PR_MSEC_PER_SEC)
|
||||
// The time in ms the user should be idle before we run expiration when the
|
||||
// previous call ran out of expirable pages.
|
||||
#define EXPIRATION_IDLE_LONG_TIMEOUT EXPIRATION_IDLE_TIMEOUT * 10
|
||||
|
||||
// Number of expirations we'll do after the most recent page is loaded before
|
||||
// stopping. We don't want to keep the computer chugging forever expiring
|
||||
// annotations if the user stopped using the browser.
|
||||
//
|
||||
// This current value of one prevents history expiration while the page is
|
||||
// being shown, because expiration may interfere with media playback.
|
||||
#define MAX_SEQUENTIAL_RUNS 1
|
||||
// During idle we can expire a larger chunk of pages.
|
||||
#define EXPIRATION_MAX_PAGES_AT_IDLE 100
|
||||
|
||||
// During shutdown we should cleanup any dangling moz_places record, but we
|
||||
// cannot expire a too large number of entries since that would slowdown
|
||||
// shutdown.
|
||||
#define EXPIRATION_MAX_PAGES_AT_SHUTDOWN 100
|
||||
|
||||
// Expiration policy amounts in microseconds.
|
||||
const PRTime EXPIRATION_POLICY_DAYS = ((PRTime)7 * 86400 * PR_USEC_PER_SEC);
|
||||
const PRTime EXPIRATION_POLICY_WEEKS = ((PRTime)30 * 86400 * PR_USEC_PER_SEC);
|
||||
const PRTime EXPIRATION_POLICY_MONTHS = ((PRTime)180 * 86400 * PR_USEC_PER_SEC);
|
||||
|
||||
// History preferences.
|
||||
#define PREF_BRANCH_BASE "browser."
|
||||
#define PREF_BROWSER_HISTORY_EXPIRE_DAYS "history_expire_days"
|
||||
|
||||
// Sanitization preferences
|
||||
#define PREF_SANITIZE_ON_SHUTDOWN "privacy.sanitize.sanitizeOnShutdown"
|
||||
#define PREF_SANITIZE_ITEM_HISTORY "privacy.item.history"
|
||||
|
||||
// Expiration policy amounts (in microseconds)
|
||||
const PRTime EXPIRATION_POLICY_DAYS = ((PRTime)7 * 86400 * PR_USEC_PER_SEC);
|
||||
const PRTime EXPIRATION_POLICY_WEEKS = ((PRTime)30 * 86400 * PR_USEC_PER_SEC);
|
||||
const PRTime EXPIRATION_POLICY_MONTHS = ((PRTime)180 * 86400 * PR_USEC_PER_SEC);
|
||||
|
||||
// Expiration cap for dangling moz_places records
|
||||
#define EXPIRATION_CAP_PLACES 500
|
||||
|
||||
// History preferences
|
||||
#define PREF_BRANCH_BASE "browser."
|
||||
#define PREF_BROWSER_HISTORY_EXPIRE_DAYS "history_expire_days"
|
||||
|
||||
// nsNavHistoryExpire::nsNavHistoryExpire
|
||||
//
|
||||
// Warning: don't do anything with aHistory in the constructor, since
|
||||
// this is a member of the nsNavHistory, it is still being constructed
|
||||
// when this is called.
|
||||
|
||||
nsNavHistoryExpire::nsNavHistoryExpire(nsNavHistory* aHistory) :
|
||||
mHistory(aHistory),
|
||||
mTimerSet(PR_FALSE),
|
||||
mAnyEmptyRuns(PR_FALSE),
|
||||
mNextExpirationTime(0),
|
||||
mAddCount(0),
|
||||
mExpiredItems(0)
|
||||
nsNavHistoryExpire::nsNavHistoryExpire() :
|
||||
mNextExpirationTime(0)
|
||||
{
|
||||
mHistory = nsNavHistory::GetHistoryService();
|
||||
NS_ASSERTION(mHistory, "History service should exist at this point.");
|
||||
mDBConn = mHistory->GetStorageConnection();
|
||||
NS_ASSERTION(mDBConn, "History service should have a valid database connection");
|
||||
|
||||
// Initialize idle timer.
|
||||
InitializeIdleTimer(EXPIRATION_IDLE_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::~nsNavHistoryExpire
|
||||
|
||||
nsNavHistoryExpire::~nsNavHistoryExpire()
|
||||
{
|
||||
|
||||
// Cancel any pending timers.
|
||||
if (mPartialExpirationTimer) {
|
||||
mPartialExpirationTimer->Cancel();
|
||||
mPartialExpirationTimer = 0;
|
||||
}
|
||||
if (mIdleTimer) {
|
||||
mIdleTimer->Cancel();
|
||||
mIdleTimer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::OnAddURI
|
||||
//
|
||||
// Called by history when a URI is added to history. This starts the timer
|
||||
// for when we are going to expire.
|
||||
//
|
||||
// The current time is passed in by the history service as an optimization.
|
||||
// The AddURI function has already computed the proper time, and getting the
|
||||
// time again from the OS is nontrivial.
|
||||
|
||||
void
|
||||
nsNavHistoryExpire::OnAddURI(PRTime aNow)
|
||||
nsNavHistoryExpire::InitializeIdleTimer(PRUint32 aTimeInMs)
|
||||
{
|
||||
mAddCount ++;
|
||||
|
||||
if (mTimer && mTimerSet) {
|
||||
mTimer->Cancel();
|
||||
mTimerSet = PR_FALSE;
|
||||
if (mIdleTimer) {
|
||||
mIdleTimer->Cancel();
|
||||
mIdleTimer = 0;
|
||||
}
|
||||
|
||||
if (mNextExpirationTime != 0 && aNow < mNextExpirationTime)
|
||||
return; // we know there's nothing to expire yet
|
||||
|
||||
StartTimer(PARTIAL_EXPIRATION_TIMEOUT);
|
||||
mIdleTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
if (mIdleTimer) {
|
||||
(void)mIdleTimer->InitWithFuncCallback(IdleTimerCallback, this, aTimeInMs,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
}
|
||||
|
||||
// nsNavHistoryExpire::OnDeleteURI
|
||||
//
|
||||
// Called by history when a URI is deleted from history.
|
||||
// This kicks off an expiration of annotations.
|
||||
//
|
||||
void
|
||||
nsNavHistoryExpire::OnDeleteURI()
|
||||
void // static
|
||||
nsNavHistoryExpire::IdleTimerCallback(nsITimer* aTimer, void* aClosure)
|
||||
{
|
||||
mozIStorageConnection* connection = mHistory->GetStorageConnection();
|
||||
if (!connection) {
|
||||
NS_NOTREACHED("No connection");
|
||||
nsNavHistoryExpire* expire = static_cast<nsNavHistoryExpire*>(aClosure);
|
||||
expire->mIdleTimer = 0;
|
||||
expire->OnIdle();
|
||||
}
|
||||
|
||||
void
|
||||
nsNavHistoryExpire::OnIdle()
|
||||
{
|
||||
PRUint32 idleTime = 0;
|
||||
nsCOMPtr<nsIIdleService> idleService =
|
||||
do_GetService("@mozilla.org/widget/idleservice;1");
|
||||
if (idleService)
|
||||
(void)idleService->GetIdleTime(&idleTime);
|
||||
|
||||
// If we've been idle for more than EXPIRATION_IDLE_TIMEOUT
|
||||
// we can expire a chunk of elements.
|
||||
if (idleTime < EXPIRATION_IDLE_TIMEOUT)
|
||||
return;
|
||||
|
||||
mozStorageTransaction transaction(mDBConn, PR_TRUE);
|
||||
|
||||
bool keepGoing = ExpireItems(EXPIRATION_MAX_PAGES_AT_IDLE);
|
||||
ExpireOrphans(EXPIRATION_MAX_PAGES_AT_IDLE);
|
||||
|
||||
if (!keepGoing) {
|
||||
// We have expired enough entries, so there is no more need to be agressive
|
||||
// on idle for some time.
|
||||
InitializeIdleTimer(EXPIRATION_IDLE_LONG_TIMEOUT);
|
||||
}
|
||||
nsresult rv = ExpireAnnotations(connection);
|
||||
if (NS_FAILED(rv))
|
||||
NS_WARNING("ExpireAnnotations failed.");
|
||||
else
|
||||
InitializeIdleTimer(EXPIRATION_IDLE_TIMEOUT);
|
||||
}
|
||||
|
||||
// nsNavHistoryExpire::OnQuit
|
||||
//
|
||||
// Here we check for some edge cases and fix them
|
||||
void
|
||||
nsNavHistoryExpire::OnDeleteVisits()
|
||||
{
|
||||
(void)ExpireAnnotations();
|
||||
}
|
||||
|
||||
void
|
||||
nsNavHistoryExpire::OnQuit()
|
||||
{
|
||||
mozIStorageConnection* connection = mHistory->GetStorageConnection();
|
||||
if (!connection) {
|
||||
NS_NOTREACHED("No connection");
|
||||
return;
|
||||
// Cancel any pending timers so we won't try to expire during shutdown.
|
||||
if (mPartialExpirationTimer) {
|
||||
mPartialExpirationTimer->Cancel();
|
||||
mPartialExpirationTimer = 0;
|
||||
}
|
||||
if (mIdleTimer) {
|
||||
mIdleTimer->Cancel();
|
||||
mIdleTimer = 0;
|
||||
}
|
||||
|
||||
// Need to cancel any pending timers so we don't try to expire during shutdown
|
||||
if (mTimer)
|
||||
mTimer->Cancel();
|
||||
nsCOMPtr<nsIPrefBranch> prefs =
|
||||
do_GetService("@mozilla.org/preferences-service;1");
|
||||
if (prefs) {
|
||||
// Determine whether we can skip partially expiration of dangling entries
|
||||
// because we be doing a full expiration on shutdown in ClearHistory().
|
||||
PRBool sanitizeOnShutdown = PR_FALSE;
|
||||
(void)prefs->GetBoolPref(PREF_SANITIZE_ON_SHUTDOWN, &sanitizeOnShutdown);
|
||||
PRBool sanitizeHistory = PR_FALSE;
|
||||
(void)prefs->GetBoolPref(PREF_SANITIZE_ITEM_HISTORY, &sanitizeHistory);
|
||||
|
||||
// Handle degenerate runs:
|
||||
nsresult rv = ExpireForDegenerateRuns();
|
||||
if (NS_FAILED(rv))
|
||||
NS_WARNING("ExpireForDegenerateRuns failed.");
|
||||
|
||||
// Determine whether we can skip partially expiration of dangling entries
|
||||
// because we be doing a full expiration on shutdown in ClearHistory()
|
||||
nsCOMPtr<nsIPrefBranch> prefs(do_GetService("@mozilla.org/preferences-service;1"));
|
||||
PRBool sanitizeOnShutdown = PR_FALSE;
|
||||
PRBool sanitizeHistory = PR_FALSE;
|
||||
(void)prefs->GetBoolPref(PREF_SANITIZE_ON_SHUTDOWN, &sanitizeOnShutdown);
|
||||
(void)prefs->GetBoolPref(PREF_SANITIZE_ITEM_HISTORY, &sanitizeHistory);
|
||||
if (sanitizeHistory && sanitizeOnShutdown)
|
||||
return;
|
||||
if (sanitizeHistory && sanitizeOnShutdown)
|
||||
return;
|
||||
}
|
||||
|
||||
// Get rid of all records orphaned due to expiration.
|
||||
rv = ExpireOrphans(EXPIRATION_CAP_PLACES);
|
||||
if (NS_FAILED(rv))
|
||||
NS_WARNING("ExpireOrphans failed.");
|
||||
ExpireOrphans(EXPIRATION_MAX_PAGES_AT_SHUTDOWN);
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::ClearHistory
|
||||
//
|
||||
// Performance: ExpireItems sends notifications. We may want to disable this
|
||||
// for clear history cases. However, my initial tests show that the
|
||||
// notifications are not a significant part of clear history time.
|
||||
|
||||
nsresult
|
||||
nsNavHistoryExpire::ClearHistory()
|
||||
{
|
||||
mozIStorageConnection* connection = mHistory->GetStorageConnection();
|
||||
NS_ENSURE_TRUE(connection, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
mozStorageTransaction transaction(connection, PR_FALSE);
|
||||
mozStorageTransaction transaction(mDBConn, PR_FALSE);
|
||||
|
||||
// reset frecency for all items that will _not_ be deleted
|
||||
// Note, we set frecency to -visit_count since we use that value in our
|
||||
// idle query to figure out which places to recalcuate frecency first.
|
||||
// We must do this before deleting visits
|
||||
nsresult rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
// We must do this before deleting visits.
|
||||
nsresult rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"UPDATE moz_places_view SET frecency = -MAX(visit_count, 1) "
|
||||
"WHERE id IN("
|
||||
"SELECT h.id FROM moz_places_temp h "
|
||||
@ -244,31 +240,18 @@ nsNavHistoryExpire::ClearHistory()
|
||||
")"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// expire visits, then let the paranoid functions do the cleanup for us
|
||||
rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
// Expire visits, then let the paranoid functions do the cleanup for us.
|
||||
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_historyvisits_view"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = ExpireHistoryParanoid(connection, -1);
|
||||
if (NS_FAILED(rv))
|
||||
NS_WARNING("ExpireHistoryParanoid failed.");
|
||||
// Expire all orphans.
|
||||
ExpireOrphans(-1);
|
||||
|
||||
rv = ExpireFaviconsParanoid(connection);
|
||||
if (NS_FAILED(rv))
|
||||
NS_WARNING("ExpireFaviconsParanoid failed.");
|
||||
|
||||
rv = ExpireAnnotationsParanoid(connection);
|
||||
if (NS_FAILED(rv))
|
||||
NS_WARNING("ExpireAnnotationsParanoid failed.");
|
||||
|
||||
rv = ExpireInputHistoryParanoid(connection);
|
||||
if (NS_FAILED(rv))
|
||||
NS_WARNING("ExpireInputHistoryParanoid failed.");
|
||||
|
||||
// some of the remaining places could be place: urls or
|
||||
// Some of the remaining places could be place: urls or
|
||||
// unvisited livemark items, so setting the frecency to -1
|
||||
// will cause them to show up in the url bar autocomplete
|
||||
// call FixInvalidFrecenciesForExcludedPlaces() to handle that scenario
|
||||
// call FixInvalidFrecenciesForExcludedPlaces to handle that scenario.
|
||||
rv = mHistory->FixInvalidFrecenciesForExcludedPlaces();
|
||||
if (NS_FAILED(rv))
|
||||
NS_WARNING("failed to fix invalid frecencies");
|
||||
@ -276,10 +259,6 @@ nsNavHistoryExpire::ClearHistory()
|
||||
rv = transaction.Commit();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// XXX todo
|
||||
// forcibly call the "on idle" timer here to do a little work
|
||||
// but the rest will happen on idle.
|
||||
|
||||
ENUMERATE_OBSERVERS(mHistory->canNotify(), mHistory->mCacheObservers,
|
||||
mHistory->mObservers, nsINavHistoryObserver,
|
||||
OnClearHistory())
|
||||
@ -287,101 +266,70 @@ nsNavHistoryExpire::ClearHistory()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::OnExpirationChanged
|
||||
//
|
||||
// Called when the expiration length in days has changed. We clear any
|
||||
// next expiration time, meaning that we'll try to expire stuff next time,
|
||||
// and recompute the value if there's still nothing to expire.
|
||||
|
||||
void
|
||||
nsNavHistoryExpire::OnExpirationChanged()
|
||||
{
|
||||
mNextExpirationTime = 0;
|
||||
// kick off expiration
|
||||
(void)OnAddURI(PR_Now());
|
||||
// Kick off partial expiration.
|
||||
// Subsequent steps will be on timer.
|
||||
StartPartialExpirationTimer(EXPIRATION_PARTIAL_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::DoPartialExpiration
|
||||
|
||||
nsresult
|
||||
nsNavHistoryExpire::DoPartialExpiration()
|
||||
{
|
||||
// expire history items
|
||||
PRBool keepGoing;
|
||||
nsresult rv = ExpireItems(EXPIRATION_COUNT_PER_RUN, &keepGoing);
|
||||
if (NS_FAILED(rv))
|
||||
NS_WARNING("ExpireItems failed.");
|
||||
else if (keepGoing)
|
||||
StartTimer(SUBSEQUENT_EXPIRATION_TIMEOUT);
|
||||
bool keepGoing = ExpireItems(EXPIRATION_PAGES_PER_RUN);
|
||||
if (keepGoing)
|
||||
StartPartialExpirationTimer(EXPIRATION_PARTIAL_SUBSEQUENT_TIMEOUT);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::ExpireItems
|
||||
//
|
||||
// Here, we try to expire aNumToExpire items and their associated data,
|
||||
// If we expired things and then stopped because we hit this limit,
|
||||
// aKeepGoing will be set indicating we should keep expiring. If we ran
|
||||
// out of things to expire, it will be unset indicating we should wait.
|
||||
//
|
||||
// As a special case, aNumToExpire can be 0 and we'll expire everything
|
||||
// in history.
|
||||
|
||||
nsresult
|
||||
nsNavHistoryExpire::ExpireItems(PRUint32 aNumToExpire, PRBool* aKeepGoing)
|
||||
bool
|
||||
nsNavHistoryExpire::ExpireItems(PRUint32 aNumToExpire)
|
||||
{
|
||||
mozIStorageConnection* connection = mHistory->GetStorageConnection();
|
||||
NS_ENSURE_TRUE(connection, NS_ERROR_OUT_OF_MEMORY);
|
||||
// Whether to keep going after this expiration step.
|
||||
bool keepGoing = true;
|
||||
|
||||
// This transaction is important for performance. It makes the DB flush
|
||||
// everything to disk in one larger operation rather than many small ones.
|
||||
// Note that this transaction always commits.
|
||||
mozStorageTransaction transaction(connection, PR_FALSE);
|
||||
|
||||
*aKeepGoing = PR_TRUE;
|
||||
mozStorageTransaction transaction(mDBConn, PR_FALSE);
|
||||
|
||||
PRInt64 expireTime;
|
||||
if (aNumToExpire == 0) {
|
||||
// special case: erase all history
|
||||
if (!aNumToExpire) {
|
||||
// Special case: erase all pages from history.
|
||||
expireTime = 0;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
expireTime = PR_Now() - GetExpirationTimeAgo(mHistory->mExpireDaysMax);
|
||||
}
|
||||
|
||||
// find some visits to expire
|
||||
// Find some visits to expire.
|
||||
nsTArray<nsNavHistoryExpireRecord> expiredVisits;
|
||||
nsresult rv = FindVisits(expireTime, aNumToExpire, connection,
|
||||
expiredVisits);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsresult rv = FindVisits(expireTime, aNumToExpire, expiredVisits);
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "FindVisits Failed");
|
||||
|
||||
// if we didn't find as many things to expire as we could have, then
|
||||
// we should note the next time we need to expire.
|
||||
if (expiredVisits.Length() < aNumToExpire) {
|
||||
*aKeepGoing = PR_FALSE;
|
||||
ComputeNextExpirationTime(connection);
|
||||
|
||||
if (expiredVisits.Length() == 0) {
|
||||
// Nothing to expire. Set the flag so we know we don't have to do any
|
||||
// work on shutdown.
|
||||
mAnyEmptyRuns = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
keepGoing = false;
|
||||
ComputeNextExpirationTime();
|
||||
}
|
||||
mExpiredItems += expiredVisits.Length();
|
||||
|
||||
rv = EraseVisits(connection, expiredVisits);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = EraseVisits(expiredVisits);
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "EraseVisits Failed");
|
||||
|
||||
rv = EraseHistory(connection, expiredVisits);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = EraseHistory(expiredVisits);
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "EraseHistory Failed");
|
||||
|
||||
// send observer messages
|
||||
// Send observer messages.
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
for (PRUint32 i = 0; i < expiredVisits.Length(); i ++) {
|
||||
rv = NS_NewURI(getter_AddRefs(uri), expiredVisits[i].uri);
|
||||
if (NS_FAILED(rv)) continue;
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Trying to expire a corrupt uri?!");
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME bug 325241 provide a way to observe hidden elements
|
||||
if (expiredVisits[i].hidden) continue;
|
||||
@ -392,65 +340,49 @@ nsNavHistoryExpire::ExpireItems(PRUint32 aNumToExpire, PRBool* aKeepGoing)
|
||||
expiredVisits[i].erased));
|
||||
}
|
||||
|
||||
// don't worry about errors here, it doesn't affect our ability to continue
|
||||
rv = EraseFavicons(connection, expiredVisits);
|
||||
if (NS_FAILED(rv))
|
||||
NS_WARNING("EraseFavicons failed.");
|
||||
|
||||
rv = EraseAnnotations(connection, expiredVisits);
|
||||
if (NS_FAILED(rv))
|
||||
NS_WARNING("EraseAnnotations failed.");
|
||||
|
||||
// expire annotations by policy
|
||||
rv = ExpireAnnotations(connection);
|
||||
if (NS_FAILED(rv))
|
||||
NS_WARNING("ExpireAnnotations failed.");
|
||||
// Don't worry about errors here, it doesn't affect our ability to continue.
|
||||
rv = EraseFavicons(expiredVisits);
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "EraseFavicons Failed");
|
||||
rv = EraseAnnotations(expiredVisits);
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "EraseAnnotations Failed");
|
||||
rv = ExpireAnnotations();
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "ExpireAnnotarions Failed");
|
||||
|
||||
rv = transaction.Commit();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Committing transaction Failed");
|
||||
|
||||
return NS_OK;
|
||||
return keepGoing;
|
||||
}
|
||||
|
||||
// nsNavHistoryExpire::ExpireOrphans
|
||||
//
|
||||
// Try to expire aNumToExpire items that are orphans. aNumToExpire only
|
||||
// limits how many moz_places we worry about. Everything else (favicons,
|
||||
// annotations, and input history) is completely expired.
|
||||
|
||||
nsresult
|
||||
void
|
||||
nsNavHistoryExpire::ExpireOrphans(PRUint32 aNumToExpire)
|
||||
{
|
||||
mozIStorageConnection* connection = mHistory->GetStorageConnection();
|
||||
NS_ENSURE_TRUE(connection, NS_ERROR_OUT_OF_MEMORY);
|
||||
mozStorageTransaction transaction(mDBConn, PR_FALSE);
|
||||
|
||||
mozStorageTransaction transaction(connection, PR_FALSE);
|
||||
nsresult rv = ExpireHistoryParanoid(aNumToExpire);
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "ExpireHistoryParanoid Failed");
|
||||
|
||||
nsresult rv = ExpireHistoryParanoid(connection, aNumToExpire);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = ExpireFaviconsParanoid();
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "ExpireFaviconsParanoid Failed");
|
||||
|
||||
rv = ExpireFaviconsParanoid(connection);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = ExpireAnnotationsParanoid();
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "ExpireAnnotationsParanoid Failed");
|
||||
|
||||
rv = ExpireAnnotationsParanoid(connection);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = ExpireInputHistoryParanoid(connection);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = ExpireInputHistoryParanoid();
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "ExpireInputHistoryParanoid Failed");
|
||||
|
||||
rv = transaction.Commit();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Commit Transaction Failed");
|
||||
}
|
||||
|
||||
// nsNavHistoryExpireRecord::nsNavHistoryExpireRecord
|
||||
//
|
||||
// Statement should be the one created in FindVisits. The parameters must
|
||||
// agree.
|
||||
|
||||
/**
|
||||
* nsNavHistoryExpireRecord::nsNavHistoryExpireRecord
|
||||
*
|
||||
* Statement should be the one created in FindVisits. The parameters must
|
||||
* agree.
|
||||
*/
|
||||
nsNavHistoryExpireRecord::nsNavHistoryExpireRecord(
|
||||
mozIStorageStatement* statement)
|
||||
mozIStorageStatement* statement)
|
||||
{
|
||||
visitID = statement->AsInt64(0);
|
||||
placeID = statement->AsInt64(1);
|
||||
@ -462,29 +394,13 @@ nsNavHistoryExpireRecord::nsNavHistoryExpireRecord(
|
||||
erased = PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::FindVisits
|
||||
//
|
||||
// Find visits to expire, meeting the following criteria:
|
||||
//
|
||||
// * With a visit date older than browser.history_expire_days ago.
|
||||
// * With a visit date older than browser.history_expire_days_min ago
|
||||
// if we have more than browser.history_expire_sites unique urls.
|
||||
//
|
||||
// aExpireThreshold is the time at which we will delete visits before.
|
||||
// If it is zero, we will match everything.
|
||||
//
|
||||
// aNumToExpire is the maximum number of visits to find. If it is 0, then
|
||||
// we will get all matching visits.
|
||||
|
||||
nsresult
|
||||
nsNavHistoryExpire::FindVisits(PRTime aExpireThreshold, PRUint32 aNumToExpire,
|
||||
mozIStorageConnection* aConnection,
|
||||
nsTArray<nsNavHistoryExpireRecord>& aRecords)
|
||||
{
|
||||
// Select a limited number of visits older than a time
|
||||
// Select a limited number of visits older than a time.
|
||||
nsCOMPtr<mozIStorageStatement> selectStatement;
|
||||
nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
|
||||
nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT v.id, v.place_id, v.visit_date, IFNULL(h_t.url, h.url), "
|
||||
"IFNULL(h_t.favicon_id, h.favicon_id), "
|
||||
"IFNULL(h_t.hidden, h.hidden), b.fk "
|
||||
@ -507,12 +423,12 @@ nsNavHistoryExpire::FindVisits(PRTime aExpireThreshold, PRUint32 aNumToExpire,
|
||||
getter_AddRefs(selectStatement));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// browser.history_expire_days || match all visits
|
||||
// Use browser.history_expire_days or match all visits.
|
||||
PRTime expireMaxTime = aExpireThreshold ? aExpireThreshold : LL_MAXINT;
|
||||
rv = selectStatement->BindInt64Parameter(0, expireMaxTime);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// use LIMIT -1 to not limit
|
||||
// Use LIMIT -1 to not limit.
|
||||
PRInt32 numToExpire = aNumToExpire ? aNumToExpire : -1;
|
||||
rv = selectStatement->BindInt64Parameter(1, numToExpire);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -528,7 +444,7 @@ nsNavHistoryExpire::FindVisits(PRTime aExpireThreshold, PRUint32 aNumToExpire,
|
||||
if (aRecords.Length() < aNumToExpire) {
|
||||
// check the number of visited unique urls in the db.
|
||||
nsCOMPtr<mozIStorageStatement> countStatement;
|
||||
rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT "
|
||||
"(SELECT count(*) FROM moz_places_temp WHERE visit_count > 0) + "
|
||||
"(SELECT count(*) FROM moz_places WHERE visit_count > 0 AND "
|
||||
@ -537,14 +453,14 @@ nsNavHistoryExpire::FindVisits(PRTime aExpireThreshold, PRUint32 aNumToExpire,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
hasMore = PR_FALSE;
|
||||
// initialize to mExpiresites to avoid expiring if something goes wrong
|
||||
// initialize to mExpiresites to avoid expiring if something goes wrong.
|
||||
PRInt32 pageCount = mHistory->mExpireSites;
|
||||
if (NS_SUCCEEDED(countStatement->ExecuteStep(&hasMore)) && hasMore) {
|
||||
rv = countStatement->GetInt32(0, &pageCount);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Don't find any more pages to expire if we have not reached the urls cap
|
||||
// Don't find any more pages to expire if we have not reached the urls cap.
|
||||
if (pageCount <= mHistory->mExpireSites)
|
||||
return NS_OK;
|
||||
|
||||
@ -571,11 +487,8 @@ nsNavHistoryExpire::FindVisits(PRTime aExpireThreshold, PRUint32 aNumToExpire,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::EraseVisits
|
||||
|
||||
nsresult
|
||||
nsNavHistoryExpire::EraseVisits(mozIStorageConnection* aConnection,
|
||||
nsNavHistoryExpire::EraseVisits(
|
||||
const nsTArray<nsNavHistoryExpireRecord>& aRecords)
|
||||
{
|
||||
// build a comma separated string of visit ids to delete
|
||||
@ -607,7 +520,7 @@ nsNavHistoryExpire::EraseVisits(mozIStorageConnection* aConnection,
|
||||
// keep the old frecencies when possible as an estimate for the new frecency
|
||||
// unless we know it has to be invalidated.
|
||||
// We must do this before deleting visits
|
||||
nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
nsresult rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"UPDATE moz_places_view "
|
||||
"SET frecency = -MAX(visit_count, 1) "
|
||||
"WHERE id IN ( "
|
||||
@ -643,7 +556,7 @@ nsNavHistoryExpire::EraseVisits(mozIStorageConnection* aConnection,
|
||||
")"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aConnection->ExecuteSimpleSQL(
|
||||
rv = mDBConn->ExecuteSimpleSQL(
|
||||
NS_LITERAL_CSTRING("DELETE FROM moz_historyvisits_view WHERE id IN (") +
|
||||
deletedVisitIds +
|
||||
NS_LITERAL_CSTRING(")"));
|
||||
@ -652,18 +565,8 @@ nsNavHistoryExpire::EraseVisits(mozIStorageConnection* aConnection,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::EraseHistory
|
||||
//
|
||||
// This erases records in moz_places when there are no more visits.
|
||||
// We need to be careful not to delete: bookmarks, items that still have
|
||||
// visits and place: URIs.
|
||||
//
|
||||
// This will modify the input by setting the erased flag on each of the
|
||||
// array elements according to whether the history item was erased or not.
|
||||
|
||||
nsresult
|
||||
nsNavHistoryExpire::EraseHistory(mozIStorageConnection* aConnection,
|
||||
nsNavHistoryExpire::EraseHistory(
|
||||
nsTArray<nsNavHistoryExpireRecord>& aRecords)
|
||||
{
|
||||
// build a comma separated string of place ids to delete
|
||||
@ -688,7 +591,7 @@ nsNavHistoryExpire::EraseHistory(mozIStorageConnection* aConnection,
|
||||
if (deletedPlaceIds.IsEmpty())
|
||||
return NS_OK;
|
||||
|
||||
nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
nsresult rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_places_view WHERE id IN( "
|
||||
"SELECT h.id "
|
||||
"FROM moz_places h "
|
||||
@ -717,11 +620,8 @@ nsNavHistoryExpire::EraseHistory(mozIStorageConnection* aConnection,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::EraseFavicons
|
||||
|
||||
nsresult
|
||||
nsNavHistoryExpire::EraseFavicons(mozIStorageConnection* aConnection,
|
||||
nsNavHistoryExpire::EraseFavicons(
|
||||
const nsTArray<nsNavHistoryExpireRecord>& aRecords)
|
||||
{
|
||||
// build a comma separated string of favicon ids to delete
|
||||
@ -745,7 +645,7 @@ nsNavHistoryExpire::EraseFavicons(mozIStorageConnection* aConnection,
|
||||
return NS_OK;
|
||||
|
||||
// delete only if favicon id is not referenced
|
||||
nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
nsresult rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_favicons WHERE id IN ( "
|
||||
"SELECT f.id FROM moz_favicons f "
|
||||
"LEFT JOIN moz_places h ON f.id = h.favicon_id "
|
||||
@ -759,11 +659,8 @@ nsNavHistoryExpire::EraseFavicons(mozIStorageConnection* aConnection,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::EraseAnnotations
|
||||
|
||||
nsresult
|
||||
nsNavHistoryExpire::EraseAnnotations(mozIStorageConnection* aConnection,
|
||||
nsNavHistoryExpire::EraseAnnotations(
|
||||
const nsTArray<nsNavHistoryExpireRecord>& aRecords)
|
||||
{
|
||||
// remove annotations for the set of records passed in
|
||||
@ -783,7 +680,7 @@ nsNavHistoryExpire::EraseAnnotations(mozIStorageConnection* aConnection,
|
||||
if (placeIds.IsEmpty())
|
||||
return NS_OK;
|
||||
|
||||
nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
nsresult rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_annos WHERE place_id in (") +
|
||||
placeIds + NS_LITERAL_CSTRING(") AND expiration != ") +
|
||||
nsPrintfCString("%d", nsIAnnotationService::EXPIRE_NEVER));
|
||||
@ -791,31 +688,23 @@ nsNavHistoryExpire::EraseAnnotations(mozIStorageConnection* aConnection,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsAnnotationService::ExpireAnnotations
|
||||
//
|
||||
// Periodic expiration of annotations that have time-sensitive
|
||||
// expiration policies.
|
||||
//
|
||||
// NOTE: Always specify the exact policy constant, as they're
|
||||
// not guaranteed to be in numerical order.
|
||||
//
|
||||
nsresult
|
||||
nsNavHistoryExpire::ExpireAnnotations(mozIStorageConnection* aConnection)
|
||||
nsNavHistoryExpire::ExpireAnnotations()
|
||||
{
|
||||
mozStorageTransaction transaction(aConnection, PR_FALSE);
|
||||
mozStorageTransaction transaction(mDBConn, PR_FALSE);
|
||||
|
||||
// Note: The COALESCE is used to cover a short period where NULLs were inserted
|
||||
// into the lastModified column.
|
||||
PRTime now = PR_Now();
|
||||
nsCOMPtr<mozIStorageStatement> expirePagesStatement;
|
||||
nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
|
||||
nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_annos "
|
||||
"WHERE expiration = ?1 AND "
|
||||
"(?2 > MAX(COALESCE(lastModified, 0), dateAdded))"),
|
||||
getter_AddRefs(expirePagesStatement));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<mozIStorageStatement> expireItemsStatement;
|
||||
rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_items_annos "
|
||||
"WHERE expiration = ?1 AND "
|
||||
"(?2 > MAX(COALESCE(lastModified, 0), dateAdded))"),
|
||||
@ -879,7 +768,7 @@ nsNavHistoryExpire::ExpireAnnotations(mozIStorageConnection* aConnection)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// remove EXPIRE_WITH_HISTORY annos for pages without visits
|
||||
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_annos WHERE expiration = ") +
|
||||
nsPrintfCString("%d", nsIAnnotationService::EXPIRE_WITH_HISTORY) +
|
||||
NS_LITERAL_CSTRING(" AND NOT EXISTS "
|
||||
@ -896,17 +785,8 @@ nsNavHistoryExpire::ExpireAnnotations(mozIStorageConnection* aConnection)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsNavHistoryExpire::ExpireHistoryParanoid
|
||||
//
|
||||
// Deletes any dangling history entries that aren't associated with any
|
||||
// visits, bookmarks or "place:" URIs.
|
||||
//
|
||||
// The aMaxRecords parameter is an optional cap on the number of
|
||||
// records to delete. If its value is -1, all records will be deleted.
|
||||
|
||||
nsresult
|
||||
nsNavHistoryExpire::ExpireHistoryParanoid(mozIStorageConnection* aConnection,
|
||||
PRInt32 aMaxRecords)
|
||||
nsNavHistoryExpire::ExpireHistoryParanoid(PRInt32 aMaxRecords)
|
||||
{
|
||||
nsCAutoString query(
|
||||
"DELETE FROM moz_places_view WHERE id IN ("
|
||||
@ -932,20 +812,16 @@ nsNavHistoryExpire::ExpireHistoryParanoid(mozIStorageConnection* aConnection,
|
||||
query.AppendInt(aMaxRecords);
|
||||
}
|
||||
query.AppendLiteral(")");
|
||||
nsresult rv = aConnection->ExecuteSimpleSQL(query);
|
||||
nsresult rv = mDBConn->ExecuteSimpleSQL(query);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::ExpireFaviconsParanoid
|
||||
//
|
||||
// Deletes any dangling favicons that aren't associated with any pages.
|
||||
|
||||
nsresult
|
||||
nsNavHistoryExpire::ExpireFaviconsParanoid(mozIStorageConnection* aConnection)
|
||||
nsNavHistoryExpire::ExpireFaviconsParanoid()
|
||||
{
|
||||
nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
nsresult rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_favicons WHERE id IN ("
|
||||
"SELECT f.id FROM moz_favicons f "
|
||||
"LEFT JOIN moz_places h ON f.id = h.favicon_id "
|
||||
@ -957,25 +833,19 @@ nsNavHistoryExpire::ExpireFaviconsParanoid(mozIStorageConnection* aConnection)
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::ExpireAnnotationsParanoid
|
||||
//
|
||||
// Deletes session annotations, dangling annotations
|
||||
// and annotation names that are unused.
|
||||
|
||||
nsresult
|
||||
nsNavHistoryExpire::ExpireAnnotationsParanoid(mozIStorageConnection* aConnection)
|
||||
nsNavHistoryExpire::ExpireAnnotationsParanoid()
|
||||
{
|
||||
// delete session annos
|
||||
nsCAutoString session_query = NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_annos WHERE expiration = ") +
|
||||
nsPrintfCString("%d", nsIAnnotationService::EXPIRE_SESSION);
|
||||
nsresult rv = aConnection->ExecuteSimpleSQL(session_query);
|
||||
nsresult rv = mDBConn->ExecuteSimpleSQL(session_query);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// delete all uri annos w/o a corresponding place id
|
||||
// or without any visits *and* not EXPIRE_NEVER.
|
||||
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_annos WHERE id IN ("
|
||||
"SELECT a.id FROM moz_annos a "
|
||||
"LEFT JOIN moz_places h ON a.place_id = h.id "
|
||||
@ -990,7 +860,7 @@ nsNavHistoryExpire::ExpireAnnotationsParanoid(mozIStorageConnection* aConnection
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// delete item annos w/o a corresponding item id
|
||||
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_items_annos WHERE id IN "
|
||||
"(SELECT a.id FROM moz_items_annos a "
|
||||
"LEFT OUTER JOIN moz_bookmarks b ON a.item_id = b.id "
|
||||
@ -998,7 +868,7 @@ nsNavHistoryExpire::ExpireAnnotationsParanoid(mozIStorageConnection* aConnection
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// delete all anno names w/o a corresponding anno
|
||||
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_anno_attributes WHERE id IN ("
|
||||
"SELECT n.id FROM moz_anno_attributes n "
|
||||
"LEFT JOIN moz_annos a ON n.id = a.anno_attribute_id "
|
||||
@ -1010,16 +880,11 @@ nsNavHistoryExpire::ExpireAnnotationsParanoid(mozIStorageConnection* aConnection
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::ExpireInputHistoryParanoid
|
||||
//
|
||||
// Deletes dangling input history
|
||||
|
||||
nsresult
|
||||
nsNavHistoryExpire::ExpireInputHistoryParanoid(mozIStorageConnection* aConnection)
|
||||
nsNavHistoryExpire::ExpireInputHistoryParanoid()
|
||||
{
|
||||
// Delete dangling input history that have no associated pages
|
||||
nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
nsresult rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_inputhistory WHERE place_id IN ( "
|
||||
"SELECT place_id FROM moz_inputhistory "
|
||||
"LEFT JOIN moz_places h ON h.id = place_id "
|
||||
@ -1032,46 +897,13 @@ nsNavHistoryExpire::ExpireInputHistoryParanoid(mozIStorageConnection* aConnectio
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::ExpireForDegenerateRuns
|
||||
//
|
||||
// This checks for potential degenerate runs. For example, a tinderbox
|
||||
// loads many web pages quickly and we'll never have a chance to expire.
|
||||
// Particularly crazy users might also do this. If we detect this, then we
|
||||
// want to force some expiration so history doesn't keep increasing.
|
||||
//
|
||||
// Returns true if we did anything.
|
||||
|
||||
PRBool
|
||||
nsNavHistoryExpire::ExpireForDegenerateRuns()
|
||||
{
|
||||
// If there were any times that we didn't have anything to expire, this is
|
||||
// not a degenerate run.
|
||||
if (mAnyEmptyRuns)
|
||||
return PR_FALSE;
|
||||
|
||||
// Expire a larger chunk of runs to catch up.
|
||||
PRBool keepGoing;
|
||||
nsresult rv = ExpireItems(EXPIRATION_COUNT_PER_RUN_LARGE, &keepGoing);
|
||||
if (NS_FAILED(rv))
|
||||
NS_WARNING("ExpireItems failed.");
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::ComputeNextExpirationTime
|
||||
//
|
||||
// This computes mNextExpirationTime. See that var in the header file.
|
||||
// It is passed the number of microseconds that things expire in.
|
||||
|
||||
void
|
||||
nsNavHistoryExpire::ComputeNextExpirationTime(
|
||||
mozIStorageConnection* aConnection)
|
||||
nsNavHistoryExpire::ComputeNextExpirationTime()
|
||||
{
|
||||
mNextExpirationTime = 0;
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> statement;
|
||||
nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
|
||||
nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT MIN(visit_date) FROM moz_historyvisits"),
|
||||
getter_AddRefs(statement));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Could not create statement");
|
||||
@ -1087,36 +919,30 @@ nsNavHistoryExpire::ComputeNextExpirationTime(
|
||||
mNextExpirationTime = minTime + GetExpirationTimeAgo(mHistory->mExpireDaysMax);
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::StartTimer
|
||||
|
||||
nsresult
|
||||
nsNavHistoryExpire::StartTimer(PRUint32 aMilleseconds)
|
||||
void
|
||||
nsNavHistoryExpire::StartPartialExpirationTimer(PRUint32 aMilleseconds)
|
||||
{
|
||||
if (!mTimer)
|
||||
mTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
NS_ENSURE_STATE(mTimer); // returns on error
|
||||
nsresult rv = mTimer->InitWithFuncCallback(TimerCallback, this,
|
||||
aMilleseconds,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
if (mPartialExpirationTimer) {
|
||||
mPartialExpirationTimer->Cancel();
|
||||
mPartialExpirationTimer = 0;
|
||||
}
|
||||
|
||||
mPartialExpirationTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
if(mPartialExpirationTimer) {
|
||||
(void)mPartialExpirationTimer->InitWithFuncCallback(
|
||||
PartialExpirationTimerCallback, this, aMilleseconds,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::TimerCallback
|
||||
|
||||
void // static
|
||||
nsNavHistoryExpire::TimerCallback(nsITimer* aTimer, void* aClosure)
|
||||
nsNavHistoryExpire::PartialExpirationTimerCallback(nsITimer* aTimer, void* aClosure)
|
||||
{
|
||||
nsNavHistoryExpire* that = static_cast<nsNavHistoryExpire*>(aClosure);
|
||||
that->mTimerSet = PR_FALSE;
|
||||
that->DoPartialExpiration();
|
||||
nsNavHistoryExpire* expire = static_cast<nsNavHistoryExpire*>(aClosure);
|
||||
expire->mPartialExpirationTimer = 0;
|
||||
expire->DoPartialExpiration();
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryExpire::GetExpirationTimeAgo
|
||||
|
||||
PRTime
|
||||
nsNavHistoryExpire::GetExpirationTimeAgo(PRInt32 aExpireDays)
|
||||
{
|
||||
|
@ -21,6 +21,8 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brett Wilson <brettw@gmail.com> (original author)
|
||||
* Dietrich Ayala <dietrich@mozilla.com>
|
||||
* Marco Bonardo <mak77@bonardo.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -49,67 +51,156 @@ struct nsNavHistoryExpireRecord;
|
||||
class nsNavHistoryExpire
|
||||
{
|
||||
public:
|
||||
nsNavHistoryExpire(nsNavHistory* aHistory);
|
||||
nsNavHistoryExpire();
|
||||
~nsNavHistoryExpire();
|
||||
|
||||
void OnAddURI(PRTime aNow);
|
||||
void OnDeleteURI();
|
||||
void OnQuit();
|
||||
nsresult ClearHistory();
|
||||
void OnExpirationChanged();
|
||||
nsresult ExpireItems(PRUint32 aNumToExpire, PRBool* aKeepGoing);
|
||||
/**
|
||||
* Called by history when visits are deleted from history.
|
||||
* This kicks off an expiration of page annotations.
|
||||
*/
|
||||
void OnDeleteVisits();
|
||||
|
||||
nsresult ExpireOrphans(PRUint32 aNumToExpire);
|
||||
/**
|
||||
* Manages shutdown work and final expiration of orphans.
|
||||
*/
|
||||
void OnQuit();
|
||||
|
||||
/**
|
||||
* Called when the expiration length in days has changed. We clear any
|
||||
* next expiration time, meaning that we'll try to expire stuff next time,
|
||||
* and recompute the value if there's still nothing to expire.
|
||||
*/
|
||||
void OnExpirationChanged();
|
||||
|
||||
/**
|
||||
* Performance: ExpireItems sends notifications. We may want to disable this
|
||||
* for clear history cases. However, my initial tests show that the
|
||||
* notifications are not a significant part of clear history time.
|
||||
*/
|
||||
nsresult ClearHistory();
|
||||
|
||||
/**
|
||||
|
||||
* Tries to expire aNumToExpire pages and their associated data.
|
||||
*
|
||||
* @param aNumToExpire
|
||||
* Number of history pages to expire, pass 0 to expire every page
|
||||
* in history.
|
||||
* @return true if we did not expire enough items and we should keep expiring.
|
||||
* false otherwise.
|
||||
*/
|
||||
bool ExpireItems(PRUint32 aNumToExpire);
|
||||
|
||||
/**
|
||||
* Tries to expire aNumToExpire items that are orphans.
|
||||
*
|
||||
* @param aNumToExpire
|
||||
* Limits how many orphan moz_places we worry about.
|
||||
* Everything else (favicons, annotations, and input history) is
|
||||
* completely expired.
|
||||
*/
|
||||
void ExpireOrphans(PRUint32 aNumToExpire);
|
||||
|
||||
protected:
|
||||
nsNavHistory *mHistory;
|
||||
mozIStorageConnection *mDBConn;
|
||||
|
||||
nsNavHistory* mHistory;
|
||||
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
PRBool mTimerSet;
|
||||
|
||||
// Set when we try to expire something and find there is nothing to expire.
|
||||
// This short-curcuits the shutdown logic by indicating that there probably
|
||||
// isn't anything important we need to expire.
|
||||
PRBool mAnyEmptyRuns;
|
||||
nsCOMPtr<nsITimer> mPartialExpirationTimer;
|
||||
void StartPartialExpirationTimer(PRUint32 aMilleseconds);
|
||||
static void PartialExpirationTimerCallback(nsITimer *aTimer, void *aClosure);
|
||||
|
||||
// When we have found nothing to expire, we compute the time the next item
|
||||
// will expire. This is that time so we won't try to expire anything until
|
||||
// then. It is 0 when we don't need to wait to expire stuff.
|
||||
PRTime mNextExpirationTime;
|
||||
void ComputeNextExpirationTime(mozIStorageConnection* aConnection);
|
||||
|
||||
// global statistics
|
||||
PRUint32 mAddCount;
|
||||
PRUint32 mExpiredItems;
|
||||
/**
|
||||
* This computes mNextExpirationTime. See that var in the header file.
|
||||
* It is passed the number of microseconds that things expire in.
|
||||
*/
|
||||
void ComputeNextExpirationTime();
|
||||
|
||||
nsresult DoPartialExpiration();
|
||||
|
||||
nsresult ExpireAnnotations(mozIStorageConnection* aConnection);
|
||||
/**
|
||||
* Creates the idle timer. We expire visits and orphans on idle.
|
||||
*/
|
||||
void InitializeIdleTimer(PRUint32 aTimeInMs);
|
||||
nsCOMPtr<nsITimer> mIdleTimer;
|
||||
static void IdleTimerCallback(nsITimer *aTimer, void *aClosure);
|
||||
|
||||
// parts of ExpireItems
|
||||
nsresult FindVisits(PRTime aExpireThreshold, PRUint32 aNumToExpire,
|
||||
mozIStorageConnection* aConnection,
|
||||
nsTArray<nsNavHistoryExpireRecord>& aRecords);
|
||||
nsresult EraseVisits(mozIStorageConnection* aConnection,
|
||||
const nsTArray<nsNavHistoryExpireRecord>& aRecords);
|
||||
nsresult EraseHistory(mozIStorageConnection* aConnection,
|
||||
nsTArray<nsNavHistoryExpireRecord>& aRecords);
|
||||
nsresult EraseFavicons(mozIStorageConnection* aConnection,
|
||||
const nsTArray<nsNavHistoryExpireRecord>& aRecords);
|
||||
nsresult EraseAnnotations(mozIStorageConnection* aConnection,
|
||||
const nsTArray<nsNavHistoryExpireRecord>& aRecords);
|
||||
|
||||
// paranoid checks
|
||||
nsresult ExpireHistoryParanoid(mozIStorageConnection* aConnection, PRInt32 aMaxRecords);
|
||||
nsresult ExpireFaviconsParanoid(mozIStorageConnection* aConnection);
|
||||
nsresult ExpireAnnotationsParanoid(mozIStorageConnection* aConnection);
|
||||
nsresult ExpireInputHistoryParanoid(mozIStorageConnection* aConnection);
|
||||
|
||||
PRBool ExpireForDegenerateRuns();
|
||||
|
||||
nsresult StartTimer(PRUint32 aMilleseconds);
|
||||
static void TimerCallback(nsITimer* aTimer, void* aClosure);
|
||||
/**
|
||||
* We usually expire periodically, but that could not be fast enough, so on idle
|
||||
* we want to expire a bigget chunk of items to help partial expiration.
|
||||
* This way we try to hit when the user is not going to suffer from UI hangs.
|
||||
*/
|
||||
void OnIdle();
|
||||
|
||||
PRTime GetExpirationTimeAgo(PRInt32 aExpireDays);
|
||||
|
||||
nsresult ExpireAnnotations();
|
||||
|
||||
/**
|
||||
* Find visits to expire, meeting the following criteria:
|
||||
*
|
||||
* - With a visit date older than browser.history_expire_days ago.
|
||||
* - With a visit date older than browser.history_expire_days_min ago
|
||||
* if we have more than browser.history_expire_sites unique urls.
|
||||
*
|
||||
* aExpireThreshold is the time at which we will delete visits before.
|
||||
* If it is zero, we will match everything.
|
||||
*
|
||||
* aNumToExpire is the maximum number of visits to find. If it is 0, then
|
||||
* we will get all matching visits.
|
||||
*/
|
||||
nsresult FindVisits(PRTime aExpireThreshold, PRUint32 aNumToExpire,
|
||||
nsTArray<nsNavHistoryExpireRecord> &aRecords);
|
||||
|
||||
nsresult EraseVisits(const nsTArray<nsNavHistoryExpireRecord> &aRecords);
|
||||
|
||||
/**
|
||||
* This erases records in moz_places when there are no more visits.
|
||||
* We need to be careful not to delete: bookmarks, items that still have
|
||||
* visits and place: URIs.
|
||||
*
|
||||
* This will modify the input by setting the erased flag on each of the
|
||||
* array elements according to whether the history item was erased or not.
|
||||
*/
|
||||
nsresult EraseHistory(nsTArray<nsNavHistoryExpireRecord> &aRecords);
|
||||
|
||||
nsresult EraseFavicons(const nsTArray<nsNavHistoryExpireRecord> &aRecords);
|
||||
|
||||
/**
|
||||
* Periodic expiration of annotations that have time-sensitive
|
||||
* expiration policies.
|
||||
*
|
||||
* @note Always specify the exact policy constant, as they're
|
||||
* not guaranteed to be in numerical order.
|
||||
*/
|
||||
nsresult EraseAnnotations(const nsTArray<nsNavHistoryExpireRecord> &aRecords);
|
||||
|
||||
/**
|
||||
* Deletes any dangling history entries that aren't associated with any
|
||||
* visits, bookmarks or "place:" URIs.
|
||||
*
|
||||
* The aMaxRecords parameter is an optional cap on the number of
|
||||
* records to delete. If its value is -1, all records will be deleted.
|
||||
*/
|
||||
nsresult ExpireHistoryParanoid(PRInt32 aMaxRecords);
|
||||
|
||||
/**
|
||||
* Deletes any dangling favicons that aren't associated with any pages.
|
||||
*/
|
||||
nsresult ExpireFaviconsParanoid();
|
||||
|
||||
/**
|
||||
* Deletes session annotations, dangling annotations
|
||||
* and annotation names that are unused.
|
||||
*/
|
||||
nsresult ExpireAnnotationsParanoid();
|
||||
|
||||
/**
|
||||
* Deletes dangling input history
|
||||
*/
|
||||
nsresult ExpireInputHistoryParanoid();
|
||||
};
|
||||
|
@ -67,6 +67,8 @@ const kQuerySyncPlacesId = 0;
|
||||
const kQuerySyncHistoryVisitsId = 1;
|
||||
const kQuerySelectExpireVisitsId = 2;
|
||||
const kQueryExpireVisitsId = 3;
|
||||
const kQuerySelectExpireHistoryOrphansId = 4;
|
||||
const kQueryExpireHistoryOrphansId = 5;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// nsPlacesDBFlush class
|
||||
@ -267,6 +269,8 @@ nsPlacesDBFlush.prototype = {
|
||||
let queries = [
|
||||
kQuerySelectExpireVisitsId,
|
||||
kQueryExpireVisitsId,
|
||||
kQuerySelectExpireHistoryOrphansId,
|
||||
kQueryExpireHistoryOrphansId,
|
||||
kQuerySyncPlacesId,
|
||||
kQuerySyncHistoryVisitsId,
|
||||
];
|
||||
@ -290,7 +294,7 @@ nsPlacesDBFlush.prototype = {
|
||||
this._expiredResults.push({
|
||||
uri: this._ios.newURI(row.getResultByName("url"), null, null),
|
||||
visitDate: row.getResultByName("visit_date"),
|
||||
wholeEntry: (row.getResultByName("visit_count") == 1)
|
||||
wholeEntry: (row.getResultByName("whole_entry") == 1)
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -385,6 +389,10 @@ nsPlacesDBFlush.prototype = {
|
||||
params.visit_date = (Date.now() - (this._expireDays * kMSPerDay)) * 1000;
|
||||
params.max_expire = kMaxExpire;
|
||||
break;
|
||||
case kQuerySelectExpireHistoryOrphansId:
|
||||
case kQueryExpireHistoryOrphansId:
|
||||
params.max_expire = kMaxExpire;
|
||||
break;
|
||||
}
|
||||
|
||||
return stmt;
|
||||
@ -421,7 +429,7 @@ nsPlacesDBFlush.prototype = {
|
||||
// Determine which entries will be flushed out from moz_historyvisits
|
||||
// when kQueryExpireVisitsId runs.
|
||||
this._cachedStatements[aQueryType] = this._db.createStatement(
|
||||
"SELECT h.url, v.visit_date, h.hidden, h.visit_count " +
|
||||
"SELECT h.url, v.visit_date, h.hidden, 0 AS whole_entry " +
|
||||
"FROM moz_places h " +
|
||||
"JOIN moz_historyvisits v ON h.id = v.place_id " +
|
||||
"WHERE v.visit_date < :visit_date " +
|
||||
@ -431,7 +439,7 @@ nsPlacesDBFlush.prototype = {
|
||||
break;
|
||||
|
||||
case kQueryExpireVisitsId:
|
||||
// Flush out entries from moz_historyvisits
|
||||
// Expire entries from moz_historyvisits.
|
||||
this._cachedStatements[aQueryType] = this._db.createStatement(
|
||||
"DELETE FROM moz_historyvisits " +
|
||||
"WHERE id IN ( " +
|
||||
@ -444,6 +452,41 @@ nsPlacesDBFlush.prototype = {
|
||||
);
|
||||
break;
|
||||
|
||||
case kQuerySelectExpireHistoryOrphansId:
|
||||
// Determine which entries will be flushed out from moz_places
|
||||
// when kQueryExpireHistoryOrphansId runs.
|
||||
this._cachedStatements[aQueryType] = this._db.createStatement(
|
||||
"SELECT h.url, h.last_visit_date AS visit_date, h.hidden, " +
|
||||
"1 as whole_entry FROM moz_places h " +
|
||||
"LEFT JOIN moz_historyvisits v ON h.id = v.place_id " +
|
||||
"LEFT JOIN moz_historyvisits_temp v_t ON h.id = v_t.place_id " +
|
||||
"LEFT JOIN moz_bookmarks b ON h.id = b.fk " +
|
||||
"WHERE v.id IS NULL " +
|
||||
"AND v_t.id IS NULL " +
|
||||
"AND b.id IS NULL " +
|
||||
"AND SUBSTR(h.url, 1, 6) <> 'place:' " +
|
||||
"LIMIT :max_expire"
|
||||
);
|
||||
break;
|
||||
|
||||
case kQueryExpireHistoryOrphansId:
|
||||
// Flush out entries from moz_historyvisits.
|
||||
this._cachedStatements[aQueryType] = this._db.createStatement(
|
||||
"DELETE FROM moz_places_view " +
|
||||
"WHERE id IN ( " +
|
||||
"SELECT h.id FROM moz_places h " +
|
||||
"LEFT JOIN moz_historyvisits v ON h.id = v.place_id " +
|
||||
"LEFT JOIN moz_historyvisits_temp v_t ON h.id = v_t.place_id " +
|
||||
"LEFT JOIN moz_bookmarks b ON h.id = b.fk " +
|
||||
"WHERE v.id IS NULL " +
|
||||
"AND v_t.id IS NULL " +
|
||||
"AND b.id IS NULL " +
|
||||
"AND SUBSTR(h.url, 1, 6) <> 'place:' " +
|
||||
"LIMIT :max_expire" +
|
||||
")"
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw "Unexpected statement!";
|
||||
}
|
||||
|
@ -84,6 +84,7 @@ os.addObserver(observer, kSyncFinished, false);
|
||||
// Used to ensure that we did in fact get notified about our expiration.
|
||||
var historyObserver = {
|
||||
visitTime: -1,
|
||||
_runCount: 0,
|
||||
onPageExpired: function(aURI, aVisitTime, aWholeEntry)
|
||||
{
|
||||
do_check_true(aURI.equals(uri(TEST_URI)));
|
||||
@ -92,7 +93,10 @@ var historyObserver = {
|
||||
do_check_eq(this.visitTime, aVisitTime);
|
||||
|
||||
// This was the only visit for this uri, so ensure that aWholeEntry is true.
|
||||
do_check_true(aWholeEntry);
|
||||
if (++this._runCount == 1)
|
||||
do_check_false(aWholeEntry);
|
||||
else
|
||||
do_check_true(aWholeEntry);
|
||||
|
||||
observer.notificationReceived = true;
|
||||
hs.removeObserver(this, false);
|
||||
|
@ -56,6 +56,7 @@ DummyObserver.prototype = {
|
||||
os.notifyObservers(null, "dummy-observer-visited", null);
|
||||
},
|
||||
onTitleChanged: function(aURI, aPageTitle) {},
|
||||
onBeforeDeleteURI: function(aURI) {},
|
||||
onDeleteURI: function(aURI) {},
|
||||
onClearHistory: function() {},
|
||||
onPageChanged: function(aURI, aWhat, aValue) {},
|
||||
|
@ -64,4 +64,3 @@ if (pip.DBConnection.connectionReady) {
|
||||
pip.DBConnection.close();
|
||||
do_check_false(pip.DBConnection.connectionReady);
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,8 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Globals and Constants
|
||||
|
||||
let hs = Cc["@mozilla.org/browser/nav-history-service;1"].
|
||||
getService(Ci.nsINavHistoryService);
|
||||
let ac = Cc["@mozilla.org/autocomplete/search;1?name=history"].
|
||||
getService(Ci.nsIAutoCompleteSearch);
|
||||
|
||||
|
@ -522,11 +522,10 @@ function startExpireNeither() {
|
||||
// set date maximum to 3
|
||||
prefs.setIntPref("browser.history_expire_days", 3);
|
||||
|
||||
// Changing expiration preferences has already triggered expiration, it will
|
||||
// run after the partial expiration timer (3,5s).
|
||||
// Changing expiration preferences triggers partial expiration.
|
||||
|
||||
// Check results.
|
||||
do_timeout(3600, "checkExpireNeither();");
|
||||
do_timeout(600, "checkExpireNeither();");
|
||||
}
|
||||
|
||||
function checkExpireNeither() {
|
||||
@ -584,11 +583,10 @@ function startExpireDaysOnly() {
|
||||
// set date maximum to 3
|
||||
prefs.setIntPref("browser.history_expire_days", 3);
|
||||
|
||||
// Changing expiration preferences has already triggered expiration, it will
|
||||
// run after the partial expiration timer (3,5s).
|
||||
// Changing expiration preferences triggers partial expiration.
|
||||
|
||||
// Check results.
|
||||
do_timeout(3600, "checkExpireDaysOnly();");
|
||||
do_timeout(600, "checkExpireDaysOnly();");
|
||||
}
|
||||
|
||||
function checkExpireDaysOnly() {
|
||||
@ -655,11 +653,10 @@ function startExpireBoth() {
|
||||
// set date minimum to 1
|
||||
prefs.setIntPref("browser.history_expire_days_min", 1);
|
||||
|
||||
// Changing expiration preferences has already triggered expiration, it will
|
||||
// run after the partial expiration timer (3,5s).
|
||||
// Changing expiration preferences triggers partial expiration.
|
||||
|
||||
// Check results.
|
||||
do_timeout(3600, "checkExpireBoth();"); // incremental expiration timer is 3500
|
||||
do_timeout(600, "checkExpireBoth();"); // incremental expiration timer is 3500
|
||||
}
|
||||
|
||||
function checkExpireBoth() {
|
||||
@ -714,11 +711,10 @@ function startExpireNeitherOver() {
|
||||
// set date maximum to 3
|
||||
prefs.setIntPref("browser.history_expire_days", 3);
|
||||
|
||||
// Changing expiration preferences has already triggered expiration, it will
|
||||
// run after the partial expiration timer (3,5s).
|
||||
// Changing expiration preferences triggers partial expiration.
|
||||
|
||||
// Check results.
|
||||
do_timeout(3600, "checkExpireNeitherOver();");
|
||||
do_timeout(600, "checkExpireNeitherOver();");
|
||||
}
|
||||
|
||||
function checkExpireNeitherOver() {
|
||||
@ -764,11 +760,10 @@ function startExpireHistoryDisabled() {
|
||||
// set date maximum to 0
|
||||
prefs.setIntPref("browser.history_expire_days", 0);
|
||||
|
||||
// Changing expiration preferences has already triggered expiration, it will
|
||||
// run after the partial expiration timer (3,5s).
|
||||
// Changing expiration preferences triggers partial expiration.
|
||||
|
||||
// Check results.
|
||||
do_timeout(3600, "checkExpireHistoryDisabled();");
|
||||
do_timeout(600, "checkExpireHistoryDisabled();");
|
||||
}
|
||||
|
||||
function checkExpireHistoryDisabled() {
|
||||
@ -817,11 +812,10 @@ function startExpireBadPrefs() {
|
||||
// set date maximum to 1
|
||||
prefs.setIntPref("browser.history_expire_days", 1);
|
||||
|
||||
// Changing expiration preferences has already triggered expiration, it will
|
||||
// run after the partial expiration timer (3,5s).
|
||||
// Changing expiration preferences triggers partial expiration.
|
||||
|
||||
// Check results.
|
||||
do_timeout(3600, "checkExpireBadPrefs();");
|
||||
do_timeout(600, "checkExpireBadPrefs();");
|
||||
}
|
||||
|
||||
function checkExpireBadPrefs() {
|
||||
|
Loading…
Reference in New Issue
Block a user