1 /* vim:set ts=4 sw=2 sts=2 et cin: */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "HostRecordQueue.h"
7 #include "mozilla/Telemetry.h"
8 #include "nsQueryObject.h"
13 void HostRecordQueue::InsertRecord(nsHostRecord
* aRec
,
14 nsIDNSService::DNSFlags aFlags
,
15 const MutexAutoLock
& aProofOfLock
) {
16 if (aRec
->isInList()) {
17 MOZ_DIAGNOSTIC_ASSERT(!mEvictionQ
.contains(aRec
),
18 "Already in eviction queue");
19 MOZ_DIAGNOSTIC_ASSERT(!mHighQ
.contains(aRec
), "Already in high queue");
20 MOZ_DIAGNOSTIC_ASSERT(!mMediumQ
.contains(aRec
), "Already in med queue");
21 MOZ_DIAGNOSTIC_ASSERT(!mLowQ
.contains(aRec
), "Already in low queue");
22 MOZ_DIAGNOSTIC_ASSERT(false, "Already on some other queue?");
25 switch (AddrHostRecord::GetPriority(aFlags
)) {
26 case AddrHostRecord::DNS_PRIORITY_HIGH
:
27 mHighQ
.insertBack(aRec
);
30 case AddrHostRecord::DNS_PRIORITY_MEDIUM
:
31 mMediumQ
.insertBack(aRec
);
34 case AddrHostRecord::DNS_PRIORITY_LOW
:
35 mLowQ
.insertBack(aRec
);
41 void HostRecordQueue::AddToEvictionQ(
42 nsHostRecord
* aRec
, uint32_t aMaxCacheEntries
,
43 nsRefPtrHashtable
<nsGenericHashKey
<nsHostKey
>, nsHostRecord
>& aDB
,
44 const MutexAutoLock
& aProofOfLock
) {
45 if (aRec
->isInList()) {
46 bool inEvictionQ
= mEvictionQ
.contains(aRec
);
47 MOZ_DIAGNOSTIC_ASSERT(!inEvictionQ
, "Already in eviction queue");
48 bool inHighQ
= mHighQ
.contains(aRec
);
49 MOZ_DIAGNOSTIC_ASSERT(!inHighQ
, "Already in high queue");
50 bool inMediumQ
= mMediumQ
.contains(aRec
);
51 MOZ_DIAGNOSTIC_ASSERT(!inMediumQ
, "Already in med queue");
52 bool inLowQ
= mLowQ
.contains(aRec
);
53 MOZ_DIAGNOSTIC_ASSERT(!inLowQ
, "Already in low queue");
54 MOZ_DIAGNOSTIC_ASSERT(false, "Already on some other queue?");
56 // Bug 1678117 - it's not clear why this can happen, but let's fix it
60 MOZ_DIAGNOSTIC_ASSERT(mEvictionQSize
> 0);
62 } else if (inHighQ
|| inMediumQ
|| inLowQ
) {
63 MOZ_DIAGNOSTIC_ASSERT(mPendingCount
> 0);
67 mEvictionQ
.insertBack(aRec
);
68 if (mEvictionQSize
< aMaxCacheEntries
) {
71 // remove first element on mEvictionQ
72 RefPtr
<nsHostRecord
> head
= mEvictionQ
.popFirst();
73 aDB
.Remove(*static_cast<nsHostKey
*>(head
.get()));
75 if (!head
->negative
) {
76 // record the age of the entry upon eviction.
77 TimeDuration age
= TimeStamp::NowLoRes() - head
->mValidStart
;
78 if (aRec
->IsAddrRecord()) {
79 Telemetry::Accumulate(Telemetry::DNS_CLEANUP_AGE
,
80 static_cast<uint32_t>(age
.ToSeconds() / 60));
82 Telemetry::Accumulate(Telemetry::DNS_BY_TYPE_CLEANUP_AGE
,
83 static_cast<uint32_t>(age
.ToSeconds() / 60));
85 if (head
->CheckExpiration(TimeStamp::Now()) !=
86 nsHostRecord::EXP_EXPIRED
) {
87 if (aRec
->IsAddrRecord()) {
88 Telemetry::Accumulate(Telemetry::DNS_PREMATURE_EVICTION
,
89 static_cast<uint32_t>(age
.ToSeconds() / 60));
91 Telemetry::Accumulate(Telemetry::DNS_BY_TYPE_PREMATURE_EVICTION
,
92 static_cast<uint32_t>(age
.ToSeconds() / 60));
99 void HostRecordQueue::MaybeRenewHostRecord(nsHostRecord
* aRec
,
100 const MutexAutoLock
& aProofOfLock
) {
101 if (!aRec
->isInList()) {
105 bool inEvictionQ
= mEvictionQ
.contains(aRec
);
106 MOZ_DIAGNOSTIC_ASSERT(inEvictionQ
, "Should be in eviction queue");
107 bool inHighQ
= mHighQ
.contains(aRec
);
108 MOZ_DIAGNOSTIC_ASSERT(!inHighQ
, "Already in high queue");
109 bool inMediumQ
= mMediumQ
.contains(aRec
);
110 MOZ_DIAGNOSTIC_ASSERT(!inMediumQ
, "Already in med queue");
111 bool inLowQ
= mLowQ
.contains(aRec
);
112 MOZ_DIAGNOSTIC_ASSERT(!inLowQ
, "Already in low queue");
114 // we're already on the eviction queue. This is a renewal
117 MOZ_DIAGNOSTIC_ASSERT(mEvictionQSize
> 0);
119 } else if (inHighQ
|| inMediumQ
|| inLowQ
) {
120 MOZ_DIAGNOSTIC_ASSERT(mPendingCount
> 0);
125 void HostRecordQueue::FlushEvictionQ(
126 nsRefPtrHashtable
<nsGenericHashKey
<nsHostKey
>, nsHostRecord
>& aDB
,
127 const MutexAutoLock
& aProofOfLock
) {
130 // Clear the evictionQ and remove all its corresponding entries from
132 if (!mEvictionQ
.isEmpty()) {
133 for (const RefPtr
<nsHostRecord
>& rec
: mEvictionQ
) {
135 aDB
.Remove(*static_cast<nsHostKey
*>(rec
));
141 void HostRecordQueue::MaybeRemoveFromQ(nsHostRecord
* aRec
,
142 const MutexAutoLock
& aProofOfLock
) {
143 if (!aRec
->isInList()) {
147 if (mHighQ
.contains(aRec
) || mMediumQ
.contains(aRec
) ||
148 mLowQ
.contains(aRec
)) {
150 } else if (mEvictionQ
.contains(aRec
)) {
153 MOZ_ASSERT(false, "record is in other queue");
159 void HostRecordQueue::MoveToAnotherPendingQ(nsHostRecord
* aRec
,
160 nsIDNSService::DNSFlags aFlags
,
161 const MutexAutoLock
& aProofOfLock
) {
162 if (!(mHighQ
.contains(aRec
) || mMediumQ
.contains(aRec
) ||
163 mLowQ
.contains(aRec
))) {
164 MOZ_ASSERT(false, "record is not in the pending queue");
169 InsertRecord(aRec
, aFlags
, aProofOfLock
);
172 already_AddRefed
<nsHostRecord
> HostRecordQueue::Dequeue(
173 bool aHighQOnly
, const MutexAutoLock
& aProofOfLock
) {
174 RefPtr
<nsHostRecord
> rec
;
175 if (!mHighQ
.isEmpty()) {
176 rec
= mHighQ
.popFirst();
177 } else if (!mMediumQ
.isEmpty() && !aHighQOnly
) {
178 rec
= mMediumQ
.popFirst();
179 } else if (!mLowQ
.isEmpty() && !aHighQOnly
) {
180 rec
= mLowQ
.popFirst();
190 void HostRecordQueue::ClearAll(
191 const std::function
<void(nsHostRecord
*)>& aCallback
,
192 const MutexAutoLock
& aProofOfLock
) {
195 auto clearPendingQ
= [&](LinkedList
<RefPtr
<nsHostRecord
>>& aPendingQ
) {
196 if (aPendingQ
.isEmpty()) {
200 // loop through pending queue, erroring out pending lookups.
201 for (const RefPtr
<nsHostRecord
>& rec
: aPendingQ
) {
208 clearPendingQ(mHighQ
);
209 clearPendingQ(mMediumQ
);
210 clearPendingQ(mLowQ
);
213 if (!mEvictionQ
.isEmpty()) {
214 for (const RefPtr
<nsHostRecord
>& rec
: mEvictionQ
) {
223 } // namespace mozilla