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

Unified Diff: chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.cc

Issue 10829118: gdata: Move GDataWapiFeedParser to a set of new files (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix clang build for sure... Created 8 years, 5 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
« no previous file with comments | « chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.cc
diff --git a/chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.cc b/chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b349f937ff6107a789c5bd38e56da73904765de5
--- /dev/null
+++ b/chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.cc
@@ -0,0 +1,331 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/histogram.h"
+#include "chrome/browser/chromeos/gdata/gdata_files.h"
+#include "chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.h"
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+namespace gdata {
+
+namespace {
+
+// Recursively extracts the paths set of all sub-directories of |entry|.
+void GetChildDirectoryPaths(GDataEntry* entry,
+ std::set<FilePath>* changed_dirs) {
+ GDataDirectory* dir = entry->AsGDataDirectory();
+ if (!dir)
+ return;
+
+ for (GDataDirectoryCollection::const_iterator it =
+ dir->child_directories().begin();
+ it != dir->child_directories().end(); ++it) {
+ GDataDirectory* child_dir = it->second;
+ changed_dirs->insert(child_dir->GetFilePath());
+ GetChildDirectoryPaths(child_dir, changed_dirs);
+ }
+}
+
+} // namespace
+
+FeedToFileResourceMapUmaStats::FeedToFileResourceMapUmaStats()
+ : num_regular_files(0),
+ num_hosted_documents(0) {
+}
+
+FeedToFileResourceMapUmaStats::~FeedToFileResourceMapUmaStats() {
+}
+
+GDataWapiFeedProcessor::GDataWapiFeedProcessor(
+ GDataDirectoryService* directory_service)
+ : directory_service_(directory_service) {
+}
+
+GDataWapiFeedProcessor::~GDataWapiFeedProcessor() {
+}
+
+GDataFileError GDataWapiFeedProcessor::ApplyFeeds(
+ const std::vector<DocumentFeed*>& feed_list,
+ int start_changestamp,
+ int root_feed_changestamp,
+ std::set<FilePath>* changed_dirs) {
+ bool is_delta_feed = start_changestamp != 0;
+
+ directory_service_->set_origin(FROM_SERVER);
+
+ int delta_feed_changestamp = 0;
+ FeedToFileResourceMapUmaStats uma_stats;
+ FileResourceIdMap file_map;
+ GDataFileError error = FeedToFileResourceMap(feed_list,
+ &file_map,
+ &delta_feed_changestamp,
+ &uma_stats);
+ if (error != GDATA_FILE_OK)
+ return error;
+
+ ApplyFeedFromFileUrlMap(
+ is_delta_feed,
+ is_delta_feed ? delta_feed_changestamp : root_feed_changestamp,
+ &file_map,
+ changed_dirs);
+
+ // Shouldn't record histograms when processing delta feeds.
+ if (!is_delta_feed)
+ UpdateFileCountUmaHistograms(uma_stats);
+
+ return GDATA_FILE_OK;
+}
+
+void GDataWapiFeedProcessor::UpdateFileCountUmaHistograms(
+ const FeedToFileResourceMapUmaStats& uma_stats) const {
+ const int num_total_files =
+ uma_stats.num_hosted_documents + uma_stats.num_regular_files;
+ UMA_HISTOGRAM_COUNTS("GData.NumberOfRegularFiles",
+ uma_stats.num_regular_files);
+ UMA_HISTOGRAM_COUNTS("GData.NumberOfHostedDocuments",
+ uma_stats.num_hosted_documents);
+ UMA_HISTOGRAM_COUNTS("GData.NumberOfTotalFiles", num_total_files);
+ const std::vector<int> all_entry_kinds = DocumentEntry::GetAllEntryKinds();
+ for (FeedToFileResourceMapUmaStats::EntryKindToCountMap::const_iterator iter =
+ uma_stats.num_files_with_entry_kind.begin();
+ iter != uma_stats.num_files_with_entry_kind.end();
+ ++iter) {
+ const DocumentEntry::EntryKind kind = iter->first;
+ const int count = iter->second;
+ for (int i = 0; i < count; ++i) {
+ UMA_HISTOGRAM_CUSTOM_ENUMERATION(
+ "GData.EntryKind", kind, all_entry_kinds);
+ }
+ }
+}
+
+void GDataWapiFeedProcessor::ApplyFeedFromFileUrlMap(
+ bool is_delta_feed,
+ int feed_changestamp,
+ FileResourceIdMap* file_map,
+ std::set<FilePath>* changed_dirs) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(changed_dirs);
+
+ if (!is_delta_feed) { // Full update.
+ directory_service_->root()->RemoveChildren();
+ changed_dirs->insert(directory_service_->root()->GetFilePath());
+ }
+ directory_service_->set_largest_changestamp(feed_changestamp);
+
+ scoped_ptr<GDataDirectoryService> orphaned_dir_service(
+ new GDataDirectoryService);
+ // Go through all entries generated by the feed and apply them to the local
+ // snapshot of the file system.
+ for (FileResourceIdMap::iterator it = file_map->begin();
+ it != file_map->end();) {
+ // Ensure that the entry is deleted, unless the ownership is explicitly
+ // transferred by entry.release().
+ scoped_ptr<GDataEntry> entry(it->second);
+ DCHECK_EQ(it->first, entry->resource_id());
+ // Erase the entry so the deleted entry won't be referenced.
+ file_map->erase(it++);
+
+ GDataEntry* old_entry =
+ directory_service_->GetEntryByResourceId(entry->resource_id());
+ GDataDirectory* dest_dir = NULL;
+ if (entry->is_deleted()) { // Deleted file/directory.
+ DVLOG(1) << "Removing file " << entry->base_name();
+ if (!old_entry)
+ continue;
+
+ dest_dir = old_entry->parent();
+ if (!dest_dir) {
+ NOTREACHED();
+ continue;
+ }
+ RemoveEntryFromDirectoryAndCollectChangedDirectories(
+ dest_dir, old_entry, changed_dirs);
+ } else if (old_entry) { // Change or move of existing entry.
+ // Please note that entry rename is just a special case of change here
+ // since name is just one of the properties that can change.
+ DVLOG(1) << "Changed file " << entry->base_name();
+ dest_dir = old_entry->parent();
+ if (!dest_dir) {
+ NOTREACHED();
+ continue;
+ }
+ // Move children files over if we are dealing with directories.
+ if (old_entry->AsGDataDirectory() && entry->AsGDataDirectory()) {
+ entry->AsGDataDirectory()->TakeOverEntries(
+ old_entry->AsGDataDirectory());
+ }
+ // Remove the old instance of this entry.
+ RemoveEntryFromDirectoryAndCollectChangedDirectories(
+ dest_dir, old_entry, changed_dirs);
+ // Did we actually move the new file to another directory?
+ if (dest_dir->resource_id() != entry->parent_resource_id()) {
+ changed_dirs->insert(dest_dir->GetFilePath());
+ dest_dir = FindDirectoryForNewEntry(entry.get(),
+ *file_map,
+ orphaned_dir_service.get());
+ }
+ DCHECK(dest_dir);
+ AddEntryToDirectoryAndCollectChangedDirectories(
+ entry.release(),
+ dest_dir,
+ orphaned_dir_service.get(),
+ changed_dirs);
+ } else { // Adding a new file.
+ dest_dir = FindDirectoryForNewEntry(entry.get(),
+ *file_map,
+ orphaned_dir_service.get());
+ DCHECK(dest_dir);
+ AddEntryToDirectoryAndCollectChangedDirectories(
+ entry.release(),
+ dest_dir,
+ orphaned_dir_service.get(),
+ changed_dirs);
+ }
+
+ // Record changed directory if this was a delta feed and the parent
+ // directory is already properly rooted within its parent.
+ if (dest_dir && (dest_dir->parent() ||
+ dest_dir == directory_service_->root()) &&
+ dest_dir != orphaned_dir_service->root() && is_delta_feed) {
+ changed_dirs->insert(dest_dir->GetFilePath());
+ }
+ }
+ // All entry must be erased from the map.
+ DCHECK(file_map->empty());
+}
+
+// static
+void GDataWapiFeedProcessor::AddEntryToDirectoryAndCollectChangedDirectories(
+ GDataEntry* entry,
+ GDataDirectory* directory,
+ GDataDirectoryService* orphaned_dir_service,
+ std::set<FilePath>* changed_dirs) {
+ directory->AddEntry(entry);
+ if (entry->AsGDataDirectory() && directory != orphaned_dir_service->root())
+ changed_dirs->insert(entry->GetFilePath());
+}
+
+// static
+void GDataWapiFeedProcessor::
+RemoveEntryFromDirectoryAndCollectChangedDirectories(
+ GDataDirectory* directory,
+ GDataEntry* entry,
+ std::set<FilePath>* changed_dirs) {
+ // Get the list of all sub-directory paths, so we can notify their listeners
+ // that they are smoked.
+ GetChildDirectoryPaths(entry, changed_dirs);
+ directory->RemoveEntry(entry);
+}
+
+GDataDirectory* GDataWapiFeedProcessor::FindDirectoryForNewEntry(
+ GDataEntry* new_entry,
+ const FileResourceIdMap& file_map,
+ GDataDirectoryService* orphaned_dir_service) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ GDataDirectory* dir = NULL;
+ // Added file.
+ const std::string& parent_id = new_entry->parent_resource_id();
+ if (parent_id.empty()) {
+ dir = directory_service_->root();
+ DVLOG(1) << "Root parent for " << new_entry->base_name();
+ } else {
+ GDataEntry* entry = directory_service_->GetEntryByResourceId(parent_id);
+ dir = entry ? entry->AsGDataDirectory() : NULL;
+ if (!dir) {
+ // The parent directory was also added with this set of feeds.
+ FileResourceIdMap::const_iterator find_iter =
+ file_map.find(parent_id);
+ dir = (find_iter != file_map.end() &&
+ find_iter->second) ?
+ find_iter->second->AsGDataDirectory() : NULL;
+ if (dir) {
+ DVLOG(1) << "Found parent for " << new_entry->base_name()
+ << " in file_map " << parent_id;
+ } else {
+ DVLOG(1) << "Adding orphan " << new_entry->GetFilePath().value();
+ dir = orphaned_dir_service->root();
+ }
+ }
+ }
+ return dir;
+}
+
+GDataFileError GDataWapiFeedProcessor::FeedToFileResourceMap(
+ const std::vector<DocumentFeed*>& feed_list,
+ FileResourceIdMap* file_map,
+ int* feed_changestamp,
+ FeedToFileResourceMapUmaStats* uma_stats) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(uma_stats);
+
+ GDataFileError error = GDATA_FILE_OK;
+ uma_stats->num_regular_files = 0;
+ uma_stats->num_hosted_documents = 0;
+ uma_stats->num_files_with_entry_kind.clear();
+ for (size_t i = 0; i < feed_list.size(); ++i) {
+ const DocumentFeed* feed = feed_list[i];
+
+ // Get upload url from the root feed. Links for all other collections will
+ // be handled in GDatadirectory::FromDocumentEntry();
+ if (i == 0) {
+ const Link* root_feed_upload_link =
+ feed->GetLinkByType(Link::RESUMABLE_CREATE_MEDIA);
+ if (root_feed_upload_link)
+ directory_service_->root()->set_upload_url(
+ root_feed_upload_link->href());
+ *feed_changestamp = feed->largest_changestamp();
+ DCHECK_GE(*feed_changestamp, 0);
+ }
+
+ for (ScopedVector<DocumentEntry>::const_iterator iter =
+ feed->entries().begin();
+ iter != feed->entries().end(); ++iter) {
+ DocumentEntry* doc = *iter;
+ GDataEntry* entry = GDataEntry::FromDocumentEntry(
+ NULL, doc, directory_service_);
+ // Some document entries don't map into files (i.e. sites).
+ if (!entry)
+ continue;
+ // Count the number of files.
+ GDataFile* as_file = entry->AsGDataFile();
+ if (as_file) {
+ if (as_file->is_hosted_document())
+ ++uma_stats->num_hosted_documents;
+ else
+ ++uma_stats->num_regular_files;
+ ++uma_stats->num_files_with_entry_kind[as_file->kind()];
+ }
+
+ FileResourceIdMap::iterator map_entry =
+ file_map->find(entry->resource_id());
+
+ // An entry with the same self link may already exist, so we need to
+ // release the existing GDataEntry instance before overwriting the
+ // entry with another GDataEntry instance.
+ if (map_entry != file_map->end()) {
+ LOG(WARNING) << "Found duplicate file "
+ << map_entry->second->base_name();
+
+ delete map_entry->second;
+ file_map->erase(map_entry);
+ }
+ file_map->insert(
+ std::pair<std::string, GDataEntry*>(entry->resource_id(), entry));
+ }
+ }
+
+ if (error != GDATA_FILE_OK) {
+ // If the code above fails to parse a feed, any GDataEntry instance
+ // added to |file_by_url| is not managed by a GDataDirectory instance,
+ // so we need to explicitly release them here.
+ STLDeleteValues(file_map);
+ }
+
+ return error;
+}
+
+} // namespace gdata
« no previous file with comments | « chrome/browser/chromeos/gdata/gdata_wapi_feed_processor.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698