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

Side by Side Diff: webkit/fileapi/file_system_origin_database.cc

Issue 9663021: Add database recovery for FileSystemOriginDatabase (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 8 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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "webkit/fileapi/file_system_origin_database.h" 5 #include "webkit/fileapi/file_system_origin_database.h"
6 6
7 #include "base/file_util.h"
7 #include "base/format_macros.h" 8 #include "base/format_macros.h"
8 #include "base/location.h" 9 #include "base/location.h"
9 #include "base/logging.h" 10 #include "base/logging.h"
10 #include "base/metrics/histogram.h" 11 #include "base/metrics/histogram.h"
11 #include "base/string_number_conversions.h" 12 #include "base/string_number_conversions.h"
12 #include "base/stringprintf.h" 13 #include "base/stringprintf.h"
13 #include "base/string_util.h" 14 #include "base/string_util.h"
14 #include "base/sys_string_conversions.h"
15 #include "third_party/leveldatabase/src/include/leveldb/db.h" 15 #include "third_party/leveldatabase/src/include/leveldb/db.h"
16 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 16 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
17 #include "webkit/fileapi/file_system_util.h"
17 18
18 namespace { 19 namespace {
19 20
21 const FilePath::CharType kOriginDatabaseName[] = FILE_PATH_LITERAL("Origins");
20 const char kOriginKeyPrefix[] = "ORIGIN:"; 22 const char kOriginKeyPrefix[] = "ORIGIN:";
21 const char kLastPathKey[] = "LAST_PATH"; 23 const char kLastPathKey[] = "LAST_PATH";
22 const int64 kMinimumReportIntervalHours = 1; 24 const int64 kMinimumReportIntervalHours = 1;
23 const char kInitStatusHistogramLabel[] = "FileSystem.OriginDatabaseInit"; 25 const char kInitStatusHistogramLabel[] = "FileSystem.OriginDatabaseInit";
24 26
25 enum InitStatus { 27 enum InitStatus {
26 INIT_STATUS_OK = 0, 28 INIT_STATUS_OK = 0,
27 INIT_STATUS_CORRUPTION, 29 INIT_STATUS_CORRUPTION,
28 INIT_STATUS_MAX 30 INIT_STATUS_MAX
29 }; 31 };
(...skipping 15 matching lines...) Expand all
45 } 47 }
46 48
47 FileSystemOriginDatabase::OriginRecord::OriginRecord( 49 FileSystemOriginDatabase::OriginRecord::OriginRecord(
48 const std::string& origin_in, const FilePath& path_in) 50 const std::string& origin_in, const FilePath& path_in)
49 : origin(origin_in), path(path_in) { 51 : origin(origin_in), path(path_in) {
50 } 52 }
51 53
52 FileSystemOriginDatabase::OriginRecord::~OriginRecord() { 54 FileSystemOriginDatabase::OriginRecord::~OriginRecord() {
53 } 55 }
54 56
55 FileSystemOriginDatabase::FileSystemOriginDatabase(const FilePath& path) { 57 FileSystemOriginDatabase::FileSystemOriginDatabase(
56 #if defined(OS_POSIX) 58 const FilePath& file_system_directory)
57 path_ = path.value(); 59 : file_system_directory_(file_system_directory) {
58 #elif defined(OS_WIN)
59 path_ = base::SysWideToUTF8(path.value());
60 #endif
61 } 60 }
62 61
63 FileSystemOriginDatabase::~FileSystemOriginDatabase() { 62 FileSystemOriginDatabase::~FileSystemOriginDatabase() {
64 } 63 }
65 64
66 bool FileSystemOriginDatabase::Init() { 65 bool FileSystemOriginDatabase::Init(RecoveryOption recovery_option) {
67 if (db_.get()) 66 if (db_.get())
68 return true; 67 return true;
69 68
69 std::string path =
70 FilePathToString(file_system_directory_.Append(kOriginDatabaseName));
70 leveldb::Options options; 71 leveldb::Options options;
71 options.create_if_missing = true; 72 options.create_if_missing = true;
72 leveldb::DB* db; 73 leveldb::DB* db;
73 leveldb::Status status = leveldb::DB::Open(options, path_, &db); 74 leveldb::Status status = leveldb::DB::Open(options, path, &db);
74 ReportInitStatus(status); 75 ReportInitStatus(status);
75 if (status.ok()) { 76 if (status.ok()) {
76 db_.reset(db); 77 db_.reset(db);
77 return true; 78 return true;
78 } 79 }
79 HandleError(FROM_HERE, status); 80 HandleError(FROM_HERE, status);
81
82 switch (recovery_option) {
83 case FAIL_ON_CORRUPTION:
84 return false;
85 case REPAIR_ON_CORRUPTION:
86 LOG(WARNING) << "Attempting to repair FileSystemOriginDatabase.";
87 if (RepairDatabase(path)) {
88 LOG(WARNING) << "Repairing FileSystemOriginDatabase completed.";
89 return true;
90 }
91 // fall through
92 case DELETE_ON_CORRUPTION:
93 if (!file_util::Delete(file_system_directory_, true))
94 return false;
95 if (!file_util::CreateDirectory(file_system_directory_))
96 return false;
97 return Init(FAIL_ON_CORRUPTION);
98 }
99 NOTREACHED();
80 return false; 100 return false;
81 } 101 }
82 102
103 bool FileSystemOriginDatabase::RepairDatabase(const std::string& db_path) {
104 DCHECK(!db_.get());
105 if (!leveldb::RepairDB(db_path, leveldb::Options()).ok() ||
106 !Init(FAIL_ON_CORRUPTION)) {
107 LOG(WARNING) << "Failed to repair FileSystemOriginDatabase.";
108 return false;
109 }
110
111 // See if the repaired entries match with what we have on disk.
112 std::set<FilePath> directories;
113 file_util::FileEnumerator file_enum(file_system_directory_,
114 false /* recursive */,
115 file_util::FileEnumerator::DIRECTORIES);
116 FilePath path_each;
117 while (!(path_each = file_enum.Next()).empty())
118 directories.insert(path_each.BaseName());
119 std::set<FilePath>::iterator db_dir_itr =
120 directories.find(FilePath(kOriginDatabaseName));
121 // Make sure we have the database file in its directory and therefore we are
122 // working on the correct path.
123 DCHECK(db_dir_itr != directories.end());
124 directories.erase(db_dir_itr);
125
126 std::vector<OriginRecord> origins;
127 if (!ListAllOrigins(&origins)) {
128 DropDatabase();
129 return false;
130 }
131
132 // Delete any obsolete entries from the origins database.
133 for (std::vector<OriginRecord>::iterator db_origin_itr = origins.begin();
134 db_origin_itr != origins.end();
135 ++db_origin_itr) {
136 std::set<FilePath>::iterator dir_itr =
137 directories.find(db_origin_itr->path);
138 if (dir_itr == directories.end()) {
139 if (!RemovePathForOrigin(db_origin_itr->origin)) {
140 DropDatabase();
141 return false;
142 }
143 } else {
144 directories.erase(dir_itr);
145 }
146 }
147
148 // Delete any directories not listed in the origins database.
149 for (std::set<FilePath>::iterator dir_itr = directories.begin();
150 dir_itr != directories.end();
151 ++dir_itr) {
152 if (!file_util::Delete(file_system_directory_.Append(*dir_itr),
153 true /* recursive */)) {
154 DropDatabase();
155 return false;
156 }
157 }
158
159 return true;
160 }
161
83 void FileSystemOriginDatabase::HandleError( 162 void FileSystemOriginDatabase::HandleError(
84 const tracked_objects::Location& from_here, 163 const tracked_objects::Location& from_here,
85 const leveldb::Status& status) { 164 const leveldb::Status& status) {
86 db_.reset(); 165 db_.reset();
87 LOG(ERROR) << "FileSystemOriginDatabase failed at: " 166 LOG(ERROR) << "FileSystemOriginDatabase failed at: "
88 << from_here.ToString() << " with error: " << status.ToString(); 167 << from_here.ToString() << " with error: " << status.ToString();
89 } 168 }
90 169
91 void FileSystemOriginDatabase::ReportInitStatus(const leveldb::Status& status) { 170 void FileSystemOriginDatabase::ReportInitStatus(const leveldb::Status& status) {
92 base::Time now = base::Time::Now(); 171 base::Time now = base::Time::Now();
93 base::TimeDelta minimum_interval = 172 base::TimeDelta minimum_interval =
94 base::TimeDelta::FromHours(kMinimumReportIntervalHours); 173 base::TimeDelta::FromHours(kMinimumReportIntervalHours);
95 if (last_reported_time_ + minimum_interval >= now) 174 if (last_reported_time_ + minimum_interval >= now)
96 return; 175 return;
97 last_reported_time_ = now; 176 last_reported_time_ = now;
98 177
99 if (status.ok()) { 178 if (status.ok()) {
100 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel, 179 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
101 INIT_STATUS_OK, INIT_STATUS_MAX); 180 INIT_STATUS_OK, INIT_STATUS_MAX);
102 } else { 181 } else {
103 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel, 182 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
104 INIT_STATUS_CORRUPTION, INIT_STATUS_MAX); 183 INIT_STATUS_CORRUPTION, INIT_STATUS_MAX);
105 } 184 }
106 } 185 }
107 186
108 bool FileSystemOriginDatabase::HasOriginPath(const std::string& origin) { 187 bool FileSystemOriginDatabase::HasOriginPath(const std::string& origin) {
109 if (!Init()) 188 if (!Init(REPAIR_ON_CORRUPTION))
110 return false; 189 return false;
111 if (origin.empty()) 190 if (origin.empty())
112 return false; 191 return false;
113 std::string path; 192 std::string path;
114 leveldb::Status status = 193 leveldb::Status status =
115 db_->Get(leveldb::ReadOptions(), OriginToOriginKey(origin), &path); 194 db_->Get(leveldb::ReadOptions(), OriginToOriginKey(origin), &path);
116 if (status.ok()) 195 if (status.ok())
117 return true; 196 return true;
118 if (status.IsNotFound()) 197 if (status.IsNotFound())
119 return false; 198 return false;
120 HandleError(FROM_HERE, status); 199 HandleError(FROM_HERE, status);
121 return false; 200 return false;
122 } 201 }
123 202
124 bool FileSystemOriginDatabase::GetPathForOrigin( 203 bool FileSystemOriginDatabase::GetPathForOrigin(
125 const std::string& origin, FilePath* directory) { 204 const std::string& origin, FilePath* directory) {
126 if (!Init()) 205 if (!Init(REPAIR_ON_CORRUPTION))
127 return false; 206 return false;
128 DCHECK(directory); 207 DCHECK(directory);
129 if (origin.empty()) 208 if (origin.empty())
130 return false; 209 return false;
131 std::string path_string; 210 std::string path_string;
132 std::string origin_key = OriginToOriginKey(origin); 211 std::string origin_key = OriginToOriginKey(origin);
133 leveldb::Status status = 212 leveldb::Status status =
134 db_->Get(leveldb::ReadOptions(), origin_key, &path_string); 213 db_->Get(leveldb::ReadOptions(), origin_key, &path_string);
135 if (status.IsNotFound()) { 214 if (status.IsNotFound()) {
136 int last_path_number; 215 int last_path_number;
137 if (!GetLastPathNumber(&last_path_number)) 216 if (!GetLastPathNumber(&last_path_number))
138 return false; 217 return false;
139 path_string = StringPrintf("%03u", last_path_number + 1); 218 path_string = StringPrintf("%03u", last_path_number + 1);
140 // store both back as a single transaction 219 // store both back as a single transaction
141 leveldb::WriteBatch batch; 220 leveldb::WriteBatch batch;
142 batch.Put(LastPathKey(), path_string); 221 batch.Put(LastPathKey(), path_string);
143 batch.Put(origin_key, path_string); 222 batch.Put(origin_key, path_string);
144 status = db_->Write(leveldb::WriteOptions(), &batch); 223 status = db_->Write(leveldb::WriteOptions(), &batch);
145 if (!status.ok()) { 224 if (!status.ok()) {
146 HandleError(FROM_HERE, status); 225 HandleError(FROM_HERE, status);
147 return false; 226 return false;
148 } 227 }
149 } 228 }
150 if (status.ok()) { 229 if (status.ok()) {
151 #if defined(OS_POSIX) 230 *directory = StringToFilePath(path_string);
152 *directory = FilePath(path_string);
153 #elif defined(OS_WIN)
154 *directory = FilePath(base::SysUTF8ToWide(path_string));
155 #endif
156 return true; 231 return true;
157 } 232 }
158 HandleError(FROM_HERE, status); 233 HandleError(FROM_HERE, status);
159 return false; 234 return false;
160 } 235 }
161 236
162 bool FileSystemOriginDatabase::RemovePathForOrigin(const std::string& origin) { 237 bool FileSystemOriginDatabase::RemovePathForOrigin(const std::string& origin) {
163 if (!Init()) 238 if (!Init(REPAIR_ON_CORRUPTION))
164 return false; 239 return false;
165 leveldb::Status status = 240 leveldb::Status status =
166 db_->Delete(leveldb::WriteOptions(), OriginToOriginKey(origin)); 241 db_->Delete(leveldb::WriteOptions(), OriginToOriginKey(origin));
167 if (status.ok() || status.IsNotFound()) 242 if (status.ok() || status.IsNotFound())
168 return true; 243 return true;
169 HandleError(FROM_HERE, status); 244 HandleError(FROM_HERE, status);
170 return false; 245 return false;
171 } 246 }
172 247
173 bool FileSystemOriginDatabase::ListAllOrigins( 248 bool FileSystemOriginDatabase::ListAllOrigins(
174 std::vector<OriginRecord>* origins) { 249 std::vector<OriginRecord>* origins) {
175 if (!Init()) 250 if (!Init(REPAIR_ON_CORRUPTION))
176 return false; 251 return false;
177 DCHECK(origins); 252 DCHECK(origins);
178 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions())); 253 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions()));
179 std::string origin_key_prefix = OriginToOriginKey(""); 254 std::string origin_key_prefix = OriginToOriginKey("");
180 iter->Seek(origin_key_prefix); 255 iter->Seek(origin_key_prefix);
181 origins->clear(); 256 origins->clear();
182 while(iter->Valid() && 257 while(iter->Valid() &&
183 StartsWithASCII(iter->key().ToString(), origin_key_prefix, true)) { 258 StartsWithASCII(iter->key().ToString(), origin_key_prefix, true)) {
184 std::string origin = 259 std::string origin =
185 iter->key().ToString().substr(origin_key_prefix.length()); 260 iter->key().ToString().substr(origin_key_prefix.length());
186 #if defined(OS_POSIX) 261 FilePath path = StringToFilePath(iter->value().ToString());
187 FilePath path = FilePath(iter->value().ToString());
188 #elif defined(OS_WIN)
189 FilePath path = FilePath(base::SysUTF8ToWide(iter->value().ToString()));
190 #endif
191 origins->push_back(OriginRecord(origin, path)); 262 origins->push_back(OriginRecord(origin, path));
192 iter->Next(); 263 iter->Next();
193 } 264 }
194 return true; 265 return true;
195 } 266 }
196 267
197 void FileSystemOriginDatabase::DropDatabase() { 268 void FileSystemOriginDatabase::DropDatabase() {
198 db_.reset(); 269 db_.reset();
199 } 270 }
200 271
201 bool FileSystemOriginDatabase::GetLastPathNumber(int* number) { 272 bool FileSystemOriginDatabase::GetLastPathNumber(int* number) {
202 if (!Init()) 273 if (!Init(REPAIR_ON_CORRUPTION))
203 return false; 274 return false;
204 DCHECK(number); 275 DCHECK(number);
205 std::string number_string; 276 std::string number_string;
206 leveldb::Status status = 277 leveldb::Status status =
207 db_->Get(leveldb::ReadOptions(), LastPathKey(), &number_string); 278 db_->Get(leveldb::ReadOptions(), LastPathKey(), &number_string);
208 if (status.ok()) 279 if (status.ok())
209 return base::StringToInt(number_string, number); 280 return base::StringToInt(number_string, number);
210 if (!status.IsNotFound()) { 281 if (!status.IsNotFound()) {
211 HandleError(FROM_HERE, status); 282 HandleError(FROM_HERE, status);
212 return false; 283 return false;
(...skipping 11 matching lines...) Expand all
224 db_->Put(leveldb::WriteOptions(), LastPathKey(), std::string("-1")); 295 db_->Put(leveldb::WriteOptions(), LastPathKey(), std::string("-1"));
225 if (!status.ok()) { 296 if (!status.ok()) {
226 HandleError(FROM_HERE, status); 297 HandleError(FROM_HERE, status);
227 return false; 298 return false;
228 } 299 }
229 *number = -1; 300 *number = -1;
230 return true; 301 return true;
231 } 302 }
232 303
233 } // namespace fileapi 304 } // namespace fileapi
OLDNEW
« no previous file with comments | « webkit/fileapi/file_system_origin_database.h ('k') | webkit/fileapi/file_system_origin_database_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698