| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/sync_file_system/drive_metadata_store.h" | 5 #include "chrome/browser/sync_file_system/drive_metadata_store.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 30 matching lines...) Expand all Loading... |
| 41 | 41 |
| 42 namespace { | 42 namespace { |
| 43 | 43 |
| 44 const char* const kServiceName = DriveFileSyncService::kServiceName; | 44 const char* const kServiceName = DriveFileSyncService::kServiceName; |
| 45 const char kDatabaseVersionKey[] = "VERSION"; | 45 const char kDatabaseVersionKey[] = "VERSION"; |
| 46 const int64 kCurrentDatabaseVersion = 2; | 46 const int64 kCurrentDatabaseVersion = 2; |
| 47 const char kChangeStampKey[] = "CHANGE_STAMP"; | 47 const char kChangeStampKey[] = "CHANGE_STAMP"; |
| 48 const char kSyncRootDirectoryKey[] = "SYNC_ROOT_DIR"; | 48 const char kSyncRootDirectoryKey[] = "SYNC_ROOT_DIR"; |
| 49 const char kDriveMetadataKeyPrefix[] = "METADATA: "; | 49 const char kDriveMetadataKeyPrefix[] = "METADATA: "; |
| 50 const char kMetadataKeySeparator = ' '; | 50 const char kMetadataKeySeparator = ' '; |
| 51 const char kDriveBatchSyncOriginKeyPrefix[] = "BSYNC_ORIGIN: "; | |
| 52 const char kDriveIncrementalSyncOriginKeyPrefix[] = "ISYNC_ORIGIN: "; | 51 const char kDriveIncrementalSyncOriginKeyPrefix[] = "ISYNC_ORIGIN: "; |
| 53 const char kDriveDisabledOriginKeyPrefix[] = "DISABLED_ORIGIN: "; | 52 const char kDriveDisabledOriginKeyPrefix[] = "DISABLED_ORIGIN: "; |
| 54 const size_t kDriveMetadataKeyPrefixLength = arraysize(kDriveMetadataKeyPrefix); | 53 const size_t kDriveMetadataKeyPrefixLength = arraysize(kDriveMetadataKeyPrefix); |
| 55 | 54 |
| 56 const base::FilePath::CharType kV0FormatPathPrefix[] = | 55 std::string RemovePrefix(const std::string& str, const std::string& prefix) { |
| 57 FILE_PATH_LITERAL("drive/"); | 56 if (StartsWithASCII(str, prefix, true)) |
| 58 | 57 return str.substr(prefix.size()); |
| 59 bool ParseV0FormatFileSystemURLString(const GURL& url, | 58 return str; |
| 60 GURL* origin, | |
| 61 base::FilePath* path) { | |
| 62 fileapi::FileSystemType mount_type; | |
| 63 base::FilePath virtual_path; | |
| 64 | |
| 65 if (!fileapi::FileSystemURL::ParseFileSystemSchemeURL( | |
| 66 url, origin, &mount_type, &virtual_path) || | |
| 67 mount_type != fileapi::kFileSystemTypeExternal) { | |
| 68 NOTREACHED() << "Failed to parse filesystem scheme URL"; | |
| 69 return false; | |
| 70 } | |
| 71 | |
| 72 base::FilePath::StringType prefix = | |
| 73 base::FilePath(kV0FormatPathPrefix).NormalizePathSeparators().value(); | |
| 74 if (virtual_path.value().substr(0, prefix.size()) != prefix) | |
| 75 return false; | |
| 76 | |
| 77 *path = base::FilePath(virtual_path.value().substr(prefix.size())); | |
| 78 return true; | |
| 79 } | 59 } |
| 80 | 60 |
| 81 std::string FileSystemURLToMetadataKey(const FileSystemURL& url) { | 61 std::string FileSystemURLToMetadataKey(const FileSystemURL& url) { |
| 82 return kDriveMetadataKeyPrefix + url.origin().spec() + | 62 return kDriveMetadataKeyPrefix + url.origin().spec() + |
| 83 kMetadataKeySeparator + url.path().AsUTF8Unsafe(); | 63 kMetadataKeySeparator + url.path().AsUTF8Unsafe(); |
| 84 } | 64 } |
| 85 | 65 |
| 86 void MetadataKeyToOriginAndPath(const std::string& metadata_key, | 66 void MetadataKeyToOriginAndPath(const std::string& metadata_key, |
| 87 GURL* origin, | 67 GURL* origin, |
| 88 base::FilePath* path) { | 68 base::FilePath* path) { |
| 89 std::string key_body(metadata_key.begin() + kDriveMetadataKeyPrefixLength - 1, | 69 std::string key_body(RemovePrefix(metadata_key, kDriveMetadataKeyPrefix)); |
| 90 metadata_key.end()); | |
| 91 size_t separator_position = key_body.find(kMetadataKeySeparator); | 70 size_t separator_position = key_body.find(kMetadataKeySeparator); |
| 92 *origin = GURL(key_body.substr(0, separator_position)); | 71 *origin = GURL(key_body.substr(0, separator_position)); |
| 93 *path = base::FilePath::FromUTF8Unsafe( | 72 *path = base::FilePath::FromUTF8Unsafe( |
| 94 key_body.substr(separator_position + 1)); | 73 key_body.substr(separator_position + 1)); |
| 95 } | 74 } |
| 96 | 75 |
| 97 bool UpdateResourceIdMap(ResourceIdByOrigin* map, | 76 bool UpdateResourceIdMap(ResourceIdByOrigin* map, |
| 98 OriginByResourceId* reverse_map, | 77 OriginByResourceId* reverse_map, |
| 99 const GURL& origin, | 78 const GURL& origin, |
| 100 const std::string& resource_id) { | 79 const std::string& resource_id) { |
| 101 ResourceIdByOrigin::iterator found = map->find(origin); | 80 ResourceIdByOrigin::iterator found = map->find(origin); |
| 102 if (found == map->end()) | 81 if (found == map->end()) |
| 103 return false; | 82 return false; |
| 104 reverse_map->erase(found->second); | 83 reverse_map->erase(found->second); |
| 105 reverse_map->insert(std::make_pair(resource_id, origin)); | 84 reverse_map->insert(std::make_pair(resource_id, origin)); |
| 106 | 85 |
| 107 found->second = resource_id; | 86 found->second = resource_id; |
| 108 return true; | 87 return true; |
| 109 } | 88 } |
| 110 | 89 |
| 111 std::string RemovePrefix(const std::string& str, const std::string& prefix) { | |
| 112 if (StartsWithASCII(str, prefix, true)) | |
| 113 return str.substr(prefix.size()); | |
| 114 return str; | |
| 115 } | |
| 116 | |
| 117 } // namespace | 90 } // namespace |
| 118 | 91 |
| 119 class DriveMetadataDB { | 92 class DriveMetadataDB { |
| 120 public: | 93 public: |
| 121 enum OriginSyncType { | 94 enum OriginSyncType { |
| 122 INCREMENTAL_SYNC_ORIGIN, | 95 INCREMENTAL_SYNC_ORIGIN, |
| 123 DISABLED_ORIGIN | 96 DISABLED_ORIGIN |
| 124 }; | 97 }; |
| 125 | 98 |
| 126 typedef DriveMetadataStore::MetadataMap MetadataMap; | 99 typedef DriveMetadataStore::MetadataMap MetadataMap; |
| 127 | 100 |
| 128 DriveMetadataDB(const base::FilePath& base_dir, | 101 DriveMetadataDB(const base::FilePath& base_dir, |
| 129 base::SequencedTaskRunner* task_runner); | 102 base::SequencedTaskRunner* task_runner); |
| 130 ~DriveMetadataDB(); | 103 ~DriveMetadataDB(); |
| 131 | 104 |
| 132 SyncStatusCode Initialize(bool* created); | 105 SyncStatusCode Initialize(bool* created); |
| 133 SyncStatusCode ReadContents(DriveMetadataDBContents* contents); | 106 SyncStatusCode ReadContents(DriveMetadataDBContents* contents); |
| 134 | 107 |
| 135 SyncStatusCode MigrateDatabaseIfNeeded(); | 108 SyncStatusCode MigrateDatabaseIfNeeded(); |
| 136 SyncStatusCode MigrateFromVersion0To1Database(); | |
| 137 | 109 |
| 138 SyncStatusCode SetLargestChangestamp(int64 largest_changestamp); | 110 SyncStatusCode SetLargestChangestamp(int64 largest_changestamp); |
| 139 SyncStatusCode SetSyncRootDirectory(const std::string& resource_id); | 111 SyncStatusCode SetSyncRootDirectory(const std::string& resource_id); |
| 140 SyncStatusCode GetSyncRootDirectory(std::string* resource_id); | 112 SyncStatusCode GetSyncRootDirectory(std::string* resource_id); |
| 141 SyncStatusCode SetOriginRootDirectory(const GURL& origin, | 113 SyncStatusCode SetOriginRootDirectory(const GURL& origin, |
| 142 OriginSyncType sync_type, | 114 OriginSyncType sync_type, |
| 143 const std::string& resource_id); | 115 const std::string& resource_id); |
| 144 SyncStatusCode UpdateEntry(const FileSystemURL& url, | 116 SyncStatusCode UpdateEntry(const FileSystemURL& url, |
| 145 DriveMetadata metadata); | 117 DriveMetadata metadata); |
| 146 SyncStatusCode DeleteEntry(const FileSystemURL& url); | 118 SyncStatusCode DeleteEntry(const FileSystemURL& url); |
| 147 | 119 |
| 148 // TODO(calvinlo): consolidate these state transition functions for sync | 120 // TODO(calvinlo): consolidate these state transition functions for sync |
| 149 // origins like "UpdateOrigin(GURL, SyncStatusEnum)". And manage origins in | 121 // origins like "UpdateOrigin(GURL, SyncStatusEnum)". And manage origins in |
| 150 // just one map like "Map<SyncStatusEnum, ResourceIDMap>". | 122 // just one map like "Map<SyncStatusEnum, ResourceIDMap>". |
| 151 // http://crbug.com/211600 | 123 // http://crbug.com/211600 |
| 152 SyncStatusCode UpdateOriginAsBatchSync(const GURL& origin, | |
| 153 const std::string& resource_id); | |
| 154 SyncStatusCode UpdateOriginAsIncrementalSync(const GURL& origin, | 124 SyncStatusCode UpdateOriginAsIncrementalSync(const GURL& origin, |
| 155 const std::string& resource_id); | 125 const std::string& resource_id); |
| 156 SyncStatusCode EnableOrigin(const GURL& origin, | 126 SyncStatusCode EnableOrigin(const GURL& origin, |
| 157 const std::string& resource_id); | 127 const std::string& resource_id); |
| 158 SyncStatusCode DisableOrigin(const GURL& origin, | 128 SyncStatusCode DisableOrigin(const GURL& origin, |
| 159 const std::string& resource_id); | 129 const std::string& resource_id); |
| 160 SyncStatusCode RemoveOrigin(const GURL& origin); | 130 SyncStatusCode RemoveOrigin(const GURL& origin); |
| 161 | 131 |
| 162 SyncStatusCode GetOrigins(ResourceIdByOrigin* incremental_sync_origins, | 132 SyncStatusCode GetOrigins(ResourceIdByOrigin* incremental_sync_origins, |
| 163 ResourceIdByOrigin* disabled_origins); | 133 ResourceIdByOrigin* disabled_origins); |
| (...skipping 609 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 773 status = db->Put(leveldb::WriteOptions(), | 743 status = db->Put(leveldb::WriteOptions(), |
| 774 kDatabaseVersionKey, | 744 kDatabaseVersionKey, |
| 775 base::Int64ToString(kCurrentDatabaseVersion)); | 745 base::Int64ToString(kCurrentDatabaseVersion)); |
| 776 if (!status.ok()) { | 746 if (!status.ok()) { |
| 777 delete db; | 747 delete db; |
| 778 return LevelDBStatusToSyncStatusCode(status); | 748 return LevelDBStatusToSyncStatusCode(status); |
| 779 } | 749 } |
| 780 } | 750 } |
| 781 | 751 |
| 782 db_.reset(db); | 752 db_.reset(db); |
| 783 | |
| 784 | |
| 785 // Deprecate legacy batch sync origin entries that are no longer needed. | |
| 786 leveldb::WriteBatch batch; | |
| 787 scoped_ptr<leveldb::Iterator> batch_origin_itr( | |
| 788 db_->NewIterator(leveldb::ReadOptions())); | |
| 789 for (batch_origin_itr->Seek(kDriveBatchSyncOriginKeyPrefix); | |
| 790 batch_origin_itr->Valid(); | |
| 791 batch_origin_itr->Next()) { | |
| 792 std::string key = batch_origin_itr->key().ToString(); | |
| 793 if (!StartsWithASCII(key, kDriveBatchSyncOriginKeyPrefix, true)) | |
| 794 break; | |
| 795 | |
| 796 batch.Delete(key); | |
| 797 } | |
| 798 status = db_->Write(leveldb::WriteOptions(), &batch); | |
| 799 return LevelDBStatusToSyncStatusCode(status); | 753 return LevelDBStatusToSyncStatusCode(status); |
| 800 } | 754 } |
| 801 | 755 |
| 802 SyncStatusCode DriveMetadataDB::ReadContents( | 756 SyncStatusCode DriveMetadataDB::ReadContents( |
| 803 DriveMetadataDBContents* contents) { | 757 DriveMetadataDBContents* contents) { |
| 804 DCHECK(CalledOnValidThread()); | 758 DCHECK(CalledOnValidThread()); |
| 805 DCHECK(db_.get()); | 759 DCHECK(db_.get()); |
| 806 DCHECK(contents); | 760 DCHECK(contents); |
| 807 | 761 |
| 808 contents->largest_changestamp = 0; | 762 contents->largest_changestamp = 0; |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 861 if (!success) | 815 if (!success) |
| 862 return SYNC_DATABASE_ERROR_FAILED; | 816 return SYNC_DATABASE_ERROR_FAILED; |
| 863 if (database_version > kCurrentDatabaseVersion) | 817 if (database_version > kCurrentDatabaseVersion) |
| 864 return SYNC_DATABASE_ERROR_FAILED; | 818 return SYNC_DATABASE_ERROR_FAILED; |
| 865 if (database_version == kCurrentDatabaseVersion) | 819 if (database_version == kCurrentDatabaseVersion) |
| 866 return SYNC_STATUS_OK; | 820 return SYNC_STATUS_OK; |
| 867 } | 821 } |
| 868 | 822 |
| 869 switch (database_version) { | 823 switch (database_version) { |
| 870 case 0: | 824 case 0: |
| 871 MigrateFromVersion0To1Database(); | 825 drive::MigrateDatabaseFromV0ToV1(db_.get()); |
| 872 // fall-through | 826 // fall-through |
| 873 case 1: | 827 case 1: |
| 874 drive::MigrateDatabaseFromV1ToV2(db_.get()); | 828 drive::MigrateDatabaseFromV1ToV2(db_.get()); |
| 875 return SYNC_STATUS_OK; | 829 return SYNC_STATUS_OK; |
| 876 } | 830 } |
| 877 return SYNC_DATABASE_ERROR_FAILED; | 831 return SYNC_DATABASE_ERROR_FAILED; |
| 878 } | 832 } |
| 879 | 833 |
| 880 SyncStatusCode DriveMetadataDB::MigrateFromVersion0To1Database() { | |
| 881 // Version 0 database format: | |
| 882 // key: "CHANGE_STAMP" | |
| 883 // value: <Largest Changestamp> | |
| 884 // | |
| 885 // key: "SYNC_ROOT_DIR" | |
| 886 // value: <Resource ID of the sync root directory> | |
| 887 // | |
| 888 // key: "METADATA: " + | |
| 889 // <FileSystemURL serialized by SerializeSyncableFileSystemURL> | |
| 890 // value: <Serialized DriveMetadata> | |
| 891 // | |
| 892 // key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin> | |
| 893 // value: <Resource ID of the drive directory for the origin> | |
| 894 // | |
| 895 // key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin> | |
| 896 // value: <Resource ID of the drive directory for the origin> | |
| 897 // | |
| 898 // Version 1 database format (changed keys/fields are marked with '*'): | |
| 899 // * key: "VERSION" (new) | |
| 900 // * value: 1 | |
| 901 // | |
| 902 // key: "CHANGE_STAMP" | |
| 903 // value: <Largest Changestamp> | |
| 904 // | |
| 905 // key: "SYNC_ROOT_DIR" | |
| 906 // value: <Resource ID of the sync root directory> | |
| 907 // | |
| 908 // * key: "METADATA: " + <Origin and URL> (changed) | |
| 909 // * value: <Serialized DriveMetadata> | |
| 910 // | |
| 911 // key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin> | |
| 912 // value: <Resource ID of the drive directory for the origin> | |
| 913 // | |
| 914 // key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin> | |
| 915 // value: <Resource ID of the drive directory for the origin> | |
| 916 // | |
| 917 // key: "DISABLED_ORIGIN: " + <URL string of a disabled origin> | |
| 918 // value: <Resource ID of the drive directory for the origin> | |
| 919 | |
| 920 leveldb::WriteBatch write_batch; | |
| 921 write_batch.Put(kDatabaseVersionKey, "1"); | |
| 922 | |
| 923 scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); | |
| 924 for (itr->Seek(kDriveMetadataKeyPrefix); itr->Valid(); itr->Next()) { | |
| 925 std::string key = itr->key().ToString(); | |
| 926 if (!StartsWithASCII(key, kDriveMetadataKeyPrefix, true)) | |
| 927 break; | |
| 928 std::string serialized_url( | |
| 929 key.begin() + kDriveMetadataKeyPrefixLength - 1, key.end()); | |
| 930 | |
| 931 GURL origin; | |
| 932 base::FilePath path; | |
| 933 bool success = ParseV0FormatFileSystemURLString( | |
| 934 GURL(serialized_url), &origin, &path); | |
| 935 DCHECK(success) << serialized_url; | |
| 936 std::string new_key = kDriveMetadataKeyPrefix + origin.spec() + | |
| 937 kMetadataKeySeparator + path.AsUTF8Unsafe(); | |
| 938 | |
| 939 write_batch.Put(new_key, itr->value()); | |
| 940 write_batch.Delete(key); | |
| 941 } | |
| 942 return LevelDBStatusToSyncStatusCode( | |
| 943 db_->Write(leveldb::WriteOptions(), &write_batch)); | |
| 944 } | |
| 945 | |
| 946 SyncStatusCode DriveMetadataDB::SetLargestChangestamp( | 834 SyncStatusCode DriveMetadataDB::SetLargestChangestamp( |
| 947 int64 largest_changestamp) { | 835 int64 largest_changestamp) { |
| 948 DCHECK(CalledOnValidThread()); | 836 DCHECK(CalledOnValidThread()); |
| 949 DCHECK(db_.get()); | 837 DCHECK(db_.get()); |
| 950 | 838 |
| 951 leveldb::Status status = db_->Put( | 839 leveldb::Status status = db_->Put( |
| 952 leveldb::WriteOptions(), | 840 leveldb::WriteOptions(), |
| 953 kChangeStampKey, base::Int64ToString(largest_changestamp)); | 841 kChangeStampKey, base::Int64ToString(largest_changestamp)); |
| 954 return LevelDBStatusToSyncStatusCode(status); | 842 return LevelDBStatusToSyncStatusCode(status); |
| 955 } | 843 } |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1150 | 1038 |
| 1151 bool result = disabled_origins->insert( | 1039 bool result = disabled_origins->insert( |
| 1152 std::make_pair(origin, origin_resource_id)).second; | 1040 std::make_pair(origin, origin_resource_id)).second; |
| 1153 DCHECK(result); | 1041 DCHECK(result); |
| 1154 } | 1042 } |
| 1155 | 1043 |
| 1156 return SYNC_STATUS_OK; | 1044 return SYNC_STATUS_OK; |
| 1157 } | 1045 } |
| 1158 | 1046 |
| 1159 } // namespace sync_file_system | 1047 } // namespace sync_file_system |
| OLD | NEW |