1731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/get_commit_ids_command.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <set>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <utility>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector>
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/syncer_util.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/syncable/syncable.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::set;
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::vector;
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace browser_sync {
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing sessions::OrderedCommitSet;
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing sessions::SyncSession;
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing sessions::StatusController;
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGetCommitIdsCommand::GetCommitIdsCommand(int commit_batch_size)
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : requested_commit_batch_size_(commit_batch_size) {}
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGetCommitIdsCommand::~GetCommitIdsCommand() {}
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GetCommitIdsCommand::ExecuteImpl(SyncSession* session) {
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Gather the full set of unsynced items and store it in the session. They
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // are not in the correct order for commit.
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::Directory::UnsyncedMetaHandles all_unsynced_handles;
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SyncerUtil::GetUnsyncedEntries(session->write_transaction(),
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 &all_unsynced_handles);
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StatusController* status = session->status_controller();
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  status->set_unsynced_handles(all_unsynced_handles);
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BuildCommitIds(status->unsynced_handles(), session->write_transaction(),
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 session->routing_info());
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const vector<syncable::Id>& verified_commit_ids =
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ordered_commit_set_->GetAllCommitIds();
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < verified_commit_ids.size(); i++)
44731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "Debug commit batch result:" << verified_commit_ids[i];
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  status->set_commit_set(*ordered_commit_set_.get());
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GetCommitIdsCommand::AddUncommittedParentsAndTheirPredecessors(
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::BaseTransaction* trans,
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::Id parent_id,
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const ModelSafeRoutingInfo& routes) {
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  using namespace syncable;
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  OrderedCommitSet item_dependencies(routes);
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Climb the tree adding entries leaf -> root.
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (!parent_id.ServerKnows()) {
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Entry parent(trans, GET_BY_ID, parent_id);
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CHECK(parent.good()) << "Bad user-only parent in item path.";
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int64 handle = parent.Get(META_HANDLE);
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (ordered_commit_set_->HaveCommitItem(handle) ||
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        item_dependencies.HaveCommitItem(handle)) {
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!AddItemThenPredecessors(trans, &parent, IS_UNSYNCED,
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 &item_dependencies)) {
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;  // Parent was already present in the set.
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    parent_id = parent.Get(PARENT_ID);
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Reverse what we added to get the correct order.
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ordered_commit_set_->AppendReverse(item_dependencies);
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetCommitIdsCommand::AddItem(syncable::Entry* item,
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  OrderedCommitSet* result) {
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int64 item_handle = item->Get(syncable::META_HANDLE);
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result->HaveCommitItem(item_handle) ||
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ordered_commit_set_->HaveCommitItem(item_handle)) {
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->AddCommitItem(item_handle, item->Get(syncable::ID),
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        item->GetModelType());
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetCommitIdsCommand::AddItemThenPredecessors(
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::BaseTransaction* trans,
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::Entry* item,
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::IndexedBitField inclusion_filter,
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OrderedCommitSet* result) {
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!AddItem(item, result))
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (item->Get(syncable::IS_DEL))
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;  // Deleted items have no predecessors.
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::Id prev_id = item->Get(syncable::PREV_ID);
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (!prev_id.IsRoot()) {
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::Entry prev(trans, syncable::GET_BY_ID, prev_id);
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CHECK(prev.good()) << "Bad id when walking predecessors.";
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!prev.Get(inclusion_filter))
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!AddItem(&prev, result))
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    prev_id = prev.Get(syncable::PREV_ID);
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GetCommitIdsCommand::AddPredecessorsThenItem(
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::BaseTransaction* trans,
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::Entry* item,
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::IndexedBitField inclusion_filter,
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const ModelSafeRoutingInfo& routes) {
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  OrderedCommitSet item_dependencies(routes);
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddItemThenPredecessors(trans, item, inclusion_filter, &item_dependencies);
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Reverse what we added to get the correct order.
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ordered_commit_set_->AppendReverse(item_dependencies);
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetCommitIdsCommand::IsCommitBatchFull() {
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return ordered_commit_set_->Size() >= requested_commit_batch_size_;
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GetCommitIdsCommand::AddCreatesAndMoves(
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const vector<int64>& unsynced_handles,
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::WriteTransaction* write_transaction,
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const ModelSafeRoutingInfo& routes) {
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Add moves and creates, and prepend their uncommitted parents.
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (CommitMetahandleIterator iterator(unsynced_handles, write_transaction,
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         ordered_commit_set_.get());
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       !IsCommitBatchFull() && iterator.Valid();
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       iterator.Increment()) {
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int64 metahandle = iterator.Current();
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::Entry entry(write_transaction,
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          syncable::GET_BY_HANDLE,
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          metahandle);
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!entry.Get(syncable::IS_DEL)) {
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      AddUncommittedParentsAndTheirPredecessors(write_transaction,
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          entry.Get(syncable::PARENT_ID), routes);
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      AddPredecessorsThenItem(write_transaction, &entry,
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          syncable::IS_UNSYNCED, routes);
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // It's possible that we overcommitted while trying to expand dependent
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // items.  If so, truncate the set down to the allowed size.
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ordered_commit_set_->Truncate(requested_commit_batch_size_);
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GetCommitIdsCommand::AddDeletes(const vector<int64>& unsynced_handles,
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::WriteTransaction* write_transaction) {
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  set<syncable::Id> legal_delete_parents;
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (CommitMetahandleIterator iterator(unsynced_handles, write_transaction,
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         ordered_commit_set_.get());
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       !IsCommitBatchFull() && iterator.Valid();
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       iterator.Increment()) {
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int64 metahandle = iterator.Current();
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::Entry entry(write_transaction, syncable::GET_BY_HANDLE,
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          metahandle);
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (entry.Get(syncable::IS_DEL)) {
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      syncable::Entry parent(write_transaction, syncable::GET_BY_ID,
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             entry.Get(syncable::PARENT_ID));
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // If the parent is deleted and unsynced, then any children of that
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // parent don't need to be added to the delete queue.
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      //
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Note: the parent could be synced if there was an update deleting a
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // folder when we had a deleted all items in it.
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We may get more updates, or we may want to delete the entry.
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (parent.good() &&
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          parent.Get(syncable::IS_DEL) &&
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          parent.Get(syncable::IS_UNSYNCED)) {
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // However, if an entry is moved, these rules can apply differently.
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        //
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // If the entry was moved, then the destination parent was deleted,
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // then we'll miss it in the roll up. We have to add it in manually.
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // TODO(chron): Unit test for move / delete cases:
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Case 1: Locally moved, then parent deleted
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Case 2: Server moved, then locally issue recursive delete.
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (entry.Get(syncable::ID).ServerKnows() &&
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            entry.Get(syncable::PARENT_ID) !=
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                entry.Get(syncable::SERVER_PARENT_ID)) {
189731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          VLOG(1) << "Inserting moved and deleted entry, will be missed by "
190731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                     "delete roll." << entry.Get(syncable::ID);
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          ordered_commit_set_->AddCommitItem(metahandle,
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              entry.Get(syncable::ID),
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              entry.GetModelType());
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Skip this entry since it's a child of a parent that will be
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // deleted. The server will unroll the delete and delete the
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // child as well.
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      legal_delete_parents.insert(entry.Get(syncable::PARENT_ID));
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We could store all the potential entries with a particular parent during
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the above scan, but instead we rescan here. This is less efficient, but
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we're dropping memory alloc/dealloc in favor of linear scans of recently
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // examined entries.
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Scan through the UnsyncedMetaHandles again. If we have a deleted
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // entry, then check if the parent is in legal_delete_parents.
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Parent being in legal_delete_parents means for the child:
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   a recursive delete is not currently happening (no recent deletes in same
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //     folder)
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   parent did expect at least one old deleted child
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   parent was not deleted
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (CommitMetahandleIterator iterator(unsynced_handles, write_transaction,
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         ordered_commit_set_.get());
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      !IsCommitBatchFull() && iterator.Valid();
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      iterator.Increment()) {
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int64 metahandle = iterator.Current();
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::MutableEntry entry(write_transaction, syncable::GET_BY_HANDLE,
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 metahandle);
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (entry.Get(syncable::IS_DEL)) {
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      syncable::Id parent_id = entry.Get(syncable::PARENT_ID);
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (legal_delete_parents.count(parent_id)) {
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ordered_commit_set_->AddCommitItem(metahandle, entry.Get(syncable::ID),
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            entry.GetModelType());
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid GetCommitIdsCommand::BuildCommitIds(const vector<int64>& unsynced_handles,
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::WriteTransaction* write_transaction,
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const ModelSafeRoutingInfo& routes) {
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ordered_commit_set_.reset(new OrderedCommitSet(routes));
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Commits follow these rules:
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // 1. Moves or creates are preceded by needed folder creates, from
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    root to leaf.  For folders whose contents are ordered, moves
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    and creates appear in order.
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // 2. Moves/Creates before deletes.
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // 3. Deletes, collapsed.
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We commit deleted moves under deleted items as moves when collapsing
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // delete trees.
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Add moves and creates, and prepend their uncommitted parents.
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddCreatesAndMoves(unsynced_handles, write_transaction, routes);
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Add all deletes.
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddDeletes(unsynced_handles, write_transaction);
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace browser_sync
259