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

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

Issue 14263005: Refactor our SimpleIndex file format and serialization to use Pickle instead of the previously bugg… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Philippe's comments 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "net/disk_cache/simple/simple_index_file.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/file_util.h"
10 #include "base/hash.h"
11 #include "base/logging.h"
12 #include "base/message_loop.h"
13 #include "base/pickle.h"
14 #include "base/task_runner.h"
15 #include "net/disk_cache/simple/simple_disk_format.h"
16 #include "net/disk_cache/simple/simple_index_util.h"
17 #include "third_party/zlib/zlib.h"
18
19 namespace {
20
21 const uint64 kMaxEntiresInIndex = 100000000;
22
23 uint32 CalculatePickleCRC(const Pickle& pickle) {
24 return crc32(crc32(0, Z_NULL, 0),
25 reinterpret_cast<const Bytef*>(pickle.payload()),
26 implicit_cast<uInt>(pickle.payload_size()));
gavinp 2013/04/15 15:40:54 You can lose this cast. Yes, I'm aware you cut and
felipeg 2013/04/15 15:56:09 Done.
27 }
28
29 } // namespace
30
31 namespace disk_cache {
32
33 SimpleIndexFile::IndexMetadata::IndexMetadata() :
34 initial_magic_number_(kSimpleIndexInitialMagicNumber),
35 version_(kSimpleVersion),
36 number_of_entries_(0),
37 cache_size_(0) {}
38
39 SimpleIndexFile::IndexMetadata::IndexMetadata(
40 uint64 number_of_entries, uint64 cache_size) :
41 initial_magic_number_(kSimpleIndexInitialMagicNumber),
42 version_(kSimpleVersion),
43 number_of_entries_(number_of_entries),
44 cache_size_(cache_size) {}
45
46 void SimpleIndexFile::IndexMetadata::Serialize(Pickle* pickle) const {
47 DCHECK(pickle);
48 pickle->WriteUInt64(initial_magic_number_);
49 pickle->WriteUInt32(version_);
50 pickle->WriteUInt64(number_of_entries_);
51 pickle->WriteUInt64(cache_size_);
52 }
53
54 bool SimpleIndexFile::IndexMetadata::DeSerialize(PickleIterator* it) {
55 DCHECK(it);
56 return it->ReadUInt64(&initial_magic_number_) &&
57 it->ReadUInt32(&version_) &&
58 it->ReadUInt64(&number_of_entries_)&&
59 it->ReadUInt64(&cache_size_);
60 }
61
62 bool SimpleIndexFile::IndexMetadata::CheckIndexMetadata() {
63 return number_of_entries_ <= kMaxEntiresInIndex &&
64 initial_magic_number_ == disk_cache::kSimpleIndexInitialMagicNumber &&
65 version_ == disk_cache::kSimpleVersion;
66 }
67
68 // static
69 void SimpleIndexFile::LoadFromDisk(
70 const base::FilePath& index_filename,
71 const scoped_refptr<base::TaskRunner>& callback_runner,
72 const IndexCompletionCallback& completion_callback) {
73 std::string contents;
74 if(!file_util::ReadFileToString(index_filename, &contents)) {
75 LOG(WARNING) << "Could not read Simple Index file.";
76 return RestoreFromDisk(
77 index_filename, callback_runner, completion_callback);
78 }
79
80 Pickle pickle(contents.data(), contents.size());
81 PickleIterator pickle_it(pickle);
82
83 SimpleIndexFile::PickleHeader* header_p =
84 pickle.headerT<SimpleIndexFile::PickleHeader>();
85 const uint32 crc_read = header_p->crc;
86 const uint32 crc_calculated = CalculatePickleCRC(pickle);
87
88 if (crc_read != crc_calculated) {
89 LOG(WARNING) << "Invalid CRC in Simple Index file.";
90 return RestoreFromDisk(
91 index_filename, callback_runner, completion_callback);
92 }
93
94 SimpleIndexFile::IndexMetadata index_metadata;
95 if (!index_metadata.DeSerialize(&pickle_it)) {
96 LOG(ERROR) << "Invalid index_metadata on Simple Cache Index.";
97 return RestoreFromDisk(
98 index_filename, callback_runner, completion_callback);
99 }
100
101 if (!index_metadata.CheckIndexMetadata()) {
102 LOG(ERROR) << "Invalid index_metadata on Simple Cache Index.";
103 return RestoreFromDisk(
104 index_filename, callback_runner, completion_callback);
105 }
106
107 scoped_ptr<EntrySet> index_file_entries(new EntrySet());
108 while (index_file_entries->size() < index_metadata.GetNumberOfEntries()) {
109 EntryMetadata entry_metadata;
110 if (!entry_metadata.DeSerialize(&pickle_it)) {
111 LOG(WARNING) << "Invalid EntryMetadata in Simple Index file.";
112 return RestoreFromDisk(
113 index_filename, callback_runner, completion_callback);
114 }
115 InsertInEntrySet(entry_metadata,
116 index_file_entries.get());
117 }
118 callback_runner->PostTask(FROM_HERE,
119 base::Bind(completion_callback,
120 base::Passed(&index_file_entries)));
121 }
122
123 // static
124 void SimpleIndexFile::RestoreFromDisk(
125 const base::FilePath& index_filename,
126 const scoped_refptr<base::TaskRunner>& callback_runner,
127 const IndexCompletionCallback& completion_callback) {
128 using file_util::FileEnumerator;
129 LOG(INFO) << "Simple Cache Index is being restored from disk.";
130
131 file_util::Delete(index_filename, /* recursive = */ false);
132 scoped_ptr<EntrySet> index_file_entries(new EntrySet());
133
134 // TODO(felipeg,gavinp): Fix this once we have a one-file per entry format.
135 COMPILE_ASSERT(kSimpleEntryFileCount == 3,
136 file_pattern_must_match_file_count);
137 const base::FilePath::StringType file_pattern = FILE_PATH_LITERAL("*_[0-2]");
138 FileEnumerator enumerator(index_filename.DirName(),
139 false /* recursive */,
140 FileEnumerator::FILES,
141 file_pattern);
142 for (base::FilePath file_path = enumerator.Next(); !file_path.empty();
143 file_path = enumerator.Next()) {
144 const base::FilePath::StringType base_name = file_path.BaseName().value();
145 // Converting to std::string is OK since we never use UTF8 wide chars in our
146 // file names.
147 const std::string hash_name(base_name.begin(), base_name.end());
148 const std::string hash_key_string =
149 hash_name.substr(0, kEntryHashKeyAsHexStringSize);
150 uint64 hash_key = 0;
151 if (!GetEntryHashKeyFromHexString(hash_key_string, &hash_key)) {
152 LOG(WARNING) << "Invalid Entry Hash Key filename while restoring "
153 << "Simple Index from disk: " << hash_name;
154 // TODO(felipeg): Should we delete the invalid file here ?
155 continue;
156 }
157
158 FileEnumerator::FindInfo find_info = {};
159 enumerator.GetFindInfo(&find_info);
160 base::Time last_used_time;
161 #if defined(OS_POSIX)
162 // For POSIX systems, a last access time is available. However, it's not
163 // guaranteed to be more accurate than mtime. It is no worse though.
164 last_used_time = base::Time::FromTimeT(find_info.stat.st_atime);
165 #endif
166 if (last_used_time.is_null())
167 last_used_time = FileEnumerator::GetLastModifiedTime(find_info);
168
169 int64 file_size = FileEnumerator::GetFilesize(find_info);
170 EntrySet::iterator it = index_file_entries->find(hash_key);
171 if (it == index_file_entries->end()) {
172 InsertInEntrySet(EntryMetadata(hash_key, last_used_time, file_size),
173 index_file_entries.get());
174 } else {
175 // Summing up the total size of the entry through all the *_[0-2] files
176 it->second.SetEntrySize(it->second.GetEntrySize() + file_size);
177 }
178 }
179
180 callback_runner->PostTask(FROM_HERE,
181 base::Bind(completion_callback,
182 base::Passed(&index_file_entries)));
183 }
184
185 // static
186 scoped_ptr<Pickle> SimpleIndexFile::Serialize(
187 const SimpleIndexFile::IndexMetadata& index_metadata,
188 const EntrySet& entries) {
189 scoped_ptr<Pickle> pickle(new Pickle(sizeof(SimpleIndexFile::PickleHeader)));
190
191 index_metadata.Serialize(pickle.get());
192 for (EntrySet::const_iterator it = entries.begin();
193 it != entries.end(); ++it) {
194 it->second.Serialize(pickle.get());
195 }
196 SimpleIndexFile::PickleHeader* header_p =
197 pickle->headerT<SimpleIndexFile::PickleHeader>();
198 header_p->crc = CalculatePickleCRC(*pickle);
199 return pickle.Pass();
200 }
201
202 // static
203 void SimpleIndexFile::WriteToDisk(const base::FilePath& index_filename,
204 scoped_ptr<Pickle> pickle) {
205 const base::FilePath temp_filename =
206 index_filename.DirName().AppendASCII("index_temp");
207 int bytes_written = file_util::WriteFile(
208 temp_filename,
209 reinterpret_cast<const char*>(pickle->data()),
210 pickle->size());
211 DCHECK_EQ(bytes_written, implicit_cast<int>(pickle->size()));
212 if (bytes_written != static_cast<int>(pickle->size())) {
213 // TODO(felipeg): Add better error handling.
214 LOG(ERROR) << "Could not write Simple Cache index to temporary file: "
215 << temp_filename.value();
216 file_util::Delete(temp_filename, /* recursive = */ false);
217 return;
218 }
219 // Swap temp and index_file.
220 bool result = file_util::ReplaceFile(temp_filename, index_filename);
221 DCHECK(result);
222 }
223
224 } // namespace disk_cache
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698