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