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 "sync/syncable/directory_backing_store.h" | 5 #include "sync/syncable/directory_backing_store.h" |
6 | 6 |
7 #include "build/build_config.h" | 7 #include "build/build_config.h" |
8 | 8 |
9 #include <limits> | 9 #include <limits> |
10 | 10 |
(...skipping 22 matching lines...) Expand all Loading... | |
33 | 33 |
34 namespace syncer { | 34 namespace syncer { |
35 namespace syncable { | 35 namespace syncable { |
36 | 36 |
37 // This just has to be big enough to hold an UPDATE or INSERT statement that | 37 // This just has to be big enough to hold an UPDATE or INSERT statement that |
38 // modifies all the columns in the entry table. | 38 // modifies all the columns in the entry table. |
39 static const string::size_type kUpdateStatementBufferSize = 2048; | 39 static const string::size_type kUpdateStatementBufferSize = 2048; |
40 | 40 |
41 // Increment this version whenever updating DB tables. | 41 // Increment this version whenever updating DB tables. |
42 extern const int32 kCurrentDBVersion; // Global visibility for our unittest. | 42 extern const int32 kCurrentDBVersion; // Global visibility for our unittest. |
43 const int32 kCurrentDBVersion = 83; | 43 const int32 kCurrentDBVersion = 84; |
44 | 44 |
45 // Iterate over the fields of |entry| and bind each to |statement| for | 45 // Iterate over the fields of |entry| and bind each to |statement| for |
46 // updating. Returns the number of args bound. | 46 // updating. Returns the number of args bound. |
47 void BindFields(const EntryKernel& entry, | 47 void BindFields(const EntryKernel& entry, |
48 sql::Statement* statement) { | 48 sql::Statement* statement) { |
49 int index = 0; | 49 int index = 0; |
50 int i = 0; | 50 int i = 0; |
51 for (i = BEGIN_FIELDS; i < INT64_FIELDS_END; ++i) { | 51 for (i = BEGIN_FIELDS; i < INT64_FIELDS_END; ++i) { |
52 statement->BindInt64(index++, entry.ref(static_cast<Int64Field>(i))); | 52 statement->BindInt64(index++, entry.ref(static_cast<Int64Field>(i))); |
53 } | 53 } |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
190 } | 190 } |
191 | 191 |
192 bool DirectoryBackingStore::SaveChanges( | 192 bool DirectoryBackingStore::SaveChanges( |
193 const Directory::SaveChangesSnapshot& snapshot) { | 193 const Directory::SaveChangesSnapshot& snapshot) { |
194 DCHECK(CalledOnValidThread()); | 194 DCHECK(CalledOnValidThread()); |
195 DCHECK(db_->is_open()); | 195 DCHECK(db_->is_open()); |
196 | 196 |
197 // Back out early if there is nothing to write. | 197 // Back out early if there is nothing to write. |
198 bool save_info = | 198 bool save_info = |
199 (Directory::KERNEL_SHARE_INFO_DIRTY == snapshot.kernel_info_status); | 199 (Directory::KERNEL_SHARE_INFO_DIRTY == snapshot.kernel_info_status); |
200 if (snapshot.dirty_metas.size() < 1 && !save_info) | 200 if (snapshot.dirty_metas.empty() |
201 && snapshot.metahandles_to_purge.empty() | |
202 && !save_info) { | |
201 return true; | 203 return true; |
204 } | |
202 | 205 |
203 sql::Transaction transaction(db_.get()); | 206 sql::Transaction transaction(db_.get()); |
204 if (!transaction.Begin()) | 207 if (!transaction.Begin()) |
205 return false; | 208 return false; |
206 | 209 |
207 for (EntryKernelSet::const_iterator i = snapshot.dirty_metas.begin(); | 210 for (EntryKernelSet::const_iterator i = snapshot.dirty_metas.begin(); |
208 i != snapshot.dirty_metas.end(); ++i) { | 211 i != snapshot.dirty_metas.end(); ++i) { |
209 DCHECK(i->is_dirty()); | 212 DCHECK(i->is_dirty()); |
210 if (!SaveEntryToDB(*i)) | 213 if (!SaveEntryToDB(*i)) |
211 return false; | 214 return false; |
(...skipping 17 matching lines...) Expand all Loading... | |
229 info.notification_state.size()); | 232 info.notification_state.size()); |
230 s1.BindBlob(3, info.bag_of_chips.data(), info.bag_of_chips.size()); | 233 s1.BindBlob(3, info.bag_of_chips.data(), info.bag_of_chips.size()); |
231 | 234 |
232 if (!s1.Run()) | 235 if (!s1.Run()) |
233 return false; | 236 return false; |
234 DCHECK_EQ(db_->GetLastChangeCount(), 1); | 237 DCHECK_EQ(db_->GetLastChangeCount(), 1); |
235 | 238 |
236 sql::Statement s2(db_->GetCachedStatement( | 239 sql::Statement s2(db_->GetCachedStatement( |
237 SQL_FROM_HERE, | 240 SQL_FROM_HERE, |
238 "INSERT OR REPLACE " | 241 "INSERT OR REPLACE " |
239 "INTO models (model_id, progress_marker, initial_sync_ended, " | 242 "INTO models (model_id, progress_marker, transaction_version) " |
240 " transaction_version) " | 243 "VALUES (?, ?, ?)")); |
241 "VALUES (?, ?, ?, ?)")); | |
242 | 244 |
243 for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) { | 245 for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) { |
244 // We persist not ModelType but rather a protobuf-derived ID. | 246 // We persist not ModelType but rather a protobuf-derived ID. |
245 string model_id = ModelTypeEnumToModelId(ModelTypeFromInt(i)); | 247 string model_id = ModelTypeEnumToModelId(ModelTypeFromInt(i)); |
246 string progress_marker; | 248 string progress_marker; |
247 info.download_progress[i].SerializeToString(&progress_marker); | 249 info.download_progress[i].SerializeToString(&progress_marker); |
248 s2.BindBlob(0, model_id.data(), model_id.length()); | 250 s2.BindBlob(0, model_id.data(), model_id.length()); |
249 s2.BindBlob(1, progress_marker.data(), progress_marker.length()); | 251 s2.BindBlob(1, progress_marker.data(), progress_marker.length()); |
250 s2.BindBool(2, info.initial_sync_ended.Has(ModelTypeFromInt(i))); | 252 s2.BindInt64(2, info.transaction_version[i]); |
251 s2.BindInt64(3, info.transaction_version[i]); | |
252 if (!s2.Run()) | 253 if (!s2.Run()) |
253 return false; | 254 return false; |
254 DCHECK_EQ(db_->GetLastChangeCount(), 1); | 255 DCHECK_EQ(db_->GetLastChangeCount(), 1); |
255 s2.Reset(true); | 256 s2.Reset(true); |
256 } | 257 } |
257 } | 258 } |
258 | 259 |
259 return transaction.Commit(); | 260 return transaction.Commit(); |
260 } | 261 } |
261 | 262 |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
357 if (MigrateVersion81To82()) | 358 if (MigrateVersion81To82()) |
358 version_on_disk = 82; | 359 version_on_disk = 82; |
359 } | 360 } |
360 | 361 |
361 // Version 83 migration added transaction_version column per sync entry. | 362 // Version 83 migration added transaction_version column per sync entry. |
362 if (version_on_disk == 82) { | 363 if (version_on_disk == 82) { |
363 if (MigrateVersion82To83()) | 364 if (MigrateVersion82To83()) |
364 version_on_disk = 83; | 365 version_on_disk = 83; |
365 } | 366 } |
366 | 367 |
368 // Version 84 migration removes the initial_sync_ended bits. | |
369 if (version_on_disk == 83) { | |
370 if (MigrateVersion83To84()) | |
371 version_on_disk = 84; | |
372 } | |
373 | |
367 // If one of the migrations requested it, drop columns that aren't current. | 374 // If one of the migrations requested it, drop columns that aren't current. |
368 // It's only safe to do this after migrating all the way to the current | 375 // It's only safe to do this after migrating all the way to the current |
369 // version. | 376 // version. |
370 if (version_on_disk == kCurrentDBVersion && needs_column_refresh_) { | 377 if (version_on_disk == kCurrentDBVersion && needs_column_refresh_) { |
371 if (!RefreshColumns()) | 378 if (!RefreshColumns()) |
372 version_on_disk = 0; | 379 version_on_disk = 0; |
373 } | 380 } |
374 | 381 |
375 // A final, alternative catch-all migration to simply re-sync everything. | 382 // A final, alternative catch-all migration to simply re-sync everything. |
376 // | 383 // |
377 // TODO(rlarocque): It's wrong to recreate the database here unless the higher | 384 // TODO(rlarocque): It's wrong to recreate the database here unless the higher |
rlarocque
2012/12/12 01:19:16
I've been meaning to delete this comment for a whi
| |
378 // layers were expecting us to do so. See crbug.com/103824. We must leave | 385 // layers were expecting us to do so. See crbug.com/103824. We must leave |
379 // this code as is for now because this is the code that ends up creating the | 386 // this code as is for now because this is the code that ends up creating the |
380 // database in the first time sync case, where the higher layers are expecting | 387 // database in the first time sync case, where the higher layers are expecting |
381 // us to create a fresh database. The solution to this should be to implement | 388 // us to create a fresh database. The solution to this should be to implement |
382 // crbug.com/105018. | 389 // crbug.com/105018. |
383 if (version_on_disk != kCurrentDBVersion) { | 390 if (version_on_disk != kCurrentDBVersion) { |
384 if (version_on_disk > kCurrentDBVersion) | 391 if (version_on_disk > kCurrentDBVersion) |
385 return false; | 392 return false; |
386 | 393 |
387 // Fallback (re-sync everything) migration path. | 394 // Fallback (re-sync everything) migration path. |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
495 s.ColumnBlobAsString(4, &(info->kernel_info.bag_of_chips)); | 502 s.ColumnBlobAsString(4, &(info->kernel_info.bag_of_chips)); |
496 | 503 |
497 // Verify there was only one row returned. | 504 // Verify there was only one row returned. |
498 DCHECK(!s.Step()); | 505 DCHECK(!s.Step()); |
499 DCHECK(s.Succeeded()); | 506 DCHECK(s.Succeeded()); |
500 } | 507 } |
501 | 508 |
502 { | 509 { |
503 sql::Statement s( | 510 sql::Statement s( |
504 db_->GetUniqueStatement( | 511 db_->GetUniqueStatement( |
505 "SELECT model_id, progress_marker, initial_sync_ended, " | 512 "SELECT model_id, progress_marker, " |
506 "transaction_version FROM models")); | 513 "transaction_version FROM models")); |
507 | 514 |
508 while (s.Step()) { | 515 while (s.Step()) { |
509 ModelType type = ModelIdToModelTypeEnum(s.ColumnBlob(0), | 516 ModelType type = ModelIdToModelTypeEnum(s.ColumnBlob(0), |
510 s.ColumnByteLength(0)); | 517 s.ColumnByteLength(0)); |
511 if (type != UNSPECIFIED && type != TOP_LEVEL_FOLDER) { | 518 if (type != UNSPECIFIED && type != TOP_LEVEL_FOLDER) { |
512 info->kernel_info.download_progress[type].ParseFromArray( | 519 info->kernel_info.download_progress[type].ParseFromArray( |
513 s.ColumnBlob(1), s.ColumnByteLength(1)); | 520 s.ColumnBlob(1), s.ColumnByteLength(1)); |
514 if (s.ColumnBool(2)) | 521 info->kernel_info.transaction_version[type] = s.ColumnInt64(2); |
515 info->kernel_info.initial_sync_ended.Put(type); | |
516 info->kernel_info.transaction_version[type] = s.ColumnInt64(3); | |
517 } | 522 } |
518 } | 523 } |
519 if (!s.Succeeded()) | 524 if (!s.Succeeded()) |
520 return false; | 525 return false; |
521 } | 526 } |
522 { | 527 { |
523 sql::Statement s( | 528 sql::Statement s( |
524 db_->GetUniqueStatement( | 529 db_->GetUniqueStatement( |
525 "SELECT MAX(metahandle) FROM metas")); | 530 "SELECT MAX(metahandle) FROM metas")); |
526 if (!s.Step()) | 531 if (!s.Step()) |
(...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
901 // boolean initial_sync_ended | 906 // boolean initial_sync_ended |
902 // In version 75, we deprecated the integer-valued last_download_timestamp, | 907 // In version 75, we deprecated the integer-valued last_download_timestamp, |
903 // using insted a protobuf-valued progress_marker field: | 908 // using insted a protobuf-valued progress_marker field: |
904 // blob progress_marker | 909 // blob progress_marker |
905 // The progress_marker values are initialized from the value of | 910 // The progress_marker values are initialized from the value of |
906 // last_download_timestamp, thereby preserving the download state. | 911 // last_download_timestamp, thereby preserving the download state. |
907 | 912 |
908 // Move aside the old table and create a new empty one at the current schema. | 913 // Move aside the old table and create a new empty one at the current schema. |
909 if (!db_->Execute("ALTER TABLE models RENAME TO temp_models")) | 914 if (!db_->Execute("ALTER TABLE models RENAME TO temp_models")) |
910 return false; | 915 return false; |
911 if (!CreateModelsTable()) | 916 if (!CreateV75ModelsTable()) |
912 return false; | 917 return false; |
913 | 918 |
914 sql::Statement query(db_->GetUniqueStatement( | 919 sql::Statement query(db_->GetUniqueStatement( |
915 "SELECT model_id, last_download_timestamp, initial_sync_ended " | 920 "SELECT model_id, last_download_timestamp, initial_sync_ended " |
916 "FROM temp_models")); | 921 "FROM temp_models")); |
917 | 922 |
918 sql::Statement update(db_->GetUniqueStatement( | 923 sql::Statement update(db_->GetUniqueStatement( |
919 "INSERT INTO models (model_id, " | 924 "INSERT INTO models (model_id, " |
920 "progress_marker, initial_sync_ended) VALUES (?, ?, ?)")); | 925 "progress_marker, initial_sync_ended) VALUES (?, ?, ?)")); |
921 | 926 |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1052 return false; | 1057 return false; |
1053 put_ordinals.Reset(true); | 1058 put_ordinals.Reset(true); |
1054 } | 1059 } |
1055 | 1060 |
1056 SetVersion(81); | 1061 SetVersion(81); |
1057 needs_column_refresh_ = true; | 1062 needs_column_refresh_ = true; |
1058 return true; | 1063 return true; |
1059 } | 1064 } |
1060 | 1065 |
1061 bool DirectoryBackingStore::MigrateVersion81To82() { | 1066 bool DirectoryBackingStore::MigrateVersion81To82() { |
1062 // Version 82 added transaction_version to kernel info. But if user is | 1067 // Version 82 added transaction_version to kernel info. But if user is |
rlarocque
2012/12/12 01:19:16
This is the wrong way to handle a change in the Cr
| |
1063 // migrating from 74 or before, 74->75 migration would recreate models table | 1068 // migrating from 74 or before, 74->75 migration would recreate models table |
1064 // that already has transaction_version column. | 1069 // that already has transaction_version column. |
1065 if (db_->DoesColumnExist("models", "transaction_version")) { | 1070 if (db_->DoesColumnExist("models", "transaction_version")) { |
1066 SetVersion(82); | 1071 SetVersion(82); |
1067 return true; | 1072 return true; |
1068 } | 1073 } |
1069 | 1074 |
1070 if (!db_->Execute( | 1075 if (!db_->Execute( |
1071 "ALTER TABLE models ADD COLUMN transaction_version BIGINT default 0")) | 1076 "ALTER TABLE models ADD COLUMN transaction_version BIGINT default 0")) |
1072 return false; | 1077 return false; |
(...skipping 11 matching lines...) Expand all Loading... | |
1084 "ALTER TABLE metas ADD COLUMN transaction_version BIGINT default 0")) | 1089 "ALTER TABLE metas ADD COLUMN transaction_version BIGINT default 0")) |
1085 return false; | 1090 return false; |
1086 sql::Statement update(db_->GetUniqueStatement( | 1091 sql::Statement update(db_->GetUniqueStatement( |
1087 "UPDATE metas SET transaction_version = 0")); | 1092 "UPDATE metas SET transaction_version = 0")); |
1088 if (!update.Run()) | 1093 if (!update.Run()) |
1089 return false; | 1094 return false; |
1090 SetVersion(83); | 1095 SetVersion(83); |
1091 return true; | 1096 return true; |
1092 } | 1097 } |
1093 | 1098 |
1099 | |
1100 bool DirectoryBackingStore::MigrateVersion83To84() { | |
1101 // Version 84 removes the initial_sync_ended flag. | |
1102 if (!db_->Execute("ALTER TABLE models RENAME TO temp_models")) | |
1103 return false; | |
1104 if (!CreateModelsTable()) | |
1105 return false; | |
1106 if (!db_->Execute("INSERT INTO models SELECT " | |
1107 "model_id, progress_marker, transaction_version " | |
1108 "FROM temp_models")) { | |
1109 return false; | |
1110 } | |
1111 SafeDropTable("temp_models"); | |
1112 SetVersion(84); | |
1113 return true; | |
1114 } | |
1115 | |
1094 bool DirectoryBackingStore::CreateTables() { | 1116 bool DirectoryBackingStore::CreateTables() { |
1095 DVLOG(1) << "First run, creating tables"; | 1117 DVLOG(1) << "First run, creating tables"; |
1096 // Create two little tables share_version and share_info | 1118 // Create two little tables share_version and share_info |
1097 if (!db_->Execute( | 1119 if (!db_->Execute( |
1098 "CREATE TABLE share_version (" | 1120 "CREATE TABLE share_version (" |
1099 "id VARCHAR(128) primary key, data INT)")) { | 1121 "id VARCHAR(128) primary key, data INT)")) { |
1100 return false; | 1122 return false; |
1101 } | 1123 } |
1102 | 1124 |
1103 { | 1125 { |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1181 return db_->Execute( | 1203 return db_->Execute( |
1182 "CREATE TABLE models (" | 1204 "CREATE TABLE models (" |
1183 "model_id BLOB primary key, " | 1205 "model_id BLOB primary key, " |
1184 "last_download_timestamp INT, " | 1206 "last_download_timestamp INT, " |
1185 // Gets set if the syncer ever gets updates from the | 1207 // Gets set if the syncer ever gets updates from the |
1186 // server and the server returns 0. Lets us detect the | 1208 // server and the server returns 0. Lets us detect the |
1187 // end of the initial sync. | 1209 // end of the initial sync. |
1188 "initial_sync_ended BOOLEAN default 0)"); | 1210 "initial_sync_ended BOOLEAN default 0)"); |
1189 } | 1211 } |
1190 | 1212 |
1213 bool DirectoryBackingStore::CreateV75ModelsTable() { | |
1214 // This is an old schema for the Models table, used from versions 75 to 83. | |
1215 return db_->Execute( | |
1216 "CREATE TABLE models (" | |
1217 "model_id BLOB primary key, " | |
1218 "progress_marker BLOB, " | |
1219 // Gets set if the syncer ever gets updates from the | |
1220 // server and the server returns 0. Lets us detect the | |
1221 // end of the initial sync. | |
1222 "initial_sync_ended BOOLEAN default 0, " | |
1223 "transaction_version BIGINT default 0)"); | |
1224 } | |
1225 | |
1191 bool DirectoryBackingStore::CreateModelsTable() { | 1226 bool DirectoryBackingStore::CreateModelsTable() { |
1192 // This is the current schema for the Models table, from version 81 | 1227 // This is the current schema for the Models table, from version 81 |
1193 // onward. If you change the schema, you'll probably want to double-check | 1228 // onward. If you change the schema, you'll probably want to double-check |
1194 // the use of this function in the v74-v75 migration. | 1229 // the use of this function in the v83-v84 migration. |
1195 return db_->Execute( | 1230 return db_->Execute( |
1196 "CREATE TABLE models (" | 1231 "CREATE TABLE models (" |
1197 "model_id BLOB primary key, " | 1232 "model_id BLOB primary key, " |
1198 "progress_marker BLOB, " | 1233 "progress_marker BLOB, " |
1199 // Gets set if the syncer ever gets updates from the | 1234 // Gets set if the syncer ever gets updates from the |
1200 // server and the server returns 0. Lets us detect the | 1235 // server and the server returns 0. Lets us detect the |
1201 // end of the initial sync. | 1236 // end of the initial sync. |
1202 "initial_sync_ended BOOLEAN default 0, " | |
1203 "transaction_version BIGINT default 0)"); | 1237 "transaction_version BIGINT default 0)"); |
1204 } | 1238 } |
1205 | 1239 |
1206 bool DirectoryBackingStore::CreateShareInfoTable(bool is_temporary) { | 1240 bool DirectoryBackingStore::CreateShareInfoTable(bool is_temporary) { |
1207 const char* name = is_temporary ? "temp_share_info" : "share_info"; | 1241 const char* name = is_temporary ? "temp_share_info" : "share_info"; |
1208 string query = "CREATE TABLE "; | 1242 string query = "CREATE TABLE "; |
1209 query.append(name); | 1243 query.append(name); |
1210 // This is the current schema for the ShareInfo table, from version 76 | 1244 // This is the current schema for the ShareInfo table, from version 76 |
1211 // onward. | 1245 // onward. |
1212 query.append(" (" | 1246 query.append(" (" |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1266 bool prev_exists = (ids_set.find(entry->ref(PREV_ID).value()) != end); | 1300 bool prev_exists = (ids_set.find(entry->ref(PREV_ID).value()) != end); |
1267 bool parent_exists = (ids_set.find(entry->ref(PARENT_ID).value()) != end); | 1301 bool parent_exists = (ids_set.find(entry->ref(PARENT_ID).value()) != end); |
1268 bool next_exists = (ids_set.find(entry->ref(NEXT_ID).value()) != end); | 1302 bool next_exists = (ids_set.find(entry->ref(NEXT_ID).value()) != end); |
1269 is_ok = is_ok && prev_exists && parent_exists && next_exists; | 1303 is_ok = is_ok && prev_exists && parent_exists && next_exists; |
1270 } | 1304 } |
1271 return is_ok; | 1305 return is_ok; |
1272 } | 1306 } |
1273 | 1307 |
1274 } // namespace syncable | 1308 } // namespace syncable |
1275 } // namespace syncer | 1309 } // namespace syncer |
OLD | NEW |