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

Side by Side Diff: webkit/fileapi/syncable/local_file_change_tracker.cc

Issue 10966003: Add LocalFileChangeTracker database to record non-synced dirty files (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 3 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/syncable/local_file_change_tracker.h" 5 #include "webkit/fileapi/syncable/local_file_change_tracker.h"
6 6
7 #include "base/location.h"
8 #include "base/logging.h"
9 #include "base/metrics/histogram.h"
7 #include "base/sequenced_task_runner.h" 10 #include "base/sequenced_task_runner.h"
11 #include "third_party/leveldatabase/src/include/leveldb/db.h"
8 #include "webkit/fileapi/syncable/local_file_sync_status.h" 12 #include "webkit/fileapi/syncable/local_file_sync_status.h"
13 #include "webkit/fileapi/file_system_util.h"
14
15 namespace {
16
17 const FilePath::CharType kDatabaseName[] =
18 FILE_PATH_LITERAL("LocalFileChangeTracker");
19 const int64 kMinimumReportIntervalHours = 1;
20 const char kInitStatusHistogramLabel[] =
21 "FileSystem.LocalFileChangeTracker.InitDatabase";
22 const char kMark[] = "d";
23
24 }
9 25
10 namespace fileapi { 26 namespace fileapi {
11 27
28 // A database class that stores local file changes in a local database. This
29 // object must be destructed on file_task_runner.
30 class LocalFileChangeTracker::TrackerDB {
31 public:
32 TrackerDB(const FilePath& profile_path);
33
34 void MarkDirty(const FileSystemURL& url);
35 void ClearDirty(const FileSystemURL& url);
36
37 private:
38 enum InitStatus {
39 INIT_STATUS_OK = 0,
40 INIT_STATUS_CORRUPTION,
41 INIT_STATUS_IO_ERROR,
42 INIT_STATUS_UNKNOWN_ERROR,
43 INIT_STATUS_MAX,
44 };
45
46 enum RecoveryOption {
47 REPAIR_ON_CORRUPTION,
48 FAIL_ON_CORRUPTION,
49 };
50
51 bool Init(RecoveryOption recovery_option);
52 bool Repair(const std::string& db_path);
53 void HandleError(const tracked_objects::Location& from_here,
54 const leveldb::Status& status);
55 void ReportInitStatus(const leveldb::Status& status);
56
57 const FilePath profile_path_;
58 scoped_ptr<leveldb::DB> db_;
59 base::Time last_reported_time_;
60 bool db_disabled_;
61
62 DISALLOW_COPY_AND_ASSIGN(TrackerDB);
63 };
64
65 // LocalFileChangeTracker ------------------------------------------------------
66
12 LocalFileChangeTracker::LocalFileChangeTracker( 67 LocalFileChangeTracker::LocalFileChangeTracker(
13 LocalFileSyncStatus* sync_status, 68 LocalFileSyncStatus* sync_status,
69 const FilePath& profile_path,
14 base::SequencedTaskRunner* file_task_runner) 70 base::SequencedTaskRunner* file_task_runner)
15 : sync_status_(sync_status), 71 : sync_status_(sync_status),
16 file_task_runner_(file_task_runner) {} 72 file_task_runner_(file_task_runner),
73 tracker_db_(new TrackerDB(profile_path)) {}
17 74
18 LocalFileChangeTracker::~LocalFileChangeTracker() { 75 LocalFileChangeTracker::~LocalFileChangeTracker() {
19 // file_task_runner_->PostTask(FROM_HERE, base::Bind(&DropDatabase)); 76 if (tracker_db_.get())
20 // TODO(kinuko): implement. 77 file_task_runner_->DeleteSoon(FROM_HERE, tracker_db_.release());
21 } 78 }
22 79
23 void LocalFileChangeTracker::OnStartUpdate(const FileSystemURL& url) { 80 void LocalFileChangeTracker::OnStartUpdate(const FileSystemURL& url) {
24 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 81 DCHECK(file_task_runner_->RunsTasksOnCurrentThread());
25 // TODO(kinuko): we may want to reduce the number of this call if 82 // TODO(kinuko): we may want to reduce the number of this call if
26 // the URL is already marked dirty. 83 // the URL is already marked dirty.
27 MarkDirtyOnDatabase(url); 84 MarkDirtyOnDatabase(url);
28 } 85 }
29 86
30 void LocalFileChangeTracker::OnEndUpdate(const FileSystemURL& url) { 87 void LocalFileChangeTracker::OnEndUpdate(const FileSystemURL& url) {
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 NOTREACHED(); 157 NOTREACHED();
101 } 158 }
102 159
103 void LocalFileChangeTracker::RecordChange( 160 void LocalFileChangeTracker::RecordChange(
104 const FileSystemURL& url, const FileChange& change) { 161 const FileSystemURL& url, const FileChange& change) {
105 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 162 DCHECK(file_task_runner_->RunsTasksOnCurrentThread());
106 changes_[url].Update(change); 163 changes_[url].Update(change);
107 } 164 }
108 165
109 void LocalFileChangeTracker::MarkDirtyOnDatabase(const FileSystemURL& url) { 166 void LocalFileChangeTracker::MarkDirtyOnDatabase(const FileSystemURL& url) {
110 // TODO(kinuko): implement. 167 tracker_db_->MarkDirty(url);
111 } 168 }
112 169
113 void LocalFileChangeTracker::ClearDirtyOnDatabase(const FileSystemURL& url) { 170 void LocalFileChangeTracker::ClearDirtyOnDatabase(const FileSystemURL& url) {
114 // TODO(kinuko): implement. 171 tracker_db_->ClearDirty(url);
172 }
173
174 // TrackerDB -------------------------------------------------------------------
175
176 LocalFileChangeTracker::TrackerDB::TrackerDB(const FilePath& profile_path)
177 : profile_path_(profile_path),
178 db_disabled_(false) {}
179
180 bool LocalFileChangeTracker::TrackerDB::Init(RecoveryOption recovery_option) {
181 if (db_.get())
182 return true;
183
184 std::string path = FilePathToString(profile_path_.Append(kDatabaseName));
185 leveldb::Options options;
186 options.create_if_missing = true;
187 leveldb::DB* db;
188 leveldb::Status status = leveldb::DB::Open(options, path, &db);
189 ReportInitStatus(status);
190 if (status.ok()) {
191 db_.reset(db);
192 return true;
193 }
194
195 HandleError(FROM_HERE, status);
196 if (!status.IsCorruption())
197 return false;
198
199 switch (recovery_option) {
200 case FAIL_ON_CORRUPTION:
201 return false;
202 case REPAIR_ON_CORRUPTION:
203 if (Repair(path))
tzik 2012/09/20 05:24:50 can be just return Repair(path);
nhiroki 2012/09/20 09:30:33 Done.
204 return true;
205 return false;
206 }
207 NOTREACHED();
208 return false;
209 }
210
211 bool LocalFileChangeTracker::TrackerDB::Repair(const std::string& db_path) {
212 DCHECK(!db_.get());
213 LOG(WARNING) << "Attempting to repair TrackerDB.";
214
215 if (leveldb::RepairDB(db_path, leveldb::Options()).ok() ||
tzik 2012/09/20 05:24:50 We might lose some database entry on this method.
nhiroki 2012/09/20 09:30:33 For now, added TODO comments.
216 Init(FAIL_ON_CORRUPTION)) {
217 LOG(WARNING) << "Repairing TrackerDB completed.";
218 return true;
219 }
220
221 LOG(WARNING) << "Failed to repair TrackerDB.";
222 return false;
223 }
224
225 void LocalFileChangeTracker::TrackerDB::HandleError(
226 const tracked_objects::Location& from_here,
227 const leveldb::Status& status) {
228 LOG(ERROR) << "LocalFileChangeTracker::TrackerDB failed at: "
229 << from_here.ToString() << " with error: " << status.ToString();
kinuko 2012/09/20 05:09:11 (Not directly related to this cl but would be nice
nhiroki 2012/09/20 09:30:33 Added TODO comments.
230 }
231
232 void LocalFileChangeTracker::TrackerDB::ReportInitStatus(
233 const leveldb::Status& status) {
234 base::Time now = base::Time::Now();
235 base::TimeDelta minimum_interval =
236 base::TimeDelta::FromHours(kMinimumReportIntervalHours);
237 if (last_reported_time_ + minimum_interval >= now)
238 return;
239 last_reported_time_ = now;
240
241 if (status.ok()) {
242 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
243 INIT_STATUS_OK, INIT_STATUS_MAX);
244 } else if (status.IsCorruption()) {
245 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
246 INIT_STATUS_CORRUPTION, INIT_STATUS_OK);
247 } else if (status.IsIOError()) {
248 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
249 INIT_STATUS_IO_ERROR, INIT_STATUS_MAX);
250 } else {
251 UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
252 INIT_STATUS_UNKNOWN_ERROR, INIT_STATUS_MAX);
kinuko 2012/09/20 05:09:11 Adding UMA is great, but can we not add these in t
nhiroki 2012/09/20 09:30:33 Okay, removed it.
253 }
254 }
255
256 void LocalFileChangeTracker::TrackerDB::MarkDirty(const FileSystemURL& url) {
kinuko 2012/09/20 05:09:11 Can we return success/fail here?
nhiroki 2012/09/20 09:30:33 Done.
257 if (db_disabled_)
258 return;
259
260 if (!Init(REPAIR_ON_CORRUPTION)) {
261 db_disabled_ = true;
262 return;
263 }
264
265 leveldb::Status status = db_->Put(leveldb::WriteOptions(), url.spec(), kMark);
kinuko 2012/09/20 05:09:11 I'm afraid Current spec() impl does not maintain a
nhiroki 2012/09/20 09:30:33 Added serialize/deserialize methods.
266 if (!status.ok()) {
267 HandleError(FROM_HERE, status);
268 db_disabled_ = true;
269 return;
270 }
271 return;
272 }
273
274 void LocalFileChangeTracker::TrackerDB::ClearDirty(const FileSystemURL& url) {
kinuko 2012/09/20 05:09:11 Can we return success/fail here?
nhiroki 2012/09/20 09:30:33 Done.
275 if (db_disabled_)
276 return;
277
278 if (!Init(REPAIR_ON_CORRUPTION)) {
279 db_disabled_ = true;
280 return;
281 }
282
283 leveldb::Status status = db_->Delete(leveldb::WriteOptions(), url.spec());
284 if (!status.ok() && !status.IsNotFound()) {
285 HandleError(FROM_HERE, status);
286 db_disabled_ = true;
287 return;
288 }
289 return;
115 } 290 }
116 291
117 } // namespace fileapi 292 } // namespace fileapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698