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

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

Issue 13839011: Asynchronous initialization in Simple Index. (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 "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/task_runner.h" 10 #include "base/task_runner.h"
(...skipping 25 matching lines...) Expand all
36 disk_cache::kSimpleIndexInitialMagicNumber && 36 disk_cache::kSimpleIndexInitialMagicNumber &&
37 header.version == disk_cache::kSimpleVersion; 37 header.version == disk_cache::kSimpleVersion;
38 } 38 }
39 39
40 } // namespace 40 } // namespace
41 41
42 namespace disk_cache { 42 namespace disk_cache {
43 43
44 SimpleIndex::SimpleIndex( 44 SimpleIndex::SimpleIndex(
45 const scoped_refptr<base::TaskRunner>& cache_thread, 45 const scoped_refptr<base::TaskRunner>& cache_thread,
46 const scoped_refptr<base::TaskRunner>& io_thread,
46 const base::FilePath& path) 47 const base::FilePath& path)
47 : path_(path), 48 : path_(path),
48 cache_thread_(cache_thread) { 49 cache_size_(0),
49 index_filename_ = path_.AppendASCII("simple-index"); 50 initialized_(false),
51 index_filename_(path_.AppendASCII("simple-index")),
52 cache_thread_(cache_thread),
53 io_thread_(io_thread) { }
54
55 void SimpleIndex::Initialize() {
56 base::WorkerPool::PostTask(FROM_HERE,
57 base::Bind(&SimpleIndex::LoadFromDisk,
58 base::Unretained(this)),
gavinp 2013/04/10 11:45:44 I don't think this use of base::Unretained is safe
felipeg 2013/04/10 14:21:45 Done.
59 true);
50 } 60 }
51 61
52 bool SimpleIndex::Initialize() { 62 void SimpleIndex::LoadFromDisk() {
53 if (!OpenIndexFile()) 63 if (!OpenIndexFile())
54 return RestoreFromDisk(); 64 return RestoreFromDisk();
55 uLong incremental_crc = crc32(0L, Z_NULL, 0); 65 uLong incremental_crc = crc32(0L, Z_NULL, 0);
56 int64 index_file_offset = 0; 66 int64 index_file_offset = 0;
57 SimpleIndexFile::Header header; 67 SimpleIndexFile::Header header;
58 if (base::ReadPlatformFile(index_file_, 68 if (base::ReadPlatformFile(index_file_,
59 index_file_offset, 69 index_file_offset,
60 reinterpret_cast<char*>(&header), 70 reinterpret_cast<char*>(&header),
61 sizeof(header)) != sizeof(header)) { 71 sizeof(header)) != sizeof(header)) {
62 return RestoreFromDisk(); 72 return RestoreFromDisk();
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
96 const uint32 crc_read = footer.crc; 106 const uint32 crc_read = footer.crc;
97 const uint32 crc_calculated = incremental_crc; 107 const uint32 crc_calculated = incremental_crc;
98 if (crc_read != crc_calculated) 108 if (crc_read != crc_calculated)
99 return RestoreFromDisk(); 109 return RestoreFromDisk();
100 110
101 int entries_buffer_offset = 0; 111 int entries_buffer_offset = 0;
102 while(entries_buffer_offset < entries_buffer_size) { 112 while(entries_buffer_offset < entries_buffer_size) {
103 SimpleIndexFile::EntryMetadata entry_metadata; 113 SimpleIndexFile::EntryMetadata entry_metadata;
104 SimpleIndexFile::EntryMetadata::DeSerialize( 114 SimpleIndexFile::EntryMetadata::DeSerialize(
105 &entries_buffer.get()[entries_buffer_offset], &entry_metadata); 115 &entries_buffer.get()[entries_buffer_offset], &entry_metadata);
106 InsertInternal(entry_metadata); 116 InsertInternal(&initializing_set_, entry_metadata);
107 entries_buffer_offset += SimpleIndexFile::kEntryMetadataSize; 117 entries_buffer_offset += SimpleIndexFile::kEntryMetadataSize;
108 } 118 }
109 DCHECK_EQ(header.number_of_entries, entries_set_.size()); 119 DCHECK_EQ(header.number_of_entries, initializing_set_.size());
110 CloseIndexFile(); 120 CloseIndexFile();
111 return true; 121
122 io_thread_->PostTask(FROM_HERE,
123 base::Bind(&SimpleIndex::MergeInitializingSet,
124 base::Unretained(this)));
112 } 125 }
113 126
114 void SimpleIndex::Insert(const std::string& key) { 127 void SimpleIndex::Insert(const std::string& key) {
115 // Upon insert we don't know yet the size of the entry. 128 // Upon insert we don't know yet the size of the entry.
116 // It will be updated later when the SynchronousEntryImpl finish and the 129 // It will be updated later when the SynchronousEntryImpl finish and the
117 // UpdateEntrySize will be called. 130 // UpdateEntrySize will be called.
118 InsertInternal(SimpleIndexFile::EntryMetadata(GetEntryHashForKey(key), 131 const std::string hash_key = GetEntryHashForKey(key);
132 InsertInternal(&entries_set_, SimpleIndexFile::EntryMetadata(hash_key,
119 base::Time::Now(), 0)); 133 base::Time::Now(), 0));
134 if (!initialized_)
135 removals_set_.erase(hash_key);
120 } 136 }
121 137
122 void SimpleIndex::Remove(const std::string& key) { 138 void SimpleIndex::Remove(const std::string& key) {
123 UpdateEntrySize(key, 0); 139 UpdateEntrySize(key, 0);
124 entries_set_.erase(GetEntryHashForKey(key)); 140 const std::string hash_key = GetEntryHashForKey(key);
141 entries_set_.erase(hash_key);
142
143 if (!initialized_)
144 removals_set_.insert(hash_key);
125 } 145 }
126 146
127 bool SimpleIndex::Has(const std::string& key) const { 147 bool SimpleIndex::Has(const std::string& key) const {
128 return entries_set_.count(GetEntryHashForKey(key)) != 0; 148 // If not initialized, always return true, forcing it to go to the disk.
149 return !initialized_ || entries_set_.count(GetEntryHashForKey(key)) != 0;
129 } 150 }
130 151
131 bool SimpleIndex::UseIfExists(const std::string& key) { 152 bool SimpleIndex::UseIfExists(const std::string& key) {
153 // Always update the last used time, even if it is during initialization.
154 // It will be merged later.
132 EntrySet::iterator it = entries_set_.find(GetEntryHashForKey(key)); 155 EntrySet::iterator it = entries_set_.find(GetEntryHashForKey(key));
133 if (it == entries_set_.end()) 156 if (it == entries_set_.end())
134 return false; 157 // If not initialized, always return true, forcing it to go to the disk.
158 return !initialized_;
135 it->second.SetLastUsedTime(base::Time::Now()); 159 it->second.SetLastUsedTime(base::Time::Now());
136 return true; 160 return true;
137 } 161 }
138 162
139 bool SimpleIndex::UpdateEntrySize(const std::string& key, uint64 entry_size) { 163 bool SimpleIndex::UpdateEntrySize(const std::string& key, uint64 entry_size) {
140 EntrySet::iterator it = entries_set_.find(GetEntryHashForKey(key)); 164 EntrySet::iterator it = entries_set_.find(GetEntryHashForKey(key));
141 if (it == entries_set_.end()) 165 if (it == entries_set_.end())
142 return false; 166 return false;
143 167
144 // Update the total cache size with the new entry size. 168 // Update the total cache size with the new entry size.
145 cache_size_ -= it->second.entry_size; 169 cache_size_ -= it->second.entry_size;
146 cache_size_ += entry_size; 170 cache_size_ += entry_size;
147 it->second.entry_size = entry_size; 171 it->second.entry_size = entry_size;
148 172
149 return true; 173 return true;
150 } 174 }
151 175
176 // static
152 void SimpleIndex::InsertInternal( 177 void SimpleIndex::InsertInternal(
178 EntrySet* entry_set,
153 const SimpleIndexFile::EntryMetadata& entry_metadata) { 179 const SimpleIndexFile::EntryMetadata& entry_metadata) {
154 entries_set_.insert(make_pair(entry_metadata.GetHashKey(), entry_metadata)); 180 DCHECK(entry_set);
181 entry_set->insert(make_pair(entry_metadata.GetHashKey(), entry_metadata));
155 } 182 }
156 183
157 bool SimpleIndex::RestoreFromDisk() { 184 void SimpleIndex::RestoreFromDisk() {
158 using file_util::FileEnumerator; 185 using file_util::FileEnumerator;
159 LOG(INFO) << "Simple Cache Index is being restored from disk."; 186 LOG(INFO) << "Simple Cache Index is being restored from disk.";
160 CloseIndexFile(); 187 CloseIndexFile();
161 file_util::Delete(index_filename_, /* recursive = */ false); 188 file_util::Delete(index_filename_, /* recursive = */ false);
162 entries_set_.clear(); 189 DCHECK_EQ(0U, initializing_set_.size());
190
163 // TODO(felipeg,gavinp): Fix this once we have a one-file per entry format. 191 // TODO(felipeg,gavinp): Fix this once we have a one-file per entry format.
164 const base::FilePath::StringType file_pattern = FILE_PATH_LITERAL("*_[0-2]"); 192 const base::FilePath::StringType file_pattern = FILE_PATH_LITERAL("*_[0-2]");
165 FileEnumerator enumerator(path_, 193 FileEnumerator enumerator(path_,
166 false /* recursive */, 194 false /* recursive */,
167 FileEnumerator::FILES, 195 FileEnumerator::FILES,
168 file_pattern); 196 file_pattern);
169 197
170 for (base::FilePath file_path = enumerator.Next(); !file_path.empty(); 198 for (base::FilePath file_path = enumerator.Next(); !file_path.empty();
171 file_path = enumerator.Next()) { 199 file_path = enumerator.Next()) {
172 const base::FilePath::StringType base_name = file_path.BaseName().value(); 200 const base::FilePath::StringType base_name = file_path.BaseName().value();
173 // Converting to std::string is OK since we never use UTF8 wide chars in our 201 // Converting to std::string is OK since we never use UTF8 wide chars in our
174 // file names. 202 // file names.
175 const std::string hash_name(base_name.begin(), base_name.end()); 203 const std::string hash_name(base_name.begin(), base_name.end());
176 const std::string hash_key = hash_name.substr(0, kEntryHashKeySize); 204 const std::string hash_key = hash_name.substr(0, kEntryHashKeySize);
177 205
178 FileEnumerator::FindInfo find_info = {}; 206 FileEnumerator::FindInfo find_info = {};
179 enumerator.GetFindInfo(&find_info); 207 enumerator.GetFindInfo(&find_info);
180 base::Time last_used_time; 208 base::Time last_used_time;
181 #if defined(OS_POSIX) 209 #if defined(OS_POSIX)
182 // For POSIX systems, a last access time is available. However, it's not 210 // For POSIX systems, a last access time is available. However, it's not
183 // guaranteed to be more accurate than mtime. It is no worse though. 211 // guaranteed to be more accurate than mtime. It is no worse though.
184 last_used_time = base::Time::FromTimeT(find_info.stat.st_atime); 212 last_used_time = base::Time::FromTimeT(find_info.stat.st_atime);
185 #endif 213 #endif
186 if (last_used_time.is_null()) 214 if (last_used_time.is_null())
187 last_used_time = FileEnumerator::GetLastModifiedTime(find_info); 215 last_used_time = FileEnumerator::GetLastModifiedTime(find_info);
188 216
189 int64 file_size = FileEnumerator::GetFilesize(find_info); 217 int64 file_size = FileEnumerator::GetFilesize(find_info);
190 EntrySet::iterator it = entries_set_.find(hash_key); 218 EntrySet::iterator it = initializing_set_.find(hash_key);
191 if (it == entries_set_.end()) { 219 if (it == initializing_set_.end()) {
192 InsertInternal(SimpleIndexFile::EntryMetadata( 220 InsertInternal(&initializing_set_, SimpleIndexFile::EntryMetadata(
193 hash_key, last_used_time, file_size)); 221 hash_key, last_used_time, file_size));
194 } else { 222 } else {
195 // Summing up the total size of the entry through all the *_[0-2] files 223 // Summing up the total size of the entry through all the *_[0-2] files
196 it->second.entry_size += file_size; 224 it->second.entry_size += file_size;
197 } 225 }
198 } 226 }
199 227
200 // TODO(felipeg): Detect unrecoverable problems and return false here. 228 io_thread_->PostTask(FROM_HERE,
201 return true; 229 base::Bind(&SimpleIndex::MergeInitializingSet,
230 base::Unretained(this)));
231 }
232
233 void SimpleIndex::MergeInitializingSet() {
234 // First, remove the entries that are in the |removals_set_| from both sets.
235 for (base::hash_set<std::string>::const_iterator it = removals_set_.begin();
236 it != removals_set_.end(); ++it) {
237 entries_set_.erase(*it);
238 initializing_set_.erase(*it);
239 }
240
241 // Recalculate the cache size while merging the two sets.
242 cache_size_ = 0;
243 for (EntrySet::const_iterator it = initializing_set_.begin();
244 it != initializing_set_.end(); ++it) {
245 // If there is already an entry in the current entries_set_, we need to
246 // merge the new data there with the data loaded in the initialization.
247 EntrySet::iterator current_entry = entries_set_.find(it->first);
248 if (current_entry != entries_set_.end()) {
249 // When Merging, existing valid data in the |current_entry| will prevail.
250 SimpleIndexFile::EntryMetadata::Merge(
251 it->second, &(current_entry->second));
252 cache_size_ += current_entry->second.entry_size;
253 } else {
254 InsertInternal(&entries_set_, it->second);
255 cache_size_ += it->second.entry_size;
256 }
257 }
258 initializing_set_.clear();
259
260 initialized_ = true;
202 } 261 }
203 262
204 void SimpleIndex::Serialize(std::string* out_buffer) { 263 void SimpleIndex::Serialize(std::string* out_buffer) {
205 DCHECK(out_buffer); 264 DCHECK(out_buffer);
206 SimpleIndexFile::Header header; 265 SimpleIndexFile::Header header;
207 SimpleIndexFile::Footer footer; 266 SimpleIndexFile::Footer footer;
208 267
209 header.initial_magic_number = kSimpleIndexInitialMagicNumber; 268 header.initial_magic_number = kSimpleIndexInitialMagicNumber;
210 header.version = kSimpleVersion; 269 header.version = kSimpleVersion;
211 header.number_of_entries = entries_set_.size(); 270 header.number_of_entries = entries_set_.size();
(...skipping 13 matching lines...) Expand all
225 } 284 }
226 285
227 // Then, CRC. 286 // Then, CRC.
228 footer.crc = crc32(crc32(0, Z_NULL, 0), 287 footer.crc = crc32(crc32(0, Z_NULL, 0),
229 reinterpret_cast<const Bytef*>(out_buffer->data()), 288 reinterpret_cast<const Bytef*>(out_buffer->data()),
230 implicit_cast<uInt>(out_buffer->size())); 289 implicit_cast<uInt>(out_buffer->size()));
231 290
232 out_buffer->append(reinterpret_cast<const char*>(&footer), sizeof(footer)); 291 out_buffer->append(reinterpret_cast<const char*>(&footer), sizeof(footer));
233 } 292 }
234 293
235 void SimpleIndex::Cleanup() { 294 void SimpleIndex::WriteToDisk() {
236 scoped_ptr<std::string> buffer(new std::string()); 295 scoped_ptr<std::string> buffer(new std::string());
237 Serialize(buffer.get()); 296 Serialize(buffer.get());
238 cache_thread_->PostTask(FROM_HERE, 297 cache_thread_->PostTask(FROM_HERE,
239 base::Bind(&SimpleIndex::UpdateFile, 298 base::Bind(&SimpleIndex::UpdateFile,
240 index_filename_, 299 index_filename_,
241 path_.AppendASCII("index_temp"), 300 path_.AppendASCII("index_temp"),
242 base::Passed(&buffer))); 301 base::Passed(&buffer)));
243 } 302 }
244 303
245 SimpleIndex::~SimpleIndex() { 304 SimpleIndex::~SimpleIndex() {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 << temp_filename.value(); 337 << temp_filename.value();
279 file_util::Delete(temp_filename, /* recursive = */ false); 338 file_util::Delete(temp_filename, /* recursive = */ false);
280 return; 339 return;
281 } 340 }
282 // Swap temp and index_file. 341 // Swap temp and index_file.
283 bool result = file_util::ReplaceFile(temp_filename, index_filename); 342 bool result = file_util::ReplaceFile(temp_filename, index_filename);
284 DCHECK(result); 343 DCHECK(result);
285 } 344 }
286 345
287 } // namespace disk_cache 346 } // 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