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

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