| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/disk_cache/backend_impl.h" | 5 #include "net/disk_cache/backend_impl.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
| 10 #include "base/files/file_path.h" | 10 #include "base/files/file_path.h" |
| 11 #include "base/hash.h" | 11 #include "base/hash.h" |
| 12 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
| 13 #include "base/metrics/field_trial.h" | 13 #include "base/metrics/field_trial.h" |
| 14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 15 #include "base/metrics/stats_counters.h" | 15 #include "base/metrics/stats_counters.h" |
| 16 #include "base/rand_util.h" | 16 #include "base/rand_util.h" |
| 17 #include "base/string_util.h" | 17 #include "base/string_util.h" |
| 18 #include "base/stringprintf.h" | 18 #include "base/stringprintf.h" |
| 19 #include "base/sys_info.h" | 19 #include "base/sys_info.h" |
| 20 #include "base/threading/thread_restrictions.h" | 20 #include "base/threading/thread_restrictions.h" |
| 21 #include "base/threading/worker_pool.h" | |
| 22 #include "base/time.h" | 21 #include "base/time.h" |
| 23 #include "base/timer.h" | 22 #include "base/timer.h" |
| 24 #include "net/base/net_errors.h" | 23 #include "net/base/net_errors.h" |
| 25 #include "net/disk_cache/cache_util.h" | 24 #include "net/disk_cache/cache_util.h" |
| 26 #include "net/disk_cache/entry_impl.h" | 25 #include "net/disk_cache/entry_impl.h" |
| 27 #include "net/disk_cache/errors.h" | 26 #include "net/disk_cache/errors.h" |
| 28 #include "net/disk_cache/experiments.h" | 27 #include "net/disk_cache/experiments.h" |
| 29 #include "net/disk_cache/file.h" | 28 #include "net/disk_cache/file.h" |
| 30 #include "net/disk_cache/mem_backend_impl.h" | |
| 31 #include "net/disk_cache/simple/simple_backend_impl.h" | |
| 32 | 29 |
| 33 // This has to be defined before including histogram_macros.h from this file. | 30 // This has to be defined before including histogram_macros.h from this file. |
| 34 #define NET_DISK_CACHE_BACKEND_IMPL_CC_ | 31 #define NET_DISK_CACHE_BACKEND_IMPL_CC_ |
| 35 #include "net/disk_cache/histogram_macros.h" | 32 #include "net/disk_cache/histogram_macros.h" |
| 36 | 33 |
| 37 using base::Time; | 34 using base::Time; |
| 38 using base::TimeDelta; | 35 using base::TimeDelta; |
| 39 using base::TimeTicks; | 36 using base::TimeTicks; |
| 40 | 37 |
| 41 namespace { | 38 namespace { |
| 42 | 39 |
| 43 const char* kIndexName = "index"; | 40 const char* kIndexName = "index"; |
| 44 const int kMaxOldFolders = 100; | |
| 45 | 41 |
| 46 // Seems like ~240 MB correspond to less than 50k entries for 99% of the people. | 42 // Seems like ~240 MB correspond to less than 50k entries for 99% of the people. |
| 47 // Note that the actual target is to keep the index table load factor under 55% | 43 // Note that the actual target is to keep the index table load factor under 55% |
| 48 // for most users. | 44 // for most users. |
| 49 const int k64kEntriesStore = 240 * 1000 * 1000; | 45 const int k64kEntriesStore = 240 * 1000 * 1000; |
| 50 const int kBaseTableLen = 64 * 1024; | 46 const int kBaseTableLen = 64 * 1024; |
| 51 const int kDefaultCacheSize = 80 * 1024 * 1024; | 47 const int kDefaultCacheSize = 80 * 1024 * 1024; |
| 52 | 48 |
| 53 // Avoid trimming the cache for the first 5 minutes (10 timer ticks). | 49 // Avoid trimming the cache for the first 5 minutes (10 timer ticks). |
| 54 const int kTrimDelay = 10; | 50 const int kTrimDelay = 10; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 71 return table_len * (k64kEntriesStore / kBaseTableLen); | 67 return table_len * (k64kEntriesStore / kBaseTableLen); |
| 72 } | 68 } |
| 73 | 69 |
| 74 size_t GetIndexSize(int table_len) { | 70 size_t GetIndexSize(int table_len) { |
| 75 size_t table_size = sizeof(disk_cache::CacheAddr) * table_len; | 71 size_t table_size = sizeof(disk_cache::CacheAddr) * table_len; |
| 76 return sizeof(disk_cache::IndexHeader) + table_size; | 72 return sizeof(disk_cache::IndexHeader) + table_size; |
| 77 } | 73 } |
| 78 | 74 |
| 79 // ------------------------------------------------------------------------ | 75 // ------------------------------------------------------------------------ |
| 80 | 76 |
| 81 // Returns a fully qualified name from path and name, using a given name prefix | |
| 82 // and index number. For instance, if the arguments are "/foo", "bar" and 5, it | |
| 83 // will return "/foo/old_bar_005". | |
| 84 base::FilePath GetPrefixedName(const base::FilePath& path, | |
| 85 const std::string& name, | |
| 86 int index) { | |
| 87 std::string tmp = base::StringPrintf("%s%s_%03d", "old_", | |
| 88 name.c_str(), index); | |
| 89 return path.AppendASCII(tmp); | |
| 90 } | |
| 91 | |
| 92 // This is a simple callback to cleanup old caches. | |
| 93 void CleanupCallback(const base::FilePath& path, const std::string& name) { | |
| 94 for (int i = 0; i < kMaxOldFolders; i++) { | |
| 95 base::FilePath to_delete = GetPrefixedName(path, name, i); | |
| 96 disk_cache::DeleteCache(to_delete, true); | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 // Returns a full path to rename the current cache, in order to delete it. path | |
| 101 // is the current folder location, and name is the current folder name. | |
| 102 base::FilePath GetTempCacheName(const base::FilePath& path, | |
| 103 const std::string& name) { | |
| 104 // We'll attempt to have up to kMaxOldFolders folders for deletion. | |
| 105 for (int i = 0; i < kMaxOldFolders; i++) { | |
| 106 base::FilePath to_delete = GetPrefixedName(path, name, i); | |
| 107 if (!file_util::PathExists(to_delete)) | |
| 108 return to_delete; | |
| 109 } | |
| 110 return base::FilePath(); | |
| 111 } | |
| 112 | |
| 113 // Moves the cache files to a new folder and creates a task to delete them. | |
| 114 bool DelayedCacheCleanup(const base::FilePath& full_path) { | |
| 115 // GetTempCacheName() and MoveCache() use synchronous file | |
| 116 // operations. | |
| 117 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
| 118 | |
| 119 base::FilePath current_path = full_path.StripTrailingSeparators(); | |
| 120 | |
| 121 base::FilePath path = current_path.DirName(); | |
| 122 base::FilePath name = current_path.BaseName(); | |
| 123 #if defined(OS_POSIX) | |
| 124 std::string name_str = name.value(); | |
| 125 #elif defined(OS_WIN) | |
| 126 // We created this file so it should only contain ASCII. | |
| 127 std::string name_str = WideToASCII(name.value()); | |
| 128 #endif | |
| 129 | |
| 130 base::FilePath to_delete = GetTempCacheName(path, name_str); | |
| 131 if (to_delete.empty()) { | |
| 132 LOG(ERROR) << "Unable to get another cache folder"; | |
| 133 return false; | |
| 134 } | |
| 135 | |
| 136 if (!disk_cache::MoveCache(full_path, to_delete)) { | |
| 137 LOG(ERROR) << "Unable to move cache folder " << full_path.value() << " to " | |
| 138 << to_delete.value(); | |
| 139 return false; | |
| 140 } | |
| 141 | |
| 142 base::WorkerPool::PostTask( | |
| 143 FROM_HERE, base::Bind(&CleanupCallback, path, name_str), true); | |
| 144 return true; | |
| 145 } | |
| 146 | |
| 147 // Sets group for the current experiment. Returns false if the files should be | 77 // Sets group for the current experiment. Returns false if the files should be |
| 148 // discarded. | 78 // discarded. |
| 149 bool InitExperiment(disk_cache::IndexHeader* header) { | 79 bool InitExperiment(disk_cache::IndexHeader* header) { |
| 150 if (header->experiment == disk_cache::EXPERIMENT_OLD_FILE1 || | 80 if (header->experiment == disk_cache::EXPERIMENT_OLD_FILE1 || |
| 151 header->experiment == disk_cache::EXPERIMENT_OLD_FILE2) { | 81 header->experiment == disk_cache::EXPERIMENT_OLD_FILE2) { |
| 152 // Discard current cache. | 82 // Discard current cache. |
| 153 return false; | 83 return false; |
| 154 } | 84 } |
| 155 | 85 |
| 156 header->experiment = disk_cache::NO_EXPERIMENT; | 86 header->experiment = disk_cache::NO_EXPERIMENT; |
| 157 return true; | 87 return true; |
| 158 } | 88 } |
| 159 | 89 |
| 160 // ------------------------------------------------------------------------ | |
| 161 | |
| 162 // This class takes care of building an instance of the backend. | |
| 163 class CacheCreator { | |
| 164 public: | |
| 165 CacheCreator(const base::FilePath& path, bool force, int max_bytes, | |
| 166 net::CacheType type, uint32 flags, | |
| 167 base::MessageLoopProxy* thread, net::NetLog* net_log, | |
| 168 disk_cache::Backend** backend, | |
| 169 const net::CompletionCallback& callback) | |
| 170 : path_(path), | |
| 171 force_(force), | |
| 172 retry_(false), | |
| 173 max_bytes_(max_bytes), | |
| 174 type_(type), | |
| 175 flags_(flags), | |
| 176 thread_(thread), | |
| 177 backend_(backend), | |
| 178 callback_(callback), | |
| 179 cache_(NULL), | |
| 180 net_log_(net_log) { | |
| 181 } | |
| 182 ~CacheCreator() {} | |
| 183 | |
| 184 // Creates the backend. | |
| 185 int Run(); | |
| 186 | |
| 187 private: | |
| 188 void DoCallback(int result); | |
| 189 | |
| 190 // Callback implementation. | |
| 191 void OnIOComplete(int result); | |
| 192 | |
| 193 const base::FilePath& path_; | |
| 194 bool force_; | |
| 195 bool retry_; | |
| 196 int max_bytes_; | |
| 197 net::CacheType type_; | |
| 198 uint32 flags_; | |
| 199 scoped_refptr<base::MessageLoopProxy> thread_; | |
| 200 disk_cache::Backend** backend_; | |
| 201 net::CompletionCallback callback_; | |
| 202 disk_cache::BackendImpl* cache_; | |
| 203 net::NetLog* net_log_; | |
| 204 | |
| 205 DISALLOW_COPY_AND_ASSIGN(CacheCreator); | |
| 206 }; | |
| 207 | |
| 208 int CacheCreator::Run() { | |
| 209 cache_ = new disk_cache::BackendImpl(path_, thread_, net_log_); | |
| 210 cache_->SetMaxSize(max_bytes_); | |
| 211 cache_->SetType(type_); | |
| 212 cache_->SetFlags(flags_); | |
| 213 int rv = cache_->Init( | |
| 214 base::Bind(&CacheCreator::OnIOComplete, base::Unretained(this))); | |
| 215 DCHECK_EQ(net::ERR_IO_PENDING, rv); | |
| 216 return rv; | |
| 217 } | |
| 218 | |
| 219 void CacheCreator::DoCallback(int result) { | |
| 220 DCHECK_NE(net::ERR_IO_PENDING, result); | |
| 221 if (result == net::OK) { | |
| 222 *backend_ = cache_; | |
| 223 } else { | |
| 224 LOG(ERROR) << "Unable to create cache"; | |
| 225 *backend_ = NULL; | |
| 226 delete cache_; | |
| 227 } | |
| 228 callback_.Run(result); | |
| 229 delete this; | |
| 230 } | |
| 231 | |
| 232 void CacheCreator::OnIOComplete(int result) { | |
| 233 if (result == net::OK || !force_ || retry_) | |
| 234 return DoCallback(result); | |
| 235 | |
| 236 // This is a failure and we are supposed to try again, so delete the object, | |
| 237 // delete all the files, and try again. | |
| 238 retry_ = true; | |
| 239 delete cache_; | |
| 240 cache_ = NULL; | |
| 241 if (!DelayedCacheCleanup(path_)) | |
| 242 return DoCallback(result); | |
| 243 | |
| 244 // The worker thread will start deleting files soon, but the original folder | |
| 245 // is not there anymore... let's create a new set of files. | |
| 246 int rv = Run(); | |
| 247 DCHECK_EQ(net::ERR_IO_PENDING, rv); | |
| 248 } | |
| 249 | |
| 250 // A callback to perform final cleanup on the background thread. | 90 // A callback to perform final cleanup on the background thread. |
| 251 void FinalCleanupCallback(disk_cache::BackendImpl* backend) { | 91 void FinalCleanupCallback(disk_cache::BackendImpl* backend) { |
| 252 backend->CleanupCache(); | 92 backend->CleanupCache(); |
| 253 } | 93 } |
| 254 | 94 |
| 255 } // namespace | 95 } // namespace |
| 256 | 96 |
| 257 // ------------------------------------------------------------------------ | 97 // ------------------------------------------------------------------------ |
| 258 | 98 |
| 259 namespace disk_cache { | 99 namespace disk_cache { |
| 260 | 100 |
| 261 int CreateCacheBackend(net::CacheType type, const base::FilePath& path, | |
| 262 int max_bytes, | |
| 263 bool force, base::MessageLoopProxy* thread, | |
| 264 net::NetLog* net_log, Backend** backend, | |
| 265 const net::CompletionCallback& callback) { | |
| 266 // TODO(pasko): Separate out cache creation when landing cache tracer. | |
| 267 DCHECK(!callback.is_null()); | |
| 268 if (type == net::MEMORY_CACHE) { | |
| 269 *backend = MemBackendImpl::CreateBackend(max_bytes, net_log); | |
| 270 return *backend ? net::OK : net::ERR_FAILED; | |
| 271 } | |
| 272 DCHECK(thread); | |
| 273 | |
| 274 #if defined(USE_SIMPLE_CACHE_BACKEND) | |
| 275 // TODO(gavinp,pasko): While simple backend development proceeds, we're only | |
| 276 // testing it against net::DISK_CACHE. Turn it on for more cache types as | |
| 277 // appropriate. | |
| 278 if (type == net::DISK_CACHE) { | |
| 279 return SimpleBackendImpl::CreateBackend(path, force, max_bytes, type, kNone, | |
| 280 thread, net_log, backend, callback); | |
| 281 } | |
| 282 #endif | |
| 283 return BackendImpl::CreateBackend(path, force, max_bytes, type, kNone, | |
| 284 thread, net_log, backend, callback); | |
| 285 } | |
| 286 | |
| 287 // Returns the preferred maximum number of bytes for the cache given the | 101 // Returns the preferred maximum number of bytes for the cache given the |
| 288 // number of available bytes. | 102 // number of available bytes. |
| 289 int PreferedCacheSize(int64 available) { | 103 int PreferedCacheSize(int64 available) { |
| 290 // Return 80% of the available space if there is not enough space to use | 104 // Return 80% of the available space if there is not enough space to use |
| 291 // kDefaultCacheSize. | 105 // kDefaultCacheSize. |
| 292 if (available < kDefaultCacheSize * 10 / 8) | 106 if (available < kDefaultCacheSize * 10 / 8) |
| 293 return static_cast<int32>(available * 8 / 10); | 107 return static_cast<int32>(available * 8 / 10); |
| 294 | 108 |
| 295 // Return kDefaultCacheSize if it uses 80% to 10% of the available space. | 109 // Return kDefaultCacheSize if it uses 80% to 10% of the available space. |
| 296 if (available < kDefaultCacheSize * 10) | 110 if (available < kDefaultCacheSize * 10) |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 382 CleanupCache(); | 196 CleanupCache(); |
| 383 } else { | 197 } else { |
| 384 background_queue_.background_thread()->PostTask( | 198 background_queue_.background_thread()->PostTask( |
| 385 FROM_HERE, base::Bind(&FinalCleanupCallback, base::Unretained(this))); | 199 FROM_HERE, base::Bind(&FinalCleanupCallback, base::Unretained(this))); |
| 386 // http://crbug.com/74623 | 200 // http://crbug.com/74623 |
| 387 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 201 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| 388 done_.Wait(); | 202 done_.Wait(); |
| 389 } | 203 } |
| 390 } | 204 } |
| 391 | 205 |
| 392 // If the initialization of the cache fails, and force is true, we will discard | |
| 393 // the whole cache and create a new one. In order to process a potentially large | |
| 394 // number of files, we'll rename the cache folder to old_ + original_name + | |
| 395 // number, (located on the same parent folder), and spawn a worker thread to | |
| 396 // delete all the files on all the stale cache folders. The whole process can | |
| 397 // still fail if we are not able to rename the cache folder (for instance due to | |
| 398 // a sharing violation), and in that case a cache for this profile (on the | |
| 399 // desired path) cannot be created. | |
| 400 // | |
| 401 // Static. | |
| 402 int BackendImpl::CreateBackend(const base::FilePath& full_path, bool force, | |
| 403 int max_bytes, net::CacheType type, | |
| 404 uint32 flags, base::MessageLoopProxy* thread, | |
| 405 net::NetLog* net_log, Backend** backend, | |
| 406 const CompletionCallback& callback) { | |
| 407 DCHECK(!callback.is_null()); | |
| 408 CacheCreator* creator = | |
| 409 new CacheCreator(full_path, force, max_bytes, type, flags, thread, | |
| 410 net_log, backend, callback); | |
| 411 // This object will self-destroy when finished. | |
| 412 return creator->Run(); | |
| 413 } | |
| 414 | |
| 415 int BackendImpl::Init(const CompletionCallback& callback) { | 206 int BackendImpl::Init(const CompletionCallback& callback) { |
| 416 background_queue_.Init(callback); | 207 background_queue_.Init(callback); |
| 417 return net::ERR_IO_PENDING; | 208 return net::ERR_IO_PENDING; |
| 418 } | 209 } |
| 419 | 210 |
| 420 int BackendImpl::SyncInit() { | 211 int BackendImpl::SyncInit() { |
| 421 #if defined(NET_BUILD_STRESS_CACHE) | 212 #if defined(NET_BUILD_STRESS_CACHE) |
| 422 // Start evictions right away. | 213 // Start evictions right away. |
| 423 up_ticks_ = kTrimDelay * 2; | 214 up_ticks_ = kTrimDelay * 2; |
| 424 #endif | 215 #endif |
| (...skipping 1827 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2252 if (total_memory > kMaxBuffersSize || total_memory <= 0) | 2043 if (total_memory > kMaxBuffersSize || total_memory <= 0) |
| 2253 total_memory = kMaxBuffersSize; | 2044 total_memory = kMaxBuffersSize; |
| 2254 | 2045 |
| 2255 done = true; | 2046 done = true; |
| 2256 } | 2047 } |
| 2257 | 2048 |
| 2258 return static_cast<int>(total_memory); | 2049 return static_cast<int>(total_memory); |
| 2259 } | 2050 } |
| 2260 | 2051 |
| 2261 } // namespace disk_cache | 2052 } // namespace disk_cache |
| OLD | NEW |