Index: chrome/browser/net/passive_log_collector.cc |
diff --git a/chrome/browser/net/passive_log_collector.cc b/chrome/browser/net/passive_log_collector.cc |
index 64484daaac9a47de1164ec3b7eaec2e594327ffb..9ffac480401ef38c91c9fb4a5fa56bab9d74747f 100644 |
--- a/chrome/browser/net/passive_log_collector.cc |
+++ b/chrome/browser/net/passive_log_collector.cc |
@@ -7,6 +7,7 @@ |
#include <algorithm> |
#include "base/string_util.h" |
+#include "base/format_macros.h" |
#include "chrome/browser/chrome_thread.h" |
namespace { |
@@ -18,7 +19,7 @@ const size_t kMaxLiveRequests = 200; |
// Sort function on source ID. |
bool OrderBySourceID(const PassiveLogCollector::RequestInfo& a, |
const PassiveLogCollector::RequestInfo& b) { |
- return a.entries[0].source.id < b.entries[0].source.id; |
+ return a.source_id < b.source_id; |
} |
void AddEntryToRequestInfo(const PassiveLogCollector::Entry& entry, |
@@ -56,6 +57,23 @@ bool SortByOrderComparator(const PassiveLogCollector::Entry& a, |
return a.order < b.order; |
} |
+void SetSubordinateSource(PassiveLogCollector::RequestInfo* info, |
+ const PassiveLogCollector::Entry& entry) { |
+ info->subordinate_source.id = static_cast<net::NetLogIntegerParameter*>( |
+ entry.extra_parameters.get())->value(); |
+ switch (entry.type) { |
+ case net::NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_ID: |
+ info->subordinate_source.type = net::NetLog::SOURCE_CONNECT_JOB; |
+ break; |
+ case net::NetLog::TYPE_SOCKET_POOL_SOCKET_ID: |
+ info->subordinate_source.type = net::NetLog::SOURCE_SOCKET; |
+ break; |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+} |
+ |
} // namespace |
//---------------------------------------------------------------------------- |
@@ -63,8 +81,8 @@ bool SortByOrderComparator(const PassiveLogCollector::Entry& a, |
//---------------------------------------------------------------------------- |
PassiveLogCollector::PassiveLogCollector() |
- : url_request_tracker_(&connect_job_tracker_), |
- socket_stream_tracker_(&connect_job_tracker_), |
+ : url_request_tracker_(&connect_job_tracker_, &socket_tracker_), |
+ socket_stream_tracker_(&connect_job_tracker_, &socket_tracker_), |
num_events_seen_(0) { |
} |
@@ -90,6 +108,9 @@ void PassiveLogCollector::OnAddEntry( |
case net::NetLog::SOURCE_CONNECT_JOB: |
connect_job_tracker_.OnAddEntry(entry); |
break; |
+ case net::NetLog::SOURCE_SOCKET: |
+ socket_tracker_.OnAddEntry(entry); |
+ break; |
case net::NetLog::SOURCE_INIT_PROXY_RESOLVER: |
init_proxy_resolver_tracker_.OnAddEntry(entry); |
break; |
@@ -134,6 +155,7 @@ PassiveLogCollector::RequestTrackerBase::RequestTrackerBase( |
void PassiveLogCollector::RequestTrackerBase::OnAddEntry(const Entry& entry) { |
RequestInfo& info = live_requests_[entry.source.id]; |
+ info.source_id = entry.source.id; // In case this is a new entry. |
Action result = DoAddEntry(entry, &info); |
switch (result) { |
@@ -165,6 +187,11 @@ PassiveLogCollector::RequestTrackerBase::GetLiveRequests() const { |
it != live_requests_.end(); |
++it) { |
list.push_back(it->second); |
+ // We pass the copy (made by the list insert), so changes made in |
+ // OnLiveRequest are only seen by our caller. |
+ OnLiveRequest(&list.back()); |
+ std::sort(list.back().entries.begin(), list.back().entries.end(), |
+ SortByOrderComparator); |
} |
std::sort(list.begin(), list.end(), OrderBySourceID); |
@@ -190,12 +217,16 @@ PassiveLogCollector::RequestTrackerBase::GetRecentlyDeceased() const { |
return list; |
} |
-const PassiveLogCollector::RequestInfo* |
-PassiveLogCollector::RequestTrackerBase::GetRequestInfoFromGraveyard( |
- int source_id) const { |
- // Scan through the graveyard to find an entry for |source_id|. |
+PassiveLogCollector::RequestInfo* |
+PassiveLogCollector::RequestTrackerBase::GetRequestInfo(uint32 source_id) { |
+ // Look for it in the live requests first. |
+ SourceIDToInfoMap::iterator it = live_requests_.find(source_id); |
+ if (it != live_requests_.end()) |
+ return &(it->second); |
+ |
+ // Otherwise, scan through the graveyard to find an entry for |source_id|. |
for (size_t i = 0; i < graveyard_.size(); ++i) { |
- if (graveyard_[i].entries[0].source.id == source_id) { |
+ if (graveyard_[i].source_id == source_id) { |
return &graveyard_[i]; |
} |
} |
@@ -203,7 +234,7 @@ PassiveLogCollector::RequestTrackerBase::GetRequestInfoFromGraveyard( |
} |
void PassiveLogCollector::RequestTrackerBase::RemoveFromLiveRequests( |
- int source_id) { |
+ uint32 source_id) { |
// Remove from |live_requests_|. |
SourceIDToInfoMap::iterator it = live_requests_.find(source_id); |
// TODO(eroman): Shouldn't have this 'if', is it actually really necessary? |
@@ -260,7 +291,7 @@ void PassiveLogCollector::RequestTrackerBase::InsertIntoGraveyard( |
// ConnectJobTracker |
//---------------------------------------------------------------------------- |
-const size_t PassiveLogCollector::ConnectJobTracker::kMaxGraveyardSize = 3; |
+const size_t PassiveLogCollector::ConnectJobTracker::kMaxGraveyardSize = 15; |
PassiveLogCollector::ConnectJobTracker::ConnectJobTracker() |
: RequestTrackerBase(kMaxGraveyardSize) { |
@@ -269,9 +300,12 @@ PassiveLogCollector::ConnectJobTracker::ConnectJobTracker() |
PassiveLogCollector::RequestTrackerBase::Action |
PassiveLogCollector::ConnectJobTracker::DoAddEntry(const Entry& entry, |
RequestInfo* out_info) { |
- // Save the entry (possibly truncating). |
AddEntryToRequestInfo(entry, is_unbounded(), out_info); |
+ if (entry.type == net::NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_ID) { |
+ SetSubordinateSource(out_info, entry); |
+ } |
+ |
// If this is the end of the connect job, move the request to the graveyard. |
if (entry.type == net::NetLog::TYPE_SOCKET_POOL_CONNECT_JOB && |
entry.phase == net::NetLog::PHASE_END) { |
@@ -281,6 +315,118 @@ PassiveLogCollector::ConnectJobTracker::DoAddEntry(const Entry& entry, |
return ACTION_NONE; |
} |
+void PassiveLogCollector::ConnectJobTracker::AppendLogEntries( |
+ RequestInfo* out_info, bool unbounded, uint32 connect_id) { |
+ RequestInfo* connect_info = GetRequestInfo(connect_id); |
+ if (!connect_info) { |
+ net::NetLogStringParameter* text = new net::NetLogStringParameter( |
+ StringPrintf("Used ConnectJob id=%u", connect_id)); |
+ Entry new_entry(0, net::NetLog::TYPE_TODO_STRING, base::TimeTicks(), |
+ net::NetLog::Source(net::NetLog::SOURCE_CONNECT_JOB, |
+ connect_id), |
+ net::NetLog::PHASE_NONE, text); |
+ AddEntryToRequestInfo(new_entry, unbounded, out_info); |
+ return; |
+ } |
+ |
+ AppendToRequestInfo(*connect_info, unbounded, out_info); |
+ std::sort(out_info->entries.begin(), out_info->entries.end(), |
+ &SortByOrderComparator); |
+ out_info->num_entries_truncated += connect_info->num_entries_truncated; |
+ |
+ if (connect_info->subordinate_source.is_valid()) |
+ AppendLogEntries(out_info, unbounded, connect_info->subordinate_source.id); |
+} |
+ |
+//---------------------------------------------------------------------------- |
+// SocketTracker |
+//---------------------------------------------------------------------------- |
+ |
+const size_t PassiveLogCollector::SocketTracker::kMaxGraveyardSize = 15; |
+ |
+PassiveLogCollector::SocketTracker::SocketTracker() |
+ : RequestTrackerBase(kMaxGraveyardSize) { |
+} |
+ |
+PassiveLogCollector::RequestTrackerBase::Action |
+PassiveLogCollector::SocketTracker::DoAddEntry(const Entry& entry, |
+ RequestInfo* out_info) { |
+ int int_arg; |
+ switch (entry.type) { |
+ case net::NetLog::TYPE_SOCKET_BYTES_SENT: |
+ int_arg = static_cast<net::NetLogIntegerParameter*>( |
+ entry.extra_parameters.get())->value(); |
+ out_info->total_bytes_transmitted += int_arg; |
+ out_info->bytes_transmitted += int_arg; |
+ out_info->last_tx_rx_time = entry.time; |
+ out_info->last_tx_rx_position = entry.order; |
+ break; |
+ case net::NetLog::TYPE_SOCKET_BYTES_RECEIVED: |
+ int_arg = static_cast<net::NetLogIntegerParameter*>( |
+ entry.extra_parameters.get())->value(); |
+ out_info->total_bytes_received += int_arg; |
+ out_info->bytes_received += int_arg; |
+ out_info->last_tx_rx_time = entry.time; |
+ out_info->last_tx_rx_position = entry.order; |
+ break; |
+ case net::NetLog::TYPE_TCP_SOCKET_DONE: |
+ return ACTION_MOVE_TO_GRAVEYARD; |
+ default: |
+ AddEntryToRequestInfo(entry, is_unbounded(), out_info); |
+ break; |
+ } |
+ return ACTION_NONE; |
+} |
+ |
+void PassiveLogCollector::SocketTracker::AppendLogEntries( |
+ RequestInfo* out_info, bool unbounded, uint32 socket_id, bool clear) { |
+ RequestInfo* socket_info = GetRequestInfo(socket_id); |
+ if (!socket_info) { |
+ net::NetLogStringParameter* text = new net::NetLogStringParameter( |
+ StringPrintf("Used Socket id=%u.", socket_id)); |
+ Entry new_entry(0, net::NetLog::TYPE_TODO_STRING, base::TimeTicks(), |
+ net::NetLog::Source(net::NetLog::SOURCE_SOCKET, socket_id), |
+ net::NetLog::PHASE_NONE, text); |
+ AddEntryToRequestInfo(new_entry, unbounded, out_info); |
+ return; |
+ } |
+ |
+ AppendToRequestInfo(*socket_info, unbounded, out_info); |
+ out_info->num_entries_truncated += socket_info->num_entries_truncated; |
+ |
+ // Synthesize a log entry for bytes sent and received. |
+ if (socket_info->bytes_transmitted > 0 || socket_info->bytes_received > 0) { |
+ net::NetLogStringParameter* text = new net::NetLogStringParameter( |
+ StringPrintf("Tx/Rx: %"PRIu64"/%"PRIu64" [%"PRIu64"/%"PRIu64 |
+ " total on socket] (Bytes)", |
+ socket_info->bytes_transmitted, |
+ socket_info->bytes_received, |
+ socket_info->total_bytes_transmitted, |
+ socket_info->total_bytes_received)); |
+ Entry new_entry(socket_info->last_tx_rx_position, |
+ net::NetLog::TYPE_TODO_STRING, |
+ socket_info->last_tx_rx_time, |
+ net::NetLog::Source(net::NetLog::SOURCE_SOCKET, socket_id), |
+ net::NetLog::PHASE_NONE, |
+ text); |
+ AddEntryToRequestInfo(new_entry, unbounded, out_info); |
+ } |
+ std::sort(out_info->entries.begin(), out_info->entries.end(), |
+ &SortByOrderComparator); |
+ |
+ if (clear) |
+ ClearInfo(socket_info); |
+} |
+ |
+void PassiveLogCollector::SocketTracker::ClearInfo(RequestInfo* info) { |
+ info->entries.clear(); |
+ info->num_entries_truncated = 0; |
+ info->bytes_transmitted = 0; |
+ info->bytes_received = 0; |
+ info->last_tx_rx_position = 0; |
+ info->last_tx_rx_time = base::TimeTicks(); |
+} |
+ |
//---------------------------------------------------------------------------- |
// RequestTracker |
//---------------------------------------------------------------------------- |
@@ -289,24 +435,62 @@ const size_t PassiveLogCollector::RequestTracker::kMaxGraveyardSize = 25; |
const size_t PassiveLogCollector::RequestTracker::kMaxGraveyardURLSize = 1000; |
PassiveLogCollector::RequestTracker::RequestTracker( |
- ConnectJobTracker* connect_job_tracker) |
+ ConnectJobTracker* connect_job_tracker, SocketTracker* socket_tracker) |
: RequestTrackerBase(kMaxGraveyardSize), |
- connect_job_tracker_(connect_job_tracker) { |
+ connect_job_tracker_(connect_job_tracker), |
+ socket_tracker_(socket_tracker) { |
} |
PassiveLogCollector::RequestTrackerBase::Action |
PassiveLogCollector::RequestTracker::DoAddEntry(const Entry& entry, |
RequestInfo* out_info) { |
- |
- if (entry.type == net::NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_ID) { |
- // If this was notification that a ConnectJob was bound to the request, |
- // copy all the logged data for that ConnectJob. |
- AddConnectJobInfo(entry, out_info); |
- } else { |
- // Otherwise just append this entry to the request info. |
- AddEntryToRequestInfo(entry, is_unbounded(), out_info); |
+ // We expect up to three events with IDs. |
+ // - Begin SOCKET_POOL_CONNECT_JOB_ID: Means a ConnectJob was created for |
+ // this request. Including it for now, but the resulting socket may be |
+ // used for a different request. |
+ // - End SOCKET_POOL_CONNECT_JOB_ID: The named ConnectJob completed and |
+ // this request will be getting the socket from that request. |
+ // - SOCKET_POOL_SOCKET_ID: The given socket will be used for this request. |
+ // |
+ // The action to take when seeing these events depends on the current |
+ // content of the |subordinate_source| field: |
+ // |subordinate_source| is invalid (fresh state). |
+ // - Begin SOCKET_POOL_CONNECT_JOB_ID: Set |subordinate_source|. |
+ // - End SOCKET_POOL_CONNECT_JOB_ID: Integrate the named ConnectJob ID. |
+ // - SOCKET_POOL_SOCKET_ID: Set |subordinate_source|. |
+ // |subordinate_source| is a ConnectJob: |
+ // - Begin SOCKET_POOL_CONNECT_JOB_ID: Set |subordinate_source|. |
+ // - End SOCKET_POOL_CONNECT_JOB_ID: Integrate the named ConnectJob ID and |
+ // clear the |subordinate_source|. |
+ // - SOCKET_POOL_SOCKET_ID: Set |subordinate_source|. (The request was |
+ // assigned a new idle socket, after starting a ConnectJob.) |
+ // |subordinate_source| is a Socket: |
+ // First, integrate the subordinate socket source, then: |
+ // - Begin SOCKET_POOL_CONNECT_JOB_ID: Set |subordinate_source|. |
+ // (Connection restarted with a new ConnectJob.) |
+ // - End SOCKET_POOL_CONNECT_JOB_ID: Integrate the named ConnectJob ID and |
+ // clear the |subordinate_source|. (Connection restarted with a late bound |
+ // ConnectJob.) |
+ // - SOCKET_POOL_SOCKET_ID: Set |subordinate_source|. (Connection |
+ // restarted and got an idle socket.) |
+ if (entry.type == net::NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_ID || |
+ entry.type == net::NetLog::TYPE_SOCKET_POOL_SOCKET_ID) { |
+ |
+ if (out_info->subordinate_source.is_valid() && |
+ out_info->subordinate_source.type == net::NetLog::SOURCE_SOCKET) |
+ IntegrateSubordinateSource(out_info, true); |
+ |
+ SetSubordinateSource(out_info, entry); |
+ |
+ if (entry.phase == net::NetLog::PHASE_END && |
+ entry.type == net::NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_ID) { |
+ IntegrateSubordinateSource(out_info, true); |
+ out_info->subordinate_source.id = net::NetLog::Source::kInvalidId; |
+ } |
} |
+ AddEntryToRequestInfo(entry, is_unbounded(), out_info); |
+ |
// If this was the start of a URLRequest/SocketStream, extract the URL. |
// Note: we look at the first *two* entries, since the outer REQUEST_ALIVE |
// doesn't actually contain any data. |
@@ -321,6 +505,7 @@ PassiveLogCollector::RequestTracker::DoAddEntry(const Entry& entry, |
// If the request has ended, move it to the graveyard. |
if (entry.type == net::NetLog::TYPE_REQUEST_ALIVE && |
entry.phase == net::NetLog::PHASE_END) { |
+ IntegrateSubordinateSource(out_info, true); |
if (StartsWithASCII(out_info->url, "chrome://", false)) { |
// Avoid sending "chrome://" requests to the graveyard, since it just |
// adds to clutter. |
@@ -332,31 +517,24 @@ PassiveLogCollector::RequestTracker::DoAddEntry(const Entry& entry, |
return ACTION_NONE; |
} |
-void PassiveLogCollector::RequestTracker::AddConnectJobInfo( |
- const Entry& entry, |
- RequestInfo* live_entry) { |
- // We have just been notified of which ConnectJob the |
- // URLRequest/SocketStream was assigned. Lookup all the data we captured |
- // for the ConnectJob, and append it to the URLRequest/SocketStream's |
- // RequestInfo. |
- |
- int connect_job_id = static_cast<net::NetLogIntegerParameter*>( |
- entry.extra_parameters.get())->value(); |
- |
- const RequestInfo* connect_job_info = |
- connect_job_tracker_->GetRequestInfoFromGraveyard(connect_job_id); |
+void PassiveLogCollector::RequestTracker::IntegrateSubordinateSource( |
+ RequestInfo* info, bool clear_entries) const { |
+ if (!info->subordinate_source.is_valid()) |
+ return; |
- if (connect_job_info) { |
- // Append the ConnectJob information we found. |
- AppendToRequestInfo(*connect_job_info, is_unbounded(), live_entry); |
- } else { |
- // If we couldn't find the information for the ConnectJob, append a |
- // generic message instead. |
- Entry e(entry); |
- e.type = net::NetLog::TYPE_TODO_STRING; |
- e.extra_parameters = new net::NetLogStringParameter( |
- StringPrintf("Used ConnectJob id=%d", connect_job_id)); |
- AddEntryToRequestInfo(e, is_unbounded(), live_entry); |
+ uint32 subordinate_id = info->subordinate_source.id; |
+ switch (info->subordinate_source.type) { |
+ case net::NetLog::SOURCE_CONNECT_JOB: |
+ connect_job_tracker_->AppendLogEntries( |
+ info, connect_job_tracker_->is_unbounded(), subordinate_id); |
+ break; |
+ case net::NetLog::SOURCE_SOCKET: |
+ socket_tracker_->AppendLogEntries(info, socket_tracker_->is_unbounded(), |
+ subordinate_id, clear_entries); |
+ break; |
+ default: |
+ NOTREACHED(); |
+ break; |
} |
} |