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

Side by Side Diff: net/disk_cache/simple/simple_index.cc

Issue 14230009: Write the Simple Cache Index file to disk once in a while (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase again 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 | Annotate | Revision Log
« no previous file with comments | « net/disk_cache/simple/simple_index.h ('k') | no next file » | 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) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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/simple/simple_index.h" 5 #include "net/disk_cache/simple/simple_index.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/bind_helpers.h" 10 #include "base/bind_helpers.h"
11 #include "base/file_util.h" 11 #include "base/file_util.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/message_loop.h" 13 #include "base/message_loop.h"
14 #include "base/pickle.h" 14 #include "base/pickle.h"
15 #include "base/task_runner.h" 15 #include "base/task_runner.h"
16 #include "base/threading/worker_pool.h" 16 #include "base/threading/worker_pool.h"
17 #include "net/base/net_errors.h" 17 #include "net/base/net_errors.h"
18 #include "net/disk_cache/simple/simple_entry_format.h" 18 #include "net/disk_cache/simple/simple_entry_format.h"
19 #include "net/disk_cache/simple/simple_index_file.h" 19 #include "net/disk_cache/simple/simple_index_file.h"
20 #include "net/disk_cache/simple/simple_util.h" 20 #include "net/disk_cache/simple/simple_util.h"
21 21
22 namespace {
23
24 // How many seconds we delay writing the index to disk since the last cache
25 // operation has happened.
26 const int kWriteToDiskDelaySecs = 20;
27
28 // WriteToDisk at lest every 5 minutes.
29 const int kMaxWriteToDiskDelaySecs = 300;
30
31 } // namespace
32
22 namespace disk_cache { 33 namespace disk_cache {
23 34
24 EntryMetadata::EntryMetadata() : hash_key_(0), 35 EntryMetadata::EntryMetadata() : hash_key_(0),
25 last_used_time_(0), 36 last_used_time_(0),
26 entry_size_(0) { 37 entry_size_(0) {
27 } 38 }
28 39
29
30 EntryMetadata::EntryMetadata(uint64 hash_key, 40 EntryMetadata::EntryMetadata(uint64 hash_key,
31 base::Time last_used_time, 41 base::Time last_used_time,
32 uint64 entry_size) : 42 uint64 entry_size) :
33 hash_key_(hash_key), 43 hash_key_(hash_key),
34 last_used_time_(last_used_time.ToInternalValue()), 44 last_used_time_(last_used_time.ToInternalValue()),
35 entry_size_(entry_size) { 45 entry_size_(entry_size) {
36 } 46 }
37 47
38 base::Time EntryMetadata::GetLastUsedTime() const { 48 base::Time EntryMetadata::GetLastUsedTime() const {
39 return base::Time::FromInternalValue(last_used_time_); 49 return base::Time::FromInternalValue(last_used_time_);
(...skipping 29 matching lines...) Expand all
69 } 79 }
70 80
71 SimpleIndex::SimpleIndex( 81 SimpleIndex::SimpleIndex(
72 base::SingleThreadTaskRunner* cache_thread, 82 base::SingleThreadTaskRunner* cache_thread,
73 base::SingleThreadTaskRunner* io_thread, 83 base::SingleThreadTaskRunner* io_thread,
74 const base::FilePath& path) 84 const base::FilePath& path)
75 : cache_size_(0), 85 : cache_size_(0),
76 initialized_(false), 86 initialized_(false),
77 index_filename_(path.AppendASCII("simple-index")), 87 index_filename_(path.AppendASCII("simple-index")),
78 cache_thread_(cache_thread), 88 cache_thread_(cache_thread),
79 io_thread_(io_thread) {} 89 io_thread_(io_thread) {
90 }
80 91
81 SimpleIndex::~SimpleIndex() { 92 SimpleIndex::~SimpleIndex() {
82 DCHECK(io_thread_checker_.CalledOnValidThread()); 93 DCHECK(io_thread_checker_.CalledOnValidThread());
83 } 94 }
84 95
85 void SimpleIndex::Initialize() { 96 void SimpleIndex::Initialize() {
86 DCHECK(io_thread_checker_.CalledOnValidThread()); 97 DCHECK(io_thread_checker_.CalledOnValidThread());
87 IndexCompletionCallback merge_callback = 98 IndexCompletionCallback merge_callback =
88 base::Bind(&SimpleIndex::MergeInitializingSet, AsWeakPtr()); 99 base::Bind(&SimpleIndex::MergeInitializingSet, AsWeakPtr());
89 base::WorkerPool::PostTask(FROM_HERE, 100 base::WorkerPool::PostTask(FROM_HERE,
90 base::Bind(&SimpleIndex::LoadFromDisk, 101 base::Bind(&SimpleIndex::LoadFromDisk,
91 index_filename_, 102 index_filename_,
92 io_thread_, 103 io_thread_,
93 merge_callback), 104 merge_callback),
94 true); 105 true);
95 } 106 }
96 107
97 void SimpleIndex::Insert(const std::string& key) { 108 void SimpleIndex::Insert(const std::string& key) {
98 DCHECK(io_thread_checker_.CalledOnValidThread()); 109 DCHECK(io_thread_checker_.CalledOnValidThread());
99 // Upon insert we don't know yet the size of the entry. 110 // Upon insert we don't know yet the size of the entry.
100 // It will be updated later when the SimpleEntryImpl finishes opening or 111 // It will be updated later when the SimpleEntryImpl finishes opening or
101 // creating the new entry, and then UpdateEntrySize will be called. 112 // creating the new entry, and then UpdateEntrySize will be called.
102 const uint64 hash_key = simple_util::GetEntryHashKey(key); 113 const uint64 hash_key = simple_util::GetEntryHashKey(key);
103 InsertInEntrySet(EntryMetadata(hash_key, base::Time::Now(), 0), 114 InsertInEntrySet(EntryMetadata(hash_key, base::Time::Now(), 0),
104 &entries_set_); 115 &entries_set_);
105 if (!initialized_) 116 if (!initialized_)
106 removed_entries_.erase(hash_key); 117 removed_entries_.erase(hash_key);
118 PostponeWritingToDisk();
107 } 119 }
108 120
109 void SimpleIndex::Remove(const std::string& key) { 121 void SimpleIndex::Remove(const std::string& key) {
110 DCHECK(io_thread_checker_.CalledOnValidThread()); 122 DCHECK(io_thread_checker_.CalledOnValidThread());
111 UpdateEntrySize(key, 0); 123 UpdateEntrySize(key, 0);
112 const uint64 hash_key = simple_util::GetEntryHashKey(key); 124 const uint64 hash_key = simple_util::GetEntryHashKey(key);
113 entries_set_.erase(hash_key); 125 entries_set_.erase(hash_key);
114 126
115 if (!initialized_) 127 if (!initialized_)
116 removed_entries_.insert(hash_key); 128 removed_entries_.insert(hash_key);
129 PostponeWritingToDisk();
117 } 130 }
118 131
119 bool SimpleIndex::Has(const std::string& key) const { 132 bool SimpleIndex::Has(const std::string& key) const {
120 DCHECK(io_thread_checker_.CalledOnValidThread()); 133 DCHECK(io_thread_checker_.CalledOnValidThread());
121 // If not initialized, always return true, forcing it to go to the disk. 134 // If not initialized, always return true, forcing it to go to the disk.
122 return !initialized_ || 135 return !initialized_ ||
123 entries_set_.count(simple_util::GetEntryHashKey(key)) != 0; 136 entries_set_.count(simple_util::GetEntryHashKey(key)) != 0;
124 } 137 }
125 138
126 bool SimpleIndex::UseIfExists(const std::string& key) { 139 bool SimpleIndex::UseIfExists(const std::string& key) {
127 DCHECK(io_thread_checker_.CalledOnValidThread()); 140 DCHECK(io_thread_checker_.CalledOnValidThread());
128 // Always update the last used time, even if it is during initialization. 141 // Always update the last used time, even if it is during initialization.
129 // It will be merged later. 142 // It will be merged later.
130 EntrySet::iterator it = entries_set_.find(simple_util::GetEntryHashKey(key)); 143 EntrySet::iterator it = entries_set_.find(simple_util::GetEntryHashKey(key));
131 if (it == entries_set_.end()) 144 if (it == entries_set_.end())
132 // If not initialized, always return true, forcing it to go to the disk. 145 // If not initialized, always return true, forcing it to go to the disk.
133 return !initialized_; 146 return !initialized_;
134 it->second.SetLastUsedTime(base::Time::Now()); 147 it->second.SetLastUsedTime(base::Time::Now());
148 PostponeWritingToDisk();
135 return true; 149 return true;
136 } 150 }
137 151
138 bool SimpleIndex::UpdateEntrySize(const std::string& key, uint64 entry_size) { 152 bool SimpleIndex::UpdateEntrySize(const std::string& key, uint64 entry_size) {
139 DCHECK(io_thread_checker_.CalledOnValidThread()); 153 DCHECK(io_thread_checker_.CalledOnValidThread());
140 EntrySet::iterator it = entries_set_.find(simple_util::GetEntryHashKey(key)); 154 EntrySet::iterator it = entries_set_.find(simple_util::GetEntryHashKey(key));
141 if (it == entries_set_.end()) 155 if (it == entries_set_.end())
142 return false; 156 return false;
143 157
144 // Update the total cache size with the new entry size. 158 // Update the total cache size with the new entry size.
145 cache_size_ -= it->second.GetEntrySize(); 159 cache_size_ -= it->second.GetEntrySize();
146 cache_size_ += entry_size; 160 cache_size_ += entry_size;
147 it->second.SetEntrySize(entry_size); 161 it->second.SetEntrySize(entry_size);
148 162 PostponeWritingToDisk();
149 return true; 163 return true;
150 } 164 }
151 165
152 // static 166 // static
153 void SimpleIndex::InsertInEntrySet( 167 void SimpleIndex::InsertInEntrySet(
154 const disk_cache::EntryMetadata& entry_metadata, 168 const disk_cache::EntryMetadata& entry_metadata,
155 EntrySet* entry_set) { 169 EntrySet* entry_set) {
156 DCHECK(entry_set); 170 DCHECK(entry_set);
157 entry_set->insert( 171 entry_set->insert(
158 std::make_pair(entry_metadata.GetHashKey(), entry_metadata)); 172 std::make_pair(entry_metadata.GetHashKey(), entry_metadata));
159 } 173 }
160 174
175 void SimpleIndex::PostponeWritingToDisk() {
176 const base::TimeDelta file_age = base::Time::Now() - last_write_to_disk_;
177 if (file_age > base::TimeDelta::FromSeconds(kMaxWriteToDiskDelaySecs) &&
178 write_to_disk_timer_.IsRunning()) {
179 // If the index file is too old and there is a timer programmed to run a
180 // WriteToDisk soon, we don't postpone it, so we always WriteToDisk
181 // approximately every kMaxWriteToDiskDelaySecs.
182 return;
183 }
184
185 // If the timer is already active, Start() will just Reset it, postponing it.
186 write_to_disk_timer_.Start(
187 FROM_HERE,
188 base::TimeDelta::FromSeconds(kWriteToDiskDelaySecs),
189 base::Bind(&SimpleIndex::WriteToDisk, AsWeakPtr()));
190 }
191
161 // static 192 // static
162 void SimpleIndex::LoadFromDisk( 193 void SimpleIndex::LoadFromDisk(
163 const base::FilePath& index_filename, 194 const base::FilePath& index_filename,
164 base::SingleThreadTaskRunner* io_thread, 195 base::SingleThreadTaskRunner* io_thread,
165 const IndexCompletionCallback& completion_callback) { 196 const IndexCompletionCallback& completion_callback) {
166 scoped_ptr<EntrySet> index_file_entries = 197 scoped_ptr<EntrySet> index_file_entries =
167 SimpleIndexFile::LoadFromDisk(index_filename); 198 SimpleIndexFile::LoadFromDisk(index_filename);
168 199
169 if (!index_file_entries.get()) 200 bool force_index_flush = false;
170 index_file_entries = SimpleIndex::RestoreFromDisk(index_filename); 201 if (!index_file_entries.get()) {
202 index_file_entries = SimpleIndex::RestoreFromDisk(index_filename);
203 // When we restore from disk we write the merged index file to disk right
204 // away, this might save us from having to restore again next time.
205 force_index_flush = true;
206 }
171 207
172 io_thread->PostTask(FROM_HERE, 208 io_thread->PostTask(FROM_HERE,
173 base::Bind(completion_callback, 209 base::Bind(completion_callback,
174 base::Passed(&index_file_entries))); 210 base::Passed(&index_file_entries),
211 force_index_flush));
175 } 212 }
176 213
177 // static 214 // static
178 scoped_ptr<SimpleIndex::EntrySet> SimpleIndex::RestoreFromDisk( 215 scoped_ptr<SimpleIndex::EntrySet> SimpleIndex::RestoreFromDisk(
179 const base::FilePath& index_filename) { 216 const base::FilePath& index_filename) {
180 using file_util::FileEnumerator; 217 using file_util::FileEnumerator;
181 LOG(INFO) << "Simple Cache Index is being restored from disk."; 218 LOG(INFO) << "Simple Cache Index is being restored from disk.";
182 219
183 file_util::Delete(index_filename, /* recursive = */ false); 220 file_util::Delete(index_filename, /* recursive = */ false);
184 scoped_ptr<EntrySet> index_file_entries(new EntrySet()); 221 scoped_ptr<EntrySet> index_file_entries(new EntrySet());
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 return index_file_entries.Pass(); 271 return index_file_entries.Pass();
235 } 272 }
236 273
237 274
238 // static 275 // static
239 void SimpleIndex::WriteToDiskInternal(const base::FilePath& index_filename, 276 void SimpleIndex::WriteToDiskInternal(const base::FilePath& index_filename,
240 scoped_ptr<Pickle> pickle) { 277 scoped_ptr<Pickle> pickle) {
241 SimpleIndexFile::WriteToDisk(index_filename, *pickle); 278 SimpleIndexFile::WriteToDisk(index_filename, *pickle);
242 } 279 }
243 280
244 void SimpleIndex::MergeInitializingSet( 281 void SimpleIndex::MergeInitializingSet(scoped_ptr<EntrySet> index_file_entries,
245 scoped_ptr<EntrySet> index_file_entries) { 282 bool force_index_flush) {
246 DCHECK(io_thread_checker_.CalledOnValidThread()); 283 DCHECK(io_thread_checker_.CalledOnValidThread());
247 // First, remove the entries that are in the |removed_entries_| from both 284 // First, remove the entries that are in the |removed_entries_| from both
248 // sets. 285 // sets.
249 for (base::hash_set<uint64>::const_iterator it = 286 for (base::hash_set<uint64>::const_iterator it =
250 removed_entries_.begin(); it != removed_entries_.end(); ++it) { 287 removed_entries_.begin(); it != removed_entries_.end(); ++it) {
251 entries_set_.erase(*it); 288 entries_set_.erase(*it);
252 index_file_entries->erase(*it); 289 index_file_entries->erase(*it);
253 } 290 }
254 291
255 // Recalculate the cache size while merging the two sets. 292 // Recalculate the cache size while merging the two sets.
256 cache_size_ = 0; 293 cache_size_ = 0;
257 for (EntrySet::const_iterator it = index_file_entries->begin(); 294 for (EntrySet::const_iterator it = index_file_entries->begin();
258 it != index_file_entries->end(); ++it) { 295 it != index_file_entries->end(); ++it) {
259 // If there is already an entry in the current entries_set_, we need to 296 // If there is already an entry in the current entries_set_, we need to
260 // merge the new data there with the data loaded in the initialization. 297 // merge the new data there with the data loaded in the initialization.
261 EntrySet::iterator current_entry = entries_set_.find(it->first); 298 EntrySet::iterator current_entry = entries_set_.find(it->first);
262 if (current_entry != entries_set_.end()) { 299 if (current_entry != entries_set_.end()) {
263 // When Merging, existing valid data in the |current_entry| will prevail. 300 // When Merging, existing valid data in the |current_entry| will prevail.
264 current_entry->second.MergeWith(it->second); 301 current_entry->second.MergeWith(it->second);
265 cache_size_ += current_entry->second.GetEntrySize(); 302 cache_size_ += current_entry->second.GetEntrySize();
266 } else { 303 } else {
267 InsertInEntrySet(it->second, &entries_set_); 304 InsertInEntrySet(it->second, &entries_set_);
268 cache_size_ += it->second.GetEntrySize(); 305 cache_size_ += it->second.GetEntrySize();
269 } 306 }
270 } 307 }
308 last_write_to_disk_ = base::Time::Now();
309 initialized_ = true;
310 removed_entries_.clear();
271 311
272 initialized_ = true; 312 // The actual IO is asynchronous, so calling WriteToDisk() shouldn't slow down
313 // much the merge.
314 if (force_index_flush)
315 WriteToDisk();
273 } 316 }
274 317
275 void SimpleIndex::WriteToDisk() { 318 void SimpleIndex::WriteToDisk() {
276 DCHECK(io_thread_checker_.CalledOnValidThread()); 319 DCHECK(io_thread_checker_.CalledOnValidThread());
320 if (!initialized_)
321 return;
322 last_write_to_disk_ = base::Time::Now();
277 SimpleIndexFile::IndexMetadata index_metadata(entries_set_.size(), 323 SimpleIndexFile::IndexMetadata index_metadata(entries_set_.size(),
278 cache_size_); 324 cache_size_);
279 scoped_ptr<Pickle> pickle = SimpleIndexFile::Serialize(index_metadata, 325 scoped_ptr<Pickle> pickle = SimpleIndexFile::Serialize(index_metadata,
280 entries_set_); 326 entries_set_);
281 cache_thread_->PostTask(FROM_HERE, base::Bind( 327 cache_thread_->PostTask(FROM_HERE, base::Bind(
282 &SimpleIndex::WriteToDiskInternal, 328 &SimpleIndex::WriteToDiskInternal,
283 index_filename_, 329 index_filename_,
284 base::Passed(&pickle))); 330 base::Passed(&pickle)));
285 } 331 }
286 332
287 } // namespace disk_cache 333 } // namespace disk_cache
OLDNEW
« no previous file with comments | « net/disk_cache/simple/simple_index.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698