| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <utility> | 5 #include <utility> |
| 6 | 6 |
| 7 #include "base/metrics/histogram.h" | 7 #include "base/metrics/histogram.h" |
| 8 #include "chrome/browser/chromeos/drive/document_entry_conversion.h" | 8 #include "chrome/browser/chromeos/drive/document_entry_conversion.h" |
| 9 #include "chrome/browser/chromeos/drive/drive_feed_processor.h" | 9 #include "chrome/browser/chromeos/drive/drive_feed_processor.h" |
| 10 #include "chrome/browser/chromeos/drive/drive_files.h" | 10 #include "chrome/browser/chromeos/drive/drive_files.h" |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 // Go through all entries generated by the feed and apply them to the local | 94 // Go through all entries generated by the feed and apply them to the local |
| 95 // snapshot of the file system. | 95 // snapshot of the file system. |
| 96 ApplyNextEntryProtoAsync(); | 96 ApplyNextEntryProtoAsync(); |
| 97 } | 97 } |
| 98 | 98 |
| 99 void DriveFeedProcessor::ApplyNextEntryProtoAsync() { | 99 void DriveFeedProcessor::ApplyNextEntryProtoAsync() { |
| 100 base::MessageLoopProxy::current()->PostTask( | 100 base::MessageLoopProxy::current()->PostTask( |
| 101 FROM_HERE, | 101 FROM_HERE, |
| 102 base::Bind(&DriveFeedProcessor::ApplyNextEntryProto, | 102 base::Bind(&DriveFeedProcessor::ApplyNextEntryProto, |
| 103 weak_ptr_factory_.GetWeakPtr())); | 103 weak_ptr_factory_.GetWeakPtr())); |
| 104 | |
| 105 } | 104 } |
| 106 | 105 |
| 107 void DriveFeedProcessor::ApplyNextEntryProto() { | 106 void DriveFeedProcessor::ApplyNextEntryProto() { |
| 108 DCHECK(!on_complete_callback_.is_null()); | 107 DCHECK(!on_complete_callback_.is_null()); |
| 109 | 108 |
| 110 if (entry_proto_map_.empty()) { | 109 if (entry_proto_map_.empty()) { |
| 111 // All entries have been processed. | 110 // All entries have been processed. |
| 112 on_complete_callback_.Run(); | 111 on_complete_callback_.Run(); |
| 113 return; | 112 return; |
| 114 } | 113 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 132 weak_ptr_factory_.GetWeakPtr(), | 131 weak_ptr_factory_.GetWeakPtr(), |
| 133 parent_it)); | 132 parent_it)); |
| 134 } else { | 133 } else { |
| 135 // Erase the entry so the deleted entry won't be referenced. | 134 // Erase the entry so the deleted entry won't be referenced. |
| 136 entry_proto_map_.erase(it); | 135 entry_proto_map_.erase(it); |
| 137 ApplyEntryProto(entry_proto); | 136 ApplyEntryProto(entry_proto); |
| 138 } | 137 } |
| 139 } | 138 } |
| 140 | 139 |
| 141 void DriveFeedProcessor::ApplyEntryProto(const DriveEntryProto& entry_proto) { | 140 void DriveFeedProcessor::ApplyEntryProto(const DriveEntryProto& entry_proto) { |
| 142 scoped_ptr<DriveEntry> entry = | 141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 143 resource_metadata_->CreateDriveEntryFromProto(entry_proto); | |
| 144 DCHECK(entry.get()); | |
| 145 DriveEntry* old_entry = | |
| 146 resource_metadata_->GetEntryByResourceId(entry->resource_id()); | |
| 147 | 142 |
| 148 if (entry->is_deleted()) { | 143 // Lookup the entry. |
| 149 // Deleted file/directory. | 144 resource_metadata_->GetEntryInfoByResourceId( |
| 150 DVLOG(1) << "Removing file " << entry->base_name(); | 145 entry_proto.resource_id(), |
| 151 if (old_entry) | 146 base::Bind(&DriveFeedProcessor::ContinueApplyEntryProto, |
| 152 RemoveEntryFromParent(old_entry); | 147 weak_ptr_factory_.GetWeakPtr(), |
| 153 } else if (old_entry) { | 148 entry_proto)); |
| 154 // Change or move of existing entry. | 149 } |
| 155 // Please note that entry rename is just a special case of change here | |
| 156 // since name is just one of the properties that can change. | |
| 157 DVLOG(1) << "Changed file " << entry->base_name(); | |
| 158 | 150 |
| 159 // Move children files over if we are dealing with directories. | 151 void DriveFeedProcessor::ContinueApplyEntryProto( |
| 160 if (old_entry->AsDriveDirectory() && entry->AsDriveDirectory()) { | 152 const DriveEntryProto& entry_proto, |
| 161 entry->AsDriveDirectory()->TakeOverEntries( | 153 DriveFileError error, |
| 162 old_entry->AsDriveDirectory()); | 154 const FilePath& file_path, |
| 155 scoped_ptr<DriveEntryProto> old_entry_proto) { |
| 156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 157 |
| 158 if (error == DRIVE_FILE_OK) { |
| 159 if (entry_proto.deleted()) { |
| 160 // Deleted file/directory. |
| 161 RemoveEntryFromParent(entry_proto, file_path); |
| 162 } else { |
| 163 // Entry exists and needs to be refreshed. |
| 164 RefreshEntryProto(entry_proto, file_path); |
| 163 } | 165 } |
| 166 } else if (error == DRIVE_FILE_ERROR_NOT_FOUND && !entry_proto.deleted()) { |
| 167 // Adding a new entry. |
| 168 AddEntryToParent(entry_proto); |
| 169 } else { |
| 170 // Continue. |
| 171 ApplyNextEntryProtoAsync(); |
| 172 } |
| 173 } |
| 164 | 174 |
| 165 // Remove the old instance of this entry. | 175 void DriveFeedProcessor::RefreshEntryProto(const DriveEntryProto& entry_proto, |
| 166 RemoveEntryFromParent(old_entry); | 176 const FilePath& file_path) { |
| 177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 167 | 178 |
| 168 // Add to parent. | 179 resource_metadata_->RefreshEntryProto( |
| 169 AddEntryToParent(entry.release()); | 180 entry_proto, |
| 170 } else { | 181 base::Bind(&DriveFeedProcessor::NotifyForRefreshEntryProto, |
| 171 // Adding a new file. | 182 weak_ptr_factory_.GetWeakPtr(), |
| 172 AddEntryToParent(entry.release()); | 183 file_path)); |
| 184 } |
| 185 |
| 186 void DriveFeedProcessor::NotifyForRefreshEntryProto( |
| 187 const FilePath& old_file_path, |
| 188 DriveFileError error, |
| 189 const FilePath& file_path, |
| 190 scoped_ptr<DriveEntryProto> entry_proto) { |
| 191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 192 |
| 193 DVLOG(1) << "NotifyForRefreshEntryProto " << file_path.value(); |
| 194 if (error == DRIVE_FILE_OK) { |
| 195 // Notify old parent. |
| 196 changed_dirs_.insert(old_file_path.DirName()); |
| 197 |
| 198 // Notify new parent. |
| 199 changed_dirs_.insert(file_path.DirName()); |
| 200 |
| 201 // Notify self if entry is a directory. |
| 202 if (entry_proto->file_info().is_directory()) { |
| 203 // Notify new self. |
| 204 changed_dirs_.insert(file_path); |
| 205 // Notify old self. |
| 206 changed_dirs_.insert(old_file_path); |
| 207 } |
| 173 } | 208 } |
| 174 | 209 |
| 175 // Process the next DriveEntryProto from the map. | |
| 176 ApplyNextEntryProtoAsync(); | 210 ApplyNextEntryProtoAsync(); |
| 177 } | 211 } |
| 178 | 212 |
| 179 void DriveFeedProcessor::AddEntryToParent( | 213 void DriveFeedProcessor::AddEntryToParent(const DriveEntryProto& entry_proto) { |
| 180 DriveEntry* entry) { | 214 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 215 |
| 216 resource_metadata_->AddEntryToParent(entry_proto, |
| 217 base::Bind(&DriveFeedProcessor::NotifyForAddEntryToParent, |
| 218 weak_ptr_factory_.GetWeakPtr(), |
| 219 entry_proto.file_info().is_directory())); |
| 220 } |
| 221 |
| 222 void DriveFeedProcessor::NotifyForAddEntryToParent(bool is_directory, |
| 223 DriveFileError error, |
| 224 const FilePath& file_path) { |
| 225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 226 |
| 227 DVLOG(1) << "NotifyForAddEntryToParent " << file_path.value(); |
| 228 if (error == DRIVE_FILE_OK) { |
| 229 // Notify if a directory has been created. |
| 230 if (is_directory) |
| 231 changed_dirs_.insert(file_path); |
| 232 |
| 233 // Notify parent. |
| 234 changed_dirs_.insert(file_path.DirName()); |
| 235 } |
| 236 |
| 237 ApplyNextEntryProtoAsync(); |
| 238 } |
| 239 |
| 240 |
| 241 void DriveFeedProcessor::RemoveEntryFromParent( |
| 242 const DriveEntryProto& entry_proto, |
| 243 const FilePath& file_path) { |
| 244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 245 DCHECK(!file_path.empty()); |
| 246 |
| 247 if (!entry_proto.file_info().is_directory()) { |
| 248 // No children if entry is a file. |
| 249 OnGetChildrenForRemove(entry_proto, |
| 250 file_path, |
| 251 std::set<FilePath>()); |
| 252 } else { |
| 253 // If entry is a directory, notify its children. |
| 254 resource_metadata_->GetChildDirectories( |
| 255 entry_proto.resource_id(), |
| 256 base::Bind(&DriveFeedProcessor::OnGetChildrenForRemove, |
| 257 weak_ptr_factory_.GetWeakPtr(), |
| 258 entry_proto, |
| 259 file_path)); |
| 260 } |
| 261 } |
| 262 |
| 263 void DriveFeedProcessor::OnGetChildrenForRemove( |
| 264 const DriveEntryProto& entry_proto, |
| 265 const FilePath& file_path, |
| 266 const std::set<FilePath>& changed_directories) { |
| 267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 268 DCHECK(!file_path.empty()); |
| 269 |
| 270 resource_metadata_->RemoveEntryFromParent( |
| 271 entry_proto.resource_id(), |
| 272 base::Bind(&DriveFeedProcessor::NotifyForRemoveEntryFromParent, |
| 273 weak_ptr_factory_.GetWeakPtr(), |
| 274 entry_proto.file_info().is_directory(), |
| 275 file_path, |
| 276 changed_directories)); |
| 277 } |
| 278 |
| 279 void DriveFeedProcessor::NotifyForRemoveEntryFromParent( |
| 280 bool is_directory, |
| 281 const FilePath& file_path, |
| 282 const std::set<FilePath>& changed_directories, |
| 283 DriveFileError error, |
| 284 const FilePath& parent_path) { |
| 285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 286 |
| 287 DVLOG(1) << "NotifyForRemoveEntryFromParent " << file_path.value(); |
| 288 if (error == DRIVE_FILE_OK) { |
| 289 // Notify parent. |
| 290 changed_dirs_.insert(parent_path); |
| 291 |
| 292 // Notify children, if any. |
| 293 changed_dirs_.insert(changed_directories.begin(), |
| 294 changed_directories.end()); |
| 295 |
| 296 // If entry is a directory, notify self. |
| 297 if (is_directory) |
| 298 changed_dirs_.insert(file_path); |
| 299 } |
| 300 |
| 301 // Continue. |
| 302 ApplyNextEntryProtoAsync(); |
| 303 } |
| 304 |
| 305 void DriveFeedProcessor::AddEntryToParentDeprecated(DriveEntry* entry) { |
| 181 DriveDirectory* parent = ResolveParent(entry); | 306 DriveDirectory* parent = ResolveParent(entry); |
| 182 | 307 |
| 183 if (!parent) { // Orphan. | 308 if (!parent) { // Orphan. |
| 184 delete entry; | 309 delete entry; |
| 185 return; | 310 return; |
| 186 } | 311 } |
| 187 parent->AddEntry(entry); | 312 parent->AddEntry(entry); |
| 188 | 313 |
| 189 // Notify this directory that has been created. | 314 // Notify this directory that has been created. |
| 190 if (entry->AsDriveDirectory()) | 315 if (entry->AsDriveDirectory()) |
| 191 changed_dirs_.insert(entry->GetFilePath()); | 316 changed_dirs_.insert(entry->GetFilePath()); |
| 192 | 317 |
| 193 // Notify |parent| only if it already exists by checking if it is attached to | 318 // Notify |parent| only if it already exists by checking if it is attached to |
| 194 // the tree (has parent) or if it is root. The parent of |parent| may not | 319 // the tree (has parent) or if it is root. The parent of |parent| may not |
| 195 // exist here if it is about to be created later in the same feed. | 320 // exist here if it is about to be created later in the same feed. |
| 196 if (parent->parent() || parent == resource_metadata_->root()) | 321 if (parent->parent() || parent == resource_metadata_->root()) |
| 197 changed_dirs_.insert(parent->GetFilePath()); | 322 changed_dirs_.insert(parent->GetFilePath()); |
| 198 } | 323 } |
| 199 | 324 |
| 200 void DriveFeedProcessor::RemoveEntryFromParent( | 325 void DriveFeedProcessor::RemoveEntryFromParent(DriveEntry* entry) { |
| 201 DriveEntry* entry) { | |
| 202 DriveDirectory* parent = entry->parent(); | 326 DriveDirectory* parent = entry->parent(); |
| 203 if (!parent) { | 327 if (!parent) { |
| 204 NOTREACHED(); | 328 NOTREACHED(); |
| 205 return; | 329 return; |
| 206 } | 330 } |
| 207 | 331 |
| 208 DriveDirectory* dir = entry->AsDriveDirectory(); | 332 DriveDirectory* dir = entry->AsDriveDirectory(); |
| 209 if (dir) { | 333 // Notify all children of entry, if entry is a directory. |
| 210 // We need to notify all children of entry if entry is a directory. | 334 if (dir) |
| 211 dir->GetChildDirectoryPaths(&changed_dirs_); | 335 dir->GetChildDirectoryPaths(&changed_dirs_); |
| 212 // Besides children, notify this removed directory too. | |
| 213 changed_dirs_.insert(dir->GetFilePath()); | |
| 214 } | |
| 215 | 336 |
| 216 parent->RemoveEntry(entry); | 337 parent->RemoveEntry(entry); |
| 217 | 338 |
| 218 // Notify parent. | 339 // Notify parent. |
| 219 changed_dirs_.insert(parent->GetFilePath()); | 340 changed_dirs_.insert(parent->GetFilePath()); |
| 220 } | 341 } |
| 221 | 342 |
| 222 DriveDirectory* DriveFeedProcessor::ResolveParent( | 343 DriveDirectory* DriveFeedProcessor::ResolveParent(DriveEntry* new_entry) { |
| 223 DriveEntry* new_entry) { | |
| 224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 344 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 225 | 345 |
| 226 const std::string& parent_resource_id = new_entry->parent_resource_id(); | 346 const std::string& parent_resource_id = new_entry->parent_resource_id(); |
| 227 if (parent_resource_id.empty()) { | 347 if (parent_resource_id.empty()) { |
| 228 DVLOG(1) << "Root parent for " << new_entry->base_name(); | 348 DVLOG(1) << "Root parent for " << new_entry->base_name(); |
| 229 return resource_metadata_->root(); | 349 return resource_metadata_->root(); |
| 230 } | 350 } |
| 231 | 351 |
| 232 DriveEntry* parent = | 352 DriveEntry* parent = |
| 233 resource_metadata_->GetEntryByResourceId(parent_resource_id); | 353 resource_metadata_->GetEntryByResourceId(parent_resource_id); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 260 } | 380 } |
| 261 | 381 |
| 262 for (size_t j = 0; j < feed->entries().size(); ++j) { | 382 for (size_t j = 0; j < feed->entries().size(); ++j) { |
| 263 const google_apis::DocumentEntry* doc = feed->entries()[j]; | 383 const google_apis::DocumentEntry* doc = feed->entries()[j]; |
| 264 DriveEntryProto entry_proto = ConvertDocumentEntryToDriveEntryProto(*doc); | 384 DriveEntryProto entry_proto = ConvertDocumentEntryToDriveEntryProto(*doc); |
| 265 // Some document entries don't map into files (i.e. sites). | 385 // Some document entries don't map into files (i.e. sites). |
| 266 if (entry_proto.resource_id().empty()) | 386 if (entry_proto.resource_id().empty()) |
| 267 continue; | 387 continue; |
| 268 | 388 |
| 269 // Count the number of files. | 389 // Count the number of files. |
| 270 if (uma_stats && entry_proto.has_file_specific_info()) { | 390 if (uma_stats && !entry_proto.file_info().is_directory()) { |
| 271 uma_stats->IncrementNumFiles( | 391 uma_stats->IncrementNumFiles( |
| 272 entry_proto.file_specific_info().is_hosted_document()); | 392 entry_proto.file_specific_info().is_hosted_document()); |
| 273 } | 393 } |
| 274 | 394 |
| 275 std::pair<DriveEntryProtoMap::iterator, bool> ret = entry_proto_map_. | 395 std::pair<DriveEntryProtoMap::iterator, bool> ret = entry_proto_map_. |
| 276 insert(std::make_pair(entry_proto.resource_id(), entry_proto)); | 396 insert(std::make_pair(entry_proto.resource_id(), entry_proto)); |
| 277 DCHECK(ret.second); | 397 DCHECK(ret.second); |
| 278 if (!ret.second) | 398 if (!ret.second) |
| 279 LOG(WARNING) << "Found duplicate file " << entry_proto.base_name(); | 399 LOG(WARNING) << "Found duplicate file " << entry_proto.base_name(); |
| 280 } | 400 } |
| 281 } | 401 } |
| 282 } | 402 } |
| 283 | 403 |
| 284 void DriveFeedProcessor::Clear() { | 404 void DriveFeedProcessor::Clear() { |
| 285 entry_proto_map_.clear(); | 405 entry_proto_map_.clear(); |
| 286 changed_dirs_.clear(); | 406 changed_dirs_.clear(); |
| 287 on_complete_callback_.Reset(); | 407 on_complete_callback_.Reset(); |
| 288 } | 408 } |
| 289 | 409 |
| 290 } // namespace drive | 410 } // namespace drive |
| OLD | NEW |