diff options
3 files changed, 104 insertions, 11 deletions
diff --git a/chrome/browser/sync_file_system/local/local_file_change_tracker.cc b/chrome/browser/sync_file_system/local/local_file_change_tracker.cc index 3b42634..0f6f186 100644 --- a/chrome/browser/sync_file_system/local/local_file_change_tracker.cc +++ b/chrome/browser/sync_file_system/local/local_file_change_tracker.cc @@ -13,6 +13,7 @@ #include "chrome/browser/sync_file_system/local/local_file_sync_status.h" #include "chrome/browser/sync_file_system/syncable_file_system_util.h" #include "third_party/leveldatabase/src/include/leveldb/db.h" +#include "third_party/leveldatabase/src/include/leveldb/write_batch.h" #include "webkit/browser/fileapi/file_system_context.h" #include "webkit/browser/fileapi/file_system_file_util.h" #include "webkit/browser/fileapi/file_system_operation_context.h" @@ -42,6 +43,7 @@ class LocalFileChangeTracker::TrackerDB { SyncStatusCode ClearDirty(const std::string& url); SyncStatusCode GetDirtyEntries( std::queue<FileSystemURL>* dirty_files); + SyncStatusCode WriteBatch(scoped_ptr<leveldb::WriteBatch> batch); private: enum RecoveryOption { @@ -205,6 +207,37 @@ SyncStatusCode LocalFileChangeTracker::Initialize( return status; } +void LocalFileChangeTracker::ResetForFileSystem( + const GURL& origin, + fileapi::FileSystemType type) { + DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); + scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); + for (FileChangeMap::iterator iter = changes_.begin(); + iter != changes_.end();) { + fileapi::FileSystemURL url = iter->first; + if (url.origin() != origin || url.type() != type) { + ++iter; + continue; + } + mirror_changes_.erase(url); + change_seqs_.erase(iter->second.change_seq); + changes_.erase(iter++); + + std::string serialized_url; + const bool should_success = + SerializeSyncableFileSystemURL(url, &serialized_url); + if (!should_success) { + NOTREACHED() << "Failed to serialize: " << url.DebugString(); + continue; + } + batch->Delete(serialized_url); + } + // Fail to apply batch to database wouldn't have critical effect, they'll be + // just marked deleted on next relaunch. + tracker_db_->WriteBatch(batch.Pass()); + UpdateNumChanges(); +} + void LocalFileChangeTracker::UpdateNumChanges() { base::AutoLock lock(num_changes_lock_); num_changes_ = static_cast<int64>(change_seqs_.size()); @@ -471,4 +504,19 @@ SyncStatusCode LocalFileChangeTracker::TrackerDB::GetDirtyEntries( return SYNC_STATUS_OK; } +SyncStatusCode LocalFileChangeTracker::TrackerDB::WriteBatch( + scoped_ptr<leveldb::WriteBatch> batch) { + if (db_status_ != SYNC_STATUS_OK) + return db_status_; + + leveldb::Status status = db_->Write(leveldb::WriteOptions(), batch.get()); + if (!status.ok() && !status.IsNotFound()) { + HandleError(FROM_HERE, status); + db_status_ = LevelDBStatusToSyncStatusCode(status); + db_.reset(); + return db_status_; + } + return SYNC_STATUS_OK; +} + } // namespace sync_file_system diff --git a/chrome/browser/sync_file_system/local/local_file_change_tracker.h b/chrome/browser/sync_file_system/local/local_file_change_tracker.h index 456a489..9fafc7d 100644 --- a/chrome/browser/sync_file_system/local/local_file_change_tracker.h +++ b/chrome/browser/sync_file_system/local/local_file_change_tracker.h @@ -90,14 +90,17 @@ class LocalFileChangeTracker // left after the last shutdown (if any). SyncStatusCode Initialize(fileapi::FileSystemContext* file_system_context); + // Resets all the changes recorded for the given |origin| and |type|. + // TODO(kinuko,nhiroki): Ideally this should be automatically called in + // DeleteFileSystem via QuotaUtil::DeleteOriginDataOnFileThread. + void ResetForFileSystem(const GURL& origin, fileapi::FileSystemType type); + // This method is (exceptionally) thread-safe. int64 num_changes() const { base::AutoLock lock(num_changes_lock_); return num_changes_; } - void UpdateNumChanges(); - private: class TrackerDB; friend class CannedSyncableFileSystem; @@ -118,6 +121,8 @@ class LocalFileChangeTracker FileChangeMap; typedef std::map<int64, fileapi::FileSystemURL> ChangeSeqMap; + void UpdateNumChanges(); + // This does mostly same as calling GetNextChangedURLs with max_url=0 // except that it returns urls in set rather than in deque. // Used only in testings. diff --git a/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc b/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc index 6c5f3b6..4125d97 100644 --- a/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc +++ b/chrome/browser/sync_file_system/local/local_file_change_tracker_unittest.cc @@ -101,6 +101,10 @@ class LocalFileChangeTrackerTest : public testing::Test { change_tracker()->CollectLastDirtyChanges(file_system_context()); } + void GetAllChangedURLs(fileapi::FileSystemURLSet* urls) { + change_tracker()->GetAllChangedURLs(urls); + } + ScopedEnableSyncFSDirectoryOperation enable_directory_operation_; base::MessageLoop message_loop_; CannedSyncableFileSystem file_system_; @@ -566,8 +570,6 @@ TEST_F(LocalFileChangeTrackerTest, NextChangedURLsWithRecursiveCopy) { TEST_F(LocalFileChangeTrackerTest, NextChangedURLsWithRecursiveRemove) { EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.OpenFileSystem()); - FileSystemURLSet urls; - const char kPath0[] = "dir a"; const char kPath1[] = "dir a/file1"; const char kPath2[] = "dir a/file2"; @@ -582,8 +584,8 @@ TEST_F(LocalFileChangeTrackerTest, NextChangedURLsWithRecursiveRemove) { EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.Remove(URL(kPath0), true /* recursive */)); - std::deque<FileSystemURL> urls_to_process; - change_tracker()->GetNextChangedURLs(&urls_to_process, 0); + FileSystemURLSet urls; + GetAllChangedURLs(&urls); // This is actually not really desirable, but since the directory // creation and deletion have been offset now we only have two @@ -595,13 +597,51 @@ TEST_F(LocalFileChangeTrackerTest, NextChangedURLsWithRecursiveRemove) { // TODO(kinuko): For micro optimization we could probably restore the ADD // change type (other than ADD_OR_UPDATE) and offset file ADD+DELETE // changes too. - ASSERT_EQ(2U, urls_to_process.size()); + ASSERT_EQ(2U, urls.size()); // The exact order of recursive removal cannot be determined. - EXPECT_TRUE(URL(kPath1) == urls_to_process[0] || - URL(kPath2) == urls_to_process[0]); - EXPECT_TRUE(URL(kPath1) == urls_to_process[1] || - URL(kPath2) == urls_to_process[1]); + EXPECT_TRUE(ContainsKey(urls, URL(kPath1))); + EXPECT_TRUE(ContainsKey(urls, URL(kPath2))); +} + +TEST_F(LocalFileChangeTrackerTest, ResetForFileSystem) { + EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.OpenFileSystem()); + + const char kPath0[] = "dir a"; + const char kPath1[] = "dir a/file"; + const char kPath2[] = "dir a/subdir"; + const char kPath3[] = "dir b"; + + EXPECT_EQ(base::PLATFORM_FILE_OK, + file_system_.CreateDirectory(URL(kPath0))); + EXPECT_EQ(base::PLATFORM_FILE_OK, + file_system_.CreateFile(URL(kPath1))); + EXPECT_EQ(base::PLATFORM_FILE_OK, + file_system_.CreateDirectory(URL(kPath2))); + EXPECT_EQ(base::PLATFORM_FILE_OK, + file_system_.CreateDirectory(URL(kPath3))); + + FileSystemURLSet urls; + GetAllChangedURLs(&urls); + EXPECT_EQ(4u, urls.size()); + EXPECT_TRUE(ContainsKey(urls, URL(kPath0))); + EXPECT_TRUE(ContainsKey(urls, URL(kPath1))); + EXPECT_TRUE(ContainsKey(urls, URL(kPath2))); + EXPECT_TRUE(ContainsKey(urls, URL(kPath3))); + + // Reset all changes for the file system. + change_tracker()->ResetForFileSystem( + file_system_.origin(), file_system_.type()); + + GetAllChangedURLs(&urls); + EXPECT_TRUE(urls.empty()); + + // Make sure they're gone from the database too. + DropChangesInTracker(); + RestoreChangesFromTrackerDB(); + + GetAllChangedURLs(&urls); + EXPECT_TRUE(urls.empty()); } } // namespace sync_file_system |