OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "chrome/browser/sync_file_system/drive_backend/metadata_database.h" | 5 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h" |
6 | 6 |
7 #include <stack> | 7 #include <stack> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
(...skipping 13 matching lines...) Expand all Loading... |
24 #include "chrome/browser/sync_file_system/drive_backend/metadata_db_migration_ut
il.h" | 24 #include "chrome/browser/sync_file_system/drive_backend/metadata_db_migration_ut
il.h" |
25 #include "chrome/browser/sync_file_system/logger.h" | 25 #include "chrome/browser/sync_file_system/logger.h" |
26 #include "chrome/browser/sync_file_system/syncable_file_system_util.h" | 26 #include "chrome/browser/sync_file_system/syncable_file_system_util.h" |
27 #include "third_party/leveldatabase/src/include/leveldb/db.h" | 27 #include "third_party/leveldatabase/src/include/leveldb/db.h" |
28 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" | 28 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" |
29 #include "webkit/common/fileapi/file_system_util.h" | 29 #include "webkit/common/fileapi/file_system_util.h" |
30 | 30 |
31 namespace sync_file_system { | 31 namespace sync_file_system { |
32 namespace drive_backend { | 32 namespace drive_backend { |
33 | 33 |
34 typedef MetadataDatabase::FileByAppID FileByAppID; | |
35 typedef MetadataDatabase::FileByFileID FileByFileID; | |
36 typedef MetadataDatabase::FileByParentAndTitle FileByParentAndTitle; | |
37 typedef MetadataDatabase::FileSet FileSet; | |
38 typedef MetadataDatabase::FilesByParent FilesByParent; | |
39 | |
40 const char kDatabaseVersionKey[] = "VERSION"; | 34 const char kDatabaseVersionKey[] = "VERSION"; |
41 const int64 kCurrentDatabaseVersion = 3; | 35 const int64 kCurrentDatabaseVersion = 3; |
42 const char kServiceMetadataKey[] = "SERVICE"; | 36 const char kServiceMetadataKey[] = "SERVICE"; |
43 const char kFileMetadataKeyPrefix[] = "FILE: "; | 37 const char kFileMetadataKeyPrefix[] = "FILE: "; |
44 | 38 |
45 struct DatabaseContents { | 39 struct DatabaseContents { |
46 scoped_ptr<ServiceMetadata> service_metadata; | 40 scoped_ptr<ServiceMetadata> service_metadata; |
47 ScopedVector<DriveFileMetadata> file_metadata; | |
48 }; | 41 }; |
49 | 42 |
50 namespace { | 43 namespace { |
51 | 44 |
52 std::string RemovePrefix(const std::string& str, const std::string& prefix) { | 45 std::string RemovePrefix(const std::string& str, const std::string& prefix) { |
53 if (StartsWithASCII(str, prefix, true)) | 46 if (StartsWithASCII(str, prefix, true)) |
54 return str.substr(prefix.size()); | 47 return str.substr(prefix.size()); |
55 return str; | 48 return str; |
56 } | 49 } |
57 | 50 |
(...skipping 12 matching lines...) Expand all Loading... |
70 result.reserve(total_size); | 63 result.reserve(total_size); |
71 for (PathComponents::const_reverse_iterator itr = components.rbegin(); | 64 for (PathComponents::const_reverse_iterator itr = components.rbegin(); |
72 itr != components.rend(); ++itr) { | 65 itr != components.rend(); ++itr) { |
73 result.append(1, base::FilePath::kSeparators[0]); | 66 result.append(1, base::FilePath::kSeparators[0]); |
74 result.append(itr->value()); | 67 result.append(itr->value()); |
75 } | 68 } |
76 | 69 |
77 return base::FilePath(result).NormalizePathSeparators(); | 70 return base::FilePath(result).NormalizePathSeparators(); |
78 } | 71 } |
79 | 72 |
80 void PopulateFileDetailsFromFileResource( | |
81 int64 change_id, | |
82 const google_apis::FileResource& file_resource, | |
83 DriveFileMetadata::Details* details) { | |
84 details->set_change_id(change_id); | |
85 for (ScopedVector<google_apis::ParentReference>::const_iterator itr = | |
86 file_resource.parents().begin(); | |
87 itr != file_resource.parents().end(); | |
88 ++itr) { | |
89 details->add_parent_folder_id((*itr)->file_id()); | |
90 } | |
91 details->set_title(file_resource.title()); | |
92 | |
93 google_apis::DriveEntryKind kind = file_resource.GetKind(); | |
94 if (kind == google_apis::ENTRY_KIND_FILE) | |
95 details->set_kind(KIND_FILE); | |
96 else if (kind == google_apis::ENTRY_KIND_FOLDER) | |
97 details->set_kind(KIND_FOLDER); | |
98 else | |
99 details->set_kind(KIND_UNSUPPORTED); | |
100 | |
101 details->set_md5(file_resource.md5_checksum()); | |
102 details->set_etag(file_resource.etag()); | |
103 details->set_creation_time(file_resource.created_date().ToInternalValue()); | |
104 details->set_modification_time( | |
105 file_resource.modified_date().ToInternalValue()); | |
106 details->set_deleted(false); | |
107 } | |
108 | |
109 void AdaptLevelDBStatusToSyncStatusCode(const SyncStatusCallback& callback, | 73 void AdaptLevelDBStatusToSyncStatusCode(const SyncStatusCallback& callback, |
110 const leveldb::Status& status) { | 74 const leveldb::Status& status) { |
111 callback.Run(LevelDBStatusToSyncStatusCode(status)); | 75 callback.Run(LevelDBStatusToSyncStatusCode(status)); |
112 } | 76 } |
113 | 77 |
114 void PutFileToBatch(const DriveFileMetadata& file, leveldb::WriteBatch* batch) { | |
115 std::string value; | |
116 bool success = file.SerializeToString(&value); | |
117 DCHECK(success); | |
118 batch->Put(kFileMetadataKeyPrefix + file.file_id(), value); | |
119 } | |
120 | |
121 void PushChildrenToStack(const FilesByParent& files_by_parent, | |
122 const std::string& folder_id, | |
123 std::stack<std::string>* stack) { | |
124 FilesByParent::const_iterator found = files_by_parent.find(folder_id); | |
125 if (found == files_by_parent.end()) | |
126 return; | |
127 const FileSet& children = found->second; | |
128 for (FileSet::const_iterator itr = children.begin(); | |
129 itr != children.end(); ++itr) | |
130 stack->push((*itr)->file_id()); | |
131 } | |
132 | |
133 // Returns true if |db| has no content. | 78 // Returns true if |db| has no content. |
134 bool IsDatabaseEmpty(leveldb::DB* db) { | 79 bool IsDatabaseEmpty(leveldb::DB* db) { |
135 DCHECK(db); | 80 DCHECK(db); |
136 scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions())); | 81 scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions())); |
137 itr->SeekToFirst(); | 82 itr->SeekToFirst(); |
138 return !itr->Valid(); | 83 return !itr->Valid(); |
139 } | 84 } |
140 | 85 |
141 SyncStatusCode OpenDatabase(const base::FilePath& path, | 86 SyncStatusCode OpenDatabase(const base::FilePath& path, |
142 scoped_ptr<leveldb::DB>* db_out, | 87 scoped_ptr<leveldb::DB>* db_out, |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 if (!service_metadata->ParseFromString(value)) { | 174 if (!service_metadata->ParseFromString(value)) { |
230 util::Log(logging::LOG_WARNING, FROM_HERE, | 175 util::Log(logging::LOG_WARNING, FROM_HERE, |
231 "Failed to parse SyncServiceMetadata"); | 176 "Failed to parse SyncServiceMetadata"); |
232 continue; | 177 continue; |
233 } | 178 } |
234 | 179 |
235 contents->service_metadata = service_metadata.Pass(); | 180 contents->service_metadata = service_metadata.Pass(); |
236 continue; | 181 continue; |
237 } | 182 } |
238 | 183 |
239 if (StartsWithASCII(key, kFileMetadataKeyPrefix, true)) { | 184 NOTIMPLEMENTED(); |
240 std::string file_id = RemovePrefix(key, kFileMetadataKeyPrefix); | 185 continue; |
241 | |
242 scoped_ptr<DriveFileMetadata> metadata(new DriveFileMetadata); | |
243 if (!metadata->ParseFromString(itr->value().ToString())) { | |
244 util::Log(logging::LOG_WARNING, FROM_HERE, | |
245 "Failed to parse a Metadata"); | |
246 continue; | |
247 } | |
248 | |
249 contents->file_metadata.push_back(metadata.release()); | |
250 continue; | |
251 } | |
252 } | 186 } |
253 | 187 |
254 return SYNC_STATUS_OK; | 188 return SYNC_STATUS_OK; |
255 } | 189 } |
256 | 190 |
257 SyncStatusCode InitializeServiceMetadata(DatabaseContents* contents, | 191 SyncStatusCode InitializeServiceMetadata(DatabaseContents* contents, |
258 leveldb::WriteBatch* batch) { | 192 leveldb::WriteBatch* batch) { |
259 | 193 |
260 if (!contents->service_metadata) { | 194 if (!contents->service_metadata) { |
261 contents->service_metadata.reset(new ServiceMetadata); | 195 contents->service_metadata.reset(new ServiceMetadata); |
262 | 196 |
263 std::string value; | 197 std::string value; |
264 contents->service_metadata->SerializeToString(&value); | 198 contents->service_metadata->SerializeToString(&value); |
265 batch->Put(kServiceMetadataKey, value); | 199 batch->Put(kServiceMetadataKey, value); |
266 } | 200 } |
267 return SYNC_STATUS_OK; | 201 return SYNC_STATUS_OK; |
268 } | 202 } |
269 | 203 |
270 SyncStatusCode RemoveUnreachableFiles(DatabaseContents* contents, | 204 SyncStatusCode RemoveUnreachableFiles(DatabaseContents* contents, |
271 leveldb::WriteBatch* batch) { | 205 leveldb::WriteBatch* batch) { |
272 FileByFileID unvisited_files; | 206 NOTIMPLEMENTED(); |
273 FilesByParent files_by_parent; | |
274 | |
275 for (ScopedVector<DriveFileMetadata>::iterator itr = | |
276 contents->file_metadata.begin(); | |
277 itr != contents->file_metadata.end(); | |
278 ++itr) { | |
279 DriveFileMetadata* metadata = *itr; | |
280 DCHECK(!ContainsKey(unvisited_files, metadata->file_id())); | |
281 unvisited_files[metadata->file_id()] = metadata; | |
282 files_by_parent[metadata->parent_folder_id()].insert(metadata); | |
283 } | |
284 | |
285 // Traverse synced metadata tree. Take only active items and their children. | |
286 // Drop unreachable items. | |
287 ScopedVector<DriveFileMetadata> reachable_files; | |
288 std::stack<std::string> pending; | |
289 if (!contents->service_metadata->sync_root_folder_id().empty()) | |
290 pending.push(contents->service_metadata->sync_root_folder_id()); | |
291 | |
292 while (!pending.empty()) { | |
293 std::string file_id = pending.top(); | |
294 pending.pop(); | |
295 | |
296 { | |
297 FileByFileID::iterator found = unvisited_files.find(file_id); | |
298 if (found == unvisited_files.end()) | |
299 continue; | |
300 | |
301 DriveFileMetadata* metadata = found->second; | |
302 unvisited_files.erase(found); | |
303 reachable_files.push_back(metadata); | |
304 | |
305 if (!metadata->active() && !metadata->is_app_root()) | |
306 continue; | |
307 } | |
308 | |
309 FilesByParent::iterator found = files_by_parent.find(file_id); | |
310 if (found == files_by_parent.end()) | |
311 continue; | |
312 | |
313 for (FileSet::const_iterator itr = found->second.begin(); | |
314 itr != found->second.end(); | |
315 ++itr) | |
316 pending.push((*itr)->file_id()); | |
317 } | |
318 | |
319 for (FileByFileID::iterator itr = unvisited_files.begin(); | |
320 itr != unvisited_files.end(); | |
321 ++itr) { | |
322 DriveFileMetadata* metadata = itr->second; | |
323 batch->Delete(metadata->file_id()); | |
324 delete metadata; | |
325 } | |
326 unvisited_files.clear(); | |
327 | |
328 // |reachable_files| contains all files/folders reachable from sync-root | |
329 // folder via active folders. | |
330 contents->file_metadata.weak_clear(); | |
331 contents->file_metadata.swap(reachable_files); | |
332 | |
333 return SYNC_STATUS_OK; | 207 return SYNC_STATUS_OK; |
334 } | 208 } |
335 | 209 |
336 template <typename Container, typename Key, typename Value> | 210 template <typename Container, typename Key, typename Value> |
337 bool FindItem(const Container& container, const Key& key, Value* value) { | 211 bool FindItem(const Container& container, const Key& key, Value* value) { |
338 typename Container::const_iterator found = container.find(key); | 212 typename Container::const_iterator found = container.find(key); |
339 if (found == container.end()) | 213 if (found == container.end()) |
340 return false; | 214 return false; |
341 if (value) | 215 if (value) |
342 *value = *found->second; | 216 *value = *found->second; |
343 return true; | 217 return true; |
344 } | 218 } |
345 | 219 |
346 void RunSoon(const tracked_objects::Location& from_here, | 220 void RunSoon(const tracked_objects::Location& from_here, |
347 const base::Closure& closure) { | 221 const base::Closure& closure) { |
348 base::MessageLoopProxy::current()->PostTask(from_here, closure); | 222 base::MessageLoopProxy::current()->PostTask(from_here, closure); |
349 } | 223 } |
350 | 224 |
351 } // namespace | 225 } // namespace |
352 | 226 |
353 bool MetadataDatabase::FileIDComparator::operator()( | |
354 DriveFileMetadata* left, | |
355 DriveFileMetadata* right) const { | |
356 return left->file_id() < right->file_id(); | |
357 } | |
358 | |
359 // static | 227 // static |
360 void MetadataDatabase::Create(base::SequencedTaskRunner* task_runner, | 228 void MetadataDatabase::Create(base::SequencedTaskRunner* task_runner, |
361 const base::FilePath& database_path, | 229 const base::FilePath& database_path, |
362 const CreateCallback& callback) { | 230 const CreateCallback& callback) { |
363 task_runner->PostTask(FROM_HERE, base::Bind( | 231 task_runner->PostTask(FROM_HERE, base::Bind( |
364 &CreateOnTaskRunner, | 232 &CreateOnTaskRunner, |
365 base::MessageLoopProxy::current(), | 233 base::MessageLoopProxy::current(), |
366 make_scoped_refptr(task_runner), | 234 make_scoped_refptr(task_runner), |
367 database_path, callback)); | 235 database_path, callback)); |
368 } | 236 } |
369 | 237 |
370 MetadataDatabase::~MetadataDatabase() { | 238 MetadataDatabase::~MetadataDatabase() { |
371 task_runner_->DeleteSoon(FROM_HERE, db_.release()); | 239 task_runner_->DeleteSoon(FROM_HERE, db_.release()); |
372 STLDeleteContainerPairSecondPointers( | |
373 file_by_file_id_.begin(), file_by_file_id_.end()); | |
374 } | 240 } |
375 | 241 |
376 int64 MetadataDatabase::GetLargestChangeID() const { | 242 int64 MetadataDatabase::GetLargestChangeID() const { |
377 return service_metadata_->largest_change_id(); | 243 return service_metadata_->largest_change_id(); |
378 } | 244 } |
379 | 245 |
380 void MetadataDatabase::RegisterApp(const std::string& app_id, | 246 void MetadataDatabase::RegisterApp(const std::string& app_id, |
381 const std::string& folder_id, | 247 const std::string& folder_id, |
382 const SyncStatusCallback& callback) { | 248 const SyncStatusCallback& callback) { |
383 if (FindAppRootFolder(app_id, NULL)) { | 249 NOTIMPLEMENTED(); |
384 RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK)); | |
385 return; | |
386 } | |
387 | |
388 DriveFileMetadata folder; | |
389 if (!FindFileByFileID(folder_id, &folder)) { | |
390 RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); | |
391 return; | |
392 } | |
393 | |
394 DCHECK(!folder.active()); | |
395 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); | |
396 RegisterFolderAsAppRoot(app_id, folder.file_id(), batch.get()); | |
397 WriteToDatabase(batch.Pass(), callback); | |
398 } | 250 } |
399 | 251 |
400 void MetadataDatabase::DisableApp(const std::string& app_id, | 252 void MetadataDatabase::DisableApp(const std::string& app_id, |
401 const SyncStatusCallback& callback) { | 253 const SyncStatusCallback& callback) { |
402 DriveFileMetadata folder; | 254 NOTIMPLEMENTED(); |
403 if (!FindAppRootFolder(app_id, &folder)) { | |
404 RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); | |
405 return; | |
406 } | |
407 | |
408 if (!folder.active()) { | |
409 RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK)); | |
410 return; | |
411 } | |
412 | |
413 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); | |
414 MakeFileInactive(folder.file_id(), batch.get()); | |
415 WriteToDatabase(batch.Pass(), callback); | |
416 } | 255 } |
417 | 256 |
418 void MetadataDatabase::EnableApp(const std::string& app_id, | 257 void MetadataDatabase::EnableApp(const std::string& app_id, |
419 const SyncStatusCallback& callback) { | 258 const SyncStatusCallback& callback) { |
420 DriveFileMetadata folder; | 259 NOTIMPLEMENTED(); |
421 if (!FindAppRootFolder(app_id, &folder)) { | |
422 RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); | |
423 return; | |
424 } | |
425 | |
426 if (folder.active()) { | |
427 RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK)); | |
428 return; | |
429 } | |
430 | |
431 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); | |
432 MakeFileActive(folder.file_id(), batch.get()); | |
433 WriteToDatabase(batch.Pass(), callback); | |
434 } | 260 } |
435 | 261 |
436 void MetadataDatabase::UnregisterApp(const std::string& app_id, | 262 void MetadataDatabase::UnregisterApp(const std::string& app_id, |
437 const SyncStatusCallback& callback) { | 263 const SyncStatusCallback& callback) { |
438 DriveFileMetadata folder; | |
439 if (!FindAppRootFolder(app_id, &folder)) { | |
440 RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK)); | |
441 return; | |
442 } | |
443 | |
444 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); | |
445 UnregisterFolderAsAppRoot(app_id, batch.get()); | |
446 WriteToDatabase(batch.Pass(), callback); | |
447 } | |
448 | |
449 bool MetadataDatabase::FindAppRootFolder(const std::string& app_id, | |
450 DriveFileMetadata* folder) const { | |
451 return FindItem(app_root_by_app_id_, app_id, folder); | |
452 } | |
453 | |
454 bool MetadataDatabase::FindFileByFileID(const std::string& file_id, | |
455 DriveFileMetadata* metadata) const { | |
456 return FindItem(file_by_file_id_, file_id, metadata); | |
457 } | |
458 | |
459 size_t MetadataDatabase::FindFilesByParentAndTitle( | |
460 const std::string& file_id, | |
461 const std::string& title, | |
462 ScopedVector<DriveFileMetadata>* files) const { | |
463 NOTIMPLEMENTED(); | 264 NOTIMPLEMENTED(); |
464 return 0; | |
465 } | |
466 | |
467 bool MetadataDatabase::FindActiveFileByParentAndTitle( | |
468 const std::string& folder_id, | |
469 const std::string& title, | |
470 DriveFileMetadata* file) const { | |
471 return FindItem(active_file_by_parent_and_title_, | |
472 std::make_pair(folder_id, title), | |
473 file); | |
474 } | |
475 | |
476 bool MetadataDatabase::FindActiveFileByPath(const std::string& app_id, | |
477 const base::FilePath& path, | |
478 DriveFileMetadata* file) const { | |
479 DriveFileMetadata current; | |
480 if (!FindAppRootFolder(app_id, ¤t)) | |
481 return false; | |
482 | |
483 std::vector<base::FilePath::StringType> components; | |
484 path.GetComponents(&components); | |
485 | |
486 std::string parent_folder_id = current.file_id(); | |
487 for (std::vector<base::FilePath::StringType>::iterator itr = | |
488 components.begin(); | |
489 itr != components.end(); | |
490 ++itr) { | |
491 std::string current_folder_id = current.file_id(); | |
492 if (!FindActiveFileByParentAndTitle( | |
493 current_folder_id, base::FilePath(*itr).AsUTF8Unsafe(), ¤t)) | |
494 return false; | |
495 } | |
496 if (file) | |
497 *file = current; | |
498 return true; | |
499 } | |
500 | |
501 bool MetadataDatabase::BuildPathForFile(const std::string& file_id, | |
502 base::FilePath* path) const { | |
503 DriveFileMetadata current; | |
504 if (!FindFileByFileID(file_id, ¤t) || !current.active()) | |
505 return false; | |
506 | |
507 std::vector<base::FilePath> components; | |
508 while (!current.is_app_root()) { | |
509 components.push_back(base::FilePath::FromUTF8Unsafe( | |
510 current.synced_details().title())); | |
511 if (!FindFileByFileID(current.parent_folder_id(), ¤t) || | |
512 !current.active()) | |
513 return false; | |
514 } | |
515 | |
516 if (path) | |
517 *path = ReverseConcatPathComponents(components); | |
518 | |
519 return true; | |
520 } | 265 } |
521 | 266 |
522 void MetadataDatabase::UpdateByChangeList( | 267 void MetadataDatabase::UpdateByChangeList( |
523 ScopedVector<google_apis::ChangeResource> changes, | 268 ScopedVector<google_apis::ChangeResource> changes, |
524 const SyncStatusCallback& callback) { | 269 const SyncStatusCallback& callback) { |
525 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); | |
526 | |
527 for (ScopedVector<google_apis::ChangeResource>::iterator itr = | |
528 changes.begin(); | |
529 itr != changes.end(); | |
530 ++itr) { | |
531 const google_apis::ChangeResource& change = **itr; | |
532 DriveFileMetadata file; | |
533 | |
534 // If the remote file already has an entry in the database, update its | |
535 // |remote_detais| and mark it dirty. | |
536 if (FindFileByFileID(change.file_id(), NULL)) { | |
537 const google_apis::FileResource* file_resource = NULL; | |
538 if (!change.is_deleted()) | |
539 file_resource = change.file(); | |
540 UpdateRemoteDetails(change.change_id(), change.file_id(), file_resource, | |
541 batch.get()); | |
542 continue; | |
543 } | |
544 | |
545 // Deletion of an unknown file can be safely ignorable. | |
546 if (change.is_deleted()) | |
547 continue; | |
548 | |
549 // Find first active parent. | |
550 std::string parent_folder_id; | |
551 DriveFileMetadata parent; | |
552 for (ScopedVector<google_apis::ParentReference>::const_iterator itr = | |
553 change.file()->parents().begin(); | |
554 itr != change.file()->parents().end(); | |
555 ++itr) { | |
556 if (FindFileByFileID((*itr)->file_id(), &parent) && | |
557 (parent.active() || parent.is_app_root())) { | |
558 parent_folder_id = parent.file_id(); | |
559 break; | |
560 } | |
561 } | |
562 | |
563 // If the remote file doesn't have active parent, ignore the file. | |
564 if (parent_folder_id.empty()) | |
565 continue; | |
566 | |
567 RegisterNewFile(change.change_id(), parent, *change.file(), | |
568 batch.get()); | |
569 } | |
570 | |
571 WriteToDatabase(batch.Pass(), callback); | |
572 } | |
573 | |
574 void MetadataDatabase::PopulateFolder( | |
575 const std::string& folder_id, | |
576 ScopedVector<google_apis::ResourceEntry> children, | |
577 const SyncStatusCallback& callback) { | |
578 NOTIMPLEMENTED(); | 270 NOTIMPLEMENTED(); |
579 } | 271 } |
580 | 272 |
581 MetadataDatabase::MetadataDatabase(base::SequencedTaskRunner* task_runner) | 273 MetadataDatabase::MetadataDatabase(base::SequencedTaskRunner* task_runner) |
582 : task_runner_(task_runner), weak_ptr_factory_(this) { | 274 : task_runner_(task_runner), weak_ptr_factory_(this) { |
583 DCHECK(task_runner); | 275 DCHECK(task_runner); |
584 } | 276 } |
585 | 277 |
586 // static | 278 // static |
587 void MetadataDatabase::CreateOnTaskRunner( | 279 void MetadataDatabase::CreateOnTaskRunner( |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
655 status = LevelDBStatusToSyncStatusCode( | 347 status = LevelDBStatusToSyncStatusCode( |
656 db_->Write(leveldb::WriteOptions(), &batch)); | 348 db_->Write(leveldb::WriteOptions(), &batch)); |
657 if (status != SYNC_STATUS_OK) | 349 if (status != SYNC_STATUS_OK) |
658 return status; | 350 return status; |
659 | 351 |
660 BuildIndexes(&contents); | 352 BuildIndexes(&contents); |
661 return status; | 353 return status; |
662 } | 354 } |
663 | 355 |
664 void MetadataDatabase::BuildIndexes(DatabaseContents* contents) { | 356 void MetadataDatabase::BuildIndexes(DatabaseContents* contents) { |
665 for (ScopedVector<DriveFileMetadata>::iterator itr = | 357 NOTIMPLEMENTED(); |
666 contents->file_metadata.begin(); | |
667 itr != contents->file_metadata.end(); | |
668 ++itr) { | |
669 DriveFileMetadata* file = *itr; | |
670 file_by_file_id_[file->file_id()] = file; | |
671 | |
672 if (file->is_app_root()) | |
673 app_root_by_app_id_[file->app_id()] = file; | |
674 | |
675 if (file->active() && file->has_synced_details()) { | |
676 FileByParentAndTitle::key_type key( | |
677 file->parent_folder_id(), file->synced_details().title()); | |
678 active_file_by_parent_and_title_[key] = file; | |
679 } | |
680 | |
681 if (!file->parent_folder_id().empty()) | |
682 files_by_parent_[file->parent_folder_id()].insert(file); | |
683 | |
684 if (file->dirty()) | |
685 dirty_files_.insert(file); | |
686 } | |
687 | |
688 contents->file_metadata.weak_clear(); | |
689 } | |
690 | |
691 void MetadataDatabase::RegisterFolderAsAppRoot( | |
692 const std::string& app_id, | |
693 const std::string& folder_id, | |
694 leveldb::WriteBatch* batch) { | |
695 DriveFileMetadata* folder = file_by_file_id_[folder_id]; | |
696 if (!folder || folder->active() || folder->is_app_root() || | |
697 !folder->app_id().empty()) { | |
698 NOTREACHED(); | |
699 return; | |
700 } | |
701 | |
702 folder->set_is_app_root(true); | |
703 folder->set_app_id(app_id); | |
704 folder->set_active(true); | |
705 folder->set_dirty(true); | |
706 folder->set_needs_folder_listing(true); | |
707 PutFileToBatch(*folder, batch); | |
708 | |
709 app_root_by_app_id_[app_id] = folder; | |
710 if (folder->has_synced_details()) { | |
711 FileByParentAndTitle::key_type key( | |
712 folder->parent_folder_id(), folder->synced_details().title()); | |
713 DCHECK(!ContainsKey(active_file_by_parent_and_title_, key)); | |
714 active_file_by_parent_and_title_[key] = folder; | |
715 } | |
716 dirty_files_.insert(folder); | |
717 } | |
718 | |
719 void MetadataDatabase::UnregisterFolderAsAppRoot( | |
720 const std::string& app_id, | |
721 leveldb::WriteBatch* batch) { | |
722 DriveFileMetadata* folder = app_root_by_app_id_[app_id]; | |
723 if (!folder || !folder->active() || | |
724 folder->app_id() != app_id || !folder->is_app_root()) { | |
725 NOTREACHED(); | |
726 return; | |
727 } | |
728 | |
729 folder->set_active(false); | |
730 folder->set_is_app_root(false); | |
731 folder->set_app_id(std::string()); | |
732 PutFileToBatch(*folder, batch); | |
733 | |
734 // Remove child entries recursively. | |
735 std::stack<std::string> pending_files; | |
736 PushChildrenToStack(files_by_parent_, folder->file_id(), &pending_files); | |
737 while (!pending_files.empty()) { | |
738 std::string file_id = pending_files.top(); | |
739 pending_files.pop(); | |
740 PushChildrenToStack(files_by_parent_, file_id, &pending_files); | |
741 RemoveFile(file_id, batch); | |
742 } | |
743 | |
744 app_root_by_app_id_.erase(app_id); | |
745 if (folder->has_synced_details()) { | |
746 FileByParentAndTitle::key_type key( | |
747 folder->parent_folder_id(), folder->synced_details().title()); | |
748 active_file_by_parent_and_title_.erase(key); | |
749 } | |
750 } | |
751 | |
752 void MetadataDatabase::MakeFileActive(const std::string& file_id, | |
753 leveldb::WriteBatch* batch) { | |
754 DriveFileMetadata* file = file_by_file_id_[file_id]; | |
755 if (!file || file->active()) { | |
756 NOTREACHED(); | |
757 return; | |
758 } | |
759 | |
760 file->set_active(true); | |
761 if (file->has_synced_details() && | |
762 file->synced_details().kind() == KIND_FOLDER) | |
763 file->set_needs_folder_listing(true); | |
764 PutFileToBatch(*file, batch); | |
765 | |
766 if (file->has_synced_details()) { | |
767 FileByParentAndTitle::key_type key( | |
768 file->parent_folder_id(), file->synced_details().title()); | |
769 DCHECK(!ContainsKey(active_file_by_parent_and_title_, key)); | |
770 active_file_by_parent_and_title_[key] = file; | |
771 } | |
772 } | |
773 | |
774 void MetadataDatabase::MakeFileInactive(const std::string& file_id, | |
775 leveldb::WriteBatch* batch) { | |
776 DriveFileMetadata* file = file_by_file_id_[file_id]; | |
777 if (!file || !file->active()) { | |
778 NOTREACHED(); | |
779 return; | |
780 } | |
781 | |
782 file->set_active(false); | |
783 PutFileToBatch(*file, batch); | |
784 | |
785 if (file->has_synced_details()) { | |
786 FileByParentAndTitle::key_type key( | |
787 file->parent_folder_id(), file->synced_details().title()); | |
788 DCHECK(ContainsKey(active_file_by_parent_and_title_, key)); | |
789 active_file_by_parent_and_title_.erase(key); | |
790 } | |
791 } | |
792 | |
793 void MetadataDatabase::RemoveFile(const std::string& file_id, | |
794 leveldb::WriteBatch* batch) { | |
795 scoped_ptr<DriveFileMetadata> file(file_by_file_id_[file_id]); | |
796 file_by_file_id_.erase(file_id); | |
797 | |
798 batch->Delete(file->file_id()); | |
799 | |
800 files_by_parent_[file->parent_folder_id()].erase(file.get()); | |
801 if (file->is_app_root()) | |
802 app_root_by_app_id_.erase(file->app_id()); | |
803 if (file->active() && file->has_synced_details()) { | |
804 FileByParentAndTitle::key_type key( | |
805 file->parent_folder_id(), file->synced_details().title()); | |
806 active_file_by_parent_and_title_.erase(key); | |
807 } | |
808 dirty_files_.erase(file.get()); | |
809 } | |
810 | |
811 void MetadataDatabase::UpdateRemoteDetails( | |
812 int64 change_id, | |
813 const std::string& file_id, | |
814 const google_apis::FileResource* file_resource, | |
815 leveldb::WriteBatch* batch) { | |
816 DriveFileMetadata* file = file_by_file_id_[file_id]; | |
817 | |
818 file->clear_remote_details(); | |
819 DriveFileMetadata::Details* details = file->mutable_remote_details(); | |
820 if (file_resource) { | |
821 PopulateFileDetailsFromFileResource(change_id, *file_resource, details); | |
822 } else { | |
823 details->set_deleted(true); | |
824 details->set_change_id(change_id); | |
825 } | |
826 | |
827 file->set_dirty(true); | |
828 PutFileToBatch(*file, batch); | |
829 | |
830 dirty_files_.insert(file); | |
831 } | |
832 | |
833 void MetadataDatabase::RegisterNewFile( | |
834 int64 change_id, | |
835 const DriveFileMetadata& parent_folder, | |
836 const google_apis::FileResource& new_file_resource, | |
837 leveldb::WriteBatch* batch) { | |
838 scoped_ptr<DriveFileMetadata> file(new DriveFileMetadata); | |
839 std::string file_id = new_file_resource.file_id(); | |
840 file->set_file_id(file_id); | |
841 file->set_parent_folder_id(parent_folder.file_id()); | |
842 file->set_app_id(parent_folder.app_id()); | |
843 file->set_is_app_root(false); | |
844 | |
845 PopulateFileDetailsFromFileResource( | |
846 change_id, new_file_resource, file->mutable_remote_details()); | |
847 | |
848 file->set_dirty(true); | |
849 file->set_active(false); | |
850 file->set_needs_folder_listing( | |
851 new_file_resource.GetKind() == google_apis::ENTRY_KIND_FOLDER); | |
852 | |
853 PutFileToBatch(*file, batch); | |
854 | |
855 files_by_parent_[parent_folder.file_id()].insert(file.get()); | |
856 dirty_files_.insert(file.get()); | |
857 | |
858 file_by_file_id_[file_id] = file.release(); | |
859 } | 358 } |
860 | 359 |
861 void MetadataDatabase::WriteToDatabase(scoped_ptr<leveldb::WriteBatch> batch, | 360 void MetadataDatabase::WriteToDatabase(scoped_ptr<leveldb::WriteBatch> batch, |
862 const SyncStatusCallback& callback) { | 361 const SyncStatusCallback& callback) { |
863 base::PostTaskAndReplyWithResult( | 362 base::PostTaskAndReplyWithResult( |
864 task_runner_.get(), | 363 task_runner_.get(), |
865 FROM_HERE, | 364 FROM_HERE, |
866 base::Bind(&leveldb::DB::Write, | 365 base::Bind(&leveldb::DB::Write, |
867 base::Unretained(db_.get()), | 366 base::Unretained(db_.get()), |
868 leveldb::WriteOptions(), | 367 leveldb::WriteOptions(), |
869 base::Owned(batch.release())), | 368 base::Owned(batch.release())), |
870 base::Bind(&AdaptLevelDBStatusToSyncStatusCode, callback)); | 369 base::Bind(&AdaptLevelDBStatusToSyncStatusCode, callback)); |
871 } | 370 } |
872 | 371 |
873 } // namespace drive_backend | 372 } // namespace drive_backend |
874 } // namespace sync_file_system | 373 } // namespace sync_file_system |
OLD | NEW |