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

Side by Side Diff: chrome/browser/sync/syncable/syncable.cc

Issue 2865022: sync: add CleanupDisabledTypesCommand to purge data pertaining to previously... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 5 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 (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "chrome/browser/sync/syncable/syncable.h" 5 #include "chrome/browser/sync/syncable/syncable.h"
6 6
7 #include "build/build_config.h" 7 #include "build/build_config.h"
8 8
9 #include <sys/stat.h> 9 #include <sys/stat.h>
10 #if defined(OS_POSIX) 10 #if defined(OS_POSIX)
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 bool LessPathNames::operator() (const string& a, const string& b) const { 150 bool LessPathNames::operator() (const string& a, const string& b) const {
151 return ComparePathNames(a, b) < 0; 151 return ComparePathNames(a, b) < 0;
152 } 152 }
153 153
154 /////////////////////////////////////////////////////////////////////////// 154 ///////////////////////////////////////////////////////////////////////////
155 // Directory 155 // Directory
156 156
157 static const DirectoryChangeEvent kShutdownChangesEvent = 157 static const DirectoryChangeEvent kShutdownChangesEvent =
158 { DirectoryChangeEvent::SHUTDOWN, 0, 0 }; 158 { DirectoryChangeEvent::SHUTDOWN, 0, 0 };
159 159
160 void Directory::init_kernel(const std::string& name) {
161 DCHECK(kernel_ == NULL);
162 kernel_ = new Kernel(FilePath(), name, KernelLoadInfo());
163 }
164
160 Directory::Kernel::Kernel(const FilePath& db_path, 165 Directory::Kernel::Kernel(const FilePath& db_path,
161 const string& name, 166 const string& name,
162 const KernelLoadInfo& info) 167 const KernelLoadInfo& info)
163 : db_path(db_path), 168 : db_path(db_path),
164 refcount(1), 169 refcount(1),
165 name(name), 170 name(name),
166 metahandles_index(new Directory::MetahandlesIndex), 171 metahandles_index(new Directory::MetahandlesIndex),
167 ids_index(new Directory::IdsIndex), 172 ids_index(new Directory::IdsIndex),
168 parent_id_child_index(new Directory::ParentIdChildIndex), 173 parent_id_child_index(new Directory::ParentIdChildIndex),
169 client_tag_index(new Directory::ClientTagIndex), 174 client_tag_index(new Directory::ClientTagIndex),
170 unapplied_update_metahandles(new MetahandleSet), 175 unapplied_update_metahandles(new MetahandleSet),
171 unsynced_metahandles(new MetahandleSet), 176 unsynced_metahandles(new MetahandleSet),
172 dirty_metahandles(new MetahandleSet), 177 dirty_metahandles(new MetahandleSet),
178 metahandles_to_purge(new MetahandleSet),
173 channel(new Directory::Channel(syncable::DIRECTORY_DESTROYED)), 179 channel(new Directory::Channel(syncable::DIRECTORY_DESTROYED)),
174 info_status(Directory::KERNEL_SHARE_INFO_VALID), 180 info_status(Directory::KERNEL_SHARE_INFO_VALID),
175 persisted_info(info.kernel_info), 181 persisted_info(info.kernel_info),
176 cache_guid(info.cache_guid), 182 cache_guid(info.cache_guid),
177 next_metahandle(info.max_metahandle + 1) { 183 next_metahandle(info.max_metahandle + 1) {
178 } 184 }
179 185
180 inline void DeleteEntry(EntryKernel* kernel) { 186 inline void DeleteEntry(EntryKernel* kernel) {
181 delete kernel; 187 delete kernel;
182 } 188 }
183 189
184 void Directory::Kernel::AddRef() { 190 void Directory::Kernel::AddRef() {
185 base::subtle::NoBarrier_AtomicIncrement(&refcount, 1); 191 base::subtle::NoBarrier_AtomicIncrement(&refcount, 1);
186 } 192 }
187 193
188 void Directory::Kernel::Release() { 194 void Directory::Kernel::Release() {
189 if (!base::subtle::NoBarrier_AtomicIncrement(&refcount, -1)) 195 if (!base::subtle::NoBarrier_AtomicIncrement(&refcount, -1))
190 delete this; 196 delete this;
191 } 197 }
192 198
193 Directory::Kernel::~Kernel() { 199 Directory::Kernel::~Kernel() {
194 CHECK(0 == refcount); 200 CHECK(0 == refcount);
195 delete channel; 201 delete channel;
196 changes_channel.Notify(kShutdownChangesEvent); 202 changes_channel.Notify(kShutdownChangesEvent);
197 delete unsynced_metahandles; 203 delete unsynced_metahandles;
198 delete unapplied_update_metahandles; 204 delete unapplied_update_metahandles;
199 delete dirty_metahandles; 205 delete dirty_metahandles;
206 delete metahandles_to_purge;
200 delete parent_id_child_index; 207 delete parent_id_child_index;
201 delete client_tag_index; 208 delete client_tag_index;
202 delete ids_index; 209 delete ids_index;
203 for_each(metahandles_index->begin(), metahandles_index->end(), DeleteEntry); 210 for_each(metahandles_index->begin(), metahandles_index->end(), DeleteEntry);
204 delete metahandles_index; 211 delete metahandles_index;
205 } 212 }
206 213
207 Directory::Directory() : kernel_(NULL), store_(NULL) { 214 Directory::Directory() : kernel_(NULL), store_(NULL) {
208 } 215 }
209 216
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after
515 if (!entry->is_dirty()) 522 if (!entry->is_dirty())
516 continue; 523 continue;
517 snapshot->dirty_metas.insert(snapshot->dirty_metas.end(), *entry); 524 snapshot->dirty_metas.insert(snapshot->dirty_metas.end(), *entry);
518 DCHECK_EQ(1U, kernel_->dirty_metahandles->count(*i)); 525 DCHECK_EQ(1U, kernel_->dirty_metahandles->count(*i));
519 // We don't bother removing from the index here as we blow the entire thing 526 // We don't bother removing from the index here as we blow the entire thing
520 // in a moment, and it unnecessarily complicates iteration. 527 // in a moment, and it unnecessarily complicates iteration.
521 entry->clear_dirty(NULL); 528 entry->clear_dirty(NULL);
522 } 529 }
523 ClearDirtyMetahandles(); 530 ClearDirtyMetahandles();
524 531
532 // Set purged handles.
533 DCHECK(snapshot->metahandles_to_purge.empty());
534 snapshot->metahandles_to_purge.swap(*(kernel_->metahandles_to_purge));
535
525 // Fill kernel_info_status and kernel_info. 536 // Fill kernel_info_status and kernel_info.
526 snapshot->kernel_info = kernel_->persisted_info; 537 snapshot->kernel_info = kernel_->persisted_info;
527 // To avoid duplicates when the process crashes, we record the next_id to be 538 // To avoid duplicates when the process crashes, we record the next_id to be
528 // greater magnitude than could possibly be reached before the next save 539 // greater magnitude than could possibly be reached before the next save
529 // changes. In other words, it's effectively impossible for the user to 540 // changes. In other words, it's effectively impossible for the user to
530 // generate 65536 new bookmarks in 3 seconds. 541 // generate 65536 new bookmarks in 3 seconds.
531 snapshot->kernel_info.next_id -= 65536; 542 snapshot->kernel_info.next_id -= 65536;
532 snapshot->kernel_info_status = kernel_->info_status; 543 snapshot->kernel_info_status = kernel_->info_status;
533 // This one we reset on failure. 544 // This one we reset on failure.
534 kernel_->info_status = KERNEL_SHARE_INFO_VALID; 545 kernel_->info_status = KERNEL_SHARE_INFO_VALID;
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
572 size_t num_erased = 0; 583 size_t num_erased = 0;
573 kernel_->flushed_metahandles.Push(entry->ref(META_HANDLE)); 584 kernel_->flushed_metahandles.Push(entry->ref(META_HANDLE));
574 num_erased = kernel_->ids_index->erase(entry); 585 num_erased = kernel_->ids_index->erase(entry);
575 DCHECK_EQ(1u, num_erased); 586 DCHECK_EQ(1u, num_erased);
576 num_erased = kernel_->metahandles_index->erase(entry); 587 num_erased = kernel_->metahandles_index->erase(entry);
577 DCHECK_EQ(1u, num_erased); 588 DCHECK_EQ(1u, num_erased);
578 589
579 // Might not be in it 590 // Might not be in it
580 num_erased = kernel_->client_tag_index->erase(entry); 591 num_erased = kernel_->client_tag_index->erase(entry);
581 DCHECK_EQ(entry->ref(UNIQUE_CLIENT_TAG).empty(), !num_erased); 592 DCHECK_EQ(entry->ref(UNIQUE_CLIENT_TAG).empty(), !num_erased);
593 DCHECK(!kernel_->parent_id_child_index->count(entry));
582 delete entry; 594 delete entry;
583 } 595 }
584 } 596 }
585 } 597 }
586 598
587 void Directory::PurgeEntriesWithTypeIn(const std::set<ModelType>& types) { 599 void Directory::PurgeEntriesWithTypeIn(const std::set<ModelType>& types) {
588 if (types.count(UNSPECIFIED) != 0U || types.count(TOP_LEVEL_FOLDER) != 0U) { 600 if (types.count(UNSPECIFIED) != 0U || types.count(TOP_LEVEL_FOLDER) != 0U) {
589 NOTREACHED() << "Don't support purging unspecified or top level entries."; 601 NOTREACHED() << "Don't support purging unspecified or top level entries.";
590 return; 602 return;
591 } 603 }
592 604
593 if (types.empty()) 605 if (types.empty())
594 return; 606 return;
595 607
596 { 608 {
597 ScopedKernelLock lock(this); 609 WriteTransaction trans(this, PURGE_ENTRIES, __FILE__, __LINE__);
598 for (MetahandlesIndex::iterator it = kernel_->metahandles_index->begin(); 610 {
599 it != kernel_->metahandles_index->end(); ++it) { 611 ScopedKernelLock lock(this);
600 const sync_pb::EntitySpecifics& local_specifics = (*it)->ref(SPECIFICS); 612 MetahandlesIndex::iterator it = kernel_->metahandles_index->begin();
601 const sync_pb::EntitySpecifics& server_specifics = 613 while (it != kernel_->metahandles_index->end()) {
602 (*it)->ref(SERVER_SPECIFICS); 614 const sync_pb::EntitySpecifics& local_specifics = (*it)->ref(SPECIFICS);
603 ModelType local_type = GetModelTypeFromSpecifics(local_specifics); 615 const sync_pb::EntitySpecifics& server_specifics =
604 ModelType server_type = GetModelTypeFromSpecifics(server_specifics); 616 (*it)->ref(SERVER_SPECIFICS);
617 ModelType local_type = GetModelTypeFromSpecifics(local_specifics);
618 ModelType server_type = GetModelTypeFromSpecifics(server_specifics);
605 619
606 if (types.count(local_type) > 0 || types.count(server_type) > 0) { 620 // Note the dance around incrementing |it|, since we sometimes erase().
607 // Set conditions for permanent deletion. 621 if (types.count(local_type) > 0 || types.count(server_type) > 0) {
608 (*it)->put(IS_DEL, true); 622 UnlinkEntryFromOrder(*it, NULL, &lock);
609 (*it)->put(IS_UNSYNCED, false); 623
610 (*it)->put(IS_UNAPPLIED_UPDATE, false); 624 kernel_->metahandles_to_purge->insert((*it)->ref(META_HANDLE));
611 (*it)->mark_dirty(kernel_->dirty_metahandles); 625
612 DCHECK(!SafeToPurgeFromMemory(*it)); 626 size_t num_erased = 0;
627 num_erased = kernel_->ids_index->erase(*it);
628 DCHECK_EQ(1u, num_erased);
629 num_erased = kernel_->client_tag_index->erase(*it);
630 DCHECK_EQ((*it)->ref(UNIQUE_CLIENT_TAG).empty(), !num_erased);
631 num_erased = kernel_->parent_id_child_index->erase(*it);
632 DCHECK_EQ((*it)->ref(IS_DEL), !num_erased);
633 kernel_->metahandles_index->erase(it++);
634 } else {
635 ++it;
636 }
613 } 637 }
614 }
615 638
616 // Ensure meta tracking for these data types reflects the deleted state. 639 // Ensure meta tracking for these data types reflects the deleted state.
617 for (std::set<ModelType>::const_iterator it = types.begin(); 640 for (std::set<ModelType>::const_iterator it = types.begin();
618 it != types.end(); ++it) { 641 it != types.end(); ++it) {
619 set_initial_sync_ended_for_type_unsafe(*it, false); 642 set_initial_sync_ended_for_type_unsafe(*it, false);
620 set_last_download_timestamp_unsafe(*it, 0); 643 set_last_download_timestamp_unsafe(*it, 0);
644 }
621 } 645 }
622 } 646 }
623 } 647 }
624 648
625 void Directory::HandleSaveChangesFailure(const SaveChangesSnapshot& snapshot) { 649 void Directory::HandleSaveChangesFailure(const SaveChangesSnapshot& snapshot) {
626 ScopedKernelLock lock(this); 650 ScopedKernelLock lock(this);
627 kernel_->info_status = KERNEL_SHARE_INFO_DIRTY; 651 kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
628 652
629 // Because we optimistically cleared the dirty bit on the real entries when 653 // Because we optimistically cleared the dirty bit on the real entries when
630 // taking the snapshot, we must restore it on failure. Not doing this could 654 // taking the snapshot, we must restore it on failure. Not doing this could
631 // cause lost data, if no other changes are made to the in-memory entries 655 // cause lost data, if no other changes are made to the in-memory entries
632 // that would cause the dirty bit to get set again. Setting the bit ensures 656 // that would cause the dirty bit to get set again. Setting the bit ensures
633 // that SaveChanges will at least try again later. 657 // that SaveChanges will at least try again later.
634 for (OriginalEntries::const_iterator i = snapshot.dirty_metas.begin(); 658 for (OriginalEntries::const_iterator i = snapshot.dirty_metas.begin();
635 i != snapshot.dirty_metas.end(); ++i) { 659 i != snapshot.dirty_metas.end(); ++i) {
636 kernel_->needle.put(META_HANDLE, i->ref(META_HANDLE)); 660 kernel_->needle.put(META_HANDLE, i->ref(META_HANDLE));
637 MetahandlesIndex::iterator found = 661 MetahandlesIndex::iterator found =
638 kernel_->metahandles_index->find(&kernel_->needle); 662 kernel_->metahandles_index->find(&kernel_->needle);
639 if (found != kernel_->metahandles_index->end()) { 663 if (found != kernel_->metahandles_index->end()) {
640 (*found)->mark_dirty(kernel_->dirty_metahandles); 664 (*found)->mark_dirty(kernel_->dirty_metahandles);
641 } 665 }
642 } 666 }
667
668 kernel_->metahandles_to_purge->insert(snapshot.metahandles_to_purge.begin(),
669 snapshot.metahandles_to_purge.end());
643 } 670 }
644 671
645 int64 Directory::last_download_timestamp(ModelType model_type) const { 672 int64 Directory::last_download_timestamp(ModelType model_type) const {
646 ScopedKernelLock lock(this); 673 ScopedKernelLock lock(this);
647 return kernel_->persisted_info.last_download_timestamp[model_type]; 674 return kernel_->persisted_info.last_download_timestamp[model_type];
648 } 675 }
649 676
650 void Directory::set_last_download_timestamp(ModelType model_type, 677 void Directory::set_last_download_timestamp(ModelType model_type,
651 int64 timestamp) { 678 int64 timestamp) {
652 ScopedKernelLock lock(this); 679 ScopedKernelLock lock(this);
(...skipping 616 matching lines...) Expand 10 before | Expand all | Expand 10 after
1269 CHECK(index->insert(kernel_->ref(META_HANDLE)).second); 1296 CHECK(index->insert(kernel_->ref(META_HANDLE)).second);
1270 else 1297 else
1271 CHECK(1 == index->erase(kernel_->ref(META_HANDLE))); 1298 CHECK(1 == index->erase(kernel_->ref(META_HANDLE)));
1272 kernel_->put(field, value); 1299 kernel_->put(field, value);
1273 kernel_->mark_dirty(dir()->kernel_->dirty_metahandles); 1300 kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
1274 } 1301 }
1275 return true; 1302 return true;
1276 } 1303 }
1277 1304
1278 void MutableEntry::UnlinkFromOrder() { 1305 void MutableEntry::UnlinkFromOrder() {
1279 Id old_previous = Get(PREV_ID); 1306 ScopedKernelLock lock(dir());
1280 Id old_next = Get(NEXT_ID); 1307 dir()->UnlinkEntryFromOrder(kernel_, write_transaction(), &lock);
1308 }
1281 1309
1282 // Self-looping signifies that this item is not in the order. If we were to 1310 void Directory::UnlinkEntryFromOrder(EntryKernel* entry,
1283 // set these to 0, we could get into trouble because this node might look 1311 WriteTransaction* trans,
1284 // like the first node in the ordering. 1312 ScopedKernelLock* lock) {
1285 Put(NEXT_ID, Get(ID)); 1313 CHECK(!trans || this == trans->directory());
1286 Put(PREV_ID, Get(ID)); 1314 Id old_previous = entry->ref(PREV_ID);
1315 Id old_next = entry->ref(NEXT_ID);
1316
1317 entry->put(NEXT_ID, entry->ref(ID));
1318 entry->put(PREV_ID, entry->ref(ID));
1319 entry->mark_dirty(kernel_->dirty_metahandles);
1287 1320
1288 if (!old_previous.IsRoot()) { 1321 if (!old_previous.IsRoot()) {
1289 if (old_previous == old_next) { 1322 if (old_previous == old_next) {
1290 // Note previous == next doesn't imply previous == next == Get(ID). We 1323 // Note previous == next doesn't imply previous == next == Get(ID). We
1291 // could have prev==next=="c-XX" and Get(ID)=="sX..." if an item was added 1324 // could have prev==next=="c-XX" and Get(ID)=="sX..." if an item was added
1292 // and deleted before receiving the server ID in the commit response. 1325 // and deleted before receiving the server ID in the commit response.
1293 CHECK((old_next == Get(ID)) || !old_next.ServerKnows()); 1326 CHECK((old_next == entry->ref(ID)) || !old_next.ServerKnows());
1294 return; // Done if we were already self-looped (hence unlinked). 1327 return; // Done if we were already self-looped (hence unlinked).
1295 } 1328 }
1296 MutableEntry previous_entry(write_transaction(), GET_BY_ID, old_previous); 1329 EntryKernel* previous_entry = GetEntryById(old_previous, lock);
1297 CHECK(previous_entry.good()); 1330 CHECK(previous_entry);
1298 previous_entry.Put(NEXT_ID, old_next); 1331 if (trans)
1332 trans->SaveOriginal(previous_entry);
1333 previous_entry->put(NEXT_ID, old_next);
1334 previous_entry->mark_dirty(kernel_->dirty_metahandles);
1299 } 1335 }
1300 1336
1301 if (!old_next.IsRoot()) { 1337 if (!old_next.IsRoot()) {
1302 MutableEntry next_entry(write_transaction(), GET_BY_ID, old_next); 1338 EntryKernel* next_entry = GetEntryById(old_next, lock);
1303 CHECK(next_entry.good()); 1339 CHECK(next_entry);
1304 next_entry.Put(PREV_ID, old_previous); 1340 if (trans)
1341 trans->SaveOriginal(next_entry);
1342 next_entry->put(PREV_ID, old_previous);
1343 next_entry->mark_dirty(kernel_->dirty_metahandles);
1305 } 1344 }
1306 } 1345 }
1307 1346
1308 bool MutableEntry::PutPredecessor(const Id& predecessor_id) { 1347 bool MutableEntry::PutPredecessor(const Id& predecessor_id) {
1309 UnlinkFromOrder(); 1348 UnlinkFromOrder();
1310 1349
1311 if (Get(IS_DEL)) { 1350 if (Get(IS_DEL)) {
1312 DCHECK(predecessor_id.IsNull()); 1351 DCHECK(predecessor_id.IsNull());
1313 return true; 1352 return true;
1314 } 1353 }
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
1507 return s << std::dec; 1546 return s << std::dec;
1508 } 1547 }
1509 1548
1510 FastDump& operator<<(FastDump& dump, const syncable::Blob& blob) { 1549 FastDump& operator<<(FastDump& dump, const syncable::Blob& blob) {
1511 if (blob.empty()) 1550 if (blob.empty())
1512 return dump; 1551 return dump;
1513 string buffer(HexEncode(&blob[0], blob.size())); 1552 string buffer(HexEncode(&blob[0], blob.size()));
1514 dump.out_->sputn(buffer.c_str(), buffer.size()); 1553 dump.out_->sputn(buffer.c_str(), buffer.size());
1515 return dump; 1554 return dump;
1516 } 1555 }
OLDNEW
« no previous file with comments | « chrome/browser/sync/syncable/syncable.h ('k') | chrome/browser/sync/syncable/syncable_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698