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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: webkit/fileapi/syncable/local_file_change_tracker.cc
diff --git a/webkit/fileapi/syncable/local_file_change_tracker.cc b/webkit/fileapi/syncable/local_file_change_tracker.cc
index 81e61a094b956a2dabd3a8c07f9b5ba2d0f31939..7ed60e09d550cf40c2956def852ff79bf51febca 100644
--- a/webkit/fileapi/syncable/local_file_change_tracker.cc
+++ b/webkit/fileapi/syncable/local_file_change_tracker.cc
@@ -4,20 +4,77 @@
#include "webkit/fileapi/syncable/local_file_change_tracker.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
#include "base/sequenced_task_runner.h"
+#include "third_party/leveldatabase/src/include/leveldb/db.h"
#include "webkit/fileapi/syncable/local_file_sync_status.h"
+#include "webkit/fileapi/file_system_util.h"
+
+namespace {
+
+const FilePath::CharType kDatabaseName[] =
+ FILE_PATH_LITERAL("LocalFileChangeTracker");
+const int64 kMinimumReportIntervalHours = 1;
+const char kInitStatusHistogramLabel[] =
+ "FileSystem.LocalFileChangeTracker.InitDatabase";
+const char kMark[] = "d";
+
+}
namespace fileapi {
+// A database class that stores local file changes in a local database. This
+// object must be destructed on file_task_runner.
+class LocalFileChangeTracker::TrackerDB {
+ public:
+ TrackerDB(const FilePath& profile_path);
+
+ void MarkDirty(const FileSystemURL& url);
+ void ClearDirty(const FileSystemURL& url);
+
+ private:
+ enum InitStatus {
+ INIT_STATUS_OK = 0,
+ INIT_STATUS_CORRUPTION,
+ INIT_STATUS_IO_ERROR,
+ INIT_STATUS_UNKNOWN_ERROR,
+ INIT_STATUS_MAX,
+ };
+
+ enum RecoveryOption {
+ REPAIR_ON_CORRUPTION,
+ FAIL_ON_CORRUPTION,
+ };
+
+ bool Init(RecoveryOption recovery_option);
+ bool Repair(const std::string& db_path);
+ void HandleError(const tracked_objects::Location& from_here,
+ const leveldb::Status& status);
+ void ReportInitStatus(const leveldb::Status& status);
+
+ const FilePath profile_path_;
+ scoped_ptr<leveldb::DB> db_;
+ base::Time last_reported_time_;
+ bool db_disabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrackerDB);
+};
+
+// LocalFileChangeTracker ------------------------------------------------------
+
LocalFileChangeTracker::LocalFileChangeTracker(
LocalFileSyncStatus* sync_status,
+ const FilePath& profile_path,
base::SequencedTaskRunner* file_task_runner)
: sync_status_(sync_status),
- file_task_runner_(file_task_runner) {}
+ file_task_runner_(file_task_runner),
+ tracker_db_(new TrackerDB(profile_path)) {}
LocalFileChangeTracker::~LocalFileChangeTracker() {
- // file_task_runner_->PostTask(FROM_HERE, base::Bind(&DropDatabase));
- // TODO(kinuko): implement.
+ if (tracker_db_.get())
+ file_task_runner_->DeleteSoon(FROM_HERE, tracker_db_.release());
}
void LocalFileChangeTracker::OnStartUpdate(const FileSystemURL& url) {
@@ -107,11 +164,129 @@ void LocalFileChangeTracker::RecordChange(
}
void LocalFileChangeTracker::MarkDirtyOnDatabase(const FileSystemURL& url) {
- // TODO(kinuko): implement.
+ tracker_db_->MarkDirty(url);
}
void LocalFileChangeTracker::ClearDirtyOnDatabase(const FileSystemURL& url) {
- // TODO(kinuko): implement.
+ tracker_db_->ClearDirty(url);
+}
+
+// TrackerDB -------------------------------------------------------------------
+
+LocalFileChangeTracker::TrackerDB::TrackerDB(const FilePath& profile_path)
+ : profile_path_(profile_path),
+ db_disabled_(false) {}
+
+bool LocalFileChangeTracker::TrackerDB::Init(RecoveryOption recovery_option) {
+ if (db_.get())
+ return true;
+
+ std::string path = FilePathToString(profile_path_.Append(kDatabaseName));
+ leveldb::Options options;
+ options.create_if_missing = true;
+ leveldb::DB* db;
+ leveldb::Status status = leveldb::DB::Open(options, path, &db);
+ ReportInitStatus(status);
+ if (status.ok()) {
+ db_.reset(db);
+ return true;
+ }
+
+ HandleError(FROM_HERE, status);
+ if (!status.IsCorruption())
+ return false;
+
+ switch (recovery_option) {
+ case FAIL_ON_CORRUPTION:
+ return false;
+ case REPAIR_ON_CORRUPTION:
+ if (Repair(path))
tzik 2012/09/20 05:24:50 can be just return Repair(path);
nhiroki 2012/09/20 09:30:33 Done.
+ return true;
+ return false;
+ }
+ NOTREACHED();
+ return false;
+}
+
+bool LocalFileChangeTracker::TrackerDB::Repair(const std::string& db_path) {
+ DCHECK(!db_.get());
+ LOG(WARNING) << "Attempting to repair TrackerDB.";
+
+ 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.
+ Init(FAIL_ON_CORRUPTION)) {
+ LOG(WARNING) << "Repairing TrackerDB completed.";
+ return true;
+ }
+
+ LOG(WARNING) << "Failed to repair TrackerDB.";
+ return false;
+}
+
+void LocalFileChangeTracker::TrackerDB::HandleError(
+ const tracked_objects::Location& from_here,
+ const leveldb::Status& status) {
+ LOG(ERROR) << "LocalFileChangeTracker::TrackerDB failed at: "
+ << 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.
+}
+
+void LocalFileChangeTracker::TrackerDB::ReportInitStatus(
+ const leveldb::Status& status) {
+ base::Time now = base::Time::Now();
+ base::TimeDelta minimum_interval =
+ base::TimeDelta::FromHours(kMinimumReportIntervalHours);
+ if (last_reported_time_ + minimum_interval >= now)
+ return;
+ last_reported_time_ = now;
+
+ if (status.ok()) {
+ UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
+ INIT_STATUS_OK, INIT_STATUS_MAX);
+ } else if (status.IsCorruption()) {
+ UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
+ INIT_STATUS_CORRUPTION, INIT_STATUS_OK);
+ } else if (status.IsIOError()) {
+ UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
+ INIT_STATUS_IO_ERROR, INIT_STATUS_MAX);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
+ 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.
+ }
+}
+
+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.
+ if (db_disabled_)
+ return;
+
+ if (!Init(REPAIR_ON_CORRUPTION)) {
+ db_disabled_ = true;
+ return;
+ }
+
+ 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.
+ if (!status.ok()) {
+ HandleError(FROM_HERE, status);
+ db_disabled_ = true;
+ return;
+ }
+ return;
+}
+
+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.
+ if (db_disabled_)
+ return;
+
+ if (!Init(REPAIR_ON_CORRUPTION)) {
+ db_disabled_ = true;
+ return;
+ }
+
+ leveldb::Status status = db_->Delete(leveldb::WriteOptions(), url.spec());
+ if (!status.ok() && !status.IsNotFound()) {
+ HandleError(FROM_HERE, status);
+ db_disabled_ = true;
+ return;
+ }
+ return;
}
} // namespace fileapi

Powered by Google App Engine
This is Rietveld 408576698