Bug 1866777 - Disable test_race_cache_with_network.js on windows opt for frequent...
[gecko.git] / netwerk / dns / HostRecordQueue.cpp
blob6e8fd5488fb6a9044eb55700deb1a67ea2e6702f
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"
10 namespace mozilla {
11 namespace net {
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);
28 break;
30 case AddrHostRecord::DNS_PRIORITY_MEDIUM:
31 mMediumQ.insertBack(aRec);
32 break;
34 case AddrHostRecord::DNS_PRIORITY_LOW:
35 mLowQ.insertBack(aRec);
36 break;
38 mPendingCount++;
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
57 // for release users.
58 aRec->remove();
59 if (inEvictionQ) {
60 MOZ_DIAGNOSTIC_ASSERT(mEvictionQSize > 0);
61 mEvictionQSize--;
62 } else if (inHighQ || inMediumQ || inLowQ) {
63 MOZ_DIAGNOSTIC_ASSERT(mPendingCount > 0);
64 mPendingCount--;
67 mEvictionQ.insertBack(aRec);
68 if (mEvictionQSize < aMaxCacheEntries) {
69 mEvictionQSize++;
70 } else {
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));
81 } else {
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));
90 } else {
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()) {
102 return;
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
115 aRec->remove();
116 if (inEvictionQ) {
117 MOZ_DIAGNOSTIC_ASSERT(mEvictionQSize > 0);
118 mEvictionQSize--;
119 } else if (inHighQ || inMediumQ || inLowQ) {
120 MOZ_DIAGNOSTIC_ASSERT(mPendingCount > 0);
121 mPendingCount--;
125 void HostRecordQueue::FlushEvictionQ(
126 nsRefPtrHashtable<nsGenericHashKey<nsHostKey>, nsHostRecord>& aDB,
127 const MutexAutoLock& aProofOfLock) {
128 mEvictionQSize = 0;
130 // Clear the evictionQ and remove all its corresponding entries from
131 // the cache first
132 if (!mEvictionQ.isEmpty()) {
133 for (const RefPtr<nsHostRecord>& rec : mEvictionQ) {
134 rec->Cancel();
135 aDB.Remove(*static_cast<nsHostKey*>(rec));
137 mEvictionQ.clear();
141 void HostRecordQueue::MaybeRemoveFromQ(nsHostRecord* aRec,
142 const MutexAutoLock& aProofOfLock) {
143 if (!aRec->isInList()) {
144 return;
147 if (mHighQ.contains(aRec) || mMediumQ.contains(aRec) ||
148 mLowQ.contains(aRec)) {
149 mPendingCount--;
150 } else if (mEvictionQ.contains(aRec)) {
151 mEvictionQSize--;
152 } else {
153 MOZ_ASSERT(false, "record is in other queue");
156 aRec->remove();
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");
165 return;
168 aRec->remove();
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();
183 if (rec) {
184 mPendingCount--;
187 return rec.forget();
190 void HostRecordQueue::ClearAll(
191 const std::function<void(nsHostRecord*)>& aCallback,
192 const MutexAutoLock& aProofOfLock) {
193 mPendingCount = 0;
195 auto clearPendingQ = [&](LinkedList<RefPtr<nsHostRecord>>& aPendingQ) {
196 if (aPendingQ.isEmpty()) {
197 return;
200 // loop through pending queue, erroring out pending lookups.
201 for (const RefPtr<nsHostRecord>& rec : aPendingQ) {
202 rec->Cancel();
203 aCallback(rec);
205 aPendingQ.clear();
208 clearPendingQ(mHighQ);
209 clearPendingQ(mMediumQ);
210 clearPendingQ(mLowQ);
212 mEvictionQSize = 0;
213 if (!mEvictionQ.isEmpty()) {
214 for (const RefPtr<nsHostRecord>& rec : mEvictionQ) {
215 rec->Cancel();
219 mEvictionQ.clear();
222 } // namespace net
223 } // namespace mozilla