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

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: '' Created 8 years, 9 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) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/string_number_conversions.h" 11 #include "base/string_number_conversions.h"
11 #include "base/stringprintf.h" 12 #include "base/stringprintf.h"
12 #include "base/string_util.h" 13 #include "base/string_util.h"
13 #include "base/sys_string_conversions.h" 14 #include "base/utf_string_conversions.h"
14 #include "third_party/leveldatabase/src/include/leveldb/iterator.h" 15 #include "third_party/leveldatabase/src/include/leveldb/iterator.h"
15 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 16 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
16 17
17 namespace { 18 namespace {
18 19
20 const FilePath::CharType kOriginDatabaseName[] = FILE_PATH_LITERAL("Origins");
19 const char kOriginKeyPrefix[] = "ORIGIN:"; 21 const char kOriginKeyPrefix[] = "ORIGIN:";
20 const char kLastPathKey[] = "LAST_PATH"; 22 const char kLastPathKey[] = "LAST_PATH";
21 23
24 std::string FilePathToString(const FilePath& path) {
25 // TODO(tzik): Unify this to FilePathToString in
26 // third_party/leveldatabase/env_chromium.cc.
27 #if defined(OS_WIN)
28 return UTF16ToUTF8(path.value());
29 #elif defined(OS_POSIX)
30 return path.value();
31 #endif
32 }
33
34 FilePath StringToFilePath(const std::string& path_string) {
35 // TODO(tzik): Unify this to CreateFilePath in
36 // third_party/leveldatabase/env_chromium.cc.
37 #if defined(OS_WIN)
38 return FilePath(UTF8ToUTF16(path_string));
39 #elif defined(OS_POSIX)
40 return FilePath(path_string);
41 #endif
42 }
43
22 std::string OriginToOriginKey(const std::string& origin) { 44 std::string OriginToOriginKey(const std::string& origin) {
23 std::string key(kOriginKeyPrefix); 45 std::string key(kOriginKeyPrefix);
24 return key + origin; 46 return key + origin;
25 } 47 }
26 48
27 const char* LastPathKey() { 49 const char* LastPathKey() {
28 return kLastPathKey; 50 return kLastPathKey;
29 } 51 }
30 52
31 } 53 }
32 54
33 namespace fileapi { 55 namespace fileapi {
34 56
35 FileSystemOriginDatabase::OriginRecord::OriginRecord() { 57 FileSystemOriginDatabase::OriginRecord::OriginRecord() {
36 } 58 }
37 59
38 FileSystemOriginDatabase::OriginRecord::OriginRecord( 60 FileSystemOriginDatabase::OriginRecord::OriginRecord(
39 const std::string& origin_in, const FilePath& path_in) 61 const std::string& origin_in, const FilePath& path_in)
40 : origin(origin_in), path(path_in) { 62 : origin(origin_in), path(path_in) {
41 } 63 }
42 64
43 FileSystemOriginDatabase::OriginRecord::~OriginRecord() { 65 FileSystemOriginDatabase::OriginRecord::~OriginRecord() {
44 } 66 }
45 67
46 FileSystemOriginDatabase::FileSystemOriginDatabase(const FilePath& path) { 68 FileSystemOriginDatabase::FileSystemOriginDatabase(
47 #if defined(OS_POSIX) 69 const FilePath& file_system_directory)
48 path_ = path.value(); 70 : file_system_directory_(file_system_directory) {
49 #elif defined(OS_WIN)
50 path_ = base::SysWideToUTF8(path.value());
51 #endif
52 } 71 }
53 72
54 FileSystemOriginDatabase::~FileSystemOriginDatabase() { 73 FileSystemOriginDatabase::~FileSystemOriginDatabase() {
55 } 74 }
56 75
57 bool FileSystemOriginDatabase::Init() { 76 bool FileSystemOriginDatabase::Init(RecoveryOption recovery_option) {
58 if (db_.get()) 77 if (db_.get())
59 return true; 78 return true;
60 79
80 std::string path =
81 FilePathToString(file_system_directory_.Append(kOriginDatabaseName));
61 leveldb::Options options; 82 leveldb::Options options;
62 options.create_if_missing = true; 83 options.create_if_missing = true;
63 leveldb::DB* db; 84 leveldb::DB* db;
64 leveldb::Status status = leveldb::DB::Open(options, path_, &db); 85 leveldb::Status status = leveldb::DB::Open(options, path, &db);
86 // TODO(tzik): Collect status metrics here.
65 if (status.ok()) { 87 if (status.ok()) {
66 db_.reset(db); 88 db_.reset(db);
67 return true; 89 return true;
68 } 90 }
69 HandleError(FROM_HERE, status); 91 HandleError(FROM_HERE, status);
70 return false; 92
93 if (recovery_option == FAIL_ON_CORRUPTION)
94 return false;
95
96 if (recovery_option == REPAIR_ON_CORRUPTION) {
97 LOG(WARNING) << "Attempting to repair FileSystemOriginDatabase.";
98 if (RepairDatabase(path)) {
99 LOG(WARNING) << "Repairing FileSystemOriginDatabase completed.";
100 return true;
101 }
102 }
103
104 DCHECK(DELETE_ON_CORRUPTION == recovery_option ||
105 REPAIR_ON_CORRUPTION == recovery_option);
106 if (!file_util::Delete(file_system_directory_, true))
107 return false;
108 if (!file_util::CreateDirectory(file_system_directory_))
109 return false;
110
kinuko 2012/03/26 05:25:09 The lines 93-110 might look easier to follow in sw
tzik 2012/03/26 08:04:56 Done.
111 return Init(FAIL_ON_CORRUPTION);
112 }
113
114 bool FileSystemOriginDatabase::RepairDatabase(const std::string& db_path) {
115 DCHECK(!db_.get());
116 if (!leveldb::RepairDB(db_path, leveldb::Options()).ok() ||
117 !Init(FAIL_ON_CORRUPTION)) {
118 LOG(WARNING) << "Failed to repair FileSystemOriginDatabase.";
119 return false;
120 }
121
122 // See if the repaired entries match with what we have on disk.
123 std::set<FilePath> directories;
124 file_util::FileEnumerator file_enum(file_system_directory_,
125 false /* recursive */,
126 file_util::FileEnumerator::DIRECTORIES);
127 FilePath path_each;
128 while (!(path_each = file_enum.Next()).empty())
129 directories.insert(path_each.BaseName());
130 std::set<FilePath>::iterator db_dir_itr =
131 directories.find(FilePath(kOriginDatabaseName));
132 DCHECK(db_dir_itr != directories.end());
133 directories.erase(db_dir_itr);
134
135 std::vector<OriginRecord> origins;
136 if (!ListAllOrigins(&origins)) {
137 DropDatabase();
138 return false;
139 }
140 for (std::vector<OriginRecord>::iterator db_origin_itr = origins.begin();
141 db_origin_itr != origins.end();
142 ++db_origin_itr) {
143 std::set<FilePath>::iterator dir_itr =
144 directories.find(db_origin_itr->path);
145 if (dir_itr == directories.end()) {
146 if (!RemovePathForOrigin(db_origin_itr->origin)) {
147 DropDatabase();
148 return false;
149 }
150 } else {
151 directories.erase(dir_itr);
152 }
153 }
154
155 // Delete any directories not listed in the origins database.
156 for (std::set<FilePath>::iterator dir_itr = directories.begin();
157 dir_itr != directories.end();
158 ++dir_itr) {
159 if (!file_util::Delete(file_system_directory_.Append(*dir_itr),
160 true /* recursive */)) {
161 DropDatabase();
162 return false;
163 }
164 }
165
166 return true;
71 } 167 }
72 168
73 void FileSystemOriginDatabase::HandleError( 169 void FileSystemOriginDatabase::HandleError(
74 const tracked_objects::Location& from_here, leveldb::Status status) { 170 const tracked_objects::Location& from_here, leveldb::Status status) {
75 db_.reset(); 171 db_.reset();
76 LOG(ERROR) << "FileSystemOriginDatabase failed at: " 172 LOG(ERROR) << "FileSystemOriginDatabase failed at: "
77 << from_here.ToString() << " with error: " << status.ToString(); 173 << from_here.ToString() << " with error: " << status.ToString();
78 } 174 }
79 175
80 bool FileSystemOriginDatabase::HasOriginPath(const std::string& origin) { 176 bool FileSystemOriginDatabase::HasOriginPath(const std::string& origin) {
81 if (!Init()) 177 if (!Init(REPAIR_ON_CORRUPTION))
82 return false; 178 return false;
83 if (origin.empty()) 179 if (origin.empty())
84 return false; 180 return false;
85 std::string path; 181 std::string path;
86 leveldb::Status status = 182 leveldb::Status status =
87 db_->Get(leveldb::ReadOptions(), OriginToOriginKey(origin), &path); 183 db_->Get(leveldb::ReadOptions(), OriginToOriginKey(origin), &path);
88 if (status.ok()) 184 if (status.ok())
89 return true; 185 return true;
90 if (status.IsNotFound()) 186 if (status.IsNotFound())
91 return false; 187 return false;
92 HandleError(FROM_HERE, status); 188 HandleError(FROM_HERE, status);
93 return false; 189 return false;
94 } 190 }
95 191
96 bool FileSystemOriginDatabase::GetPathForOrigin( 192 bool FileSystemOriginDatabase::GetPathForOrigin(
97 const std::string& origin, FilePath* directory) { 193 const std::string& origin, FilePath* directory) {
98 if (!Init()) 194 if (!Init(REPAIR_ON_CORRUPTION))
99 return false; 195 return false;
100 DCHECK(directory); 196 DCHECK(directory);
101 if (origin.empty()) 197 if (origin.empty())
102 return false; 198 return false;
103 std::string path_string; 199 std::string path_string;
104 std::string origin_key = OriginToOriginKey(origin); 200 std::string origin_key = OriginToOriginKey(origin);
105 leveldb::Status status = 201 leveldb::Status status =
106 db_->Get(leveldb::ReadOptions(), origin_key, &path_string); 202 db_->Get(leveldb::ReadOptions(), origin_key, &path_string);
107 if (status.IsNotFound()) { 203 if (status.IsNotFound()) {
108 int last_path_number; 204 int last_path_number;
109 if (!GetLastPathNumber(&last_path_number)) 205 if (!GetLastPathNumber(&last_path_number))
110 return false; 206 return false;
111 path_string = StringPrintf("%03u", last_path_number + 1); 207 path_string = StringPrintf("%03u", last_path_number + 1);
112 // store both back as a single transaction 208 // store both back as a single transaction
113 leveldb::WriteBatch batch; 209 leveldb::WriteBatch batch;
114 batch.Put(LastPathKey(), path_string); 210 batch.Put(LastPathKey(), path_string);
115 batch.Put(origin_key, path_string); 211 batch.Put(origin_key, path_string);
116 status = db_->Write(leveldb::WriteOptions(), &batch); 212 status = db_->Write(leveldb::WriteOptions(), &batch);
117 if (!status.ok()) { 213 if (!status.ok()) {
118 HandleError(FROM_HERE, status); 214 HandleError(FROM_HERE, status);
119 return false; 215 return false;
120 } 216 }
121 } 217 }
122 if (status.ok()) { 218 if (status.ok()) {
123 #if defined(OS_POSIX) 219 *directory = StringToFilePath(path_string);
124 *directory = FilePath(path_string);
125 #elif defined(OS_WIN)
126 *directory = FilePath(base::SysUTF8ToWide(path_string));
127 #endif
128 return true; 220 return true;
129 } 221 }
130 HandleError(FROM_HERE, status); 222 HandleError(FROM_HERE, status);
131 return false; 223 return false;
132 } 224 }
133 225
134 bool FileSystemOriginDatabase::RemovePathForOrigin(const std::string& origin) { 226 bool FileSystemOriginDatabase::RemovePathForOrigin(const std::string& origin) {
135 if (!Init()) 227 if (!Init(REPAIR_ON_CORRUPTION))
136 return false; 228 return false;
137 leveldb::Status status = 229 leveldb::Status status =
138 db_->Delete(leveldb::WriteOptions(), OriginToOriginKey(origin)); 230 db_->Delete(leveldb::WriteOptions(), OriginToOriginKey(origin));
139 if (status.ok() || status.IsNotFound()) 231 if (status.ok() || status.IsNotFound())
140 return true; 232 return true;
141 HandleError(FROM_HERE, status); 233 HandleError(FROM_HERE, status);
142 return false; 234 return false;
143 } 235 }
144 236
145 bool FileSystemOriginDatabase::ListAllOrigins( 237 bool FileSystemOriginDatabase::ListAllOrigins(
146 std::vector<OriginRecord>* origins) { 238 std::vector<OriginRecord>* origins) {
147 if (!Init()) 239 if (!Init(REPAIR_ON_CORRUPTION))
148 return false; 240 return false;
149 DCHECK(origins); 241 DCHECK(origins);
150 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions())); 242 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions()));
151 std::string origin_key_prefix = OriginToOriginKey(""); 243 std::string origin_key_prefix = OriginToOriginKey("");
152 iter->Seek(origin_key_prefix); 244 iter->Seek(origin_key_prefix);
153 origins->clear(); 245 origins->clear();
154 while(iter->Valid() && 246 while(iter->Valid() &&
155 StartsWithASCII(iter->key().ToString(), origin_key_prefix, true)) { 247 StartsWithASCII(iter->key().ToString(), origin_key_prefix, true)) {
156 std::string origin = 248 std::string origin =
157 iter->key().ToString().substr(origin_key_prefix.length()); 249 iter->key().ToString().substr(origin_key_prefix.length());
158 #if defined(OS_POSIX) 250 FilePath path = StringToFilePath(iter->value().ToString());
159 FilePath path = FilePath(iter->value().ToString());
160 #elif defined(OS_WIN)
161 FilePath path = FilePath(base::SysUTF8ToWide(iter->value().ToString()));
162 #endif
163 origins->push_back(OriginRecord(origin, path)); 251 origins->push_back(OriginRecord(origin, path));
164 iter->Next(); 252 iter->Next();
165 } 253 }
166 return true; 254 return true;
167 } 255 }
168 256
169 void FileSystemOriginDatabase::DropDatabase() { 257 void FileSystemOriginDatabase::DropDatabase() {
170 db_.reset(); 258 db_.reset();
171 } 259 }
172 260
173 bool FileSystemOriginDatabase::GetLastPathNumber(int* number) { 261 bool FileSystemOriginDatabase::GetLastPathNumber(int* number) {
174 if (!Init()) 262 if (!Init(REPAIR_ON_CORRUPTION))
175 return false; 263 return false;
176 DCHECK(number); 264 DCHECK(number);
177 std::string number_string; 265 std::string number_string;
178 leveldb::Status status = 266 leveldb::Status status =
179 db_->Get(leveldb::ReadOptions(), LastPathKey(), &number_string); 267 db_->Get(leveldb::ReadOptions(), LastPathKey(), &number_string);
180 if (status.ok()) 268 if (status.ok())
181 return base::StringToInt(number_string, number); 269 return base::StringToInt(number_string, number);
182 if (!status.IsNotFound()) { 270 if (!status.IsNotFound()) {
183 HandleError(FROM_HERE, status); 271 HandleError(FROM_HERE, status);
184 return false; 272 return false;
(...skipping 11 matching lines...) Expand all
196 db_->Put(leveldb::WriteOptions(), LastPathKey(), std::string("-1")); 284 db_->Put(leveldb::WriteOptions(), LastPathKey(), std::string("-1"));
197 if (!status.ok()) { 285 if (!status.ok()) {
198 HandleError(FROM_HERE, status); 286 HandleError(FROM_HERE, status);
199 return false; 287 return false;
200 } 288 }
201 *number = -1; 289 *number = -1;
202 return true; 290 return true;
203 } 291 }
204 292
205 } // namespace fileapi 293 } // namespace fileapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698