| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/syncable/directory_backing_store.h" | 5 #include "chrome/browser/sync/syncable/directory_backing_store.h" |
| 6 | 6 |
| 7 #include "build/build_config.h" | 7 #include "build/build_config.h" |
| 8 | 8 |
| 9 #if defined(OS_MACOSX) |
| 10 #include <CoreFoundation/CoreFoundation.h> |
| 11 #endif |
| 12 |
| 9 #include <limits> | 13 #include <limits> |
| 10 | 14 |
| 11 #include "base/file_util.h" | 15 #include "base/file_util.h" |
| 12 #include "base/hash_tables.h" | 16 #include "base/hash_tables.h" |
| 13 #include "base/logging.h" | 17 #include "base/logging.h" |
| 14 #include "base/metrics/histogram.h" | 18 #include "base/metrics/histogram.h" |
| 15 #include "base/stl_util.h" | 19 #include "base/stl_util.h" |
| 16 #include "base/string_number_conversions.h" | 20 #include "base/string_number_conversions.h" |
| 17 #include "base/stringprintf.h" | 21 #include "base/stringprintf.h" |
| 18 #include "base/time.h" | |
| 19 #include "chrome/browser/sync/protocol/bookmark_specifics.pb.h" | 22 #include "chrome/browser/sync/protocol/bookmark_specifics.pb.h" |
| 20 #include "chrome/browser/sync/protocol/service_constants.h" | 23 #include "chrome/browser/sync/protocol/service_constants.h" |
| 21 #include "chrome/browser/sync/protocol/sync.pb.h" | 24 #include "chrome/browser/sync/protocol/sync.pb.h" |
| 22 #include "chrome/browser/sync/syncable/syncable-inl.h" | 25 #include "chrome/browser/sync/syncable/syncable-inl.h" |
| 23 #include "chrome/browser/sync/syncable/syncable_columns.h" | 26 #include "chrome/browser/sync/syncable/syncable_columns.h" |
| 24 #include "chrome/browser/sync/util/sqlite_utils.h" | 27 #include "chrome/browser/sync/util/sqlite_utils.h" |
| 25 #include "chrome/browser/sync/util/time.h" | |
| 26 #include "chrome/common/random.h" | 28 #include "chrome/common/random.h" |
| 27 #include "third_party/sqlite/sqlite3.h" | 29 #include "third_party/sqlite/sqlite3.h" |
| 28 | 30 |
| 29 // Sometimes threads contend on the DB lock itself, especially when one thread | 31 // Sometimes threads contend on the DB lock itself, especially when one thread |
| 30 // is calling SaveChanges. In the worst case scenario, the user can put his | 32 // is calling SaveChanges. In the worst case scenario, the user can put his |
| 31 // laptop to sleep during db contention, and wake up the laptop days later, so | 33 // laptop to sleep during db contention, and wake up the laptop days later, so |
| 32 // infinity seems like the best choice here. | 34 // infinity seems like the best choice here. |
| 33 const int kDirectoryBackingStoreBusyTimeoutMs = std::numeric_limits<int>::max(); | 35 const int kDirectoryBackingStoreBusyTimeoutMs = std::numeric_limits<int>::max(); |
| 34 | 36 |
| 35 using std::string; | 37 using std::string; |
| 36 | 38 |
| 37 namespace syncable { | 39 namespace syncable { |
| 38 | 40 |
| 39 // This just has to be big enough to hold an UPDATE or INSERT statement that | 41 // This just has to be big enough to hold an UPDATE or INSERT statement that |
| 40 // modifies all the columns in the entry table. | 42 // modifies all the columns in the entry table. |
| 41 static const string::size_type kUpdateStatementBufferSize = 2048; | 43 static const string::size_type kUpdateStatementBufferSize = 2048; |
| 42 | 44 |
| 43 // Increment this version whenever updating DB tables. | 45 // Increment this version whenever updating DB tables. |
| 44 extern const int32 kCurrentDBVersion; // Global visibility for our unittest. | 46 extern const int32 kCurrentDBVersion; // Global visibility for our unittest. |
| 45 const int32 kCurrentDBVersion = 77; | 47 const int32 kCurrentDBVersion = 76; |
| 46 | 48 |
| 47 namespace { | 49 namespace { |
| 48 | 50 |
| 49 int ExecQuery(sqlite3* dbhandle, const char* query) { | 51 int ExecQuery(sqlite3* dbhandle, const char* query) { |
| 50 sqlite_utils::SQLStatement statement; | 52 sqlite_utils::SQLStatement statement; |
| 51 int result = statement.prepare(dbhandle, query); | 53 int result = statement.prepare(dbhandle, query); |
| 52 if (SQLITE_OK != result) | 54 if (SQLITE_OK != result) |
| 53 return result; | 55 return result; |
| 54 do { | 56 do { |
| 55 result = statement.step(); | 57 result = statement.step(); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 67 | 69 |
| 68 // Iterate over the fields of |entry| and bind each to |statement| for | 70 // Iterate over the fields of |entry| and bind each to |statement| for |
| 69 // updating. Returns the number of args bound. | 71 // updating. Returns the number of args bound. |
| 70 int BindFields(const EntryKernel& entry, | 72 int BindFields(const EntryKernel& entry, |
| 71 sqlite_utils::SQLStatement* statement) { | 73 sqlite_utils::SQLStatement* statement) { |
| 72 int index = 0; | 74 int index = 0; |
| 73 int i = 0; | 75 int i = 0; |
| 74 for (i = BEGIN_FIELDS; i < INT64_FIELDS_END; ++i) { | 76 for (i = BEGIN_FIELDS; i < INT64_FIELDS_END; ++i) { |
| 75 statement->bind_int64(index++, entry.ref(static_cast<Int64Field>(i))); | 77 statement->bind_int64(index++, entry.ref(static_cast<Int64Field>(i))); |
| 76 } | 78 } |
| 77 for ( ; i < TIME_FIELDS_END; ++i) { | |
| 78 statement->bind_int64(index++, | |
| 79 browser_sync::TimeToProtoTime( | |
| 80 entry.ref(static_cast<TimeField>(i)))); | |
| 81 } | |
| 82 for ( ; i < ID_FIELDS_END; ++i) { | 79 for ( ; i < ID_FIELDS_END; ++i) { |
| 83 statement->bind_string(index++, entry.ref(static_cast<IdField>(i)).s_); | 80 statement->bind_string(index++, entry.ref(static_cast<IdField>(i)).s_); |
| 84 } | 81 } |
| 85 for ( ; i < BIT_FIELDS_END; ++i) { | 82 for ( ; i < BIT_FIELDS_END; ++i) { |
| 86 statement->bind_int(index++, entry.ref(static_cast<BitField>(i))); | 83 statement->bind_int(index++, entry.ref(static_cast<BitField>(i))); |
| 87 } | 84 } |
| 88 for ( ; i < STRING_FIELDS_END; ++i) { | 85 for ( ; i < STRING_FIELDS_END; ++i) { |
| 89 statement->bind_string(index++, entry.ref(static_cast<StringField>(i))); | 86 statement->bind_string(index++, entry.ref(static_cast<StringField>(i))); |
| 90 } | 87 } |
| 91 std::string temp; | 88 std::string temp; |
| 92 for ( ; i < PROTO_FIELDS_END; ++i) { | 89 for ( ; i < PROTO_FIELDS_END; ++i) { |
| 93 entry.ref(static_cast<ProtoField>(i)).SerializeToString(&temp); | 90 entry.ref(static_cast<ProtoField>(i)).SerializeToString(&temp); |
| 94 statement->bind_blob(index++, temp.data(), temp.length()); | 91 statement->bind_blob(index++, temp.data(), temp.length()); |
| 95 } | 92 } |
| 96 return index; | 93 return index; |
| 97 } | 94 } |
| 98 | 95 |
| 99 // The caller owns the returned EntryKernel*. | 96 // The caller owns the returned EntryKernel*. |
| 100 int UnpackEntry(sqlite_utils::SQLStatement* statement, EntryKernel** kernel) { | 97 int UnpackEntry(sqlite_utils::SQLStatement* statement, EntryKernel** kernel) { |
| 101 *kernel = NULL; | 98 *kernel = NULL; |
| 102 int query_result = statement->step(); | 99 int query_result = statement->step(); |
| 103 if (query_result == SQLITE_ROW) { | 100 if (SQLITE_ROW == query_result) { |
| 104 *kernel = new EntryKernel(); | 101 *kernel = new EntryKernel; |
| 105 DCHECK_EQ(statement->column_count(), static_cast<int>(FIELD_COUNT)); | 102 (*kernel)->clear_dirty(NULL); |
| 103 DCHECK(statement->column_count() == static_cast<int>(FIELD_COUNT)); |
| 106 int i = 0; | 104 int i = 0; |
| 107 for (i = BEGIN_FIELDS; i < INT64_FIELDS_END; ++i) { | 105 for (i = BEGIN_FIELDS; i < INT64_FIELDS_END; ++i) { |
| 108 (*kernel)->put(static_cast<Int64Field>(i), statement->column_int64(i)); | 106 (*kernel)->put(static_cast<Int64Field>(i), statement->column_int64(i)); |
| 109 } | 107 } |
| 110 for ( ; i < TIME_FIELDS_END; ++i) { | |
| 111 (*kernel)->put(static_cast<TimeField>(i), | |
| 112 browser_sync::ProtoTimeToTime( | |
| 113 statement->column_int64(i))); | |
| 114 } | |
| 115 for ( ; i < ID_FIELDS_END; ++i) { | 108 for ( ; i < ID_FIELDS_END; ++i) { |
| 116 (*kernel)->mutable_ref(static_cast<IdField>(i)).s_ = | 109 (*kernel)->mutable_ref(static_cast<IdField>(i)).s_ = |
| 117 statement->column_string(i); | 110 statement->column_string(i); |
| 118 } | 111 } |
| 119 for ( ; i < BIT_FIELDS_END; ++i) { | 112 for ( ; i < BIT_FIELDS_END; ++i) { |
| 120 (*kernel)->put(static_cast<BitField>(i), (0 != statement->column_int(i))); | 113 (*kernel)->put(static_cast<BitField>(i), (0 != statement->column_int(i))); |
| 121 } | 114 } |
| 122 for ( ; i < STRING_FIELDS_END; ++i) { | 115 for ( ; i < STRING_FIELDS_END; ++i) { |
| 123 (*kernel)->put(static_cast<StringField>(i), | 116 (*kernel)->put(static_cast<StringField>(i), |
| 124 statement->column_string(i)); | 117 statement->column_string(i)); |
| 125 } | 118 } |
| 126 for ( ; i < PROTO_FIELDS_END; ++i) { | 119 for ( ; i < PROTO_FIELDS_END; ++i) { |
| 127 (*kernel)->mutable_ref(static_cast<ProtoField>(i)).ParseFromArray( | 120 (*kernel)->mutable_ref(static_cast<ProtoField>(i)).ParseFromArray( |
| 128 statement->column_blob(i), statement->column_bytes(i)); | 121 statement->column_blob(i), statement->column_bytes(i)); |
| 129 } | 122 } |
| 123 ZeroFields((*kernel), i); |
| 130 } else { | 124 } else { |
| 131 DCHECK_EQ(query_result, SQLITE_DONE); | 125 DCHECK(SQLITE_DONE == query_result); |
| 132 (*kernel) = NULL; | 126 (*kernel) = NULL; |
| 133 } | 127 } |
| 134 return query_result; | 128 return query_result; |
| 135 } | 129 } |
| 136 | 130 |
| 137 namespace { | 131 namespace { |
| 138 | 132 |
| 139 string ComposeCreateTableColumnSpecs() { | 133 string ComposeCreateTableColumnSpecs() { |
| 140 const ColumnSpec* begin = g_metas_columns; | 134 const ColumnSpec* begin = g_metas_columns; |
| 141 const ColumnSpec* end = g_metas_columns + arraysize(g_metas_columns); | 135 const ColumnSpec* end = g_metas_columns + arraysize(g_metas_columns); |
| (...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 477 if (MigrateVersion74To75()) | 471 if (MigrateVersion74To75()) |
| 478 version_on_disk = 75; | 472 version_on_disk = 75; |
| 479 } | 473 } |
| 480 | 474 |
| 481 // Version 76 removed all (5) autofill migration related columns. | 475 // Version 76 removed all (5) autofill migration related columns. |
| 482 if (version_on_disk == 75) { | 476 if (version_on_disk == 75) { |
| 483 if (MigrateVersion75To76()) | 477 if (MigrateVersion75To76()) |
| 484 version_on_disk = 76; | 478 version_on_disk = 76; |
| 485 } | 479 } |
| 486 | 480 |
| 487 // Version 77 standardized all time fields to ms since the Unix | |
| 488 // epoch. | |
| 489 if (version_on_disk == 76) { | |
| 490 if (MigrateVersion76To77()) | |
| 491 version_on_disk = 77; | |
| 492 } | |
| 493 | |
| 494 // If one of the migrations requested it, drop columns that aren't current. | 481 // If one of the migrations requested it, drop columns that aren't current. |
| 495 // It's only safe to do this after migrating all the way to the current | 482 // It's only safe to do this after migrating all the way to the current |
| 496 // version. | 483 // version. |
| 497 if (version_on_disk == kCurrentDBVersion && needs_column_refresh_) { | 484 if (version_on_disk == kCurrentDBVersion && needs_column_refresh_) { |
| 498 if (!RefreshColumns()) | 485 if (!RefreshColumns()) |
| 499 version_on_disk = 0; | 486 version_on_disk = 0; |
| 500 } | 487 } |
| 501 | 488 |
| 502 // A final, alternative catch-all migration to simply re-sync everything. | 489 // A final, alternative catch-all migration to simply re-sync everything. |
| 503 if (version_on_disk != kCurrentDBVersion) { | 490 if (version_on_disk != kCurrentDBVersion) { |
| (...skipping 591 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1095 // bookmarks_added_during_autofill_migration | 1082 // bookmarks_added_during_autofill_migration |
| 1096 // autofill_migration_time | 1083 // autofill_migration_time |
| 1097 // autofill_entries_added_during_migration | 1084 // autofill_entries_added_during_migration |
| 1098 // autofill_profiles_added_during_migration | 1085 // autofill_profiles_added_during_migration |
| 1099 // No data migration is necessary, but we should do a column refresh. | 1086 // No data migration is necessary, but we should do a column refresh. |
| 1100 SetVersion(76); | 1087 SetVersion(76); |
| 1101 needs_column_refresh_ = true; | 1088 needs_column_refresh_ = true; |
| 1102 return true; | 1089 return true; |
| 1103 } | 1090 } |
| 1104 | 1091 |
| 1105 bool DirectoryBackingStore::MigrateVersion76To77() { | |
| 1106 sqlite_utils::SQLStatement update_timestamps; | |
| 1107 // This change changes the format of stored timestamps to ms since | |
| 1108 // the Unix epoch. | |
| 1109 #if defined(OS_WIN) | |
| 1110 // On Windows, we used to store timestamps in FILETIME format (100s of | |
| 1111 // ns since Jan 1, 1601). Magic numbers taken from | |
| 1112 // http://stackoverflow.com/questions/5398557/java-library-for-dealing-with-win3
2-filetime | |
| 1113 // . | |
| 1114 #define TO_UNIX_TIME_MS(x) #x " = " #x " / 10000 - 11644473600000" | |
| 1115 #else | |
| 1116 // On other platforms, we used to store timestamps in time_t format (s | |
| 1117 // since the Unix epoch). | |
| 1118 #define TO_UNIX_TIME_MS(x) #x " = " #x " * 1000" | |
| 1119 #endif | |
| 1120 update_timestamps.prepare( | |
| 1121 load_dbhandle_, | |
| 1122 "UPDATE metas SET " | |
| 1123 TO_UNIX_TIME_MS(mtime) ", " | |
| 1124 TO_UNIX_TIME_MS(server_mtime) ", " | |
| 1125 TO_UNIX_TIME_MS(ctime) ", " | |
| 1126 TO_UNIX_TIME_MS(server_ctime)); | |
| 1127 #undef TO_UNIX_TIME_MS | |
| 1128 if (update_timestamps.step() != SQLITE_DONE) | |
| 1129 return false; | |
| 1130 SetVersion(77); | |
| 1131 return true; | |
| 1132 } | |
| 1133 | |
| 1134 int DirectoryBackingStore::CreateTables() { | 1092 int DirectoryBackingStore::CreateTables() { |
| 1135 VLOG(1) << "First run, creating tables"; | 1093 VLOG(1) << "First run, creating tables"; |
| 1136 // Create two little tables share_version and share_info | 1094 // Create two little tables share_version and share_info |
| 1137 int result = ExecQuery(load_dbhandle_, | 1095 int result = ExecQuery(load_dbhandle_, |
| 1138 "CREATE TABLE share_version (" | 1096 "CREATE TABLE share_version (" |
| 1139 "id VARCHAR(128) primary key, data INT)"); | 1097 "id VARCHAR(128) primary key, data INT)"); |
| 1140 if (result != SQLITE_DONE) | 1098 if (result != SQLITE_DONE) |
| 1141 return result; | 1099 return result; |
| 1142 { | 1100 { |
| 1143 sqlite_utils::SQLStatement statement; | 1101 sqlite_utils::SQLStatement statement; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1178 | 1136 |
| 1179 result = CreateModelsTable(); | 1137 result = CreateModelsTable(); |
| 1180 if (result != SQLITE_DONE) | 1138 if (result != SQLITE_DONE) |
| 1181 return result; | 1139 return result; |
| 1182 // Create the big metas table. | 1140 // Create the big metas table. |
| 1183 result = CreateMetasTable(false); | 1141 result = CreateMetasTable(false); |
| 1184 if (result != SQLITE_DONE) | 1142 if (result != SQLITE_DONE) |
| 1185 return result; | 1143 return result; |
| 1186 { | 1144 { |
| 1187 // Insert the entry for the root into the metas table. | 1145 // Insert the entry for the root into the metas table. |
| 1188 const int64 now = browser_sync::TimeToProtoTime(base::Time::Now()); | 1146 const int64 now = Now(); |
| 1189 sqlite_utils::SQLStatement statement; | 1147 sqlite_utils::SQLStatement statement; |
| 1190 statement.prepare(load_dbhandle_, | 1148 statement.prepare(load_dbhandle_, |
| 1191 "INSERT INTO metas " | 1149 "INSERT INTO metas " |
| 1192 "( id, metahandle, is_dir, ctime, mtime) " | 1150 "( id, metahandle, is_dir, ctime, mtime) " |
| 1193 "VALUES ( \"r\", 1, 1, ?, ?)"); | 1151 "VALUES ( \"r\", 1, 1, ?, ?)"); |
| 1194 statement.bind_int64(0, now); | 1152 statement.bind_int64(0, now); |
| 1195 statement.bind_int64(1, now); | 1153 statement.bind_int64(1, now); |
| 1196 result = statement.step(); | 1154 result = statement.step(); |
| 1197 } | 1155 } |
| 1198 return result; | 1156 return result; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1270 "id TEXT primary key, " | 1228 "id TEXT primary key, " |
| 1271 "name TEXT, " | 1229 "name TEXT, " |
| 1272 "store_birthday TEXT, " | 1230 "store_birthday TEXT, " |
| 1273 "db_create_version TEXT, " | 1231 "db_create_version TEXT, " |
| 1274 "db_create_time INT, " | 1232 "db_create_time INT, " |
| 1275 "next_id INT default -2, " | 1233 "next_id INT default -2, " |
| 1276 "cache_guid TEXT )"); | 1234 "cache_guid TEXT )"); |
| 1277 return ExecQuery(load_dbhandle_, query.c_str()); | 1235 return ExecQuery(load_dbhandle_, query.c_str()); |
| 1278 } | 1236 } |
| 1279 } // namespace syncable | 1237 } // namespace syncable |
| OLD | NEW |