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.
5 #include "chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.h"
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"
13 #include "webkit/common/fileapi/file_system_types.h"
14 #include "webkit/common/fileapi/file_system_util.h"
16 namespace sync_file_system {
17 namespace drive_backend {
21 const base::FilePath::CharType kV0FormatPathPrefix[] =
22 FILE_PATH_LITERAL("drive/");
23 const char kWapiFileIdPrefix[] = "file:";
24 const char kWapiFolderIdPrefix[] = "folder:";
28 bool ParseV0FormatFileSystemURL(const GURL& url,
30 base::FilePath* path) {
31 fileapi::FileSystemType mount_type;
32 base::FilePath virtual_path;
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();
41 base::FilePath::StringType prefix =
42 base::FilePath(kV0FormatPathPrefix).NormalizePathSeparators().value();
43 if (virtual_path.value().substr(0, prefix.size()) != prefix)
46 *path = base::FilePath(virtual_path.value().substr(prefix.size()));
50 std::string AddWapiFilePrefix(const std::string& resource_id) {
51 DCHECK(!StartsWithASCII(resource_id, kWapiFileIdPrefix, true));
52 DCHECK(!StartsWithASCII(resource_id, kWapiFolderIdPrefix, true));
54 if (resource_id.empty() ||
55 StartsWithASCII(resource_id, kWapiFileIdPrefix, true) ||
56 StartsWithASCII(resource_id, kWapiFolderIdPrefix, true))
58 return kWapiFileIdPrefix + resource_id;
61 std::string AddWapiFolderPrefix(const std::string& resource_id) {
62 DCHECK(!StartsWithASCII(resource_id, kWapiFileIdPrefix, true));
63 DCHECK(!StartsWithASCII(resource_id, kWapiFolderIdPrefix, true));
65 if (resource_id.empty() ||
66 StartsWithASCII(resource_id, kWapiFileIdPrefix, true) ||
67 StartsWithASCII(resource_id, kWapiFolderIdPrefix, true))
69 return kWapiFolderIdPrefix + resource_id;
72 std::string AddWapiIdPrefix(const std::string& resource_id,
73 DriveMetadata_ResourceType 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);
84 std::string RemoveWapiIdPrefix(const std::string& resource_id) {
86 if (RemovePrefix(resource_id, kWapiFileIdPrefix, &value))
88 if (RemovePrefix(resource_id, kWapiFolderIdPrefix, &value))
93 SyncStatusCode MigrateDatabaseFromV0ToV1(leveldb::DB* db) {
94 // Version 0 database format:
95 // key: "CHANGE_STAMP"
96 // value: <Largest Changestamp>
98 // key: "SYNC_ROOT_DIR"
99 // value: <Resource ID of the sync root directory>
101 // key: "METADATA: " +
102 // <FileSystemURL serialized by SerializeSyncableFileSystemURL>
103 // value: <Serialized DriveMetadata>
105 // key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin>
106 // value: <Resource ID of the drive directory for the origin>
108 // key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin>
109 // value: <Resource ID of the drive directory for the origin>
111 // Version 1 database format (changed keys/fields are marked with '*'):
112 // * key: "VERSION" (new)
115 // key: "CHANGE_STAMP"
116 // value: <Largest Changestamp>
118 // key: "SYNC_ROOT_DIR"
119 // value: <Resource ID of the sync root directory>
121 // * key: "METADATA: " + <Origin and URL> (changed)
122 // * value: <Serialized DriveMetadata>
124 // key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin>
125 // value: <Resource ID of the drive directory for the origin>
127 // key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin>
128 // value: <Resource ID of the drive directory for the origin>
130 // key: "DISABLED_ORIGIN: " + <URL string of a disabled origin>
131 // value: <Resource ID of the drive directory for the origin>
133 const char kDatabaseVersionKey[] = "VERSION";
134 const char kDriveMetadataKeyPrefix[] = "METADATA: ";
135 const char kMetadataKeySeparator = ' ';
137 leveldb::WriteBatch write_batch;
138 write_batch.Put(kDatabaseVersionKey, "1");
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))
145 std::string serialized_url;
146 RemovePrefix(key, kDriveMetadataKeyPrefix, &serialized_url);
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();
156 write_batch.Put(new_key, itr->value());
157 write_batch.Delete(key);
160 return LevelDBStatusToSyncStatusCode(
161 db->Write(leveldb::WriteOptions(), &write_batch));
164 SyncStatusCode 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")
168 // Version 2 database format (changed keys/fields are marked with '*'):
172 // key: "CHANGE_STAMP"
173 // value: <Largest Changestamp>
175 // key: "SYNC_ROOT_DIR"
176 // * value: <Resource ID of the sync root directory> (striped)
178 // key: "METADATA: " + <Origin and URL>
179 // * value: <Serialized DriveMetadata> (stripped)
181 // * key: "BSYNC_ORIGIN: " + <URL string of a batch sync origin> (deleted)
182 // * value: <Resource ID of the drive directory for the origin> (deleted)
184 // key: "ISYNC_ORIGIN: " + <URL string of a incremental sync origin>
185 // * value: <Resource ID of the drive directory for the origin> (stripped)
187 // key: "DISABLED_ORIGIN: " + <URL string of a disabled origin>
188 // * value: <Resource ID of the drive directory for the origin> (stripped)
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: ";
197 leveldb::WriteBatch write_batch;
198 write_batch.Put(kDatabaseVersionKey, "2");
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();
204 // Strip resource id for the sync root directory.
205 if (StartsWithASCII(key, kSyncRootDirectoryKey, true)) {
206 write_batch.Put(key, RemoveWapiIdPrefix(itr->value().ToString()));
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());
216 metadata.set_resource_id(RemoveWapiIdPrefix(metadata.resource_id()));
217 std::string metadata_string;
218 metadata.SerializeToString(&metadata_string);
220 write_batch.Put(key, metadata_string);
224 // Deprecate legacy batch sync origin entries that are no longer needed.
225 if (StartsWithASCII(key, kDriveBatchSyncOriginKeyPrefix, true)) {
226 write_batch.Delete(key);
230 // Strip resource ids of the incremental sync origins.
231 if (StartsWithASCII(key, kDriveIncrementalSyncOriginKeyPrefix, true)) {
232 write_batch.Put(key, RemoveWapiIdPrefix(itr->value().ToString()));
236 // Strip resource ids of the disabled sync origins.
237 if (StartsWithASCII(key, kDriveDisabledOriginKeyPrefix, true)) {
238 write_batch.Put(key, RemoveWapiIdPrefix(itr->value().ToString()));
243 return LevelDBStatusToSyncStatusCode(
244 db->Write(leveldb::WriteOptions(), &write_batch));
247 SyncStatusCode 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.
252 const char kDatabaseVersionKey[] = "VERSION";
253 const char kServiceMetadataKey[] = "SERVICE";
254 const char kFileMetadataKeyPrefix[] = "FILE: ";
255 const char kFileTrackerKeyPrefix[] = "TRACKER: ";
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: ";
268 leveldb::WriteBatch write_batch;
269 write_batch.Put(kDatabaseVersionKey, "3");
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();
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)) {
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);
296 DVLOG(3) << "Unknown key: " << key << " was found.";
299 return LevelDBStatusToSyncStatusCode(
300 db->Write(leveldb::WriteOptions(), &write_batch));
303 } // namespace drive_backend
304 } // namespace sync_file_system