| 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 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 DirectoryBackingStore::DirectoryBackingStore(const string& dir_name, | 165 DirectoryBackingStore::DirectoryBackingStore(const string& dir_name, |
| 166 sql::Connection* db) | 166 sql::Connection* db) |
| 167 : db_(db), | 167 : db_(db), |
| 168 dir_name_(dir_name), | 168 dir_name_(dir_name), |
| 169 needs_column_refresh_(false) { | 169 needs_column_refresh_(false) { |
| 170 } | 170 } |
| 171 | 171 |
| 172 DirectoryBackingStore::~DirectoryBackingStore() { | 172 DirectoryBackingStore::~DirectoryBackingStore() { |
| 173 } | 173 } |
| 174 | 174 |
| 175 bool DirectoryBackingStore::DeleteEntries(const MetahandleSet& handles) { | 175 bool DirectoryBackingStore::DeleteEntries(EntryTable from, |
| 176 const MetahandleSet& handles) { |
| 176 if (handles.empty()) | 177 if (handles.empty()) |
| 177 return true; | 178 return true; |
| 178 | 179 |
| 179 sql::Statement statement(db_->GetCachedStatement( | 180 sql::Statement statement; |
| 181 // Call GetCachedStatement() separately to get different statements for |
| 182 // different tables. |
| 183 switch (from) { |
| 184 case METAS_TABLE: |
| 185 statement.Assign(db_->GetCachedStatement( |
| 180 SQL_FROM_HERE, "DELETE FROM metas WHERE metahandle = ?")); | 186 SQL_FROM_HERE, "DELETE FROM metas WHERE metahandle = ?")); |
| 187 break; |
| 188 case DELETE_JOURNAL_TABLE: |
| 189 statement.Assign(db_->GetCachedStatement( |
| 190 SQL_FROM_HERE, "DELETE FROM deleted_metas WHERE metahandle = ?")); |
| 191 break; |
| 192 } |
| 181 | 193 |
| 182 for (MetahandleSet::const_iterator i = handles.begin(); i != handles.end(); | 194 for (MetahandleSet::const_iterator i = handles.begin(); i != handles.end(); |
| 183 ++i) { | 195 ++i) { |
| 184 statement.BindInt64(0, *i); | 196 statement.BindInt64(0, *i); |
| 185 if (!statement.Run()) | 197 if (!statement.Run()) |
| 186 return false; | 198 return false; |
| 187 statement.Reset(true); | 199 statement.Reset(true); |
| 188 } | 200 } |
| 189 return true; | 201 return true; |
| 190 } | 202 } |
| 191 | 203 |
| 192 bool DirectoryBackingStore::SaveChanges( | 204 bool DirectoryBackingStore::SaveChanges( |
| 193 const Directory::SaveChangesSnapshot& snapshot) { | 205 const Directory::SaveChangesSnapshot& snapshot) { |
| 194 DCHECK(CalledOnValidThread()); | 206 DCHECK(CalledOnValidThread()); |
| 195 DCHECK(db_->is_open()); | 207 DCHECK(db_->is_open()); |
| 196 | 208 |
| 197 // Back out early if there is nothing to write. | 209 // Back out early if there is nothing to write. |
| 198 bool save_info = | 210 bool save_info = |
| 199 (Directory::KERNEL_SHARE_INFO_DIRTY == snapshot.kernel_info_status); | 211 (Directory::KERNEL_SHARE_INFO_DIRTY == snapshot.kernel_info_status); |
| 200 if (snapshot.dirty_metas.empty() | 212 if (snapshot.dirty_metas.empty() && snapshot.metahandles_to_purge.empty() && |
| 201 && snapshot.metahandles_to_purge.empty() | 213 snapshot.delete_journals.empty() && |
| 202 && !save_info) { | 214 snapshot.delete_journals_to_purge.empty() && !save_info) { |
| 203 return true; | 215 return true; |
| 204 } | 216 } |
| 205 | 217 |
| 206 sql::Transaction transaction(db_.get()); | 218 sql::Transaction transaction(db_.get()); |
| 207 if (!transaction.Begin()) | 219 if (!transaction.Begin()) |
| 208 return false; | 220 return false; |
| 209 | 221 |
| 222 PrepareSaveEntryStatement(METAS_TABLE, &save_meta_statment_); |
| 210 for (EntryKernelSet::const_iterator i = snapshot.dirty_metas.begin(); | 223 for (EntryKernelSet::const_iterator i = snapshot.dirty_metas.begin(); |
| 211 i != snapshot.dirty_metas.end(); ++i) { | 224 i != snapshot.dirty_metas.end(); ++i) { |
| 212 DCHECK(i->is_dirty()); | 225 DCHECK((*i)->is_dirty()); |
| 213 if (!SaveEntryToDB(*i)) | 226 if (!SaveEntryToDB(&save_meta_statment_, **i)) |
| 214 return false; | 227 return false; |
| 215 } | 228 } |
| 216 | 229 |
| 217 if (!DeleteEntries(snapshot.metahandles_to_purge)) | 230 if (!DeleteEntries(METAS_TABLE, snapshot.metahandles_to_purge)) |
| 231 return false; |
| 232 |
| 233 PrepareSaveEntryStatement(DELETE_JOURNAL_TABLE, |
| 234 &save_delete_journal_statment_); |
| 235 for (EntryKernelSet::const_iterator i = snapshot.delete_journals.begin(); |
| 236 i != snapshot.delete_journals.end(); ++i) { |
| 237 if (!SaveEntryToDB(&save_delete_journal_statment_, **i)) |
| 238 return false; |
| 239 } |
| 240 |
| 241 if (!DeleteEntries(DELETE_JOURNAL_TABLE, snapshot.delete_journals_to_purge)) |
| 218 return false; | 242 return false; |
| 219 | 243 |
| 220 if (save_info) { | 244 if (save_info) { |
| 221 const Directory::PersistedKernelInfo& info = snapshot.kernel_info; | 245 const Directory::PersistedKernelInfo& info = snapshot.kernel_info; |
| 222 sql::Statement s1(db_->GetCachedStatement( | 246 sql::Statement s1(db_->GetCachedStatement( |
| 223 SQL_FROM_HERE, | 247 SQL_FROM_HERE, |
| 224 "UPDATE share_info " | 248 "UPDATE share_info " |
| 225 "SET store_birthday = ?, " | 249 "SET store_birthday = ?, " |
| 226 "next_id = ?, " | 250 "next_id = ?, " |
| 227 "notification_state = ?, " | 251 "notification_state = ?, " |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 459 | 483 |
| 460 SafeDropTable("share_info"); | 484 SafeDropTable("share_info"); |
| 461 if (!db_->Execute("ALTER TABLE temp_share_info RENAME TO share_info")) | 485 if (!db_->Execute("ALTER TABLE temp_share_info RENAME TO share_info")) |
| 462 return false; | 486 return false; |
| 463 | 487 |
| 464 needs_column_refresh_ = false; | 488 needs_column_refresh_ = false; |
| 465 return true; | 489 return true; |
| 466 } | 490 } |
| 467 | 491 |
| 468 bool DirectoryBackingStore::LoadEntries(MetahandlesIndex* entry_bucket) { | 492 bool DirectoryBackingStore::LoadEntries(MetahandlesIndex* entry_bucket) { |
| 469 string select; | 493 return LoadEntriesInternal("metas", entry_bucket); |
| 470 select.reserve(kUpdateStatementBufferSize); | 494 } |
| 471 select.append("SELECT "); | |
| 472 AppendColumnList(&select); | |
| 473 select.append(" FROM metas "); | |
| 474 | 495 |
| 475 sql::Statement s(db_->GetUniqueStatement(select.c_str())); | 496 bool DirectoryBackingStore::LoadDeleteJournals( |
| 476 | 497 JournalIndex* delete_journals) { |
| 477 while (s.Step()) { | 498 return LoadEntriesInternal("deleted_metas", delete_journals); |
| 478 scoped_ptr<EntryKernel> kernel = UnpackEntry(&s); | |
| 479 // A null kernel is evidence of external data corruption. | |
| 480 if (!kernel.get()) | |
| 481 return false; | |
| 482 entry_bucket->insert(kernel.release()); | |
| 483 } | |
| 484 return s.Succeeded(); | |
| 485 } | 499 } |
| 486 | 500 |
| 487 bool DirectoryBackingStore::LoadInfo(Directory::KernelLoadInfo* info) { | 501 bool DirectoryBackingStore::LoadInfo(Directory::KernelLoadInfo* info) { |
| 488 { | 502 { |
| 489 sql::Statement s( | 503 sql::Statement s( |
| 490 db_->GetUniqueStatement( | 504 db_->GetUniqueStatement( |
| 491 "SELECT store_birthday, next_id, cache_guid, notification_state, " | 505 "SELECT store_birthday, next_id, cache_guid, notification_state, " |
| 492 "bag_of_chips " | 506 "bag_of_chips " |
| 493 "FROM share_info")); | 507 "FROM share_info")); |
| 494 if (!s.Step()) | 508 if (!s.Step()) |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 532 | 546 |
| 533 info->max_metahandle = s.ColumnInt64(0); | 547 info->max_metahandle = s.ColumnInt64(0); |
| 534 | 548 |
| 535 // Verify only one row was returned. | 549 // Verify only one row was returned. |
| 536 DCHECK(!s.Step()); | 550 DCHECK(!s.Step()); |
| 537 DCHECK(s.Succeeded()); | 551 DCHECK(s.Succeeded()); |
| 538 } | 552 } |
| 539 return true; | 553 return true; |
| 540 } | 554 } |
| 541 | 555 |
| 542 bool DirectoryBackingStore::SaveEntryToDB(const EntryKernel& entry) { | 556 /* static */ |
| 543 // This statement is constructed at runtime, so we can't use | 557 bool DirectoryBackingStore::SaveEntryToDB(sql::Statement* save_statement, |
| 544 // GetCachedStatement() to let the Connection cache it. We will construct | 558 const EntryKernel& entry) { |
| 545 // and cache it ourselves the first time this function is called. | 559 save_statement->Reset(true); |
| 546 if (!save_entry_statement_.is_valid()) { | 560 BindFields(entry, save_statement); |
| 547 string query; | 561 return save_statement->Run(); |
| 548 query.reserve(kUpdateStatementBufferSize); | |
| 549 query.append("INSERT OR REPLACE INTO metas "); | |
| 550 string values; | |
| 551 values.reserve(kUpdateStatementBufferSize); | |
| 552 values.append("VALUES "); | |
| 553 const char* separator = "( "; | |
| 554 int i = 0; | |
| 555 for (i = BEGIN_FIELDS; i < FIELD_COUNT; ++i) { | |
| 556 query.append(separator); | |
| 557 values.append(separator); | |
| 558 separator = ", "; | |
| 559 query.append(ColumnName(i)); | |
| 560 values.append("?"); | |
| 561 } | |
| 562 query.append(" ) "); | |
| 563 values.append(" )"); | |
| 564 query.append(values); | |
| 565 | |
| 566 save_entry_statement_.Assign( | |
| 567 db_->GetUniqueStatement(query.c_str())); | |
| 568 } else { | |
| 569 save_entry_statement_.Reset(true); | |
| 570 } | |
| 571 | |
| 572 BindFields(entry, &save_entry_statement_); | |
| 573 return save_entry_statement_.Run(); | |
| 574 } | 562 } |
| 575 | 563 |
| 576 bool DirectoryBackingStore::DropDeletedEntries() { | 564 bool DirectoryBackingStore::DropDeletedEntries() { |
| 577 if (!db_->Execute("DELETE FROM metas " | 565 if (!db_->Execute("DELETE FROM metas " |
| 578 "WHERE is_del > 0 " | 566 "WHERE is_del > 0 " |
| 579 "AND is_unsynced < 1 " | 567 "AND is_unsynced < 1 " |
| 580 "AND is_unapplied_update < 1")) { | 568 "AND is_unapplied_update < 1")) { |
| 581 return false; | 569 return false; |
| 582 } | 570 } |
| 583 if (!db_->Execute("DELETE FROM metas " | 571 if (!db_->Execute("DELETE FROM metas " |
| (...skipping 503 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1087 return true; | 1075 return true; |
| 1088 } | 1076 } |
| 1089 | 1077 |
| 1090 bool DirectoryBackingStore::MigrateVersion83To84() { | 1078 bool DirectoryBackingStore::MigrateVersion83To84() { |
| 1091 // Version 84 added deleted_metas table to store deleted metas until we know | 1079 // Version 84 added deleted_metas table to store deleted metas until we know |
| 1092 // for sure that the deletions are persisted in native models. | 1080 // for sure that the deletions are persisted in native models. |
| 1093 string query = "CREATE TABLE deleted_metas "; | 1081 string query = "CREATE TABLE deleted_metas "; |
| 1094 query.append(ComposeCreateTableColumnSpecs()); | 1082 query.append(ComposeCreateTableColumnSpecs()); |
| 1095 if (!db_->Execute(query.c_str())) | 1083 if (!db_->Execute(query.c_str())) |
| 1096 return false; | 1084 return false; |
| 1097 | |
| 1098 SetVersion(84); | 1085 SetVersion(84); |
| 1099 return true; | 1086 return true; |
| 1100 } | 1087 } |
| 1101 | 1088 |
| 1102 bool DirectoryBackingStore::MigrateVersion84To85() { | 1089 bool DirectoryBackingStore::MigrateVersion84To85() { |
| 1103 // Version 84 removes the initial_sync_ended flag. | 1090 // Version 84 removes the initial_sync_ended flag. |
| 1104 if (!db_->Execute("ALTER TABLE models RENAME TO temp_models")) | 1091 if (!db_->Execute("ALTER TABLE models RENAME TO temp_models")) |
| 1105 return false; | 1092 return false; |
| 1106 if (!CreateModelsTable()) | 1093 if (!CreateModelsTable()) |
| 1107 return false; | 1094 return false; |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1308 it != index.end(); ++it) { | 1295 it != index.end(); ++it) { |
| 1309 EntryKernel* entry = *it; | 1296 EntryKernel* entry = *it; |
| 1310 bool prev_exists = (ids_set.find(entry->ref(PREV_ID).value()) != end); | 1297 bool prev_exists = (ids_set.find(entry->ref(PREV_ID).value()) != end); |
| 1311 bool parent_exists = (ids_set.find(entry->ref(PARENT_ID).value()) != end); | 1298 bool parent_exists = (ids_set.find(entry->ref(PARENT_ID).value()) != end); |
| 1312 bool next_exists = (ids_set.find(entry->ref(NEXT_ID).value()) != end); | 1299 bool next_exists = (ids_set.find(entry->ref(NEXT_ID).value()) != end); |
| 1313 is_ok = is_ok && prev_exists && parent_exists && next_exists; | 1300 is_ok = is_ok && prev_exists && parent_exists && next_exists; |
| 1314 } | 1301 } |
| 1315 return is_ok; | 1302 return is_ok; |
| 1316 } | 1303 } |
| 1317 | 1304 |
| 1305 template<class T> |
| 1306 bool DirectoryBackingStore::LoadEntriesInternal(const std::string& table, |
| 1307 T* bucket) { |
| 1308 string select; |
| 1309 select.reserve(kUpdateStatementBufferSize); |
| 1310 select.append("SELECT "); |
| 1311 AppendColumnList(&select); |
| 1312 select.append(" FROM " + table); |
| 1313 |
| 1314 sql::Statement s(db_->GetUniqueStatement(select.c_str())); |
| 1315 |
| 1316 while (s.Step()) { |
| 1317 scoped_ptr<EntryKernel> kernel = UnpackEntry(&s); |
| 1318 // A null kernel is evidence of external data corruption. |
| 1319 if (!kernel.get()) |
| 1320 return false; |
| 1321 bucket->insert(kernel.release()); |
| 1322 } |
| 1323 return s.Succeeded(); |
| 1324 } |
| 1325 |
| 1326 void DirectoryBackingStore::PrepareSaveEntryStatement( |
| 1327 EntryTable table, sql::Statement* save_statement) { |
| 1328 if (save_statement->is_valid()) |
| 1329 return; |
| 1330 |
| 1331 string query; |
| 1332 query.reserve(kUpdateStatementBufferSize); |
| 1333 switch (table) { |
| 1334 case METAS_TABLE: |
| 1335 query.append("INSERT OR REPLACE INTO metas "); |
| 1336 break; |
| 1337 case DELETE_JOURNAL_TABLE: |
| 1338 query.append("INSERT OR REPLACE INTO deleted_metas "); |
| 1339 break; |
| 1340 } |
| 1341 |
| 1342 string values; |
| 1343 values.reserve(kUpdateStatementBufferSize); |
| 1344 values.append(" VALUES "); |
| 1345 const char* separator = "( "; |
| 1346 int i = 0; |
| 1347 for (i = BEGIN_FIELDS; i < FIELD_COUNT; ++i) { |
| 1348 query.append(separator); |
| 1349 values.append(separator); |
| 1350 separator = ", "; |
| 1351 query.append(ColumnName(i)); |
| 1352 values.append("?"); |
| 1353 } |
| 1354 query.append(" ) "); |
| 1355 values.append(" )"); |
| 1356 query.append(values); |
| 1357 save_statement->Assign(db_->GetUniqueStatement( |
| 1358 base::StringPrintf(query.c_str(), "metas").c_str())); |
| 1359 } |
| 1360 |
| 1318 } // namespace syncable | 1361 } // namespace syncable |
| 1319 } // namespace syncer | 1362 } // namespace syncer |
| OLD | NEW |