metadata_database.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
1cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com// Copyright 2013 The Chromium Authors. All rights reserved. 2cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com// Use of this source code is governed by a BSD-style license that can be 3cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com// found in the LICENSE file. 4cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com 5cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com#include "chrome/browser/sync_file_system/drive_backend/metadata_database.h" 6cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com 7cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com#include <algorithm> 8cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com#include <stack> 9cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com 108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/bind.h" 118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/callback.h" 128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/files/file_path.h" 138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/location.h" 148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/memory/scoped_vector.h" 158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/message_loop/message_loop_proxy.h" 168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/sequenced_task_runner.h" 178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/stl_util.h" 188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/strings/string_number_conversions.h" 198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/strings/string_util.h" 208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/strings/stringprintf.h" 218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/task_runner_util.h" 228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/threading/thread_restrictions.h" 238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chrome/browser/drive/drive_api_util.h" 248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chrome/browser/google_apis/drive_api_parser.h" 258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chrome/browser/google_apis/drive_entry_kinds.h" 268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h" 278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.h" 288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chrome/browser/sync_file_system/logger.h" 298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chrome/browser/sync_file_system/syncable_file_system_util.h" 308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "third_party/leveldatabase/src/include/leveldb/db.h" 318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "webkit/common/fileapi/file_system_util.h" 338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comnamespace sync_file_system { 358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comnamespace drive_backend { 368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char kDatabaseVersionKey[] = "VERSION"; 388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst int64 kCurrentDatabaseVersion = 3; 398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char kServiceMetadataKey[] = "SERVICE"; 408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char kFileMetadataKeyPrefix[] = "FILE: "; 418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char kFileTrackerKeyPrefix[] = "TRACKER: "; 428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstruct DatabaseContents { 448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com scoped_ptr<ServiceMetadata> service_metadata; 458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ScopedVector<FileMetadata> file_metadata; 468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ScopedVector<FileTracker> file_trackers; 478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}; 488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comnamespace { 508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comtypedef MetadataDatabase::FileByID FileByID; 528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comtypedef MetadataDatabase::TrackerByID TrackerByID; 538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comtypedef MetadataDatabase::TrackersByParentAndTitle TrackersByParentAndTitle; 548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comtypedef MetadataDatabase::TrackersByTitle TrackersByTitle; 558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.combool IsAppRoot(const FileTracker& tracker) { 578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return tracker.tracker_kind() == TRACKER_KIND_APP_ROOT || 588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com tracker.tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT; 598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstd::string RemovePrefix(const std::string& str, const std::string& prefix) { 628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (StartsWithASCII(str, prefix, true)) 638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return str.substr(prefix.size()); 648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return str; 658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.combase::FilePath ReverseConcatPathComponents( 688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com const std::vector<base::FilePath>& components) { 698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (components.empty()) 708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return base::FilePath(FILE_PATH_LITERAL("/")).NormalizePathSeparators(); 718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com size_t total_size = 0; 738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com typedef std::vector<base::FilePath> PathComponents; 748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com for (PathComponents::const_iterator itr = components.begin(); 758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com itr != components.end(); ++itr) 768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com total_size += itr->value().size() + 1; 778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com base::FilePath::StringType result; 798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com result.reserve(total_size); 808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com for (PathComponents::const_reverse_iterator itr = components.rbegin(); 818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com itr != components.rend(); ++itr) { 828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com result.append(1, base::FilePath::kSeparators[0]); 838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com result.append(itr->value()); 848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return base::FilePath(result).NormalizePathSeparators(); 878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid PopulateFileDetailsByFileResource( 908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com const google_apis::FileResource& file_resource, 918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com FileDetails* details) { 928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com details->clear_parent_folder_ids(); 938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com for (ScopedVector<google_apis::ParentReference>::const_iterator itr = 948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com file_resource.parents().begin(); 958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com itr != file_resource.parents().end(); 968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ++itr) { 978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com details->add_parent_folder_ids((*itr)->file_id()); 988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com details->set_title(file_resource.title()); 1008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com google_apis::DriveEntryKind kind = drive::util::GetKind(file_resource); 1028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (kind == google_apis::ENTRY_KIND_FILE) 1038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com details->set_file_kind(FILE_KIND_FILE); 1048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com else if (kind == google_apis::ENTRY_KIND_FOLDER) 1058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com details->set_file_kind(FILE_KIND_FOLDER); 1068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com else 1078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com details->set_file_kind(FILE_KIND_UNSUPPORTED); 1088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com details->set_md5(file_resource.md5_checksum()); 1108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com details->set_etag(file_resource.etag()); 1118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com details->set_creation_time(file_resource.created_date().ToInternalValue()); 1128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com details->set_modification_time( 1138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com file_resource.modified_date().ToInternalValue()); 1148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com details->set_deleted(false); 1158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 1168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comscoped_ptr<FileMetadata> CreateFileMetadataFromChangeResource( 1188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com const google_apis::ChangeResource& change) { 1198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com scoped_ptr<FileMetadata> file(new FileMetadata); 1208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com file->set_file_id(change.file_id()); 1218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com FileDetails* details = file->mutable_details(); 1238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com details->set_change_id(change.change_id()); 1248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (change.is_deleted()) { 1268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com details->set_deleted(true); 1278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return file.Pass(); 1288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 1298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com PopulateFileDetailsByFileResource(*change.file(), details); 1318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return file.Pass(); 1328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 1338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid CreateInitialSyncRootTracker( 1358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com int64 tracker_id, 1368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com const google_apis::FileResource& file_resource, 1378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com scoped_ptr<FileMetadata>* file_out, 1388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com scoped_ptr<FileTracker>* tracker_out) { 1398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com FileDetails details; 1408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com PopulateFileDetailsByFileResource(file_resource, &details); 1418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com scoped_ptr<FileMetadata> file(new FileMetadata); 1438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com file->set_file_id(file_resource.file_id()); 1448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *file->mutable_details() = details; 1458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com scoped_ptr<FileTracker> tracker(new FileTracker); 1478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com tracker->set_tracker_id(tracker_id); 1488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com tracker->set_file_id(file_resource.file_id()); 1498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com tracker->set_parent_tracker_id(0); 1508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com tracker->set_tracker_kind(TRACKER_KIND_REGULAR); 1518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com tracker->set_dirty(false); 1528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com tracker->set_active(true); 1538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com tracker->set_needs_folder_listing(false); 1548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *tracker->mutable_synced_details() = details; 1558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *file_out = file.Pass(); 1578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *tracker_out = tracker.Pass(); 1588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 1598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid CreateInitialAppRootTracker( 1618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com int64 tracker_id, 1628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com const FileTracker& parent_tracker, 1638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com const google_apis::FileResource& file_resource, 1648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com scoped_ptr<FileMetadata>* file_out, 1658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com scoped_ptr<FileTracker>* tracker_out) { 1668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com FileDetails details; 1678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com PopulateFileDetailsByFileResource(file_resource, &details); 1688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com scoped_ptr<FileMetadata> file(new FileMetadata); 1708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com file->set_file_id(file_resource.file_id()); 1718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *file->mutable_details() = details; 1728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com scoped_ptr<FileTracker> tracker(new FileTracker); 1748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com tracker->set_tracker_id(tracker_id); 1758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com tracker->set_parent_tracker_id(parent_tracker.tracker_id()); 1768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com tracker->set_file_id(file_resource.file_id()); 1778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com tracker->set_tracker_kind(TRACKER_KIND_REGULAR); 1788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com tracker->set_dirty(false); 1798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com tracker->set_active(false); 1808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com tracker->set_needs_folder_listing(false); 1818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *tracker->mutable_synced_details() = details; 1828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *file_out = file.Pass(); 1848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *tracker_out = tracker.Pass(); 1858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 1868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid AdaptLevelDBStatusToSyncStatusCode(const SyncStatusCallback& callback, 1888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com const leveldb::Status& status) { 1898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com callback.Run(LevelDBStatusToSyncStatusCode(status)); 1908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 1918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 1928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid PutServiceMetadataToBatch(const ServiceMetadata& service_metadata, 1938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com leveldb::WriteBatch* batch) { 1948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com std::string value; 1958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com bool success = service_metadata.SerializeToString(&value); 1968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com DCHECK(success); 1978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com batch->Put(kServiceMetadataKey, value); 1988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 1998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid PutFileToBatch(const FileMetadata& file, leveldb::WriteBatch* batch) { 2018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com std::string value; 2028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com bool success = file.SerializeToString(&value); 2038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com DCHECK(success); 2048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com batch->Put(kFileMetadataKeyPrefix + file.file_id(), value); 2058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 2068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid PutTrackerToBatch(const FileTracker& tracker, leveldb::WriteBatch* batch) { 2088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com std::string value; 2098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com bool success = tracker.SerializeToString(&value); 2108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com DCHECK(success); 2118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com batch->Put(kFileTrackerKeyPrefix + base::Int64ToString(tracker.tracker_id()), 2128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com value); 2138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 2148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid PutFileDeletionToBatch(const std::string& file_id, 2168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com leveldb::WriteBatch* batch) { 2178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com batch->Delete(kFileMetadataKeyPrefix + file_id); 2188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 2198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid PutTrackerDeletionToBatch(int64 tracker_id, leveldb::WriteBatch* batch) { 2218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com batch->Delete(kFileTrackerKeyPrefix + base::Int64ToString(tracker_id)); 2228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 2238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comtemplate <typename OutputIterator> 2258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comOutputIterator PushChildTrackersToContainer( 2268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com const TrackersByParentAndTitle& trackers_by_parent, 2278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com int64 parent_tracker_id, 2288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com OutputIterator target_itr) { 2298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com TrackersByParentAndTitle::const_iterator found = 2308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com trackers_by_parent.find(parent_tracker_id); 2318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (found == trackers_by_parent.end()) 2328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return target_itr; 2338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com for (TrackersByTitle::const_iterator title_itr = found->second.begin(); 2358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com title_itr != found->second.end(); ++title_itr) { 2368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com const TrackerSet& trackers = title_itr->second; 2378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com for (TrackerSet::const_iterator tracker_itr = trackers.begin(); 2388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com tracker_itr != trackers.end(); ++tracker_itr) { 2398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *target_itr = (*tracker_itr)->tracker_id(); 2408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ++target_itr; 2418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 2428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 2438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return target_itr; 2448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 2458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstd::string GetTrackerTitle(const FileTracker& tracker) { 2478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (tracker.has_synced_details()) 2488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return tracker.synced_details().title(); 2498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return std::string(); 2508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 2518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// Returns true if |db| has no content. 2538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.combool IsDatabaseEmpty(leveldb::DB* db) { 2548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com DCHECK(db); 2558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions())); 2568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com itr->SeekToFirst(); 2578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return !itr->Valid(); 2588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 2598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comSyncStatusCode OpenDatabase(const base::FilePath& path, 2618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com scoped_ptr<leveldb::DB>* db_out, 2628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com bool* created) { 2638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com base::ThreadRestrictions::AssertIOAllowed(); 2648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com DCHECK(db_out); 2658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com DCHECK(created); 2668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com leveldb::Options options; 2688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com options.max_open_files = 0; // Use minimum. 2698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com options.create_if_missing = true; 2708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com leveldb::DB* db = NULL; 2718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com leveldb::Status db_status = 2728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com leveldb::DB::Open(options, path.AsUTF8Unsafe(), &db); 2738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com SyncStatusCode status = LevelDBStatusToSyncStatusCode(db_status); 2748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (status != SYNC_STATUS_OK) { 2758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com delete db; 2768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return status; 2778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 2788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *created = IsDatabaseEmpty(db); 2808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com db_out->reset(db); 2818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return status; 2828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 2838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comSyncStatusCode MigrateDatabaseIfNeeded(leveldb::DB* db) { 2858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com base::ThreadRestrictions::AssertIOAllowed(); 2868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com DCHECK(db); 2878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com std::string value; 2888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com leveldb::Status status = 2898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com db->Get(leveldb::ReadOptions(), kDatabaseVersionKey, &value); 2908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com int64 version = 0; 2918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (status.ok()) { 2928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!base::StringToInt64(value, &version)) 2938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return SYNC_DATABASE_ERROR_FAILED; 2948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } else { 2958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!status.IsNotFound()) 2968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return SYNC_DATABASE_ERROR_FAILED; 2978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 2988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 2998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com switch (version) { 3008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com case 0: 3018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com drive_backend::MigrateDatabaseFromV0ToV1(db); 3028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // fall-through 3038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com case 1: 3048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com drive_backend::MigrateDatabaseFromV1ToV2(db); 3058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // fall-through 3068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com case 2: 3078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // TODO(tzik): Migrate database from version 2 to 3. 3088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // * Add sync-root folder as active, dirty and needs_folder_listing 3098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // folder. 3108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // * Add app-root folders for each origins. Each app-root folder for 3118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // an enabled origin should be a active, dirty and 3128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // needs_folder_listing folder. And Each app-root folder for a 3138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // disabled origin should be an inactive, dirty and 3148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // non-needs_folder_listing folder. 3158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // * Add a file metadata for each file in previous version. 3168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com NOTIMPLEMENTED(); 3178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return SYNC_DATABASE_ERROR_FAILED; 3188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // fall-through 3198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com case 3: 3208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com DCHECK_EQ(3, kCurrentDatabaseVersion); 3218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return SYNC_STATUS_OK; 3228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com default: 3238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return SYNC_DATABASE_ERROR_FAILED; 3248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 3258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 3268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comSyncStatusCode WriteVersionInfo(leveldb::DB* db) { 3288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com base::ThreadRestrictions::AssertIOAllowed(); 3298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com DCHECK(db); 3308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return LevelDBStatusToSyncStatusCode( 3318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com db->Put(leveldb::WriteOptions(), 3328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com kDatabaseVersionKey, 3338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com base::Int64ToString(kCurrentDatabaseVersion))); 3348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 3358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comSyncStatusCode ReadDatabaseContents(leveldb::DB* db, 3378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com DatabaseContents* contents) { 3388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com base::ThreadRestrictions::AssertIOAllowed(); 3398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com DCHECK(db); 3408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com DCHECK(contents); 3418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions())); 3438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com for (itr->SeekToFirst(); itr->Valid(); itr->Next()) { 3448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com std::string key = itr->key().ToString(); 3458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com std::string value = itr->value().ToString(); 3468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (key == kServiceMetadataKey) { 3478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com scoped_ptr<ServiceMetadata> service_metadata(new ServiceMetadata); 3488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!service_metadata->ParseFromString(value)) { 3498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com util::Log(logging::LOG_WARNING, FROM_HERE, 3508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com "Failed to parse SyncServiceMetadata"); 3518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com continue; 3528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 3538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com contents->service_metadata = service_metadata.Pass(); 3558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com continue; 3568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 3578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (StartsWithASCII(key, kFileMetadataKeyPrefix, true)) { 3598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com std::string file_id = RemovePrefix(key, kFileMetadataKeyPrefix); 3608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com scoped_ptr<FileMetadata> file(new FileMetadata); 3628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!file->ParseFromString(itr->value().ToString())) { 3638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com util::Log(logging::LOG_WARNING, FROM_HERE, 3648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com "Failed to parse a FileMetadata"); 3658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com continue; 3668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 3678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com contents->file_metadata.push_back(file.release()); 3698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com continue; 3708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 3718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (StartsWithASCII(key, kFileTrackerKeyPrefix, true)) { 3738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com int64 tracker_id = 0; 3748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!base::StringToInt64(RemovePrefix(key, kFileTrackerKeyPrefix), 3758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com &tracker_id)) { 3768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com util::Log(logging::LOG_WARNING, FROM_HERE, 3778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com "Failed to parse TrackerID"); 3788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com continue; 3798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 3808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com scoped_ptr<FileTracker> tracker(new FileTracker); 3828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!tracker->ParseFromString(itr->value().ToString())) { 3838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com util::Log(logging::LOG_WARNING, FROM_HERE, 3848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com "Failed to parse a Tracker"); 3858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com continue; 3868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 3878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com contents->file_trackers.push_back(tracker.release()); 3888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com continue; 3898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 3908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 3918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return SYNC_STATUS_OK; 3938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 3948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 3958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comSyncStatusCode InitializeServiceMetadata(DatabaseContents* contents, 3968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com leveldb::WriteBatch* batch) { 3978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!contents->service_metadata) { 3988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com contents->service_metadata.reset(new ServiceMetadata); 3998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com contents->service_metadata->set_next_tracker_id(1); 4008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com std::string value; 4028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com contents->service_metadata->SerializeToString(&value); 4038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com batch->Put(kServiceMetadataKey, value); 4048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 4058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return SYNC_STATUS_OK; 4068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 4078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comSyncStatusCode RemoveUnreachableItems(DatabaseContents* contents, 4098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com leveldb::WriteBatch* batch) { 4108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com TrackerByID unvisited_trackers; 4118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com typedef std::map<int64, std::set<FileTracker*> > TrackersByParent; 4128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com TrackersByParent trackers_by_parent; 4138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com for (ScopedVector<FileTracker>::iterator itr = 4158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com contents->file_trackers.begin(); 4168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com itr != contents->file_trackers.end(); 4178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ++itr) { 4188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com FileTracker* tracker = *itr; 4198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com DCHECK(!ContainsKey(unvisited_trackers, tracker->tracker_id())); 4208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com unvisited_trackers[tracker->tracker_id()] = tracker; 4218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (tracker->parent_tracker_id()) 4228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com trackers_by_parent[tracker->parent_tracker_id()].insert(tracker); 4238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 4248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // Traverse synced tracker tree. Take only active items, app-root and their 4268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // children. Drop unreachable items. 4278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ScopedVector<FileTracker> reachable_trackers; 4288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com std::stack<int64> pending; 4298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (contents->service_metadata->sync_root_tracker_id()) 4308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com pending.push(contents->service_metadata->sync_root_tracker_id()); 4318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com while (!pending.empty()) { 4338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com int64 tracker_id = pending.top(); 4348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com pending.pop(); 4358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com { 4378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com TrackerByID::iterator found = unvisited_trackers.find(tracker_id); 4388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (found == unvisited_trackers.end()) 4398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com continue; 4408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com FileTracker* tracker = found->second; 4428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com unvisited_trackers.erase(found); 4438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com reachable_trackers.push_back(tracker); 4448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (!tracker->active()) 4468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com continue; 4478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 4488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com TrackersByParent::iterator found = trackers_by_parent.find(tracker_id); 4508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (found == trackers_by_parent.end()) 4518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com continue; 4528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com for (std::set<FileTracker*>::const_iterator itr = 4548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com found->second.begin(); 4558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com itr != found->second.end(); 4568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ++itr) 4578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com pending.push((*itr)->tracker_id()); 4588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 4598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // Delete all unreachable trackers. 4618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com for (TrackerByID::iterator itr = unvisited_trackers.begin(); 4628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com itr != unvisited_trackers.end(); ++itr) { 4638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com FileTracker* tracker = itr->second; 4648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com PutTrackerDeletionToBatch(tracker->tracker_id(), batch); 4658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com delete tracker; 4668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 4678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com unvisited_trackers.clear(); 4688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // |reachable_trackers| contains all files/folders reachable from sync-root 4708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // folder via active folders and app-root folders. 4718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // Update the tracker set in database contents with the reachable tracker set. 4728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com contents->file_trackers.weak_clear(); 4738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com contents->file_trackers.swap(reachable_trackers); 4748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // Do the similar traverse for FileMetadata and remove FileMetadata that don't 4768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com // have reachable trackers. 4778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com FileByID unreferred_files; 4788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com for (ScopedVector<FileMetadata>::const_iterator itr = 4798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com contents->file_metadata.begin(); 4808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com itr != contents->file_metadata.end(); 4818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ++itr) { 4828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com unreferred_files.insert(std::make_pair((*itr)->file_id(), *itr)); 4838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 4848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ScopedVector<FileMetadata> referred_files; 4868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com for (ScopedVector<FileTracker>::const_iterator itr = 4878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com contents->file_trackers.begin(); 4888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com itr != contents->file_trackers.end(); 4898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com ++itr) { 4908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com FileByID::iterator found = unreferred_files.find((*itr)->file_id()); 4918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (found != unreferred_files.end()) { 4928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com referred_files.push_back(found->second); 4938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com unreferred_files.erase(found); 4948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 4958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 4968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 4978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com for (FileByID::iterator itr = unreferred_files.begin(); 4988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com itr != unreferred_files.end(); ++itr) { 4998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com FileMetadata* file = itr->second; 5008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com PutFileDeletionToBatch(file->file_id(), batch); 5018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com delete file; 5028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com } 5038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com unreferred_files.clear(); 5048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 5058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com contents->file_metadata.weak_clear(); 5068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com contents->file_metadata.swap(referred_files); 5078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 5088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return SYNC_STATUS_OK; 5098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 5108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 5118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comtemplate <typename Container, typename Key, typename Value> 5128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.combool FindItem(const Container& container, const Key& key, Value* value) { 5138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com typename Container::const_iterator found = container.find(key); 5148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (found == container.end()) 5158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return false; 5168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com if (value) 5178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com *value = *found->second; 5188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return true; 5198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 5208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 5218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comtemplate <typename Container, typename Key> 5228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comtypename Container::mapped_type FindAndEraseItem(Container* container, 523cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com const Key& key) { 5248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com typedef typename Container::mapped_type Value; 5258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com typename Container::iterator found = container->find(key); 526cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com if (found == container->end()) 5278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return Value(); 5288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 529cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com Value result = found->second; 5308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com container->erase(found); 5318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com return result; 5328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com} 5338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com 5348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid RunSoon(const tracked_objects::Location& from_here, 535cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com const base::Closure& closure) { 536 base::MessageLoopProxy::current()->PostTask(from_here, closure); 537} 538 539} // namespace 540 541bool MetadataDatabase::DirtyTrackerComparator::operator()( 542 const FileTracker* left, 543 const FileTracker* right) const { 544 return left->tracker_id() < right->tracker_id(); 545} 546 547// static 548void MetadataDatabase::Create(base::SequencedTaskRunner* task_runner, 549 const base::FilePath& database_path, 550 const CreateCallback& callback) { 551 task_runner->PostTask(FROM_HERE, base::Bind( 552 &CreateOnTaskRunner, 553 base::MessageLoopProxy::current(), 554 make_scoped_refptr(task_runner), 555 database_path, callback)); 556} 557 558MetadataDatabase::~MetadataDatabase() { 559 task_runner_->DeleteSoon(FROM_HERE, db_.release()); 560 STLDeleteContainerPairSecondPointers( 561 file_by_id_.begin(), file_by_id_.end()); 562 STLDeleteContainerPairSecondPointers( 563 tracker_by_id_.begin(), tracker_by_id_.end()); 564} 565 566int64 MetadataDatabase::GetLargestChangeID() const { 567 return service_metadata_->largest_change_id(); 568} 569 570int64 MetadataDatabase::GetSyncRootTrackerID() const { 571 return service_metadata_->sync_root_tracker_id(); 572} 573 574bool MetadataDatabase::HasSyncRoot() const { 575 return service_metadata_->has_sync_root_tracker_id() && 576 !!service_metadata_->sync_root_tracker_id(); 577} 578 579void MetadataDatabase::PopulateInitialData( 580 int64 largest_change_id, 581 const google_apis::FileResource& sync_root_folder, 582 const ScopedVector<google_apis::FileResource>& app_root_folders, 583 const SyncStatusCallback& callback) { 584 DCHECK(tracker_by_id_.empty()); 585 DCHECK(file_by_id_.empty()); 586 587 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 588 service_metadata_->set_largest_change_id(largest_change_id); 589 590 FileTracker* sync_root_tracker = NULL; 591 int64 sync_root_tracker_id = 0; 592 { 593 scoped_ptr<FileMetadata> folder; 594 scoped_ptr<FileTracker> tracker; 595 CreateInitialSyncRootTracker(GetNextTrackerID(batch.get()), 596 sync_root_folder, 597 &folder, 598 &tracker); 599 std::string sync_root_folder_id = folder->file_id(); 600 sync_root_tracker = tracker.get(); 601 sync_root_tracker_id = tracker->tracker_id(); 602 603 PutFileToBatch(*folder, batch.get()); 604 PutTrackerToBatch(*tracker, batch.get()); 605 606 service_metadata_->set_sync_root_tracker_id(tracker->tracker_id()); 607 PutServiceMetadataToBatch(*service_metadata_, batch.get()); 608 609 trackers_by_file_id_[folder->file_id()].Insert(tracker.get()); 610 611 file_by_id_[sync_root_folder_id] = folder.release(); 612 tracker_by_id_[sync_root_tracker_id] = tracker.release(); 613 } 614 615 for (ScopedVector<google_apis::FileResource>::const_iterator itr = 616 app_root_folders.begin(); 617 itr != app_root_folders.end(); 618 ++itr) { 619 const google_apis::FileResource& folder_resource = **itr; 620 scoped_ptr<FileMetadata> folder; 621 scoped_ptr<FileTracker> tracker; 622 CreateInitialAppRootTracker(GetNextTrackerID(batch.get()), 623 *sync_root_tracker, 624 folder_resource, 625 &folder, 626 &tracker); 627 std::string title = folder->details().title(); 628 std::string folder_id = folder->file_id(); 629 int64 tracker_id = tracker->tracker_id(); 630 631 PutFileToBatch(*folder, batch.get()); 632 PutTrackerToBatch(*tracker, batch.get()); 633 634 trackers_by_file_id_[folder_id].Insert(tracker.get()); 635 trackers_by_parent_and_title_[sync_root_tracker_id][title] 636 .Insert(tracker.get()); 637 638 file_by_id_[folder_id] = folder.release(); 639 tracker_by_id_[tracker_id] = tracker.release(); 640 } 641 642 WriteToDatabase(batch.Pass(), callback); 643} 644 645 646void MetadataDatabase::RegisterApp(const std::string& app_id, 647 const std::string& folder_id, 648 const SyncStatusCallback& callback) { 649 if (FindAppRootTracker(app_id, NULL)) { 650 // The app-root is already registered. 651 RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK)); 652 return; 653 } 654 655 TrackerSet trackers; 656 if (!FindTrackersByFileID(folder_id, &trackers) || trackers.has_active()) { 657 // The folder is tracked by another tracker. 658 util::Log(logging::LOG_WARNING, FROM_HERE, 659 "Failed to register App for %s", app_id.c_str()); 660 RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_HAS_CONFLICT)); 661 return; 662 } 663 664 int64 sync_root_tracker_id = service_metadata_->sync_root_tracker_id(); 665 if (!sync_root_tracker_id) { 666 util::Log(logging::LOG_WARNING, FROM_HERE, 667 "Sync-root needs to be set up before registering app-root"); 668 RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); 669 return; 670 } 671 672 // Make this tracker an app-root tracker. 673 FileTracker* app_root_tracker = NULL; 674 for (TrackerSet::iterator itr = trackers.begin(); 675 itr != trackers.end(); ++itr) { 676 FileTracker* tracker = *itr; 677 if (tracker->parent_tracker_id() == sync_root_tracker_id) 678 app_root_tracker = tracker; 679 } 680 681 if (!app_root_tracker) { 682 RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); 683 return; 684 } 685 686 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 687 RegisterTrackerAsAppRoot(app_id, app_root_tracker->tracker_id(), batch.get()); 688 WriteToDatabase(batch.Pass(), callback); 689} 690 691void MetadataDatabase::DisableApp(const std::string& app_id, 692 const SyncStatusCallback& callback) { 693 FileTracker tracker; 694 if (!FindAppRootTracker(app_id, &tracker)) { 695 RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); 696 return; 697 } 698 699 if (tracker.tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT) { 700 RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK)); 701 return; 702 } 703 704 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 705 MakeAppRootDisabled(tracker.tracker_id(), batch.get()); 706 WriteToDatabase(batch.Pass(), callback); 707} 708 709void MetadataDatabase::EnableApp(const std::string& app_id, 710 const SyncStatusCallback& callback) { 711 FileTracker tracker; 712 if (!FindAppRootTracker(app_id, &tracker) || 713 tracker.tracker_kind() == TRACKER_KIND_REGULAR) { 714 RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); 715 return; 716 } 717 718 if (tracker.tracker_kind() == TRACKER_KIND_APP_ROOT) { 719 RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK)); 720 return; 721 } 722 723 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 724 MakeAppRootEnabled(tracker.tracker_id(), batch.get()); 725 WriteToDatabase(batch.Pass(), callback); 726} 727 728void MetadataDatabase::UnregisterApp(const std::string& app_id, 729 const SyncStatusCallback& callback) { 730 FileTracker tracker; 731 if (!FindAppRootTracker(app_id, &tracker) || 732 tracker.tracker_kind() == TRACKER_KIND_REGULAR) { 733 RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK)); 734 return; 735 } 736 737 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 738 UnregisterTrackerAsAppRoot(app_id, batch.get()); 739 WriteToDatabase(batch.Pass(), callback); 740} 741 742bool MetadataDatabase::FindAppRootTracker(const std::string& app_id, 743 FileTracker* tracker) const { 744 return FindItem(app_root_by_app_id_, app_id, tracker); 745} 746 747bool MetadataDatabase::FindFileByFileID(const std::string& file_id, 748 FileMetadata* file) const { 749 return FindItem(file_by_id_, file_id, file); 750} 751 752bool MetadataDatabase::FindTrackersByFileID(const std::string& file_id, 753 TrackerSet* trackers) const { 754 TrackersByFileID::const_iterator found = trackers_by_file_id_.find(file_id); 755 if (found == trackers_by_file_id_.end()) 756 return false; 757 if (trackers) 758 *trackers = found->second; 759 return true; 760} 761 762bool MetadataDatabase::FindTrackerByTrackerID(int64 tracker_id, 763 FileTracker* tracker) const { 764 return FindItem(tracker_by_id_, tracker_id, tracker); 765} 766 767bool MetadataDatabase::BuildPathForTracker(int64 tracker_id, 768 base::FilePath* path) const { 769 FileTracker current; 770 if (!FindTrackerByTrackerID(tracker_id, ¤t) || !current.active()) 771 return false; 772 773 std::vector<base::FilePath> components; 774 while (!IsAppRoot(current)) { 775 std::string title = GetTrackerTitle(current); 776 if (title.empty()) 777 return false; 778 components.push_back(base::FilePath::FromUTF8Unsafe(title)); 779 if (!FindTrackerByTrackerID(current.parent_tracker_id(), ¤t) || 780 !current.active()) 781 return false; 782 } 783 784 if (path) 785 *path = ReverseConcatPathComponents(components); 786 787 return true; 788} 789 790void MetadataDatabase::UpdateByChangeList( 791 ScopedVector<google_apis::ChangeResource> changes, 792 const SyncStatusCallback& callback) { 793 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 794 795 for (ScopedVector<google_apis::ChangeResource>::const_iterator itr = 796 changes.begin(); 797 itr != changes.end(); 798 ++itr) { 799 const google_apis::ChangeResource& change = **itr; 800 scoped_ptr<FileMetadata> file( 801 CreateFileMetadataFromChangeResource(change)); 802 std::string file_id = file->file_id(); 803 804 MarkTrackersDirtyByFileID(file_id, batch.get()); 805 if (!file->details().deleted()) 806 MaybeAddTrackersForNewFile(*file, batch.get()); 807 808 if (FindTrackersByFileID(file_id, NULL)) { 809 PutFileToBatch(*file, batch.get()); 810 811 FileMetadata* file_ptr = file.release(); 812 std::swap(file_ptr, file_by_id_[file_id]); 813 delete file_ptr; 814 } 815 } 816 817 WriteToDatabase(batch.Pass(), callback); 818} 819 820void MetadataDatabase::PopulateFolderByChildList( 821 const std::string& folder_id, 822 const FileIDList& child_file_ids, 823 const SyncStatusCallback& callback) { 824 TrackerSet trackers; 825 if (!FindTrackersByFileID(folder_id, &trackers) || 826 !trackers.has_active()) { 827 // It's OK that there is no folder to populate its children. 828 // Inactive folders should ignore their contents updates. 829 RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK)); 830 return; 831 } 832 833 FileTracker* folder_tracker = 834 tracker_by_id_[trackers.active_tracker()->tracker_id()]; 835 DCHECK(folder_tracker); 836 std::set<std::string> children(child_file_ids.begin(), child_file_ids.end()); 837 838 std::vector<int64> known_children; 839 PushChildTrackersToContainer(trackers_by_parent_and_title_, 840 folder_tracker->tracker_id(), 841 std::back_inserter(known_children)); 842 for (std::vector<int64>::iterator itr = known_children.begin(); 843 itr != known_children.end(); ++itr) 844 children.erase(tracker_by_id_[*itr]->file_id()); 845 846 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 847 for (FileIDList::const_iterator itr = child_file_ids.begin(); 848 itr != child_file_ids.end(); ++itr) 849 CreateTrackerForParentAndFileID(*folder_tracker, *itr, batch.get()); 850 folder_tracker->set_needs_folder_listing(false); 851 if (folder_tracker->dirty() && !ShouldKeepDirty(*folder_tracker)) { 852 folder_tracker->set_dirty(false); 853 dirty_trackers_.erase(folder_tracker); 854 } 855 PutTrackerToBatch(*folder_tracker, batch.get()); 856 857 WriteToDatabase(batch.Pass(), callback); 858} 859 860void MetadataDatabase::UpdateTracker(int64 tracker_id, 861 const FileDetails& updated_details, 862 const SyncStatusCallback& callback) { 863 TrackerByID::iterator found = tracker_by_id_.find(tracker_id); 864 if (found == tracker_by_id_.end()) { 865 RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND)); 866 return; 867 } 868 869 FileTracker* tracker = found->second; 870 DCHECK(tracker); 871 872 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); 873 874 if (updated_details.deleted()) { 875 // The update deletes the local file. 876 FileByID::iterator found = file_by_id_.find(tracker->file_id()); 877 if (found == file_by_id_.end() || found->second->details().deleted()) { 878 // Both the tracker and metadata have the deleted flag, now it's safe to 879 // delete the |tracker|. 880 RemoveTracker(tracker->tracker_id(), batch.get()); 881 } else { 882 // The local file is deleted, but corresponding remote file isn't. 883 // Put the tracker back to the initial state. 884 tracker->clear_synced_details(); 885 tracker->set_dirty(true); 886 tracker->set_active(false); 887 PutTrackerToBatch(*tracker, batch.get()); 888 } 889 890 WriteToDatabase(batch.Pass(), callback); 891 return; 892 } 893 894 // Check if the tracker was retitled. If it was, update the title and its 895 // index in advance. 896 if (!tracker->has_synced_details() || 897 tracker->synced_details().title() != updated_details.title()) { 898 UpdateTrackerTitle(tracker, updated_details.title(), batch.get()); 899 } 900 901 *tracker->mutable_synced_details() = updated_details; 902 903 // Activate the tracker if: 904 // - There is no active tracker that tracks |tracker->file_id()|. 905 // - There is no active tracker that has the same |parent| and |title|. 906 if (!tracker->active() && CanActivateTracker(*tracker)) 907 MakeTrackerActive(tracker->tracker_id(), batch.get()); 908 if (tracker->dirty() && !ShouldKeepDirty(*tracker)) { 909 tracker->set_dirty(false); 910 dirty_trackers_.erase(tracker); 911 } 912 PutTrackerToBatch(*tracker, batch.get()); 913 914 WriteToDatabase(batch.Pass(), callback); 915} 916 917MetadataDatabase::MetadataDatabase(base::SequencedTaskRunner* task_runner) 918 : task_runner_(task_runner), weak_ptr_factory_(this) { 919 DCHECK(task_runner); 920} 921 922// static 923void MetadataDatabase::CreateOnTaskRunner( 924 base::SingleThreadTaskRunner* callback_runner, 925 base::SequencedTaskRunner* task_runner, 926 const base::FilePath& database_path, 927 const CreateCallback& callback) { 928 scoped_ptr<MetadataDatabase> metadata_database( 929 new MetadataDatabase(task_runner)); 930 SyncStatusCode status = 931 metadata_database->InitializeOnTaskRunner(database_path); 932 if (status != SYNC_STATUS_OK) 933 metadata_database.reset(); 934 935 callback_runner->PostTask(FROM_HERE, base::Bind( 936 callback, status, base::Passed(&metadata_database))); 937} 938 939// static 940SyncStatusCode MetadataDatabase::CreateForTesting( 941 scoped_ptr<leveldb::DB> db, 942 scoped_ptr<MetadataDatabase>* metadata_database_out) { 943 scoped_ptr<MetadataDatabase> metadata_database( 944 new MetadataDatabase(base::MessageLoopProxy::current())); 945 metadata_database->db_ = db.Pass(); 946 SyncStatusCode status = 947 metadata_database->InitializeOnTaskRunner(base::FilePath()); 948 if (status == SYNC_STATUS_OK) 949 *metadata_database_out = metadata_database.Pass(); 950 return status; 951} 952 953SyncStatusCode MetadataDatabase::InitializeOnTaskRunner( 954 const base::FilePath& database_path) { 955 base::ThreadRestrictions::AssertIOAllowed(); 956 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 957 958 SyncStatusCode status = SYNC_STATUS_UNKNOWN; 959 bool created = false; 960 // Open database unless |db_| is overridden for testing. 961 if (!db_) { 962 status = OpenDatabase(database_path, &db_, &created); 963 if (status != SYNC_STATUS_OK) 964 return status; 965 } 966 967 if (created) { 968 status = WriteVersionInfo(db_.get()); 969 if (status != SYNC_STATUS_OK) 970 return status; 971 } else { 972 status = MigrateDatabaseIfNeeded(db_.get()); 973 if (status != SYNC_STATUS_OK) 974 return status; 975 } 976 977 DatabaseContents contents; 978 status = ReadDatabaseContents(db_.get(), &contents); 979 if (status != SYNC_STATUS_OK) 980 return status; 981 982 leveldb::WriteBatch batch; 983 status = InitializeServiceMetadata(&contents, &batch); 984 if (status != SYNC_STATUS_OK) 985 return status; 986 987 status = RemoveUnreachableItems(&contents, &batch); 988 if (status != SYNC_STATUS_OK) 989 return status; 990 991 status = LevelDBStatusToSyncStatusCode( 992 db_->Write(leveldb::WriteOptions(), &batch)); 993 if (status != SYNC_STATUS_OK) 994 return status; 995 996 BuildIndexes(&contents); 997 return status; 998} 999 1000void MetadataDatabase::BuildIndexes(DatabaseContents* contents) { 1001 service_metadata_ = contents->service_metadata.Pass(); 1002 1003 for (ScopedVector<FileMetadata>::const_iterator itr = 1004 contents->file_metadata.begin(); 1005 itr != contents->file_metadata.end(); 1006 ++itr) { 1007 file_by_id_[(*itr)->file_id()] = *itr; 1008 } 1009 contents->file_metadata.weak_clear(); 1010 1011 for (ScopedVector<FileTracker>::const_iterator itr = 1012 contents->file_trackers.begin(); 1013 itr != contents->file_trackers.end(); 1014 ++itr) { 1015 FileTracker* tracker = *itr; 1016 tracker_by_id_[tracker->tracker_id()] = tracker; 1017 trackers_by_file_id_[tracker->file_id()].Insert(tracker); 1018 1019 if (IsAppRoot(*tracker)) 1020 app_root_by_app_id_[tracker->app_id()] = tracker; 1021 1022 if (tracker->parent_tracker_id()) { 1023 std::string title = GetTrackerTitle(*tracker); 1024 TrackerSet* trackers = 1025 &trackers_by_parent_and_title_[tracker->parent_tracker_id()][title]; 1026 trackers->Insert(tracker); 1027 } 1028 1029 if (tracker->dirty()) 1030 dirty_trackers_.insert(tracker); 1031 } 1032 contents->file_trackers.weak_clear(); 1033} 1034 1035void MetadataDatabase::RegisterTrackerAsAppRoot( 1036 const std::string& app_id, 1037 int64 tracker_id, 1038 leveldb::WriteBatch* batch) { 1039 FileTracker* tracker = tracker_by_id_[tracker_id]; 1040 DCHECK(tracker); 1041 tracker->set_app_id(app_id); 1042 tracker->set_tracker_kind(TRACKER_KIND_APP_ROOT); 1043 app_root_by_app_id_[app_id] = tracker; 1044 1045 MakeTrackerActive(tracker->tracker_id(), batch); 1046} 1047 1048void MetadataDatabase::UnregisterTrackerAsAppRoot( 1049 const std::string& app_id, 1050 leveldb::WriteBatch* batch) { 1051 FileTracker* tracker = FindAndEraseItem(&app_root_by_app_id_, app_id); 1052 tracker->set_app_id(std::string()); 1053 tracker->set_tracker_kind(TRACKER_KIND_REGULAR); 1054 1055 // Inactivate the tracker to drop all descendant. 1056 // (Note that we set tracker_kind to TRACKER_KIND_REGULAR before calling 1057 // this.) 1058 MakeTrackerInactive(tracker->tracker_id(), batch); 1059} 1060 1061void MetadataDatabase::MakeTrackerActive(int64 tracker_id, 1062 leveldb::WriteBatch* batch) { 1063 FileTracker* tracker = tracker_by_id_[tracker_id]; 1064 DCHECK(tracker); 1065 DCHECK(!tracker->active()); 1066 1067 int64 parent_tracker_id = tracker->parent_tracker_id(); 1068 DCHECK(tracker->has_synced_details()); 1069 trackers_by_file_id_[tracker->file_id()].Activate(tracker); 1070 if (parent_tracker_id) { 1071 trackers_by_parent_and_title_[parent_tracker_id][ 1072 tracker->synced_details().title()].Activate(tracker); 1073 } 1074 tracker->set_active(true); 1075 tracker->set_needs_folder_listing( 1076 tracker->synced_details().file_kind() == FILE_KIND_FOLDER); 1077 tracker->set_dirty(true); 1078 dirty_trackers_.insert(tracker); 1079 1080 PutTrackerToBatch(*tracker, batch); 1081} 1082 1083void MetadataDatabase::MakeTrackerInactive(int64 tracker_id, 1084 leveldb::WriteBatch* batch) { 1085 FileTracker* tracker = tracker_by_id_[tracker_id]; 1086 DCHECK(tracker); 1087 DCHECK(tracker->active()); 1088 DCHECK_EQ(TRACKER_KIND_REGULAR, tracker->tracker_kind()); 1089 trackers_by_file_id_[tracker->file_id()].Inactivate(tracker); 1090 1091 std::string title = GetTrackerTitle(*tracker); 1092 int64 parent_tracker_id = tracker->parent_tracker_id(); 1093 if (parent_tracker_id) 1094 trackers_by_parent_and_title_[parent_tracker_id][title].Inactivate(tracker); 1095 tracker->set_active(false); 1096 1097 RemoveAllDescendantTrackers(tracker_id, batch); 1098 MarkTrackersDirtyByFileID(tracker->file_id(), batch); 1099 if (parent_tracker_id) 1100 MarkTrackersDirtyByPath(parent_tracker_id, title, batch); 1101 PutTrackerToBatch(*tracker, batch); 1102} 1103 1104void MetadataDatabase::MakeAppRootDisabled(int64 tracker_id, 1105 leveldb::WriteBatch* batch) { 1106 FileTracker* tracker = tracker_by_id_[tracker_id]; 1107 DCHECK(tracker); 1108 DCHECK_EQ(TRACKER_KIND_APP_ROOT, tracker->tracker_kind()); 1109 DCHECK(tracker->active()); 1110 1111 // Keep the app-root tracker active (but change the tracker_kind) so that 1112 // other conflicting trackers won't become active. 1113 tracker->set_tracker_kind(TRACKER_KIND_DISABLED_APP_ROOT); 1114 PutTrackerToBatch(*tracker, batch); 1115} 1116 1117void MetadataDatabase::MakeAppRootEnabled(int64 tracker_id, 1118 leveldb::WriteBatch* batch) { 1119 FileTracker* tracker = tracker_by_id_[tracker_id]; 1120 DCHECK(tracker); 1121 DCHECK_EQ(TRACKER_KIND_DISABLED_APP_ROOT, tracker->tracker_kind()); 1122 DCHECK(tracker->active()); 1123 1124 tracker->set_tracker_kind(TRACKER_KIND_APP_ROOT); 1125 // Mark descendant trackers as dirty to handle changes in disable period. 1126 RecursiveMarkTrackerAsDirty(tracker_id, batch); 1127 PutTrackerToBatch(*tracker, batch); 1128} 1129 1130void MetadataDatabase::CreateTrackerForParentAndFileID( 1131 const FileTracker& parent_tracker, 1132 const std::string& file_id, 1133 leveldb::WriteBatch* batch) { 1134 int64 tracker_id = GetNextTrackerID(batch); 1135 scoped_ptr<FileTracker> tracker(new FileTracker); 1136 tracker->set_tracker_id(tracker_id); 1137 tracker->set_parent_tracker_id(parent_tracker.tracker_id()); 1138 tracker->set_file_id(file_id); 1139 tracker->set_app_id(parent_tracker.app_id()); 1140 tracker->set_tracker_kind(TRACKER_KIND_REGULAR); 1141 tracker->set_dirty(true); 1142 tracker->set_active(false); 1143 tracker->set_needs_folder_listing(false); 1144 PutTrackerToBatch(*tracker, batch); 1145 1146 trackers_by_file_id_[file_id].Insert(tracker.get()); 1147 // Note: |trackers_by_parent_and_title_| does not map from 1148 // FileMetadata::details but from FileTracker::synced_details, which is filled 1149 // on tracker updated phase. Use empty string as the title since 1150 // FileTracker::synced_details is empty here. 1151 trackers_by_parent_and_title_[parent_tracker.tracker_id()][std::string()] 1152 .Insert(tracker.get()); 1153 dirty_trackers_.insert(tracker.get()); 1154 DCHECK(!ContainsKey(tracker_by_id_, tracker_id)); 1155 tracker_by_id_[tracker_id] = tracker.release(); 1156} 1157 1158void MetadataDatabase::RemoveTracker(int64 tracker_id, 1159 leveldb::WriteBatch* batch) { 1160 RemoveTrackerInternal(tracker_id, batch, false); 1161} 1162 1163void MetadataDatabase::RemoveTrackerIgnoringSiblings( 1164 int64 tracker_id, 1165 leveldb::WriteBatch* batch) { 1166 RemoveTrackerInternal(tracker_id, batch, true); 1167} 1168 1169void MetadataDatabase::RemoveTrackerInternal( 1170 int64 tracker_id, 1171 leveldb::WriteBatch* batch, 1172 bool ignoring_siblings) { 1173 scoped_ptr<FileTracker> tracker( 1174 FindAndEraseItem(&tracker_by_id_, tracker_id)); 1175 if (!tracker) 1176 return; 1177 1178 EraseTrackerFromFileIDIndex(tracker.get(), batch); 1179 if (IsAppRoot(*tracker)) 1180 app_root_by_app_id_.erase(tracker->app_id()); 1181 EraseTrackerFromPathIndex(tracker.get()); 1182 1183 MarkTrackersDirtyByFileID(tracker->file_id(), batch); 1184 if (!ignoring_siblings) { 1185 MarkTrackersDirtyByPath(tracker->parent_tracker_id(), 1186 GetTrackerTitle(*tracker), 1187 batch); 1188 } 1189 PutTrackerDeletionToBatch(tracker_id, batch); 1190} 1191 1192void MetadataDatabase::MaybeAddTrackersForNewFile( 1193 const FileMetadata& file, 1194 leveldb::WriteBatch* batch) { 1195 std::set<int64> known_parents; 1196 TrackersByFileID::iterator found = trackers_by_file_id_.find(file.file_id()); 1197 if (found != trackers_by_file_id_.end()) { 1198 for (TrackerSet::const_iterator itr = found->second.begin(); 1199 itr != found->second.end(); ++itr) { 1200 int64 parent_tracker_id = (*itr)->parent_tracker_id(); 1201 if (parent_tracker_id) 1202 known_parents.insert(parent_tracker_id); 1203 } 1204 } 1205 1206 for (int i = 0; i < file.details().parent_folder_ids_size(); ++i) { 1207 std::string parent_folder_id = file.details().parent_folder_ids(i); 1208 TrackersByFileID::iterator found = 1209 trackers_by_file_id_.find(parent_folder_id); 1210 if (found == trackers_by_file_id_.end()) 1211 continue; 1212 1213 for (TrackerSet::const_iterator itr = found->second.begin(); 1214 itr != found->second.end(); ++itr) { 1215 FileTracker* parent_tracker = *itr; 1216 int64 parent_tracker_id = parent_tracker->tracker_id(); 1217 if (!parent_tracker->active()) 1218 continue; 1219 1220 if (ContainsKey(known_parents, parent_tracker_id)) 1221 continue; 1222 1223 CreateTrackerForParentAndFileID(*parent_tracker, file.file_id(), batch); 1224 } 1225 } 1226} 1227 1228void MetadataDatabase::RemoveAllDescendantTrackers(int64 root_tracker_id, 1229 leveldb::WriteBatch* batch) { 1230 std::vector<int64> pending_trackers; 1231 PushChildTrackersToContainer(trackers_by_parent_and_title_, 1232 root_tracker_id, 1233 std::back_inserter(pending_trackers)); 1234 1235 while (!pending_trackers.empty()) { 1236 int64 tracker_id = pending_trackers.back(); 1237 pending_trackers.pop_back(); 1238 PushChildTrackersToContainer(trackers_by_parent_and_title_, 1239 tracker_id, 1240 std::back_inserter(pending_trackers)); 1241 RemoveTrackerIgnoringSiblings(tracker_id, batch); 1242 } 1243} 1244 1245void MetadataDatabase::EraseTrackerFromFileIDIndex(FileTracker* tracker, 1246 leveldb::WriteBatch* batch) { 1247 TrackersByFileID::iterator found = 1248 trackers_by_file_id_.find(tracker->file_id()); 1249 if (found == trackers_by_file_id_.end()) 1250 return; 1251 1252 TrackerSet* trackers = &found->second; 1253 trackers->Erase(tracker); 1254 if (!trackers->tracker_set().empty()) 1255 return; 1256 trackers_by_file_id_.erase(found); 1257 EraseFileFromDatabase(tracker->file_id(), batch); 1258} 1259 1260void MetadataDatabase::EraseFileFromDatabase(const std::string& file_id, 1261 leveldb::WriteBatch* batch) { 1262 scoped_ptr<FileMetadata> file(FindAndEraseItem(&file_by_id_, file_id)); 1263 if (file) 1264 PutFileDeletionToBatch(file_id, batch); 1265} 1266 1267void MetadataDatabase::EraseTrackerFromPathIndex(FileTracker* tracker) { 1268 TrackersByParentAndTitle::iterator found = 1269 trackers_by_parent_and_title_.find(tracker->parent_tracker_id()); 1270 if (found == trackers_by_parent_and_title_.end()) 1271 return; 1272 1273 std::string title = GetTrackerTitle(*tracker); 1274 TrackersByTitle* trackers_by_title = &found->second; 1275 TrackersByTitle::iterator found_by_title = trackers_by_title->find(title); 1276 TrackerSet* conflicting_trackers = &found_by_title->second; 1277 conflicting_trackers->Erase(tracker); 1278 1279 if (conflicting_trackers->tracker_set().empty()) { 1280 trackers_by_title->erase(found_by_title); 1281 if (trackers_by_title->empty()) 1282 trackers_by_parent_and_title_.erase(found); 1283 } 1284} 1285 1286void MetadataDatabase::MarkTrackerSetDirty( 1287 TrackerSet* trackers, 1288 leveldb::WriteBatch* batch) { 1289 for (TrackerSet::iterator itr = trackers->begin(); 1290 itr != trackers->end(); ++itr) { 1291 FileTracker* tracker = *itr; 1292 if (tracker->dirty()) 1293 continue; 1294 tracker->set_dirty(true); 1295 PutTrackerToBatch(*tracker, batch); 1296 dirty_trackers_.insert(tracker); 1297 } 1298} 1299 1300void MetadataDatabase::MarkTrackersDirtyByFileID( 1301 const std::string& file_id, 1302 leveldb::WriteBatch* batch) { 1303 TrackersByFileID::iterator found = trackers_by_file_id_.find(file_id); 1304 if (found != trackers_by_file_id_.end()) 1305 MarkTrackerSetDirty(&found->second, batch); 1306} 1307 1308void MetadataDatabase::MarkTrackersDirtyByPath(int64 parent_tracker_id, 1309 const std::string& title, 1310 leveldb::WriteBatch* batch) { 1311 TrackersByParentAndTitle::iterator found = 1312 trackers_by_parent_and_title_.find(parent_tracker_id); 1313 if (found == trackers_by_parent_and_title_.end()) { 1314 NOTREACHED() << "parent: " << parent_tracker_id 1315 << ", title: " << title; 1316 return; 1317 } 1318 1319 TrackersByTitle::iterator itr = found->second.find(title); 1320 if (itr != found->second.end()) 1321 MarkTrackerSetDirty(&itr->second, batch); 1322} 1323 1324int64 MetadataDatabase::GetNextTrackerID(leveldb::WriteBatch* batch) { 1325 int64 tracker_id = service_metadata_->next_tracker_id(); 1326 service_metadata_->set_next_tracker_id(tracker_id + 1); 1327 PutServiceMetadataToBatch(*service_metadata_, batch); 1328 DCHECK_GT(tracker_id, 0); 1329 return tracker_id; 1330} 1331 1332void MetadataDatabase::RecursiveMarkTrackerAsDirty(int64 root_tracker_id, 1333 leveldb::WriteBatch* batch) { 1334 std::vector<int64> stack; 1335 stack.push_back(root_tracker_id); 1336 while (!stack.empty()) { 1337 int64 tracker_id = stack.back(); 1338 stack.pop_back(); 1339 PushChildTrackersToContainer( 1340 trackers_by_parent_and_title_, tracker_id, std::back_inserter(stack)); 1341 1342 FileTracker* tracker = tracker_by_id_[tracker_id]; 1343 if (!tracker->dirty()) { 1344 tracker->set_dirty(true); 1345 PutTrackerToBatch(*tracker, batch); 1346 dirty_trackers_.insert(tracker); 1347 } 1348 } 1349} 1350 1351bool MetadataDatabase::CanActivateTracker(const FileTracker& tracker) { 1352 DCHECK(!tracker.active()); 1353 DCHECK_NE(service_metadata_->sync_root_tracker_id(), tracker.tracker_id()); 1354 1355 if (HasActiveTrackerForFileID(tracker.file_id())) 1356 return false; 1357 1358 if (tracker.app_id().empty()) 1359 return false; 1360 if (!tracker.has_synced_details()) 1361 return false; 1362 DCHECK(tracker.parent_tracker_id()); 1363 1364 return !HasActiveTrackerForPath(tracker.parent_tracker_id(), 1365 tracker.synced_details().title()); 1366} 1367 1368bool MetadataDatabase::ShouldKeepDirty(const FileTracker& tracker) const { 1369 if (HasDisabledAppRoot(tracker)) 1370 return false; 1371 1372 DCHECK(tracker.dirty()); 1373 if (!tracker.has_synced_details()) 1374 return true; 1375 1376 FileByID::const_iterator found = file_by_id_.find(tracker.file_id()); 1377 if (found == file_by_id_.end()) 1378 return true; 1379 const FileMetadata* file = found->second; 1380 DCHECK(file); 1381 1382 if (tracker.active()) { 1383 if (tracker.needs_folder_listing()) 1384 return true; 1385 if (tracker.synced_details().md5() != file->details().md5()) 1386 return true; 1387 } 1388 1389 const FileDetails& local_details = tracker.synced_details(); 1390 const FileDetails& remote_details = file->details(); 1391 1392 if (local_details.title() != remote_details.title()) 1393 return true; 1394 if (local_details.deleted() != remote_details.deleted()) 1395 return true; 1396 1397 return false; 1398} 1399 1400bool MetadataDatabase::HasDisabledAppRoot(const FileTracker& tracker) const { 1401 TrackerByAppID::const_iterator found = 1402 app_root_by_app_id_.find(tracker.app_id()); 1403 if (found == app_root_by_app_id_.end()) 1404 return false; 1405 1406 const FileTracker* app_root_tracker = found->second; 1407 DCHECK(app_root_tracker); 1408 return app_root_tracker->tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT; 1409} 1410 1411bool MetadataDatabase::HasActiveTrackerForFileID( 1412 const std::string& file_id) const { 1413 TrackersByFileID::const_iterator found = trackers_by_file_id_.find(file_id); 1414 return found != trackers_by_file_id_.end() && found->second.has_active(); 1415} 1416 1417bool MetadataDatabase::HasActiveTrackerForPath(int64 parent_tracker_id, 1418 const std::string& title) const { 1419 TrackersByParentAndTitle::const_iterator found_by_parent = 1420 trackers_by_parent_and_title_.find(parent_tracker_id); 1421 if (found_by_parent == trackers_by_parent_and_title_.end()) 1422 return false; 1423 1424 const TrackersByTitle& trackers_by_title = found_by_parent->second; 1425 TrackersByTitle::const_iterator found = trackers_by_title.find(title); 1426 return found != trackers_by_title.end() && found->second.has_active(); 1427} 1428 1429void MetadataDatabase::UpdateTrackerTitle(FileTracker* tracker, 1430 const std::string& new_title, 1431 leveldb::WriteBatch* batch) { 1432 int64 parent_id = tracker->parent_tracker_id(); 1433 std::string old_title = GetTrackerTitle(*tracker); 1434 DCHECK_NE(old_title, new_title); 1435 DCHECK(!new_title.empty()); 1436 1437 TrackersByTitle* trackers_by_title = 1438 &trackers_by_parent_and_title_[parent_id]; 1439 TrackerSet* old_siblings = &(*trackers_by_title)[old_title]; 1440 TrackerSet* new_siblings = &(*trackers_by_title)[new_title]; 1441 1442 old_siblings->Erase(tracker); 1443 if (old_siblings->empty()) 1444 trackers_by_title->erase(old_title); 1445 else 1446 MarkTrackerSetDirty(old_siblings, batch); 1447 1448 if (tracker->active() && new_siblings->has_active()) { 1449 // Inactivate existing active tracker. 1450 FileTracker* obstacle = new_siblings->active_tracker(); 1451 new_siblings->Inactivate(obstacle); 1452 DCHECK_EQ(TRACKER_KIND_REGULAR, obstacle->tracker_kind()); 1453 1454 TrackerSet* same_file_id_trackers_to_obstacle = 1455 &trackers_by_file_id_[obstacle->file_id()]; 1456 same_file_id_trackers_to_obstacle->Inactivate(obstacle); 1457 MarkTrackerSetDirty(same_file_id_trackers_to_obstacle, batch); 1458 1459 obstacle->set_active(false); 1460 PutTrackerToBatch(*obstacle, batch); 1461 1462 RemoveAllDescendantTrackers(obstacle->tracker_id(), batch); 1463 } 1464 1465 tracker->mutable_synced_details()->set_title(new_title); 1466 new_siblings->Insert(tracker); 1467 PutTrackerToBatch(*tracker, batch); 1468} 1469 1470void MetadataDatabase::WriteToDatabase(scoped_ptr<leveldb::WriteBatch> batch, 1471 const SyncStatusCallback& callback) { 1472 base::PostTaskAndReplyWithResult( 1473 task_runner_.get(), 1474 FROM_HERE, 1475 base::Bind(&leveldb::DB::Write, 1476 base::Unretained(db_.get()), 1477 leveldb::WriteOptions(), 1478 base::Owned(batch.release())), 1479 base::Bind(&AdaptLevelDBStatusToSyncStatusCode, callback)); 1480} 1481 1482} // namespace drive_backend 1483} // namespace sync_file_system 1484