| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "chrome/browser/net/passive_log_collector.h" | 5 #include "chrome/browser/net/passive_log_collector.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/compiler_specific.h" |
| 9 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| 10 #include "base/format_macros.h" | 11 #include "base/format_macros.h" |
| 11 #include "chrome/browser/chrome_thread.h" | 12 #include "chrome/browser/chrome_thread.h" |
| 12 #include "net/url_request/url_request_netlog_params.h" | 13 #include "net/url_request/url_request_netlog_params.h" |
| 13 | 14 |
| 14 namespace { | 15 namespace { |
| 15 | 16 |
| 16 const size_t kMaxNumEntriesPerLog = 50; | 17 // TODO(eroman): Do something with the truncation count. |
| 17 const size_t kMaxConnectJobGraveyardSize = 3; | |
| 18 const size_t kMaxRequestGraveyardSize = 25; | |
| 19 const size_t kMaxLiveRequests = 200; | |
| 20 | 18 |
| 21 // Sort function on source ID. | 19 const size_t kMaxNumEntriesPerLog = 30; |
| 22 bool OrderBySourceID(const PassiveLogCollector::RequestInfo& a, | 20 const size_t kMaxRequestsPerTracker = 200; |
| 23 const PassiveLogCollector::RequestInfo& b) { | |
| 24 return a.source_id < b.source_id; | |
| 25 } | |
| 26 | 21 |
| 27 void AddEntryToRequestInfo(const PassiveLogCollector::Entry& entry, | 22 void AddEntryToRequestInfo(const PassiveLogCollector::Entry& entry, |
| 28 PassiveLogCollector::RequestInfo* out_info) { | 23 PassiveLogCollector::RequestInfo* out_info) { |
| 29 // Start dropping new entries when the log has gotten too big. | 24 // Start dropping new entries when the log has gotten too big. |
| 30 if (out_info->entries.size() + 1 <= kMaxNumEntriesPerLog) { | 25 if (out_info->entries.size() + 1 <= kMaxNumEntriesPerLog) { |
| 31 out_info->entries.push_back(entry); | 26 out_info->entries.push_back(entry); |
| 32 } else { | 27 } else { |
| 33 out_info->num_entries_truncated += 1; | 28 out_info->num_entries_truncated += 1; |
| 34 out_info->entries[kMaxNumEntriesPerLog - 1] = entry; | 29 out_info->entries[kMaxNumEntriesPerLog - 1] = entry; |
| 35 } | 30 } |
| 36 } | 31 } |
| 37 | 32 |
| 38 void AppendToRequestInfo(const PassiveLogCollector::RequestInfo& info, | |
| 39 PassiveLogCollector::RequestInfo* out_info) { | |
| 40 for (size_t i = 0; i < info.entries.size(); ++i) | |
| 41 AddEntryToRequestInfo(info.entries[i], out_info); | |
| 42 } | |
| 43 | |
| 44 // Appends all of the logged events in |input| to |out|. | |
| 45 void AppendAllEntriesFromRequests( | |
| 46 const PassiveLogCollector::RequestInfoList& input, | |
| 47 PassiveLogCollector::EntryList* out) { | |
| 48 for (size_t i = 0; i < input.size(); ++i) { | |
| 49 const PassiveLogCollector::EntryList& entries = input[i].entries; | |
| 50 out->insert(out->end(), entries.begin(), entries.end()); | |
| 51 } | |
| 52 } | |
| 53 | |
| 54 // Comparator to sort entries by their |order| property, ascending. | 33 // Comparator to sort entries by their |order| property, ascending. |
| 55 bool SortByOrderComparator(const PassiveLogCollector::Entry& a, | 34 bool SortByOrderComparator(const PassiveLogCollector::Entry& a, |
| 56 const PassiveLogCollector::Entry& b) { | 35 const PassiveLogCollector::Entry& b) { |
| 57 return a.order < b.order; | 36 return a.order < b.order; |
| 58 } | 37 } |
| 59 | 38 |
| 60 void SetSubordinateSource(PassiveLogCollector::RequestInfo* info, | |
| 61 const PassiveLogCollector::Entry& entry) { | |
| 62 info->subordinate_source.id = static_cast<net::NetLogIntegerParameter*>( | |
| 63 entry.params.get())->value(); | |
| 64 switch (entry.type) { | |
| 65 case net::NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_ID: | |
| 66 info->subordinate_source.type = net::NetLog::SOURCE_CONNECT_JOB; | |
| 67 break; | |
| 68 case net::NetLog::TYPE_SOCKET_POOL_SOCKET_ID: | |
| 69 info->subordinate_source.type = net::NetLog::SOURCE_SOCKET; | |
| 70 break; | |
| 71 default: | |
| 72 NOTREACHED(); | |
| 73 break; | |
| 74 } | |
| 75 } | |
| 76 | |
| 77 } // namespace | 39 } // namespace |
| 78 | 40 |
| 79 //---------------------------------------------------------------------------- | 41 //---------------------------------------------------------------------------- |
| 80 // PassiveLogCollector | 42 // PassiveLogCollector |
| 81 //---------------------------------------------------------------------------- | 43 //---------------------------------------------------------------------------- |
| 82 | 44 |
| 83 PassiveLogCollector::PassiveLogCollector() | 45 PassiveLogCollector::PassiveLogCollector() |
| 84 : url_request_tracker_(&connect_job_tracker_, &socket_tracker_), | 46 : ALLOW_THIS_IN_INITIALIZER_LIST(connect_job_tracker_(this)), |
| 85 socket_stream_tracker_(&connect_job_tracker_, &socket_tracker_), | 47 ALLOW_THIS_IN_INITIALIZER_LIST(url_request_tracker_(this)), |
| 48 ALLOW_THIS_IN_INITIALIZER_LIST(socket_stream_tracker_(this)), |
| 86 num_events_seen_(0) { | 49 num_events_seen_(0) { |
| 50 |
| 51 // Define the mapping between source types and the tracker objects. |
| 52 memset(&trackers_[0], 0, sizeof(trackers_)); |
| 53 trackers_[net::NetLog::SOURCE_URL_REQUEST] = &url_request_tracker_; |
| 54 trackers_[net::NetLog::SOURCE_SOCKET_STREAM] = &socket_stream_tracker_; |
| 55 trackers_[net::NetLog::SOURCE_CONNECT_JOB] = &connect_job_tracker_; |
| 56 trackers_[net::NetLog::SOURCE_SOCKET] = &socket_tracker_; |
| 57 trackers_[net::NetLog::SOURCE_INIT_PROXY_RESOLVER] = |
| 58 &init_proxy_resolver_tracker_; |
| 59 trackers_[net::NetLog::SOURCE_SPDY_SESSION] = &spdy_session_tracker_; |
| 60 |
| 61 // Make sure our mapping is up-to-date. |
| 62 for (size_t i = 0; i < arraysize(trackers_); ++i) |
| 63 DCHECK(trackers_[i]) << "Unhandled SourceType: " << i; |
| 87 } | 64 } |
| 88 | 65 |
| 89 PassiveLogCollector::~PassiveLogCollector() { | 66 PassiveLogCollector::~PassiveLogCollector() { |
| 90 } | 67 } |
| 91 | 68 |
| 92 void PassiveLogCollector::OnAddEntry( | 69 void PassiveLogCollector::OnAddEntry( |
| 93 net::NetLog::EventType type, | 70 net::NetLog::EventType type, |
| 94 const base::TimeTicks& time, | 71 const base::TimeTicks& time, |
| 95 const net::NetLog::Source& source, | 72 const net::NetLog::Source& source, |
| 96 net::NetLog::EventPhase phase, | 73 net::NetLog::EventPhase phase, |
| 97 net::NetLog::EventParameters* params) { | 74 net::NetLog::EventParameters* params) { |
| 98 // Package the parameters into a single struct for convenience. | 75 // Package the parameters into a single struct for convenience. |
| 99 Entry entry(num_events_seen_++, type, time, source, phase, params); | 76 Entry entry(num_events_seen_++, type, time, source, phase, params); |
| 100 | 77 |
| 101 switch (entry.source.type) { | 78 RequestTrackerBase* tracker = GetTrackerForSourceType(entry.source.type); |
| 102 case net::NetLog::SOURCE_URL_REQUEST: | 79 if (tracker) |
| 103 url_request_tracker_.OnAddEntry(entry); | 80 tracker->OnAddEntry(entry); |
| 104 break; | 81 } |
| 105 case net::NetLog::SOURCE_SOCKET_STREAM: | 82 |
| 106 socket_stream_tracker_.OnAddEntry(entry); | 83 PassiveLogCollector::RequestTrackerBase* |
| 107 break; | 84 PassiveLogCollector::GetTrackerForSourceType( |
| 108 case net::NetLog::SOURCE_CONNECT_JOB: | 85 net::NetLog::SourceType source_type) { |
| 109 connect_job_tracker_.OnAddEntry(entry); | 86 DCHECK_LE(source_type, static_cast<int>(arraysize(trackers_))); |
| 110 break; | 87 DCHECK_GE(source_type, 0); |
| 111 case net::NetLog::SOURCE_SOCKET: | 88 return trackers_[source_type]; |
| 112 socket_tracker_.OnAddEntry(entry); | |
| 113 break; | |
| 114 case net::NetLog::SOURCE_INIT_PROXY_RESOLVER: | |
| 115 init_proxy_resolver_tracker_.OnAddEntry(entry); | |
| 116 break; | |
| 117 default: | |
| 118 // Drop all other logged events. | |
| 119 break; | |
| 120 } | |
| 121 } | 89 } |
| 122 | 90 |
| 123 void PassiveLogCollector::Clear() { | 91 void PassiveLogCollector::Clear() { |
| 124 connect_job_tracker_.Clear(); | 92 for (size_t i = 0; i < arraysize(trackers_); ++i) |
| 125 url_request_tracker_.Clear(); | 93 trackers_[i]->Clear(); |
| 126 socket_stream_tracker_.Clear(); | |
| 127 } | 94 } |
| 128 | 95 |
| 129 void PassiveLogCollector::GetAllCapturedEvents(EntryList* out) const { | 96 void PassiveLogCollector::GetAllCapturedEvents(EntryList* out) const { |
| 130 out->clear(); | 97 out->clear(); |
| 131 | 98 |
| 132 // Append all of the captured entries held by the various trackers to | 99 // Append all of the captured entries held by the various trackers to |
| 133 // |out|. | 100 // |out|. |
| 134 socket_stream_tracker_.AppendAllEntries(out); | 101 for (size_t i = 0; i < arraysize(trackers_); ++i) |
| 135 url_request_tracker_.AppendAllEntries(out); | 102 trackers_[i]->AppendAllEntries(out); |
| 136 spdy_session_tracker_.AppendAllEntries(out); | |
| 137 | |
| 138 const EntryList& proxy_entries = | |
| 139 init_proxy_resolver_tracker_.entries(); | |
| 140 out->insert(out->end(), proxy_entries.begin(), proxy_entries.end()); | |
| 141 | 103 |
| 142 // Now sort the list of entries by their insertion time (ascending). | 104 // Now sort the list of entries by their insertion time (ascending). |
| 143 std::sort(out->begin(), out->end(), &SortByOrderComparator); | 105 std::sort(out->begin(), out->end(), &SortByOrderComparator); |
| 144 } | 106 } |
| 145 | 107 |
| 146 std::string PassiveLogCollector::RequestInfo::GetURL() const { | 108 std::string PassiveLogCollector::RequestInfo::GetURL() const { |
| 147 // Note: we look at the first *two* entries, since the outer REQUEST_ALIVE | 109 // Note: we look at the first *two* entries, since the outer REQUEST_ALIVE |
| 148 // doesn't actually contain any data. | 110 // doesn't actually contain any data. |
| 149 for (size_t i = 0; i < 2 && i < entries.size(); ++i) { | 111 for (size_t i = 0; i < 2 && i < entries.size(); ++i) { |
| 150 const PassiveLogCollector::Entry& entry = entries[i]; | 112 const PassiveLogCollector::Entry& entry = entries[i]; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 162 } | 124 } |
| 163 } | 125 } |
| 164 return std::string(); | 126 return std::string(); |
| 165 } | 127 } |
| 166 | 128 |
| 167 //---------------------------------------------------------------------------- | 129 //---------------------------------------------------------------------------- |
| 168 // RequestTrackerBase | 130 // RequestTrackerBase |
| 169 //---------------------------------------------------------------------------- | 131 //---------------------------------------------------------------------------- |
| 170 | 132 |
| 171 PassiveLogCollector::RequestTrackerBase::RequestTrackerBase( | 133 PassiveLogCollector::RequestTrackerBase::RequestTrackerBase( |
| 172 size_t max_graveyard_size) | 134 size_t max_graveyard_size, PassiveLogCollector* parent) |
| 173 : max_graveyard_size_(max_graveyard_size), | 135 : max_graveyard_size_(max_graveyard_size), parent_(parent) { |
| 174 next_graveyard_index_(0) { | |
| 175 } | 136 } |
| 176 | 137 |
| 138 PassiveLogCollector::RequestTrackerBase::~RequestTrackerBase() {} |
| 139 |
| 177 void PassiveLogCollector::RequestTrackerBase::OnAddEntry(const Entry& entry) { | 140 void PassiveLogCollector::RequestTrackerBase::OnAddEntry(const Entry& entry) { |
| 178 RequestInfo& info = live_requests_[entry.source.id]; | 141 RequestInfo& info = requests_[entry.source.id]; |
| 179 info.source_id = entry.source.id; // In case this is a new entry. | 142 info.source_id = entry.source.id; // In case this is a new entry. |
| 180 Action result = DoAddEntry(entry, &info); | 143 Action result = DoAddEntry(entry, &info); |
| 181 | 144 |
| 182 switch (result) { | 145 if (result != ACTION_NONE) { |
| 183 case ACTION_MOVE_TO_GRAVEYARD: | 146 // We are either queuing it for deletion, or deleting it immediately. |
| 184 InsertIntoGraveyard(info); | 147 // If someone else holds a reference to this source, defer the deletion |
| 185 // (fall-through) | 148 // until all the references are released. |
| 186 case ACTION_DELETE: | 149 info.is_alive = false; |
| 187 RemoveFromLiveRequests(entry.source.id); | 150 if (info.reference_count == 0) { |
| 188 break; | 151 switch (result) { |
| 189 default: | 152 case ACTION_MOVE_TO_GRAVEYARD: |
| 190 break; | 153 AddToDeletionQueue(info.source_id); |
| 154 break; |
| 155 case ACTION_DELETE: |
| 156 DeleteRequestInfo(info.source_id); |
| 157 break; |
| 158 default: |
| 159 NOTREACHED(); |
| 160 break; |
| 161 } |
| 162 } |
| 191 } | 163 } |
| 192 | 164 |
| 193 if (live_requests_.size() > kMaxLiveRequests) { | 165 if (requests_.size() > kMaxRequestsPerTracker) { |
| 194 // This is a safety net in case something went wrong, to avoid continually | 166 // This is a safety net in case something went wrong, to avoid continually |
| 195 // growing memory. | 167 // growing memory. |
| 196 LOG(WARNING) << "The passive log data has grown larger " | 168 LOG(WARNING) << "The passive log data has grown larger " |
| 197 "than expected, resetting"; | 169 "than expected, resetting"; |
| 198 live_requests_.clear(); | 170 Clear(); |
| 199 } | 171 } |
| 200 } | 172 } |
| 201 | 173 |
| 202 PassiveLogCollector::RequestInfoList | 174 void PassiveLogCollector::RequestTrackerBase::DeleteRequestInfo( |
| 203 PassiveLogCollector::RequestTrackerBase::GetLiveRequests() const { | |
| 204 RequestInfoList list; | |
| 205 | |
| 206 // Copy all of the live requests into the vector. | |
| 207 for (SourceIDToInfoMap::const_iterator it = live_requests_.begin(); | |
| 208 it != live_requests_.end(); | |
| 209 ++it) { | |
| 210 list.push_back(it->second); | |
| 211 // We pass the copy (made by the list insert), so changes made in | |
| 212 // OnLiveRequest are only seen by our caller. | |
| 213 OnLiveRequest(&list.back()); | |
| 214 std::sort(list.back().entries.begin(), list.back().entries.end(), | |
| 215 SortByOrderComparator); | |
| 216 } | |
| 217 | |
| 218 std::sort(list.begin(), list.end(), OrderBySourceID); | |
| 219 return list; | |
| 220 } | |
| 221 | |
| 222 void PassiveLogCollector::RequestTrackerBase::ClearRecentlyDeceased() { | |
| 223 next_graveyard_index_ = 0; | |
| 224 graveyard_.clear(); | |
| 225 } | |
| 226 | |
| 227 // Returns a list of recently completed Requests. | |
| 228 PassiveLogCollector::RequestInfoList | |
| 229 PassiveLogCollector::RequestTrackerBase::GetRecentlyDeceased() const { | |
| 230 RequestInfoList list; | |
| 231 | |
| 232 // Copy the items from |graveyard_| (our circular queue of recently | |
| 233 // deceased request infos) into a vector, ordered from oldest to newest. | |
| 234 for (size_t i = 0; i < graveyard_.size(); ++i) { | |
| 235 size_t index = (next_graveyard_index_ + i) % graveyard_.size(); | |
| 236 list.push_back(graveyard_[index]); | |
| 237 } | |
| 238 return list; | |
| 239 } | |
| 240 | |
| 241 PassiveLogCollector::RequestInfo* | |
| 242 PassiveLogCollector::RequestTrackerBase::GetRequestInfo(uint32 source_id) { | |
| 243 // Look for it in the live requests first. | |
| 244 SourceIDToInfoMap::iterator it = live_requests_.find(source_id); | |
| 245 if (it != live_requests_.end()) | |
| 246 return &(it->second); | |
| 247 | |
| 248 // Otherwise, scan through the graveyard to find an entry for |source_id|. | |
| 249 for (size_t i = 0; i < graveyard_.size(); ++i) { | |
| 250 if (graveyard_[i].source_id == source_id) { | |
| 251 return &graveyard_[i]; | |
| 252 } | |
| 253 } | |
| 254 return NULL; | |
| 255 } | |
| 256 | |
| 257 void PassiveLogCollector::RequestTrackerBase::RemoveFromLiveRequests( | |
| 258 uint32 source_id) { | 175 uint32 source_id) { |
| 259 // Remove from |live_requests_|. | 176 SourceIDToInfoMap::iterator it = requests_.find(source_id); |
| 260 SourceIDToInfoMap::iterator it = live_requests_.find(source_id); | 177 DCHECK(it != requests_.end()); |
| 261 // TODO(eroman): Shouldn't have this 'if', is it actually really necessary? | 178 // The request should not be in the deletion queue. |
| 262 if (it != live_requests_.end()) | 179 DCHECK(std::find(deletion_queue_.begin(), deletion_queue_.end(), |
| 263 live_requests_.erase(it); | 180 source_id) == deletion_queue_.end()); |
| 181 ReleaseAllReferencesToDependencies(&(it->second)); |
| 182 requests_.erase(it); |
| 264 } | 183 } |
| 265 | 184 |
| 266 void PassiveLogCollector::RequestTrackerBase::Clear() { | 185 void PassiveLogCollector::RequestTrackerBase::Clear() { |
| 267 ClearRecentlyDeceased(); | 186 deletion_queue_.clear(); |
| 268 live_requests_.clear(); | 187 |
| 188 // Release all references held to dependent sources. |
| 189 for (SourceIDToInfoMap::iterator it = requests_.begin(); |
| 190 it != requests_.end(); |
| 191 ++it) { |
| 192 ReleaseAllReferencesToDependencies(&(it->second)); |
| 193 } |
| 194 requests_.clear(); |
| 269 } | 195 } |
| 270 | 196 |
| 271 void PassiveLogCollector::RequestTrackerBase::AppendAllEntries( | 197 void PassiveLogCollector::RequestTrackerBase::AppendAllEntries( |
| 272 EntryList* out) const { | 198 EntryList* out) const { |
| 273 AppendAllEntriesFromRequests(GetLiveRequests(), out); | 199 // Append all of the entries for each of the sources. |
| 274 AppendAllEntriesFromRequests(GetRecentlyDeceased(), out); | 200 for (SourceIDToInfoMap::const_iterator it = requests_.begin(); |
| 201 it != requests_.end(); |
| 202 ++it) { |
| 203 const RequestInfo& info = it->second; |
| 204 out->insert(out->end(), info.entries.begin(), info.entries.end()); |
| 205 } |
| 275 } | 206 } |
| 276 | 207 |
| 277 void PassiveLogCollector::RequestTrackerBase::InsertIntoGraveyard( | 208 void PassiveLogCollector::RequestTrackerBase::AddToDeletionQueue( |
| 278 const RequestInfo& info) { | 209 uint32 source_id) { |
| 279 // Enforce a bound on the graveyard size, by treating it as a | 210 DCHECK(requests_.find(source_id) != requests_.end()); |
| 280 // circular buffer. | 211 DCHECK(!requests_.find(source_id)->second.is_alive); |
| 281 if (graveyard_.size() < max_graveyard_size_) { | 212 DCHECK_GE(requests_.find(source_id)->second.reference_count, 0); |
| 282 // Still growing to maximum capacity. | 213 DCHECK_LE(deletion_queue_.size(), max_graveyard_size_); |
| 283 DCHECK_EQ(next_graveyard_index_, graveyard_.size()); | 214 |
| 284 graveyard_.push_back(info); | 215 deletion_queue_.push_back(source_id); |
| 285 } else { | 216 |
| 286 // At maximum capacity, overwite the oldest entry. | 217 // After the deletion queue has reached its maximum size, start |
| 287 graveyard_[next_graveyard_index_] = info; | 218 // deleting requests in FIFO order. |
| 219 if (deletion_queue_.size() > max_graveyard_size_) { |
| 220 uint32 oldest = deletion_queue_.front(); |
| 221 deletion_queue_.pop_front(); |
| 222 DeleteRequestInfo(oldest); |
| 288 } | 223 } |
| 289 next_graveyard_index_ = (next_graveyard_index_ + 1) % max_graveyard_size_; | 224 } |
| 225 |
| 226 void PassiveLogCollector::RequestTrackerBase::AdjustReferenceCountForSource( |
| 227 int offset, uint32 source_id) { |
| 228 DCHECK(offset == -1 || offset == 1) << "invalid offset: " << offset; |
| 229 |
| 230 // In general it is invalid to call AdjustReferenceCountForSource() on |
| 231 // source that doesn't exist. However, it is possible that if |
| 232 // RequestTrackerBase::Clear() was previously called this can happen. |
| 233 // TODO(eroman): Add a unit-test that exercises this case. |
| 234 SourceIDToInfoMap::iterator it = requests_.find(source_id); |
| 235 if (it == requests_.end()) |
| 236 return; |
| 237 |
| 238 RequestInfo& info = it->second; |
| 239 DCHECK_GE(info.reference_count, 0); |
| 240 DCHECK_GE(info.reference_count + offset, 0); |
| 241 info.reference_count += offset; |
| 242 |
| 243 if (!info.is_alive) { |
| 244 if (info.reference_count == 1 && offset == 1) { |
| 245 // If we just added a reference to a dead source that had no references, |
| 246 // it must have been in the deletion queue, so remove it from the queue. |
| 247 DeletionQueue::iterator it = |
| 248 std::remove(deletion_queue_.begin(), deletion_queue_.end(), |
| 249 source_id); |
| 250 DCHECK(it != deletion_queue_.end()); |
| 251 deletion_queue_.erase(it); |
| 252 } else if (info.reference_count == 0) { |
| 253 // If we just released the final reference to a dead request, go ahead |
| 254 // and delete it right away. |
| 255 DeleteRequestInfo(source_id); |
| 256 } |
| 257 } |
| 258 } |
| 259 |
| 260 void PassiveLogCollector::RequestTrackerBase::AddReferenceToSourceDependency( |
| 261 const net::NetLog::Source& source, RequestInfo* info) { |
| 262 // Find the tracker which should be holding |source|. |
| 263 DCHECK(parent_); |
| 264 RequestTrackerBase* tracker = |
| 265 parent_->GetTrackerForSourceType(source.type); |
| 266 DCHECK(tracker); |
| 267 |
| 268 // Tell the owning tracker to increment the reference count of |source|. |
| 269 tracker->AdjustReferenceCountForSource(1, source.id); |
| 270 |
| 271 // Make a note to release this reference once |info| is destroyed. |
| 272 info->dependencies.push_back(source); |
| 273 } |
| 274 |
| 275 void |
| 276 PassiveLogCollector::RequestTrackerBase::ReleaseAllReferencesToDependencies( |
| 277 RequestInfo* info) { |
| 278 // Release all references |info| was holding to dependent sources. |
| 279 for (SourceDependencyList::const_iterator it = info->dependencies.begin(); |
| 280 it != info->dependencies.end(); ++it) { |
| 281 const net::NetLog::Source& source = *it; |
| 282 |
| 283 // Find the tracker which should be holding |source|. |
| 284 DCHECK(parent_); |
| 285 RequestTrackerBase* tracker = |
| 286 parent_->GetTrackerForSourceType(source.type); |
| 287 DCHECK(tracker); |
| 288 |
| 289 // Tell the owning tracker to decrement the reference count of |source|. |
| 290 tracker->AdjustReferenceCountForSource(-1, source.id); |
| 291 } |
| 292 |
| 293 info->dependencies.clear(); |
| 290 } | 294 } |
| 291 | 295 |
| 292 //---------------------------------------------------------------------------- | 296 //---------------------------------------------------------------------------- |
| 293 // ConnectJobTracker | 297 // ConnectJobTracker |
| 294 //---------------------------------------------------------------------------- | 298 //---------------------------------------------------------------------------- |
| 295 | 299 |
| 296 const size_t PassiveLogCollector::ConnectJobTracker::kMaxGraveyardSize = 15; | 300 const size_t PassiveLogCollector::ConnectJobTracker::kMaxGraveyardSize = 15; |
| 297 | 301 |
| 298 PassiveLogCollector::ConnectJobTracker::ConnectJobTracker() | 302 PassiveLogCollector::ConnectJobTracker::ConnectJobTracker( |
| 299 : RequestTrackerBase(kMaxGraveyardSize) { | 303 PassiveLogCollector* parent) |
| 304 : RequestTrackerBase(kMaxGraveyardSize, parent) { |
| 300 } | 305 } |
| 301 | 306 |
| 302 PassiveLogCollector::RequestTrackerBase::Action | 307 PassiveLogCollector::RequestTrackerBase::Action |
| 303 PassiveLogCollector::ConnectJobTracker::DoAddEntry(const Entry& entry, | 308 PassiveLogCollector::ConnectJobTracker::DoAddEntry(const Entry& entry, |
| 304 RequestInfo* out_info) { | 309 RequestInfo* out_info) { |
| 305 AddEntryToRequestInfo(entry, out_info); | 310 AddEntryToRequestInfo(entry, out_info); |
| 306 | 311 |
| 307 if (entry.type == net::NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_ID) { | 312 if (entry.type == net::NetLog::TYPE_CONNECT_JOB_SET_SOCKET) { |
| 308 SetSubordinateSource(out_info, entry); | 313 const net::NetLog::Source& source_dependency = |
| 314 static_cast<net::NetLogSourceParameter*>(entry.params.get())->value(); |
| 315 AddReferenceToSourceDependency(source_dependency, out_info); |
| 309 } | 316 } |
| 310 | 317 |
| 311 // If this is the end of the connect job, move the request to the graveyard. | 318 // If this is the end of the connect job, move the request to the graveyard. |
| 312 if (entry.type == net::NetLog::TYPE_SOCKET_POOL_CONNECT_JOB && | 319 if (entry.type == net::NetLog::TYPE_SOCKET_POOL_CONNECT_JOB && |
| 313 entry.phase == net::NetLog::PHASE_END) { | 320 entry.phase == net::NetLog::PHASE_END) { |
| 314 return ACTION_MOVE_TO_GRAVEYARD; | 321 return ACTION_MOVE_TO_GRAVEYARD; |
| 315 } | 322 } |
| 316 | 323 |
| 317 return ACTION_NONE; | 324 return ACTION_NONE; |
| 318 } | 325 } |
| 319 | 326 |
| 320 void PassiveLogCollector::ConnectJobTracker::AppendLogEntries( | |
| 321 RequestInfo* out_info, uint32 connect_id) { | |
| 322 RequestInfo* connect_info = GetRequestInfo(connect_id); | |
| 323 if (!connect_info) { | |
| 324 net::NetLogStringParameter* text = new net::NetLogStringParameter( | |
| 325 "todo", StringPrintf("Used ConnectJob id=%u", connect_id)); | |
| 326 Entry new_entry(0, net::NetLog::TYPE_TODO_STRING, base::TimeTicks(), | |
| 327 net::NetLog::Source(net::NetLog::SOURCE_CONNECT_JOB, | |
| 328 connect_id), | |
| 329 net::NetLog::PHASE_NONE, text); | |
| 330 AddEntryToRequestInfo(new_entry, out_info); | |
| 331 return; | |
| 332 } | |
| 333 | |
| 334 AppendToRequestInfo(*connect_info, out_info); | |
| 335 std::sort(out_info->entries.begin(), out_info->entries.end(), | |
| 336 &SortByOrderComparator); | |
| 337 out_info->num_entries_truncated += connect_info->num_entries_truncated; | |
| 338 | |
| 339 if (connect_info->subordinate_source.is_valid()) | |
| 340 AppendLogEntries(out_info, connect_info->subordinate_source.id); | |
| 341 } | |
| 342 | |
| 343 //---------------------------------------------------------------------------- | 327 //---------------------------------------------------------------------------- |
| 344 // SocketTracker | 328 // SocketTracker |
| 345 //---------------------------------------------------------------------------- | 329 //---------------------------------------------------------------------------- |
| 346 | 330 |
| 347 const size_t PassiveLogCollector::SocketTracker::kMaxGraveyardSize = 15; | 331 const size_t PassiveLogCollector::SocketTracker::kMaxGraveyardSize = 15; |
| 348 | 332 |
| 349 PassiveLogCollector::SocketTracker::SocketTracker() | 333 PassiveLogCollector::SocketTracker::SocketTracker() |
| 350 : RequestTrackerBase(kMaxGraveyardSize) { | 334 : RequestTrackerBase(kMaxGraveyardSize, NULL) { |
| 351 } | 335 } |
| 352 | 336 |
| 353 PassiveLogCollector::RequestTrackerBase::Action | 337 PassiveLogCollector::RequestTrackerBase::Action |
| 354 PassiveLogCollector::SocketTracker::DoAddEntry(const Entry& entry, | 338 PassiveLogCollector::SocketTracker::DoAddEntry(const Entry& entry, |
| 355 RequestInfo* out_info) { | 339 RequestInfo* out_info) { |
| 356 int int_arg; | 340 // TODO(eroman): aggregate the byte counts once truncation starts to happen, |
| 357 switch (entry.type) { | 341 // to summarize transaction read/writes for each SOCKET_IN_USE |
| 358 case net::NetLog::TYPE_SOCKET_BYTES_SENT: | 342 // section. |
| 359 int_arg = static_cast<net::NetLogIntegerParameter*>( | 343 if (entry.type == net::NetLog::TYPE_SOCKET_BYTES_SENT || |
| 360 entry.params.get())->value(); | 344 entry.type == net::NetLog::TYPE_SOCKET_BYTES_RECEIVED) { |
| 361 out_info->total_bytes_transmitted += int_arg; | 345 return ACTION_NONE; |
| 362 out_info->bytes_transmitted += int_arg; | |
| 363 out_info->last_tx_rx_time = entry.time; | |
| 364 out_info->last_tx_rx_position = entry.order; | |
| 365 break; | |
| 366 case net::NetLog::TYPE_SOCKET_BYTES_RECEIVED: | |
| 367 int_arg = static_cast<net::NetLogIntegerParameter*>( | |
| 368 entry.params.get())->value(); | |
| 369 out_info->total_bytes_received += int_arg; | |
| 370 out_info->bytes_received += int_arg; | |
| 371 out_info->last_tx_rx_time = entry.time; | |
| 372 out_info->last_tx_rx_position = entry.order; | |
| 373 break; | |
| 374 case net::NetLog::TYPE_TCP_SOCKET_DONE: | |
| 375 return ACTION_MOVE_TO_GRAVEYARD; | |
| 376 default: | |
| 377 AddEntryToRequestInfo(entry, out_info); | |
| 378 break; | |
| 379 } | |
| 380 return ACTION_NONE; | |
| 381 } | |
| 382 | |
| 383 void PassiveLogCollector::SocketTracker::AppendLogEntries( | |
| 384 RequestInfo* out_info, uint32 socket_id, bool clear) { | |
| 385 RequestInfo* socket_info = GetRequestInfo(socket_id); | |
| 386 if (!socket_info) { | |
| 387 net::NetLogStringParameter* text = new net::NetLogStringParameter( | |
| 388 "todo", StringPrintf("Used Socket id=%u.", socket_id)); | |
| 389 Entry new_entry(0, net::NetLog::TYPE_TODO_STRING, base::TimeTicks(), | |
| 390 net::NetLog::Source(net::NetLog::SOURCE_SOCKET, socket_id), | |
| 391 net::NetLog::PHASE_NONE, text); | |
| 392 AddEntryToRequestInfo(new_entry, out_info); | |
| 393 return; | |
| 394 } | 346 } |
| 395 | 347 |
| 396 AppendToRequestInfo(*socket_info, out_info); | 348 AddEntryToRequestInfo(entry, out_info); |
| 397 out_info->num_entries_truncated += socket_info->num_entries_truncated; | |
| 398 | 349 |
| 399 // Synthesize a log entry for bytes sent and received. | 350 if (entry.type == net::NetLog::TYPE_SOCKET_ALIVE && |
| 400 if (socket_info->bytes_transmitted > 0 || socket_info->bytes_received > 0) { | 351 entry.phase == net::NetLog::PHASE_END) { |
| 401 net::NetLogStringParameter* text = new net::NetLogStringParameter( | 352 return ACTION_MOVE_TO_GRAVEYARD; |
| 402 "stats", | |
| 403 StringPrintf("Tx/Rx: %"PRIu64"/%"PRIu64" [%"PRIu64"/%"PRIu64 | |
| 404 " total on socket] (Bytes)", | |
| 405 socket_info->bytes_transmitted, | |
| 406 socket_info->bytes_received, | |
| 407 socket_info->total_bytes_transmitted, | |
| 408 socket_info->total_bytes_received)); | |
| 409 Entry new_entry(socket_info->last_tx_rx_position, | |
| 410 net::NetLog::TYPE_TODO_STRING, | |
| 411 socket_info->last_tx_rx_time, | |
| 412 net::NetLog::Source(net::NetLog::SOURCE_SOCKET, socket_id), | |
| 413 net::NetLog::PHASE_NONE, | |
| 414 text); | |
| 415 AddEntryToRequestInfo(new_entry, out_info); | |
| 416 } | 353 } |
| 417 std::sort(out_info->entries.begin(), out_info->entries.end(), | |
| 418 &SortByOrderComparator); | |
| 419 | 354 |
| 420 if (clear) | 355 return ACTION_NONE; |
| 421 ClearInfo(socket_info); | |
| 422 } | |
| 423 | |
| 424 void PassiveLogCollector::SocketTracker::ClearInfo(RequestInfo* info) { | |
| 425 info->entries.clear(); | |
| 426 info->num_entries_truncated = 0; | |
| 427 info->bytes_transmitted = 0; | |
| 428 info->bytes_received = 0; | |
| 429 info->last_tx_rx_position = 0; | |
| 430 info->last_tx_rx_time = base::TimeTicks(); | |
| 431 } | 356 } |
| 432 | 357 |
| 433 //---------------------------------------------------------------------------- | 358 //---------------------------------------------------------------------------- |
| 434 // RequestTracker | 359 // RequestTracker |
| 435 //---------------------------------------------------------------------------- | 360 //---------------------------------------------------------------------------- |
| 436 | 361 |
| 437 const size_t PassiveLogCollector::RequestTracker::kMaxGraveyardSize = 25; | 362 const size_t PassiveLogCollector::RequestTracker::kMaxGraveyardSize = 25; |
| 438 | 363 |
| 439 PassiveLogCollector::RequestTracker::RequestTracker( | 364 PassiveLogCollector::RequestTracker::RequestTracker(PassiveLogCollector* parent) |
| 440 ConnectJobTracker* connect_job_tracker, SocketTracker* socket_tracker) | 365 : RequestTrackerBase(kMaxGraveyardSize, parent) { |
| 441 : RequestTrackerBase(kMaxGraveyardSize), | |
| 442 connect_job_tracker_(connect_job_tracker), | |
| 443 socket_tracker_(socket_tracker) { | |
| 444 } | 366 } |
| 445 | 367 |
| 446 PassiveLogCollector::RequestTrackerBase::Action | 368 PassiveLogCollector::RequestTrackerBase::Action |
| 447 PassiveLogCollector::RequestTracker::DoAddEntry(const Entry& entry, | 369 PassiveLogCollector::RequestTracker::DoAddEntry(const Entry& entry, |
| 448 RequestInfo* out_info) { | 370 RequestInfo* out_info) { |
| 449 // We expect up to three events with IDs. | 371 if (entry.type == net::NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB || |
| 450 // - Begin SOCKET_POOL_CONNECT_JOB_ID: Means a ConnectJob was created for | 372 entry.type == net::NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET) { |
| 451 // this request. Including it for now, but the resulting socket may be | 373 const net::NetLog::Source& source_dependency = |
| 452 // used for a different request. | 374 static_cast<net::NetLogSourceParameter*>(entry.params.get())->value(); |
| 453 // - End SOCKET_POOL_CONNECT_JOB_ID: The named ConnectJob completed and | 375 AddReferenceToSourceDependency(source_dependency, out_info); |
| 454 // this request will be getting the socket from that request. | |
| 455 // - SOCKET_POOL_SOCKET_ID: The given socket will be used for this request. | |
| 456 // | |
| 457 // The action to take when seeing these events depends on the current | |
| 458 // content of the |subordinate_source| field: | |
| 459 // |subordinate_source| is invalid (fresh state). | |
| 460 // - Begin SOCKET_POOL_CONNECT_JOB_ID: Set |subordinate_source|. | |
| 461 // - End SOCKET_POOL_CONNECT_JOB_ID: Integrate the named ConnectJob ID. | |
| 462 // - SOCKET_POOL_SOCKET_ID: Set |subordinate_source|. | |
| 463 // |subordinate_source| is a ConnectJob: | |
| 464 // - Begin SOCKET_POOL_CONNECT_JOB_ID: Set |subordinate_source|. | |
| 465 // - End SOCKET_POOL_CONNECT_JOB_ID: Integrate the named ConnectJob ID and | |
| 466 // clear the |subordinate_source|. | |
| 467 // - SOCKET_POOL_SOCKET_ID: Set |subordinate_source|. (The request was | |
| 468 // assigned a new idle socket, after starting a ConnectJob.) | |
| 469 // |subordinate_source| is a Socket: | |
| 470 // First, integrate the subordinate socket source, then: | |
| 471 // - Begin SOCKET_POOL_CONNECT_JOB_ID: Set |subordinate_source|. | |
| 472 // (Connection restarted with a new ConnectJob.) | |
| 473 // - End SOCKET_POOL_CONNECT_JOB_ID: Integrate the named ConnectJob ID and | |
| 474 // clear the |subordinate_source|. (Connection restarted with a late bound | |
| 475 // ConnectJob.) | |
| 476 // - SOCKET_POOL_SOCKET_ID: Set |subordinate_source|. (Connection | |
| 477 // restarted and got an idle socket.) | |
| 478 if (entry.type == net::NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_ID || | |
| 479 entry.type == net::NetLog::TYPE_SOCKET_POOL_SOCKET_ID) { | |
| 480 | |
| 481 if (out_info->subordinate_source.is_valid() && | |
| 482 out_info->subordinate_source.type == net::NetLog::SOURCE_SOCKET) | |
| 483 IntegrateSubordinateSource(out_info, true); | |
| 484 | |
| 485 SetSubordinateSource(out_info, entry); | |
| 486 | |
| 487 if (entry.phase == net::NetLog::PHASE_END && | |
| 488 entry.type == net::NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_ID) { | |
| 489 IntegrateSubordinateSource(out_info, true); | |
| 490 out_info->subordinate_source.id = net::NetLog::Source::kInvalidId; | |
| 491 } | |
| 492 } | 376 } |
| 493 | 377 |
| 494 AddEntryToRequestInfo(entry, out_info); | 378 AddEntryToRequestInfo(entry, out_info); |
| 495 | 379 |
| 496 // If the request has ended, move it to the graveyard. | 380 // If the request has ended, move it to the graveyard. |
| 497 if (entry.type == net::NetLog::TYPE_REQUEST_ALIVE && | 381 if (entry.type == net::NetLog::TYPE_REQUEST_ALIVE && |
| 498 entry.phase == net::NetLog::PHASE_END) { | 382 entry.phase == net::NetLog::PHASE_END) { |
| 499 IntegrateSubordinateSource(out_info, true); | |
| 500 if (StartsWithASCII(out_info->GetURL(), "chrome://", false)) { | 383 if (StartsWithASCII(out_info->GetURL(), "chrome://", false)) { |
| 501 // Avoid sending "chrome://" requests to the graveyard, since it just | 384 // Avoid sending "chrome://" requests to the graveyard, since it just |
| 502 // adds to clutter. | 385 // adds to clutter. |
| 503 return ACTION_DELETE; | 386 return ACTION_DELETE; |
| 504 } | 387 } |
| 505 return ACTION_MOVE_TO_GRAVEYARD; | 388 return ACTION_MOVE_TO_GRAVEYARD; |
| 506 } | 389 } |
| 507 | 390 |
| 508 return ACTION_NONE; | 391 return ACTION_NONE; |
| 509 } | 392 } |
| 510 | 393 |
| 511 void PassiveLogCollector::RequestTracker::IntegrateSubordinateSource( | |
| 512 RequestInfo* info, bool clear_entries) const { | |
| 513 if (!info->subordinate_source.is_valid()) | |
| 514 return; | |
| 515 | |
| 516 uint32 subordinate_id = info->subordinate_source.id; | |
| 517 switch (info->subordinate_source.type) { | |
| 518 case net::NetLog::SOURCE_CONNECT_JOB: | |
| 519 connect_job_tracker_->AppendLogEntries(info, subordinate_id); | |
| 520 break; | |
| 521 case net::NetLog::SOURCE_SOCKET: | |
| 522 socket_tracker_->AppendLogEntries(info, subordinate_id, clear_entries); | |
| 523 break; | |
| 524 default: | |
| 525 NOTREACHED(); | |
| 526 break; | |
| 527 } | |
| 528 } | |
| 529 | |
| 530 //---------------------------------------------------------------------------- | 394 //---------------------------------------------------------------------------- |
| 531 // InitProxyResolverTracker | 395 // InitProxyResolverTracker |
| 532 //---------------------------------------------------------------------------- | 396 //---------------------------------------------------------------------------- |
| 533 | 397 |
| 534 PassiveLogCollector::InitProxyResolverTracker::InitProxyResolverTracker() {} | 398 const size_t PassiveLogCollector::InitProxyResolverTracker::kMaxGraveyardSize = |
| 399 3; |
| 535 | 400 |
| 536 void PassiveLogCollector::InitProxyResolverTracker::OnAddEntry( | 401 PassiveLogCollector::InitProxyResolverTracker::InitProxyResolverTracker() |
| 537 const Entry& entry) { | 402 : RequestTrackerBase(kMaxGraveyardSize, NULL) { |
| 403 } |
| 404 |
| 405 PassiveLogCollector::RequestTrackerBase::Action |
| 406 PassiveLogCollector::InitProxyResolverTracker::DoAddEntry( |
| 407 const Entry& entry, RequestInfo* out_info) { |
| 408 AddEntryToRequestInfo(entry, out_info); |
| 538 if (entry.type == net::NetLog::TYPE_INIT_PROXY_RESOLVER && | 409 if (entry.type == net::NetLog::TYPE_INIT_PROXY_RESOLVER && |
| 539 entry.phase == net::NetLog::PHASE_BEGIN) { | 410 entry.phase == net::NetLog::PHASE_END) { |
| 540 // If this is the start of a new InitProxyResolver, overwrite the old data. | 411 return ACTION_MOVE_TO_GRAVEYARD; |
| 541 entries_.clear(); | |
| 542 entries_.push_back(entry); | |
| 543 } else { | 412 } else { |
| 544 // Otherwise append it to the log for the latest InitProxyResolver. | 413 return ACTION_NONE; |
| 545 if (!entries_.empty() && entries_[0].source.id != entry.source.id) { | |
| 546 // If this entry doesn't match what we think was the latest | |
| 547 // InitProxyResolver, drop it. (This shouldn't happen, but we will guard | |
| 548 // against it). | |
| 549 return; | |
| 550 } | |
| 551 entries_.push_back(entry); | |
| 552 } | 414 } |
| 553 | |
| 554 // Safety net: INIT_PROXY_RESOLVER shouldn't generate many messages, but in | |
| 555 // case something goes wrong, avoid exploding the memory usage. | |
| 556 if (entries_.size() > kMaxNumEntriesPerLog) | |
| 557 entries_.clear(); | |
| 558 } | 415 } |
| 559 | 416 |
| 560 //---------------------------------------------------------------------------- | 417 //---------------------------------------------------------------------------- |
| 561 // SpdySessionTracker | 418 // SpdySessionTracker |
| 562 //---------------------------------------------------------------------------- | 419 //---------------------------------------------------------------------------- |
| 563 | 420 |
| 564 const size_t PassiveLogCollector::SpdySessionTracker::kMaxGraveyardSize = 10; | 421 const size_t PassiveLogCollector::SpdySessionTracker::kMaxGraveyardSize = 10; |
| 565 | 422 |
| 566 PassiveLogCollector::SpdySessionTracker::SpdySessionTracker() | 423 PassiveLogCollector::SpdySessionTracker::SpdySessionTracker() |
| 567 : RequestTrackerBase(kMaxGraveyardSize) { | 424 : RequestTrackerBase(kMaxGraveyardSize, NULL) { |
| 568 } | 425 } |
| 569 | 426 |
| 570 PassiveLogCollector::RequestTrackerBase::Action | 427 PassiveLogCollector::RequestTrackerBase::Action |
| 571 PassiveLogCollector::SpdySessionTracker::DoAddEntry(const Entry& entry, | 428 PassiveLogCollector::SpdySessionTracker::DoAddEntry(const Entry& entry, |
| 572 RequestInfo* out_info) { | 429 RequestInfo* out_info) { |
| 430 AddEntryToRequestInfo(entry, out_info); |
| 573 if (entry.type == net::NetLog::TYPE_SPDY_SESSION && | 431 if (entry.type == net::NetLog::TYPE_SPDY_SESSION && |
| 574 entry.phase == net::NetLog::PHASE_END) { | 432 entry.phase == net::NetLog::PHASE_END) { |
| 575 return ACTION_MOVE_TO_GRAVEYARD; | 433 return ACTION_MOVE_TO_GRAVEYARD; |
| 576 } else { | 434 } else { |
| 577 AddEntryToRequestInfo(entry, out_info); | |
| 578 return ACTION_NONE; | 435 return ACTION_NONE; |
| 579 } | 436 } |
| 580 } | 437 } |
| OLD | NEW |