Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(178)

Side by Side Diff: net/http/broken_alternative_services.cc

Issue 2898983006: Fix and refactor HttpServerPropertiesImpl's alternative services brokenness expiration behavior (Closed)
Patch Set: Inlined all uses of BROKEN_ALT_SVC_EXPIRATION_DELAY. Unrolled loops to reduce logic in BrokenAltern… Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/http/broken_alternative_services.h"
6
7 #include "base/memory/singleton.h"
8 #include "base/time/tick_clock.h"
9 #include "base/time/time.h"
10 #include "net/http/http_server_properties_impl.h"
11
12 namespace net {
13
14 namespace {
15
16 // Initial delay for broken alternative services.
17 const uint64_t kBrokenAlternativeProtocolDelaySecs = 300;
18 // Subsequent failures result in exponential (base 2) backoff.
19 // Limit binary shift to limit delay to approximately 2 days.
20 const int kBrokenDelayMaxShift = 9;
21
22 base::TimeDelta ComputeBrokenAlternativeServiceExpirationDelay(
23 int broken_count) {
24 DCHECK(broken_count >= 0);
Zhongyi Shi 2017/05/31 18:54:14 nit: DCHECK_GE(borken_count, 0);
wangyix1 2017/06/01 20:05:48 Done.
25 if (broken_count > kBrokenDelayMaxShift)
26 broken_count = kBrokenDelayMaxShift;
27 return base::TimeDelta::FromSeconds(kBrokenAlternativeProtocolDelaySecs) *
28 (1 << broken_count);
29 }
30
31 } // namespace
32
33 BrokenAlternativeServices::BrokenAlternativeServices(Delegate* delegate,
34 base::TickClock* clock)
35 : delegate_(delegate),
36 clock_(clock),
37 recently_broken_alternative_services_(
38 RecentlyBrokenAlternativeServices::NO_AUTO_EVICT),
39 weak_ptr_factory_(this) {
40 DCHECK(delegate_);
41 DCHECK(clock_);
42 }
43
44 BrokenAlternativeServices::~BrokenAlternativeServices() {}
45
46 void BrokenAlternativeServices::MarkAlternativeServiceBroken(
47 const AlternativeService& alternative_service) {
48 // Empty host means use host of origin, callers are supposed to substitute.
49 DCHECK(!alternative_service.host.empty());
50 DCHECK_NE(kProtoUnknown, alternative_service.protocol);
51
52 auto it = recently_broken_alternative_services_.Get(alternative_service);
53 int broken_count = 0;
54 if (it == recently_broken_alternative_services_.end()) {
55 recently_broken_alternative_services_.Put(alternative_service, 1);
56 } else {
57 broken_count = it->second++;
58 }
59 base::TimeTicks expiration =
60 clock_->NowTicks() +
61 ComputeBrokenAlternativeServiceExpirationDelay(broken_count);
62 // Return if alternative service is already in expiration queue.
63 BrokenAlternativeServiceList::iterator list_it;
64 if (!AddToBrokenAlternativeServiceListAndMap(alternative_service, expiration,
65 &list_it)) {
66 return;
67 }
68
69 // If this is now the first entry in the list (i.e. |alternative_service| is
70 // the next alt svc to expire), schedule an expiration task for it.
71 if (list_it == broken_alternative_service_list_.begin()) {
72 ScheduleBrokenAlternateProtocolMappingsExpiration();
73 }
74 }
75
76 void BrokenAlternativeServices::MarkAlternativeServiceRecentlyBroken(
77 const AlternativeService& alternative_service) {
78 DCHECK_NE(kProtoUnknown, alternative_service.protocol);
79 if (recently_broken_alternative_services_.Get(alternative_service) ==
80 recently_broken_alternative_services_.end()) {
81 recently_broken_alternative_services_.Put(alternative_service, 1);
82 }
83 }
84
85 bool BrokenAlternativeServices::IsAlternativeServiceBroken(
86 const AlternativeService& alternative_service) const {
87 // Empty host means use host of origin, callers are supposed to substitute.
88 DCHECK(!alternative_service.host.empty());
89 return broken_alternative_service_map_.find(alternative_service) !=
90 broken_alternative_service_map_.end();
91 }
92
93 bool BrokenAlternativeServices::WasAlternativeServiceRecentlyBroken(
94 const AlternativeService& alternative_service) {
95 return recently_broken_alternative_services_.Get(alternative_service) !=
96 recently_broken_alternative_services_.end();
97 }
98
99 void BrokenAlternativeServices::ConfirmAlternativeService(
100 const AlternativeService& alternative_service) {
101 DCHECK_NE(kProtoUnknown, alternative_service.protocol);
102
103 // Remove |alternative_service| from |alternative_service_list_| and
104 // |alternative_service_map_|.
105 auto map_it = broken_alternative_service_map_.find(alternative_service);
106 if (map_it != broken_alternative_service_map_.end()) {
107 broken_alternative_service_list_.erase(map_it->second);
108 broken_alternative_service_map_.erase(map_it);
109 }
110
111 auto it = recently_broken_alternative_services_.Get(alternative_service);
112 if (it != recently_broken_alternative_services_.end()) {
113 recently_broken_alternative_services_.Erase(it);
114 }
115 }
116
117 bool BrokenAlternativeServices::AddToBrokenAlternativeServiceListAndMap(
118 const AlternativeService& alternative_service,
119 base::TimeTicks expiration,
120 BrokenAlternativeServiceList::iterator* it) {
121 DCHECK(it);
122
123 auto map_it = broken_alternative_service_map_.find(alternative_service);
124 if (map_it != broken_alternative_service_map_.end())
125 return false;
126
127 // Iterate from end of |broken_alternative_service_list_| to find where to
128 // insert it to keep the list sorted by expiration time.
129 auto list_it = broken_alternative_service_list_.end();
130 while (list_it != broken_alternative_service_list_.begin()) {
131 --list_it;
132 if (list_it->expiration <= expiration) {
133 ++list_it;
134 break;
135 }
136 }
137
138 // Insert |alternative_service| into the list and the map
139 list_it = broken_alternative_service_list_.insert(
140 list_it, BrokenAltSvcExpireInfo(alternative_service, expiration));
141 broken_alternative_service_map_.insert(
142 std::make_pair(alternative_service, list_it));
143
144 *it = list_it;
145 return true;
146 }
147
148 void BrokenAlternativeServices::ExpireBrokenAlternateProtocolMappings() {
149 base::TimeTicks now = clock_->NowTicks();
150
151 while (!broken_alternative_service_list_.empty()) {
152 auto it = broken_alternative_service_list_.begin();
153 if (now < it->expiration) {
154 break;
155 }
156
157 delegate_->OnExpireBrokenAlternativeService(it->alternative_service);
158
159 broken_alternative_service_map_.erase(it->alternative_service);
160 broken_alternative_service_list_.erase(it);
161 }
162
163 if (!broken_alternative_service_list_.empty())
164 ScheduleBrokenAlternateProtocolMappingsExpiration();
165 }
166
167 void BrokenAlternativeServices ::
168 ScheduleBrokenAlternateProtocolMappingsExpiration() {
169 DCHECK(!broken_alternative_service_list_.empty());
170 base::TimeTicks now = clock_->NowTicks();
171 base::TimeTicks when = broken_alternative_service_list_.front().expiration;
172 base::TimeDelta delay = when > now ? when - now : base::TimeDelta();
173 expiration_timer_.Stop();
174 expiration_timer_.Start(
175 FROM_HERE, delay,
176 base::Bind(
177 &BrokenAlternativeServices ::ExpireBrokenAlternateProtocolMappings,
178 weak_ptr_factory_.GetWeakPtr()));
179 }
180
181 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698