metadata_db_migration_util.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.h" 6 7#include "base/files/file_path.h" 8#include "base/memory/scoped_ptr.h" 9#include "base/strings/string_util.h" 10#include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h" 11#include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 12#include "url/gurl.h" 13#include "webkit/common/fileapi/file_system_types.h" 14#include "webkit/common/fileapi/file_system_util.h" 15 16namespace sync_file_system { 17namespace drive_backend { 18 19namespace { 20 21const base::FilePath::CharType kV0FormatPathPrefix[] = 22 FILE_PATH_LITERAL("drive/"); 23const char kWapiFileIdPrefix[] = "file:"; 24const char kWapiFolderIdPrefix[] = "folder:"; 25 26} // namespace 27 28bool ParseV0FormatFileSystemURL(const GURL& url, 29 GURL* origin, 30 base::FilePath* path) { 31 fileapi::FileSystemType mount_type; 32 base::FilePath virtual_path; 33 34 if (!fileapi::ParseFileSystemSchemeURL( 35 url, origin, &mount_type, &virtual_path) || 36 mount_type != fileapi::kFileSystemTypeExternal) { 37 NOTREACHED() << "Failed to parse filesystem scheme URL " << url.spec(); 38 return false; 39 } 40 41 base::FilePath::StringType prefix = 42 base::FilePath(kV0FormatPathPrefix).NormalizePathSeparators().value(); 43 if (virtual_path.value().substr(0, prefix.size()) != prefix) 44 return false; 45 46 *path = base::FilePath(virtual_path.value().substr(prefix.size())); 47 return true; 48} 49 50std::string AddWapiFilePrefix(const std::string& resource_id) { 51 DCHECK(!StartsWithASCII(resource_id, kWapiFileIdPrefix, true)); 52 DCHECK(!StartsWithASCII(resource_id, kWapiFolderIdPrefix, true)); 53 54 if (resource_id.empty() || 55 StartsWithASCII(resource_id, kWapiFileIdPrefix, true) || 56 StartsWithASCII(resource_id, kWapiFolderIdPrefix, true)) 57 return resource_id; 58 return kWapiFileIdPrefix + resource_id; 59} 60 61std::string AddWapiFolderPrefix(const std::string& resource_id) { 62 DCHECK(!StartsWithASCII(resource_id, kWapiFileIdPrefix, true)); 63 DCHECK(!StartsWithASCII(resource_id, kWapiFolderIdPrefix, true)); 64 65 if (resource_id.empty() || 66 StartsWithASCII(resource_id, kWapiFileIdPrefix, true) || 67 StartsWithASCII(resource_id, kWapiFolderIdPrefix, true)) 68 return resource_id; 69 return kWapiFolderIdPrefix + resource_id; 70} 71 72std::string AddWapiIdPrefix(const std::string& resource_id, 73 DriveMetadata_ResourceType type) { 74 switch (type) { 75 case DriveMetadata_ResourceType_RESOURCE_TYPE_FILE: 76 return AddWapiFilePrefix(resource_id); 77 case DriveMetadata_ResourceType_RESOURCE_TYPE_FOLDER: 78 return AddWapiFolderPrefix(resource_id); 79 } 80 NOTREACHED(); 81 return resource_id; 82} 83 84std::string RemoveWapiIdPrefix(const std::string& resource_id) { 85 std::string value; 86 if (RemovePrefix(resource_id, kWapiFileIdPrefix, &value)) 87 return value; 88 if (RemovePrefix(resource_id, kWapiFolderIdPrefix, &value)) 89 return value; 90 return resource_id; 91} 92 93SyncStatusCode MigrateDatabaseFromV0ToV1(leveldb::DB* db) { 94 // Version 0 database format: 95 // key: "CHANGE_STAMP" 96 // value: <Largest Changestamp> 97 // 98 // key: "SYNC_ROOT_DIR" 99 // value: <Resource ID of the sync root directory> 100 // 101 // key: "METADATA: " + 102 // <FileSystemURL serialized by SerializeSyncableFileSystemURL> 103 // value: <Serialized DriveMetadata> 104 // 105 // key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin> 106 // value: <Resource ID of the drive directory for the origin> 107 // 108 // key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin> 109 // value: <Resource ID of the drive directory for the origin> 110 // 111 // Version 1 database format (changed keys/fields are marked with '*'): 112 // * key: "VERSION" (new) 113 // * value: 1 114 // 115 // key: "CHANGE_STAMP" 116 // value: <Largest Changestamp> 117 // 118 // key: "SYNC_ROOT_DIR" 119 // value: <Resource ID of the sync root directory> 120 // 121 // * key: "METADATA: " + <Origin and URL> (changed) 122 // * value: <Serialized DriveMetadata> 123 // 124 // key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin> 125 // value: <Resource ID of the drive directory for the origin> 126 // 127 // key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin> 128 // value: <Resource ID of the drive directory for the origin> 129 // 130 // key: "DISABLED_ORIGIN: " + <URL string of a disabled origin> 131 // value: <Resource ID of the drive directory for the origin> 132 133 const char kDatabaseVersionKey[] = "VERSION"; 134 const char kDriveMetadataKeyPrefix[] = "METADATA: "; 135 const char kMetadataKeySeparator = ' '; 136 137 leveldb::WriteBatch write_batch; 138 write_batch.Put(kDatabaseVersionKey, "1"); 139 140 scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions())); 141 for (itr->Seek(kDriveMetadataKeyPrefix); itr->Valid(); itr->Next()) { 142 std::string key = itr->key().ToString(); 143 if (!StartsWithASCII(key, kDriveMetadataKeyPrefix, true)) 144 break; 145 std::string serialized_url; 146 RemovePrefix(key, kDriveMetadataKeyPrefix, &serialized_url); 147 148 GURL origin; 149 base::FilePath path; 150 bool success = ParseV0FormatFileSystemURL( 151 GURL(serialized_url), &origin, &path); 152 DCHECK(success) << serialized_url; 153 std::string new_key = kDriveMetadataKeyPrefix + origin.spec() + 154 kMetadataKeySeparator + path.AsUTF8Unsafe(); 155 156 write_batch.Put(new_key, itr->value()); 157 write_batch.Delete(key); 158 } 159 160 return LevelDBStatusToSyncStatusCode( 161 db->Write(leveldb::WriteOptions(), &write_batch)); 162} 163 164SyncStatusCode MigrateDatabaseFromV1ToV2(leveldb::DB* db) { 165 // Strips prefix of WAPI resource ID, and discards batch sync origins. 166 // (i.e. "file:xxxx" => "xxxx", "folder:yyyy" => "yyyy") 167 // 168 // Version 2 database format (changed keys/fields are marked with '*'): 169 // key: "VERSION" 170 // * value: 2 171 // 172 // key: "CHANGE_STAMP" 173 // value: <Largest Changestamp> 174 // 175 // key: "SYNC_ROOT_DIR" 176 // * value: <Resource ID of the sync root directory> (striped) 177 // 178 // key: "METADATA: " + <Origin and URL> 179 // * value: <Serialized DriveMetadata> (stripped) 180 // 181 // * key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin> (deleted) 182 // * value: <Resource ID of the drive directory for the origin> (deleted) 183 // 184 // key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin> 185 // * value: <Resource ID of the drive directory for the origin> (stripped) 186 // 187 // key: "DISABLED_ORIGIN: " + <URL string of a disabled origin> 188 // * value: <Resource ID of the drive directory for the origin> (stripped) 189 190 const char kDatabaseVersionKey[] = "VERSION"; 191 const char kSyncRootDirectoryKey[] = "SYNC_ROOT_DIR"; 192 const char kDriveMetadataKeyPrefix[] = "METADATA: "; 193 const char kDriveBatchSyncOriginKeyPrefix[] = "BSYNC_ORIGIN: "; 194 const char kDriveIncrementalSyncOriginKeyPrefix[] = "ISYNC_ORIGIN: "; 195 const char kDriveDisabledOriginKeyPrefix[] = "DISABLED_ORIGIN: "; 196 197 leveldb::WriteBatch write_batch; 198 write_batch.Put(kDatabaseVersionKey, "2"); 199 200 scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions())); 201 for (itr->SeekToFirst(); itr->Valid(); itr->Next()) { 202 std::string key = itr->key().ToString(); 203 204 // Strip resource id for the sync root directory. 205 if (StartsWithASCII(key, kSyncRootDirectoryKey, true)) { 206 write_batch.Put(key, RemoveWapiIdPrefix(itr->value().ToString())); 207 continue; 208 } 209 210 // Strip resource ids in the drive metadata. 211 if (StartsWithASCII(key, kDriveMetadataKeyPrefix, true)) { 212 DriveMetadata metadata; 213 bool success = metadata.ParseFromString(itr->value().ToString()); 214 DCHECK(success); 215 216 metadata.set_resource_id(RemoveWapiIdPrefix(metadata.resource_id())); 217 std::string metadata_string; 218 metadata.SerializeToString(&metadata_string); 219 220 write_batch.Put(key, metadata_string); 221 continue; 222 } 223 224 // Deprecate legacy batch sync origin entries that are no longer needed. 225 if (StartsWithASCII(key, kDriveBatchSyncOriginKeyPrefix, true)) { 226 write_batch.Delete(key); 227 continue; 228 } 229 230 // Strip resource ids of the incremental sync origins. 231 if (StartsWithASCII(key, kDriveIncrementalSyncOriginKeyPrefix, true)) { 232 write_batch.Put(key, RemoveWapiIdPrefix(itr->value().ToString())); 233 continue; 234 } 235 236 // Strip resource ids of the disabled sync origins. 237 if (StartsWithASCII(key, kDriveDisabledOriginKeyPrefix, true)) { 238 write_batch.Put(key, RemoveWapiIdPrefix(itr->value().ToString())); 239 continue; 240 } 241 } 242 243 return LevelDBStatusToSyncStatusCode( 244 db->Write(leveldb::WriteOptions(), &write_batch)); 245} 246 247SyncStatusCode MigrateDatabaseFromV4ToV3(leveldb::DB* db) { 248 // Rollback from version 4 to version 3. 249 // Please see metadata_database_index.cc for version 3 format, and 250 // metadata_database_index_on_disk.cc for version 4 format. 251 252 const char kDatabaseVersionKey[] = "VERSION"; 253 const char kServiceMetadataKey[] = "SERVICE"; 254 const char kFileMetadataKeyPrefix[] = "FILE: "; 255 const char kFileTrackerKeyPrefix[] = "TRACKER: "; 256 257 // Key prefixes used in version 4. 258 const char kAppRootIDByAppIDKeyPrefix[] = "APP_ROOT: "; 259 const char kActiveTrackerIDByFileIDKeyPrefix[] = "ACTIVE_FILE: "; 260 const char kTrackerIDByFileIDKeyPrefix[] = "TRACKER_FILE: "; 261 const char kMultiTrackerByFileIDKeyPrefix[] = "MULTI_FILE: "; 262 const char kActiveTrackerIDByParentAndTitleKeyPrefix[] = "ACTIVE_PATH: "; 263 const char kTrackerIDByParentAndTitleKeyPrefix[] = "TRACKER_PATH: "; 264 const char kMultiBackingParentAndTitleKeyPrefix[] = "MULTI_PATH: "; 265 const char kDirtyIDKeyPrefix[] = "DIRTY: "; 266 const char kDemotedDirtyIDKeyPrefix[] = "DEMOTED_DIRTY: "; 267 268 leveldb::WriteBatch write_batch; 269 write_batch.Put(kDatabaseVersionKey, "3"); 270 271 scoped_ptr<leveldb::Iterator> itr(db->NewIterator(leveldb::ReadOptions())); 272 for (itr->SeekToFirst(); itr->Valid(); itr->Next()) { 273 std::string key = itr->key().ToString(); 274 275 // Do nothing for valid entries in both versions. 276 if (StartsWithASCII(key, kServiceMetadataKey, true) || 277 StartsWithASCII(key, kFileMetadataKeyPrefix, true) || 278 StartsWithASCII(key, kFileTrackerKeyPrefix, true)) { 279 continue; 280 } 281 282 // Drop entries used in version 4 only. 283 if (StartsWithASCII(key, kAppRootIDByAppIDKeyPrefix, true) || 284 StartsWithASCII(key, kActiveTrackerIDByFileIDKeyPrefix, true) || 285 StartsWithASCII(key, kTrackerIDByFileIDKeyPrefix, true) || 286 StartsWithASCII(key, kMultiTrackerByFileIDKeyPrefix, true) || 287 StartsWithASCII(key, kActiveTrackerIDByParentAndTitleKeyPrefix, true) || 288 StartsWithASCII(key, kTrackerIDByParentAndTitleKeyPrefix, true) || 289 StartsWithASCII(key, kMultiBackingParentAndTitleKeyPrefix, true) || 290 StartsWithASCII(key, kDirtyIDKeyPrefix, true) || 291 StartsWithASCII(key, kDemotedDirtyIDKeyPrefix, true)) { 292 write_batch.Delete(key); 293 continue; 294 } 295 296 DVLOG(3) << "Unknown key: " << key << " was found."; 297 } 298 299 return LevelDBStatusToSyncStatusCode( 300 db->Write(leveldb::WriteOptions(), &write_batch)); 301} 302 303} // namespace drive_backend 304} // namespace sync_file_system 305