Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit 392c65b

Browse files
committed
Bug 1261386 - Avoid history flooding from repeated reloads. r=adw
MozReview-Commit-ID: FhU8nOoNUHb --HG-- extra : rebase_source : ff75adb252b13f4042da49d4572fb807c3d0d823
1 parent 84a96ef commit 392c65b

19 files changed

Lines changed: 220 additions & 191 deletions

browser/app/profile/firefox.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,7 @@ pref("places.frecency.bookmarkVisitBonus", 75);
836836
pref("places.frecency.downloadVisitBonus", 0);
837837
pref("places.frecency.permRedirectVisitBonus", 0);
838838
pref("places.frecency.tempRedirectVisitBonus", 0);
839+
pref("places.frecency.reloadVisitBonus", 0);
839840
pref("places.frecency.defaultVisitBonus", 0);
840841

841842
// bonus (in percent) for place types for frecency calculations

services/sync/modules/engines/history.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -302,8 +302,8 @@ HistoryStore.prototype = {
302302
continue;
303303
}
304304

305-
if (!visit.type || !(visit.type >= PlacesUtils.history.TRANSITION_LINK &&
306-
visit.type <= PlacesUtils.history.TRANSITION_FRAMED_LINK)) {
305+
if (!visit.type ||
306+
!Object.values(PlacesUtils.history.TRANSITIONS).includes(visit.type)) {
307307
this._log.warn("Encountered record with invalid visit type: " +
308308
visit.type + "; ignoring.");
309309
continue;

toolkit/components/places/History.cpp

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,8 +1210,8 @@ class InsertVisitedURIs final: public Runnable
12101210
_place.visitTime);
12111211
NS_ENSURE_SUCCESS(rv, rv);
12121212
uint32_t transitionType = _place.transitionType;
1213-
NS_ASSERTION(transitionType >= nsINavHistoryService::TRANSITION_LINK &&
1214-
transitionType <= nsINavHistoryService::TRANSITION_FRAMED_LINK,
1213+
MOZ_ASSERT(transitionType >= nsINavHistoryService::TRANSITION_LINK &&
1214+
transitionType <= nsINavHistoryService::TRANSITION_RELOAD,
12151215
"Invalid transition type!");
12161216
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("visit_type"),
12171217
transitionType);
@@ -1970,7 +1970,7 @@ History::History()
19701970
: mShuttingDown(false)
19711971
, mShutdownMutex("History::mShutdownMutex")
19721972
, mObservers(VISIT_OBSERVERS_INITIAL_CACHE_LENGTH)
1973-
, mRecentlyVisitedURIsNextIndex(0)
1973+
, mRecentlyVisitedURIs(RECENTLY_VISITED_URIS_SIZE)
19741974
{
19751975
NS_ASSERTION(!gService, "Ruh-roh! This service has already been created!");
19761976
gService = this;
@@ -2406,25 +2406,29 @@ History::Shutdown()
24062406

24072407
void
24082408
History::AppendToRecentlyVisitedURIs(nsIURI* aURI) {
2409-
if (mRecentlyVisitedURIs.Length() < RECENTLY_VISITED_URI_SIZE) {
2410-
// Append a new element while the array is not full.
2411-
mRecentlyVisitedURIs.AppendElement(aURI);
2412-
} else {
2413-
// Otherwise, replace the oldest member.
2414-
mRecentlyVisitedURIsNextIndex %= RECENTLY_VISITED_URI_SIZE;
2415-
mRecentlyVisitedURIs.ElementAt(mRecentlyVisitedURIsNextIndex) = aURI;
2416-
mRecentlyVisitedURIsNextIndex++;
2409+
// Add a new entry, if necessary.
2410+
RecentURIKey* entry = mRecentlyVisitedURIs.GetEntry(aURI);
2411+
if (!entry) {
2412+
entry = mRecentlyVisitedURIs.PutEntry(aURI);
2413+
}
2414+
if (entry) {
2415+
entry->time = PR_Now();
2416+
}
2417+
2418+
// Remove entries older than RECENTLY_VISITED_URIS_MAX_AGE.
2419+
for (auto iter = mRecentlyVisitedURIs.Iter(); !iter.Done(); iter.Next()) {
2420+
RecentURIKey* entry = iter.Get();
2421+
if ((PR_Now() - entry->time) > RECENTLY_VISITED_URIS_MAX_AGE) {
2422+
iter.Remove();
2423+
}
24172424
}
24182425
}
24192426

24202427
inline bool
24212428
History::IsRecentlyVisitedURI(nsIURI* aURI) {
2422-
bool equals = false;
2423-
RecentlyVisitedArray::index_type i;
2424-
for (i = 0; i < mRecentlyVisitedURIs.Length() && !equals; ++i) {
2425-
aURI->Equals(mRecentlyVisitedURIs.ElementAt(i), &equals);
2426-
}
2427-
return equals;
2429+
RecentURIKey* entry = mRecentlyVisitedURIs.GetEntry(aURI);
2430+
// Check if the entry exists and is younger than RECENTLY_VISITED_URIS_MAX_AGE.
2431+
return entry && (PR_Now() - entry->time) < RECENTLY_VISITED_URIS_MAX_AGE;
24282432
}
24292433

24302434
////////////////////////////////////////////////////////////////////////////////
@@ -2466,12 +2470,14 @@ History::VisitURI(nsIURI* aURI,
24662470
return NS_OK;
24672471
}
24682472

2473+
// Do not save a reloaded uri if we have visited the same URI recently.
2474+
bool reload = false;
24692475
if (aLastVisitedURI) {
2470-
bool same;
2471-
rv = aURI->Equals(aLastVisitedURI, &same);
2476+
rv = aURI->Equals(aLastVisitedURI, &reload);
24722477
NS_ENSURE_SUCCESS(rv, rv);
2473-
if (same && IsRecentlyVisitedURI(aURI)) {
2474-
// Do not save refresh visits if we have visited this URI recently.
2478+
if (reload && IsRecentlyVisitedURI(aURI)) {
2479+
// Regardless we must update the stored visit time.
2480+
AppendToRecentlyVisitedURIs(aURI);
24752481
return NS_OK;
24762482
}
24772483
}
@@ -2507,6 +2513,9 @@ History::VisitURI(nsIURI* aURI,
25072513
else if (aFlags & IHistory::REDIRECT_PERMANENT) {
25082514
transitionType = nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT;
25092515
}
2516+
else if (reload) {
2517+
transitionType = nsINavHistoryService::TRANSITION_RELOAD;
2518+
}
25102519
else if ((recentFlags & nsNavHistory::RECENT_TYPED) &&
25112520
!(aFlags & IHistory::UNRECOVERABLE_ERROR)) {
25122521
// 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,
29482957
NS_ENSURE_SUCCESS(rv, rv);
29492958
NS_ENSURE_ARG_RANGE(transitionType,
29502959
nsINavHistoryService::TRANSITION_LINK,
2951-
nsINavHistoryService::TRANSITION_FRAMED_LINK);
2960+
nsINavHistoryService::TRANSITION_RELOAD);
29522961
data.SetTransitionType(transitionType);
29532962
data.hidden = GetHiddenState(false, transitionType);
29542963

toolkit/components/places/History.h

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,14 @@ class ConcurrentStatementsHolder;
3333
#define NS_HISTORYSERVICE_CID \
3434
{0x0937a705, 0x91a6, 0x417a, {0x82, 0x92, 0xb2, 0x2e, 0xb1, 0x0d, 0xa8, 0x6c}}
3535

36-
// Max size of History::mRecentlyVisitedURIs
37-
#define RECENTLY_VISITED_URI_SIZE 8
36+
// Initial size of mRecentlyVisitedURIs.
37+
#define RECENTLY_VISITED_URIS_SIZE 64
38+
// Microseconds after which a visit can be expired from mRecentlyVisitedURIs.
39+
// When an URI is reloaded we only take into account the first visit to it, and
40+
// ignore any subsequent visits, if they happen before this time has elapsed.
41+
// A commonly found case is to reload a page every 5 minutes, so we pick a time
42+
// larger than that.
43+
#define RECENTLY_VISITED_URIS_MAX_AGE 6 * 60 * PR_USEC_PER_SEC
3844

3945
class History final : public IHistory
4046
, public nsIDownloadHistory
@@ -189,14 +195,26 @@ class History final : public IHistory
189195
nsTHashtable<KeyClass> mObservers;
190196

191197
/**
192-
* mRecentlyVisitedURIs remembers URIs which are recently added to the DB,
193-
* to avoid saving these locations repeatedly in a short period.
198+
* mRecentlyVisitedURIs remembers URIs which have been recently added to
199+
* history, to avoid saving these locations repeatedly in a short period.
200+
*/
201+
class RecentURIKey : public nsURIHashKey
202+
{
203+
public:
204+
explicit RecentURIKey(const nsIURI* aURI) : nsURIHashKey(aURI)
205+
{
206+
}
207+
RecentURIKey(const RecentURIKey& aOther) : nsURIHashKey(aOther)
208+
{
209+
NS_NOTREACHED("Do not call me!");
210+
}
211+
PRTime time;
212+
};
213+
nsTHashtable<RecentURIKey> mRecentlyVisitedURIs;
214+
/**
215+
* Whether aURI has been visited "recently".
216+
* See RECENTLY_VISITED_URIS_MAX_AGE.
194217
*/
195-
typedef AutoTArray<nsCOMPtr<nsIURI>, RECENTLY_VISITED_URI_SIZE>
196-
RecentlyVisitedArray;
197-
RecentlyVisitedArray mRecentlyVisitedURIs;
198-
RecentlyVisitedArray::index_type mRecentlyVisitedURIsNextIndex;
199-
200218
bool IsRecentlyVisitedURI(nsIURI* aURI);
201219
};
202220

toolkit/components/places/History.jsm

Lines changed: 55 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
* - date: (Date)
4141
* The time the visit occurred.
4242
* - transition: (number)
43-
* How the user reached the page. See constants `TRANSITION_*`
43+
* How the user reached the page. See constants `TRANSITIONS.*`
4444
* for the possible transition types.
4545
* - referrer: (URL)
4646
* or (nsIURI)
@@ -408,51 +408,58 @@ this.History = Object.freeze({
408408
* objects.
409409
*/
410410

411-
/**
412-
* The user followed a link and got a new toplevel window.
413-
*/
414-
TRANSITION_LINK: Ci.nsINavHistoryService.TRANSITION_LINK,
415-
416-
/**
417-
* The user typed the page's URL in the URL bar or selected it from
418-
* URL bar autocomplete results, clicked on it from a history query
419-
* (from the History sidebar, History menu, or history query in the
420-
* personal toolbar or Places organizer.
421-
*/
422-
TRANSITION_TYPED: Ci.nsINavHistoryService.TRANSITION_TYPED,
423-
424-
/**
425-
* The user followed a bookmark to get to the page.
426-
*/
427-
TRANSITION_BOOKMARK: Ci.nsINavHistoryService.TRANSITION_BOOKMARK,
428-
429-
/**
430-
* Some inner content is loaded. This is true of all images on a
431-
* page, and the contents of the iframe. It is also true of any
432-
* content in a frame if the user did not explicitly follow a link
433-
* to get there.
434-
*/
435-
TRANSITION_EMBED: Ci.nsINavHistoryService.TRANSITION_EMBED,
436-
437-
/**
438-
* Set when the transition was a permanent redirect.
439-
*/
440-
TRANSITION_REDIRECT_PERMANENT: Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT,
441-
442-
/**
443-
* Set when the transition was a temporary redirect.
444-
*/
445-
TRANSITION_REDIRECT_TEMPORARY: Ci.nsINavHistoryService.TRANSITION_REDIRECT_TEMPORARY,
446-
447-
/**
448-
* Set when the transition is a download.
449-
*/
450-
TRANSITION_DOWNLOAD: Ci.nsINavHistoryService.TRANSITION_REDIRECT_DOWNLOAD,
451-
452-
/**
453-
* The user followed a link and got a visit in a frame.
454-
*/
455-
TRANSITION_FRAMED_LINK: Ci.nsINavHistoryService.TRANSITION_FRAMED_LINK,
411+
TRANSITIONS: {
412+
/**
413+
* The user followed a link and got a new toplevel window.
414+
*/
415+
LINK: Ci.nsINavHistoryService.TRANSITION_LINK,
416+
417+
/**
418+
* The user typed the page's URL in the URL bar or selected it from
419+
* URL bar autocomplete results, clicked on it from a history query
420+
* (from the History sidebar, History menu, or history query in the
421+
* personal toolbar or Places organizer.
422+
*/
423+
TYPED: Ci.nsINavHistoryService.TRANSITION_TYPED,
424+
425+
/**
426+
* The user followed a bookmark to get to the page.
427+
*/
428+
BOOKMARK: Ci.nsINavHistoryService.TRANSITION_BOOKMARK,
429+
430+
/**
431+
* Some inner content is loaded. This is true of all images on a
432+
* page, and the contents of the iframe. It is also true of any
433+
* content in a frame if the user did not explicitly follow a link
434+
* to get there.
435+
*/
436+
EMBED: Ci.nsINavHistoryService.TRANSITION_EMBED,
437+
438+
/**
439+
* Set when the transition was a permanent redirect.
440+
*/
441+
REDIRECT_PERMANENT: Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT,
442+
443+
/**
444+
* Set when the transition was a temporary redirect.
445+
*/
446+
REDIRECT_TEMPORARY: Ci.nsINavHistoryService.TRANSITION_REDIRECT_TEMPORARY,
447+
448+
/**
449+
* Set when the transition is a download.
450+
*/
451+
DOWNLOAD: Ci.nsINavHistoryService.TRANSITION_DOWNLOAD,
452+
453+
/**
454+
* The user followed a link and got a visit in a frame.
455+
*/
456+
FRAMED_LINK: Ci.nsINavHistoryService.TRANSITION_FRAMED_LINK,
457+
458+
/**
459+
* The user reloaded a page.
460+
*/
461+
RELOAD: Ci.nsINavHistoryService.TRANSITION_RELOAD,
462+
},
456463
});
457464

458465
/**
@@ -484,7 +491,7 @@ function validatePageInfo(pageInfo) {
484491
for (let inVisit of pageInfo.visits) {
485492
let visit = {
486493
date: new Date(),
487-
transition: inVisit.transition || History.TRANSITION_LINK,
494+
transition: inVisit.transition || History.TRANSITIONS.LINK,
488495
};
489496

490497
if (!isValidTransitionType(visit.transition)) {
@@ -541,16 +548,7 @@ function convertForUpdatePlaces(pageInfo) {
541548
* @return (Boolean)
542549
*/
543550
function isValidTransitionType(transitionType) {
544-
return [
545-
History.TRANSITION_LINK,
546-
History.TRANSITION_TYPED,
547-
History.TRANSITION_BOOKMARK,
548-
History.TRANSITION_EMBED,
549-
History.TRANSITION_REDIRECT_PERMANENT,
550-
History.TRANSITION_REDIRECT_TEMPORARY,
551-
History.TRANSITION_DOWNLOAD,
552-
History.TRANSITION_FRAMED_LINK
553-
].includes(transitionType);
551+
return Object.values(History.TRANSITIONS).includes(transitionType);
554552
}
555553

556554
/**

toolkit/components/places/PlacesDBUtils.jsm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -690,13 +690,13 @@ this.PlacesDBUtils = {
690690
let fixVisitStats = DBConn.createAsyncStatement(
691691
`UPDATE moz_places
692692
SET visit_count = (SELECT count(*) FROM moz_historyvisits
693-
WHERE place_id = moz_places.id AND visit_type NOT IN (0,4,7,8)),
693+
WHERE place_id = moz_places.id AND visit_type NOT IN (0,4,7,8,9)),
694694
last_visit_date = (SELECT MAX(visit_date) FROM moz_historyvisits
695695
WHERE place_id = moz_places.id)
696696
WHERE id IN (
697697
SELECT h.id FROM moz_places h
698698
WHERE visit_count <> (SELECT count(*) FROM moz_historyvisits v
699-
WHERE v.place_id = h.id AND visit_type NOT IN (0,4,7,8))
699+
WHERE v.place_id = h.id AND visit_type NOT IN (0,4,7,8,9))
700700
OR last_visit_date <> (SELECT MAX(visit_date) FROM moz_historyvisits v
701701
WHERE v.place_id = h.id)
702702
)`);

0 commit comments

Comments
 (0)