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

Unified Diff: content/browser/renderer_host/websocket_dispatcher_host.cc

Issue 972963002: Per-renderer WebSocket throttling (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix content_unittests Created 5 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 side-by-side diff with in-line comments
Download patch
Index: content/browser/renderer_host/websocket_dispatcher_host.cc
diff --git a/content/browser/renderer_host/websocket_dispatcher_host.cc b/content/browser/renderer_host/websocket_dispatcher_host.cc
index d49199a7cb8f44e08ea03435a58905f63b618fc5..870b63070bad468c3868e4229bdb5d8f91fdd9fc 100644
--- a/content/browser/renderer_host/websocket_dispatcher_host.cc
+++ b/content/browser/renderer_host/websocket_dispatcher_host.cc
@@ -9,6 +9,7 @@
#include "base/callback.h"
#include "base/logging.h"
+#include "base/rand_util.h"
#include "base/stl_util.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/renderer_host/websocket_host.h"
@@ -23,6 +24,10 @@ namespace {
// fully-qualified every time.
typedef WebSocketDispatcherHost::WebSocketHostState WebSocketHostState;
+// Max of pending connections per WebSocketDispatcherHost
Adam Rice 2015/03/04 08:20:50 Nitpick: "Max number of"
hiroshige 2015/03/04 11:13:15 Done.
+// used for per-renderer WebSocket throttling.
+const int kMaxPendingWebSocketConnections = 255;
+
} // namespace
WebSocketDispatcherHost::WebSocketDispatcherHost(
@@ -33,7 +38,12 @@ WebSocketDispatcherHost::WebSocketDispatcherHost(
get_context_callback_(get_context_callback),
websocket_host_factory_(
base::Bind(&WebSocketDispatcherHost::CreateWebSocketHost,
- base::Unretained(this))) {}
+ base::Unretained(this))),
+ num_pending_connections_(0),
+ num_current_succeeded_connections_(0),
+ num_previous_succeeded_connections_(0),
+ num_current_failed_connections_(0),
+ num_previous_failed_connections_(0) {}
WebSocketDispatcherHost::WebSocketDispatcherHost(
int process_id,
@@ -44,8 +54,11 @@ WebSocketDispatcherHost::WebSocketDispatcherHost(
get_context_callback_(get_context_callback),
websocket_host_factory_(websocket_host_factory) {}
-WebSocketHost* WebSocketDispatcherHost::CreateWebSocketHost(int routing_id) {
- return new WebSocketHost(routing_id, this, get_context_callback_.Run());
+WebSocketHost* WebSocketDispatcherHost::CreateWebSocketHost(
+ int routing_id,
+ base::TimeDelta delay) {
+ return new WebSocketHost(
+ routing_id, this, get_context_callback_.Run(), delay);
}
bool WebSocketDispatcherHost::OnMessageReceived(const IPC::Message& message) {
@@ -73,8 +86,23 @@ bool WebSocketDispatcherHost::OnMessageReceived(const IPC::Message& message) {
// little extreme. So for now just ignore the bogus request.
return true; // We handled the message (by ignoring it).
}
- host = websocket_host_factory_.Run(routing_id);
+ if (num_pending_connections_ > kMaxPendingWebSocketConnections) {
+ if(!Send(new WebSocketMsg_NotifyFailure(routing_id,
+ "Error in connection establishment: net::ERR_INSUFFICIENT_RESOURCES"
+ ))) {
+ DVLOG(1) << "Sending of message type "
+ << "WebSocketMsg_NotifyFailure failed.";
+ }
+ return true;
+ }
+ host = websocket_host_factory_.Run(routing_id, CalculateDelay());
hosts_.insert(WebSocketHostTable::value_type(routing_id, host));
+ ++num_pending_connections_;
+ if (!timer_.IsRunning())
+ timer_.Start(FROM_HERE,
+ base::TimeDelta::FromMinutes(2),
+ this,
+ &WebSocketDispatcherHost::FinishThrottlingPeriod);
}
if (!host) {
DVLOG(1) << "Received invalid routing ID " << routing_id
@@ -121,6 +149,16 @@ WebSocketHostState WebSocketDispatcherHost::SendAddChannelResponse(
DeleteWebSocketHost(routing_id);
return WEBSOCKET_HOST_DELETED;
}
+
+ // Update throttling counters (success).
+ WebSocketHost* host = GetHost(routing_id);
+ DCHECK(host);
+ host->OnHandshakeSucceeded();
+ --num_pending_connections_;
+ DCHECK_GE(num_pending_connections_, 0);
+ ++num_current_succeeded_connections_;
+ DCHECK_LT(num_current_succeeded_connections_, kint64max / 2);
Adam Rice 2015/03/04 08:20:50 I don't think the "/ 2" is doing anything useful h
hiroshige 2015/03/04 11:13:15 I added "/ 2" here because this variable is used l
Adam Rice 2015/03/05 07:48:27 Yes, just remove it. Even if there is a bug in the
hiroshige 2015/03/06 06:04:29 Done.
+
return WEBSOCKET_HOST_ALIVE;
}
@@ -200,8 +238,47 @@ WebSocketDispatcherHost::~WebSocketDispatcherHost() {
void WebSocketDispatcherHost::DeleteWebSocketHost(int routing_id) {
WebSocketHostTable::iterator it = hosts_.find(routing_id);
DCHECK(it != hosts_.end());
+ DCHECK(it->second);
+ if (!it->second->handshake_succeeded()) {
+ // Update throttling counters (failure).
+ --num_pending_connections_;
+ DCHECK_GE(num_pending_connections_, 0);
+ ++num_current_failed_connections_;
+ DCHECK_LT(num_current_failed_connections_, kint64max / 2);
+ }
+
delete it->second;
hosts_.erase(it);
+
+ DCHECK(static_cast<size_t>(num_pending_connections_) <= hosts_.size());
Adam Rice 2015/03/04 08:20:49 DCHECK_LE. Also, you should use checked_cast<> fr
hiroshige 2015/03/04 11:13:15 Done.
+}
+
+// Calculate delay according to
Adam Rice 2015/03/04 08:20:49 I think "as described in" sounds nicer than "accor
hiroshige 2015/03/04 11:13:15 Done.
+// the per-renderer WebSocket throttling design doc:
+// https://docs.google.com/document/d/1aw2oN5PKfk-1gLnBrlv1OwLA8K3-ykM2ckwX2lubTg4/edit?usp=sharing
+base::TimeDelta WebSocketDispatcherHost::CalculateDelay() const {
+ int64_t f = num_previous_failed_connections_ +
+ num_current_failed_connections_;
+ int64_t s = num_previous_succeeded_connections_ +
+ num_current_succeeded_connections_;
+ int p = num_pending_connections_;
+ return base::TimeDelta::FromMilliseconds(
+ base::RandInt(1000, 5000) *
+ (1 << std::min(p + f / (s + 1), static_cast<int64_t>(16))) / 65536);
Adam Rice 2015/03/04 08:20:49 I think it is probably clearer to write 16LL rathe
hiroshige 2015/03/04 11:13:14 Sadly 16LL doesn't pass compilation; std::min requ
Adam Rice 2015/03/05 07:48:27 Sorry. I just remembered how to do this properly.
hiroshige 2015/03/06 06:04:29 Done.
+}
+
+void WebSocketDispatcherHost::FinishThrottlingPeriod() {
+ num_previous_failed_connections_ = num_current_failed_connections_;
+ num_current_failed_connections_ = 0;
+
+ num_previous_succeeded_connections_ = num_current_succeeded_connections_;
+ num_current_succeeded_connections_ = 0;
+
+ if (num_pending_connections_ == 0 &&
+ num_previous_failed_connections_ == 0 &&
+ num_previous_succeeded_connections_ == 0) {
+ timer_.Stop();
+ }
}
} // namespace content

Powered by Google App Engine
This is Rietveld 408576698