This source file includes following definitions.
- num_shared_with_me_entries_
- IncrementNumFiles
- IncrementNumSharedWithMeEntries
- UpdateFileCountUmaHistograms
- ShouldApplyChange
- ToString
- Apply
- ApplyEntryMap
- ApplyEntry
- RefreshDirectory
- SetParentLocalIdOfEntry
- UpdateChangedDirs
#include "chrome/browser/chromeos/drive/change_list_processor.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/chromeos/drive/drive.pb.h"
#include "chrome/browser/chromeos/drive/file_system_util.h"
#include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
#include "chrome/browser/chromeos/drive/resource_metadata.h"
#include "google_apis/drive/drive_api_parser.h"
#include "google_apis/drive/gdata_wapi_parser.h"
namespace drive {
namespace internal {
namespace {
class ChangeListToEntryMapUMAStats {
public:
ChangeListToEntryMapUMAStats()
: num_regular_files_(0),
num_hosted_documents_(0),
num_shared_with_me_entries_(0) {
}
void IncrementNumFiles(bool is_hosted_document) {
is_hosted_document ? num_hosted_documents_++ : num_regular_files_++;
}
void IncrementNumSharedWithMeEntries() {
num_shared_with_me_entries_++;
}
void UpdateFileCountUmaHistograms() {
const int num_total_files = num_hosted_documents_ + num_regular_files_;
UMA_HISTOGRAM_COUNTS("Drive.NumberOfRegularFiles", num_regular_files_);
UMA_HISTOGRAM_COUNTS("Drive.NumberOfHostedDocuments",
num_hosted_documents_);
UMA_HISTOGRAM_COUNTS("Drive.NumberOfTotalFiles", num_total_files);
UMA_HISTOGRAM_COUNTS("Drive.NumberOfSharedWithMeEntries",
num_shared_with_me_entries_);
}
private:
int num_regular_files_;
int num_hosted_documents_;
int num_shared_with_me_entries_;
};
bool ShouldApplyChange(const ResourceEntry& local_entry,
const ResourceEntry& remote_entry,
const base::Time& modification_date) {
base::Time creation_time =
base::Time::FromInternalValue(remote_entry.file_info().creation_time());
const bool entry_is_new = creation_time == modification_date;
return !entry_is_new;
}
}
std::string DirectoryFetchInfo::ToString() const {
return ("local_id: " + local_id_ +
", resource_id: " + resource_id_ +
", changestamp: " + base::Int64ToString(changestamp_));
}
ChangeList::ChangeList() {}
ChangeList::ChangeList(const google_apis::ResourceList& resource_list)
: largest_changestamp_(resource_list.largest_changestamp()) {
resource_list.GetNextFeedURL(&next_url_);
entries_.resize(resource_list.entries().size());
parent_resource_ids_.resize(resource_list.entries().size());
modification_dates_.resize(resource_list.entries().size());
size_t entries_index = 0;
for (size_t i = 0; i < resource_list.entries().size(); ++i) {
if (ConvertToResourceEntry(*resource_list.entries()[i],
&entries_[entries_index],
&parent_resource_ids_[entries_index])) {
modification_dates_[entries_index] =
resource_list.entries()[i]->modification_date();
++entries_index;
}
}
entries_.resize(entries_index);
parent_resource_ids_.resize(entries_index);
modification_dates_.resize(entries_index);
}
ChangeList::~ChangeList() {}
ChangeListProcessor::ChangeListProcessor(ResourceMetadata* resource_metadata)
: resource_metadata_(resource_metadata) {
}
ChangeListProcessor::~ChangeListProcessor() {
}
FileError ChangeListProcessor::Apply(
scoped_ptr<google_apis::AboutResource> about_resource,
ScopedVector<ChangeList> change_lists,
bool is_delta_update) {
DCHECK(about_resource);
int64 largest_changestamp = 0;
if (is_delta_update) {
if (!change_lists.empty()) {
largest_changestamp = change_lists[0]->largest_changestamp();
DCHECK_GE(change_lists[0]->largest_changestamp(), 0);
}
} else {
largest_changestamp = about_resource->largest_change_id();
DVLOG(1) << "Root folder ID is " << about_resource->root_folder_id();
DCHECK(!about_resource->root_folder_id().empty());
}
ChangeListToEntryMapUMAStats uma_stats;
for (size_t i = 0; i < change_lists.size(); ++i) {
ChangeList* change_list = change_lists[i];
std::vector<ResourceEntry>* entries = change_list->mutable_entries();
for (size_t i = 0; i < entries->size(); ++i) {
ResourceEntry* entry = &(*entries)[i];
if (!entry->file_info().is_directory()) {
uma_stats.IncrementNumFiles(
entry->file_specific_info().is_hosted_document());
if (entry->shared_with_me())
uma_stats.IncrementNumSharedWithMeEntries();
}
modification_date_map_[entry->resource_id()] =
change_list->modification_dates()[i];
parent_resource_id_map_[entry->resource_id()] =
change_list->parent_resource_ids()[i];
entry_map_[entry->resource_id()].Swap(entry);
LOG_IF(WARNING, !entry->resource_id().empty())
<< "Found duplicated file: " << entry->base_name();
}
}
for (ResourceEntryMap::iterator it = entry_map_.begin();
it != entry_map_.end(); ++it) {
if (it->second.file_info().is_directory()) {
it->second.mutable_directory_specific_info()->set_changestamp(
largest_changestamp);
}
}
FileError error = ApplyEntryMap(largest_changestamp, about_resource.Pass());
if (error != FILE_ERROR_OK) {
DLOG(ERROR) << "ApplyEntryMap failed: " << FileErrorToString(error);
return error;
}
error = resource_metadata_->SetLargestChangestamp(largest_changestamp);
if (error != FILE_ERROR_OK) {
DLOG(ERROR) << "SetLargestChangeStamp failed: " << FileErrorToString(error);
return error;
}
if (!is_delta_update)
uma_stats.UpdateFileCountUmaHistograms();
return FILE_ERROR_OK;
}
FileError ChangeListProcessor::ApplyEntryMap(
int64 changestamp,
scoped_ptr<google_apis::AboutResource> about_resource) {
DCHECK(about_resource);
ResourceEntry root;
FileError error = resource_metadata_->GetResourceEntryByPath(
util::GetDriveMyDriveRootPath(), &root);
if (error != FILE_ERROR_OK) {
LOG(ERROR) << "Failed to get root entry: " << FileErrorToString(error);
return error;
}
root.mutable_directory_specific_info()->set_changestamp(changestamp);
root.set_resource_id(about_resource->root_folder_id());
error = resource_metadata_->RefreshEntry(root);
if (error != FILE_ERROR_OK) {
LOG(ERROR) << "Failed to update root entry: " << FileErrorToString(error);
return error;
}
for (ResourceEntryMap::iterator it = entry_map_.begin();
it != entry_map_.end(); ++it) {
UpdateChangedDirs(it->second);
}
std::vector<std::string> deleted_resource_ids;
while (!entry_map_.empty()) {
ResourceEntryMap::iterator it = entry_map_.begin();
if (it->second.deleted()) {
deleted_resource_ids.push_back(it->first);
entry_map_.erase(it);
continue;
}
std::vector<ResourceEntryMap::iterator> entries;
for (ResourceEntryMap::iterator it = entry_map_.begin();
it != entry_map_.end();) {
entries.push_back(it);
DCHECK(parent_resource_id_map_.count(it->first)) << it->first;
const std::string& parent_resource_id =
parent_resource_id_map_[it->first];
if (parent_resource_id.empty())
break;
ResourceEntryMap::iterator it_parent =
entry_map_.find(parent_resource_id);
if (it_parent == entry_map_.end()) {
std::string parent_local_id;
FileError error = resource_metadata_->GetIdByResourceId(
parent_resource_id, &parent_local_id);
if (error != FILE_ERROR_OK) {
if (error == FILE_ERROR_NOT_FOUND) {
parent_resource_id_map_[it->first] = "";
} else {
LOG(ERROR) << "Failed to get local ID: " << parent_resource_id
<< ", error = " << FileErrorToString(error);
}
break;
}
ResourceEntry parent_entry;
while (it_parent == entry_map_.end() && !parent_local_id.empty()) {
error = resource_metadata_->GetResourceEntryById(
parent_local_id, &parent_entry);
if (error != FILE_ERROR_OK) {
LOG(ERROR) << "Failed to get local entry: "
<< FileErrorToString(error);
break;
}
it_parent = entry_map_.find(parent_entry.resource_id());
parent_local_id = parent_entry.parent_local_id();
}
}
it = it_parent;
}
std::reverse(entries.begin(), entries.end());
for (size_t i = 0; i < entries.size(); ++i) {
ResourceEntryMap::iterator it = entries[i];
if (it->first != root.resource_id()) {
FileError error = ApplyEntry(it->second);
DLOG_IF(WARNING, error != FILE_ERROR_OK)
<< "ApplyEntry failed: " << FileErrorToString(error)
<< ", title = " << it->second.title();
}
entry_map_.erase(it);
}
}
for (size_t i = 0; i < deleted_resource_ids.size(); ++i) {
std::string local_id;
FileError error = resource_metadata_->GetIdByResourceId(
deleted_resource_ids[i], &local_id);
if (error == FILE_ERROR_OK)
error = resource_metadata_->RemoveEntry(local_id);
DLOG_IF(WARNING, error != FILE_ERROR_OK && error != FILE_ERROR_NOT_FOUND)
<< "Failed to delete: " << FileErrorToString(error)
<< ", resource_id = " << deleted_resource_ids[i];
}
return FILE_ERROR_OK;
}
FileError ChangeListProcessor::ApplyEntry(const ResourceEntry& entry) {
DCHECK(!entry.deleted());
DCHECK(parent_resource_id_map_.count(entry.resource_id()));
DCHECK(modification_date_map_.count(entry.resource_id()));
const std::string& parent_resource_id =
parent_resource_id_map_[entry.resource_id()];
const base::Time& modification_date =
modification_date_map_[entry.resource_id()];
ResourceEntry new_entry(entry);
FileError error = SetParentLocalIdOfEntry(resource_metadata_, &new_entry,
parent_resource_id);
if (error != FILE_ERROR_OK)
return error;
std::string local_id;
error = resource_metadata_->GetIdByResourceId(entry.resource_id(), &local_id);
ResourceEntry existing_entry;
if (error == FILE_ERROR_OK)
error = resource_metadata_->GetResourceEntryById(local_id, &existing_entry);
switch (error) {
case FILE_ERROR_OK:
if (ShouldApplyChange(existing_entry, new_entry, modification_date)) {
new_entry.set_local_id(local_id);
error = resource_metadata_->RefreshEntry(new_entry);
} else {
if (entry.file_info().is_directory()) {
new_entry = existing_entry;
new_entry.mutable_directory_specific_info()->set_changestamp(
new_entry.directory_specific_info().changestamp());
error = resource_metadata_->RefreshEntry(new_entry);
}
DVLOG(1) << "Change was discarded for: "
<< resource_metadata_->GetFilePath(local_id).value();
}
break;
case FILE_ERROR_NOT_FOUND: {
std::string local_id;
error = resource_metadata_->AddEntry(new_entry, &local_id);
break;
}
default:
return error;
}
if (error != FILE_ERROR_OK)
return error;
UpdateChangedDirs(entry);
return FILE_ERROR_OK;
}
FileError ChangeListProcessor::RefreshDirectory(
ResourceMetadata* resource_metadata,
const DirectoryFetchInfo& directory_fetch_info,
scoped_ptr<ChangeList> change_list,
std::vector<ResourceEntry>* out_refreshed_entries) {
DCHECK(!directory_fetch_info.empty());
ResourceEntry directory;
FileError error = resource_metadata->GetResourceEntryById(
directory_fetch_info.local_id(), &directory);
if (error != FILE_ERROR_OK)
return error;
if (!directory.file_info().is_directory())
return FILE_ERROR_NOT_A_DIRECTORY;
std::vector<ResourceEntry>* entries = change_list->mutable_entries();
for (size_t i = 0; i < entries->size(); ++i) {
ResourceEntry* entry = &(*entries)[i];
const std::string& parent_resource_id =
change_list->parent_resource_ids()[i];
if (parent_resource_id != directory_fetch_info.resource_id()) {
DVLOG(1) << "Wrong-parent entry rejected: " << entry->resource_id();
continue;
}
entry->set_parent_local_id(directory_fetch_info.local_id());
std::string local_id;
error = resource_metadata->GetIdByResourceId(entry->resource_id(),
&local_id);
if (error == FILE_ERROR_OK) {
entry->set_local_id(local_id);
error = resource_metadata->RefreshEntry(*entry);
}
if (error == FILE_ERROR_NOT_FOUND) {
entry->clear_local_id();
error = resource_metadata->AddEntry(*entry, &local_id);
}
if (error != FILE_ERROR_OK)
return error;
ResourceEntry result_entry;
error = resource_metadata->GetResourceEntryById(local_id, &result_entry);
if (error != FILE_ERROR_OK)
return error;
out_refreshed_entries->push_back(result_entry);
}
return FILE_ERROR_OK;
}
FileError ChangeListProcessor::SetParentLocalIdOfEntry(
ResourceMetadata* resource_metadata,
ResourceEntry* entry,
const std::string& parent_resource_id) {
std::string parent_local_id;
if (parent_resource_id.empty()) {
parent_local_id = util::kDriveOtherDirLocalId;
} else {
FileError error = resource_metadata->GetIdByResourceId(
parent_resource_id, &parent_local_id);
if (error != FILE_ERROR_OK)
return error;
}
entry->set_parent_local_id(parent_local_id);
return FILE_ERROR_OK;
}
void ChangeListProcessor::UpdateChangedDirs(const ResourceEntry& entry) {
DCHECK(!entry.resource_id().empty());
std::string local_id;
base::FilePath file_path;
if (resource_metadata_->GetIdByResourceId(
entry.resource_id(), &local_id) == FILE_ERROR_OK)
file_path = resource_metadata_->GetFilePath(local_id);
if (!file_path.empty()) {
changed_dirs_.insert(file_path.DirName());
if (entry.file_info().is_directory()) {
changed_dirs_.insert(file_path);
if (entry.deleted()) {
std::set<base::FilePath> sub_directories;
resource_metadata_->GetSubDirectoriesRecursively(local_id,
&sub_directories);
changed_dirs_.insert(sub_directories.begin(), sub_directories.end());
}
}
}
}
}
}