| 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 |