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

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