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

Side by Side Diff: sync/syncable/directory.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
« no previous file with comments | « sync/syncable/directory.h ('k') | sync/syncable/directory_backing_store.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.h" 5 #include "sync/syncable/directory.h"
6 6
7 #include "base/debug/trace_event.h" 7 #include "base/debug/trace_event.h"
8 #include "base/perftimer.h" 8 #include "base/perftimer.h"
9 #include "base/stl_util.h" 9 #include "base/stl_util.h"
10 #include "base/string_number_conversions.h" 10 #include "base/string_number_conversions.h"
11 #include "sync/internal_api/public/base/node_ordinal.h" 11 #include "sync/internal_api/public/base/node_ordinal.h"
12 #include "sync/internal_api/public/util/unrecoverable_error_handler.h" 12 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
13 #include "sync/syncable/delete_journal.h"
13 #include "sync/syncable/entry.h" 14 #include "sync/syncable/entry.h"
14 #include "sync/syncable/entry_kernel.h" 15 #include "sync/syncable/entry_kernel.h"
15 #include "sync/syncable/in_memory_directory_backing_store.h" 16 #include "sync/syncable/in_memory_directory_backing_store.h"
16 #include "sync/syncable/on_disk_directory_backing_store.h" 17 #include "sync/syncable/on_disk_directory_backing_store.h"
17 #include "sync/syncable/scoped_index_updater.h" 18 #include "sync/syncable/scoped_index_updater.h"
18 #include "sync/syncable/syncable-inl.h" 19 #include "sync/syncable/syncable-inl.h"
19 #include "sync/syncable/syncable_base_transaction.h" 20 #include "sync/syncable/syncable_base_transaction.h"
20 #include "sync/syncable/syncable_changes_version.h" 21 #include "sync/syncable/syncable_changes_version.h"
21 #include "sync/syncable/syncable_read_transaction.h" 22 #include "sync/syncable/syncable_read_transaction.h"
22 #include "sync/syncable/syncable_util.h" 23 #include "sync/syncable/syncable_util.h"
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 download_progress[model_type].set_data_type_id( 95 download_progress[model_type].set_data_type_id(
95 GetSpecificsFieldNumberFromModelType(model_type)); 96 GetSpecificsFieldNumberFromModelType(model_type));
96 // An empty-string token indicates no prior knowledge. 97 // An empty-string token indicates no prior knowledge.
97 download_progress[model_type].set_token(std::string()); 98 download_progress[model_type].set_token(std::string());
98 } 99 }
99 100
100 Directory::SaveChangesSnapshot::SaveChangesSnapshot() 101 Directory::SaveChangesSnapshot::SaveChangesSnapshot()
101 : kernel_info_status(KERNEL_SHARE_INFO_INVALID) { 102 : kernel_info_status(KERNEL_SHARE_INFO_INVALID) {
102 } 103 }
103 104
104 Directory::SaveChangesSnapshot::~SaveChangesSnapshot() {} 105 Directory::SaveChangesSnapshot::~SaveChangesSnapshot() {
106 STLDeleteElements(&dirty_metas);
107 STLDeleteElements(&delete_journals);
108 }
105 109
106 Directory::Kernel::Kernel( 110 Directory::Kernel::Kernel(
107 const std::string& name, 111 const std::string& name,
108 const KernelLoadInfo& info, DirectoryChangeDelegate* delegate, 112 const KernelLoadInfo& info, DirectoryChangeDelegate* delegate,
109 const WeakHandle<TransactionObserver>& transaction_observer) 113 const WeakHandle<TransactionObserver>& transaction_observer)
110 : next_write_transaction_id(0), 114 : next_write_transaction_id(0),
111 name(name), 115 name(name),
112 metahandles_index(new Directory::MetahandlesIndex), 116 metahandles_index(new Directory::MetahandlesIndex),
113 ids_index(new Directory::IdsIndex), 117 ids_index(new Directory::IdsIndex),
114 parent_id_child_index(new Directory::ParentIdChildIndex), 118 parent_id_child_index(new Directory::ParentIdChildIndex),
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 } 193 }
190 DCHECK(!entry->is_dirty()); 194 DCHECK(!entry->is_dirty());
191 } 195 }
192 } 196 }
193 197
194 DirOpenResult Directory::OpenImpl( 198 DirOpenResult Directory::OpenImpl(
195 const string& name, 199 const string& name,
196 DirectoryChangeDelegate* delegate, 200 DirectoryChangeDelegate* delegate,
197 const WeakHandle<TransactionObserver>& 201 const WeakHandle<TransactionObserver>&
198 transaction_observer) { 202 transaction_observer) {
199
200 KernelLoadInfo info; 203 KernelLoadInfo info;
201 // Temporary indices before kernel_ initialized in case Load fails. We 0(1) 204 // Temporary indices before kernel_ initialized in case Load fails. We 0(1)
202 // swap these later. 205 // swap these later.
203 MetahandlesIndex metas_bucket; 206 MetahandlesIndex metas_bucket;
204 DirOpenResult result = store_->Load(&metas_bucket, &info); 207 JournalIndex delete_journals;
208
209 DirOpenResult result = store_->Load(&metas_bucket, &delete_journals, &info);
205 if (OPENED != result) 210 if (OPENED != result)
206 return result; 211 return result;
207 212
208 kernel_ = new Kernel(name, info, delegate, transaction_observer); 213 kernel_ = new Kernel(name, info, delegate, transaction_observer);
209 kernel_->metahandles_index->swap(metas_bucket); 214 kernel_->metahandles_index->swap(metas_bucket);
215 delete_journal_.reset(new DeleteJournal(&delete_journals));
210 InitializeIndices(); 216 InitializeIndices();
211 217
212 // Write back the share info to reserve some space in 'next_id'. This will 218 // Write back the share info to reserve some space in 'next_id'. This will
213 // prevent local ID reuse in the case of an early crash. See the comments in 219 // prevent local ID reuse in the case of an early crash. See the comments in
214 // TakeSnapshotForSaveChanges() or crbug.com/142987 for more information. 220 // TakeSnapshotForSaveChanges() or crbug.com/142987 for more information.
215 kernel_->info_status = KERNEL_SHARE_INFO_DIRTY; 221 kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
216 if (!SaveChanges()) 222 if (!SaveChanges())
217 return FAILED_INITIAL_WRITE; 223 return FAILED_INITIAL_WRITE;
218 224
219 return OPENED; 225 return OPENED;
220 } 226 }
221 227
228 DeleteJournal* Directory::delete_journal() {
229 DCHECK(delete_journal_.get());
230 return delete_journal_.get();
231 }
232
222 void Directory::Close() { 233 void Directory::Close() {
223 store_.reset(); 234 store_.reset();
224 if (kernel_) { 235 if (kernel_) {
225 delete kernel_; 236 delete kernel_;
226 kernel_ = NULL; 237 kernel_ = NULL;
227 } 238 }
228 } 239 }
229 240
230 void Directory::OnUnrecoverableError(const BaseTransaction* trans, 241 void Directory::OnUnrecoverableError(const BaseTransaction* trans,
231 const tracked_objects::Location& location, 242 const tracked_objects::Location& location,
232 const std::string & message) { 243 const std::string & message) {
233 DCHECK(trans != NULL); 244 DCHECK(trans != NULL);
234 unrecoverable_error_set_ = true; 245 unrecoverable_error_set_ = true;
235 unrecoverable_error_handler_->OnUnrecoverableError(location, 246 unrecoverable_error_handler_->OnUnrecoverableError(location,
236 message); 247 message);
237 } 248 }
238 249
239
240 EntryKernel* Directory::GetEntryById(const Id& id) { 250 EntryKernel* Directory::GetEntryById(const Id& id) {
241 ScopedKernelLock lock(this); 251 ScopedKernelLock lock(this);
242 return GetEntryById(id, &lock); 252 return GetEntryById(id, &lock);
243 } 253 }
244 254
245 EntryKernel* Directory::GetEntryById(const Id& id, 255 EntryKernel* Directory::GetEntryById(const Id& id,
246 ScopedKernelLock* const lock) { 256 ScopedKernelLock* const lock) {
247 DCHECK(kernel_); 257 DCHECK(kernel_);
248 // Find it in the in memory ID index. 258 // Find it in the in memory ID index.
249 kernel_->needle.put(ID, id); 259 kernel_->needle.put(ID, id);
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
459 // Deep copy dirty entries from kernel_->metahandles_index into snapshot and 469 // Deep copy dirty entries from kernel_->metahandles_index into snapshot and
460 // clear dirty flags. 470 // clear dirty flags.
461 for (MetahandleSet::const_iterator i = kernel_->dirty_metahandles->begin(); 471 for (MetahandleSet::const_iterator i = kernel_->dirty_metahandles->begin();
462 i != kernel_->dirty_metahandles->end(); ++i) { 472 i != kernel_->dirty_metahandles->end(); ++i) {
463 EntryKernel* entry = GetEntryByHandle(*i, &lock); 473 EntryKernel* entry = GetEntryByHandle(*i, &lock);
464 if (!entry) 474 if (!entry)
465 continue; 475 continue;
466 // Skip over false positives; it happens relatively infrequently. 476 // Skip over false positives; it happens relatively infrequently.
467 if (!entry->is_dirty()) 477 if (!entry->is_dirty())
468 continue; 478 continue;
469 snapshot->dirty_metas.insert(snapshot->dirty_metas.end(), *entry); 479 snapshot->dirty_metas.insert(snapshot->dirty_metas.end(),
480 new EntryKernel(*entry));
470 DCHECK_EQ(1U, kernel_->dirty_metahandles->count(*i)); 481 DCHECK_EQ(1U, kernel_->dirty_metahandles->count(*i));
471 // We don't bother removing from the index here as we blow the entire thing 482 // We don't bother removing from the index here as we blow the entire thing
472 // in a moment, and it unnecessarily complicates iteration. 483 // in a moment, and it unnecessarily complicates iteration.
473 entry->clear_dirty(NULL); 484 entry->clear_dirty(NULL);
474 } 485 }
475 ClearDirtyMetahandles(); 486 ClearDirtyMetahandles();
476 487
477 // Set purged handles. 488 // Set purged handles.
478 DCHECK(snapshot->metahandles_to_purge.empty()); 489 DCHECK(snapshot->metahandles_to_purge.empty());
479 snapshot->metahandles_to_purge.swap(*(kernel_->metahandles_to_purge)); 490 snapshot->metahandles_to_purge.swap(*(kernel_->metahandles_to_purge));
480 491
481 // Fill kernel_info_status and kernel_info. 492 // Fill kernel_info_status and kernel_info.
482 snapshot->kernel_info = kernel_->persisted_info; 493 snapshot->kernel_info = kernel_->persisted_info;
483 // To avoid duplicates when the process crashes, we record the next_id to be 494 // To avoid duplicates when the process crashes, we record the next_id to be
484 // greater magnitude than could possibly be reached before the next save 495 // greater magnitude than could possibly be reached before the next save
485 // changes. In other words, it's effectively impossible for the user to 496 // changes. In other words, it's effectively impossible for the user to
486 // generate 65536 new bookmarks in 3 seconds. 497 // generate 65536 new bookmarks in 3 seconds.
487 snapshot->kernel_info.next_id -= 65536; 498 snapshot->kernel_info.next_id -= 65536;
488 snapshot->kernel_info_status = kernel_->info_status; 499 snapshot->kernel_info_status = kernel_->info_status;
489 // This one we reset on failure. 500 // This one we reset on failure.
490 kernel_->info_status = KERNEL_SHARE_INFO_VALID; 501 kernel_->info_status = KERNEL_SHARE_INFO_VALID;
502
503 delete_journal_->TakeSnapshotAndClear(
504 &trans, &snapshot->delete_journals, &snapshot->delete_journals_to_purge);
491 } 505 }
492 506
493 bool Directory::SaveChanges() { 507 bool Directory::SaveChanges() {
494 bool success = false; 508 bool success = false;
495 509
496 base::AutoLock scoped_lock(kernel_->save_changes_mutex); 510 base::AutoLock scoped_lock(kernel_->save_changes_mutex);
497 511
498 // Snapshot and save. 512 // Snapshot and save.
499 SaveChangesSnapshot snapshot; 513 SaveChangesSnapshot snapshot;
500 TakeSnapshotForSaveChanges(&snapshot); 514 TakeSnapshotForSaveChanges(&snapshot);
(...skipping 10 matching lines...) Expand all
511 bool Directory::VacuumAfterSaveChanges(const SaveChangesSnapshot& snapshot) { 525 bool Directory::VacuumAfterSaveChanges(const SaveChangesSnapshot& snapshot) {
512 if (snapshot.dirty_metas.empty()) 526 if (snapshot.dirty_metas.empty())
513 return true; 527 return true;
514 528
515 // Need a write transaction as we are about to permanently purge entries. 529 // Need a write transaction as we are about to permanently purge entries.
516 WriteTransaction trans(FROM_HERE, VACUUM_AFTER_SAVE, this); 530 WriteTransaction trans(FROM_HERE, VACUUM_AFTER_SAVE, this);
517 ScopedKernelLock lock(this); 531 ScopedKernelLock lock(this);
518 // Now drop everything we can out of memory. 532 // Now drop everything we can out of memory.
519 for (EntryKernelSet::const_iterator i = snapshot.dirty_metas.begin(); 533 for (EntryKernelSet::const_iterator i = snapshot.dirty_metas.begin();
520 i != snapshot.dirty_metas.end(); ++i) { 534 i != snapshot.dirty_metas.end(); ++i) {
521 kernel_->needle.put(META_HANDLE, i->ref(META_HANDLE)); 535 kernel_->needle.put(META_HANDLE, (*i)->ref(META_HANDLE));
522 MetahandlesIndex::iterator found = 536 MetahandlesIndex::iterator found =
523 kernel_->metahandles_index->find(&kernel_->needle); 537 kernel_->metahandles_index->find(&kernel_->needle);
524 EntryKernel* entry = (found == kernel_->metahandles_index->end() ? 538 EntryKernel* entry = (found == kernel_->metahandles_index->end() ?
525 NULL : *found); 539 NULL : *found);
526 if (entry && SafeToPurgeFromMemory(&trans, entry)) { 540 if (entry && SafeToPurgeFromMemory(&trans, entry)) {
527 // We now drop deleted metahandles that are up to date on both the client 541 // We now drop deleted metahandles that are up to date on both the client
528 // and the server. 542 // and the server.
529 size_t num_erased = 0; 543 size_t num_erased = 0;
530 num_erased = kernel_->ids_index->erase(entry); 544 num_erased = kernel_->ids_index->erase(entry);
531 DCHECK_EQ(1u, num_erased); 545 DCHECK_EQ(1u, num_erased);
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
598 it.Good(); it.Inc()) { 612 it.Good(); it.Inc()) {
599 kernel_->persisted_info.reset_download_progress(it.Get()); 613 kernel_->persisted_info.reset_download_progress(it.Get());
600 kernel_->persisted_info.transaction_version[it.Get()] = 0; 614 kernel_->persisted_info.transaction_version[it.Get()] = 0;
601 } 615 }
602 } 616 }
603 } 617 }
604 return true; 618 return true;
605 } 619 }
606 620
607 void Directory::HandleSaveChangesFailure(const SaveChangesSnapshot& snapshot) { 621 void Directory::HandleSaveChangesFailure(const SaveChangesSnapshot& snapshot) {
622 WriteTransaction trans(FROM_HERE, HANDLE_SAVE_FAILURE, this);
608 ScopedKernelLock lock(this); 623 ScopedKernelLock lock(this);
609 kernel_->info_status = KERNEL_SHARE_INFO_DIRTY; 624 kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
610 625
611 // Because we optimistically cleared the dirty bit on the real entries when 626 // Because we optimistically cleared the dirty bit on the real entries when
612 // taking the snapshot, we must restore it on failure. Not doing this could 627 // taking the snapshot, we must restore it on failure. Not doing this could
613 // cause lost data, if no other changes are made to the in-memory entries 628 // cause lost data, if no other changes are made to the in-memory entries
614 // that would cause the dirty bit to get set again. Setting the bit ensures 629 // that would cause the dirty bit to get set again. Setting the bit ensures
615 // that SaveChanges will at least try again later. 630 // that SaveChanges will at least try again later.
616 for (EntryKernelSet::const_iterator i = snapshot.dirty_metas.begin(); 631 for (EntryKernelSet::const_iterator i = snapshot.dirty_metas.begin();
617 i != snapshot.dirty_metas.end(); ++i) { 632 i != snapshot.dirty_metas.end(); ++i) {
618 kernel_->needle.put(META_HANDLE, i->ref(META_HANDLE)); 633 kernel_->needle.put(META_HANDLE, (*i)->ref(META_HANDLE));
619 MetahandlesIndex::iterator found = 634 MetahandlesIndex::iterator found =
620 kernel_->metahandles_index->find(&kernel_->needle); 635 kernel_->metahandles_index->find(&kernel_->needle);
621 if (found != kernel_->metahandles_index->end()) { 636 if (found != kernel_->metahandles_index->end()) {
622 (*found)->mark_dirty(kernel_->dirty_metahandles); 637 (*found)->mark_dirty(kernel_->dirty_metahandles);
623 } 638 }
624 } 639 }
625 640
626 kernel_->metahandles_to_purge->insert(snapshot.metahandles_to_purge.begin(), 641 kernel_->metahandles_to_purge->insert(snapshot.metahandles_to_purge.begin(),
627 snapshot.metahandles_to_purge.end()); 642 snapshot.metahandles_to_purge.end());
643
644 // Restore delete journals.
645 delete_journal_->AddJournalBatch(&trans, snapshot.delete_journals);
646 delete_journal_->PurgeDeleteJournals(&trans,
647 snapshot.delete_journals_to_purge);
628 } 648 }
629 649
630 void Directory::GetDownloadProgress( 650 void Directory::GetDownloadProgress(
631 ModelType model_type, 651 ModelType model_type,
632 sync_pb::DataTypeProgressMarker* value_out) const { 652 sync_pb::DataTypeProgressMarker* value_out) const {
633 ScopedKernelLock lock(this); 653 ScopedKernelLock lock(this);
634 return value_out->CopyFrom( 654 return value_out->CopyFrom(
635 kernel_->persisted_info.download_progress[model_type]); 655 kernel_->persisted_info.download_progress[model_type]);
636 } 656 }
637 657
(...skipping 627 matching lines...) Expand 10 before | Expand all | Expand 10 after
1265 // There were no children in the linked list. 1285 // There were no children in the linked list.
1266 return NULL; 1286 return NULL;
1267 } 1287 }
1268 1288
1269 ScopedKernelLock::ScopedKernelLock(const Directory* dir) 1289 ScopedKernelLock::ScopedKernelLock(const Directory* dir)
1270 : scoped_lock_(dir->kernel_->mutex), dir_(const_cast<Directory*>(dir)) { 1290 : scoped_lock_(dir->kernel_->mutex), dir_(const_cast<Directory*>(dir)) {
1271 } 1291 }
1272 1292
1273 } // namespace syncable 1293 } // namespace syncable
1274 } // namespace syncer 1294 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/syncable/directory.h ('k') | sync/syncable/directory_backing_store.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698