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

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: Reflect comments 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..942d3e5f251a726c3561817da9821a3a42b3abd8 100644
--- a/webkit/fileapi/syncable/local_file_change_tracker.cc
+++ b/webkit/fileapi/syncable/local_file_change_tracker.cc
@@ -4,20 +4,70 @@
#include "webkit/fileapi/syncable/local_file_change_tracker.h"
+#include "base/location.h"
+#include "base/logging.h"
#include "base/sequenced_task_runner.h"
+#include "third_party/leveldatabase/src/include/leveldb/db.h"
+#include "webkit/fileapi/file_system_util.h"
#include "webkit/fileapi/syncable/local_file_sync_status.h"
+namespace {
+const FilePath::CharType kDatabaseName[] =
+ FILE_PATH_LITERAL("LocalFileChangeTracker");
+const char kMark[] = "d";
+} // namespace
+
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:
+ explicit TrackerDB(const FilePath& profile_path);
+
+ bool MarkDirty(const std::string& url);
+ bool ClearDirty(const std::string& 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);
+
+ 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 +157,120 @@ void LocalFileChangeTracker::RecordChange(
}
void LocalFileChangeTracker::MarkDirtyOnDatabase(const FileSystemURL& url) {
- // TODO(kinuko): implement.
+ tracker_db_->MarkDirty(SerializeExternalFileSystemURL(url));
}
void LocalFileChangeTracker::ClearDirtyOnDatabase(const FileSystemURL& url) {
- // TODO(kinuko): implement.
+ tracker_db_->ClearDirty(SerializeExternalFileSystemURL(url));
+}
+
+std::string LocalFileChangeTracker::SerializeExternalFileSystemURL(
+ const FileSystemURL& url) {
+ return GetFileSystemRootURI(url.origin(), kFileSystemTypeExternal).spec() +
+ url.filesystem_id() + "/" + url.path().AsUTF8Unsafe();
+}
+
+FileSystemURL LocalFileChangeTracker::DeserializeExternalFileSystemURL(
+ const std::string& url) {
+ return FileSystemURL(GURL(url));
kinuko 2012/09/21 08:12:32 I prefer making this method like: bool Deserializ
nhiroki 2012/09/24 07:01:40 Done.
+}
+
+// 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);
+ 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:
+ return Repair(path);
+ }
+ 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() &&
+ Init(FAIL_ON_CORRUPTION)) {
+ // TODO(nhiroki): perform some consistency checks between TrackerDB and
+ // cloud-backed file system.
kinuko 2012/09/21 08:12:32 nit: cloud-backed -> syncable
nhiroki 2012/09/24 07:01:40 Done.
+ LOG(WARNING) << "Repairing TrackerDB completed.";
+ return true;
+ }
+
+ LOG(WARNING) << "Failed to repair TrackerDB.";
+ return false;
+}
+
+// TODO(nhiroki): factor out the common methods into somewhere else.
+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();
+}
+
+bool LocalFileChangeTracker::TrackerDB::MarkDirty(const std::string& url) {
+ if (db_disabled_)
+ return false;
+
+ if (!Init(REPAIR_ON_CORRUPTION)) {
+ db_disabled_ = true;
+ db_.reset();
+ return false;
+ }
+
+ leveldb::Status status = db_->Put(leveldb::WriteOptions(), url, kMark);
+ if (!status.ok()) {
+ HandleError(FROM_HERE, status);
+ db_disabled_ = true;
+ db_.reset();
+ return false;
+ }
+ return true;
+}
+
+bool LocalFileChangeTracker::TrackerDB::ClearDirty(const std::string& url) {
+ if (db_disabled_)
+ return false;
+
+ if (!Init(REPAIR_ON_CORRUPTION)) {
kinuko 2012/09/21 08:12:32 Not sure if this could get called before initializ
nhiroki 2012/09/24 07:01:40 I understand. Yes, we can just do DCHECK().
+ db_disabled_ = true;
+ db_.reset();
+ return false;
+ }
+
+ leveldb::Status status = db_->Delete(leveldb::WriteOptions(), url);
+ if (!status.ok() && !status.IsNotFound()) {
+ HandleError(FROM_HERE, status);
+ db_disabled_ = true;
+ db_.reset();
+ return false;
+ }
+ return true;
}
} // namespace fileapi

Powered by Google App Engine
This is Rietveld 408576698