Index: chrome/browser/sync/syncable/syncable.cc |
=================================================================== |
--- chrome/browser/sync/syncable/syncable.cc (revision 51231) |
+++ chrome/browser/sync/syncable/syncable.cc (working copy) |
@@ -157,6 +157,11 @@ |
static const DirectoryChangeEvent kShutdownChangesEvent = |
{ DirectoryChangeEvent::SHUTDOWN, 0, 0 }; |
+void Directory::init_kernel(const std::string& name) { |
+ DCHECK(kernel_ == NULL); |
+ kernel_ = new Kernel(FilePath(), name, KernelLoadInfo()); |
+} |
+ |
Directory::Kernel::Kernel(const FilePath& db_path, |
const string& name, |
const KernelLoadInfo& info) |
@@ -170,6 +175,7 @@ |
unapplied_update_metahandles(new MetahandleSet), |
unsynced_metahandles(new MetahandleSet), |
dirty_metahandles(new MetahandleSet), |
+ metahandles_to_purge(new MetahandleSet), |
channel(new Directory::Channel(syncable::DIRECTORY_DESTROYED)), |
info_status(Directory::KERNEL_SHARE_INFO_VALID), |
persisted_info(info.kernel_info), |
@@ -197,6 +203,7 @@ |
delete unsynced_metahandles; |
delete unapplied_update_metahandles; |
delete dirty_metahandles; |
+ delete metahandles_to_purge; |
delete parent_id_child_index; |
delete client_tag_index; |
delete ids_index; |
@@ -522,6 +529,10 @@ |
} |
ClearDirtyMetahandles(); |
+ // Set purged handles. |
+ DCHECK(snapshot->metahandles_to_purge.empty()); |
+ snapshot->metahandles_to_purge.swap(*(kernel_->metahandles_to_purge)); |
+ |
// Fill kernel_info_status and kernel_info. |
snapshot->kernel_info = kernel_->persisted_info; |
// To avoid duplicates when the process crashes, we record the next_id to be |
@@ -579,6 +590,7 @@ |
// Might not be in it |
num_erased = kernel_->client_tag_index->erase(entry); |
DCHECK_EQ(entry->ref(UNIQUE_CLIENT_TAG).empty(), !num_erased); |
+ DCHECK(!kernel_->parent_id_child_index->count(entry)); |
delete entry; |
} |
} |
@@ -594,30 +606,42 @@ |
return; |
{ |
- ScopedKernelLock lock(this); |
- for (MetahandlesIndex::iterator it = kernel_->metahandles_index->begin(); |
- it != kernel_->metahandles_index->end(); ++it) { |
- const sync_pb::EntitySpecifics& local_specifics = (*it)->ref(SPECIFICS); |
- const sync_pb::EntitySpecifics& server_specifics = |
- (*it)->ref(SERVER_SPECIFICS); |
- ModelType local_type = GetModelTypeFromSpecifics(local_specifics); |
- ModelType server_type = GetModelTypeFromSpecifics(server_specifics); |
+ WriteTransaction trans(this, PURGE_ENTRIES, __FILE__, __LINE__); |
+ { |
+ ScopedKernelLock lock(this); |
+ MetahandlesIndex::iterator it = kernel_->metahandles_index->begin(); |
+ while (it != kernel_->metahandles_index->end()) { |
+ const sync_pb::EntitySpecifics& local_specifics = (*it)->ref(SPECIFICS); |
+ const sync_pb::EntitySpecifics& server_specifics = |
+ (*it)->ref(SERVER_SPECIFICS); |
+ ModelType local_type = GetModelTypeFromSpecifics(local_specifics); |
+ ModelType server_type = GetModelTypeFromSpecifics(server_specifics); |
- if (types.count(local_type) > 0 || types.count(server_type) > 0) { |
- // Set conditions for permanent deletion. |
- (*it)->put(IS_DEL, true); |
- (*it)->put(IS_UNSYNCED, false); |
- (*it)->put(IS_UNAPPLIED_UPDATE, false); |
- (*it)->mark_dirty(kernel_->dirty_metahandles); |
- DCHECK(!SafeToPurgeFromMemory(*it)); |
+ // Note the dance around incrementing |it|, since we sometimes erase(). |
+ if (types.count(local_type) > 0 || types.count(server_type) > 0) { |
+ UnlinkEntryFromOrder(*it, NULL, &lock); |
+ |
+ kernel_->metahandles_to_purge->insert((*it)->ref(META_HANDLE)); |
+ |
+ size_t num_erased = 0; |
+ num_erased = kernel_->ids_index->erase(*it); |
+ DCHECK_EQ(1u, num_erased); |
+ num_erased = kernel_->client_tag_index->erase(*it); |
+ DCHECK_EQ((*it)->ref(UNIQUE_CLIENT_TAG).empty(), !num_erased); |
+ num_erased = kernel_->parent_id_child_index->erase(*it); |
+ DCHECK_EQ((*it)->ref(IS_DEL), !num_erased); |
+ kernel_->metahandles_index->erase(it++); |
+ } else { |
+ ++it; |
+ } |
} |
- } |
- // Ensure meta tracking for these data types reflects the deleted state. |
- for (std::set<ModelType>::const_iterator it = types.begin(); |
- it != types.end(); ++it) { |
- set_initial_sync_ended_for_type_unsafe(*it, false); |
- set_last_download_timestamp_unsafe(*it, 0); |
+ // Ensure meta tracking for these data types reflects the deleted state. |
+ for (std::set<ModelType>::const_iterator it = types.begin(); |
+ it != types.end(); ++it) { |
+ set_initial_sync_ended_for_type_unsafe(*it, false); |
+ set_last_download_timestamp_unsafe(*it, 0); |
+ } |
} |
} |
} |
@@ -640,6 +664,9 @@ |
(*found)->mark_dirty(kernel_->dirty_metahandles); |
} |
} |
+ |
+ kernel_->metahandles_to_purge->insert(snapshot.metahandles_to_purge.begin(), |
+ snapshot.metahandles_to_purge.end()); |
} |
int64 Directory::last_download_timestamp(ModelType model_type) const { |
@@ -1276,32 +1303,44 @@ |
} |
void MutableEntry::UnlinkFromOrder() { |
- Id old_previous = Get(PREV_ID); |
- Id old_next = Get(NEXT_ID); |
+ ScopedKernelLock lock(dir()); |
+ dir()->UnlinkEntryFromOrder(kernel_, write_transaction(), &lock); |
+} |
- // Self-looping signifies that this item is not in the order. If we were to |
- // set these to 0, we could get into trouble because this node might look |
- // like the first node in the ordering. |
- Put(NEXT_ID, Get(ID)); |
- Put(PREV_ID, Get(ID)); |
+void Directory::UnlinkEntryFromOrder(EntryKernel* entry, |
+ WriteTransaction* trans, |
+ ScopedKernelLock* lock) { |
+ CHECK(!trans || this == trans->directory()); |
+ Id old_previous = entry->ref(PREV_ID); |
+ Id old_next = entry->ref(NEXT_ID); |
+ entry->put(NEXT_ID, entry->ref(ID)); |
+ entry->put(PREV_ID, entry->ref(ID)); |
+ entry->mark_dirty(kernel_->dirty_metahandles); |
+ |
if (!old_previous.IsRoot()) { |
if (old_previous == old_next) { |
// Note previous == next doesn't imply previous == next == Get(ID). We |
// could have prev==next=="c-XX" and Get(ID)=="sX..." if an item was added |
// and deleted before receiving the server ID in the commit response. |
- CHECK((old_next == Get(ID)) || !old_next.ServerKnows()); |
+ CHECK((old_next == entry->ref(ID)) || !old_next.ServerKnows()); |
return; // Done if we were already self-looped (hence unlinked). |
} |
- MutableEntry previous_entry(write_transaction(), GET_BY_ID, old_previous); |
- CHECK(previous_entry.good()); |
- previous_entry.Put(NEXT_ID, old_next); |
+ EntryKernel* previous_entry = GetEntryById(old_previous, lock); |
+ CHECK(previous_entry); |
+ if (trans) |
+ trans->SaveOriginal(previous_entry); |
+ previous_entry->put(NEXT_ID, old_next); |
+ previous_entry->mark_dirty(kernel_->dirty_metahandles); |
} |
if (!old_next.IsRoot()) { |
- MutableEntry next_entry(write_transaction(), GET_BY_ID, old_next); |
- CHECK(next_entry.good()); |
- next_entry.Put(PREV_ID, old_previous); |
+ EntryKernel* next_entry = GetEntryById(old_next, lock); |
+ CHECK(next_entry); |
+ if (trans) |
+ trans->SaveOriginal(next_entry); |
+ next_entry->put(PREV_ID, old_previous); |
+ next_entry->mark_dirty(kernel_->dirty_metahandles); |
} |
} |