Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1381)

Side by Side Diff: sync/syncable/directory_backing_store.cc

Issue 11441026: [Sync] Add support for loading, updating and querying delete journals in (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « sync/syncable/directory_backing_store.h ('k') | sync/syncable/directory_backing_store_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698