Bug 1795082 - Part 2/2: Drop post-processing from getURL() r=zombie
[gecko.git] / netwerk / protocol / http / PendingTransactionQueue.cpp
blob9598769cc82d436b8f94b3f4d27298e86abb7fc5
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 // HttpLog.h should generally be included first
7 #include "HttpLog.h"
9 // Log on level :5, instead of default :4.
10 #undef LOG
11 #define LOG(args) LOG5(args)
12 #undef LOG_ENABLED
13 #define LOG_ENABLED() LOG5_ENABLED()
15 #include "PendingTransactionQueue.h"
16 #include "nsHttpHandler.h"
17 #include "mozilla/ChaosMode.h"
19 namespace mozilla {
20 namespace net {
22 static uint64_t TabIdForQueuing(nsAHttpTransaction* transaction) {
23 return gHttpHandler->ActiveTabPriority() ? transaction->BrowserId() : 0;
26 // This function decides the transaction's order in the pending queue.
27 // Given two transactions t1 and t2, returning true means that t2 is
28 // more important than t1 and thus should be dispatched first.
29 static bool TransactionComparator(nsHttpTransaction* t1,
30 nsHttpTransaction* t2) {
31 bool t1Blocking =
32 t1->Caps() & (NS_HTTP_LOAD_AS_BLOCKING | NS_HTTP_LOAD_UNBLOCKED);
33 bool t2Blocking =
34 t2->Caps() & (NS_HTTP_LOAD_AS_BLOCKING | NS_HTTP_LOAD_UNBLOCKED);
36 if (t1Blocking > t2Blocking) {
37 return false;
40 if (t2Blocking > t1Blocking) {
41 return true;
44 return t1->Priority() >= t2->Priority();
47 void PendingTransactionQueue::InsertTransactionNormal(
48 PendingTransactionInfo* info,
49 bool aInsertAsFirstForTheSamePriority /*= false*/) {
50 LOG(
51 ("PendingTransactionQueue::InsertTransactionNormal"
52 " trans=%p, bid=%" PRIu64 "\n",
53 info->Transaction(), info->Transaction()->BrowserId()));
55 uint64_t windowId = TabIdForQueuing(info->Transaction());
56 nsTArray<RefPtr<PendingTransactionInfo>>* const infoArray =
57 mPendingTransactionTable.GetOrInsertNew(windowId);
59 // XXX At least if a new array was empty before, this isn't efficient, as it
60 // does an insert-sort. It would be better to just append all elements and
61 // then sort.
62 InsertTransactionSorted(*infoArray, info, aInsertAsFirstForTheSamePriority);
65 void PendingTransactionQueue::InsertTransactionSorted(
66 nsTArray<RefPtr<PendingTransactionInfo>>& pendingQ,
67 PendingTransactionInfo* pendingTransInfo,
68 bool aInsertAsFirstForTheSamePriority /*= false*/) {
69 // insert the transaction into the front of the queue based on following
70 // rules:
71 // 1. The transaction has NS_HTTP_LOAD_AS_BLOCKING or NS_HTTP_LOAD_UNBLOCKED.
72 // 2. The transaction's priority is higher.
74 // search in reverse order under the assumption that many of the
75 // existing transactions will have the same priority (usually 0).
77 nsHttpTransaction* trans = pendingTransInfo->Transaction();
79 for (int32_t i = pendingQ.Length() - 1; i >= 0; --i) {
80 nsHttpTransaction* t = pendingQ[i]->Transaction();
81 if (TransactionComparator(trans, t)) {
82 if (ChaosMode::isActive(ChaosFeature::NetworkScheduling) ||
83 aInsertAsFirstForTheSamePriority) {
84 int32_t samePriorityCount;
85 for (samePriorityCount = 0; i - samePriorityCount >= 0;
86 ++samePriorityCount) {
87 if (pendingQ[i - samePriorityCount]->Transaction()->Priority() !=
88 trans->Priority()) {
89 break;
92 if (aInsertAsFirstForTheSamePriority) {
93 i -= samePriorityCount;
94 } else {
95 // skip over 0...all of the elements with the same priority.
96 i -= ChaosMode::randomUint32LessThan(samePriorityCount + 1);
99 pendingQ.InsertElementAt(i + 1, pendingTransInfo);
100 return;
103 pendingQ.InsertElementAt(0, pendingTransInfo);
106 void PendingTransactionQueue::InsertTransaction(
107 PendingTransactionInfo* pendingTransInfo,
108 bool aInsertAsFirstForTheSamePriority /* = false */) {
109 if (pendingTransInfo->Transaction()->Caps() & NS_HTTP_URGENT_START) {
110 LOG(
111 (" adding transaction to pending queue "
112 "[trans=%p urgent-start-count=%zu]\n",
113 pendingTransInfo->Transaction(), mUrgentStartQ.Length() + 1));
114 // put this transaction on the urgent-start queue...
115 InsertTransactionSorted(mUrgentStartQ, pendingTransInfo);
116 } else {
117 LOG(
118 (" adding transaction to pending queue "
119 "[trans=%p pending-count=%zu]\n",
120 pendingTransInfo->Transaction(), PendingQueueLength() + 1));
121 // put this transaction on the pending queue...
122 InsertTransactionNormal(pendingTransInfo);
126 nsTArray<RefPtr<PendingTransactionInfo>>*
127 PendingTransactionQueue::GetTransactionPendingQHelper(
128 nsAHttpTransaction* trans) {
129 nsTArray<RefPtr<PendingTransactionInfo>>* pendingQ = nullptr;
130 int32_t caps = trans->Caps();
131 if (caps & NS_HTTP_URGENT_START) {
132 pendingQ = &(mUrgentStartQ);
133 } else {
134 pendingQ = mPendingTransactionTable.Get(TabIdForQueuing(trans));
136 return pendingQ;
139 void PendingTransactionQueue::AppendPendingUrgentStartQ(
140 nsTArray<RefPtr<PendingTransactionInfo>>& result) {
141 result.InsertElementsAt(0, mUrgentStartQ.Elements(), mUrgentStartQ.Length());
142 mUrgentStartQ.Clear();
145 void PendingTransactionQueue::AppendPendingQForFocusedWindow(
146 uint64_t windowId, nsTArray<RefPtr<PendingTransactionInfo>>& result,
147 uint32_t maxCount) {
148 nsTArray<RefPtr<PendingTransactionInfo>>* infoArray = nullptr;
149 if (!mPendingTransactionTable.Get(windowId, &infoArray)) {
150 result.Clear();
151 return;
154 uint32_t countToAppend = maxCount;
155 countToAppend = countToAppend > infoArray->Length() || countToAppend == 0
156 ? infoArray->Length()
157 : countToAppend;
159 result.InsertElementsAt(result.Length(), infoArray->Elements(),
160 countToAppend);
161 infoArray->RemoveElementsAt(0, countToAppend);
163 LOG(
164 ("PendingTransactionQueue::AppendPendingQForFocusedWindow, "
165 "pendingQ count=%zu window.count=%zu for focused window (id=%" PRIu64
166 ")\n",
167 result.Length(), infoArray->Length(), windowId));
170 void PendingTransactionQueue::AppendPendingQForNonFocusedWindows(
171 uint64_t windowId, nsTArray<RefPtr<PendingTransactionInfo>>& result,
172 uint32_t maxCount) {
173 // XXX Adjust the order of transactions in a smarter manner.
174 uint32_t totalCount = 0;
175 for (const auto& entry : mPendingTransactionTable) {
176 if (windowId && entry.GetKey() == windowId) {
177 continue;
180 uint32_t count = 0;
181 for (; count < entry.GetWeak()->Length(); ++count) {
182 if (maxCount && totalCount == maxCount) {
183 break;
186 // Because elements in |result| could come from multiple penndingQ,
187 // call |InsertTransactionSorted| to make sure the order is correct.
188 InsertTransactionSorted(result, entry.GetWeak()->ElementAt(count));
189 ++totalCount;
191 entry.GetWeak()->RemoveElementsAt(0, count);
193 if (maxCount && totalCount == maxCount) {
194 if (entry.GetWeak()->Length()) {
195 // There are still some pending transactions for background
196 // tabs but we limit their dispatch. This is considered as
197 // an active tab optimization.
198 nsHttp::NotifyActiveTabLoadOptimization();
200 break;
205 void PendingTransactionQueue::ReschedTransaction(nsHttpTransaction* aTrans) {
206 nsTArray<RefPtr<PendingTransactionInfo>>* pendingQ =
207 GetTransactionPendingQHelper(aTrans);
209 int32_t index =
210 pendingQ ? pendingQ->IndexOf(aTrans, 0, PendingComparator()) : -1;
211 if (index >= 0) {
212 RefPtr<PendingTransactionInfo> pendingTransInfo = (*pendingQ)[index];
213 pendingQ->RemoveElementAt(index);
214 InsertTransactionSorted(*pendingQ, pendingTransInfo);
218 void PendingTransactionQueue::RemoveEmptyPendingQ() {
219 for (auto it = mPendingTransactionTable.Iter(); !it.Done(); it.Next()) {
220 if (it.UserData()->IsEmpty()) {
221 it.Remove();
226 size_t PendingTransactionQueue::PendingQueueLength() const {
227 size_t length = 0;
228 for (const auto& data : mPendingTransactionTable.Values()) {
229 length += data->Length();
232 return length;
235 size_t PendingTransactionQueue::PendingQueueLengthForWindow(
236 uint64_t windowId) const {
237 auto* pendingQ = mPendingTransactionTable.Get(windowId);
238 return (pendingQ) ? pendingQ->Length() : 0;
241 size_t PendingTransactionQueue::UrgentStartQueueLength() {
242 return mUrgentStartQ.Length();
245 void PendingTransactionQueue::PrintPendingQ() {
246 LOG(("urgent queue ["));
247 for (const auto& info : mUrgentStartQ) {
248 LOG((" %p", info->Transaction()));
250 for (const auto& entry : mPendingTransactionTable) {
251 LOG(("] window id = %" PRIx64 " queue [", entry.GetKey()));
252 for (const auto& info : *entry.GetWeak()) {
253 LOG((" %p", info->Transaction()));
256 LOG(("]"));
259 void PendingTransactionQueue::Compact() {
260 mUrgentStartQ.Compact();
261 for (const auto& data : mPendingTransactionTable.Values()) {
262 data->Compact();
266 void PendingTransactionQueue::CancelAllTransactions(nsresult reason) {
267 for (const auto& pendingTransInfo : mUrgentStartQ) {
268 LOG(("PendingTransactionQueue::CancelAllTransactions %p\n",
269 pendingTransInfo->Transaction()));
270 pendingTransInfo->Transaction()->Close(reason);
272 mUrgentStartQ.Clear();
274 for (const auto& data : mPendingTransactionTable.Values()) {
275 for (const auto& pendingTransInfo : *data) {
276 LOG(("PendingTransactionQueue::CancelAllTransactions %p\n",
277 pendingTransInfo->Transaction()));
278 pendingTransInfo->Transaction()->Close(reason);
280 data->Clear();
283 mPendingTransactionTable.Clear();
286 } // namespace net
287 } // namespace mozilla