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 "net/url_request/url_request_throttler_manager.h" | 5 #include "net/url_request/url_request_throttler_manager.h" |
6 | 6 |
7 #include <list> | 7 #include <list> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
11 #include "base/synchronization/lock.h" | |
12 #include "base/threading/platform_thread.h" | |
13 | |
14 namespace { | |
15 | |
16 // AccessLog records threads that have accessed the URLRequestThrottlerManager | |
17 // singleton object. | |
18 // TODO(yzshen): It is used for diagnostic purpose and should be removed once we | |
19 // figure out crbug.com/71721 | |
20 class AccessLog { | |
21 public: | |
22 static const size_t kAccessLogSize = 4; | |
23 | |
24 AccessLog() { | |
25 for (size_t i = 0; i < kAccessLogSize; ++i) { | |
26 thread_ids_[i] = base::kInvalidThreadId; | |
27 urls_[i][0] = '\0'; | |
28 } | |
29 } | |
30 | |
31 AccessLog(const AccessLog& log) { | |
32 base::AutoLock auto_lock(log.lock_); | |
33 for (size_t i = 0; i < kAccessLogSize; ++i) { | |
34 thread_ids_[i] = log.thread_ids_[i]; | |
35 base::strlcpy(urls_[i], log.urls_[i], kUrlBufferSize); | |
36 } | |
37 } | |
38 | |
39 void Add(base::PlatformThreadId id, const GURL& url) { | |
40 base::AutoLock auto_lock(lock_); | |
41 for (size_t i = 0; i < kAccessLogSize; ++i) { | |
42 if (thread_ids_[i] == id) { | |
43 return; | |
44 } else if (thread_ids_[i] == base::kInvalidThreadId) { | |
45 DCHECK(i == 0); | |
46 thread_ids_[i] = id; | |
47 base::strlcpy(urls_[i], url.spec().c_str(), kUrlBufferSize); | |
48 return; | |
49 } | |
50 } | |
51 } | |
52 | |
53 private: | |
54 static const size_t kUrlBufferSize = 128; | |
55 | |
56 mutable base::Lock lock_; | |
57 base::PlatformThreadId thread_ids_[kAccessLogSize]; | |
58 // Records the URL argument of the first RegisterRequestUrl() call on each | |
59 // thread. | |
60 char urls_[kAccessLogSize][kUrlBufferSize]; | |
61 }; | |
62 | |
63 AccessLog access_log; | |
64 | |
65 } // namespace | |
66 | 11 |
67 namespace net { | 12 namespace net { |
68 | 13 |
69 const unsigned int URLRequestThrottlerManager::kMaximumNumberOfEntries = 1500; | 14 const unsigned int URLRequestThrottlerManager::kMaximumNumberOfEntries = 1500; |
70 const unsigned int URLRequestThrottlerManager::kRequestsBetweenCollecting = 200; | 15 const unsigned int URLRequestThrottlerManager::kRequestsBetweenCollecting = 200; |
71 | 16 |
72 URLRequestThrottlerManager* URLRequestThrottlerManager::GetInstance() { | 17 URLRequestThrottlerManager* URLRequestThrottlerManager::GetInstance() { |
73 return Singleton<URLRequestThrottlerManager>::get(); | 18 return Singleton<URLRequestThrottlerManager>::get(); |
74 } | 19 } |
75 | 20 |
76 scoped_refptr<URLRequestThrottlerEntryInterface> | 21 scoped_refptr<URLRequestThrottlerEntryInterface> |
77 URLRequestThrottlerManager::RegisterRequestUrl(const GURL &url) { | 22 URLRequestThrottlerManager::RegisterRequestUrl(const GURL &url) { |
78 if (record_access_log_) | |
79 access_log.Add(base::PlatformThread::CurrentId(), url); | |
80 | |
81 // Normalize the url. | 23 // Normalize the url. |
82 std::string url_id = GetIdFromUrl(url); | 24 std::string url_id = GetIdFromUrl(url); |
83 | 25 |
84 // Periodically garbage collect old entries. | 26 // Periodically garbage collect old entries. |
85 GarbageCollectEntriesIfNecessary(); | 27 GarbageCollectEntriesIfNecessary(); |
86 | 28 |
87 // Find the entry in the map or create it. | 29 // Find the entry in the map or create it. |
88 UrlEntryMap::iterator i = url_entries_.find(url_id); | 30 UrlEntryMap::iterator i = url_entries_.find(url_id); |
89 if (i == url_entries_.end()) { | 31 if (i == url_entries_.end()) { |
90 scoped_refptr<URLRequestThrottlerEntry> entry( | 32 scoped_refptr<URLRequestThrottlerEntry> entry( |
(...skipping 26 matching lines...) Expand all Loading... |
117 } | 59 } |
118 | 60 |
119 void URLRequestThrottlerManager::EraseEntryForTests(const GURL& url) { | 61 void URLRequestThrottlerManager::EraseEntryForTests(const GURL& url) { |
120 // Normalize the url. | 62 // Normalize the url. |
121 std::string url_id = GetIdFromUrl(url); | 63 std::string url_id = GetIdFromUrl(url); |
122 url_entries_.erase(url_id); | 64 url_entries_.erase(url_id); |
123 } | 65 } |
124 | 66 |
125 void URLRequestThrottlerManager::InitializeOptions(bool enforce_throttling) { | 67 void URLRequestThrottlerManager::InitializeOptions(bool enforce_throttling) { |
126 enforce_throttling_ = enforce_throttling; | 68 enforce_throttling_ = enforce_throttling; |
127 record_access_log_ = true; | |
128 } | 69 } |
129 | 70 |
130 URLRequestThrottlerManager::URLRequestThrottlerManager() | 71 URLRequestThrottlerManager::URLRequestThrottlerManager() |
131 : requests_since_last_gc_(0), | 72 : requests_since_last_gc_(0), |
132 enforce_throttling_(true), | 73 enforce_throttling_(true) { |
133 record_access_log_(false) { | |
134 } | 74 } |
135 | 75 |
136 URLRequestThrottlerManager::~URLRequestThrottlerManager() { | 76 URLRequestThrottlerManager::~URLRequestThrottlerManager() { |
137 // Delete all entries. | 77 // Delete all entries. |
138 url_entries_.clear(); | 78 url_entries_.clear(); |
139 } | 79 } |
140 | 80 |
141 std::string URLRequestThrottlerManager::GetIdFromUrl(const GURL& url) const { | 81 std::string URLRequestThrottlerManager::GetIdFromUrl(const GURL& url) const { |
142 if (!url.is_valid()) | 82 if (!url.is_valid()) |
143 return url.possibly_invalid_spec(); | 83 return url.possibly_invalid_spec(); |
(...skipping 14 matching lines...) Expand all Loading... |
158 void URLRequestThrottlerManager::GarbageCollectEntriesIfNecessary() { | 98 void URLRequestThrottlerManager::GarbageCollectEntriesIfNecessary() { |
159 requests_since_last_gc_++; | 99 requests_since_last_gc_++; |
160 if (requests_since_last_gc_ < kRequestsBetweenCollecting) | 100 if (requests_since_last_gc_ < kRequestsBetweenCollecting) |
161 return; | 101 return; |
162 | 102 |
163 requests_since_last_gc_ = 0; | 103 requests_since_last_gc_ = 0; |
164 GarbageCollectEntries(); | 104 GarbageCollectEntries(); |
165 } | 105 } |
166 | 106 |
167 void URLRequestThrottlerManager::GarbageCollectEntries() { | 107 void URLRequestThrottlerManager::GarbageCollectEntries() { |
168 volatile AccessLog access_log_copy(access_log); | |
169 | |
170 // The more efficient way to remove outdated entries is iterating over all the | 108 // The more efficient way to remove outdated entries is iterating over all the |
171 // elements in the map, and removing those outdated ones during the process. | 109 // elements in the map, and removing those outdated ones during the process. |
172 // However, one hypothesis about the cause of crbug.com/71721 is that some | 110 // However, one hypothesis about the cause of crbug.com/71721 is that some |
173 // kind of iterator error happens when we change the map during iteration. As | 111 // kind of iterator error happens when we change the map during iteration. As |
174 // a result, we write the code this way in order to track down the bug. | 112 // a result, we write the code this way in order to track down the bug. |
175 std::list<std::string> outdated_keys; | 113 std::list<std::string> outdated_keys; |
176 for (UrlEntryMap::iterator entry_iter = url_entries_.begin(); | 114 for (UrlEntryMap::iterator entry_iter = url_entries_.begin(); |
177 entry_iter != url_entries_.end(); ++entry_iter) { | 115 entry_iter != url_entries_.end(); ++entry_iter) { |
178 std::string key = entry_iter->first; | 116 std::string key = entry_iter->first; |
179 CHECK(entry_iter->second.get()); | 117 CHECK(entry_iter->second.get()); |
180 | 118 |
181 if ((entry_iter->second)->IsEntryOutdated()) | 119 if ((entry_iter->second)->IsEntryOutdated()) |
182 outdated_keys.push_back(key); | 120 outdated_keys.push_back(key); |
183 } | 121 } |
184 for (std::list<std::string>::iterator key_iter = outdated_keys.begin(); | 122 for (std::list<std::string>::iterator key_iter = outdated_keys.begin(); |
185 key_iter != outdated_keys.end(); ++key_iter) { | 123 key_iter != outdated_keys.end(); ++key_iter) { |
186 url_entries_.erase(*key_iter); | 124 url_entries_.erase(*key_iter); |
187 } | 125 } |
188 | 126 |
189 // In case something broke we want to make sure not to grow indefinitely. | 127 // In case something broke we want to make sure not to grow indefinitely. |
190 while (url_entries_.size() > kMaximumNumberOfEntries) { | 128 while (url_entries_.size() > kMaximumNumberOfEntries) { |
191 url_entries_.erase(url_entries_.begin()); | 129 url_entries_.erase(url_entries_.begin()); |
192 } | 130 } |
193 } | 131 } |
194 | 132 |
195 } // namespace net | 133 } // namespace net |
OLD | NEW |