mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-20 08:51:04 +00:00
Bug 1261386 - Avoid history flooding from repeated reloads. r=adw
MozReview-Commit-ID: FhU8nOoNUHb --HG-- extra : rebase_source : ff75adb252b13f4042da49d4572fb807c3d0d823
This commit is contained in:
parent
84a96ef029
commit
392c65b534
@ -836,6 +836,7 @@ pref("places.frecency.bookmarkVisitBonus", 75);
|
||||
pref("places.frecency.downloadVisitBonus", 0);
|
||||
pref("places.frecency.permRedirectVisitBonus", 0);
|
||||
pref("places.frecency.tempRedirectVisitBonus", 0);
|
||||
pref("places.frecency.reloadVisitBonus", 0);
|
||||
pref("places.frecency.defaultVisitBonus", 0);
|
||||
|
||||
// bonus (in percent) for place types for frecency calculations
|
||||
|
@ -302,8 +302,8 @@ HistoryStore.prototype = {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!visit.type || !(visit.type >= PlacesUtils.history.TRANSITION_LINK &&
|
||||
visit.type <= PlacesUtils.history.TRANSITION_FRAMED_LINK)) {
|
||||
if (!visit.type ||
|
||||
!Object.values(PlacesUtils.history.TRANSITIONS).includes(visit.type)) {
|
||||
this._log.warn("Encountered record with invalid visit type: " +
|
||||
visit.type + "; ignoring.");
|
||||
continue;
|
||||
|
@ -1210,8 +1210,8 @@ private:
|
||||
_place.visitTime);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
uint32_t transitionType = _place.transitionType;
|
||||
NS_ASSERTION(transitionType >= nsINavHistoryService::TRANSITION_LINK &&
|
||||
transitionType <= nsINavHistoryService::TRANSITION_FRAMED_LINK,
|
||||
MOZ_ASSERT(transitionType >= nsINavHistoryService::TRANSITION_LINK &&
|
||||
transitionType <= nsINavHistoryService::TRANSITION_RELOAD,
|
||||
"Invalid transition type!");
|
||||
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("visit_type"),
|
||||
transitionType);
|
||||
@ -1970,7 +1970,7 @@ History::History()
|
||||
: mShuttingDown(false)
|
||||
, mShutdownMutex("History::mShutdownMutex")
|
||||
, mObservers(VISIT_OBSERVERS_INITIAL_CACHE_LENGTH)
|
||||
, mRecentlyVisitedURIsNextIndex(0)
|
||||
, mRecentlyVisitedURIs(RECENTLY_VISITED_URIS_SIZE)
|
||||
{
|
||||
NS_ASSERTION(!gService, "Ruh-roh! This service has already been created!");
|
||||
gService = this;
|
||||
@ -2406,25 +2406,29 @@ History::Shutdown()
|
||||
|
||||
void
|
||||
History::AppendToRecentlyVisitedURIs(nsIURI* aURI) {
|
||||
if (mRecentlyVisitedURIs.Length() < RECENTLY_VISITED_URI_SIZE) {
|
||||
// Append a new element while the array is not full.
|
||||
mRecentlyVisitedURIs.AppendElement(aURI);
|
||||
} else {
|
||||
// Otherwise, replace the oldest member.
|
||||
mRecentlyVisitedURIsNextIndex %= RECENTLY_VISITED_URI_SIZE;
|
||||
mRecentlyVisitedURIs.ElementAt(mRecentlyVisitedURIsNextIndex) = aURI;
|
||||
mRecentlyVisitedURIsNextIndex++;
|
||||
// Add a new entry, if necessary.
|
||||
RecentURIKey* entry = mRecentlyVisitedURIs.GetEntry(aURI);
|
||||
if (!entry) {
|
||||
entry = mRecentlyVisitedURIs.PutEntry(aURI);
|
||||
}
|
||||
if (entry) {
|
||||
entry->time = PR_Now();
|
||||
}
|
||||
|
||||
// Remove entries older than RECENTLY_VISITED_URIS_MAX_AGE.
|
||||
for (auto iter = mRecentlyVisitedURIs.Iter(); !iter.Done(); iter.Next()) {
|
||||
RecentURIKey* entry = iter.Get();
|
||||
if ((PR_Now() - entry->time) > RECENTLY_VISITED_URIS_MAX_AGE) {
|
||||
iter.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
History::IsRecentlyVisitedURI(nsIURI* aURI) {
|
||||
bool equals = false;
|
||||
RecentlyVisitedArray::index_type i;
|
||||
for (i = 0; i < mRecentlyVisitedURIs.Length() && !equals; ++i) {
|
||||
aURI->Equals(mRecentlyVisitedURIs.ElementAt(i), &equals);
|
||||
}
|
||||
return equals;
|
||||
RecentURIKey* entry = mRecentlyVisitedURIs.GetEntry(aURI);
|
||||
// Check if the entry exists and is younger than RECENTLY_VISITED_URIS_MAX_AGE.
|
||||
return entry && (PR_Now() - entry->time) < RECENTLY_VISITED_URIS_MAX_AGE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -2466,12 +2470,14 @@ History::VisitURI(nsIURI* aURI,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Do not save a reloaded uri if we have visited the same URI recently.
|
||||
bool reload = false;
|
||||
if (aLastVisitedURI) {
|
||||
bool same;
|
||||
rv = aURI->Equals(aLastVisitedURI, &same);
|
||||
rv = aURI->Equals(aLastVisitedURI, &reload);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (same && IsRecentlyVisitedURI(aURI)) {
|
||||
// Do not save refresh visits if we have visited this URI recently.
|
||||
if (reload && IsRecentlyVisitedURI(aURI)) {
|
||||
// Regardless we must update the stored visit time.
|
||||
AppendToRecentlyVisitedURIs(aURI);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
@ -2507,6 +2513,9 @@ History::VisitURI(nsIURI* aURI,
|
||||
else if (aFlags & IHistory::REDIRECT_PERMANENT) {
|
||||
transitionType = nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT;
|
||||
}
|
||||
else if (reload) {
|
||||
transitionType = nsINavHistoryService::TRANSITION_RELOAD;
|
||||
}
|
||||
else if ((recentFlags & nsNavHistory::RECENT_TYPED) &&
|
||||
!(aFlags & IHistory::UNRECOVERABLE_ERROR)) {
|
||||
// Don't mark error pages as typed, even if they were actually typed by
|
||||
@ -2948,7 +2957,7 @@ History::UpdatePlaces(JS::Handle<JS::Value> aPlaceInfos,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_ARG_RANGE(transitionType,
|
||||
nsINavHistoryService::TRANSITION_LINK,
|
||||
nsINavHistoryService::TRANSITION_FRAMED_LINK);
|
||||
nsINavHistoryService::TRANSITION_RELOAD);
|
||||
data.SetTransitionType(transitionType);
|
||||
data.hidden = GetHiddenState(false, transitionType);
|
||||
|
||||
|
@ -33,8 +33,14 @@ class ConcurrentStatementsHolder;
|
||||
#define NS_HISTORYSERVICE_CID \
|
||||
{0x0937a705, 0x91a6, 0x417a, {0x82, 0x92, 0xb2, 0x2e, 0xb1, 0x0d, 0xa8, 0x6c}}
|
||||
|
||||
// Max size of History::mRecentlyVisitedURIs
|
||||
#define RECENTLY_VISITED_URI_SIZE 8
|
||||
// Initial size of mRecentlyVisitedURIs.
|
||||
#define RECENTLY_VISITED_URIS_SIZE 64
|
||||
// Microseconds after which a visit can be expired from mRecentlyVisitedURIs.
|
||||
// When an URI is reloaded we only take into account the first visit to it, and
|
||||
// ignore any subsequent visits, if they happen before this time has elapsed.
|
||||
// A commonly found case is to reload a page every 5 minutes, so we pick a time
|
||||
// larger than that.
|
||||
#define RECENTLY_VISITED_URIS_MAX_AGE 6 * 60 * PR_USEC_PER_SEC
|
||||
|
||||
class History final : public IHistory
|
||||
, public nsIDownloadHistory
|
||||
@ -189,14 +195,26 @@ private:
|
||||
nsTHashtable<KeyClass> mObservers;
|
||||
|
||||
/**
|
||||
* mRecentlyVisitedURIs remembers URIs which are recently added to the DB,
|
||||
* to avoid saving these locations repeatedly in a short period.
|
||||
* mRecentlyVisitedURIs remembers URIs which have been recently added to
|
||||
* history, to avoid saving these locations repeatedly in a short period.
|
||||
*/
|
||||
class RecentURIKey : public nsURIHashKey
|
||||
{
|
||||
public:
|
||||
explicit RecentURIKey(const nsIURI* aURI) : nsURIHashKey(aURI)
|
||||
{
|
||||
}
|
||||
RecentURIKey(const RecentURIKey& aOther) : nsURIHashKey(aOther)
|
||||
{
|
||||
NS_NOTREACHED("Do not call me!");
|
||||
}
|
||||
PRTime time;
|
||||
};
|
||||
nsTHashtable<RecentURIKey> mRecentlyVisitedURIs;
|
||||
/**
|
||||
* Whether aURI has been visited "recently".
|
||||
* See RECENTLY_VISITED_URIS_MAX_AGE.
|
||||
*/
|
||||
typedef AutoTArray<nsCOMPtr<nsIURI>, RECENTLY_VISITED_URI_SIZE>
|
||||
RecentlyVisitedArray;
|
||||
RecentlyVisitedArray mRecentlyVisitedURIs;
|
||||
RecentlyVisitedArray::index_type mRecentlyVisitedURIsNextIndex;
|
||||
|
||||
bool IsRecentlyVisitedURI(nsIURI* aURI);
|
||||
};
|
||||
|
||||
|
@ -40,7 +40,7 @@
|
||||
* - date: (Date)
|
||||
* The time the visit occurred.
|
||||
* - transition: (number)
|
||||
* How the user reached the page. See constants `TRANSITION_*`
|
||||
* How the user reached the page. See constants `TRANSITIONS.*`
|
||||
* for the possible transition types.
|
||||
* - referrer: (URL)
|
||||
* or (nsIURI)
|
||||
@ -408,51 +408,58 @@ this.History = Object.freeze({
|
||||
* objects.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The user followed a link and got a new toplevel window.
|
||||
*/
|
||||
TRANSITION_LINK: Ci.nsINavHistoryService.TRANSITION_LINK,
|
||||
TRANSITIONS: {
|
||||
/**
|
||||
* The user followed a link and got a new toplevel window.
|
||||
*/
|
||||
LINK: Ci.nsINavHistoryService.TRANSITION_LINK,
|
||||
|
||||
/**
|
||||
* The user typed the page's URL in the URL bar or selected it from
|
||||
* URL bar autocomplete results, clicked on it from a history query
|
||||
* (from the History sidebar, History menu, or history query in the
|
||||
* personal toolbar or Places organizer.
|
||||
*/
|
||||
TRANSITION_TYPED: Ci.nsINavHistoryService.TRANSITION_TYPED,
|
||||
/**
|
||||
* The user typed the page's URL in the URL bar or selected it from
|
||||
* URL bar autocomplete results, clicked on it from a history query
|
||||
* (from the History sidebar, History menu, or history query in the
|
||||
* personal toolbar or Places organizer.
|
||||
*/
|
||||
TYPED: Ci.nsINavHistoryService.TRANSITION_TYPED,
|
||||
|
||||
/**
|
||||
* The user followed a bookmark to get to the page.
|
||||
*/
|
||||
TRANSITION_BOOKMARK: Ci.nsINavHistoryService.TRANSITION_BOOKMARK,
|
||||
/**
|
||||
* The user followed a bookmark to get to the page.
|
||||
*/
|
||||
BOOKMARK: Ci.nsINavHistoryService.TRANSITION_BOOKMARK,
|
||||
|
||||
/**
|
||||
* Some inner content is loaded. This is true of all images on a
|
||||
* page, and the contents of the iframe. It is also true of any
|
||||
* content in a frame if the user did not explicitly follow a link
|
||||
* to get there.
|
||||
*/
|
||||
TRANSITION_EMBED: Ci.nsINavHistoryService.TRANSITION_EMBED,
|
||||
/**
|
||||
* Some inner content is loaded. This is true of all images on a
|
||||
* page, and the contents of the iframe. It is also true of any
|
||||
* content in a frame if the user did not explicitly follow a link
|
||||
* to get there.
|
||||
*/
|
||||
EMBED: Ci.nsINavHistoryService.TRANSITION_EMBED,
|
||||
|
||||
/**
|
||||
* Set when the transition was a permanent redirect.
|
||||
*/
|
||||
TRANSITION_REDIRECT_PERMANENT: Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT,
|
||||
/**
|
||||
* Set when the transition was a permanent redirect.
|
||||
*/
|
||||
REDIRECT_PERMANENT: Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT,
|
||||
|
||||
/**
|
||||
* Set when the transition was a temporary redirect.
|
||||
*/
|
||||
TRANSITION_REDIRECT_TEMPORARY: Ci.nsINavHistoryService.TRANSITION_REDIRECT_TEMPORARY,
|
||||
/**
|
||||
* Set when the transition was a temporary redirect.
|
||||
*/
|
||||
REDIRECT_TEMPORARY: Ci.nsINavHistoryService.TRANSITION_REDIRECT_TEMPORARY,
|
||||
|
||||
/**
|
||||
* Set when the transition is a download.
|
||||
*/
|
||||
TRANSITION_DOWNLOAD: Ci.nsINavHistoryService.TRANSITION_REDIRECT_DOWNLOAD,
|
||||
/**
|
||||
* Set when the transition is a download.
|
||||
*/
|
||||
DOWNLOAD: Ci.nsINavHistoryService.TRANSITION_DOWNLOAD,
|
||||
|
||||
/**
|
||||
* The user followed a link and got a visit in a frame.
|
||||
*/
|
||||
TRANSITION_FRAMED_LINK: Ci.nsINavHistoryService.TRANSITION_FRAMED_LINK,
|
||||
/**
|
||||
* The user followed a link and got a visit in a frame.
|
||||
*/
|
||||
FRAMED_LINK: Ci.nsINavHistoryService.TRANSITION_FRAMED_LINK,
|
||||
|
||||
/**
|
||||
* The user reloaded a page.
|
||||
*/
|
||||
RELOAD: Ci.nsINavHistoryService.TRANSITION_RELOAD,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
@ -484,7 +491,7 @@ function validatePageInfo(pageInfo) {
|
||||
for (let inVisit of pageInfo.visits) {
|
||||
let visit = {
|
||||
date: new Date(),
|
||||
transition: inVisit.transition || History.TRANSITION_LINK,
|
||||
transition: inVisit.transition || History.TRANSITIONS.LINK,
|
||||
};
|
||||
|
||||
if (!isValidTransitionType(visit.transition)) {
|
||||
@ -541,16 +548,7 @@ function convertForUpdatePlaces(pageInfo) {
|
||||
* @return (Boolean)
|
||||
*/
|
||||
function isValidTransitionType(transitionType) {
|
||||
return [
|
||||
History.TRANSITION_LINK,
|
||||
History.TRANSITION_TYPED,
|
||||
History.TRANSITION_BOOKMARK,
|
||||
History.TRANSITION_EMBED,
|
||||
History.TRANSITION_REDIRECT_PERMANENT,
|
||||
History.TRANSITION_REDIRECT_TEMPORARY,
|
||||
History.TRANSITION_DOWNLOAD,
|
||||
History.TRANSITION_FRAMED_LINK
|
||||
].includes(transitionType);
|
||||
return Object.values(History.TRANSITIONS).includes(transitionType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -690,13 +690,13 @@ this.PlacesDBUtils = {
|
||||
let fixVisitStats = DBConn.createAsyncStatement(
|
||||
`UPDATE moz_places
|
||||
SET visit_count = (SELECT count(*) FROM moz_historyvisits
|
||||
WHERE place_id = moz_places.id AND visit_type NOT IN (0,4,7,8)),
|
||||
WHERE place_id = moz_places.id AND visit_type NOT IN (0,4,7,8,9)),
|
||||
last_visit_date = (SELECT MAX(visit_date) FROM moz_historyvisits
|
||||
WHERE place_id = moz_places.id)
|
||||
WHERE id IN (
|
||||
SELECT h.id FROM moz_places h
|
||||
WHERE visit_count <> (SELECT count(*) FROM moz_historyvisits v
|
||||
WHERE v.place_id = h.id AND visit_type NOT IN (0,4,7,8))
|
||||
WHERE v.place_id = h.id AND visit_type NOT IN (0,4,7,8,9))
|
||||
OR last_visit_date <> (SELECT MAX(visit_date) FROM moz_historyvisits v
|
||||
WHERE v.place_id = h.id)
|
||||
)`);
|
||||
|
@ -476,16 +476,22 @@ namespace places {
|
||||
uint32_t numEntries;
|
||||
nsresult rv = aArguments->GetNumEntries(&numEntries);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ASSERTION(numEntries > 0, "unexpected number of arguments");
|
||||
MOZ_ASSERT(numEntries == 1, "unexpected number of arguments");
|
||||
|
||||
int64_t pageId = aArguments->AsInt64(0);
|
||||
int32_t typed = numEntries > 1 ? aArguments->AsInt32(1) : 0;
|
||||
int32_t fullVisitCount = numEntries > 2 ? aArguments->AsInt32(2) : 0;
|
||||
int64_t bookmarkId = numEntries > 3 ? aArguments->AsInt64(3) : 0;
|
||||
MOZ_ASSERT(pageId > 0, "Should always pass a valid page id");
|
||||
if (pageId <= 0) {
|
||||
NS_ADDREF(*_result = new IntegerVariant(0));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t typed = 0;
|
||||
int32_t visitCount = 0;
|
||||
int32_t hidden = 0;
|
||||
bool hasBookmark = false;
|
||||
int32_t isQuery = 0;
|
||||
float pointsForSampledVisits = 0.0;
|
||||
int32_t numSampledVisits = 0;
|
||||
int32_t bonus = 0;
|
||||
|
||||
// This is a const version of the history object for thread-safety.
|
||||
const nsNavHistory* history = nsNavHistory::GetConstHistoryService();
|
||||
@ -493,14 +499,12 @@ namespace places {
|
||||
RefPtr<Database> DB = Database::GetDatabase();
|
||||
NS_ENSURE_STATE(DB);
|
||||
|
||||
if (pageId > 0) {
|
||||
// The page is already in the database, and we can fetch current
|
||||
// params from the database.
|
||||
|
||||
// Fetch the page stats from the database.
|
||||
{
|
||||
RefPtr<mozIStorageStatement> getPageInfo = DB->GetStatement(
|
||||
"SELECT typed, hidden, visit_count, "
|
||||
"(SELECT count(*) FROM moz_historyvisits WHERE place_id = :page_id), "
|
||||
"EXISTS (SELECT 1 FROM moz_bookmarks WHERE fk = :page_id), "
|
||||
"(url > 'place:' AND url < 'place;') "
|
||||
"SELECT typed, visit_count, foreign_count, "
|
||||
"(substr(url, 0, 7) = 'place:') "
|
||||
"FROM moz_places "
|
||||
"WHERE id = :page_id "
|
||||
);
|
||||
@ -510,29 +514,26 @@ namespace places {
|
||||
rv = getPageInfo->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), pageId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool hasResult;
|
||||
bool hasResult = false;
|
||||
rv = getPageInfo->ExecuteStep(&hasResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(hasResult, NS_ERROR_UNEXPECTED);
|
||||
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && hasResult, NS_ERROR_UNEXPECTED);
|
||||
|
||||
rv = getPageInfo->GetInt32(0, &typed);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = getPageInfo->GetInt32(1, &hidden);
|
||||
rv = getPageInfo->GetInt32(1, &visitCount);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = getPageInfo->GetInt32(2, &visitCount);
|
||||
int32_t foreignCount = 0;
|
||||
rv = getPageInfo->GetInt32(2, &foreignCount);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = getPageInfo->GetInt32(3, &fullVisitCount);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = getPageInfo->GetInt64(4, &bookmarkId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = getPageInfo->GetInt32(5, &isQuery);
|
||||
hasBookmark = foreignCount > 0;
|
||||
rv = getPageInfo->GetInt32(3, &isQuery);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// NOTE: This is not limited to visits with "visit_type NOT IN (0,4,7,8)"
|
||||
// because otherwise it would not return any visit for those transitions
|
||||
// causing an incorrect frecency, see CalculateFrecencyInternal().
|
||||
if (visitCount > 0) {
|
||||
// Get a sample of the last visits to the page, to calculate its weight.
|
||||
// In case of a temporary or permanent redirect, calculate the frecency
|
||||
// as if the original page was visited.
|
||||
// Get a sample of the last visits to the page, to calculate its weight.
|
||||
nsCOMPtr<mozIStorageStatement> getVisits = DB->GetStatement(
|
||||
NS_LITERAL_CSTRING(
|
||||
"/* do not warn (bug 659740 - SQLite may ignore index if few visits exist) */"
|
||||
@ -551,12 +552,11 @@ namespace places {
|
||||
);
|
||||
NS_ENSURE_STATE(getVisits);
|
||||
mozStorageStatementScoper visitsScoper(getVisits);
|
||||
|
||||
rv = getVisits->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), pageId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Fetch only a limited number of recent visits.
|
||||
int32_t numSampledVisits = 0;
|
||||
bool hasResult = false;
|
||||
for (int32_t maxVisits = history->GetNumVisitsForFrecency();
|
||||
numSampledVisits < maxVisits &&
|
||||
NS_SUCCEEDED(getVisits->ExecuteStep(&hasResult)) && hasResult;
|
||||
@ -564,10 +564,10 @@ namespace places {
|
||||
int32_t visitType;
|
||||
rv = getVisits->GetInt32(1, &visitType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
int32_t bonus = history->GetFrecencyTransitionBonus(visitType, true);
|
||||
bonus = history->GetFrecencyTransitionBonus(visitType, true);
|
||||
|
||||
// Always add the bookmark visit bonus.
|
||||
if (bookmarkId) {
|
||||
// Add the bookmark visit bonus.
|
||||
if (hasBookmark) {
|
||||
bonus += history->GetFrecencyTransitionBonus(nsINavHistoryService::TRANSITION_BOOKMARK, true);
|
||||
}
|
||||
|
||||
@ -578,56 +578,49 @@ namespace places {
|
||||
pointsForSampledVisits += (float)(weight * (bonus / 100.0));
|
||||
}
|
||||
}
|
||||
|
||||
// If we found some visits for this page, use the calculated weight.
|
||||
if (numSampledVisits) {
|
||||
// fix for bug #412219
|
||||
if (!pointsForSampledVisits) {
|
||||
// For URIs with zero points in the sampled recent visits
|
||||
// but "browsing" type visits outside the sampling range, set
|
||||
// frecency to -visit_count, so they're still shown in autocomplete.
|
||||
NS_ADDREF(*_result = new IntegerVariant(-visitCount));
|
||||
}
|
||||
else {
|
||||
// Estimate frecency using the last few visits.
|
||||
// Use ceilf() so that we don't round down to 0, which
|
||||
// would cause us to completely ignore the place during autocomplete.
|
||||
NS_ADDREF(*_result = new IntegerVariant((int32_t) ceilf(fullVisitCount * ceilf(pointsForSampledVisits) / numSampledVisits)));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// This page is unknown or has no visits. It could have just been added, so
|
||||
// use passed in or default values.
|
||||
// If we sampled some visits for this page, use the calculated weight.
|
||||
if (numSampledVisits) {
|
||||
// We were unable to calculate points, maybe cause all the visits in the
|
||||
// sample had a zero bonus. Though, we know the page has some past valid
|
||||
// visit, or visit_count would be zero. Thus we set the frecency to
|
||||
// -1, so they are still shown in autocomplete.
|
||||
if (!pointsForSampledVisits) {
|
||||
NS_ADDREF(*_result = new IntegerVariant(-1));
|
||||
}
|
||||
else {
|
||||
// Estimate frecency using the sampled visits.
|
||||
// Use ceilf() so that we don't round down to 0, which
|
||||
// would cause us to completely ignore the place during autocomplete.
|
||||
NS_ADDREF(*_result = new IntegerVariant((int32_t) ceilf(visitCount * ceilf(pointsForSampledVisits) / numSampledVisits)));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// The code below works well for guessing the frecency on import, and we'll
|
||||
// correct later once we have visits.
|
||||
// TODO: What if we don't have visits and we never visit? We could end up
|
||||
// with a really high value that keeps coming up in ac results? Should we
|
||||
// only do this on import? Have to figure it out.
|
||||
int32_t bonus = 0;
|
||||
// Otherwise this page has no visits, it may be bookmarked.
|
||||
if (!hasBookmark || isQuery) {
|
||||
NS_ADDREF(*_result = new IntegerVariant(0));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// For unvisited bookmarks, produce a non-zero frecency, so that they show
|
||||
// up in URL bar autocomplete.
|
||||
visitCount = 1;
|
||||
|
||||
// Make it so something bookmarked and typed will have a higher frecency
|
||||
// than something just typed or just bookmarked.
|
||||
if (bookmarkId && !isQuery) {
|
||||
bonus += history->GetFrecencyTransitionBonus(nsINavHistoryService::TRANSITION_BOOKMARK, false);;
|
||||
// For unvisited bookmarks, produce a non-zero frecency, so that they show
|
||||
// up in URL bar autocomplete.
|
||||
fullVisitCount = 1;
|
||||
}
|
||||
|
||||
bonus += history->GetFrecencyTransitionBonus(nsINavHistoryService::TRANSITION_BOOKMARK, false);
|
||||
if (typed) {
|
||||
bonus += history->GetFrecencyTransitionBonus(nsINavHistoryService::TRANSITION_TYPED, false);
|
||||
}
|
||||
|
||||
// Assume "now" as our ageInDays, so use the first bucket.
|
||||
pointsForSampledVisits = history->GetFrecencyBucketWeight(1) * (bonus / (float)100.0);
|
||||
pointsForSampledVisits = history->GetFrecencyBucketWeight(1) * (bonus / (float)100.0);
|
||||
|
||||
// use ceilf() so that we don't round down to 0, which
|
||||
// would cause us to completely ignore the place during autocomplete
|
||||
NS_ADDREF(*_result = new IntegerVariant((int32_t) ceilf(fullVisitCount * ceilf(pointsForSampledVisits))));
|
||||
NS_ADDREF(*_result = new IntegerVariant((int32_t) ceilf(visitCount * ceilf(pointsForSampledVisits))));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1257,6 +1257,11 @@ interface nsINavHistoryService : nsISupports
|
||||
*/
|
||||
const unsigned long TRANSITION_FRAMED_LINK = 8;
|
||||
|
||||
/**
|
||||
* This transition type means the page has been reloaded.
|
||||
*/
|
||||
const unsigned long TRANSITION_RELOAD = 9;
|
||||
|
||||
/**
|
||||
* Set when database is coherent
|
||||
*/
|
||||
|
@ -99,6 +99,8 @@ using namespace mozilla::places;
|
||||
#define PREF_FREC_UNVISITED_BOOKMARK_BONUS_DEF 140
|
||||
#define PREF_FREC_UNVISITED_TYPED_BONUS "places.frecency.unvisitedTypedBonus"
|
||||
#define PREF_FREC_UNVISITED_TYPED_BONUS_DEF 200
|
||||
#define PREF_FREC_RELOAD_VISIT_BONUS "places.frecency.reloadVisitBonus"
|
||||
#define PREF_FREC_RELOAD_VISIT_BONUS_DEF 0
|
||||
|
||||
// In order to avoid calling PR_now() too often we use a cached "now" value
|
||||
// for repeating stuff. These are milliseconds between "now" cache refreshes.
|
||||
@ -482,6 +484,7 @@ nsNavHistory::LoadPrefs()
|
||||
FRECENCY_PREF(mDefaultVisitBonus, PREF_FREC_DEFAULT_VISIT_BONUS);
|
||||
FRECENCY_PREF(mUnvisitedBookmarkBonus, PREF_FREC_UNVISITED_BOOKMARK_BONUS);
|
||||
FRECENCY_PREF(mUnvisitedTypedBonus, PREF_FREC_UNVISITED_TYPED_BONUS);
|
||||
FRECENCY_PREF(mReloadVisitBonus, PREF_FREC_RELOAD_VISIT_BONUS);
|
||||
FRECENCY_PREF(mFirstBucketWeight, PREF_FREC_FIRST_BUCKET_WEIGHT);
|
||||
FRECENCY_PREF(mSecondBucketWeight, PREF_FREC_SECOND_BUCKET_WEIGHT);
|
||||
FRECENCY_PREF(mThirdBucketWeight, PREF_FREC_THIRD_BUCKET_WEIGHT);
|
||||
|
@ -412,6 +412,8 @@ public:
|
||||
return mPermRedirectVisitBonus;
|
||||
case nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY:
|
||||
return mTempRedirectVisitBonus;
|
||||
case nsINavHistoryService::TRANSITION_RELOAD:
|
||||
return mReloadVisitBonus;
|
||||
default:
|
||||
// 0 == undefined (see bug #375777 for details)
|
||||
NS_WARN_IF_FALSE(!aTransitionType, "new transition but no bonus for frecency");
|
||||
@ -485,9 +487,6 @@ protected:
|
||||
*/
|
||||
nsresult DecayFrecency();
|
||||
|
||||
nsresult CalculateFrecency(int64_t aPageID, int32_t aTyped, int32_t aVisitCount, nsAutoCString &aURL, int32_t *aFrecency);
|
||||
nsresult CalculateFrecencyInternal(int64_t aPageID, int32_t aTyped, int32_t aVisitCount, bool aIsBookmarked, int32_t *aFrecency);
|
||||
|
||||
nsresult RemovePagesInternal(const nsCString& aPlaceIdsQueryString);
|
||||
nsresult CleanupPlacesOnVisitsDelete(const nsCString& aPlaceIdsQueryString);
|
||||
|
||||
@ -610,6 +609,7 @@ protected:
|
||||
int32_t mDefaultVisitBonus;
|
||||
int32_t mUnvisitedBookmarkBonus;
|
||||
int32_t mUnvisitedTypedBonus;
|
||||
int32_t mReloadVisitBonus;
|
||||
|
||||
// in nsNavHistoryQuery.cpp
|
||||
nsresult TokensToQueries(const nsTArray<QueryKeyValuePair>& aTokens,
|
||||
|
@ -14,9 +14,10 @@
|
||||
* 0 - invalid
|
||||
* 4 - EMBED
|
||||
* 7 - DOWNLOAD
|
||||
* 7 - FRAMED_LINK
|
||||
* 8 - FRAMED_LINK
|
||||
* 9 - RELOAD
|
||||
**/
|
||||
#define EXCLUDED_VISIT_TYPES "0, 4, 7, 8"
|
||||
#define EXCLUDED_VISIT_TYPES "0, 4, 7, 8, 9"
|
||||
|
||||
/**
|
||||
* This triggers update visit_count and last_visit_date based on historyvisits
|
||||
|
@ -18,6 +18,7 @@ const TRANSITION_FRAMED_LINK = Ci.nsINavHistoryService.TRANSITION_FRAMED_LINK;
|
||||
const TRANSITION_REDIRECT_PERMANENT = Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT;
|
||||
const TRANSITION_REDIRECT_TEMPORARY = Ci.nsINavHistoryService.TRANSITION_REDIRECT_TEMPORARY;
|
||||
const TRANSITION_DOWNLOAD = Ci.nsINavHistoryService.TRANSITION_DOWNLOAD;
|
||||
const TRANSITION_RELOAD = Ci.nsINavHistoryService.TRANSITION_RELOAD;
|
||||
|
||||
const TITLE_LENGTH_MAX = 4096;
|
||||
|
||||
|
@ -43,6 +43,7 @@ var bonusPrefs = {
|
||||
downloadVisitBonus: Ci.nsINavHistoryService.TRANSITION_DOWNLOAD,
|
||||
permRedirectVisitBonus: Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT,
|
||||
tempRedirectVisitBonus: Ci.nsINavHistoryService.TRANSITION_REDIRECT_TEMPORARY,
|
||||
reloadVisitBonus: Ci.nsINavHistoryService.TRANSITION_RELOAD,
|
||||
};
|
||||
|
||||
// create test data
|
||||
@ -110,6 +111,7 @@ function* task_initializeBucket(bucket) {
|
||||
if (visitType == Ci.nsINavHistoryService.TRANSITION_EMBED ||
|
||||
visitType == Ci.nsINavHistoryService.TRANSITION_FRAMED_LINK ||
|
||||
visitType == Ci.nsINavHistoryService.TRANSITION_DOWNLOAD ||
|
||||
visitType == Ci.nsINavHistoryService.TRANSITION_RELOAD ||
|
||||
bonusName == "defaultVisitBonus")
|
||||
frecency = 0;
|
||||
else
|
||||
|
@ -19,7 +19,8 @@ add_task(function* test_execute()
|
||||
|
||||
let notcount_visited_URIs = ["http://www.test-embed.com/",
|
||||
"http://www.test-download.com/",
|
||||
"http://www.test-framed.com/"];
|
||||
"http://www.test-framed.com/",
|
||||
"http://www.test-reload.com/"];
|
||||
|
||||
// add visits, one for each transition type
|
||||
yield PlacesTestUtils.addVisits([
|
||||
@ -39,6 +40,8 @@ add_task(function* test_execute()
|
||||
transition: TRANSITION_REDIRECT_TEMPORARY },
|
||||
{ uri: uri("http://www.test-download.com/"),
|
||||
transition: TRANSITION_DOWNLOAD },
|
||||
{ uri: uri("http://www.test-reload.com/"),
|
||||
transition: TRANSITION_RELOAD },
|
||||
]);
|
||||
|
||||
// check that all links are marked as visited
|
||||
|
@ -35,7 +35,8 @@ function* task_add_visit(aURI, aVisitType)
|
||||
if (aVisitType != 0 &&
|
||||
aVisitType != TRANSITION_EMBED &&
|
||||
aVisitType != TRANSITION_FRAMED_LINK &&
|
||||
aVisitType != TRANSITION_DOWNLOAD) {
|
||||
aVisitType != TRANSITION_DOWNLOAD &&
|
||||
aVisitType != TRANSITION_RELOAD) {
|
||||
visit_count ++;
|
||||
}
|
||||
|
||||
@ -107,6 +108,14 @@ add_task(function* test_execute()
|
||||
do_check_eq((yield task_add_visit(TEST_URI, TRANSITION_TYPED)), placeId);
|
||||
check_results(1, 1);
|
||||
|
||||
// Add a visit that should not increase visit_count
|
||||
do_check_eq((yield task_add_visit(TEST_URI, TRANSITION_RELOAD)), placeId);
|
||||
check_results(1, 1);
|
||||
|
||||
// Add a visit that should not increase visit_count
|
||||
do_check_eq((yield task_add_visit(TEST_URI, TRANSITION_DOWNLOAD)), placeId);
|
||||
check_results(1, 1);
|
||||
|
||||
// Add a visit, check that hidden is not overwritten
|
||||
// - We expect that the place has still hidden = 0, while retaining
|
||||
// correct visit_count.
|
||||
|
@ -333,7 +333,7 @@ add_task(function* test_add_visit_invalid_transitionType_throws() {
|
||||
}
|
||||
|
||||
// Now, test something that has a transition type greater than the last one.
|
||||
place.visits[0] = new VisitInfo(TRANSITION_FRAMED_LINK + 1);
|
||||
place.visits[0] = new VisitInfo(TRANSITION_RELOAD + 1);
|
||||
try {
|
||||
yield promiseUpdatePlaces(place);
|
||||
do_throw("Should have thrown!");
|
||||
@ -647,9 +647,8 @@ add_task(function* test_add_visit() {
|
||||
title: "test_add_visit title",
|
||||
visits: [],
|
||||
};
|
||||
for (let transitionType = TRANSITION_LINK;
|
||||
transitionType <= TRANSITION_FRAMED_LINK;
|
||||
transitionType++) {
|
||||
for (let t in PlacesUtils.history.TRANSITIONS) {
|
||||
let transitionType = PlacesUtils.history.TRANSITIONS[t];
|
||||
place.visits.push(new VisitInfo(transitionType, VISIT_TIME));
|
||||
}
|
||||
do_check_false(yield promiseIsURIVisited(place.uri));
|
||||
@ -672,8 +671,8 @@ add_task(function* test_add_visit() {
|
||||
do_check_eq(visits.length, 1);
|
||||
let visit = visits[0];
|
||||
do_check_eq(visit.visitDate, VISIT_TIME);
|
||||
do_check_true(visit.transitionType >= TRANSITION_LINK &&
|
||||
visit.transitionType <= TRANSITION_FRAMED_LINK);
|
||||
let transitions =
|
||||
do_check_true(Object.values(PlacesUtils.history.TRANSITIONS).includes(visit.transitionType));
|
||||
do_check_true(visit.referrerURI === null);
|
||||
|
||||
// For TRANSITION_EMBED visits, many properties will always be zero or
|
||||
@ -706,9 +705,8 @@ add_task(function* test_add_visit() {
|
||||
add_task(function* test_properties_saved() {
|
||||
// Check each transition type to make sure it is saved properly.
|
||||
let places = [];
|
||||
for (let transitionType = TRANSITION_LINK;
|
||||
transitionType <= TRANSITION_FRAMED_LINK;
|
||||
transitionType++) {
|
||||
for (let t in PlacesUtils.history.TRANSITIONS) {
|
||||
let transitionType = PlacesUtils.history.TRANSITIONS[t];
|
||||
let place = {
|
||||
uri: NetUtil.newURI(TEST_DOMAIN + "test_properties_saved/" +
|
||||
transitionType),
|
||||
|
@ -79,7 +79,7 @@ add_task(function* test_history_clear()
|
||||
PlacesUtils.annotations.EXPIRE_NEVER);
|
||||
|
||||
// Add a bookmark
|
||||
// Bookmarked page should have history cleared and frecency = -old_visit_count
|
||||
// Bookmarked page should have history cleared and frecency = -1
|
||||
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
||||
uri("http://typed.mozilla.org/"),
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
@ -105,8 +105,7 @@ add_task(function* test_history_clear()
|
||||
yield PlacesTestUtils.promiseAsyncUpdates();
|
||||
|
||||
// Check that frecency for not cleared items (bookmarks) has been converted
|
||||
// to -MAX(visit_count, 1), so we will be able to recalculate frecency
|
||||
// starting from most frecent bookmarks.
|
||||
// to -1.
|
||||
stmt = mDBConn.createStatement(
|
||||
"SELECT h.id FROM moz_places h WHERE h.frecency > 0 ");
|
||||
do_check_false(stmt.executeStep());
|
||||
|
@ -23,17 +23,6 @@ const SCHEMES = {
|
||||
"javascript:": false,
|
||||
};
|
||||
|
||||
const TRANSITIONS = [
|
||||
TRANSITION_LINK,
|
||||
TRANSITION_TYPED,
|
||||
TRANSITION_BOOKMARK,
|
||||
TRANSITION_EMBED,
|
||||
TRANSITION_FRAMED_LINK,
|
||||
TRANSITION_REDIRECT_PERMANENT,
|
||||
TRANSITION_REDIRECT_TEMPORARY,
|
||||
TRANSITION_DOWNLOAD,
|
||||
];
|
||||
|
||||
var gRunner;
|
||||
function run_test()
|
||||
{
|
||||
@ -49,9 +38,9 @@ function* step()
|
||||
|
||||
for (let scheme in SCHEMES) {
|
||||
do_print("Testing scheme " + scheme);
|
||||
for (let i = 0; i < TRANSITIONS.length; i++) {
|
||||
let transition = TRANSITIONS[i];
|
||||
do_print("With transition " + transition);
|
||||
for (let t in PlacesUtils.history.TRANSITIONS) {
|
||||
do_print("With transition " + t);
|
||||
let transition = PlacesUtils.history.TRANSITIONS[t];
|
||||
|
||||
let uri = NetUtil.newURI(scheme + "mozilla.org/");
|
||||
|
||||
|
@ -1133,7 +1133,7 @@ tests.push({
|
||||
check: function() {
|
||||
let stmt = mDBConn.createStatement(
|
||||
`SELECT h.id FROM moz_places h
|
||||
JOIN moz_historyvisits v ON v.place_id = h.id AND visit_type NOT IN (0,4,7,8)
|
||||
JOIN moz_historyvisits v ON v.place_id = h.id AND visit_type NOT IN (0,4,7,8,9)
|
||||
GROUP BY h.id HAVING h.visit_count <> count(*)
|
||||
UNION ALL
|
||||
SELECT h.id FROM moz_places h
|
||||
|
Loading…
x
Reference in New Issue
Block a user