diff options
author | mukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-02 17:16:34 +0000 |
---|---|---|
committer | mukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-02 17:16:34 +0000 |
commit | d4c7bdc5e8864e1383d05ad3c4bf9ec9aaf9b0d4 (patch) | |
tree | 9aadd5805cf59a3c07d72af5685470a558c1e349 | |
parent | bf4adf79297bc1d3c55bfa0d72b9c082e724c7a2 (diff) | |
download | chromium_src-d4c7bdc5e8864e1383d05ad3c4bf9ec9aaf9b0d4.zip chromium_src-d4c7bdc5e8864e1383d05ad3c4bf9ec9aaf9b0d4.tar.gz chromium_src-d4c7bdc5e8864e1383d05ad3c4bf9ec9aaf9b0d4.tar.bz2 |
Prevent duplicated runs of initialization of root directory.
BUG=chromium-os:28761
TEST=manually + unittest passed locally
Review URL: https://chromiumcodereview.appspot.com/9963047
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@130153 0039d316-1c4b-4281-b951-d872f2087c98
5 files changed, 108 insertions, 4 deletions
diff --git a/chrome/browser/chromeos/gdata/gdata_file_system.cc b/chrome/browser/chromeos/gdata/gdata_file_system.cc index ef69992..35cb99e 100644 --- a/chrome/browser/chromeos/gdata/gdata_file_system.cc +++ b/chrome/browser/chromeos/gdata/gdata_file_system.cc @@ -343,6 +343,26 @@ void RunGetCacheStateCallbackHelper( callback.Run(*error, *cache_state); } +// The class to wait for the initial load of root feed and runs the callback +// after the initialization. +class InitialLoadObserver : public GDataFileSystemInterface::Observer { + public: + InitialLoadObserver(GDataFileSystemInterface* file_system, + const base::Closure& callback) + : file_system_(file_system), callback_(callback) {} + + virtual void OnInitialLoadFinished() OVERRIDE { + if (!callback_.is_null()) + base::MessageLoopProxy::current()->PostTask(FROM_HERE, callback_); + file_system_->RemoveObserver(this); + base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, this); + } + + private: + GDataFileSystemInterface* file_system_; + base::Closure callback_; +}; + } // namespace // FindFileDelegate class implementation. @@ -573,9 +593,21 @@ void GDataFileSystem::FindFileByPathAsync( const FilePath& search_file_path, const FindFileCallback& callback) { base::AutoLock lock(lock_); - if (root_->origin() == UNINITIALIZED) { + if (root_->origin() == INITIALIZING) { + // If root feed is not initialized but the initilization process has + // already started, add an observer to execute the remaining task after + // the end of the initialization. + AddObserver(new InitialLoadObserver( + this, + base::Bind(&GDataFileSystem::FindFileByPathOnCallingThread, + GetWeakPtrForCurrentThread(), + search_file_path, + callback))); + return; + } else if (root_->origin() == UNINITIALIZED) { // Load root feed from this disk cache. Upon completion, kick off server // fetching. + root_->set_origin(INITIALIZING); LoadRootFeedFromCache(FEED_CHUNK_INITIAL, search_file_path, true, // should_load_from_server @@ -584,6 +616,7 @@ void GDataFileSystem::FindFileByPathAsync( } else if (root_->NeedsRefresh()) { // If content is stale or from disk from cache, fetch content from // the server. + root_->set_origin(REFRESHING); LoadFeedFromServer(search_file_path, callback); return; } @@ -1778,7 +1811,7 @@ void GDataFileSystem::OnGetDocuments( bool initial_read = false; { base::AutoLock lock(lock_); - initial_read = root_->origin() == UNINITIALIZED; + initial_read = root_->origin() == INITIALIZING; } bool has_more_data = current_feed->GetNextFeedURL(&next_feed_url) && @@ -1912,6 +1945,8 @@ void GDataFileSystem::OnLoadRootFeed( // If the first chunk was ok, get the rest of the feed from disk cache if // we haven't fetched content from the server in the meantime. if (*error == base::PLATFORM_FILE_OK) { + base::AutoLock lock(lock_); + root_->set_origin(REFRESHING); LoadRootFeedFromCache(FEED_CHUNK_REST, search_file_path, false, // should_load_from_server @@ -1921,6 +1956,12 @@ void GDataFileSystem::OnLoadRootFeed( if (!should_load_from_server) return; + { + base::AutoLock lock(lock_); + if (root_->origin() != INITIALIZING) + root_->set_origin(REFRESHING); + } + // Kick of the retreival of the feed from server. If we have previously // |reported| to the original callback, then we just need to refresh the // content without continuing search upon operation completion. @@ -2273,7 +2314,8 @@ base::PlatformFileError GDataFileSystem::UpdateDirectoryWithDocumentFeed( base::AutoLock lock(lock_); // Don't send directory content change notification while performing // the initial content retreival. - bool should_nofify = root_->origin() != UNINITIALIZED; + bool should_notify_directory_changed = root_->origin() != INITIALIZING; + bool should_notify_initial_load = root_->origin() == INITIALIZING; root_->set_origin(origin); root_->set_refresh_time(base::Time::Now()); @@ -2374,8 +2416,10 @@ base::PlatformFileError GDataFileSystem::UpdateDirectoryWithDocumentFeed( dir->AddFile(file.release()); } - if (should_nofify) + if (should_notify_directory_changed) NotifyDirectoryChanged(root_->GetFilePath()); + if (should_notify_initial_load) + NotifyInitialLoadFinished(); return base::PLATFORM_FILE_OK; } @@ -2447,6 +2491,20 @@ void GDataFileSystem::NotifyDirectoryChanged(const FilePath& directory_path) { FOR_EACH_OBSERVER(Observer, observers_, OnDirectoryChanged(directory_path)); } +void GDataFileSystem::NotifyInitialLoadFinished() { + DVLOG(1) << "Initial load finished"; + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&GDataFileSystem::NotifyInitialLoadFinished, ui_weak_ptr_)); + return; + } + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + // Notify the observers that root directory has been initialized. + FOR_EACH_OBSERVER(Observer, observers_, OnInitialLoadFinished()); +} + base::PlatformFileError GDataFileSystem::AddNewDirectory( const FilePath& directory_path, base::Value* entry_value) { if (!entry_value) diff --git a/chrome/browser/chromeos/gdata/gdata_file_system.h b/chrome/browser/chromeos/gdata/gdata_file_system.h index 3c32924..c97c702 100644 --- a/chrome/browser/chromeos/gdata/gdata_file_system.h +++ b/chrome/browser/chromeos/gdata/gdata_file_system.h @@ -162,6 +162,9 @@ class GDataFileSystemInterface { // changed directory. virtual void OnDirectoryChanged(const FilePath& directory_path) {} + // Triggered when the file system is initially loaded. + virtual void OnInitialLoadFinished() {} + protected: virtual ~Observer() {} }; @@ -867,6 +870,7 @@ class GDataFileSystem : public GDataFileSystemInterface { void NotifyFileUnpinned(const std::string& resource_id, const std::string& md5); void NotifyDirectoryChanged(const FilePath& directory_path); + void NotifyInitialLoadFinished(); // Helper function that completes bookkeeping tasks related to // completed file transfer. diff --git a/chrome/browser/chromeos/gdata/gdata_file_system_unittest.cc b/chrome/browser/chromeos/gdata/gdata_file_system_unittest.cc index d0a1229..3d33680 100644 --- a/chrome/browser/chromeos/gdata/gdata_file_system_unittest.cc +++ b/chrome/browser/chromeos/gdata/gdata_file_system_unittest.cc @@ -895,6 +895,40 @@ class MockFindFileDelegate : public gdata::FindFileDelegate { GDataFileBase*)); }; +void AsyncInitializationCallback(int* counter, + int expected_counter, + const FilePath& expected_file_path, + MessageLoop* message_loop, + base::PlatformFileError error, + const FilePath& directory_path, + GDataFileBase* file) { + LOG(INFO) << "here"; + ASSERT_EQ(base::PLATFORM_FILE_OK, error); + EXPECT_EQ(expected_file_path, directory_path); + EXPECT_FALSE(file == NULL); + + (*counter)++; + if (*counter >= expected_counter) + message_loop->Quit(); +} + +TEST_F(GDataFileSystemTest, DuplicatedAsyncInitialization) { + int counter = 0; + FindFileCallback callback = base::Bind( + &AsyncInitializationCallback, + &counter, + 2, + FilePath(FILE_PATH_LITERAL("gdata")), + &message_loop_); + + file_system_->FindFileByPathAsync( + FilePath(FILE_PATH_LITERAL("gdata")), callback); + file_system_->FindFileByPathAsync( + FilePath(FILE_PATH_LITERAL("gdata")), callback); + message_loop_.Run(); // Wait to get our result + EXPECT_EQ(2, counter); +} + TEST_F(GDataFileSystemTest, SearchRootDirectory) { MockFindFileDelegate mock_find_file_delegate; EXPECT_CALL(mock_find_file_delegate, diff --git a/chrome/browser/chromeos/gdata/gdata_files.cc b/chrome/browser/chromeos/gdata/gdata_files.cc index b416128a..2b80b5c 100644 --- a/chrome/browser/chromeos/gdata/gdata_files.cc +++ b/chrome/browser/chromeos/gdata/gdata_files.cc @@ -249,6 +249,10 @@ void GDataDirectory::RemoveChildren() { } bool GDataDirectory::NeedsRefresh() const { + // Already refreshing by someone else. + if (origin_ == REFRESHING) + return false; + // Refresh is needed for content read from disk cache or stale content. if (origin_ == FROM_CACHE) return true; diff --git a/chrome/browser/chromeos/gdata/gdata_files.h b/chrome/browser/chromeos/gdata/gdata_files.h index f37e8eb..5a5329b 100644 --- a/chrome/browser/chromeos/gdata/gdata_files.h +++ b/chrome/browser/chromeos/gdata/gdata_files.h @@ -36,6 +36,10 @@ typedef base::Callback<void(base::PlatformFileError error, // Directory content origin. enum ContentOrigin { UNINITIALIZED, + // Directory content is currently loading from somewhere. needs to wait. + INITIALIZING, + // Directory content is initialized, but during refreshing. + REFRESHING, // Directory content is initialized from disk cache. FROM_CACHE, // Directory content is initialized from the direct server response. |