Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(184)

Side by Side Diff: net/disk_cache/backend_impl.cc

Issue 12794003: Initialize the simple cache backend at runtime. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: rebased to latest, auto-merged net.gyp Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/disk_cache/backend_impl.h ('k') | net/disk_cache/backend_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « net/disk_cache/backend_impl.h ('k') | net/disk_cache/backend_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698