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 |