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

Side by Side Diff: google_apis/gcm/engine/connection_factory_impl.cc

Issue 160703002: [GCM] Track connection failures properly (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Self review and add connection success rate Created 6 years, 10 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "google_apis/gcm/engine/connection_factory_impl.h" 5 #include "google_apis/gcm/engine/connection_factory_impl.h"
6 6
7 #include "base/message_loop/message_loop.h" 7 #include "base/message_loop/message_loop.h"
8 #include "base/metrics/histogram.h" 8 #include "base/metrics/histogram.h"
9 #include "base/metrics/sparse_histogram.h" 9 #include "base/metrics/sparse_histogram.h"
10 #include "google_apis/gcm/engine/connection_handler_impl.h" 10 #include "google_apis/gcm/engine/connection_handler_impl.h"
(...skipping 11 matching lines...) Expand all
22 namespace { 22 namespace {
23 23
24 // The amount of time a Socket read should wait before timing out. 24 // The amount of time a Socket read should wait before timing out.
25 const int kReadTimeoutMs = 30000; // 30 seconds. 25 const int kReadTimeoutMs = 30000; // 30 seconds.
26 26
27 // If a connection is reset after succeeding within this window of time, 27 // If a connection is reset after succeeding within this window of time,
28 // the previous backoff entry is restored (and the connection success is treated 28 // the previous backoff entry is restored (and the connection success is treated
29 // as if it was transient). 29 // as if it was transient).
30 const int kConnectionResetWindowSecs = 10; // 10 seconds. 30 const int kConnectionResetWindowSecs = 10; // 10 seconds.
31 31
32 // Decides whether the last login was within kConnectionResetWindowSecs of now
33 // or not.
34 bool ShouldRestorePreviousBackoff(const base::TimeTicks& login_time,
35 const base::TimeTicks& now_ticks) {
36 return !login_time.is_null() &&
37 now_ticks - login_time <=
38 base::TimeDelta::FromSeconds(kConnectionResetWindowSecs);
39 }
40
32 } // namespace 41 } // namespace
33 42
34 ConnectionFactoryImpl::ConnectionFactoryImpl( 43 ConnectionFactoryImpl::ConnectionFactoryImpl(
35 const GURL& mcs_endpoint, 44 const GURL& mcs_endpoint,
36 const net::BackoffEntry::Policy& backoff_policy, 45 const net::BackoffEntry::Policy& backoff_policy,
37 scoped_refptr<net::HttpNetworkSession> network_session, 46 scoped_refptr<net::HttpNetworkSession> network_session,
38 net::NetLog* net_log) 47 net::NetLog* net_log)
39 : mcs_endpoint_(mcs_endpoint), 48 : mcs_endpoint_(mcs_endpoint),
40 backoff_policy_(backoff_policy), 49 backoff_policy_(backoff_policy),
41 network_session_(network_session), 50 network_session_(network_session),
42 net_log_(net_log), 51 net_log_(net_log),
43 connecting_(false), 52 connecting_(false),
53 logging_in_(false),
44 weak_ptr_factory_(this) { 54 weak_ptr_factory_(this) {
45 } 55 }
46 56
47 ConnectionFactoryImpl::~ConnectionFactoryImpl() { 57 ConnectionFactoryImpl::~ConnectionFactoryImpl() {
48 } 58 }
49 59
50 void ConnectionFactoryImpl::Initialize( 60 void ConnectionFactoryImpl::Initialize(
51 const BuildLoginRequestCallback& request_builder, 61 const BuildLoginRequestCallback& request_builder,
52 const ConnectionHandler::ProtoReceivedCallback& read_callback, 62 const ConnectionHandler::ProtoReceivedCallback& read_callback,
53 const ConnectionHandler::ProtoSentCallback& write_callback) { 63 const ConnectionHandler::ProtoSentCallback& write_callback) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 DVLOG(1) << "Attempting connection to MCS endpoint."; 101 DVLOG(1) << "Attempting connection to MCS endpoint.";
92 ConnectImpl(); 102 ConnectImpl();
93 } 103 }
94 104
95 bool ConnectionFactoryImpl::IsEndpointReachable() const { 105 bool ConnectionFactoryImpl::IsEndpointReachable() const {
96 return connection_handler_ && 106 return connection_handler_ &&
97 connection_handler_->CanSendMessage() && 107 connection_handler_->CanSendMessage() &&
98 !connecting_; 108 !connecting_;
99 } 109 }
100 110
101 void ConnectionFactoryImpl::SignalConnectionReset() { 111 void ConnectionFactoryImpl::SignalConnectionReset(
112 ConnectionResetReason reason) {
113 // A failure can trigger multiple resets, so no need to do anything if a
114 // connection is already in progress.
102 if (connecting_) 115 if (connecting_)
103 return; // Already attempting to reconnect. 116 return;
117
118 UMA_HISTOGRAM_ENUMERATION("GCM.ConnectionResetReason",
fgorski 2014/02/12 19:24:01 Perhaps we could wrap that in LogConnectionResetRe
Nicolas Zea 2014/02/12 21:50:16 I think that these methods are already the ones th
fgorski 2014/02/12 21:56:27 OK, I guess we can figure it out when we are close
119 reason,
120 CONNECTION_RESET_COUNT);
121 if (!last_login_time_.is_null()) {
122 UMA_HISTOGRAM_CUSTOM_TIMES("GCM.ConnectionUpTime",
123 NowTicks() - last_login_time_,
124 base::TimeDelta::FromSeconds(1),
125 base::TimeDelta::FromHours(24),
126 50);
127 // |last_login_time_| will be reset below, before attempting the new
128 // connection.
129 }
104 130
105 if (connection_handler_) 131 if (connection_handler_)
106 connection_handler_->Reset(); 132 connection_handler_->Reset();
107 133
108 if (!backoff_reset_time_.is_null() && 134 if (socket_handle_.socket() && socket_handle_.socket()->IsConnected())
109 NowTicks() - backoff_reset_time_ <= 135 socket_handle_.socket()->Disconnect();
110 base::TimeDelta::FromSeconds(kConnectionResetWindowSecs)) { 136 socket_handle_.Reset();
137
138 if (logging_in_) {
139 // Failures prior to login completion just reuse the existing backoff entry.
140 logging_in_ = false;
141 backoff_entry_->InformOfRequest(false);
142 } else if (reason == LOGIN_FAILURE ||
143 ShouldRestorePreviousBackoff(last_login_time_, NowTicks())) {
144 // Failures due to login, or within the reset window of a login, restore
145 // the backoff entry that was saved off at login completion time.
111 backoff_entry_.swap(previous_backoff_); 146 backoff_entry_.swap(previous_backoff_);
112 backoff_entry_->InformOfRequest(false); 147 backoff_entry_->InformOfRequest(false);
148 } else {
149 // We shouldn't be in backoff in thise case.
150 DCHECK(backoff_entry_->CanDiscard());
113 } 151 }
114 backoff_reset_time_ = base::TimeTicks(); 152
115 previous_backoff_->Reset(); 153 // At this point the last login time has been consumed or deemed irrelevant,
154 // reset it.
155 last_login_time_ = base::TimeTicks();
156
116 Connect(); 157 Connect();
117 } 158 }
118 159
119 base::TimeTicks ConnectionFactoryImpl::NextRetryAttempt() const { 160 base::TimeTicks ConnectionFactoryImpl::NextRetryAttempt() const {
120 if (!backoff_entry_) 161 if (!backoff_entry_)
121 return base::TimeTicks(); 162 return base::TimeTicks();
122 return backoff_entry_->GetReleaseTime(); 163 return backoff_entry_->GetReleaseTime();
123 } 164 }
124 165
125 void ConnectionFactoryImpl::OnConnectionTypeChanged( 166 void ConnectionFactoryImpl::OnConnectionTypeChanged(
(...skipping 10 matching lines...) Expand all
136 } 177 }
137 178
138 void ConnectionFactoryImpl::OnIPAddressChanged() { 179 void ConnectionFactoryImpl::OnIPAddressChanged() {
139 DVLOG(1) << "IP Address changed, resetting backoff."; 180 DVLOG(1) << "IP Address changed, resetting backoff.";
140 backoff_entry_->Reset(); 181 backoff_entry_->Reset();
141 // Connect(..) should be retrying with backoff already if a connection is 182 // Connect(..) should be retrying with backoff already if a connection is
142 // necessary, so no need to call again. 183 // necessary, so no need to call again.
143 } 184 }
144 185
145 void ConnectionFactoryImpl::ConnectImpl() { 186 void ConnectionFactoryImpl::ConnectImpl() {
146 DCHECK(!connection_handler_->CanSendMessage()); 187 DCHECK(connecting_);
147 if (socket_handle_.socket() && socket_handle_.socket()->IsConnected()) 188 DCHECK(!socket_handle_.socket());
148 socket_handle_.socket()->Disconnect();
149 socket_handle_.Reset();
150 189
151 // TODO(zea): resolve proxies. 190 // TODO(zea): resolve proxies.
152 net::ProxyInfo proxy_info; 191 net::ProxyInfo proxy_info;
153 proxy_info.UseDirect(); 192 proxy_info.UseDirect();
154 net::SSLConfig ssl_config; 193 net::SSLConfig ssl_config;
155 network_session_->ssl_config_service()->GetSSLConfig(&ssl_config); 194 network_session_->ssl_config_service()->GetSSLConfig(&ssl_config);
156 195
157 int status = net::InitSocketHandleForTlsConnect( 196 int status = net::InitSocketHandleForTlsConnect(
158 net::HostPortPair::FromURL(mcs_endpoint_), 197 net::HostPortPair::FromURL(mcs_endpoint_),
159 network_session_.get(), 198 network_session_.get(),
(...skipping 23 matching lines...) Expand all
183 scoped_ptr<net::BackoffEntry> ConnectionFactoryImpl::CreateBackoffEntry( 222 scoped_ptr<net::BackoffEntry> ConnectionFactoryImpl::CreateBackoffEntry(
184 const net::BackoffEntry::Policy* const policy) { 223 const net::BackoffEntry::Policy* const policy) {
185 return scoped_ptr<net::BackoffEntry>(new net::BackoffEntry(policy)); 224 return scoped_ptr<net::BackoffEntry>(new net::BackoffEntry(policy));
186 } 225 }
187 226
188 base::TimeTicks ConnectionFactoryImpl::NowTicks() { 227 base::TimeTicks ConnectionFactoryImpl::NowTicks() {
189 return base::TimeTicks::Now(); 228 return base::TimeTicks::Now();
190 } 229 }
191 230
192 void ConnectionFactoryImpl::OnConnectDone(int result) { 231 void ConnectionFactoryImpl::OnConnectDone(int result) {
232 UMA_HISTOGRAM_BOOLEAN("GCM.ConnectionSuccessRate", (result == net::OK));
233
193 if (result != net::OK) { 234 if (result != net::OK) {
194 LOG(ERROR) << "Failed to connect to MCS endpoint with error " << result; 235 LOG(ERROR) << "Failed to connect to MCS endpoint with error " << result;
195 backoff_entry_->InformOfRequest(false); 236 backoff_entry_->InformOfRequest(false);
196 UMA_HISTOGRAM_SPARSE_SLOWLY("GCM.ConnectionFailureErrorCode", result); 237 UMA_HISTOGRAM_SPARSE_SLOWLY("GCM.ConnectionFailureErrorCode", result);
197 Connect(); 238 Connect();
198 return; 239 return;
199 } 240 }
200 241
201 DVLOG(1) << "MCS endpoint socket connection success, starting handshake."; 242 connecting_ = false;
243 logging_in_ = true;
244 DVLOG(1) << "MCS endpoint socket connection success, starting login.";
202 InitHandler(); 245 InitHandler();
203 } 246 }
204 247
205 void ConnectionFactoryImpl::ConnectionHandlerCallback(int result) { 248 void ConnectionFactoryImpl::ConnectionHandlerCallback(int result) {
206 if (result == net::OK) { 249 DCHECK(!connecting_);
207 // Handshake succeeded, reset the backoff. 250 if (result != net::OK) {
208 connecting_ = false; 251 // TODO(zea): Consider how to handle errors that may require some sort of
209 backoff_reset_time_ = NowTicks(); 252 // user intervention (login page, etc.).
210 previous_backoff_.swap(backoff_entry_); 253 UMA_HISTOGRAM_SPARSE_SLOWLY("GCM.ConnectionDisconnectErrorCode", result);
211 backoff_entry_->Reset(); 254 SignalConnectionReset(SOCKET_FAILURE);
212 return; 255 return;
213 } 256 }
214 257
215 if (!connecting_) 258 // Handshake complete, reset backoff. If the login failed with an error,
216 UMA_HISTOGRAM_SPARSE_SLOWLY("GCM.ConnectionDisconnectErrorCode", result); 259 // the client should invoke SignalConnectionReset(LOGIN_FAILURE), which will
217 260 // restore the previous backoff.
218 if (connection_handler_) 261 last_login_time_ = NowTicks();
219 connection_handler_->Reset(); 262 previous_backoff_.swap(backoff_entry_);
220 263 backoff_entry_->Reset();
221 // TODO(zea): Consider how to handle errors that may require some sort of 264 logging_in_ = false;
222 // user intervention (login page, etc.).
223 LOG(ERROR) << "Connection reset with error " << result;
224 backoff_entry_->InformOfRequest(false);
225 Connect();
226 } 265 }
227 266
228 } // namespace gcm 267 } // namespace gcm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698