Bug 1250363 - Speed up history removals through a simulated per-statement trigger. r=yoric

This aims at speeding up DELETE FROM moz_places like queries.
The primary reason of slowness is the FOR EACH ROW trigger that takes care of updating the moz_hosts table when places are removed.
Unfortunately Sqlite doesn't support FOR EACH STATEMENT triggers, that means the trigger will hit multiple times for pages in the same host.
The patch introduces an additional temp table to accumulate hosts during a delete, then a trigger takes care of updating moz_hosts only once per touched host, rather than once per removed place.

MozReview-Commit-ID: BlJRLQZoC07

--HG--
extra : rebase_source : 5715efe580348b3810000d67a0a692dece36d306
This commit is contained in:
Marco Bonardo 2016-02-23 02:21:03 +01:00
Родитель c6eccef18d
Коммит a942905031
8 изменённых файлов: 82 добавлений и 15 удалений

Просмотреть файл

@ -464,7 +464,7 @@ Database::Init()
// like views, temp triggers or temp tables. The database should not be
// considered corrupt if any of the following fails.
rv = InitTempTriggers();
rv = InitTempEntities();
NS_ENSURE_SUCCESS(rv, rv);
// Notify we have finished database initialization.
@ -1015,7 +1015,7 @@ Database::InitFunctions()
}
nsresult
Database::InitTempTriggers()
Database::InitTempEntities()
{
MOZ_ASSERT(NS_IsMainThread());
@ -1027,6 +1027,10 @@ Database::InitTempTriggers()
// Add the triggers that update the moz_hosts table as necessary.
rv = mMainConn->ExecuteSimpleSQL(CREATE_PLACES_AFTERINSERT_TRIGGER);
NS_ENSURE_SUCCESS(rv, rv);
rv = mMainConn->ExecuteSimpleSQL(CREATE_UPDATEHOSTS_TEMP);
NS_ENSURE_SUCCESS(rv, rv);
rv = mMainConn->ExecuteSimpleSQL(CREATE_UPDATEHOSTS_AFTERDELETE_TRIGGER);
NS_ENSURE_SUCCESS(rv, rv);
rv = mMainConn->ExecuteSimpleSQL(CREATE_PLACES_AFTERDELETE_TRIGGER);
NS_ENSURE_SUCCESS(rv, rv);
rv = mMainConn->ExecuteSimpleSQL(CREATE_PLACES_AFTERUPDATE_FRECENCY_TRIGGER);

Просмотреть файл

@ -242,9 +242,9 @@ protected:
nsresult InitFunctions();
/**
* Initializes triggers defined in nsPlacesTriggers.h
* Initializes temp entities, like triggers, tables, views...
*/
nsresult InitTempTriggers();
nsresult InitTempEntities();
/**
* Helpers used by schema upgrades.

Просмотреть файл

@ -1884,6 +1884,7 @@ private:
}
#endif
{
nsCString query("DELETE FROM moz_places "
"WHERE id IN (");
query.Append(placeIdsToRemove);
@ -1894,6 +1895,18 @@ private:
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, rv);
}
{
// Hosts accumulated during the places delete are updated through a trigger
// (see nsPlacesTriggers.h).
nsAutoCString query("DELETE FROM moz_updatehosts_temp");
nsCOMPtr<mozIStorageStatement> stmt = mHistory->GetStatement(query);
NS_ENSURE_STATE(stmt);
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}

Просмотреть файл

@ -501,8 +501,12 @@ var removePagesById = Task.async(function*(db, idList) {
if (idList.length == 0) {
return;
}
// Note, we are already in a transaction, since callers create it.
yield db.execute(`DELETE FROM moz_places
WHERE id IN ( ${ sqlList(idList) } )`);
// Hosts accumulated during the places delete are updated through a trigger
// (see nsPlacesTriggers.h).
yield db.execute(`DELETE FROM moz_updatehosts_temp`);
});
/**

Просмотреть файл

@ -2455,6 +2455,13 @@ nsNavHistory::CleanupPlacesOnVisitsDelete(const nsCString& aPlaceIdsQueryString)
);
NS_ENSURE_SUCCESS(rv, rv);
// Hosts accumulated during the places delete are updated through a trigger
// (see nsPlacesTriggers.h).
rv = mDB->MainConn()->ExecuteSimpleSQL(
NS_LITERAL_CSTRING("DELETE FROM moz_updatehosts_temp")
);
NS_ENSURE_SUCCESS(rv, rv);
// Invalidate frecencies of touched places, since they need recalculation.
rv = invalidateFrecencies(aPlaceIdsQueryString);
NS_ENSURE_SUCCESS(rv, rv);

Просмотреть файл

@ -241,6 +241,15 @@ const EXPIRATION_QUERIES = {
actions: ACTION.CLEAR_HISTORY
},
// Hosts accumulated during the places delete are updated through a trigger
// (see nsPlacesTriggers.h).
QUERY_UPDATE_HOSTS: {
sql: `DELETE FROM moz_updatehosts_temp`,
actions: ACTION.CLEAR_HISTORY | ACTION.TIMED | ACTION.TIMED_OVERLIMIT |
ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
ACTION.DEBUG
},
// Expire orphan icons from the database.
QUERY_EXPIRE_FAVICONS: {
sql: `DELETE FROM moz_favicons WHERE id IN (

Просмотреть файл

@ -144,4 +144,15 @@
")" \
)
// This table is used, along with moz_places_afterdelete_trigger, to update
// hosts after places removals. During a DELETE FROM moz_places, hosts are
// accumulated into this table, then a DELETE FROM moz_updatehosts_temp will
// take care of updating the moz_hosts table for every modified host.
// See CREATE_PLACES_AFTERDELETE_TRIGGER in nsPlacestriggers.h for details.
#define CREATE_UPDATEHOSTS_TEMP NS_LITERAL_CSTRING( \
"CREATE TEMP TABLE moz_updatehosts_temp (" \
" host TEXT PRIMARY KEY " \
") WITHOUT ROWID " \
)
#endif // __nsPlacesTables_h__

Просмотреть файл

@ -110,12 +110,31 @@
"END" \
)
// This is a hack to workaround the lack of FOR EACH STATEMENT in Sqlite, until
// bug 871908 can be fixed properly.
// We store the modified hosts in a temp table, and after every DELETE FROM
// moz_places, we issue a DELETE FROM moz_updatehosts_temp. The AFTER DELETE
// trigger will then take care of updating the moz_hosts table.
// Note this way we lose atomicity, crashing between the 2 queries may break the
// hosts table coherency. So it's better to run those DELETE queries in a single
// transaction.
// Regardless, this is still better than hanging the browser for several minutes
// on a fast machine.
#define CREATE_PLACES_AFTERDELETE_TRIGGER NS_LITERAL_CSTRING( \
"CREATE TEMP TRIGGER moz_places_afterdelete_trigger " \
"AFTER DELETE ON moz_places FOR EACH ROW " \
"BEGIN " \
"INSERT OR IGNORE INTO moz_updatehosts_temp (host)" \
"VALUES (fixup_url(get_unreversed_host(OLD.rev_host)));" \
"END" \
)
#define CREATE_UPDATEHOSTS_AFTERDELETE_TRIGGER NS_LITERAL_CSTRING( \
"CREATE TEMP TRIGGER moz_updatehosts_afterdelete_trigger " \
"AFTER DELETE ON moz_updatehosts_temp FOR EACH ROW " \
"BEGIN " \
"DELETE FROM moz_hosts " \
"WHERE host = fixup_url(get_unreversed_host(OLD.rev_host)) " \
"WHERE host = OLD.host " \
"AND NOT EXISTS(" \
"SELECT 1 FROM moz_places " \
"WHERE rev_host = get_unreversed_host(host || '.') || '.' " \
@ -123,7 +142,7 @@
"); " \
"UPDATE moz_hosts " \
"SET prefix = (" HOSTS_PREFIX_PRIORITY_FRAGMENT ") " \
"WHERE host = fixup_url(get_unreversed_host(OLD.rev_host)); " \
"WHERE host = OLD.host; " \
"END" \
)