Chromium Code Reviews| Index: webrtc/p2p/base/p2ptransportchannel.cc |
| diff --git a/webrtc/p2p/base/p2ptransportchannel.cc b/webrtc/p2p/base/p2ptransportchannel.cc |
| index 6bcf0d7d2bfb09e9548501dccfde4e2ba249a5bd..99d81c40e033a83581bfeccde2cdb6b1599ce968 100644 |
| --- a/webrtc/p2p/base/p2ptransportchannel.cc |
| +++ b/webrtc/p2p/base/p2ptransportchannel.cc |
| @@ -66,6 +66,8 @@ namespace cricket { |
| // well on a 28.8K modem, which is the slowest connection on which the voice |
| // quality is reasonable at all. |
| static const int PING_PACKET_SIZE = 60 * 8; |
| + |
| +// The next two ping intervals are at the channel level. |
| // STRONG_PING_INTERVAL (480ms) is applied when the selected connection is both |
| // writable and receiving. |
| static const int STRONG_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 1000; |
| @@ -73,11 +75,13 @@ static const int STRONG_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 1000; |
| // not writable or not receiving. |
| const int WEAK_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 10000; |
| -// Writable connections are pinged at a faster rate while stabilizing. |
| -const int STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL = 900; // ms |
| - |
| -// Writable connections are pinged at a slower rate once stabilized. |
| -const int STABLE_WRITABLE_CONNECTION_PING_INTERVAL = 2500; // ms |
| +// The next two ping intervals are at the connection level. |
| +// Writable connections are pinged at a faster rate while the connections are |
| +// stabilizing or the channel is weak. |
| +const int WEAK_OR_STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL = 900; // ms |
| +// Writable connections are pinged at a slower rate once they are stabilized and |
| +// the channel is strongly connected. |
| +const int STRONG_AND_STABLE_WRITABLE_CONNECTION_PING_INTERVAL = 2500; // ms |
| static const int MIN_CHECK_RECEIVING_INTERVAL = 50; // ms |
| @@ -116,7 +120,7 @@ P2PTransportChannel::P2PTransportChannel(const std::string& transport_name, |
| DEFAULT_BACKUP_CONNECTION_PING_INTERVAL, |
| GATHER_ONCE /* continual_gathering_policy */, |
| false /* prioritize_most_likely_candidate_pairs */, |
| - STABLE_WRITABLE_CONNECTION_PING_INTERVAL, |
| + STRONG_AND_STABLE_WRITABLE_CONNECTION_PING_INTERVAL, |
| true /* presume_writable_when_fully_relayed */, |
| DEFAULT_REGATHER_ON_FAILED_NETWORKS_INTERVAL, |
| RECEIVING_SWITCHING_DELAY) { |
| @@ -1305,6 +1309,24 @@ void P2PTransportChannel::SortConnectionsAndUpdateState() { |
| MaybeStartPinging(); |
| } |
| +std::map<rtc::Network*, Connection*> |
|
pthatcher1
2016/10/24 20:49:05
You don't need to return a map. You could instead
honghaiz3
2016/10/24 23:35:08
I wonder what was the concern about using a map. A
pthatcher1
2016/10/25 17:00:06
I thought it might be more readable. But what you
|
| +P2PTransportChannel::GetPremierConnectionsByNetwork() const { |
|
pthatcher1
2016/10/24 20:49:05
I'm not really a fan of the word "premier", since
honghaiz3
2016/10/24 23:35:08
Done. Changed Premier to best.
|
| + // |connections_| has been sorted, so the first one in the list on a given |
| + // network is the premier connection, except that the selected connection |
| + // is always the premier connection on the network. |
| + std::map<rtc::Network*, Connection*> premier_connections_by_network; |
| + if (selected_connection_) { |
| + premier_connections_by_network[selected_connection_->port()->Network()] = |
| + selected_connection_; |
| + } |
| + for (Connection* conn : connections_) { |
| + rtc::Network* network = conn->port()->Network(); |
| + // This only inserts when the network does not exist in the map. |
| + premier_connections_by_network.insert(std::make_pair(network, conn)); |
|
pthatcher1
2016/10/24 20:49:05
Instead of inserting in the map, you could just it
|
| + } |
| + return premier_connections_by_network; |
| +} |
| + |
| void P2PTransportChannel::PruneConnections() { |
| // We can prune any connection for which there is a connected, writable |
| // connection on the same network with better or equal priority. We leave |
| @@ -1315,25 +1337,15 @@ void P2PTransportChannel::PruneConnections() { |
| // switch. If the |premier| connection is not connected, we may be |
| // reconnecting a TCP connection and temporarily do not prune connections in |
| // this network. See the big comment in CompareConnectionStates. |
| - |
| - // Get a list of the networks that we are using. |
| - std::set<rtc::Network*> networks; |
| - for (const Connection* conn : connections_) { |
| - networks.insert(conn->port()->Network()); |
| - } |
| - for (rtc::Network* network : networks) { |
| - Connection* premier = GetBestConnectionOnNetwork(network); |
| - // Do not prune connections if the current selected connection is weak on |
| + auto premier_connections_by_network = GetPremierConnectionsByNetwork(); |
| + for (Connection* conn : connections_) { |
| + // Do not prune connections if the current premier connection is weak on |
| // this network. Otherwise, it may delete connections prematurely. |
| - if (!premier || premier->weak()) { |
| - continue; |
| - } |
| - |
| - for (Connection* conn : connections_) { |
| - if ((conn != premier) && (conn->port()->Network() == network) && |
| - (CompareConnectionCandidates(premier, conn) >= 0)) { |
| - conn->Prune(); |
| - } |
| + Connection* premier = |
| + premier_connections_by_network[conn->port()->Network()]; |
|
pthatcher1
2016/10/24 20:49:05
If GetBestConnectionForEachNetwork returns a vecto
honghaiz3
2016/10/24 23:35:09
Actually that is not enough. We will need to find
pthatcher1
2016/10/25 17:00:06
OK, I see the logic now.
|
| + if (premier && conn != premier && !premier->weak() && |
| + CompareConnectionCandidates(premier, conn) >= 0) { |
| + conn->Prune(); |
| } |
| } |
| } |
| @@ -1471,26 +1483,6 @@ bool P2PTransportChannel::ReadyToSend(Connection* connection) const { |
| PresumedWritable(connection)); |
| } |
| -// If we have a selected connection, return it, otherwise return top one in the |
| -// list (later we will mark it best). |
| -Connection* P2PTransportChannel::GetBestConnectionOnNetwork( |
| - rtc::Network* network) const { |
| - // If the selected connection is on this network, then it wins. |
| - if (selected_connection_ && |
| - (selected_connection_->port()->Network() == network)) { |
| - return selected_connection_; |
| - } |
| - |
| - // Otherwise, we return the top-most in sorted order. |
| - for (size_t i = 0; i < connections_.size(); ++i) { |
| - if (connections_[i]->port()->Network() == network) { |
| - return connections_[i]; |
| - } |
| - } |
| - |
| - return NULL; |
| -} |
| - |
| // Handle any queued up requests |
| void P2PTransportChannel::OnMessage(rtc::Message *pmsg) { |
| switch (pmsg->message_id) { |
| @@ -1596,14 +1588,50 @@ bool P2PTransportChannel::IsPingable(const Connection* conn, |
| return (now >= conn->last_ping_sent() + ping_interval); |
| } |
| -bool P2PTransportChannel::IsSelectedConnectionPingable(int64_t now) { |
| - if (!selected_connection_ || !selected_connection_->connected() || |
| - !selected_connection_->writable()) { |
| +// TODO(honghaiz): Re-thinking the way of prioritizing connections for ping |
| +// requests. |
| +Connection* P2PTransportChannel::FindBestPremierConnectionToPing(int64_t now) { |
|
pthatcher1
2016/10/24 20:49:05
Why not just put all of this logic into FindNextPi
honghaiz3
2016/10/24 23:35:09
Done.
|
| + // If the selected connection is pingable, select it to ping. |
| + if (IsPremierConnectionPingable(selected_connection_, now)) { |
| + return selected_connection_; |
| + } |
| + // If the selected connection is strongly connected, don't bother to ping |
|
pthatcher1
2016/10/24 20:49:05
bother to ping => bother pinging
honghaiz3
2016/10/24 23:35:08
Done.
|
| + // premier connections on other networks at a higher priority. This prevents |
| + // a few premier connections from saturating all transmission slots for ping |
| + // and also prevents the backup connections from being pinged frequently. |
| + if (!weak()) { |
| + return nullptr; |
| + } |
| + |
| + // Otherwise, find the premier connection that has not been pinged for the |
| + // longest time. |
| + auto premier_connections_by_network = GetPremierConnectionsByNetwork(); |
| + Connection* oldest_pingable_premier_connection = nullptr; |
| + for (auto kv : premier_connections_by_network) { |
|
pthatcher1
2016/10/24 20:49:05
If GetBestConnectionForEachNetwork returned a vect
|
| + Connection* conn = kv.second; |
| + if (conn == nullptr || conn == selected_connection_) { |
| + continue; |
| + } |
| + if (IsPremierConnectionPingable(conn, now) && |
| + (!oldest_pingable_premier_connection || |
| + conn->last_ping_sent() < |
| + oldest_pingable_premier_connection->last_ping_sent())) { |
| + oldest_pingable_premier_connection = conn; |
| + } |
| + } |
| + return oldest_pingable_premier_connection; |
| +} |
| + |
| +bool P2PTransportChannel::IsPremierConnectionPingable( |
|
pthatcher1
2016/10/24 20:49:05
Can't this just be IsConnectionPingable?
honghaiz3
2016/10/24 23:35:09
No. In this method, it is critical to ping connect
pthatcher1
2016/10/25 17:00:06
What I mean is that since you're already passing i
Taylor Brandstetter
2016/10/25 18:29:28
Except there's a completely different method, "IsP
honghaiz3
2016/10/25 22:01:24
IsPremierConnectionPingable (now it is called IsPe
pthatcher1
2016/10/26 22:37:50
I agree with Taylor that this is confusing. IsPin
honghaiz3
2016/10/27 19:20:58
FindNextPingableConnection has the following steps
Taylor Brandstetter
2016/10/27 21:04:54
I had an idea similar to the "ping score" concept.
honghaiz3
2016/10/27 21:45:09
Note a few details:
1. The eligibility of a connec
|
| + Connection* premier_connection, |
| + int64_t now) { |
| + if (!premier_connection || !premier_connection->connected() || |
| + !premier_connection->writable()) { |
| return false; |
| } |
| - int interval = CalculateActiveWritablePingInterval(selected_connection_, now); |
| - return selected_connection_->last_ping_sent() + interval <= now; |
| + int interval = CalculateActiveWritablePingInterval(premier_connection, now); |
| + return premier_connection->last_ping_sent() + interval <= now; |
| } |
| int P2PTransportChannel::CalculateActiveWritablePingInterval( |
| @@ -1616,10 +1644,12 @@ int P2PTransportChannel::CalculateActiveWritablePingInterval( |
| } |
| int stable_interval = config_.stable_writable_connection_ping_interval; |
| - int stablizing_interval = |
| - std::min(stable_interval, STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL); |
| - |
| - return conn->stable(now) ? stable_interval : stablizing_interval; |
| + int weak_or_stablizing_interval = std::min( |
| + stable_interval, WEAK_OR_STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL); |
| + // If the channel is weak or the connection is not stable yet, use the |
| + // weak_or_stablizing_interval. |
| + return (!weak() && conn->stable(now)) ? stable_interval |
| + : weak_or_stablizing_interval; |
| } |
| // Returns the next pingable connection to ping. This will be the oldest |
| @@ -1631,10 +1661,8 @@ int P2PTransportChannel::CalculateActiveWritablePingInterval( |
| // CompareConnectionStates. |
| Connection* P2PTransportChannel::FindNextPingableConnection() { |
| int64_t now = rtc::TimeMillis(); |
| - Connection* conn_to_ping = nullptr; |
| - if (IsSelectedConnectionPingable(now)) { |
| - conn_to_ping = selected_connection_; |
| - } else { |
| + Connection* conn_to_ping = FindBestPremierConnectionToPing(now); |
| + if (!conn_to_ping) { |
| conn_to_ping = FindConnectionToPing(now); |
| } |
| return conn_to_ping; |
| @@ -1749,8 +1777,9 @@ void P2PTransportChannel::OnConnectionDestroyed(Connection* connection) { |
| unpinged_connections_.erase(*iter); |
| connections_.erase(iter); |
| - LOG_J(LS_INFO, this) << "Removed connection (" |
| - << static_cast<int>(connections_.size()) << " remaining)"; |
| + LOG_J(LS_INFO, this) << "Removed connection " << std::hex << connection |
| + << std::dec << " (" << connections_.size() |
| + << " remaining)"; |
| // If this is currently the selected connection, then we need to pick a new |
| // one. The call to SortConnectionsAndUpdateState will pick a new one. It |
| @@ -1878,7 +1907,7 @@ void P2PTransportChannel::OnReadyToSend(Connection* connection) { |
| // Find "triggered checks". We ping first those connections that have |
| // received a ping but have not sent a ping since receiving it |
| -// (last_received_ping > last_sent_ping). But we shouldn't do |
| +// (last_ping_received > last_ping_sent). But we shouldn't do |
| // triggered checks if the connection is already writable. |
| Connection* P2PTransportChannel::FindOldestConnectionNeedingTriggeredCheck( |
| int64_t now) { |