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