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

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: make IsDeleteJournalEnabled() public Created 8 years 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 (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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698