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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h" 6 7 #include <algorithm> 8 #include <stack> 9 10 #include "base/bind.h" 11 #include "base/callback.h" 12 #include "base/file_util.h" 13 #include "base/files/file_path.h" 14 #include "base/location.h" 15 #include "base/memory/scoped_vector.h" 16 #include "base/message_loop/message_loop_proxy.h" 17 #include "base/sequenced_task_runner.h" 18 #include "base/stl_util.h" 19 #include "base/strings/string_number_conversions.h" 20 #include "base/strings/string_util.h" 21 #include "base/strings/stringprintf.h" 22 #include "base/task_runner_util.h" 23 #include "base/threading/thread_restrictions.h" 24 #include "chrome/browser/drive/drive_api_util.h" 25 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h" 26 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h" 27 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h" 28 #include "chrome/browser/sync_file_system/drive_backend/metadata_database_index.h" 29 #include "chrome/browser/sync_file_system/drive_backend/metadata_database_index_interface.h" 30 #include "chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.h" 31 #include "chrome/browser/sync_file_system/logger.h" 32 #include "chrome/browser/sync_file_system/syncable_file_system_util.h" 33 #include "google_apis/drive/drive_api_parser.h" 34 #include "google_apis/drive/drive_entry_kinds.h" 35 #include "third_party/leveldatabase/src/include/leveldb/db.h" 36 #include "third_party/leveldatabase/src/include/leveldb/env.h" 37 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 38 #include "webkit/common/fileapi/file_system_util.h" 39 40 namespace sync_file_system { 41 namespace drive_backend { 42 43 namespace { 44 45 bool IsAppRoot(const FileTracker& tracker) { 46 return tracker.tracker_kind() == TRACKER_KIND_APP_ROOT || 47 tracker.tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT; 48 } 49 50 std::string RemovePrefix(const std::string& str, const std::string& prefix) { 51 if (StartsWithASCII(str, prefix, true)) 52 return str.substr(prefix.size()); 53 return str; 54 } 55 56 base::FilePath ReverseConcatPathComponents( 57 const std::vector<base::FilePath>& components) { 58 if (components.empty()) 59 return base::FilePath(FILE_PATH_LITERAL("/")).NormalizePathSeparators(); 60 61 size_t total_size = 0; 62 typedef std::vector<base::FilePath> PathComponents; 63 for (PathComponents::const_iterator itr = components.begin(); 64 itr != components.end(); ++itr) 65 total_size += itr->value().size() + 1; 66 67 base::FilePath::StringType result; 68 result.reserve(total_size); 69 for (PathComponents::const_reverse_iterator itr = components.rbegin(); 70 itr != components.rend(); ++itr) { 71 result.append(1, base::FilePath::kSeparators[0]); 72 result.append(itr->value()); 73 } 74 75 return base::FilePath(result).NormalizePathSeparators(); 76 } 77 78 scoped_ptr<FileTracker> CreateSyncRootTracker( 79 int64 tracker_id, 80 const FileMetadata& sync_root_metadata) { 81 scoped_ptr<FileTracker> sync_root_tracker(new FileTracker); 82 sync_root_tracker->set_tracker_id(tracker_id); 83 sync_root_tracker->set_file_id(sync_root_metadata.file_id()); 84 sync_root_tracker->set_parent_tracker_id(0); 85 sync_root_tracker->set_tracker_kind(TRACKER_KIND_REGULAR); 86 sync_root_tracker->set_dirty(false); 87 sync_root_tracker->set_active(true); 88 sync_root_tracker->set_needs_folder_listing(false); 89 *sync_root_tracker->mutable_synced_details() = sync_root_metadata.details(); 90 return sync_root_tracker.Pass(); 91 } 92 93 scoped_ptr<FileTracker> CreateInitialAppRootTracker( 94 int64 tracker_id, 95 int64 parent_tracker_id, 96 const FileMetadata& app_root_metadata) { 97 scoped_ptr<FileTracker> app_root_tracker(new FileTracker); 98 app_root_tracker->set_tracker_id(tracker_id); 99 app_root_tracker->set_parent_tracker_id(parent_tracker_id); 100 app_root_tracker->set_file_id(app_root_metadata.file_id()); 101 app_root_tracker->set_tracker_kind(TRACKER_KIND_REGULAR); 102 app_root_tracker->set_dirty(false); 103 app_root_tracker->set_active(false); 104 app_root_tracker->set_needs_folder_listing(false); 105 *app_root_tracker->mutable_synced_details() = app_root_metadata.details(); 106 return app_root_tracker.Pass(); 107 } 108 109 void WriteOnFileTaskRunner( 110 leveldb::DB* db, 111 scoped_ptr<leveldb::WriteBatch> batch, 112 scoped_refptr<base::SequencedTaskRunner> worker_task_runner, 113 const SyncStatusCallback& callback) { 114 DCHECK(db); 115 DCHECK(batch); 116 leveldb::Status status = db->Write(leveldb::WriteOptions(), batch.get()); 117 worker_task_runner->PostTask( 118 FROM_HERE, 119 base::Bind(callback, LevelDBStatusToSyncStatusCode(status))); 120 } 121 122 std::string GetTrackerTitle(const FileTracker& tracker) { 123 if (tracker.has_synced_details()) 124 return tracker.synced_details().title(); 125 return std::string(); 126 } 127 128 // Returns true if |db| has no content. 129 bool IsDatabaseEmpty(leveldb::DB* db) { 130 DCHECK(db); 131 scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions())); 132 itr->SeekToFirst(); 133 return !itr->Valid(); 134 } 135 136 SyncStatusCode OpenDatabase(const base::FilePath& path, 137 leveldb::Env* env_override, 138 scoped_ptr<leveldb::DB>* db_out, 139 bool* created) { 140 base::ThreadRestrictions::AssertIOAllowed(); 141 DCHECK(db_out); 142 DCHECK(created); 143 DCHECK(path.IsAbsolute()); 144 145 leveldb::Options options; 146 options.max_open_files = 0; // Use minimum. 147 options.create_if_missing = true; 148 if (env_override) 149 options.env = env_override; 150 leveldb::DB* db = NULL; 151 leveldb::Status db_status = 152 leveldb::DB::Open(options, path.AsUTF8Unsafe(), &db); 153 SyncStatusCode status = LevelDBStatusToSyncStatusCode(db_status); 154 if (status != SYNC_STATUS_OK) { 155 delete db; 156 return status; 157 } 158 159 *created = IsDatabaseEmpty(db); 160 db_out->reset(db); 161 return status; 162 } 163 164 SyncStatusCode MigrateDatabaseIfNeeded(leveldb::DB* db) { 165 base::ThreadRestrictions::AssertIOAllowed(); 166 DCHECK(db); 167 std::string value; 168 leveldb::Status status = 169 db->Get(leveldb::ReadOptions(), kDatabaseVersionKey, &value); 170 int64 version = 0; 171 if (status.ok()) { 172 if (!base::StringToInt64(value, &version)) 173 return SYNC_DATABASE_ERROR_FAILED; 174 } else { 175 if (!status.IsNotFound()) 176 return SYNC_DATABASE_ERROR_FAILED; 177 } 178 179 switch (version) { 180 case 0: 181 drive_backend::MigrateDatabaseFromV0ToV1(db); 182 // fall-through 183 case 1: 184 drive_backend::MigrateDatabaseFromV1ToV2(db); 185 // fall-through 186 case 2: 187 // TODO(tzik): Migrate database from version 2 to 3. 188 // * Add sync-root folder as active, dirty and needs_folder_listing 189 // folder. 190 // * Add app-root folders for each origins. Each app-root folder for 191 // an enabled origin should be a active, dirty and 192 // needs_folder_listing folder. And Each app-root folder for a 193 // disabled origin should be an inactive, dirty and 194 // non-needs_folder_listing folder. 195 // * Add a file metadata for each file in previous version. 196 NOTIMPLEMENTED(); 197 return SYNC_DATABASE_ERROR_FAILED; 198 // fall-through 199 case 3: 200 DCHECK_EQ(3, kCurrentDatabaseVersion); 201 return SYNC_STATUS_OK; 202 default: 203 return SYNC_DATABASE_ERROR_FAILED; 204 } 205 } 206 207 SyncStatusCode WriteVersionInfo(leveldb::DB* db) { 208 base::ThreadRestrictions::AssertIOAllowed(); 209 DCHECK(db); 210 return LevelDBStatusToSyncStatusCode( 211 db->Put(leveldb::WriteOptions(), 212 kDatabaseVersionKey, 213 base::Int64ToString(kCurrentDatabaseVersion))); 214 } 215 216 SyncStatusCode ReadDatabaseContents(leveldb::DB* db, 217 DatabaseContents* contents) { 218 base::ThreadRestrictions::AssertIOAllowed(); 219 DCHECK(db); 220 DCHECK(contents); 221 222 scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions())); 223 for (itr->SeekToFirst(); itr->Valid(); itr->Next()) { 224 std::string key = itr->key().ToString(); 225 std::string value = itr->value().ToString(); 226 if (key == kServiceMetadataKey) { 227 scoped_ptr<ServiceMetadata> service_metadata(new ServiceMetadata); 228 if (!service_metadata->ParseFromString(value)) { 229 util::Log(logging::LOG_WARNING, FROM_HERE, 230 "Failed to parse SyncServiceMetadata"); 231 continue; 232 } 233 234 contents->service_metadata = service_metadata.Pass(); 235 continue; 236 } 237 238 if (StartsWithASCII(key, kFileMetadataKeyPrefix, true)) { 239 std::string file_id = RemovePrefix(key, kFileMetadataKeyPrefix); 240 241 scoped_ptr<FileMetadata> metadata(new FileMetadata); 242 if (!metadata->ParseFromString(itr->value().ToString())) { 243 util::Log(logging::LOG_WARNING, FROM_HERE, 244 "Failed to parse a FileMetadata"); 245 continue; 246 } 247 248 contents->file_metadata.push_back(metadata.release()); 249 continue; 250 } 251 252 if (StartsWithASCII(key, kFileTrackerKeyPrefix, true)) { 253 int64 tracker_id = 0; 254 if (!base::StringToInt64(RemovePrefix(key, kFileTrackerKeyPrefix), 255 &tracker_id)) { 256 util::Log(logging::LOG_WARNING, FROM_HERE, 257 "Failed to parse TrackerID"); 258 continue; 259 } 260 261 scoped_ptr<FileTracker> tracker(new FileTracker); 262 if (!tracker->ParseFromString(itr->value().ToString())) { 263 util::Log(logging::LOG_WARNING, FROM_HERE, 264 "Failed to parse a Tracker"); 265 continue; 266 } 267 contents->file_trackers.push_back(tracker.release()); 268 continue; 269 } 270 } 271 272 return SYNC_STATUS_OK; 273 } 274 275 SyncStatusCode InitializeServiceMetadata(DatabaseContents* contents, 276 leveldb::WriteBatch* batch) { 277 if (!contents->service_metadata) { 278 contents->service_metadata.reset(new ServiceMetadata); 279 contents->service_metadata->set_next_tracker_id(1); 280 281 std::string value; 282 contents->service_metadata->SerializeToString(&value); 283 if (batch) 284 batch->Put(kServiceMetadataKey, value); 285 } 286 return SYNC_STATUS_OK; 287 } 288 289 SyncStatusCode RemoveUnreachableItems(DatabaseContents* contents, 290 leveldb::WriteBatch* batch) { 291 typedef std::map<int64, std::set<int64> > ChildTrackersByParent; 292 ChildTrackersByParent trackers_by_parent; 293 294 // Set up links from parent tracker to child trackers. 295 for (size_t i = 0; i < contents->file_trackers.size(); ++i) { 296 const FileTracker& tracker = *contents->file_trackers[i]; 297 int64 parent_tracker_id = tracker.parent_tracker_id(); 298 int64 tracker_id = tracker.tracker_id(); 299 300 trackers_by_parent[parent_tracker_id].insert(tracker_id); 301 } 302 303 // Drop links from inactive trackers. 304 for (size_t i = 0; i < contents->file_trackers.size(); ++i) { 305 const FileTracker& tracker = *contents->file_trackers[i]; 306 307 if (!tracker.active()) 308 trackers_by_parent.erase(tracker.tracker_id()); 309 } 310 311 std::vector<int64> pending; 312 if (contents->service_metadata->sync_root_tracker_id() != kInvalidTrackerID) 313 pending.push_back(contents->service_metadata->sync_root_tracker_id()); 314 315 // Traverse tracker tree from sync-root. 316 std::set<int64> visited_trackers; 317 while (!pending.empty()) { 318 int64 tracker_id = pending.back(); 319 DCHECK_NE(kInvalidTrackerID, tracker_id); 320 pending.pop_back(); 321 322 if (!visited_trackers.insert(tracker_id).second) { 323 NOTREACHED(); 324 continue; 325 } 326 327 AppendContents( 328 LookUpMap(trackers_by_parent, tracker_id, std::set<int64>()), 329 &pending); 330 } 331 332 // Delete all unreachable trackers. 333 ScopedVector<FileTracker> reachable_trackers; 334 for (size_t i = 0; i < contents->file_trackers.size(); ++i) { 335 FileTracker* tracker = contents->file_trackers[i]; 336 if (ContainsKey(visited_trackers, tracker->tracker_id())) { 337 reachable_trackers.push_back(tracker); 338 contents->file_trackers[i] = NULL; 339 } else { 340 PutFileTrackerDeletionToBatch(tracker->tracker_id(), batch); 341 } 342 } 343 contents->file_trackers = reachable_trackers.Pass(); 344 345 // List all |file_id| referred by a tracker. 346 base::hash_set<std::string> referred_file_ids; 347 for (size_t i = 0; i < contents->file_trackers.size(); ++i) 348 referred_file_ids.insert(contents->file_trackers[i]->file_id()); 349 350 // Delete all unreferred metadata. 351 ScopedVector<FileMetadata> referred_file_metadata; 352 for (size_t i = 0; i < contents->file_metadata.size(); ++i) { 353 FileMetadata* metadata = contents->file_metadata[i]; 354 if (ContainsKey(referred_file_ids, metadata->file_id())) { 355 referred_file_metadata.push_back(metadata); 356 contents->file_metadata[i] = NULL; 357 } else { 358 PutFileMetadataDeletionToBatch(metadata->file_id(), batch); 359 } 360 } 361 contents->file_metadata = referred_file_metadata.Pass(); 362 363 return SYNC_STATUS_OK; 364 } 365 366 bool HasInvalidTitle(const std::string& title) { 367 return title.empty() || 368 title.find('/') != std::string::npos || 369 title.find('\\') != std::string::npos; 370 } 371 372 void MarkTrackerSetDirty(const TrackerIDSet& trackers, 373 MetadataDatabaseIndexInterface* index, 374 leveldb::WriteBatch* batch) { 375 for (TrackerIDSet::const_iterator itr = trackers.begin(); 376 itr != trackers.end(); ++itr) { 377 scoped_ptr<FileTracker> tracker = 378 CloneFileTracker(index->GetFileTracker(*itr)); 379 if (tracker->dirty()) 380 continue; 381 tracker->set_dirty(true); 382 PutFileTrackerToBatch(*tracker, batch); 383 index->StoreFileTracker(tracker.Pass()); 384 } 385 } 386 387 void MarkTrackersDirtyByPath(int64 parent_tracker_id, 388 const std::string& title, 389 MetadataDatabaseIndexInterface* index, 390 leveldb::WriteBatch* batch) { 391 if (parent_tracker_id == kInvalidTrackerID || title.empty()) 392 return; 393 MarkTrackerSetDirty( 394 index->GetFileTrackerIDsByParentAndTitle(parent_tracker_id, title), 395 index, batch); 396 } 397 398 void MarkTrackersDirtyByFileID(const std::string& file_id, 399 MetadataDatabaseIndexInterface* index, 400 leveldb::WriteBatch* batch) { 401 MarkTrackerSetDirty(index->GetFileTrackerIDsByFileID(file_id), 402 index, batch); 403 } 404 405 void MarkTrackersDirtyRecursively(int64 root_tracker_id, 406 MetadataDatabaseIndexInterface* index, 407 leveldb::WriteBatch* batch) { 408 std::vector<int64> stack; 409 stack.push_back(root_tracker_id); 410 while (!stack.empty()) { 411 int64 tracker_id = stack.back(); 412 stack.pop_back(); 413 AppendContents(index->GetFileTrackerIDsByParent(tracker_id), &stack); 414 415 scoped_ptr<FileTracker> tracker = 416 CloneFileTracker(index->GetFileTracker(tracker_id)); 417 tracker->set_dirty(true); 418 419 PutFileTrackerToBatch(*tracker, batch); 420 index->StoreFileTracker(tracker.Pass()); 421 } 422 } 423 424 void RemoveAllDescendantTrackers(int64 root_tracker_id, 425 MetadataDatabaseIndexInterface* index, 426 leveldb::WriteBatch* batch) { 427 std::vector<int64> pending_trackers; 428 AppendContents(index->GetFileTrackerIDsByParent(root_tracker_id), 429 &pending_trackers); 430 431 std::vector<int64> to_be_removed; 432 433 // List trackers to remove. 434 while (!pending_trackers.empty()) { 435 int64 tracker_id = pending_trackers.back(); 436 pending_trackers.pop_back(); 437 AppendContents(index->GetFileTrackerIDsByParent(tracker_id), 438 &pending_trackers); 439 to_be_removed.push_back(tracker_id); 440 } 441 442 // Remove trackers in the reversed order. 443 base::hash_set<std::string> affected_file_ids; 444 for (std::vector<int64>::reverse_iterator itr = to_be_removed.rbegin(); 445 itr != to_be_removed.rend(); ++itr) { 446 const FileTracker* trackers = index->GetFileTracker(*itr); 447 affected_file_ids.insert(trackers->file_id()); 448 PutFileTrackerDeletionToBatch(*itr, batch); 449 index->RemoveFileTracker(*itr); 450 } 451 452 for (base::hash_set<std::string>::iterator itr = affected_file_ids.begin(); 453 itr != affected_file_ids.end(); ++itr) { 454 TrackerIDSet trackers = index->GetFileTrackerIDsByFileID(*itr); 455 if (trackers.empty()) { 456 // Remove metadata that no longer has any tracker. 457 PutFileMetadataDeletionToBatch(*itr, batch); 458 index->RemoveFileMetadata(*itr); 459 } else { 460 MarkTrackerSetDirty(trackers, index, batch); 461 } 462 } 463 } 464 465 const FileTracker* FilterFileTrackersByParent( 466 const MetadataDatabaseIndexInterface* index, 467 const TrackerIDSet& trackers, 468 int64 parent_tracker_id) { 469 for (TrackerIDSet::const_iterator itr = trackers.begin(); 470 itr != trackers.end(); ++itr) { 471 const FileTracker* tracker = index->GetFileTracker(*itr); 472 if (!tracker) { 473 NOTREACHED(); 474 continue; 475 } 476 477 if (tracker->parent_tracker_id() == parent_tracker_id) 478 return tracker; 479 } 480 return NULL; 481 } 482 483 const FileTracker* FilterFileTrackersByParentAndTitle( 484 const MetadataDatabaseIndexInterface* index, 485 const TrackerIDSet& trackers, 486 int64 parent_tracker_id, 487 const std::string& title) { 488 const FileTracker* result = NULL; 489 490 for (TrackerIDSet::const_iterator itr = trackers.begin(); 491 itr != trackers.end(); ++itr) { 492 const FileTracker* tracker = index->GetFileTracker(*itr); 493 if (!tracker) { 494 NOTREACHED(); 495 continue; 496 } 497 498 if (tracker->parent_tracker_id() != parent_tracker_id) 499 continue; 500 501 if (tracker->has_synced_details() && 502 tracker->synced_details().title() != title) 503 continue; 504 505 // Prioritize trackers that has |synced_details|. 506 if (!result || !tracker->has_synced_details()) 507 result = tracker; 508 } 509 510 return result; 511 } 512 513 const FileTracker* FilterFileTrackersByFileID( 514 const MetadataDatabaseIndexInterface* index, 515 const TrackerIDSet& trackers, 516 const std::string& file_id) { 517 for (TrackerIDSet::const_iterator itr = trackers.begin(); 518 itr != trackers.end(); ++itr) { 519 const FileTracker* tracker = index->GetFileTracker(*itr); 520 if (!tracker) { 521 NOTREACHED(); 522 continue; 523 } 524 525 if (tracker->file_id() == file_id) 526 return tracker; 527 } 528 529 return NULL; 530 } 531 532 enum DirtyingOption { 533 MARK_NOTHING_DIRTY = 0, 534 MARK_ITSELF_DIRTY = 1 << 0, 535 MARK_SAME_FILE_ID_TRACKERS_DIRTY = 1 << 1, 536 MARK_SAME_PATH_TRACKERS_DIRTY = 1 << 2, 537 }; 538 539 void ActivateFileTracker(int64 tracker_id, 540 int dirtying_options, 541 MetadataDatabaseIndexInterface* index, 542 leveldb::WriteBatch* batch) { 543 DCHECK(dirtying_options == MARK_NOTHING_DIRTY || 544 dirtying_options == MARK_ITSELF_DIRTY); 545 546 scoped_ptr<FileTracker> tracker = 547 CloneFileTracker(index->GetFileTracker(tracker_id)); 548 tracker->set_active(true); 549 if (dirtying_options & MARK_ITSELF_DIRTY) { 550 tracker->set_dirty(true); 551 tracker->set_needs_folder_listing( 552 tracker->has_synced_details() && 553 tracker->synced_details().file_kind() == FILE_KIND_FOLDER); 554 } else { 555 tracker->set_dirty(false); 556 tracker->set_needs_folder_listing(false); 557 } 558 559 PutFileTrackerToBatch(*tracker, batch); 560 index->StoreFileTracker(tracker.Pass()); 561 } 562 563 void DeactivateFileTracker(int64 tracker_id, 564 int dirtying_options, 565 MetadataDatabaseIndexInterface* index, 566 leveldb::WriteBatch* batch) { 567 RemoveAllDescendantTrackers(tracker_id, index, batch); 568 569 scoped_ptr<FileTracker> tracker = 570 CloneFileTracker(index->GetFileTracker(tracker_id)); 571 572 if (dirtying_options & MARK_SAME_FILE_ID_TRACKERS_DIRTY) 573 MarkTrackersDirtyByFileID(tracker->file_id(), index, batch); 574 if (dirtying_options & MARK_SAME_PATH_TRACKERS_DIRTY) { 575 MarkTrackersDirtyByPath(tracker->parent_tracker_id(), 576 GetTrackerTitle(*tracker), 577 index, batch); 578 } 579 580 tracker->set_dirty(dirtying_options & MARK_ITSELF_DIRTY); 581 tracker->set_active(false); 582 PutFileTrackerToBatch(*tracker, batch); 583 index->StoreFileTracker(tracker.Pass()); 584 } 585 586 void RemoveFileTracker(int64 tracker_id, 587 int dirtying_options, 588 MetadataDatabaseIndexInterface* index, 589 leveldb::WriteBatch* batch) { 590 DCHECK(!(dirtying_options & MARK_ITSELF_DIRTY)); 591 592 const FileTracker* tracker = index->GetFileTracker(tracker_id); 593 if (!tracker) 594 return; 595 596 std::string file_id = tracker->file_id(); 597 int64 parent_tracker_id = tracker->parent_tracker_id(); 598 std::string title = GetTrackerTitle(*tracker); 599 600 RemoveAllDescendantTrackers(tracker_id, index, batch); 601 PutFileTrackerDeletionToBatch(tracker_id, batch); 602 index->RemoveFileTracker(tracker_id); 603 604 if (dirtying_options & MARK_SAME_FILE_ID_TRACKERS_DIRTY) 605 MarkTrackersDirtyByFileID(file_id, index, batch); 606 if (dirtying_options & MARK_SAME_PATH_TRACKERS_DIRTY) 607 MarkTrackersDirtyByPath(parent_tracker_id, title, index, batch); 608 609 if (index->GetFileTrackerIDsByFileID(file_id).empty()) { 610 PutFileMetadataDeletionToBatch(file_id, batch); 611 index->RemoveFileMetadata(file_id); 612 } 613 } 614 615 } // namespace 616 617 struct MetadataDatabase::CreateParam { 618 scoped_refptr<base::SequencedTaskRunner> worker_task_runner; 619 scoped_refptr<base::SequencedTaskRunner> file_task_runner; 620 base::FilePath database_path; 621 leveldb::Env* env_override; 622 623 CreateParam(base::SequencedTaskRunner* worker_task_runner, 624 base::SequencedTaskRunner* file_task_runner, 625 const base::FilePath& database_path, 626 leveldb::Env* env_override) 627 : worker_task_runner(worker_task_runner), 628 file_task_runner(file_task_runner), 629 database_path(database_path), 630 env_override(env_override) { 631 } 632 }; 633 634 DatabaseContents::DatabaseContents() {} 635 DatabaseContents::~DatabaseContents() {} 636 637 // static 638 void MetadataDatabase::Create(base::SequencedTaskRunner* worker_task_runner, 639 base::SequencedTaskRunner* file_task_runner, 640 const base::FilePath& database_path, 641 leveldb::Env* env_override, 642 const CreateCallback& callback) { 643 file_task_runner->PostTask(FROM_HERE, base::Bind( 644 &MetadataDatabase::CreateOnFileTaskRunner, 645 base::Passed(make_scoped_ptr(new CreateParam( 646 worker_task_runner, 647 file_task_runner, 648 database_path, 649 env_override))), 650 callback)); 651 } 652 653 // static 654 SyncStatusCode MetadataDatabase::CreateForTesting( 655 scoped_ptr<leveldb::DB> db, 656 scoped_ptr<MetadataDatabase>* metadata_database_out) { 657 scoped_ptr<MetadataDatabase> metadata_database( 658 new MetadataDatabase(base::MessageLoopProxy::current(), 659 base::MessageLoopProxy::current(), 660 base::FilePath(), NULL)); 661 metadata_database->db_ = db.Pass(); 662 SyncStatusCode status = 663 metadata_database->InitializeOnFileTaskRunner(); 664 if (status == SYNC_STATUS_OK) 665 *metadata_database_out = metadata_database.Pass(); 666 return status; 667 } 668 669 MetadataDatabase::~MetadataDatabase() { 670 file_task_runner_->DeleteSoon(FROM_HERE, db_.release()); 671 } 672 673 // static 674 void MetadataDatabase::ClearDatabase( 675 scoped_ptr<MetadataDatabase> metadata_database) { 676 DCHECK(metadata_database); 677 scoped_refptr<base::SequencedTaskRunner> file_task_runner = 678 metadata_database->file_task_runner_; 679 base::FilePath database_path = metadata_database->database_path_; 680 DCHECK(!database_path.empty()); 681 metadata_database.reset(); 682 683 file_task_runner->PostTask( 684 FROM_HERE, 685 base::Bind(base::IgnoreResult(base::DeleteFile), 686 database_path, true /* recursive */)); 687 } 688 689 int64 MetadataDatabase::GetLargestFetchedChangeID() const { 690 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 691 return service_metadata_->largest_change_id(); 692 } 693 694 int64 MetadataDatabase::GetSyncRootTrackerID() const { 695 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 696 return service_metadata_->sync_root_tracker_id(); 697 } 698 699 int64 MetadataDatabase::GetLargestKnownChangeID() const { 700 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 701 DCHECK_LE(GetLargestFetchedChangeID(), largest_known_change_id_); 702 return largest_known_change_id_; 703 } 704 705 void MetadataDatabase::UpdateLargestKnownChangeID(int64 change_id) { 706 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 707 if (largest_known_change_id_ < change_id) 708 largest_known_change_id_ = change_id; 709 } 710 711 bool MetadataDatabase::HasSyncRoot() const { 712 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 713 return service_metadata_->has_sync_root_tracker_id() && 714 !!service_metadata_->sync_root_tracker_id(); 715 } 716 717 void MetadataDatabase::PopulateInitialData( 718 int64 largest_change_id, 719 const google_apis::FileResource& sync_root_folder, 720 const ScopedVector<google_apis::FileResource>& app_root_folders, 721 const SyncStatusCallback& callback) { 722 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 723 724 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 725 service_metadata_->set_largest_change_id(largest_change_id); 726 UpdateLargestKnownChangeID(largest_change_id); 727 728 AttachSyncRoot(sync_root_folder, batch.get()); 729 for (size_t i = 0; i < app_root_folders.size(); ++i) 730 AttachInitialAppRoot(*app_root_folders[i], batch.get()); 731 732 WriteToDatabase(batch.Pass(), callback); 733 } 734 735 bool MetadataDatabase::IsAppEnabled(const std::string& app_id) const { 736 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 737 738 int64 tracker_id = index_->GetAppRootTracker(app_id); 739 if (tracker_id == kInvalidTrackerID) 740 return false; 741 742 const FileTracker* tracker = index_->GetFileTracker(tracker_id); 743 return tracker && tracker->tracker_kind() == TRACKER_KIND_APP_ROOT; 744 } 745 746 void MetadataDatabase::RegisterApp(const std::string& app_id, 747 const std::string& folder_id, 748 const SyncStatusCallback& callback) { 749 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 750 751 if (index_->GetAppRootTracker(app_id)) { 752 // The app-root is already registered. 753 worker_task_runner_->PostTask( 754 FROM_HERE, 755 base::Bind(callback, SYNC_STATUS_OK)); 756 return; 757 } 758 759 TrackerIDSet trackers = index_->GetFileTrackerIDsByFileID(folder_id); 760 if (trackers.empty()) { 761 worker_task_runner_->PostTask( 762 FROM_HERE, 763 base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); 764 return; 765 } 766 767 if (trackers.has_active()) { 768 // The folder is tracked by another tracker. 769 util::Log(logging::LOG_WARNING, FROM_HERE, 770 "Failed to register App for %s", app_id.c_str()); 771 worker_task_runner_->PostTask( 772 FROM_HERE, 773 base::Bind(callback, SYNC_STATUS_HAS_CONFLICT)); 774 return; 775 } 776 777 int64 sync_root_tracker_id = service_metadata_->sync_root_tracker_id(); 778 if (!sync_root_tracker_id) { 779 util::Log(logging::LOG_WARNING, FROM_HERE, 780 "Sync-root needs to be set up before registering app-root"); 781 worker_task_runner_->PostTask( 782 FROM_HERE, 783 base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); 784 return; 785 } 786 787 scoped_ptr<FileTracker> tracker = 788 CloneFileTracker(FilterFileTrackersByParent(index_.get(), trackers, 789 sync_root_tracker_id)); 790 if (!tracker) { 791 worker_task_runner_->PostTask( 792 FROM_HERE, 793 base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); 794 return; 795 } 796 797 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 798 tracker->set_app_id(app_id); 799 tracker->set_tracker_kind(TRACKER_KIND_APP_ROOT); 800 tracker->set_active(true); 801 tracker->set_needs_folder_listing(true); 802 tracker->set_dirty(true); 803 804 PutFileTrackerToBatch(*tracker, batch.get()); 805 index_->StoreFileTracker(tracker.Pass()); 806 WriteToDatabase(batch.Pass(), callback); 807 } 808 809 void MetadataDatabase::DisableApp(const std::string& app_id, 810 const SyncStatusCallback& callback) { 811 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 812 813 int64 tracker_id = index_->GetAppRootTracker(app_id); 814 scoped_ptr<FileTracker> tracker = 815 CloneFileTracker(index_->GetFileTracker(tracker_id)); 816 if (!tracker) { 817 callback.Run(SYNC_DATABASE_ERROR_NOT_FOUND); 818 return; 819 } 820 821 if (tracker->tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT) { 822 callback.Run(SYNC_STATUS_OK); 823 return; 824 } 825 826 DCHECK_EQ(TRACKER_KIND_APP_ROOT, tracker->tracker_kind()); 827 DCHECK(tracker->active()); 828 829 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 830 831 // Keep the app-root tracker active (but change the tracker_kind) so that 832 // other conflicting trackers won't become active. 833 tracker->set_tracker_kind(TRACKER_KIND_DISABLED_APP_ROOT); 834 835 PutFileTrackerToBatch(*tracker, batch.get()); 836 index_->StoreFileTracker(tracker.Pass()); 837 WriteToDatabase(batch.Pass(), callback); 838 } 839 840 void MetadataDatabase::EnableApp(const std::string& app_id, 841 const SyncStatusCallback& callback) { 842 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 843 844 int64 tracker_id = index_->GetAppRootTracker(app_id); 845 scoped_ptr<FileTracker> tracker = 846 CloneFileTracker(index_->GetFileTracker(tracker_id)); 847 if (!tracker) { 848 callback.Run(SYNC_DATABASE_ERROR_NOT_FOUND); 849 return; 850 } 851 852 if (tracker->tracker_kind() == TRACKER_KIND_APP_ROOT) { 853 callback.Run(SYNC_STATUS_OK); 854 return; 855 } 856 857 DCHECK_EQ(TRACKER_KIND_DISABLED_APP_ROOT, tracker->tracker_kind()); 858 DCHECK(tracker->active()); 859 860 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 861 862 tracker->set_tracker_kind(TRACKER_KIND_APP_ROOT); 863 PutFileTrackerToBatch(*tracker, batch.get()); 864 index_->StoreFileTracker(tracker.Pass()); 865 866 MarkTrackersDirtyRecursively(tracker_id, index_.get(), batch.get()); 867 WriteToDatabase(batch.Pass(), callback); 868 } 869 870 void MetadataDatabase::UnregisterApp(const std::string& app_id, 871 const SyncStatusCallback& callback) { 872 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 873 874 int64 tracker_id = index_->GetAppRootTracker(app_id); 875 scoped_ptr<FileTracker> tracker = 876 CloneFileTracker(index_->GetFileTracker(tracker_id)); 877 if (!tracker || tracker->tracker_kind() == TRACKER_KIND_REGULAR) { 878 worker_task_runner_->PostTask( 879 FROM_HERE, 880 base::Bind(callback, SYNC_STATUS_OK)); 881 return; 882 } 883 884 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 885 RemoveAllDescendantTrackers(tracker_id, index_.get(), batch.get()); 886 887 tracker->clear_app_id(); 888 tracker->set_tracker_kind(TRACKER_KIND_REGULAR); 889 tracker->set_active(false); 890 tracker->set_dirty(true); 891 892 PutFileTrackerToBatch(*tracker, batch.get()); 893 index_->StoreFileTracker(tracker.Pass()); 894 WriteToDatabase(batch.Pass(), callback); 895 } 896 897 bool MetadataDatabase::FindAppRootTracker(const std::string& app_id, 898 FileTracker* tracker_out) const { 899 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 900 901 int64 app_root_tracker_id = index_->GetAppRootTracker(app_id); 902 if (!app_root_tracker_id) 903 return false; 904 905 if (tracker_out) { 906 const FileTracker* app_root_tracker = 907 index_->GetFileTracker(app_root_tracker_id); 908 if (!app_root_tracker) { 909 NOTREACHED(); 910 return false; 911 } 912 *tracker_out = *app_root_tracker; 913 } 914 return true; 915 } 916 917 bool MetadataDatabase::FindFileByFileID(const std::string& file_id, 918 FileMetadata* metadata_out) const { 919 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 920 921 const FileMetadata* metadata = index_->GetFileMetadata(file_id); 922 if (!metadata) 923 return false; 924 if (metadata_out) 925 *metadata_out = *metadata; 926 return true; 927 } 928 929 bool MetadataDatabase::FindTrackersByFileID(const std::string& file_id, 930 TrackerIDSet* trackers_out) const { 931 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 932 933 TrackerIDSet trackers = index_->GetFileTrackerIDsByFileID(file_id); 934 if (trackers.empty()) 935 return false; 936 937 if (trackers_out) 938 std::swap(trackers, *trackers_out); 939 return true; 940 } 941 942 bool MetadataDatabase::FindTrackersByParentAndTitle( 943 int64 parent_tracker_id, 944 const std::string& title, 945 TrackerIDSet* trackers_out) const { 946 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 947 948 TrackerIDSet trackers = 949 index_->GetFileTrackerIDsByParentAndTitle(parent_tracker_id, title); 950 if (trackers.empty()) 951 return false; 952 953 if (trackers_out) 954 std::swap(trackers, *trackers_out); 955 return true; 956 } 957 958 bool MetadataDatabase::FindTrackerByTrackerID(int64 tracker_id, 959 FileTracker* tracker_out) const { 960 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 961 962 const FileTracker* tracker = index_->GetFileTracker(tracker_id); 963 if (!tracker) 964 return false; 965 if (tracker_out) 966 *tracker_out = *tracker; 967 return true; 968 } 969 970 bool MetadataDatabase::BuildPathForTracker(int64 tracker_id, 971 base::FilePath* path) const { 972 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 973 974 FileTracker current; 975 if (!FindTrackerByTrackerID(tracker_id, ¤t) || !current.active()) 976 return false; 977 978 std::vector<base::FilePath> components; 979 while (!IsAppRoot(current)) { 980 std::string title = GetTrackerTitle(current); 981 if (title.empty()) 982 return false; 983 components.push_back(base::FilePath::FromUTF8Unsafe(title)); 984 if (!FindTrackerByTrackerID(current.parent_tracker_id(), ¤t) || 985 !current.active()) 986 return false; 987 } 988 989 if (path) 990 *path = ReverseConcatPathComponents(components); 991 992 return true; 993 } 994 995 base::FilePath MetadataDatabase::BuildDisplayPathForTracker( 996 const FileTracker& tracker) const { 997 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 998 999 base::FilePath path; 1000 if (tracker.active()) { 1001 BuildPathForTracker(tracker.tracker_id(), &path); 1002 return path; 1003 } 1004 BuildPathForTracker(tracker.parent_tracker_id(), &path); 1005 if (tracker.has_synced_details()) { 1006 path = path.Append( 1007 base::FilePath::FromUTF8Unsafe(tracker.synced_details().title())); 1008 } else { 1009 path = path.Append(FILE_PATH_LITERAL("<unknown>")); 1010 } 1011 return path; 1012 } 1013 1014 bool MetadataDatabase::FindNearestActiveAncestor( 1015 const std::string& app_id, 1016 const base::FilePath& full_path, 1017 FileTracker* tracker_out, 1018 base::FilePath* path_out) const { 1019 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1020 DCHECK(tracker_out); 1021 DCHECK(path_out); 1022 1023 if (full_path.IsAbsolute() || 1024 !FindAppRootTracker(app_id, tracker_out) || 1025 tracker_out->tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT) { 1026 return false; 1027 } 1028 1029 std::vector<base::FilePath::StringType> components; 1030 full_path.GetComponents(&components); 1031 path_out->clear(); 1032 1033 for (size_t i = 0; i < components.size(); ++i) { 1034 const std::string title = base::FilePath(components[i]).AsUTF8Unsafe(); 1035 TrackerIDSet trackers; 1036 if (!FindTrackersByParentAndTitle( 1037 tracker_out->tracker_id(), title, &trackers) || 1038 !trackers.has_active()) { 1039 return true; 1040 } 1041 1042 const FileTracker* tracker = 1043 index_->GetFileTracker(trackers.active_tracker());; 1044 1045 DCHECK(tracker->has_synced_details()); 1046 const FileDetails& details = tracker->synced_details(); 1047 if (details.file_kind() != FILE_KIND_FOLDER && i != components.size() - 1) { 1048 // This non-last component indicates file. Give up search. 1049 return true; 1050 } 1051 1052 *tracker_out = *tracker; 1053 *path_out = path_out->Append(components[i]); 1054 } 1055 1056 return true; 1057 } 1058 1059 void MetadataDatabase::UpdateByChangeList( 1060 int64 largest_change_id, 1061 ScopedVector<google_apis::ChangeResource> changes, 1062 const SyncStatusCallback& callback) { 1063 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1064 DCHECK_LE(service_metadata_->largest_change_id(), largest_change_id); 1065 1066 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 1067 1068 for (size_t i = 0; i < changes.size(); ++i) { 1069 const google_apis::ChangeResource& change = *changes[i]; 1070 if (HasNewerFileMetadata(change.file_id(), change.change_id())) 1071 continue; 1072 1073 scoped_ptr<FileMetadata> metadata( 1074 CreateFileMetadataFromChangeResource(change)); 1075 UpdateByFileMetadata(FROM_HERE, metadata.Pass(), 1076 UPDATE_TRACKER_FOR_UNSYNCED_FILE, 1077 batch.get()); 1078 } 1079 1080 UpdateLargestKnownChangeID(largest_change_id); 1081 service_metadata_->set_largest_change_id(largest_change_id); 1082 PutServiceMetadataToBatch(*service_metadata_, batch.get()); 1083 WriteToDatabase(batch.Pass(), callback); 1084 } 1085 1086 void MetadataDatabase::UpdateByFileResource( 1087 const google_apis::FileResource& resource, 1088 const SyncStatusCallback& callback) { 1089 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1090 1091 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 1092 1093 scoped_ptr<FileMetadata> metadata( 1094 CreateFileMetadataFromFileResource( 1095 GetLargestKnownChangeID(), resource)); 1096 UpdateByFileMetadata(FROM_HERE, metadata.Pass(), 1097 UPDATE_TRACKER_FOR_UNSYNCED_FILE, 1098 batch.get()); 1099 WriteToDatabase(batch.Pass(), callback); 1100 } 1101 1102 void MetadataDatabase::UpdateByFileResourceList( 1103 ScopedVector<google_apis::FileResource> resources, 1104 const SyncStatusCallback& callback) { 1105 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1106 1107 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 1108 1109 for (size_t i = 0; i < resources.size(); ++i) { 1110 scoped_ptr<FileMetadata> metadata( 1111 CreateFileMetadataFromFileResource( 1112 GetLargestKnownChangeID(), *resources[i])); 1113 UpdateByFileMetadata(FROM_HERE, metadata.Pass(), 1114 UPDATE_TRACKER_FOR_UNSYNCED_FILE, 1115 batch.get()); 1116 } 1117 WriteToDatabase(batch.Pass(), callback); 1118 } 1119 1120 void MetadataDatabase::UpdateByDeletedRemoteFile( 1121 const std::string& file_id, 1122 const SyncStatusCallback& callback) { 1123 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1124 1125 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 1126 scoped_ptr<FileMetadata> metadata( 1127 CreateDeletedFileMetadata(GetLargestKnownChangeID(), file_id)); 1128 UpdateByFileMetadata(FROM_HERE, metadata.Pass(), 1129 UPDATE_TRACKER_FOR_UNSYNCED_FILE, 1130 batch.get()); 1131 WriteToDatabase(batch.Pass(), callback); 1132 } 1133 1134 void MetadataDatabase::UpdateByDeletedRemoteFileList( 1135 const FileIDList& file_ids, 1136 const SyncStatusCallback& callback) { 1137 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1138 1139 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 1140 for (FileIDList::const_iterator itr = file_ids.begin(); 1141 itr != file_ids.end(); ++itr) { 1142 scoped_ptr<FileMetadata> metadata( 1143 CreateDeletedFileMetadata(GetLargestKnownChangeID(), *itr)); 1144 UpdateByFileMetadata(FROM_HERE, metadata.Pass(), 1145 UPDATE_TRACKER_FOR_UNSYNCED_FILE, 1146 batch.get()); 1147 } 1148 WriteToDatabase(batch.Pass(), callback); 1149 } 1150 1151 void MetadataDatabase::ReplaceActiveTrackerWithNewResource( 1152 int64 parent_tracker_id, 1153 const google_apis::FileResource& resource, 1154 const SyncStatusCallback& callback) { 1155 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1156 DCHECK(index_->GetFileTracker(parent_tracker_id)); 1157 DCHECK(!index_->GetFileMetadata(resource.file_id())); 1158 1159 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 1160 UpdateByFileMetadata( 1161 FROM_HERE, 1162 CreateFileMetadataFromFileResource(GetLargestKnownChangeID(), resource), 1163 UPDATE_TRACKER_FOR_SYNCED_FILE, 1164 batch.get()); 1165 1166 DCHECK(index_->GetFileMetadata(resource.file_id())); 1167 DCHECK(!index_->GetFileTrackerIDsByFileID(resource.file_id()).has_active()); 1168 1169 TrackerIDSet same_path_trackers = 1170 index_->GetFileTrackerIDsByParentAndTitle( 1171 parent_tracker_id, resource.title()); 1172 const FileTracker* to_be_activated = 1173 FilterFileTrackersByFileID(index_.get(), same_path_trackers, 1174 resource.file_id()); 1175 if (!to_be_activated) { 1176 NOTREACHED(); 1177 worker_task_runner_->PostTask( 1178 FROM_HERE, 1179 base::Bind(callback, SYNC_STATUS_FAILED)); 1180 return; 1181 } 1182 1183 int64 tracker_id = to_be_activated->tracker_id(); 1184 if (same_path_trackers.has_active()) { 1185 DeactivateFileTracker(same_path_trackers.active_tracker(), 1186 MARK_ITSELF_DIRTY | 1187 MARK_SAME_FILE_ID_TRACKERS_DIRTY, 1188 index_.get(), batch.get()); 1189 } 1190 1191 ActivateFileTracker(tracker_id, MARK_NOTHING_DIRTY, 1192 index_.get(), batch.get()); 1193 WriteToDatabase(batch.Pass(), callback); 1194 } 1195 1196 void MetadataDatabase::PopulateFolderByChildList( 1197 const std::string& folder_id, 1198 const FileIDList& child_file_ids, 1199 const SyncStatusCallback& callback) { 1200 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1201 1202 TrackerIDSet trackers = index_->GetFileTrackerIDsByFileID(folder_id); 1203 if (!trackers.has_active()) { 1204 // It's OK that there is no folder to populate its children. 1205 // Inactive folders should ignore their contents updates. 1206 worker_task_runner_->PostTask( 1207 FROM_HERE, 1208 base::Bind(callback, SYNC_STATUS_OK)); 1209 return; 1210 } 1211 1212 scoped_ptr<FileTracker> folder_tracker = 1213 CloneFileTracker(index_->GetFileTracker(trackers.active_tracker())); 1214 if (!folder_tracker) { 1215 NOTREACHED(); 1216 worker_task_runner_->PostTask( 1217 FROM_HERE, 1218 base::Bind(callback, SYNC_STATUS_FAILED)); 1219 return; 1220 } 1221 1222 base::hash_set<std::string> children(child_file_ids.begin(), 1223 child_file_ids.end()); 1224 1225 std::vector<int64> known_children = 1226 index_->GetFileTrackerIDsByParent(folder_tracker->tracker_id()); 1227 for (size_t i = 0; i < known_children.size(); ++i) { 1228 const FileTracker* tracker = index_->GetFileTracker(known_children[i]); 1229 if (!tracker) { 1230 NOTREACHED(); 1231 continue; 1232 } 1233 children.erase(tracker->file_id()); 1234 } 1235 1236 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 1237 for (base::hash_set<std::string>::const_iterator itr = children.begin(); 1238 itr != children.end(); ++itr) 1239 CreateTrackerForParentAndFileID(*folder_tracker, *itr, batch.get()); 1240 folder_tracker->set_needs_folder_listing(false); 1241 if (folder_tracker->dirty() && !ShouldKeepDirty(*folder_tracker)) 1242 folder_tracker->set_dirty(false); 1243 PutFileTrackerToBatch(*folder_tracker, batch.get()); 1244 index_->StoreFileTracker(folder_tracker.Pass()); 1245 1246 WriteToDatabase(batch.Pass(), callback); 1247 } 1248 1249 void MetadataDatabase::UpdateTracker(int64 tracker_id, 1250 const FileDetails& updated_details, 1251 const SyncStatusCallback& callback) { 1252 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1253 1254 const FileTracker* tracker = index_->GetFileTracker(tracker_id); 1255 if (!tracker) { 1256 worker_task_runner_->PostTask( 1257 FROM_HERE, 1258 base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); 1259 return; 1260 } 1261 DCHECK(tracker); 1262 1263 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 1264 1265 // Check if the tracker is to be deleted. 1266 if (updated_details.missing()) { 1267 const FileMetadata* metadata = index_->GetFileMetadata(tracker->file_id()); 1268 if (!metadata || metadata->details().missing()) { 1269 // Both the tracker and metadata have the missing flag, now it's safe to 1270 // delete the |tracker|. 1271 RemoveFileTracker(tracker_id, 1272 MARK_SAME_FILE_ID_TRACKERS_DIRTY | 1273 MARK_SAME_PATH_TRACKERS_DIRTY, 1274 index_.get(), batch.get()); 1275 WriteToDatabase(batch.Pass(), callback); 1276 return; 1277 } 1278 } 1279 1280 // Sync-root deletion should be handled separately by SyncEngine. 1281 DCHECK(tracker_id != GetSyncRootTrackerID() || 1282 (tracker->has_synced_details() && 1283 tracker->synced_details().title() == updated_details.title() && 1284 !updated_details.missing())); 1285 1286 if (tracker_id != GetSyncRootTrackerID()) { 1287 // Check if the tracker's parent is still in |parent_tracker_ids|. 1288 // If not, there should exist another tracker for the new parent, so delete 1289 // old tracker. 1290 const FileTracker* parent_tracker = 1291 index_->GetFileTracker(tracker->parent_tracker_id()); 1292 DCHECK(parent_tracker); 1293 1294 if (!HasFileAsParent(updated_details, parent_tracker->file_id())) { 1295 RemoveFileTracker(tracker->tracker_id(), 1296 MARK_SAME_PATH_TRACKERS_DIRTY, 1297 index_.get(), batch.get()); 1298 WriteToDatabase(batch.Pass(), callback); 1299 return; 1300 } 1301 1302 if (tracker->has_synced_details()) { 1303 // Check if the tracker was retitled. If it was, there should exist 1304 // another tracker for the new title, so delete the tracker being updated. 1305 if (tracker->synced_details().title() != updated_details.title()) { 1306 RemoveFileTracker(tracker->tracker_id(), 1307 MARK_SAME_FILE_ID_TRACKERS_DIRTY, 1308 index_.get(), batch.get()); 1309 WriteToDatabase(batch.Pass(), callback); 1310 return; 1311 } 1312 } else { 1313 // Check if any other tracker exists has the same parent, title and 1314 // file_id to the updated tracker. If it exists, delete the tracker being 1315 // updated. 1316 if (FilterFileTrackersByFileID( 1317 index_.get(), 1318 index_->GetFileTrackerIDsByParentAndTitle( 1319 parent_tracker->tracker_id(), 1320 updated_details.title()), 1321 tracker->file_id())) { 1322 RemoveFileTracker(tracker->tracker_id(), 1323 MARK_NOTHING_DIRTY, 1324 index_.get(), batch.get()); 1325 WriteToDatabase(batch.Pass(), callback); 1326 return; 1327 } 1328 } 1329 } 1330 1331 scoped_ptr<FileTracker> updated_tracker = CloneFileTracker(tracker); 1332 *updated_tracker->mutable_synced_details() = updated_details; 1333 1334 // Activate the tracker if: 1335 // - There is no active tracker that tracks |tracker->file_id()|. 1336 // - There is no active tracker that has the same |parent| and |title|. 1337 if (!tracker->active() && CanActivateTracker(*tracker)) { 1338 updated_tracker->set_active(true); 1339 updated_tracker->set_dirty(true); 1340 updated_tracker->set_needs_folder_listing( 1341 tracker->synced_details().file_kind() == FILE_KIND_FOLDER); 1342 } else if (tracker->dirty() && !ShouldKeepDirty(*tracker)) { 1343 updated_tracker->set_dirty(false); 1344 } 1345 PutFileTrackerToBatch(*tracker, batch.get()); 1346 index_->StoreFileTracker(updated_tracker.Pass()); 1347 1348 WriteToDatabase(batch.Pass(), callback); 1349 } 1350 1351 MetadataDatabase::ActivationStatus MetadataDatabase::TryActivateTracker( 1352 int64 parent_tracker_id, 1353 const std::string& file_id, 1354 const SyncStatusCallback& callback) { 1355 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1356 DCHECK(index_->GetFileTracker(parent_tracker_id)); 1357 1358 const FileMetadata* metadata = index_->GetFileMetadata(file_id); 1359 if (!metadata) { 1360 NOTREACHED(); 1361 worker_task_runner_->PostTask( 1362 FROM_HERE, 1363 base::Bind(callback, SYNC_STATUS_FAILED)); 1364 return ACTIVATION_PENDING; 1365 } 1366 std::string title = metadata->details().title(); 1367 DCHECK(!HasInvalidTitle(title)); 1368 1369 TrackerIDSet same_file_id_trackers = 1370 index_->GetFileTrackerIDsByFileID(file_id); 1371 scoped_ptr<FileTracker> tracker_to_be_activated = 1372 CloneFileTracker(FilterFileTrackersByParentAndTitle( 1373 index_.get(), same_file_id_trackers, 1374 parent_tracker_id, title)); 1375 DCHECK(tracker_to_be_activated); 1376 1377 // Check if there is another active tracker that tracks |file_id|. 1378 // This can happen when the tracked file has multiple parents. 1379 // In this case, report the failure to the caller. 1380 if (!tracker_to_be_activated->active() && same_file_id_trackers.has_active()) 1381 return ACTIVATION_FAILED_ANOTHER_ACTIVE_TRACKER; 1382 1383 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 1384 1385 if (!tracker_to_be_activated->active()) { 1386 // Check if there exists another active tracker that has the same path to 1387 // the tracker. If there is, deactivate it, assuming the caller already 1388 // overrides local file with newly added file, 1389 TrackerIDSet same_title_trackers = 1390 index_->GetFileTrackerIDsByParentAndTitle(parent_tracker_id, title); 1391 if (same_title_trackers.has_active()) { 1392 RemoveAllDescendantTrackers(same_title_trackers.active_tracker(), 1393 index_.get(), batch.get()); 1394 1395 scoped_ptr<FileTracker> tracker_to_be_deactivated = 1396 CloneFileTracker(index_->GetFileTracker( 1397 same_title_trackers.active_tracker())); 1398 if (tracker_to_be_deactivated) { 1399 const std::string file_id = tracker_to_be_deactivated->file_id(); 1400 tracker_to_be_deactivated->set_active(false); 1401 PutFileTrackerToBatch(*tracker_to_be_deactivated, batch.get()); 1402 index_->StoreFileTracker(tracker_to_be_deactivated.Pass()); 1403 1404 MarkTrackersDirtyByFileID(file_id, index_.get(), batch.get()); 1405 } else { 1406 NOTREACHED(); 1407 } 1408 } 1409 } 1410 1411 tracker_to_be_activated->set_dirty(false); 1412 tracker_to_be_activated->set_active(true); 1413 *tracker_to_be_activated->mutable_synced_details() = metadata->details(); 1414 if (tracker_to_be_activated->synced_details().file_kind() == 1415 FILE_KIND_FOLDER) { 1416 tracker_to_be_activated->set_needs_folder_listing(true); 1417 } 1418 tracker_to_be_activated->set_dirty(false); 1419 1420 PutFileTrackerToBatch(*tracker_to_be_activated, batch.get()); 1421 index_->StoreFileTracker(tracker_to_be_activated.Pass()); 1422 1423 WriteToDatabase(batch.Pass(), callback); 1424 return ACTIVATION_PENDING; 1425 } 1426 1427 void MetadataDatabase::LowerTrackerPriority(int64 tracker_id) { 1428 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1429 index_->DemoteDirtyTracker(tracker_id); 1430 } 1431 1432 void MetadataDatabase::PromoteLowerPriorityTrackersToNormal() { 1433 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1434 index_->PromoteDemotedDirtyTrackers(); 1435 } 1436 1437 bool MetadataDatabase::GetNormalPriorityDirtyTracker( 1438 FileTracker* tracker_out) const { 1439 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1440 1441 int64 dirty_tracker_id = index_->PickDirtyTracker(); 1442 if (!dirty_tracker_id) 1443 return false; 1444 1445 if (tracker_out) { 1446 const FileTracker* tracker = 1447 index_->GetFileTracker(dirty_tracker_id); 1448 if (!tracker) { 1449 NOTREACHED(); 1450 return false; 1451 } 1452 *tracker_out = *tracker; 1453 } 1454 return true; 1455 } 1456 1457 bool MetadataDatabase::HasLowPriorityDirtyTracker() const { 1458 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1459 return index_->HasDemotedDirtyTracker(); 1460 } 1461 1462 bool MetadataDatabase::HasDirtyTracker() const { 1463 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1464 return index_->PickDirtyTracker() != kInvalidTrackerID; 1465 } 1466 1467 size_t MetadataDatabase::CountDirtyTracker() const { 1468 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1469 return index_->CountDirtyTracker(); 1470 } 1471 1472 bool MetadataDatabase::GetMultiParentFileTrackers(std::string* file_id_out, 1473 TrackerIDSet* trackers_out) { 1474 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1475 DCHECK(file_id_out); 1476 DCHECK(trackers_out); 1477 1478 std::string file_id = index_->PickMultiTrackerFileID(); 1479 if (file_id.empty()) 1480 return false; 1481 1482 TrackerIDSet trackers = index_->GetFileTrackerIDsByFileID(file_id); 1483 if (trackers.size() <= 1) { 1484 NOTREACHED(); 1485 return false; 1486 } 1487 1488 *file_id_out = file_id; 1489 std::swap(*trackers_out, trackers); 1490 return true; 1491 } 1492 1493 size_t MetadataDatabase::CountFileMetadata() const { 1494 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1495 return index_->CountFileMetadata(); 1496 } 1497 1498 size_t MetadataDatabase::CountFileTracker() const { 1499 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1500 return index_->CountFileTracker(); 1501 } 1502 1503 bool MetadataDatabase::GetConflictingTrackers(TrackerIDSet* trackers_out) { 1504 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1505 DCHECK(trackers_out); 1506 1507 ParentIDAndTitle parent_and_title = index_->PickMultiBackingFilePath(); 1508 if (parent_and_title.parent_id == kInvalidTrackerID) 1509 return false; 1510 1511 TrackerIDSet trackers = index_->GetFileTrackerIDsByParentAndTitle( 1512 parent_and_title.parent_id, parent_and_title.title); 1513 if (trackers.size() <= 1) { 1514 NOTREACHED(); 1515 return false; 1516 } 1517 1518 std::swap(*trackers_out, trackers); 1519 return true; 1520 } 1521 1522 void MetadataDatabase::GetRegisteredAppIDs(std::vector<std::string>* app_ids) { 1523 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1524 DCHECK(app_ids); 1525 *app_ids = index_->GetRegisteredAppIDs(); 1526 } 1527 1528 MetadataDatabase::MetadataDatabase( 1529 base::SequencedTaskRunner* worker_task_runner, 1530 base::SequencedTaskRunner* file_task_runner, 1531 const base::FilePath& database_path, 1532 leveldb::Env* env_override) 1533 : worker_task_runner_(worker_task_runner), 1534 file_task_runner_(file_task_runner), 1535 database_path_(database_path), 1536 env_override_(env_override), 1537 largest_known_change_id_(0), 1538 weak_ptr_factory_(this) { 1539 DCHECK(worker_task_runner); 1540 DCHECK(file_task_runner); 1541 } 1542 1543 // static 1544 void MetadataDatabase::CreateOnFileTaskRunner( 1545 scoped_ptr<CreateParam> create_param, 1546 const CreateCallback& callback) { 1547 scoped_ptr<MetadataDatabase> metadata_database( 1548 new MetadataDatabase(create_param->worker_task_runner.get(), 1549 create_param->file_task_runner.get(), 1550 create_param->database_path, 1551 create_param->env_override)); 1552 SyncStatusCode status = 1553 metadata_database->InitializeOnFileTaskRunner(); 1554 if (status != SYNC_STATUS_OK) 1555 metadata_database.reset(); 1556 1557 metadata_database->DetachFromSequence(); 1558 create_param->worker_task_runner->PostTask( 1559 FROM_HERE, 1560 base::Bind( 1561 callback, status, base::Passed(&metadata_database))); 1562 } 1563 1564 SyncStatusCode MetadataDatabase::InitializeOnFileTaskRunner() { 1565 base::ThreadRestrictions::AssertIOAllowed(); 1566 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 1567 1568 SyncStatusCode status = SYNC_STATUS_UNKNOWN; 1569 bool created = false; 1570 // Open database unless |db_| is overridden for testing. 1571 if (!db_) { 1572 status = OpenDatabase(database_path_, env_override_, &db_, &created); 1573 if (status != SYNC_STATUS_OK) 1574 return status; 1575 } 1576 1577 if (created) { 1578 status = WriteVersionInfo(db_.get()); 1579 if (status != SYNC_STATUS_OK) 1580 return status; 1581 } else { 1582 status = MigrateDatabaseIfNeeded(db_.get()); 1583 if (status != SYNC_STATUS_OK) 1584 return status; 1585 } 1586 1587 DatabaseContents contents; 1588 status = ReadDatabaseContents(db_.get(), &contents); 1589 if (status != SYNC_STATUS_OK) 1590 return status; 1591 1592 leveldb::WriteBatch batch; 1593 status = InitializeServiceMetadata(&contents, &batch); 1594 if (status != SYNC_STATUS_OK) 1595 return status; 1596 1597 status = RemoveUnreachableItems(&contents, &batch); 1598 if (status != SYNC_STATUS_OK) 1599 return status; 1600 1601 status = LevelDBStatusToSyncStatusCode( 1602 db_->Write(leveldb::WriteOptions(), &batch)); 1603 if (status != SYNC_STATUS_OK) 1604 return status; 1605 1606 BuildIndexes(&contents); 1607 return status; 1608 } 1609 1610 void MetadataDatabase::BuildIndexes(DatabaseContents* contents) { 1611 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); 1612 1613 service_metadata_ = contents->service_metadata.Pass(); 1614 UpdateLargestKnownChangeID(service_metadata_->largest_change_id()); 1615 index_.reset(new MetadataDatabaseIndex(contents)); 1616 } 1617 1618 void MetadataDatabase::CreateTrackerForParentAndFileID( 1619 const FileTracker& parent_tracker, 1620 const std::string& file_id, 1621 leveldb::WriteBatch* batch) { 1622 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1623 CreateTrackerInternal(parent_tracker, file_id, NULL, 1624 UPDATE_TRACKER_FOR_UNSYNCED_FILE, 1625 batch); 1626 } 1627 1628 void MetadataDatabase::CreateTrackerForParentAndFileMetadata( 1629 const FileTracker& parent_tracker, 1630 const FileMetadata& file_metadata, 1631 UpdateOption option, 1632 leveldb::WriteBatch* batch) { 1633 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1634 DCHECK(file_metadata.has_details()); 1635 CreateTrackerInternal(parent_tracker, 1636 file_metadata.file_id(), 1637 &file_metadata.details(), 1638 option, 1639 batch); 1640 } 1641 1642 void MetadataDatabase::CreateTrackerInternal(const FileTracker& parent_tracker, 1643 const std::string& file_id, 1644 const FileDetails* details, 1645 UpdateOption option, 1646 leveldb::WriteBatch* batch) { 1647 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1648 1649 int64 tracker_id = IncrementTrackerID(batch); 1650 scoped_ptr<FileTracker> tracker(new FileTracker); 1651 tracker->set_tracker_id(tracker_id); 1652 tracker->set_parent_tracker_id(parent_tracker.tracker_id()); 1653 tracker->set_file_id(file_id); 1654 tracker->set_app_id(parent_tracker.app_id()); 1655 tracker->set_tracker_kind(TRACKER_KIND_REGULAR); 1656 tracker->set_dirty(true); 1657 tracker->set_active(false); 1658 tracker->set_needs_folder_listing(false); 1659 if (details) { 1660 *tracker->mutable_synced_details() = *details; 1661 if (option == UPDATE_TRACKER_FOR_UNSYNCED_FILE) { 1662 tracker->mutable_synced_details()->set_missing(true); 1663 tracker->mutable_synced_details()->clear_md5(); 1664 } 1665 } 1666 PutFileTrackerToBatch(*tracker, batch); 1667 index_->StoreFileTracker(tracker.Pass()); 1668 } 1669 1670 void MetadataDatabase::MaybeAddTrackersForNewFile( 1671 const FileMetadata& metadata, 1672 UpdateOption option, 1673 leveldb::WriteBatch* batch) { 1674 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1675 1676 std::set<int64> parents_to_exclude; 1677 TrackerIDSet existing_trackers = 1678 index_->GetFileTrackerIDsByFileID(metadata.file_id()); 1679 for (TrackerIDSet::const_iterator itr = existing_trackers.begin(); 1680 itr != existing_trackers.end(); ++itr) { 1681 const FileTracker* tracker = index_->GetFileTracker(*itr); 1682 if (!tracker) { 1683 NOTREACHED(); 1684 continue; 1685 } 1686 1687 int64 parent_tracker_id = tracker->parent_tracker_id(); 1688 if (!parent_tracker_id) 1689 continue; 1690 1691 // Exclude |parent_tracker_id| if it already has a tracker that has 1692 // unknown title or has the same title with |file|. 1693 if (!tracker->has_synced_details() || 1694 tracker->synced_details().title() == metadata.details().title()) { 1695 parents_to_exclude.insert(parent_tracker_id); 1696 } 1697 } 1698 1699 for (int i = 0; i < metadata.details().parent_folder_ids_size(); ++i) { 1700 std::string parent_folder_id = metadata.details().parent_folder_ids(i); 1701 TrackerIDSet parent_trackers = 1702 index_->GetFileTrackerIDsByFileID(parent_folder_id); 1703 for (TrackerIDSet::const_iterator itr = parent_trackers.begin(); 1704 itr != parent_trackers.end(); ++itr) { 1705 const FileTracker* parent_tracker = index_->GetFileTracker(*itr); 1706 if (!parent_tracker->active()) 1707 continue; 1708 1709 if (ContainsKey(parents_to_exclude, parent_tracker->tracker_id())) 1710 continue; 1711 1712 CreateTrackerForParentAndFileMetadata( 1713 *parent_tracker, metadata, option, batch); 1714 } 1715 } 1716 } 1717 1718 int64 MetadataDatabase::IncrementTrackerID(leveldb::WriteBatch* batch) { 1719 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1720 1721 int64 tracker_id = service_metadata_->next_tracker_id(); 1722 service_metadata_->set_next_tracker_id(tracker_id + 1); 1723 PutServiceMetadataToBatch(*service_metadata_, batch); 1724 DCHECK_GT(tracker_id, 0); 1725 return tracker_id; 1726 } 1727 1728 bool MetadataDatabase::CanActivateTracker(const FileTracker& tracker) { 1729 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1730 DCHECK(!tracker.active()); 1731 DCHECK_NE(service_metadata_->sync_root_tracker_id(), tracker.tracker_id()); 1732 1733 if (HasActiveTrackerForFileID(tracker.file_id())) 1734 return false; 1735 1736 if (tracker.app_id().empty() && 1737 tracker.tracker_id() != GetSyncRootTrackerID()) { 1738 return false; 1739 } 1740 1741 if (!tracker.has_synced_details()) 1742 return false; 1743 if (tracker.synced_details().file_kind() == FILE_KIND_UNSUPPORTED) 1744 return false; 1745 if (HasInvalidTitle(tracker.synced_details().title())) 1746 return false; 1747 DCHECK(tracker.parent_tracker_id()); 1748 1749 return !HasActiveTrackerForPath(tracker.parent_tracker_id(), 1750 tracker.synced_details().title()); 1751 } 1752 1753 bool MetadataDatabase::ShouldKeepDirty(const FileTracker& tracker) const { 1754 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1755 1756 if (HasDisabledAppRoot(tracker)) 1757 return false; 1758 1759 DCHECK(tracker.dirty()); 1760 if (!tracker.has_synced_details()) 1761 return true; 1762 1763 const FileMetadata* metadata = index_->GetFileMetadata(tracker.file_id()); 1764 if (!metadata) 1765 return true; 1766 DCHECK(metadata); 1767 DCHECK(metadata->has_details()); 1768 1769 const FileDetails& local_details = tracker.synced_details(); 1770 const FileDetails& remote_details = metadata->details(); 1771 1772 if (tracker.active()) { 1773 if (tracker.needs_folder_listing()) 1774 return true; 1775 if (local_details.md5() != remote_details.md5()) 1776 return true; 1777 if (local_details.missing() != remote_details.missing()) 1778 return true; 1779 } 1780 1781 if (local_details.title() != remote_details.title()) 1782 return true; 1783 1784 return false; 1785 } 1786 1787 bool MetadataDatabase::HasDisabledAppRoot(const FileTracker& tracker) const { 1788 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1789 1790 int64 app_root_tracker_id = index_->GetAppRootTracker(tracker.app_id()); 1791 if (app_root_tracker_id == kInvalidTrackerID) 1792 return false; 1793 1794 const FileTracker* app_root_tracker = 1795 index_->GetFileTracker(app_root_tracker_id); 1796 if (!app_root_tracker) { 1797 NOTREACHED(); 1798 return false; 1799 } 1800 return app_root_tracker->tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT; 1801 } 1802 1803 bool MetadataDatabase::HasActiveTrackerForFileID( 1804 const std::string& file_id) const { 1805 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1806 return index_->GetFileTrackerIDsByFileID(file_id).has_active(); 1807 } 1808 1809 bool MetadataDatabase::HasActiveTrackerForPath(int64 parent_tracker_id, 1810 const std::string& title) const { 1811 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1812 return index_->GetFileTrackerIDsByParentAndTitle(parent_tracker_id, title) 1813 .has_active(); 1814 } 1815 1816 void MetadataDatabase::RemoveUnneededTrackersForMissingFile( 1817 const std::string& file_id, 1818 leveldb::WriteBatch* batch) { 1819 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1820 1821 TrackerIDSet trackers = index_->GetFileTrackerIDsByFileID(file_id); 1822 for (TrackerIDSet::const_iterator itr = trackers.begin(); 1823 itr != trackers.end(); ++itr) { 1824 const FileTracker* tracker = index_->GetFileTracker(*itr); 1825 if (!tracker) { 1826 NOTREACHED(); 1827 continue; 1828 } 1829 1830 if (!tracker->has_synced_details() || 1831 tracker->synced_details().missing()) { 1832 RemoveFileTracker(*itr, MARK_NOTHING_DIRTY, index_.get(), batch); 1833 } 1834 } 1835 } 1836 1837 void MetadataDatabase::UpdateByFileMetadata( 1838 const tracked_objects::Location& from_where, 1839 scoped_ptr<FileMetadata> metadata, 1840 UpdateOption option, 1841 leveldb::WriteBatch* batch) { 1842 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1843 DCHECK(metadata); 1844 DCHECK(metadata->has_details()); 1845 1846 DVLOG(1) << from_where.function_name() << ": " 1847 << metadata->file_id() << " (" 1848 << metadata->details().title() << ")" 1849 << (metadata->details().missing() ? " deleted" : ""); 1850 1851 std::string file_id = metadata->file_id(); 1852 if (metadata->details().missing()) 1853 RemoveUnneededTrackersForMissingFile(file_id, batch); 1854 else 1855 MaybeAddTrackersForNewFile(*metadata, option, batch); 1856 1857 TrackerIDSet trackers = index_->GetFileTrackerIDsByFileID(file_id); 1858 if (!trackers.empty()) { 1859 PutFileMetadataToBatch(*metadata, batch); 1860 index_->StoreFileMetadata(metadata.Pass()); 1861 1862 if (option != UPDATE_TRACKER_FOR_SYNCED_FILE) 1863 MarkTrackerSetDirty(trackers, index_.get(), batch); 1864 } 1865 } 1866 1867 void MetadataDatabase::WriteToDatabase(scoped_ptr<leveldb::WriteBatch> batch, 1868 const SyncStatusCallback& callback) { 1869 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1870 1871 if (!batch) { 1872 worker_task_runner_->PostTask( 1873 FROM_HERE, 1874 base::Bind(callback, SYNC_STATUS_OK)); 1875 return; 1876 } 1877 1878 file_task_runner_->PostTask( 1879 FROM_HERE, 1880 base::Bind(&WriteOnFileTaskRunner, 1881 base::Unretained(db_.get()), 1882 base::Passed(&batch), 1883 worker_task_runner_, 1884 callback)); 1885 } 1886 1887 scoped_ptr<base::ListValue> MetadataDatabase::DumpFiles( 1888 const std::string& app_id) { 1889 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1890 1891 scoped_ptr<base::ListValue> files(new base::ListValue); 1892 1893 FileTracker app_root_tracker; 1894 if (!FindAppRootTracker(app_id, &app_root_tracker)) 1895 return files.Pass(); 1896 1897 std::vector<int64> stack; 1898 AppendContents( 1899 index_->GetFileTrackerIDsByParent(app_root_tracker.tracker_id()), &stack); 1900 while (!stack.empty()) { 1901 int64 tracker_id = stack.back(); 1902 stack.pop_back(); 1903 AppendContents(index_->GetFileTrackerIDsByParent(tracker_id), &stack); 1904 1905 const FileTracker* tracker = index_->GetFileTracker(tracker_id); 1906 if (!tracker) { 1907 NOTREACHED(); 1908 continue; 1909 } 1910 base::DictionaryValue* file = new base::DictionaryValue; 1911 1912 base::FilePath path = BuildDisplayPathForTracker(*tracker); 1913 file->SetString("path", path.AsUTF8Unsafe()); 1914 if (tracker->has_synced_details()) { 1915 file->SetString("title", tracker->synced_details().title()); 1916 file->SetString("type", 1917 FileKindToString(tracker->synced_details().file_kind())); 1918 } 1919 1920 base::DictionaryValue* details = new base::DictionaryValue; 1921 details->SetString("file_id", tracker->file_id()); 1922 if (tracker->has_synced_details() && 1923 tracker->synced_details().file_kind() == FILE_KIND_FILE) 1924 details->SetString("md5", tracker->synced_details().md5()); 1925 details->SetString("active", tracker->active() ? "true" : "false"); 1926 details->SetString("dirty", tracker->dirty() ? "true" : "false"); 1927 1928 file->Set("details", details); 1929 1930 files->Append(file); 1931 } 1932 1933 return files.Pass(); 1934 } 1935 1936 scoped_ptr<base::ListValue> MetadataDatabase::DumpDatabase() { 1937 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1938 1939 scoped_ptr<base::ListValue> list(new base::ListValue); 1940 list->Append(DumpTrackers().release()); 1941 list->Append(DumpMetadata().release()); 1942 return list.Pass(); 1943 } 1944 1945 bool MetadataDatabase::HasNewerFileMetadata(const std::string& file_id, 1946 int64 change_id) { 1947 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1948 1949 const FileMetadata* metadata = index_->GetFileMetadata(file_id); 1950 if (!metadata) 1951 return false; 1952 DCHECK(metadata->has_details()); 1953 return metadata->details().change_id() >= change_id; 1954 } 1955 1956 scoped_ptr<base::ListValue> MetadataDatabase::DumpTrackers() { 1957 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 1958 1959 scoped_ptr<base::ListValue> trackers(new base::ListValue); 1960 1961 // Append the first element for metadata. 1962 base::DictionaryValue* metadata = new base::DictionaryValue; 1963 const char *trackerKeys[] = { 1964 "tracker_id", "path", "file_id", "tracker_kind", "app_id", 1965 "active", "dirty", "folder_listing", 1966 "title", "kind", "md5", "etag", "missing", "change_id", 1967 }; 1968 std::vector<std::string> key_strings( 1969 trackerKeys, trackerKeys + ARRAYSIZE_UNSAFE(trackerKeys)); 1970 base::ListValue* keys = new base::ListValue; 1971 keys->AppendStrings(key_strings); 1972 metadata->SetString("title", "Trackers"); 1973 metadata->Set("keys", keys); 1974 trackers->Append(metadata); 1975 1976 // Append tracker data. 1977 std::vector<int64> tracker_ids(index_->GetAllTrackerIDs()); 1978 for (std::vector<int64>::const_iterator itr = tracker_ids.begin(); 1979 itr != tracker_ids.end(); ++itr) { 1980 const int64 tracker_id = *itr; 1981 const FileTracker* tracker = index_->GetFileTracker(tracker_id); 1982 if (!tracker) { 1983 NOTREACHED(); 1984 continue; 1985 } 1986 1987 base::DictionaryValue* dict = new base::DictionaryValue; 1988 base::FilePath path = BuildDisplayPathForTracker(*tracker); 1989 dict->SetString("tracker_id", base::Int64ToString(tracker_id)); 1990 dict->SetString("path", path.AsUTF8Unsafe()); 1991 dict->SetString("file_id", tracker->file_id()); 1992 TrackerKind tracker_kind = tracker->tracker_kind(); 1993 dict->SetString( 1994 "tracker_kind", 1995 tracker_kind == TRACKER_KIND_APP_ROOT ? "AppRoot" : 1996 tracker_kind == TRACKER_KIND_DISABLED_APP_ROOT ? "Disabled App" : 1997 tracker->tracker_id() == GetSyncRootTrackerID() ? "SyncRoot" : 1998 "Regular"); 1999 dict->SetString("app_id", tracker->app_id()); 2000 dict->SetString("active", tracker->active() ? "true" : "false"); 2001 dict->SetString("dirty", tracker->dirty() ? "true" : "false"); 2002 dict->SetString("folder_listing", 2003 tracker->needs_folder_listing() ? "needed" : "no"); 2004 if (tracker->has_synced_details()) { 2005 const FileDetails& details = tracker->synced_details(); 2006 dict->SetString("title", details.title()); 2007 dict->SetString("kind", FileKindToString(details.file_kind())); 2008 dict->SetString("md5", details.md5()); 2009 dict->SetString("etag", details.etag()); 2010 dict->SetString("missing", details.missing() ? "true" : "false"); 2011 dict->SetString("change_id", base::Int64ToString(details.change_id())); 2012 } 2013 trackers->Append(dict); 2014 } 2015 return trackers.Pass(); 2016 } 2017 2018 scoped_ptr<base::ListValue> MetadataDatabase::DumpMetadata() { 2019 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 2020 2021 scoped_ptr<base::ListValue> files(new base::ListValue); 2022 2023 // Append the first element for metadata. 2024 base::DictionaryValue* metadata = new base::DictionaryValue; 2025 const char *fileKeys[] = { 2026 "file_id", "title", "type", "md5", "etag", "missing", 2027 "change_id", "parents" 2028 }; 2029 std::vector<std::string> key_strings( 2030 fileKeys, fileKeys + ARRAYSIZE_UNSAFE(fileKeys)); 2031 base::ListValue* keys = new base::ListValue; 2032 keys->AppendStrings(key_strings); 2033 metadata->SetString("title", "Metadata"); 2034 metadata->Set("keys", keys); 2035 files->Append(metadata); 2036 2037 // Append metadata data. 2038 std::vector<std::string> metadata_ids(index_->GetAllMetadataIDs()); 2039 for (std::vector<std::string>::const_iterator itr = metadata_ids.begin(); 2040 itr != metadata_ids.end(); ++itr) { 2041 const std::string& file_id = *itr; 2042 const FileMetadata *file = index_->GetFileMetadata(file_id); 2043 if (!file) { 2044 NOTREACHED(); 2045 continue; 2046 } 2047 2048 base::DictionaryValue* dict = new base::DictionaryValue; 2049 dict->SetString("file_id", file_id); 2050 if (file->has_details()) { 2051 const FileDetails& details = file->details(); 2052 dict->SetString("title", details.title()); 2053 dict->SetString("type", FileKindToString(details.file_kind())); 2054 dict->SetString("md5", details.md5()); 2055 dict->SetString("etag", details.etag()); 2056 dict->SetString("missing", details.missing() ? "true" : "false"); 2057 dict->SetString("change_id", base::Int64ToString(details.change_id())); 2058 2059 std::vector<std::string> parents; 2060 for (int i = 0; i < details.parent_folder_ids_size(); ++i) 2061 parents.push_back(details.parent_folder_ids(i)); 2062 dict->SetString("parents", JoinString(parents, ",")); 2063 } 2064 files->Append(dict); 2065 } 2066 return files.Pass(); 2067 } 2068 2069 void MetadataDatabase::AttachSyncRoot( 2070 const google_apis::FileResource& sync_root_folder, 2071 leveldb::WriteBatch* batch) { 2072 DCHECK(worker_sequence_checker_.CalledOnValidSequencedThread()); 2073 2074 scoped_ptr<FileMetadata> sync_root_metadata = 2075 CreateFileMetadataFromFileResource( 2076 GetLargestKnownChangeID(), sync_root_folder); 2077 scoped_ptr<FileTracker> sync_root_tracker = 2078 CreateSyncRootTracker(IncrementTrackerID(batch), *sync_root_metadata); 2079 2080 PutFileMetadataToBatch(*sync_root_metadata, batch); 2081 PutFileTrackerToBatch(*sync_root_tracker, batch); 2082 2083 service_metadata_->set_sync_root_tracker_id(sync_root_tracker->tracker_id()); 2084 PutServiceMetadataToBatch(*service_metadata_, batch); 2085 2086 index_->StoreFileMetadata(sync_root_metadata.Pass()); 2087 index_->StoreFileTracker(sync_root_tracker.Pass()); 2088 } 2089 2090 void MetadataDatabase::AttachInitialAppRoot( 2091 const google_apis::FileResource& app_root_folder, 2092 leveldb::WriteBatch* batch) { 2093 scoped_ptr<FileMetadata> app_root_metadata = 2094 CreateFileMetadataFromFileResource( 2095 GetLargestKnownChangeID(), app_root_folder); 2096 scoped_ptr<FileTracker> app_root_tracker = 2097 CreateInitialAppRootTracker(IncrementTrackerID(batch), 2098 GetSyncRootTrackerID(), 2099 *app_root_metadata); 2100 2101 PutFileMetadataToBatch(*app_root_metadata, batch); 2102 PutFileTrackerToBatch(*app_root_tracker, batch); 2103 2104 index_->StoreFileMetadata(app_root_metadata.Pass()); 2105 index_->StoreFileTracker(app_root_tracker.Pass()); 2106 } 2107 2108 void MetadataDatabase::DetachFromSequence() { 2109 worker_sequence_checker_.DetachFromSequence(); 2110 } 2111 2112 } // namespace drive_backend 2113 } // namespace sync_file_system 2114