mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 512854 - VACUUM places.sqlite database on daily idle once a month, r=sdwilsh
This commit is contained in:
parent
565378112a
commit
0e915d6038
@ -144,8 +144,7 @@ using namespace mozilla::places;
|
||||
#define PREF_FRECENCY_DEFAULT_VISIT_BONUS "places.frecency.defaultVisitBonus"
|
||||
#define PREF_FRECENCY_UNVISITED_BOOKMARK_BONUS "places.frecency.unvisitedBookmarkBonus"
|
||||
#define PREF_FRECENCY_UNVISITED_TYPED_BONUS "places.frecency.unvisitedTypedBonus"
|
||||
|
||||
#define PLACES_AUTOCOMPLETE_FEEDBACK_UPDATED_TOPIC "places-autocomplete-feedback-updated"
|
||||
#define PREF_LAST_VACUUM "places.last_vacuum"
|
||||
|
||||
// Default (integer) value of PREF_DB_CACHE_PERCENTAGE from 0-100
|
||||
// This is 6% of machine memory, giving 15MB for a user with 256MB of memory.
|
||||
@ -212,6 +211,16 @@ using namespace mozilla::places;
|
||||
#define DATE_CONT_NUM(_expireDays) \
|
||||
(ADDITIONAL_DATE_CONT_NUM + PR_MIN(6, (_expireDays/30)))
|
||||
|
||||
// fraction of free pages in the database to force a vacuum between
|
||||
// MAX_TIME_BEFORE_VACUUM and MIN_TIME_BEFORE_VACUUM.
|
||||
#define VACUUM_FREEPAGES_THRESHOLD 0.1
|
||||
// This is the maximum time (in microseconds) that can pass between 2 VACUUM
|
||||
// operations.
|
||||
#define MAX_TIME_BEFORE_VACUUM (PRInt64)60 * 24 * 60 * 60 * 1000 * 1000
|
||||
// This is the minimum time (in microseconds) that should pass between 2 VACUUM
|
||||
// operations.
|
||||
#define MIN_TIME_BEFORE_VACUUM (PRInt64)30 * 24 * 60 * 60 * 1000 * 1000
|
||||
|
||||
NS_IMPL_THREADSAFE_ADDREF(nsNavHistory)
|
||||
NS_IMPL_THREADSAFE_RELEASE(nsNavHistory)
|
||||
|
||||
@ -468,7 +477,7 @@ nsNavHistory::Init()
|
||||
// Enqueue the notification, so if we init another service that requires
|
||||
// nsNavHistoryService we don't recursive try to get it.
|
||||
nsRefPtr<PlacesEvent> completeEvent =
|
||||
new PlacesEvent(PLACES_INIT_COMPLETE_EVENT_TOPIC);
|
||||
new PlacesEvent(PLACES_INIT_COMPLETE_TOPIC);
|
||||
rv = NS_DispatchToMainThread(completeEvent);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@ -528,7 +537,7 @@ nsNavHistory::Init()
|
||||
// of the places infrastructure has been initialized.
|
||||
if (mDatabaseStatus == DATABASE_STATUS_CREATE ||
|
||||
mDatabaseStatus == DATABASE_STATUS_UPGRADED) {
|
||||
(void)observerService->AddObserver(this, PLACES_INIT_COMPLETE_EVENT_TOPIC,
|
||||
(void)observerService->AddObserver(this, PLACES_INIT_COMPLETE_TOPIC,
|
||||
PR_FALSE);
|
||||
}
|
||||
|
||||
@ -606,7 +615,7 @@ nsNavHistory::InitDBFile(PRBool aForceInit)
|
||||
// We can't do much at this point, so fire a locked event so that user is
|
||||
// notified that we can't ensure Places to work.
|
||||
nsRefPtr<PlacesEvent> lockedEvent =
|
||||
new PlacesEvent(PLACES_DB_LOCKED_EVENT_TOPIC);
|
||||
new PlacesEvent(PLACES_DB_LOCKED_TOPIC);
|
||||
(void)NS_DispatchToMainThread(lockedEvent);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -656,7 +665,7 @@ nsNavHistory::InitDBFile(PRBool aForceInit)
|
||||
// send out a notification and do not continue initialization.
|
||||
// Note: We swallow errors here, since we want service init to fail anyway.
|
||||
nsRefPtr<PlacesEvent> lockedEvent =
|
||||
new PlacesEvent(PLACES_DB_LOCKED_EVENT_TOPIC);
|
||||
new PlacesEvent(PLACES_DB_LOCKED_TOPIC);
|
||||
(void)NS_DispatchToMainThread(lockedEvent);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -5528,7 +5537,7 @@ nsNavHistory::CommitPendingChanges()
|
||||
do_GetService("@mozilla.org/observer-service;1");
|
||||
NS_ENSURE_TRUE(os, NS_ERROR_FAILURE);
|
||||
nsCOMPtr<nsISimpleEnumerator> e;
|
||||
nsresult rv = os->EnumerateObservers(PLACES_INIT_COMPLETE_EVENT_TOPIC,
|
||||
nsresult rv = os->EnumerateObservers(PLACES_INIT_COMPLETE_TOPIC,
|
||||
getter_AddRefs(e));
|
||||
if (NS_SUCCEEDED(rv) && e) {
|
||||
nsCOMPtr<nsIObserver> observer;
|
||||
@ -5537,7 +5546,7 @@ nsNavHistory::CommitPendingChanges()
|
||||
{
|
||||
e->GetNext(getter_AddRefs(observer));
|
||||
rv = observer->Observe(observer,
|
||||
PLACES_INIT_COMPLETE_EVENT_TOPIC,
|
||||
PLACES_INIT_COMPLETE_TOPIC,
|
||||
nsnull);
|
||||
}
|
||||
}
|
||||
@ -5642,58 +5651,22 @@ nsNavHistory::Observe(nsISupports *aSubject, const char *aTopic,
|
||||
// to errors or during normal shutdown process.
|
||||
NS_ENSURE_TRUE(mDBConn, NS_OK);
|
||||
|
||||
// Update frecency values
|
||||
(void)FixInvalidFrecencies();
|
||||
|
||||
// Globally decay places frecency rankings to estimate reduced frecency
|
||||
// values of pages that haven't been visited for a while, i.e., they do
|
||||
// not get an updated frecency. We directly modify moz_places to avoid
|
||||
// bringing the whole database into places_temp through places_view. A
|
||||
// scaling factor of .975 results in .5 the original value after 28 days.
|
||||
nsCOMPtr<mozIStorageStatement> decayFrecency;
|
||||
nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"UPDATE moz_places SET frecency = ROUND(frecency * .975) "
|
||||
"WHERE frecency > 0"),
|
||||
getter_AddRefs(decayFrecency));
|
||||
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||
|
||||
// Decay potentially unused adaptive entries (e.g. those that are at 1)
|
||||
// to allow better chances for new entries that will start at 1
|
||||
nsCOMPtr<mozIStorageStatement> decayAdaptive;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"UPDATE moz_inputhistory SET use_count = use_count * .975"),
|
||||
getter_AddRefs(decayAdaptive));
|
||||
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||
|
||||
// Delete any adaptive entries that won't help in ordering anymore
|
||||
nsCOMPtr<mozIStorageStatement> deleteAdaptive;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_inputhistory WHERE use_count < .01"),
|
||||
getter_AddRefs(deleteAdaptive));
|
||||
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||
|
||||
nsCOMPtr<mozIStoragePendingStatement> ps;
|
||||
mozIStorageStatement *stmts[] = {
|
||||
decayFrecency,
|
||||
decayAdaptive,
|
||||
deleteAdaptive
|
||||
};
|
||||
rv = mDBConn->ExecuteAsync(stmts, NS_ARRAY_LENGTH(stmts), nsnull,
|
||||
getter_AddRefs(ps));
|
||||
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||
(void)DecayFrecency();
|
||||
(void)VacuumDatabase();
|
||||
}
|
||||
else if (strcmp(aTopic, NS_PRIVATE_BROWSING_SWITCH_TOPIC) == 0) {
|
||||
if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).Equals(aData)) {
|
||||
mInPrivateBrowsing = PR_TRUE;
|
||||
} else if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).Equals(aData)) {
|
||||
}
|
||||
else if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).Equals(aData)) {
|
||||
mInPrivateBrowsing = PR_FALSE;
|
||||
}
|
||||
}
|
||||
else if (strcmp(aTopic, PLACES_INIT_COMPLETE_EVENT_TOPIC) == 0) {
|
||||
else if (strcmp(aTopic, PLACES_INIT_COMPLETE_TOPIC) == 0) {
|
||||
nsCOMPtr<nsIObserverService> os =
|
||||
do_GetService("@mozilla.org/observer-service;1");
|
||||
NS_ENSURE_TRUE(os, NS_ERROR_FAILURE);
|
||||
(void)os->RemoveObserver(this, PLACES_INIT_COMPLETE_EVENT_TOPIC);
|
||||
(void)os->RemoveObserver(this, PLACES_INIT_COMPLETE_TOPIC);
|
||||
|
||||
// This code is only called if we've either imported or done a migration
|
||||
// from a pre-frecency build, so we will calculate all their frecencies.
|
||||
@ -5703,6 +5676,161 @@ nsNavHistory::Observe(nsISupports *aSubject, const char *aTopic,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_HIDDEN_(nsresult)
|
||||
nsNavHistory::VacuumDatabase()
|
||||
{
|
||||
// SQLite cannot give us a real value for fragmentation percentage,
|
||||
// we could analyze the database file page by page, and count fragmented
|
||||
// space, but that would be slow and not maintainable across different SQLite
|
||||
// versions.
|
||||
// For this reason we just take a guess using the freelist count.
|
||||
// This way we know how much pages are unused, but we don't know anything
|
||||
// about fragmentation.
|
||||
// This ratio is used in conjunction with a time pref to avoid vacuuming too
|
||||
// often or too rarely.
|
||||
|
||||
PRInt32 lastVacuumPref;
|
||||
PRInt64 lastVacuumTime = 0;
|
||||
nsCOMPtr<nsIPrefBranch> prefSvc =
|
||||
do_GetService("@mozilla.org/preferences-service;1");
|
||||
NS_ENSURE_TRUE(prefSvc, NS_ERROR_OUT_OF_MEMORY);
|
||||
if (NS_SUCCEEDED(prefSvc->GetIntPref(PREF_LAST_VACUUM, &lastVacuumPref))) {
|
||||
// Value are seconds till epoch, convert it to microseconds.
|
||||
lastVacuumTime = (PRInt64)lastVacuumPref * PR_USEC_PER_SEC;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
float freePagesRatio = 0;
|
||||
if (!lastVacuumTime ||
|
||||
(lastVacuumTime < (PR_Now() - MIN_TIME_BEFORE_VACUUM) &&
|
||||
lastVacuumTime > (PR_Now() - MAX_TIME_BEFORE_VACUUM))) {
|
||||
// This is the first vacuum, or we are in the timeframe where vacuum could
|
||||
// happen. Calculate the vacuum ratio and vacuum if it is less then
|
||||
// threshold.
|
||||
nsCOMPtr<mozIStorageStatement> statement;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("PRAGMA page_count"),
|
||||
getter_AddRefs(statement));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
PRBool hasResult = PR_FALSE;
|
||||
rv = statement->ExecuteStep(&hasResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(hasResult, NS_ERROR_FAILURE);
|
||||
PRInt32 pageCount = statement->AsInt32(0);
|
||||
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("PRAGMA freelist_count"),
|
||||
getter_AddRefs(statement));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
hasResult = PR_FALSE;
|
||||
rv = statement->ExecuteStep(&hasResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(hasResult, NS_ERROR_FAILURE);
|
||||
PRInt32 freelistCount = statement->AsInt32(0);
|
||||
|
||||
freePagesRatio = (float)(freelistCount / pageCount);
|
||||
}
|
||||
|
||||
if (freePagesRatio > VACUUM_FREEPAGES_THRESHOLD ||
|
||||
lastVacuumTime < (PR_Now() - MAX_TIME_BEFORE_VACUUM)) {
|
||||
// We vacuum in 2 cases:
|
||||
// - We are in the valid vacuum timeframe and vacuum ratio is high.
|
||||
// - Last vacuum has been executed a lot of time ago.
|
||||
|
||||
// Notify we are about to vacuum. This is mostly for testability.
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
do_GetService("@mozilla.org/observer-service;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = observerService->NotifyObservers(nsnull,
|
||||
PLACES_VACUUM_STARTING_TOPIC,
|
||||
nsnull);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Actually vacuuming a database is a slow operation, since it could take
|
||||
// seconds. Part of the time is spent in updating the journal file on disk
|
||||
// and this is particularly bad on devices with slow I/O. Temporary
|
||||
// moving the journal to memory could increase a bit the possibility of
|
||||
// corruption if we crash during this time, but makes the process really
|
||||
// faster.
|
||||
nsCOMPtr<mozIStorageStatement> journalToMemory;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"PRAGMA journal_mode = MEMORY"),
|
||||
getter_AddRefs(journalToMemory));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> vacuum;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("VACUUM"),
|
||||
getter_AddRefs(vacuum));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> journalToDefault;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"PRAGMA journal_mode = " DEFAULT_JOURNAL_MODE),
|
||||
getter_AddRefs(journalToDefault));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mozIStorageStatement *stmts[] = {
|
||||
journalToMemory,
|
||||
vacuum,
|
||||
journalToDefault
|
||||
};
|
||||
nsCOMPtr<mozIStoragePendingStatement> ps;
|
||||
rv = mDBConn->ExecuteAsync(stmts, NS_ARRAY_LENGTH(stmts), nsnull,
|
||||
getter_AddRefs(ps));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = prefSvc->SetIntPref(PREF_LAST_VACUUM,
|
||||
(PRInt32)(PR_Now() / PR_USEC_PER_SEC));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_HIDDEN_(nsresult)
|
||||
nsNavHistory::DecayFrecency()
|
||||
{
|
||||
// Update frecency values.
|
||||
nsresult rv = FixInvalidFrecencies();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Globally decay places frecency rankings to estimate reduced frecency
|
||||
// values of pages that haven't been visited for a while, i.e., they do
|
||||
// not get an updated frecency. We directly modify moz_places to avoid
|
||||
// bringing the whole database into places_temp through places_view. A
|
||||
// scaling factor of .975 results in .5 the original value after 28 days.
|
||||
nsCOMPtr<mozIStorageStatement> decayFrecency;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"UPDATE moz_places SET frecency = ROUND(frecency * .975) "
|
||||
"WHERE frecency > 0"),
|
||||
getter_AddRefs(decayFrecency));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Decay potentially unused adaptive entries (e.g. those that are at 1)
|
||||
// to allow better chances for new entries that will start at 1.
|
||||
nsCOMPtr<mozIStorageStatement> decayAdaptive;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"UPDATE moz_inputhistory SET use_count = use_count * .975"),
|
||||
getter_AddRefs(decayAdaptive));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Delete any adaptive entries that won't help in ordering anymore.
|
||||
nsCOMPtr<mozIStorageStatement> deleteAdaptive;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"DELETE FROM moz_inputhistory WHERE use_count < .01"),
|
||||
getter_AddRefs(deleteAdaptive));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mozIStorageStatement *stmts[] = {
|
||||
decayFrecency,
|
||||
decayAdaptive,
|
||||
deleteAdaptive
|
||||
};
|
||||
nsCOMPtr<mozIStoragePendingStatement> ps;
|
||||
rv = mDBConn->ExecuteAsync(stmts, NS_ARRAY_LENGTH(stmts), nsnull,
|
||||
getter_AddRefs(ps));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Lazy stuff ******************************************************************
|
||||
|
||||
|
@ -98,8 +98,10 @@
|
||||
// mInPrivateBrowsing member
|
||||
#define PRIVATEBROWSING_NOTINITED (PRBool(0xffffffff))
|
||||
|
||||
#define PLACES_INIT_COMPLETE_EVENT_TOPIC "places-init-complete"
|
||||
#define PLACES_DB_LOCKED_EVENT_TOPIC "places-database-locked"
|
||||
#define PLACES_INIT_COMPLETE_TOPIC "places-init-complete"
|
||||
#define PLACES_DB_LOCKED_TOPIC "places-database-locked"
|
||||
#define PLACES_AUTOCOMPLETE_FEEDBACK_UPDATED_TOPIC "places-autocomplete-feedback-updated"
|
||||
#define PLACES_VACUUM_STARTING_TOPIC "places-vacuum-starting"
|
||||
|
||||
class mozIAnnotationService;
|
||||
class nsNavHistory;
|
||||
@ -430,6 +432,15 @@ protected:
|
||||
*/
|
||||
nsresult FinalizeStatements();
|
||||
|
||||
/**
|
||||
* Analyzes the database and VACUUM it, if needed.
|
||||
*/
|
||||
NS_HIDDEN_(nsresult) DecayFrecency();
|
||||
/**
|
||||
* Decays frecency and inputhistory values.
|
||||
*/
|
||||
NS_HIDDEN_(nsresult) VacuumDatabase();
|
||||
|
||||
// nsICharsetResolver
|
||||
NS_DECL_NSICHARSETRESOLVER
|
||||
|
||||
|
159
toolkit/components/places/tests/unit/test_vacuum.js
Normal file
159
toolkit/components/places/tests/unit/test_vacuum.js
Normal file
@ -0,0 +1,159 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Places unit test code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Marco Bonardo <mak77@bonardo.net> (Original Author)
|
||||
*
|
||||
* 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
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
let bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
let hs = Cc["@mozilla.org/browser/nav-history-service;1"].
|
||||
getService(Ci.nsINavHistoryService);
|
||||
let bh = hs.QueryInterface(Ci.nsIBrowserHistory);
|
||||
let dbConn = hs.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
|
||||
let os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
let prefs = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefService).
|
||||
getBranch("places.");
|
||||
|
||||
const LAST_VACUUM_PREF = "last_vacuum";
|
||||
const VACUUM_THRESHOLD = 0.1;
|
||||
const PLACES_VACUUM_STARTING_TOPIC = "places-vacuum-starting";
|
||||
|
||||
function getDBVacuumRatio() {
|
||||
let freelistStmt = dbConn.createStatement("PRAGMA freelist_count");
|
||||
freelistStmt.step();
|
||||
let freelistCount = freelistStmt.row.freelist_count;
|
||||
freelistStmt.finalize();
|
||||
let pageCountStmt = dbConn.createStatement("PRAGMA page_count");
|
||||
pageCountStmt.step();
|
||||
let pageCount = pageCountStmt.row.page_count;
|
||||
pageCountStmt.finalize();
|
||||
|
||||
let ratio = (freelistCount / pageCount);
|
||||
return ratio;
|
||||
}
|
||||
|
||||
function generateSparseDB(aType) {
|
||||
let limit = 0;
|
||||
if (aType == "low")
|
||||
limit = 10;
|
||||
else if (aType == "high")
|
||||
limit = 200;
|
||||
|
||||
let batch = {
|
||||
runBatched: function batch_runBatched() {
|
||||
for (let i = 0; i < limit; i++) {
|
||||
hs.addVisit(uri("http://" + i + ".mozilla.com/"),
|
||||
Date.now() * 1000 + i, null, hs.TRANSITION_TYPED, false, 0);
|
||||
}
|
||||
for (let i = 0; i < limit; i++) {
|
||||
bs.insertBookmark(bs.unfiledBookmarksFolder,
|
||||
uri("http://" + i + "." + i + ".mozilla.com/"),
|
||||
bs.DEFAULT_INDEX, "bookmark " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
hs.runInBatchMode(batch, null);
|
||||
bh.removeAllPages();
|
||||
bs.removeFolderChildren(bs.unfiledBookmarksFolder);
|
||||
}
|
||||
|
||||
var gTests = [
|
||||
{
|
||||
desc: "Low ratio, last vacuum today",
|
||||
ratio: "low",
|
||||
elapsedDays: 0,
|
||||
vacuum: false
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Low ratio, last vacuum one month ago",
|
||||
ratio: "low",
|
||||
elapsedDays: 31,
|
||||
vacuum: false
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Low ratio, last vacuum two months ago",
|
||||
ratio: "low",
|
||||
elapsedDays: 61,
|
||||
vacuum: true
|
||||
},
|
||||
|
||||
{
|
||||
desc: "High ratio, last vacuum today",
|
||||
ratio: "high",
|
||||
elapsedDays: 0,
|
||||
vacuum: false
|
||||
},
|
||||
];
|
||||
|
||||
var observer = {
|
||||
vacuum: false,
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (aTopic == PLACES_VACUUM_STARTING_TOPIC) {
|
||||
this.vacuum = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
os.addObserver(observer, PLACES_VACUUM_STARTING_TOPIC, false);
|
||||
|
||||
function run_test() {
|
||||
while (gTests.length) {
|
||||
observer.vacuum = false;
|
||||
let test = gTests.shift();
|
||||
print("PLACES TEST: " + test.desc);
|
||||
let ratio = getDBVacuumRatio();
|
||||
if (test.ratio == "high") {
|
||||
if (ratio < VACUUM_THRESHOLD)
|
||||
generateSparseDB("high");
|
||||
do_check_true(getDBVacuumRatio() > VACUUM_THRESHOLD);
|
||||
}
|
||||
else if (test.ratio == "low") {
|
||||
if (ratio == 0)
|
||||
generateSparseDB("low");
|
||||
do_check_true(getDBVacuumRatio() < VACUUM_THRESHOLD);
|
||||
}
|
||||
print("current ratio is " + getDBVacuumRatio());
|
||||
prefs.setIntPref(LAST_VACUUM_PREF, ((Date.now() / 1000) - (test.elapsedDays * 24 * 60 * 60)));
|
||||
os.notifyObservers(null, "idle-daily", null);
|
||||
let testFunc = test.vacuum ? do_check_true : do_check_false;
|
||||
testFunc(observer.vacuum);
|
||||
}
|
||||
|
||||
os.removeObserver(observer, PLACES_VACUUM_STARTING_TOPIC);
|
||||
}
|
138
toolkit/components/places/tests/unit/test_vacuum_2.js
Normal file
138
toolkit/components/places/tests/unit/test_vacuum_2.js
Normal file
@ -0,0 +1,138 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Places unit test code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Marco Bonardo <mak77@bonardo.net> (Original Author)
|
||||
*
|
||||
* 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
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
let bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
let hs = Cc["@mozilla.org/browser/nav-history-service;1"].
|
||||
getService(Ci.nsINavHistoryService);
|
||||
let bh = hs.QueryInterface(Ci.nsIBrowserHistory);
|
||||
let dbConn = hs.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
|
||||
let os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
let prefs = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefService).
|
||||
getBranch("places.");
|
||||
|
||||
const LAST_VACUUM_PREF = "last_vacuum";
|
||||
const VACUUM_THRESHOLD = 0.1;
|
||||
const PLACES_VACUUM_STARTING_TOPIC = "places-vacuum-starting";
|
||||
|
||||
function getDBVacuumRatio() {
|
||||
let freelistStmt = dbConn.createStatement("PRAGMA freelist_count");
|
||||
freelistStmt.step();
|
||||
let freelistCount = freelistStmt.row.freelist_count;
|
||||
freelistStmt.finalize();
|
||||
let pageCountStmt = dbConn.createStatement("PRAGMA page_count");
|
||||
pageCountStmt.step();
|
||||
let pageCount = pageCountStmt.row.page_count;
|
||||
pageCountStmt.finalize();
|
||||
|
||||
let ratio = (freelistCount / pageCount);
|
||||
return ratio;
|
||||
}
|
||||
|
||||
function generateSparseDB(aType) {
|
||||
let limit = 0;
|
||||
if (aType == "low")
|
||||
limit = 10;
|
||||
else if (aType == "high")
|
||||
limit = 200;
|
||||
|
||||
let batch = {
|
||||
runBatched: function batch_runBatched() {
|
||||
for (let i = 0; i < limit; i++) {
|
||||
hs.addVisit(uri("http://" + i + ".mozilla.com/"),
|
||||
Date.now() * 1000 + i, null, hs.TRANSITION_TYPED, false, 0);
|
||||
}
|
||||
for (let i = 0; i < limit; i++) {
|
||||
bs.insertBookmark(bs.unfiledBookmarksFolder,
|
||||
uri("http://" + i + "." + i + ".mozilla.com/"),
|
||||
bs.DEFAULT_INDEX, "bookmark " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
hs.runInBatchMode(batch, null);
|
||||
bh.removeAllPages();
|
||||
bs.removeFolderChildren(bs.unfiledBookmarksFolder);
|
||||
}
|
||||
|
||||
var gTests = [
|
||||
{
|
||||
desc: "High ratio, last vacuum two months ago",
|
||||
ratio: "high",
|
||||
elapsedDays: 61,
|
||||
vacuum: true
|
||||
},
|
||||
];
|
||||
|
||||
var observer = {
|
||||
vacuum: false,
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (aTopic == PLACES_VACUUM_STARTING_TOPIC) {
|
||||
this.vacuum = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
os.addObserver(observer, PLACES_VACUUM_STARTING_TOPIC, false);
|
||||
|
||||
function run_test() {
|
||||
while (gTests.length) {
|
||||
observer.vacuum = false;
|
||||
let test = gTests.shift();
|
||||
print("PLACES TEST: " + test.desc);
|
||||
let ratio = getDBVacuumRatio();
|
||||
if (test.ratio == "high") {
|
||||
if (ratio < VACUUM_THRESHOLD)
|
||||
generateSparseDB("high");
|
||||
do_check_true(getDBVacuumRatio() > VACUUM_THRESHOLD);
|
||||
}
|
||||
else if (test.ratio == "low") {
|
||||
if (ratio == 0)
|
||||
generateSparseDB("low");
|
||||
do_check_true(getDBVacuumRatio() < VACUUM_THRESHOLD);
|
||||
}
|
||||
print("current ratio is " + getDBVacuumRatio());
|
||||
prefs.setIntPref(LAST_VACUUM_PREF, ((Date.now() / 1000) - (test.elapsedDays * 24 * 60 * 60)));
|
||||
os.notifyObservers(null, "idle-daily", null);
|
||||
let testFunc = test.vacuum ? do_check_true : do_check_false;
|
||||
testFunc(observer.vacuum);
|
||||
}
|
||||
|
||||
os.removeObserver(observer, PLACES_VACUUM_STARTING_TOPIC);
|
||||
}
|
138
toolkit/components/places/tests/unit/test_vacuum_3.js
Normal file
138
toolkit/components/places/tests/unit/test_vacuum_3.js
Normal file
@ -0,0 +1,138 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Places unit test code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Marco Bonardo <mak77@bonardo.net> (Original Author)
|
||||
*
|
||||
* 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
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
let bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
let hs = Cc["@mozilla.org/browser/nav-history-service;1"].
|
||||
getService(Ci.nsINavHistoryService);
|
||||
let bh = hs.QueryInterface(Ci.nsIBrowserHistory);
|
||||
let dbConn = hs.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
|
||||
let os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
let prefs = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefService).
|
||||
getBranch("places.");
|
||||
|
||||
const LAST_VACUUM_PREF = "last_vacuum";
|
||||
const VACUUM_THRESHOLD = 0.1;
|
||||
const PLACES_VACUUM_STARTING_TOPIC = "places-vacuum-starting";
|
||||
|
||||
function getDBVacuumRatio() {
|
||||
let freelistStmt = dbConn.createStatement("PRAGMA freelist_count");
|
||||
freelistStmt.step();
|
||||
let freelistCount = freelistStmt.row.freelist_count;
|
||||
freelistStmt.finalize();
|
||||
let pageCountStmt = dbConn.createStatement("PRAGMA page_count");
|
||||
pageCountStmt.step();
|
||||
let pageCount = pageCountStmt.row.page_count;
|
||||
pageCountStmt.finalize();
|
||||
|
||||
let ratio = (freelistCount / pageCount);
|
||||
return ratio;
|
||||
}
|
||||
|
||||
function generateSparseDB(aType) {
|
||||
let limit = 0;
|
||||
if (aType == "low")
|
||||
limit = 10;
|
||||
else if (aType == "high")
|
||||
limit = 200;
|
||||
|
||||
let batch = {
|
||||
runBatched: function batch_runBatched() {
|
||||
for (let i = 0; i < limit; i++) {
|
||||
hs.addVisit(uri("http://" + i + ".mozilla.com/"),
|
||||
Date.now() * 1000 + i, null, hs.TRANSITION_TYPED, false, 0);
|
||||
}
|
||||
for (let i = 0; i < limit; i++) {
|
||||
bs.insertBookmark(bs.unfiledBookmarksFolder,
|
||||
uri("http://" + i + "." + i + ".mozilla.com/"),
|
||||
bs.DEFAULT_INDEX, "bookmark " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
hs.runInBatchMode(batch, null);
|
||||
bh.removeAllPages();
|
||||
bs.removeFolderChildren(bs.unfiledBookmarksFolder);
|
||||
}
|
||||
|
||||
var gTests = [
|
||||
{
|
||||
desc: "High ratio, last vacuum two months ago",
|
||||
ratio: "high",
|
||||
elapsedDays: 61,
|
||||
vacuum: true
|
||||
},
|
||||
];
|
||||
|
||||
var observer = {
|
||||
vacuum: false,
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (aTopic == PLACES_VACUUM_STARTING_TOPIC) {
|
||||
this.vacuum = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
os.addObserver(observer, PLACES_VACUUM_STARTING_TOPIC, false);
|
||||
|
||||
function run_test() {
|
||||
while (gTests.length) {
|
||||
observer.vacuum = false;
|
||||
let test = gTests.shift();
|
||||
print("PLACES TEST: " + test.desc);
|
||||
let ratio = getDBVacuumRatio();
|
||||
if (test.ratio == "high") {
|
||||
if (ratio < VACUUM_THRESHOLD)
|
||||
generateSparseDB("high");
|
||||
do_check_true(getDBVacuumRatio() > VACUUM_THRESHOLD);
|
||||
}
|
||||
else if (test.ratio == "low") {
|
||||
if (ratio == 0)
|
||||
generateSparseDB("low");
|
||||
do_check_true(getDBVacuumRatio() < VACUUM_THRESHOLD);
|
||||
}
|
||||
print("current ratio is " + getDBVacuumRatio());
|
||||
prefs.setIntPref(LAST_VACUUM_PREF, ((Date.now() / 1000) - (test.elapsedDays * 24 * 60 * 60)));
|
||||
os.notifyObservers(null, "idle-daily", null);
|
||||
let testFunc = test.vacuum ? do_check_true : do_check_false;
|
||||
testFunc(observer.vacuum);
|
||||
}
|
||||
|
||||
os.removeObserver(observer, PLACES_VACUUM_STARTING_TOPIC);
|
||||
}
|
Loading…
Reference in New Issue
Block a user