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 |