| 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 21 matching lines...) Expand all Loading... |
| 32 | 32 |
| 33 namespace syncer { | 33 namespace syncer { |
| 34 namespace syncable { | 34 namespace syncable { |
| 35 | 35 |
| 36 // This just has to be big enough to hold an UPDATE or INSERT statement that | 36 // This just has to be big enough to hold an UPDATE or INSERT statement that |
| 37 // modifies all the columns in the entry table. | 37 // modifies all the columns in the entry table. |
| 38 static const string::size_type kUpdateStatementBufferSize = 2048; | 38 static const string::size_type kUpdateStatementBufferSize = 2048; |
| 39 | 39 |
| 40 // Increment this version whenever updating DB tables. | 40 // Increment this version whenever updating DB tables. |
| 41 extern const int32 kCurrentDBVersion; // Global visibility for our unittest. | 41 extern const int32 kCurrentDBVersion; // Global visibility for our unittest. |
| 42 const int32 kCurrentDBVersion = 79; | 42 const int32 kCurrentDBVersion = 80; |
| 43 | 43 |
| 44 // Iterate over the fields of |entry| and bind each to |statement| for | 44 // Iterate over the fields of |entry| and bind each to |statement| for |
| 45 // updating. Returns the number of args bound. | 45 // updating. Returns the number of args bound. |
| 46 void BindFields(const EntryKernel& entry, | 46 void BindFields(const EntryKernel& entry, |
| 47 sql::Statement* statement) { | 47 sql::Statement* statement) { |
| 48 int index = 0; | 48 int index = 0; |
| 49 int i = 0; | 49 int i = 0; |
| 50 for (i = BEGIN_FIELDS; i < INT64_FIELDS_END; ++i) { | 50 for (i = BEGIN_FIELDS; i < INT64_FIELDS_END; ++i) { |
| 51 statement->BindInt64(index++, entry.ref(static_cast<Int64Field>(i))); | 51 statement->BindInt64(index++, entry.ref(static_cast<Int64Field>(i))); |
| 52 } | 52 } |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 if (!DeleteEntries(snapshot.metahandles_to_purge)) | 194 if (!DeleteEntries(snapshot.metahandles_to_purge)) |
| 195 return false; | 195 return false; |
| 196 | 196 |
| 197 if (save_info) { | 197 if (save_info) { |
| 198 const Directory::PersistedKernelInfo& info = snapshot.kernel_info; | 198 const Directory::PersistedKernelInfo& info = snapshot.kernel_info; |
| 199 sql::Statement s1(db_->GetCachedStatement( | 199 sql::Statement s1(db_->GetCachedStatement( |
| 200 SQL_FROM_HERE, | 200 SQL_FROM_HERE, |
| 201 "UPDATE share_info " | 201 "UPDATE share_info " |
| 202 "SET store_birthday = ?, " | 202 "SET store_birthday = ?, " |
| 203 "next_id = ?, " | 203 "next_id = ?, " |
| 204 "notification_state = ?")); | 204 "notification_state = ?, " |
| 205 "bag_of_chips = ?")); |
| 205 s1.BindString(0, info.store_birthday); | 206 s1.BindString(0, info.store_birthday); |
| 206 s1.BindInt64(1, info.next_id); | 207 s1.BindInt64(1, info.next_id); |
| 207 s1.BindBlob(2, info.notification_state.data(), | 208 s1.BindBlob(2, info.notification_state.data(), |
| 208 info.notification_state.size()); | 209 info.notification_state.size()); |
| 210 s1.BindBlob(3, info.bag_of_chips.data(), info.bag_of_chips.size()); |
| 209 | 211 |
| 210 if (!s1.Run()) | 212 if (!s1.Run()) |
| 211 return false; | 213 return false; |
| 212 DCHECK_EQ(db_->GetLastChangeCount(), 1); | 214 DCHECK_EQ(db_->GetLastChangeCount(), 1); |
| 213 | 215 |
| 214 sql::Statement s2(db_->GetCachedStatement( | 216 sql::Statement s2(db_->GetCachedStatement( |
| 215 SQL_FROM_HERE, | 217 SQL_FROM_HERE, |
| 216 "INSERT OR REPLACE " | 218 "INSERT OR REPLACE " |
| 217 "INTO models (model_id, progress_marker, initial_sync_ended) " | 219 "INTO models (model_id, progress_marker, initial_sync_ended) " |
| 218 "VALUES (?, ?, ?)")); | 220 "VALUES (?, ?, ?)")); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 308 if (MigrateVersion77To78()) | 310 if (MigrateVersion77To78()) |
| 309 version_on_disk = 78; | 311 version_on_disk = 78; |
| 310 } | 312 } |
| 311 | 313 |
| 312 // Version 79 migration is a one-time fix for some users in a bad state. | 314 // Version 79 migration is a one-time fix for some users in a bad state. |
| 313 if (version_on_disk == 78) { | 315 if (version_on_disk == 78) { |
| 314 if (MigrateVersion78To79()) | 316 if (MigrateVersion78To79()) |
| 315 version_on_disk = 79; | 317 version_on_disk = 79; |
| 316 } | 318 } |
| 317 | 319 |
| 320 // Version 80 migration is adding the bag_of_chips column. |
| 321 if (version_on_disk == 79) { |
| 322 if (MigrateVersion79To80()) |
| 323 version_on_disk = 80; |
| 324 } |
| 325 |
| 318 // If one of the migrations requested it, drop columns that aren't current. | 326 // If one of the migrations requested it, drop columns that aren't current. |
| 319 // It's only safe to do this after migrating all the way to the current | 327 // It's only safe to do this after migrating all the way to the current |
| 320 // version. | 328 // version. |
| 321 if (version_on_disk == kCurrentDBVersion && needs_column_refresh_) { | 329 if (version_on_disk == kCurrentDBVersion && needs_column_refresh_) { |
| 322 if (!RefreshColumns()) | 330 if (!RefreshColumns()) |
| 323 version_on_disk = 0; | 331 version_on_disk = 0; |
| 324 } | 332 } |
| 325 | 333 |
| 326 // A final, alternative catch-all migration to simply re-sync everything. | 334 // A final, alternative catch-all migration to simply re-sync everything. |
| 327 // | 335 // |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 return false; | 396 return false; |
| 389 | 397 |
| 390 // Repeat the process for share_info. | 398 // Repeat the process for share_info. |
| 391 SafeDropTable("temp_share_info"); | 399 SafeDropTable("temp_share_info"); |
| 392 if (!CreateShareInfoTable(true)) | 400 if (!CreateShareInfoTable(true)) |
| 393 return false; | 401 return false; |
| 394 | 402 |
| 395 if (!db_->Execute( | 403 if (!db_->Execute( |
| 396 "INSERT INTO temp_share_info (id, name, store_birthday, " | 404 "INSERT INTO temp_share_info (id, name, store_birthday, " |
| 397 "db_create_version, db_create_time, next_id, cache_guid," | 405 "db_create_version, db_create_time, next_id, cache_guid," |
| 398 "notification_state) " | 406 "notification_state, bag_of_chips) " |
| 399 "SELECT id, name, store_birthday, db_create_version, " | 407 "SELECT id, name, store_birthday, db_create_version, " |
| 400 "db_create_time, next_id, cache_guid, notification_state " | 408 "db_create_time, next_id, cache_guid, notification_state, " |
| 409 "bag_of_chips " |
| 401 "FROM share_info")) | 410 "FROM share_info")) |
| 402 return false; | 411 return false; |
| 403 | 412 |
| 404 SafeDropTable("share_info"); | 413 SafeDropTable("share_info"); |
| 405 if (!db_->Execute("ALTER TABLE temp_share_info RENAME TO share_info")) | 414 if (!db_->Execute("ALTER TABLE temp_share_info RENAME TO share_info")) |
| 406 return false; | 415 return false; |
| 407 | 416 |
| 408 needs_column_refresh_ = false; | 417 needs_column_refresh_ = false; |
| 409 return true; | 418 return true; |
| 410 } | 419 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 422 EntryKernel *kernel = UnpackEntry(&s); | 431 EntryKernel *kernel = UnpackEntry(&s); |
| 423 entry_bucket->insert(kernel); | 432 entry_bucket->insert(kernel); |
| 424 } | 433 } |
| 425 return s.Succeeded(); | 434 return s.Succeeded(); |
| 426 } | 435 } |
| 427 | 436 |
| 428 bool DirectoryBackingStore::LoadInfo(Directory::KernelLoadInfo* info) { | 437 bool DirectoryBackingStore::LoadInfo(Directory::KernelLoadInfo* info) { |
| 429 { | 438 { |
| 430 sql::Statement s( | 439 sql::Statement s( |
| 431 db_->GetUniqueStatement( | 440 db_->GetUniqueStatement( |
| 432 "SELECT store_birthday, next_id, cache_guid, notification_state " | 441 "SELECT store_birthday, next_id, cache_guid, notification_state, " |
| 442 "bag_of_chips " |
| 433 "FROM share_info")); | 443 "FROM share_info")); |
| 434 if (!s.Step()) | 444 if (!s.Step()) |
| 435 return false; | 445 return false; |
| 436 | 446 |
| 437 info->kernel_info.store_birthday = s.ColumnString(0); | 447 info->kernel_info.store_birthday = s.ColumnString(0); |
| 438 info->kernel_info.next_id = s.ColumnInt64(1); | 448 info->kernel_info.next_id = s.ColumnInt64(1); |
| 439 info->cache_guid = s.ColumnString(2); | 449 info->cache_guid = s.ColumnString(2); |
| 440 s.ColumnBlobAsString(3, &(info->kernel_info.notification_state)); | 450 s.ColumnBlobAsString(3, &(info->kernel_info.notification_state)); |
| 451 s.ColumnBlobAsString(4, &(info->kernel_info.bag_of_chips)); |
| 441 | 452 |
| 442 // Verify there was only one row returned. | 453 // Verify there was only one row returned. |
| 443 DCHECK(!s.Step()); | 454 DCHECK(!s.Step()); |
| 444 DCHECK(s.Succeeded()); | 455 DCHECK(s.Succeeded()); |
| 445 } | 456 } |
| 446 | 457 |
| 447 { | 458 { |
| 448 sql::Statement s( | 459 sql::Statement s( |
| 449 db_->GetUniqueStatement( | 460 db_->GetUniqueStatement( |
| 450 "SELECT model_id, progress_marker, initial_sync_ended " | 461 "SELECT model_id, progress_marker, initial_sync_ended " |
| (...skipping 499 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 950 // Some users are stuck with a DB that causes them to reuse existing IDs. We | 961 // Some users are stuck with a DB that causes them to reuse existing IDs. We |
| 951 // perform this one-time fixup on all users to help the few that are stuck. | 962 // perform this one-time fixup on all users to help the few that are stuck. |
| 952 // See crbug.com/142987 for details. | 963 // See crbug.com/142987 for details. |
| 953 if (!db_->Execute( | 964 if (!db_->Execute( |
| 954 "UPDATE share_info SET next_id = next_id - 65536")) { | 965 "UPDATE share_info SET next_id = next_id - 65536")) { |
| 955 return false; | 966 return false; |
| 956 } | 967 } |
| 957 SetVersion(79); | 968 SetVersion(79); |
| 958 return true; | 969 return true; |
| 959 } | 970 } |
| 971 bool DirectoryBackingStore::MigrateVersion79To80() { |
| 972 if (!db_->Execute( |
| 973 "ALTER TABLE share_info ADD COLUMN bag_of_chips BLOB")) |
| 974 return false; |
| 975 sql::Statement update(db_->GetUniqueStatement( |
| 976 "UPDATE share_info SET bag_of_chips = ?")); |
| 977 // An empty message is serialized to an empty string. |
| 978 update.BindBlob(0, NULL, 0); |
| 979 if (!update.Run()) |
| 980 return false; |
| 981 SetVersion(80); |
| 982 return true; |
| 983 } |
| 960 | 984 |
| 961 bool DirectoryBackingStore::CreateTables() { | 985 bool DirectoryBackingStore::CreateTables() { |
| 962 DVLOG(1) << "First run, creating tables"; | 986 DVLOG(1) << "First run, creating tables"; |
| 963 // Create two little tables share_version and share_info | 987 // Create two little tables share_version and share_info |
| 964 if (!db_->Execute( | 988 if (!db_->Execute( |
| 965 "CREATE TABLE share_version (" | 989 "CREATE TABLE share_version (" |
| 966 "id VARCHAR(128) primary key, data INT)")) { | 990 "id VARCHAR(128) primary key, data INT)")) { |
| 967 return false; | 991 return false; |
| 968 } | 992 } |
| 969 | 993 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 985 { | 1009 { |
| 986 sql::Statement s(db_->GetUniqueStatement( | 1010 sql::Statement s(db_->GetUniqueStatement( |
| 987 "INSERT INTO share_info VALUES" | 1011 "INSERT INTO share_info VALUES" |
| 988 "(?, " // id | 1012 "(?, " // id |
| 989 "?, " // name | 1013 "?, " // name |
| 990 "?, " // store_birthday | 1014 "?, " // store_birthday |
| 991 "?, " // db_create_version | 1015 "?, " // db_create_version |
| 992 "?, " // db_create_time | 1016 "?, " // db_create_time |
| 993 "-2, " // next_id | 1017 "-2, " // next_id |
| 994 "?, " // cache_guid | 1018 "?, " // cache_guid |
| 995 "?);")); // notification_state | 1019 "?, " // notification_state |
| 1020 "?);")); // bag_of_chips |
| 996 s.BindString(0, dir_name_); // id | 1021 s.BindString(0, dir_name_); // id |
| 997 s.BindString(1, dir_name_); // name | 1022 s.BindString(1, dir_name_); // name |
| 998 s.BindString(2, ""); // store_birthday | 1023 s.BindString(2, ""); // store_birthday |
| 999 // TODO(akalin): Remove this unused db_create_version field. (Or | 1024 // TODO(akalin): Remove this unused db_create_version field. (Or |
| 1000 // actually use it for something.) http://crbug.com/118356 | 1025 // actually use it for something.) http://crbug.com/118356 |
| 1001 s.BindString(3, "Unknown"); // db_create_version | 1026 s.BindString(3, "Unknown"); // db_create_version |
| 1002 s.BindInt(4, static_cast<int32>(time(0))); // db_create_time | 1027 s.BindInt(4, static_cast<int32>(time(0))); // db_create_time |
| 1003 s.BindString(5, GenerateCacheGUID()); // cache_guid | 1028 s.BindString(5, GenerateCacheGUID()); // cache_guid |
| 1004 s.BindBlob(6, NULL, 0); // notification_state | 1029 s.BindBlob(6, NULL, 0); // notification_state |
| 1005 | 1030 s.BindBlob(7, NULL, 0); // bag_of_chips |
| 1006 if (!s.Run()) | 1031 if (!s.Run()) |
| 1007 return false; | 1032 return false; |
| 1008 } | 1033 } |
| 1009 | 1034 |
| 1010 if (!CreateModelsTable()) | 1035 if (!CreateModelsTable()) |
| 1011 return false; | 1036 return false; |
| 1012 | 1037 |
| 1013 // Create the big metas table. | 1038 // Create the big metas table. |
| 1014 if (!CreateMetasTable(false)) | 1039 if (!CreateMetasTable(false)) |
| 1015 return false; | 1040 return false; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1071 query.append(name); | 1096 query.append(name); |
| 1072 // This is the current schema for the ShareInfo table, from version 76 | 1097 // This is the current schema for the ShareInfo table, from version 76 |
| 1073 // onward. | 1098 // onward. |
| 1074 query.append(" (" | 1099 query.append(" (" |
| 1075 "id TEXT primary key, " | 1100 "id TEXT primary key, " |
| 1076 "name TEXT, " | 1101 "name TEXT, " |
| 1077 "store_birthday TEXT, " | 1102 "store_birthday TEXT, " |
| 1078 "db_create_version TEXT, " | 1103 "db_create_version TEXT, " |
| 1079 "db_create_time INT, " | 1104 "db_create_time INT, " |
| 1080 "next_id INT default -2, " | 1105 "next_id INT default -2, " |
| 1081 "cache_guid TEXT "); | 1106 "cache_guid TEXT, " |
| 1082 | 1107 "notification_state BLOB, " |
| 1083 query.append(", notification_state BLOB"); | 1108 "bag_of_chips BLOB" |
| 1084 query.append(")"); | 1109 ")"); |
| 1085 return db_->Execute(query.c_str()); | 1110 return db_->Execute(query.c_str()); |
| 1086 } | 1111 } |
| 1087 | 1112 |
| 1088 bool DirectoryBackingStore::CreateShareInfoTableVersion71( | 1113 bool DirectoryBackingStore::CreateShareInfoTableVersion71( |
| 1089 bool is_temporary) { | 1114 bool is_temporary) { |
| 1090 const char* name = is_temporary ? "temp_share_info" : "share_info"; | 1115 const char* name = is_temporary ? "temp_share_info" : "share_info"; |
| 1091 string query = "CREATE TABLE "; | 1116 string query = "CREATE TABLE "; |
| 1092 query.append(name); | 1117 query.append(name); |
| 1093 // This is the schema for the ShareInfo table used from versions 71 to 72. | 1118 // This is the schema for the ShareInfo table used from versions 71 to 72. |
| 1094 query.append(" (" | 1119 query.append(" (" |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1128 bool prev_exists = (ids_set.find(entry->ref(PREV_ID).value()) != end); | 1153 bool prev_exists = (ids_set.find(entry->ref(PREV_ID).value()) != end); |
| 1129 bool parent_exists = (ids_set.find(entry->ref(PARENT_ID).value()) != end); | 1154 bool parent_exists = (ids_set.find(entry->ref(PARENT_ID).value()) != end); |
| 1130 bool next_exists = (ids_set.find(entry->ref(NEXT_ID).value()) != end); | 1155 bool next_exists = (ids_set.find(entry->ref(NEXT_ID).value()) != end); |
| 1131 is_ok = is_ok && prev_exists && parent_exists && next_exists; | 1156 is_ok = is_ok && prev_exists && parent_exists && next_exists; |
| 1132 } | 1157 } |
| 1133 return is_ok; | 1158 return is_ok; |
| 1134 } | 1159 } |
| 1135 | 1160 |
| 1136 } // namespace syncable | 1161 } // namespace syncable |
| 1137 } // namespace syncer | 1162 } // namespace syncer |
| OLD | NEW |