summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sync
diff options
context:
space:
mode:
authortim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-16 21:40:05 +0000
committertim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-16 21:40:05 +0000
commit034565e3656a7d1227ff77e8eb3f6f06e4b64ff6 (patch)
tree77e02774c532271f9a192fb9c904a7343708a407 /chrome/browser/sync
parent47e9c75cebaa22ecb24c7bb4cde81f2cf507590b (diff)
downloadchromium_src-034565e3656a7d1227ff77e8eb3f6f06e4b64ff6.zip
chromium_src-034565e3656a7d1227ff77e8eb3f6f06e4b64ff6.tar.gz
chromium_src-034565e3656a7d1227ff77e8eb3f6f06e4b64ff6.tar.bz2
For sync, make ProcessCommitResponseCommand handle commit entries one ModelSafeGroup at a time.
Enforce ModelSafeGroup restrictions in the StatusController by DCHECKing if out-of-bounds. Move OrderedCommitSet to its own file. Removed some unused error counters and ResetTransientState calls that were useless. BUG=31911 TEST=ProcessCommitResponseTest, OrderedCommitSetTest Review URL: http://codereview.chromium.org/604045 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@39139 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/sync')
-rwxr-xr-xchrome/browser/sync/engine/build_commit_command.cc5
-rw-r--r--chrome/browser/sync/engine/download_updates_command.cc1
-rw-r--r--chrome/browser/sync/engine/get_commit_ids_command.cc75
-rw-r--r--chrome/browser/sync/engine/get_commit_ids_command.h156
-rw-r--r--chrome/browser/sync/engine/mock_model_safe_workers.h25
-rw-r--r--chrome/browser/sync/engine/model_changing_syncer_command.cc2
-rw-r--r--chrome/browser/sync/engine/model_changing_syncer_command.h11
-rw-r--r--chrome/browser/sync/engine/model_safe_worker.cc7
-rw-r--r--chrome/browser/sync/engine/model_safe_worker.h8
-rw-r--r--chrome/browser/sync/engine/post_commit_message_command.cc1
-rwxr-xr-xchrome/browser/sync/engine/process_commit_response_command.cc59
-rw-r--r--chrome/browser/sync/engine/process_commit_response_command.h1
-rwxr-xr-xchrome/browser/sync/engine/process_commit_response_command_unittest.cc125
-rwxr-xr-xchrome/browser/sync/engine/process_updates_command.cc1
-rwxr-xr-xchrome/browser/sync/engine/syncer.cc2
-rwxr-xr-xchrome/browser/sync/engine/syncer_unittest.cc84
-rw-r--r--chrome/browser/sync/sessions/ordered_commit_set.cc94
-rw-r--r--chrome/browser/sync/sessions/ordered_commit_set.h119
-rw-r--r--chrome/browser/sync/sessions/ordered_commit_set_unittest.cc120
-rw-r--r--chrome/browser/sync/sessions/session_state.h12
-rw-r--r--chrome/browser/sync/sessions/status_controller.cc60
-rw-r--r--chrome/browser/sync/sessions/status_controller.h55
-rw-r--r--chrome/browser/sync/sessions/status_controller_unittest.cc78
-rw-r--r--chrome/browser/sync/sessions/sync_session.cc5
-rw-r--r--chrome/browser/sync/sessions/sync_session.h23
-rw-r--r--chrome/browser/sync/sessions/sync_session_unittest.cc25
26 files changed, 688 insertions, 466 deletions
diff --git a/chrome/browser/sync/engine/build_commit_command.cc b/chrome/browser/sync/engine/build_commit_command.cc
index f1c3d52..cf6b4f53 100755
--- a/chrome/browser/sync/engine/build_commit_command.cc
+++ b/chrome/browser/sync/engine/build_commit_command.cc
@@ -35,6 +35,11 @@ BuildCommitCommand::~BuildCommitCommand() {}
void BuildCommitCommand::AddExtensionsActivityToMessage(
SyncSession* session, CommitMessage* message) {
+ // We only send ExtensionsActivity to the server if bookmarks are being
+ // committed.
+ if (!session->status_controller()->HasBookmarkCommitActivity())
+ return;
+
const ExtensionsActivityMonitor::Records& records =
session->extensions_activity();
for (ExtensionsActivityMonitor::Records::const_iterator it = records.begin();
diff --git a/chrome/browser/sync/engine/download_updates_command.cc b/chrome/browser/sync/engine/download_updates_command.cc
index cc58874..0dd198d 100644
--- a/chrome/browser/sync/engine/download_updates_command.cc
+++ b/chrome/browser/sync/engine/download_updates_command.cc
@@ -63,7 +63,6 @@ void DownloadUpdatesCommand::ExecuteImpl(SyncSession* session) {
StatusController* status = session->status_controller();
if (!ok) {
- status->increment_num_consecutive_problem_get_updates();
status->increment_num_consecutive_errors();
LOG(ERROR) << "PostClientToServerMessage() failed";
return;
diff --git a/chrome/browser/sync/engine/get_commit_ids_command.cc b/chrome/browser/sync/engine/get_commit_ids_command.cc
index 781c545..5b6d228 100644
--- a/chrome/browser/sync/engine/get_commit_ids_command.cc
+++ b/chrome/browser/sync/engine/get_commit_ids_command.cc
@@ -17,6 +17,7 @@ using std::vector;
namespace browser_sync {
+using sessions::OrderedCommitSet;
using sessions::SyncSession;
using sessions::StatusController;
@@ -38,51 +39,50 @@ void GetCommitIdsCommand::ExecuteImpl(SyncSession* session) {
session->routing_info());
const vector<syncable::Id>& verified_commit_ids =
- ordered_commit_set_.GetAllCommitIds();
+ ordered_commit_set_->GetAllCommitIds();
for (size_t i = 0; i < verified_commit_ids.size(); i++)
LOG(INFO) << "Debug commit batch result:" << verified_commit_ids[i];
- status->set_commit_ids(verified_commit_ids);
+ status->set_commit_set(*ordered_commit_set_.get());
}
void GetCommitIdsCommand::AddUncommittedParentsAndTheirPredecessors(
syncable::BaseTransaction* trans,
syncable::Id parent_id,
- const ModelSafeRoutingInfo& routing_info) {
+ const ModelSafeRoutingInfo& routes) {
using namespace syncable;
- OrderedCommitSet item_dependencies;
+ OrderedCommitSet item_dependencies(routes);
// Climb the tree adding entries leaf -> root.
while (!parent_id.ServerKnows()) {
Entry parent(trans, GET_BY_ID, parent_id);
CHECK(parent.good()) << "Bad user-only parent in item path.";
int64 handle = parent.Get(META_HANDLE);
- if (ordered_commit_set_.HaveCommitItem(handle) ||
+ if (ordered_commit_set_->HaveCommitItem(handle) ||
item_dependencies.HaveCommitItem(handle)) {
break;
}
if (!AddItemThenPredecessors(trans, &parent, IS_UNSYNCED,
- &item_dependencies, routing_info)) {
+ &item_dependencies)) {
break; // Parent was already present in the set.
}
parent_id = parent.Get(PARENT_ID);
}
// Reverse what we added to get the correct order.
- ordered_commit_set_.AppendReverse(item_dependencies);
+ ordered_commit_set_->AppendReverse(item_dependencies);
}
bool GetCommitIdsCommand::AddItem(syncable::Entry* item,
- OrderedCommitSet* result,
- const ModelSafeRoutingInfo& routing_info) {
+ OrderedCommitSet* result) {
int64 item_handle = item->Get(syncable::META_HANDLE);
if (result->HaveCommitItem(item_handle) ||
- ordered_commit_set_.HaveCommitItem(item_handle)) {
+ ordered_commit_set_->HaveCommitItem(item_handle)) {
return false;
}
result->AddCommitItem(item_handle, item->Get(syncable::ID),
- GetGroupForEntry(item, routing_info));
+ item->GetModelType());
return true;
}
@@ -90,9 +90,8 @@ bool GetCommitIdsCommand::AddItemThenPredecessors(
syncable::BaseTransaction* trans,
syncable::Entry* item,
syncable::IndexedBitField inclusion_filter,
- OrderedCommitSet* result,
- const ModelSafeRoutingInfo& routing_info) {
- if (!AddItem(item, result, routing_info))
+ OrderedCommitSet* result) {
+ if (!AddItem(item, result))
return false;
if (item->Get(syncable::IS_DEL))
return true; // Deleted items have no predecessors.
@@ -103,7 +102,7 @@ bool GetCommitIdsCommand::AddItemThenPredecessors(
CHECK(prev.good()) << "Bad id when walking predecessors.";
if (!prev.Get(inclusion_filter))
break;
- if (!AddItem(&prev, result, routing_info))
+ if (!AddItem(&prev, result))
break;
prev_id = prev.Get(syncable::PREV_ID);
}
@@ -114,26 +113,25 @@ void GetCommitIdsCommand::AddPredecessorsThenItem(
syncable::BaseTransaction* trans,
syncable::Entry* item,
syncable::IndexedBitField inclusion_filter,
- const ModelSafeRoutingInfo& routing_info) {
- OrderedCommitSet item_dependencies;
- AddItemThenPredecessors(trans, item, inclusion_filter, &item_dependencies,
- routing_info);
+ const ModelSafeRoutingInfo& routes) {
+ OrderedCommitSet item_dependencies(routes);
+ AddItemThenPredecessors(trans, item, inclusion_filter, &item_dependencies);
// Reverse what we added to get the correct order.
- ordered_commit_set_.AppendReverse(item_dependencies);
+ ordered_commit_set_->AppendReverse(item_dependencies);
}
bool GetCommitIdsCommand::IsCommitBatchFull() {
- return ordered_commit_set_.Size() >= requested_commit_batch_size_;
+ return ordered_commit_set_->Size() >= requested_commit_batch_size_;
}
void GetCommitIdsCommand::AddCreatesAndMoves(
const vector<int64>& unsynced_handles,
syncable::WriteTransaction* write_transaction,
- const ModelSafeRoutingInfo& routing_info) {
+ const ModelSafeRoutingInfo& routes) {
// Add moves and creates, and prepend their uncommitted parents.
for (CommitMetahandleIterator iterator(unsynced_handles, write_transaction,
- &ordered_commit_set_);
+ ordered_commit_set_.get());
!IsCommitBatchFull() && iterator.Valid();
iterator.Increment()) {
int64 metahandle = iterator.Current();
@@ -143,25 +141,23 @@ void GetCommitIdsCommand::AddCreatesAndMoves(
metahandle);
if (!entry.Get(syncable::IS_DEL)) {
AddUncommittedParentsAndTheirPredecessors(write_transaction,
- entry.Get(syncable::PARENT_ID),
- routing_info);
- AddPredecessorsThenItem(write_transaction, &entry, syncable::IS_UNSYNCED,
- routing_info);
+ entry.Get(syncable::PARENT_ID), routes);
+ AddPredecessorsThenItem(write_transaction, &entry,
+ syncable::IS_UNSYNCED, routes);
}
}
// It's possible that we overcommitted while trying to expand dependent
// items. If so, truncate the set down to the allowed size.
- ordered_commit_set_.Truncate(requested_commit_batch_size_);
+ ordered_commit_set_->Truncate(requested_commit_batch_size_);
}
void GetCommitIdsCommand::AddDeletes(const vector<int64>& unsynced_handles,
- syncable::WriteTransaction* write_transaction,
- const ModelSafeRoutingInfo& routing_info) {
+ syncable::WriteTransaction* write_transaction) {
set<syncable::Id> legal_delete_parents;
for (CommitMetahandleIterator iterator(unsynced_handles, write_transaction,
- &ordered_commit_set_);
+ ordered_commit_set_.get());
!IsCommitBatchFull() && iterator.Valid();
iterator.Increment()) {
int64 metahandle = iterator.Current();
@@ -194,9 +190,9 @@ void GetCommitIdsCommand::AddDeletes(const vector<int64>& unsynced_handles,
LOG(INFO) << "Inserting moved and deleted entry, will be missed by"
" delete roll." << entry.Get(syncable::ID);
- ordered_commit_set_.AddCommitItem(metahandle,
+ ordered_commit_set_->AddCommitItem(metahandle,
entry.Get(syncable::ID),
- GetGroupForEntry(&entry, routing_info));
+ entry.GetModelType());
}
// Skip this entry since it's a child of a parent that will be
@@ -224,7 +220,7 @@ void GetCommitIdsCommand::AddDeletes(const vector<int64>& unsynced_handles,
// parent was not deleted
for (CommitMetahandleIterator iterator(unsynced_handles, write_transaction,
- &ordered_commit_set_);
+ ordered_commit_set_.get());
!IsCommitBatchFull() && iterator.Valid();
iterator.Increment()) {
int64 metahandle = iterator.Current();
@@ -233,8 +229,8 @@ void GetCommitIdsCommand::AddDeletes(const vector<int64>& unsynced_handles,
if (entry.Get(syncable::IS_DEL)) {
syncable::Id parent_id = entry.Get(syncable::PARENT_ID);
if (legal_delete_parents.count(parent_id)) {
- ordered_commit_set_.AddCommitItem(metahandle, entry.Get(syncable::ID),
- GetGroupForEntry(&entry, routing_info));
+ ordered_commit_set_->AddCommitItem(metahandle, entry.Get(syncable::ID),
+ entry.GetModelType());
}
}
}
@@ -242,7 +238,8 @@ void GetCommitIdsCommand::AddDeletes(const vector<int64>& unsynced_handles,
void GetCommitIdsCommand::BuildCommitIds(const vector<int64>& unsynced_handles,
syncable::WriteTransaction* write_transaction,
- const ModelSafeRoutingInfo& routing_info) {
+ const ModelSafeRoutingInfo& routes) {
+ ordered_commit_set_.reset(new OrderedCommitSet(routes));
// Commits follow these rules:
// 1. Moves or creates are preceded by needed folder creates, from
// root to leaf. For folders whose contents are ordered, moves
@@ -253,10 +250,10 @@ void GetCommitIdsCommand::BuildCommitIds(const vector<int64>& unsynced_handles,
// delete trees.
// Add moves and creates, and prepend their uncommitted parents.
- AddCreatesAndMoves(unsynced_handles, write_transaction, routing_info);
+ AddCreatesAndMoves(unsynced_handles, write_transaction, routes);
// Add all deletes.
- AddDeletes(unsynced_handles, write_transaction, routing_info);
+ AddDeletes(unsynced_handles, write_transaction);
}
} // namespace browser_sync
diff --git a/chrome/browser/sync/engine/get_commit_ids_command.h b/chrome/browser/sync/engine/get_commit_ids_command.h
index 8ed0f92..40f8134 100644
--- a/chrome/browser/sync/engine/get_commit_ids_command.h
+++ b/chrome/browser/sync/engine/get_commit_ids_command.h
@@ -10,6 +10,7 @@
#include "chrome/browser/sync/engine/syncer_command.h"
#include "chrome/browser/sync/engine/syncer_util.h"
+#include "chrome/browser/sync/sessions/ordered_commit_set.h"
#include "chrome/browser/sync/sessions/sync_session.h"
#include "chrome/browser/sync/util/sync_types.h"
@@ -31,139 +32,7 @@ class GetCommitIdsCommand : public SyncerCommand {
// Builds a vector of IDs that should be committed.
void BuildCommitIds(const vector<int64>& unsynced_handles,
syncable::WriteTransaction* write_transaction,
- const ModelSafeRoutingInfo& routing_info);
-
- // These classes are public for testing.
- // TODO(ncarter): This code is more generic than just Commit and can
- // be reused elsewhere (e.g. ChangeReorderBuffer do similar things). Merge
- // all these implementations.
- // TODO(tim): Move this to its own file. Also, SyncSession should now
- // hold an OrderedCommitSet instead of just the vector<syncable::Id>. Will
- // do this in upcoming CL.
- class OrderedCommitSet {
- public:
- // A list of indices into the full list of commit ids such that:
- // 1 - each element is an index belonging to a particular ModelSafeGroup.
- // 2 - the vector is in sorted (smallest to largest) order.
- // 3 - each element is a valid index for GetCommitItemAt.
- // See GetCommitIdProjection for usage.
- typedef std::vector<size_t> Projection;
-
- // TODO(chron): Reserve space according to batch size?
- OrderedCommitSet() {}
- ~OrderedCommitSet() {}
-
- bool HaveCommitItem(const int64 metahandle) const {
- return inserted_metahandles_.count(metahandle) > 0;
- }
-
- void AddCommitItem(const int64 metahandle, const syncable::Id& commit_id,
- ModelSafeGroup group) {
- if (!HaveCommitItem(metahandle)) {
- inserted_metahandles_.insert(metahandle);
- metahandle_order_.push_back(metahandle);
- commit_ids_.push_back(commit_id);
- projections_[group].push_back(commit_ids_.size() - 1);
- groups_.push_back(group);
- }
- }
-
- const vector<syncable::Id>& GetAllCommitIds() const {
- return commit_ids_;
- }
-
- // Return the Id at index |position| in this OrderedCommitSet. Note that
- // the index uniquely identifies the same logical item in each of:
- // 1) this OrderedCommitSet
- // 2) the CommitRequest sent to the server
- // 3) the list of EntryResponse objects in the CommitResponse.
- // These together allow re-association of the pre-commit Id with the
- // actual committed entry.
- const syncable::Id& GetCommitIdAt(const size_t position) const {
- return commit_ids_[position];
- }
-
- // Get the projection of commit ids onto the space of commit ids
- // belonging to |group|. This is useful when you need to process a commit
- // response one ModelSafeGroup at a time. See GetCommitIdAt for how the
- // indices contained in the returned Projection can be used.
- const Projection& GetCommitIdProjection(ModelSafeGroup group) {
- return projections_[group];
- }
-
- int Size() const {
- return commit_ids_.size();
- }
-
- void AppendReverse(const OrderedCommitSet& other) {
- for (int i = other.Size() - 1; i >= 0; i--) {
- CommitItem item = other.GetCommitItemAt(i);
- AddCommitItem(item.meta, item.id, item.group);
- }
- }
-
- void Truncate(size_t max_size) {
- if (max_size < metahandle_order_.size()) {
- for (size_t i = max_size; i < metahandle_order_.size(); ++i) {
- inserted_metahandles_.erase(metahandle_order_[i]);
- }
-
- // Some projections may refer to indices that are getting chopped.
- // Since projections are in increasing order, it's easy to fix. Except
- // that you can't erase(..) using a reverse_iterator, so we use binary
- // search to find the chop point.
- Projections::iterator it = projections_.begin();
- for (; it != projections_.end(); ++it) {
- // For each projection, chop off any indices larger than or equal to
- // max_size by looking for max_size using binary search.
- Projection& p = it->second;
- Projection::iterator element = std::lower_bound(p.begin(), p.end(),
- max_size);
- if (element != p.end())
- p.erase(element, p.end());
- }
- commit_ids_.resize(max_size);
- metahandle_order_.resize(max_size);
- groups_.resize(max_size);
- }
- }
-
- private:
- // A set of CommitIdProjections associated with particular ModelSafeGroups.
- typedef std::map<ModelSafeGroup, Projection> Projections;
-
- // Helper container for return value of GetCommitItemAt.
- struct CommitItem {
- int64 meta;
- syncable::Id id;
- ModelSafeGroup group;
- };
-
- CommitItem GetCommitItemAt(const int position) const {
- DCHECK(position < Size());
- CommitItem return_item = {metahandle_order_[position],
- commit_ids_[position],
- groups_[position]};
- return return_item;
- }
-
- // These lists are different views of the same items; e.g they are
- // isomorphic.
- syncable::MetahandleSet inserted_metahandles_;
- vector<syncable::Id> commit_ids_;
- vector<int64> metahandle_order_;
- Projections projections_;
-
- // We need this because of operations like AppendReverse that take ids from
- // one OrderedCommitSet and insert into another -- we need to know the
- // group for each ID so that the insertion can update the appropriate
- // projection. We could store it in commit_ids_, but sometimes we want
- // to just return the vector of Ids, so this is more straightforward
- // and shouldn't take up too much extra space since commit lists are small.
- std::vector<ModelSafeGroup> groups_;
-
- DISALLOW_COPY_AND_ASSIGN(OrderedCommitSet);
- };
+ const ModelSafeRoutingInfo& routes);
// TODO(chron): Remove writes from this iterator. As a warning, this
// iterator causes writes to entries and so isn't a pure iterator.
@@ -174,7 +43,7 @@ class GetCommitIdsCommand : public SyncerCommand {
// UTF8 conversion and filename checking
CommitMetahandleIterator(const vector<int64>& unsynced_handles,
syncable::WriteTransaction* write_transaction,
- OrderedCommitSet* commit_set)
+ sessions::OrderedCommitSet* commit_set)
: write_transaction_(write_transaction),
handle_iterator_(unsynced_handles.begin()),
unsynced_handles_end_(unsynced_handles.end()),
@@ -232,7 +101,7 @@ class GetCommitIdsCommand : public SyncerCommand {
syncable::WriteTransaction* const write_transaction_;
vector<int64>::const_iterator handle_iterator_;
vector<int64>::const_iterator unsynced_handles_end_;
- OrderedCommitSet* commit_set_;
+ sessions::OrderedCommitSet* commit_set_;
DISALLOW_COPY_AND_ASSIGN(CommitMetahandleIterator);
};
@@ -241,34 +110,31 @@ class GetCommitIdsCommand : public SyncerCommand {
void AddUncommittedParentsAndTheirPredecessors(
syncable::BaseTransaction* trans,
syncable::Id parent_id,
- const ModelSafeRoutingInfo& routing_info);
+ const ModelSafeRoutingInfo& routes);
// OrderedCommitSet helpers for adding predecessors in order.
// TODO(ncarter): Refactor these so that the |result| parameter goes away,
// and AddItem doesn't need to consider two OrderedCommitSets.
- bool AddItem(syncable::Entry* item, OrderedCommitSet* result,
- const ModelSafeRoutingInfo& routing_info);
+ bool AddItem(syncable::Entry* item, sessions::OrderedCommitSet* result);
bool AddItemThenPredecessors(syncable::BaseTransaction* trans,
syncable::Entry* item,
syncable::IndexedBitField inclusion_filter,
- OrderedCommitSet* result,
- const ModelSafeRoutingInfo& routing_info);
+ sessions::OrderedCommitSet* result);
void AddPredecessorsThenItem(syncable::BaseTransaction* trans,
syncable::Entry* item,
syncable::IndexedBitField inclusion_filter,
- const ModelSafeRoutingInfo& routing_info);
+ const ModelSafeRoutingInfo& routes);
bool IsCommitBatchFull();
void AddCreatesAndMoves(const vector<int64>& unsynced_handles,
syncable::WriteTransaction* write_transaction,
- const ModelSafeRoutingInfo& routing_info);
+ const ModelSafeRoutingInfo& routes);
void AddDeletes(const vector<int64>& unsynced_handles,
- syncable::WriteTransaction* write_transaction,
- const ModelSafeRoutingInfo& routing_info);
+ syncable::WriteTransaction* write_transaction);
- OrderedCommitSet ordered_commit_set_;
+ scoped_ptr<sessions::OrderedCommitSet> ordered_commit_set_;
int requested_commit_batch_size_;
diff --git a/chrome/browser/sync/engine/mock_model_safe_workers.h b/chrome/browser/sync/engine/mock_model_safe_workers.h
new file mode 100644
index 0000000..e776596
--- /dev/null
+++ b/chrome/browser/sync/engine/mock_model_safe_workers.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SYNC_ENGINE_MOCK_MODEL_SAFE_WORKERS_H_
+#define CHROME_BROWSER_SYNC_ENGINE_MOCK_MODEL_SAFE_WORKERS_H_
+
+#include "chrome/browser/sync/engine/model_safe_worker.h"
+
+namespace browser_sync {
+
+class MockUIModelWorker : public ModelSafeWorker {
+ public:
+ virtual ModelSafeGroup GetModelSafeGroup() { return GROUP_UI; }
+};
+
+class MockDBModelWorker : public ModelSafeWorker {
+ public:
+ virtual ModelSafeGroup GetModelSafeGroup() { return GROUP_DB; }
+};
+
+} // namespace browser_sync
+
+#endif // CHROME_BROWSER_SYNC_ENGINE_MOCK_MODEL_SAFE_WORKERS_H_
+
diff --git a/chrome/browser/sync/engine/model_changing_syncer_command.cc b/chrome/browser/sync/engine/model_changing_syncer_command.cc
index f531a70..e6d34a2 100644
--- a/chrome/browser/sync/engine/model_changing_syncer_command.cc
+++ b/chrome/browser/sync/engine/model_changing_syncer_command.cc
@@ -12,6 +12,8 @@ namespace browser_sync {
void ModelChangingSyncerCommand::ExecuteImpl(sessions::SyncSession* session) {
work_session_ = session;
+ ModelNeutralExecuteImpl(work_session_);
+
for (size_t i = 0; i < session->workers().size(); ++i) {
ModelSafeWorker* worker = session->workers()[i];
ModelSafeGroup group = worker->GetModelSafeGroup();
diff --git a/chrome/browser/sync/engine/model_changing_syncer_command.h b/chrome/browser/sync/engine/model_changing_syncer_command.h
index b2ebee1..eb8003a 100644
--- a/chrome/browser/sync/engine/model_changing_syncer_command.h
+++ b/chrome/browser/sync/engine/model_changing_syncer_command.h
@@ -35,7 +35,16 @@ class ModelChangingSyncerCommand : public SyncerCommand {
ModelChangingExecuteImpl(work_session_);
}
- // Abstract method to be implemented by subclasses.
+ // Sometimes, a command has work to do that needs to touch global state
+ // belonging to multiple ModelSafeGroups, but in a way that is known to be
+ // safe. This will be called once, prior to ModelChangingExecuteImpl,
+ // *without* a ModelSafeGroup restriction in place on the SyncSession.
+ virtual void ModelNeutralExecuteImpl(sessions::SyncSession* session) {}
+
+ // Abstract method to be implemented by subclasses to handle logic that
+ // operates on the model. This is invoked with a SyncSession ModelSafeGroup
+ // restriction in place so that bits of state belonging to data types
+ // running on an unsafe thread are siloed away.
virtual void ModelChangingExecuteImpl(sessions::SyncSession* session) = 0;
private:
diff --git a/chrome/browser/sync/engine/model_safe_worker.cc b/chrome/browser/sync/engine/model_safe_worker.cc
index 9c71fd3..3d42164 100644
--- a/chrome/browser/sync/engine/model_safe_worker.cc
+++ b/chrome/browser/sync/engine/model_safe_worker.cc
@@ -3,13 +3,12 @@
// found in the LICENSE file.
#include "chrome/browser/sync/engine/model_safe_worker.h"
-#include "chrome/browser/sync/syncable/syncable.h"
namespace browser_sync {
-ModelSafeGroup GetGroupForEntry(const syncable::Entry* e,
- const ModelSafeRoutingInfo& routes) {
- ModelSafeRoutingInfo::const_iterator it = routes.find(e->GetModelType());
+ModelSafeGroup GetGroupForModelType(const syncable::ModelType type,
+ const ModelSafeRoutingInfo& routes) {
+ ModelSafeRoutingInfo::const_iterator it = routes.find(type);
if (it == routes.end()) {
NOTREACHED() << "Entry does not belong to active ModelSafeGroup!";
return GROUP_PASSIVE;
diff --git a/chrome/browser/sync/engine/model_safe_worker.h b/chrome/browser/sync/engine/model_safe_worker.h
index e6552db..5e5b70d 100644
--- a/chrome/browser/sync/engine/model_safe_worker.h
+++ b/chrome/browser/sync/engine/model_safe_worker.h
@@ -13,10 +13,6 @@
#include "chrome/browser/sync/util/closure.h"
#include "chrome/browser/sync/util/sync_types.h"
-namespace syncable {
-class Entry;
-}
-
namespace browser_sync {
enum ModelSafeGroup {
@@ -63,8 +59,8 @@ class ModelSafeWorker : public base::RefCountedThreadSafe<ModelSafeWorker> {
typedef std::map<syncable::ModelType, ModelSafeGroup>
ModelSafeRoutingInfo;
-ModelSafeGroup GetGroupForEntry(const syncable::Entry* e,
- const ModelSafeRoutingInfo& routes);
+ModelSafeGroup GetGroupForModelType(const syncable::ModelType type,
+ const ModelSafeRoutingInfo& routes);
// Maintain the up-to-date state regarding which ModelSafeWorkers exist and
// which types get routed to which worker. When a sync session begins, it will
diff --git a/chrome/browser/sync/engine/post_commit_message_command.cc b/chrome/browser/sync/engine/post_commit_message_command.cc
index 9136df7..c0a7c98 100644
--- a/chrome/browser/sync/engine/post_commit_message_command.cc
+++ b/chrome/browser/sync/engine/post_commit_message_command.cc
@@ -34,7 +34,6 @@ void PostCommitMessageCommand::ExecuteImpl(sessions::SyncSession* session) {
// set to true during BuildCommitCommand, and which may still be true.
// Not to be confused with IS_UNSYNCED. This bit is used to detect local
// changes to items that happen during the server Commit operation.
- status->increment_num_consecutive_problem_commits();
status->increment_num_consecutive_errors();
syncable::WriteTransaction trans(dir, syncable::SYNCER, __FILE__, __LINE__);
const vector<syncable::Id>& commit_ids = status->commit_ids();
diff --git a/chrome/browser/sync/engine/process_commit_response_command.cc b/chrome/browser/sync/engine/process_commit_response_command.cc
index 19cd9bd..33b188e 100755
--- a/chrome/browser/sync/engine/process_commit_response_command.cc
+++ b/chrome/browser/sync/engine/process_commit_response_command.cc
@@ -40,34 +40,23 @@ using syncable::SYNCING;
namespace browser_sync {
+using sessions::OrderedCommitSet;
using sessions::StatusController;
using sessions::SyncSession;
using sessions::ConflictProgress;
void IncrementErrorCounters(StatusController* status) {
- status->increment_num_consecutive_problem_commits();
status->increment_num_consecutive_errors();
}
void ResetErrorCounters(StatusController* status) {
- status->set_num_consecutive_problem_commits(0);
status->set_num_consecutive_errors(0);
}
ProcessCommitResponseCommand::ProcessCommitResponseCommand() {}
ProcessCommitResponseCommand::~ProcessCommitResponseCommand() {}
-void ProcessCommitResponseCommand::ModelChangingExecuteImpl(
- SyncSession* session) {
- ProcessCommitResponse(session);
- ExtensionsActivityMonitor* monitor = session->context()->extensions_monitor();
- if (session->status_controller()->syncer_status().num_successful_commits == 0)
- monitor->PutRecords(session->extensions_activity());
-}
-
-void ProcessCommitResponseCommand::ProcessCommitResponse(
- SyncSession* session) {
- // TODO(sync): This function returns if it sees problems. We probably want
- // to flag the need for an update or similar.
+void ProcessCommitResponseCommand::ModelNeutralExecuteImpl(
+ sessions::SyncSession* session) {
ScopedDirLookup dir(session->context()->directory_manager(),
session->context()->account_name());
if (!dir.good()) {
@@ -100,6 +89,33 @@ void ProcessCommitResponseCommand::ProcessCommitResponse(
IncrementErrorCounters(status);
return;
}
+}
+
+void ProcessCommitResponseCommand::ModelChangingExecuteImpl(
+ SyncSession* session) {
+ ProcessCommitResponse(session);
+ ExtensionsActivityMonitor* monitor = session->context()->extensions_monitor();
+ if (session->status_controller()->HasBookmarkCommitActivity() &&
+ session->status_controller()->syncer_status()
+ .num_successful_bookmark_commits == 0) {
+ monitor->PutRecords(session->extensions_activity());
+ }
+}
+
+void ProcessCommitResponseCommand::ProcessCommitResponse(
+ SyncSession* session) {
+ // TODO(sync): This function returns if it sees problems. We probably want
+ // to flag the need for an update or similar.
+ ScopedDirLookup dir(session->context()->directory_manager(),
+ session->context()->account_name());
+ if (!dir.good()) {
+ LOG(ERROR) << "Scoped dir lookup failed!";
+ return;
+ }
+
+ StatusController* status = session->status_controller();
+ const ClientToServerResponse& response(status->commit_response());
+ const CommitResponse& cr = response.commit();
// If we try to commit a parent and child together and the parent conflicts
// the child will have a bad parent causing an error. As this is not a
@@ -113,12 +129,13 @@ void ProcessCommitResponseCommand::ProcessCommitResponse(
set<syncable::Id> conflicting_new_folder_ids;
set<syncable::Id> deleted_folders;
ConflictProgress* conflict_progress = status->mutable_conflict_progress();
+ OrderedCommitSet::Projection proj = status->commit_id_projection();
{ // Scope for WriteTransaction.
WriteTransaction trans(dir, SYNCER, __FILE__, __LINE__);
- for (int i = 0; i < cr.entryresponse_size(); i++) {
+ for (size_t i = 0; i < proj.size(); i++) {
CommitResponse::ResponseType response_type =
- ProcessSingleCommitResponse(&trans, cr.entryresponse(i),
- commit_ids[i],
+ ProcessSingleCommitResponse(&trans, cr.entryresponse(proj[i]),
+ status->GetCommitIdAt(proj[i]),
&conflicting_new_folder_ids,
&deleted_folders);
switch (response_type) {
@@ -128,11 +145,14 @@ void ProcessCommitResponseCommand::ProcessCommitResponse(
case CommitResponse::CONFLICT:
++conflicting_commits;
// Only server CONFLICT responses will activate conflict resolution.
- conflict_progress->AddConflictingItemById(commit_ids[i]);
+ conflict_progress->AddConflictingItemById(
+ status->GetCommitIdAt(proj[i]));
break;
case CommitResponse::SUCCESS:
// TODO(sync): worry about sync_rate_ rate calc?
++successes;
+ if (status->GetCommitIdModelTypeAt(proj[i]) == syncable::BOOKMARKS)
+ status->increment_num_successful_bookmark_commits();
status->increment_num_successful_commits();
break;
case CommitResponse::OVER_QUOTA:
@@ -153,7 +173,7 @@ void ProcessCommitResponseCommand::ProcessCommitResponse(
}
// TODO(sync): move status reporting elsewhere.
- status->set_num_conflicting_commits(conflicting_commits);
+ status->increment_num_conflicting_commits_by(conflicting_commits);
if (0 == successes) {
status->increment_num_consecutive_transient_error_commits_by(
transient_error_commits);
@@ -162,6 +182,7 @@ void ProcessCommitResponseCommand::ProcessCommitResponse(
status->set_num_consecutive_transient_error_commits(0);
status->set_num_consecutive_errors(0);
}
+ int commit_count = static_cast<int>(proj.size());
if (commit_count != (conflicting_commits + error_commits +
transient_error_commits)) {
ResetErrorCounters(status);
diff --git a/chrome/browser/sync/engine/process_commit_response_command.h b/chrome/browser/sync/engine/process_commit_response_command.h
index b1ba659..e83d075 100644
--- a/chrome/browser/sync/engine/process_commit_response_command.h
+++ b/chrome/browser/sync/engine/process_commit_response_command.h
@@ -26,6 +26,7 @@ class ProcessCommitResponseCommand : public ModelChangingSyncerCommand {
virtual ~ProcessCommitResponseCommand();
// ModelChangingSyncerCommand implementation.
+ virtual void ModelNeutralExecuteImpl(sessions::SyncSession* session);
virtual void ModelChangingExecuteImpl(sessions::SyncSession* session);
private:
diff --git a/chrome/browser/sync/engine/process_commit_response_command_unittest.cc b/chrome/browser/sync/engine/process_commit_response_command_unittest.cc
index c8b5d14..70c6732 100755
--- a/chrome/browser/sync/engine/process_commit_response_command_unittest.cc
+++ b/chrome/browser/sync/engine/process_commit_response_command_unittest.cc
@@ -5,6 +5,7 @@
#include <vector>
#include "base/string_util.h"
+#include "chrome/browser/sync/engine/mock_model_safe_workers.h"
#include "chrome/browser/sync/engine/process_commit_response_command.h"
#include "chrome/browser/sync/protocol/bookmark_specifics.pb.h"
#include "chrome/browser/sync/protocol/sync.pb.h"
@@ -35,6 +36,20 @@ using syncable::WriteTransaction;
// A test fixture for tests exercising ProcessCommitResponseCommand.
class ProcessCommitResponseCommandTest : public SyncerCommandTest {
public:
+ virtual void SetUp() {
+ workers()->clear();
+ mutable_routing_info()->clear();
+
+ workers()->push_back(new ModelSafeWorker()); // GROUP_PASSIVE worker.
+ workers()->push_back(new MockUIModelWorker()); // GROUP_UI worker.
+ (*mutable_routing_info())[syncable::BOOKMARKS] = GROUP_UI;
+ (*mutable_routing_info())[syncable::PREFERENCES] = GROUP_UI;
+ (*mutable_routing_info())[syncable::AUTOFILL] = GROUP_PASSIVE;
+
+ commit_set_.reset(new sessions::OrderedCommitSet(routing_info()));
+ SyncerCommandTest::SetUp();
+ }
+
protected:
ProcessCommitResponseCommandTest()
: next_old_revision_(1),
@@ -42,13 +57,26 @@ class ProcessCommitResponseCommandTest : public SyncerCommandTest {
next_server_position_(10000) {
}
+ void CheckEntry(Entry* e, const std::string& name,
+ syncable::ModelType model_type, const Id& parent_id) {
+ EXPECT_TRUE(e->good());
+ ASSERT_EQ(name, e->Get(NON_UNIQUE_NAME));
+ ASSERT_EQ(model_type, e->GetModelType());
+ ASSERT_EQ(parent_id, e->Get(syncable::PARENT_ID));
+ ASSERT_LT(0, e->Get(BASE_VERSION))
+ << "Item should have a valid (positive) server base revision";
+ }
+
// Create an unsynced item in the database. If item_id is a local ID, it
// will be treated as a create-new. Otherwise, if it's a server ID, we'll
// fake the server data so that it looks like it exists on the server.
+ // Returns the methandle of the created item in |metahandle_out| if not NULL.
void CreateUnsyncedItem(const Id& item_id,
const Id& parent_id,
const string& name,
- bool is_folder) {
+ bool is_folder,
+ syncable::ModelType model_type,
+ int64* metahandle_out) {
ScopedDirLookup dir(syncdb().manager(), syncdb().name());
ASSERT_TRUE(dir.good());
WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
@@ -63,15 +91,17 @@ class ProcessCommitResponseCommandTest : public SyncerCommandTest {
entry.Put(syncable::IS_DEL, false);
entry.Put(syncable::PARENT_ID, parent_id);
entry.PutPredecessor(predecessor_id);
- sync_pb::EntitySpecifics default_bookmark_specifics;
- default_bookmark_specifics.MutableExtension(sync_pb::bookmark);
- entry.Put(syncable::SPECIFICS, default_bookmark_specifics);
+ sync_pb::EntitySpecifics default_specifics;
+ syncable::AddDefaultExtensionValue(model_type, &default_specifics);
+ entry.Put(syncable::SPECIFICS, default_specifics);
if (item_id.ServerKnows()) {
- entry.Put(syncable::SERVER_SPECIFICS, default_bookmark_specifics);
+ entry.Put(syncable::SERVER_SPECIFICS, default_specifics);
entry.Put(syncable::SERVER_IS_DIR, is_folder);
entry.Put(syncable::SERVER_PARENT_ID, parent_id);
entry.Put(syncable::SERVER_IS_DEL, false);
}
+ if (metahandle_out)
+ *metahandle_out = entry.Get(syncable::META_HANDLE);
}
// Create a new unsynced item in the database, and synthesize a commit
@@ -80,16 +110,18 @@ class ProcessCommitResponseCommandTest : public SyncerCommandTest {
// will be an edit.
void CreateUnprocessedCommitResult(const Id& item_id,
const Id& parent_id,
- const string& name) {
+ const string& name,
+ syncable::ModelType model_type) {
sessions::StatusController* sync_state = session()->status_controller();
bool is_folder = true;
- CreateUnsyncedItem(item_id, parent_id, name, is_folder);
+ int64 metahandle = 0;
+ CreateUnsyncedItem(item_id, parent_id, name, is_folder, model_type,
+ &metahandle);
// ProcessCommitResponseCommand consumes commit_ids from the session
// state, so we need to update that. O(n^2) because it's a test.
- std::vector<Id> commit_ids = sync_state->commit_ids();
- commit_ids.push_back(item_id);
- sync_state->set_commit_ids(commit_ids);
+ commit_set_->AddCommitItem(metahandle, item_id, model_type);
+ sync_state->set_commit_set(*commit_set_.get());
ScopedDirLookup dir(syncdb().manager(), syncdb().name());
ASSERT_TRUE(dir.good());
@@ -142,7 +174,7 @@ class ProcessCommitResponseCommandTest : public SyncerCommandTest {
ProcessCommitResponseCommand command_;
TestIdFactory id_factory_;
-
+ scoped_ptr<sessions::OrderedCommitSet> commit_set_;
private:
int64 next_old_revision_;
int64 next_new_revision_;
@@ -150,6 +182,66 @@ class ProcessCommitResponseCommandTest : public SyncerCommandTest {
DISALLOW_COPY_AND_ASSIGN(ProcessCommitResponseCommandTest);
};
+TEST_F(ProcessCommitResponseCommandTest, MultipleCommitIdProjections) {
+ Id bookmark_folder_id = id_factory_.NewLocalId();
+ Id bookmark_id1 = id_factory_.NewLocalId();
+ Id bookmark_id2 = id_factory_.NewLocalId();
+ Id pref_id1 = id_factory_.NewLocalId(), pref_id2 = id_factory_.NewLocalId();
+ Id autofill_id1 = id_factory_.NewLocalId();
+ Id autofill_id2 = id_factory_.NewLocalId();
+ CreateUnprocessedCommitResult(bookmark_folder_id, id_factory_.root(),
+ "A bookmark folder", syncable::BOOKMARKS);
+ CreateUnprocessedCommitResult(bookmark_id1, bookmark_folder_id,
+ "bookmark 1", syncable::BOOKMARKS);
+ CreateUnprocessedCommitResult(bookmark_id2, bookmark_folder_id,
+ "bookmark 2", syncable::BOOKMARKS);
+ CreateUnprocessedCommitResult(pref_id1, id_factory_.root(),
+ "Pref 1", syncable::PREFERENCES);
+ CreateUnprocessedCommitResult(pref_id2, id_factory_.root(),
+ "Pref 2", syncable::PREFERENCES);
+ CreateUnprocessedCommitResult(autofill_id1, id_factory_.root(),
+ "Autofill 1", syncable::AUTOFILL);
+ CreateUnprocessedCommitResult(autofill_id2, id_factory_.root(),
+ "Autofill 2", syncable::AUTOFILL);
+
+ command_.ExecuteImpl(session());
+
+ ScopedDirLookup dir(syncdb().manager(), syncdb().name());
+ ASSERT_TRUE(dir.good());
+ ReadTransaction trans(dir, __FILE__, __LINE__);
+ Id new_fid = dir->GetFirstChildId(&trans, id_factory_.root());
+ ASSERT_FALSE(new_fid.IsRoot());
+ EXPECT_TRUE(new_fid.ServerKnows());
+ EXPECT_FALSE(bookmark_folder_id.ServerKnows());
+ EXPECT_FALSE(new_fid == bookmark_folder_id);
+ Entry b_folder(&trans, syncable::GET_BY_ID, new_fid);
+ ASSERT_TRUE(b_folder.good());
+ ASSERT_EQ("A bookmark folder", b_folder.Get(NON_UNIQUE_NAME))
+ << "Name of bookmark folder should not change.";
+ ASSERT_LT(0, b_folder.Get(BASE_VERSION))
+ << "Bookmark folder should have a valid (positive) server base revision";
+
+ // Look at the two bookmarks in bookmark_folder.
+ Id cid = dir->GetFirstChildId(&trans, new_fid);
+ Entry b1(&trans, syncable::GET_BY_ID, cid);
+ Entry b2(&trans, syncable::GET_BY_ID, b1.Get(syncable::NEXT_ID));
+ CheckEntry(&b1, "bookmark 1", syncable::BOOKMARKS, new_fid);
+ CheckEntry(&b2, "bookmark 2", syncable::BOOKMARKS, new_fid);
+ ASSERT_TRUE(b2.Get(syncable::NEXT_ID).IsRoot());
+
+ // Look at the prefs and autofill items.
+ Entry p1(&trans, syncable::GET_BY_ID, b_folder.Get(syncable::NEXT_ID));
+ Entry p2(&trans, syncable::GET_BY_ID, p1.Get(syncable::NEXT_ID));
+ CheckEntry(&p1, "Pref 1", syncable::PREFERENCES, id_factory_.root());
+ CheckEntry(&p2, "Pref 2", syncable::PREFERENCES, id_factory_.root());
+
+ Entry a1(&trans, syncable::GET_BY_ID, p2.Get(syncable::NEXT_ID));
+ Entry a2(&trans, syncable::GET_BY_ID, a1.Get(syncable::NEXT_ID));
+ CheckEntry(&a1, "Autofill 1", syncable::AUTOFILL, id_factory_.root());
+ CheckEntry(&a2, "Autofill 2", syncable::AUTOFILL, id_factory_.root());
+ ASSERT_TRUE(a2.Get(syncable::NEXT_ID).IsRoot());
+}
+
// In this test, we test processing a commit response for a commit batch that
// includes a newly created folder and some (but not all) of its children.
// In particular, the folder has 50 children, which alternate between being
@@ -163,7 +255,8 @@ class ProcessCommitResponseCommandTest : public SyncerCommandTest {
TEST_F(ProcessCommitResponseCommandTest, NewFolderCommitKeepsChildOrder) {
// Create the parent folder, a new item whose ID will change on commit.
Id folder_id = id_factory_.NewLocalId();
- CreateUnprocessedCommitResult(folder_id, id_factory_.root(), "A");
+ CreateUnprocessedCommitResult(folder_id, id_factory_.root(), "A",
+ syncable::BOOKMARKS);
// Verify that the item is reachable.
{
@@ -180,7 +273,8 @@ TEST_F(ProcessCommitResponseCommandTest, NewFolderCommitKeepsChildOrder) {
for (; i < batch_size; ++i) {
// Alternate between new and old child items, just for kicks.
Id id = (i % 4 < 2) ? id_factory_.NewLocalId() : id_factory_.NewServerId();
- CreateUnprocessedCommitResult(id, folder_id, StringPrintf("Item %d", i));
+ CreateUnprocessedCommitResult(id, folder_id, StringPrintf("Item %d", i),
+ syncable::BOOKMARKS);
}
// The second 25 children will be unsynced items but NOT part of the commit
// batch. When the ID of the parent folder changes during the commit,
@@ -189,14 +283,15 @@ TEST_F(ProcessCommitResponseCommandTest, NewFolderCommitKeepsChildOrder) {
for (; i < 2*batch_size; ++i) {
// Alternate between new and old child items, just for kicks.
Id id = (i % 4 < 2) ? id_factory_.NewLocalId() : id_factory_.NewServerId();
- CreateUnsyncedItem(id, folder_id, StringPrintf("Item %d", i), false);
+ CreateUnsyncedItem(id, folder_id, StringPrintf("Item %d", i), false,
+ syncable::BOOKMARKS, NULL);
}
// Process the commit response for the parent folder and the first
// 25 items. This should apply the values indicated by
// each CommitResponse_EntryResponse to the syncable Entries. All new
// items in the commit batch should have their IDs changed to server IDs.
- command_.ModelChangingExecuteImpl(session());
+ command_.ExecuteImpl(session());
ScopedDirLookup dir(syncdb().manager(), syncdb().name());
ASSERT_TRUE(dir.good());
diff --git a/chrome/browser/sync/engine/process_updates_command.cc b/chrome/browser/sync/engine/process_updates_command.cc
index a54481f..f17a05d 100755
--- a/chrome/browser/sync/engine/process_updates_command.cc
+++ b/chrome/browser/sync/engine/process_updates_command.cc
@@ -107,7 +107,6 @@ void ProcessUpdatesCommand::ModelChangingExecuteImpl(SyncSession* session) {
status->set_timestamp_dirty(true);
}
- status->set_num_consecutive_problem_get_updates(0);
status->set_num_consecutive_errors(0);
status->set_current_sync_timestamp(dir->last_sync_timestamp());
status->set_syncing(true);
diff --git a/chrome/browser/sync/engine/syncer.cc b/chrome/browser/sync/engine/syncer.cc
index 8316390..9170a46 100755
--- a/chrome/browser/sync/engine/syncer.cc
+++ b/chrome/browser/sync/engine/syncer.cc
@@ -81,7 +81,6 @@ bool Syncer::SyncShare(sessions::SyncSession::Delegate* delegate) {
}
bool Syncer::SyncShare(sessions::SyncSession* session) {
- session->status_controller()->ResetTransientState();
session->set_source(TestAndSetUpdatesSource());
// This isn't perfect, as we can end up bundling extensions activity
// intended for the next session into the current one. We could do a
@@ -197,6 +196,7 @@ void Syncer::SyncShare(sessions::SyncSession* session,
}
case PROCESS_COMMIT_RESPONSE: {
LOG(INFO) << "Processing the commit response";
+ session->status_controller()->reset_num_conflicting_commits();
ProcessCommitResponseCommand process_response_command;
process_response_command.Execute(session);
next_step = BUILD_AND_PROCESS_CONFLICT_SETS;
diff --git a/chrome/browser/sync/engine/syncer_unittest.cc b/chrome/browser/sync/engine/syncer_unittest.cc
index 5c9bea9..7805dae 100755
--- a/chrome/browser/sync/engine/syncer_unittest.cc
+++ b/chrome/browser/sync/engine/syncer_unittest.cc
@@ -345,31 +345,30 @@ class SyncerTest : public testing::Test,
// The expected order is "x", "b", "c", "e", truncated appropriately.
for (size_t limit = expected_id_order.size() + 2; limit > 0; --limit) {
StatusController* status = session_->status_controller();
- status->ResetTransientState();
WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
ScopedSetSessionWriteTransaction set_trans(session_.get(), &wtrans);
status->set_unsynced_handles(unsynced_handle_view);
- GetCommitIdsCommand command(limit);
ModelSafeRoutingInfo routes;
GetModelSafeRoutingInfo(&routes);
+ GetCommitIdsCommand command(limit);
command.BuildCommitIds(session_->status_controller()->unsynced_handles(),
session_->write_transaction(), routes);
vector<syncable::Id> output =
- command.ordered_commit_set_.GetAllCommitIds();
+ command.ordered_commit_set_->GetAllCommitIds();
size_t truncated_size = std::min(limit, expected_id_order.size());
ASSERT_TRUE(truncated_size == output.size());
for (size_t i = 0; i < truncated_size; ++i) {
ASSERT_TRUE(expected_id_order[i] == output[i])
<< "At index " << i << " with batch size limited to " << limit;
}
- GetCommitIdsCommand::OrderedCommitSet::Projection proj;
- proj = command.ordered_commit_set_.GetCommitIdProjection(GROUP_PASSIVE);
+ sessions::OrderedCommitSet::Projection proj;
+ proj = command.ordered_commit_set_->GetCommitIdProjection(GROUP_PASSIVE);
ASSERT_EQ(truncated_size, proj.size());
for (size_t i = 0; i < truncated_size; ++i) {
SCOPED_TRACE(::testing::Message("Projection mismatch with i = ") << i);
syncable::Id projected =
- command.ordered_commit_set_.GetCommitIdAt(proj[i]);
+ command.ordered_commit_set_->GetCommitIdAt(proj[i]);
ASSERT_TRUE(expected_id_order[proj[i]] == projected);
// Since this projection is the identity, the following holds.
ASSERT_TRUE(expected_id_order[i] == projected);
@@ -503,7 +502,7 @@ TEST_F(SyncerTest, TestCommitMetahandleIterator) {
WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
ScopedSetSessionWriteTransaction set_trans(session_.get(), &wtrans);
- GetCommitIdsCommand::OrderedCommitSet commit_set;
+ sessions::OrderedCommitSet commit_set(session_->routing_info());
GetCommitIdsCommand::CommitMetahandleIterator iterator(unsynced, &wtrans,
&commit_set);
EXPECT_FALSE(iterator.Valid());
@@ -519,7 +518,7 @@ TEST_F(SyncerTest, TestCommitMetahandleIterator) {
WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
ScopedSetSessionWriteTransaction set_trans(session_.get(), &wtrans);
- GetCommitIdsCommand::OrderedCommitSet commit_set;
+ sessions::OrderedCommitSet commit_set(session_->routing_info());
GetCommitIdsCommand::CommitMetahandleIterator iterator(unsynced, &wtrans,
&commit_set);
@@ -539,75 +538,6 @@ TEST_F(SyncerTest, TestCommitMetahandleIterator) {
}
}
-TEST_F(SyncerTest, OrderedCommitSetProjections) {
- vector<syncable::Id> expected;
- for (int i = 0; i < 8; i++)
- expected.push_back(ids_.NewLocalId());
-
- GetCommitIdsCommand::OrderedCommitSet commit_set1, commit_set2;
- commit_set1.AddCommitItem(0, expected[0], GROUP_UI);
- commit_set1.AddCommitItem(1, expected[1], GROUP_UI);
- commit_set1.AddCommitItem(2, expected[2], GROUP_UI);
- commit_set1.AddCommitItem(3, expected[3], GROUP_PASSIVE);
- commit_set1.AddCommitItem(4, expected[4], GROUP_PASSIVE);
- commit_set2.AddCommitItem(7, expected[7], GROUP_DB);
- commit_set2.AddCommitItem(6, expected[6], GROUP_DB);
- commit_set2.AddCommitItem(5, expected[5], GROUP_DB);
- commit_set1.AppendReverse(commit_set2);
-
- // First, we should verify the projections are correct. Second, we want to
- // do the same verification after truncating by 1. Next, try truncating
- // the set to a size of 4, so that the DB projection is wiped out and
- // PASSIVE has one element removed. Finally, truncate to 1 so only UI is
- // remaining.
- int j = 0;
- do {
- SCOPED_TRACE(::testing::Message("Iteration j = ") << j);
- vector<syncable::Id> all_ids = commit_set1.GetAllCommitIds();
- EXPECT_EQ(expected.size(), all_ids.size());
- for (size_t i = 0; i < expected.size(); i++) {
- SCOPED_TRACE(::testing::Message("CommitSet mismatch at iteration i = ")
- << i);
- EXPECT_TRUE(expected[i] == all_ids[i]);
- EXPECT_TRUE(expected[i] == commit_set1.GetCommitIdAt(i));
- }
-
- GetCommitIdsCommand::OrderedCommitSet::Projection p1, p2, p3;
- p1 = commit_set1.GetCommitIdProjection(GROUP_UI);
- p2 = commit_set1.GetCommitIdProjection(GROUP_PASSIVE);
- p3 = commit_set1.GetCommitIdProjection(GROUP_DB);
- EXPECT_TRUE(p1.size() + p2.size() + p3.size() == expected.size()) << "Sum"
- << "of sizes of projections should equal full expected size!";
-
- for (size_t i = 0; i < p1.size(); i++) {
- SCOPED_TRACE(::testing::Message("UI projection mismatch at i = ") << i);
- EXPECT_TRUE(expected[p1[i]] == commit_set1.GetCommitIdAt(p1[i]))
- << "expected[p1[i]] = " << expected[p1[i]]
- << ", commit_set1[p1[i]] = " << commit_set1.GetCommitIdAt(p1[i]);
- }
- for (size_t i = 0; i < p2.size(); i++) {
- SCOPED_TRACE(::testing::Message("PASSIVE projection mismatch at i = ")
- << i);
- EXPECT_TRUE(expected[p2[i]] == commit_set1.GetCommitIdAt(p2[i]))
- << "expected[p2[i]] = " << expected[p2[i]]
- << ", commit_set1[p2[i]] = " << commit_set1.GetCommitIdAt(p2[i]);
- }
- for (size_t i = 0; i < p3.size(); i++) {
- SCOPED_TRACE(::testing::Message("DB projection mismatch at i = ") << i);
- EXPECT_TRUE(expected[p3[i]] == commit_set1.GetCommitIdAt(p3[i]))
- << "expected[p3[i]] = " << expected[p3[i]]
- << ", commit_set1[p3[i]] = " << commit_set1.GetCommitIdAt(p3[i]);
- }
-
- int cut_to_size = 7 - 3 * j++;
- if (cut_to_size < 0)
- break;
-
- expected.resize(cut_to_size);
- commit_set1.Truncate(cut_to_size);
- } while (true);
-}
-
TEST_F(SyncerTest, TestGetUnsyncedAndSimpleCommit) {
ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
ASSERT_TRUE(dir.good());
diff --git a/chrome/browser/sync/sessions/ordered_commit_set.cc b/chrome/browser/sync/sessions/ordered_commit_set.cc
new file mode 100644
index 0000000..5c46a35
--- /dev/null
+++ b/chrome/browser/sync/sessions/ordered_commit_set.cc
@@ -0,0 +1,94 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sync/sessions/ordered_commit_set.h"
+
+#include "base/logging.h"
+
+namespace browser_sync {
+namespace sessions {
+
+void OrderedCommitSet::AddCommitItem(const int64 metahandle,
+ const syncable::Id& commit_id,
+ syncable::ModelType type) {
+ if (!HaveCommitItem(metahandle)) {
+ inserted_metahandles_.insert(metahandle);
+ metahandle_order_.push_back(metahandle);
+ commit_ids_.push_back(commit_id);
+ projections_[GetGroupForModelType(type, routes_)].push_back(
+ commit_ids_.size() - 1);
+ types_.push_back(type);
+ }
+}
+
+void OrderedCommitSet::AppendReverse(const OrderedCommitSet& other) {
+ for (int i = other.Size() - 1; i >= 0; i--) {
+ CommitItem item = other.GetCommitItemAt(i);
+ AddCommitItem(item.meta, item.id, item.group);
+ }
+}
+
+void OrderedCommitSet::Truncate(size_t max_size) {
+ if (max_size < metahandle_order_.size()) {
+ for (size_t i = max_size; i < metahandle_order_.size(); ++i) {
+ inserted_metahandles_.erase(metahandle_order_[i]);
+ }
+
+ // Some projections may refer to indices that are getting chopped.
+ // Since projections are in increasing order, it's easy to fix. Except
+ // that you can't erase(..) using a reverse_iterator, so we use binary
+ // search to find the chop point.
+ Projections::iterator it = projections_.begin();
+ for (; it != projections_.end(); ++it) {
+ // For each projection, chop off any indices larger than or equal to
+ // max_size by looking for max_size using binary search.
+ Projection& p = it->second;
+ Projection::iterator element = std::lower_bound(p.begin(), p.end(),
+ max_size);
+ if (element != p.end())
+ p.erase(element, p.end());
+ }
+ commit_ids_.resize(max_size);
+ metahandle_order_.resize(max_size);
+ types_.resize(max_size);
+ }
+}
+
+OrderedCommitSet::CommitItem OrderedCommitSet::GetCommitItemAt(
+ const int position) const {
+ DCHECK(position < Size());
+ CommitItem return_item = {metahandle_order_[position],
+ commit_ids_[position],
+ types_[position]};
+ return return_item;
+}
+
+bool OrderedCommitSet::HasBookmarkCommitId() const {
+ ModelSafeRoutingInfo::const_iterator group
+ = routes_.find(syncable::BOOKMARKS);
+ if (group == routes_.end())
+ return false;
+ Projections::const_iterator proj = projections_.find(group->second);
+ if (proj == projections_.end())
+ return false;
+ DCHECK_LE(proj->second.size(), types_.size());
+ for (size_t i = 0; i < proj->second.size(); i++) {
+ if (types_[proj->second[i]] == syncable::BOOKMARKS)
+ return true;
+ }
+ return false;
+}
+
+void OrderedCommitSet::operator=(const OrderedCommitSet& other) {
+ inserted_metahandles_ = other.inserted_metahandles_;
+ commit_ids_ = other.commit_ids_;
+ metahandle_order_ = other.metahandle_order_;
+ projections_ = other.projections_;
+ types_ = other.types_;
+ routes_ = other.routes_;
+}
+
+} // namespace sessions
+} // namespace browser_sync
+
diff --git a/chrome/browser/sync/sessions/ordered_commit_set.h b/chrome/browser/sync/sessions/ordered_commit_set.h
new file mode 100644
index 0000000..144fba1
--- /dev/null
+++ b/chrome/browser/sync/sessions/ordered_commit_set.h
@@ -0,0 +1,119 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SYNC_SESSIONS_ORDERED_COMMIT_SET_H_
+#define CHROME_BROWSER_SYNC_SESSIONS_ORDERED_COMMIT_SET_H_
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "chrome/browser/sync/engine/model_safe_worker.h"
+#include "chrome/browser/sync/syncable/model_type.h"
+#include "chrome/browser/sync/syncable/syncable_id.h"
+
+namespace browser_sync {
+namespace sessions {
+
+// TODO(ncarter): This code is more generic than just Commit and can
+// be reused elsewhere (e.g. ChangeReorderBuffer do similar things). Merge
+// all these implementations.
+class OrderedCommitSet {
+ public:
+ // A list of indices into the full list of commit ids such that:
+ // 1 - each element is an index belonging to a particular ModelSafeGroup.
+ // 2 - the vector is in sorted (smallest to largest) order.
+ // 3 - each element is a valid index for GetCommitItemAt.
+ // See GetCommitIdProjection for usage.
+ typedef std::vector<size_t> Projection;
+
+ // TODO(chron): Reserve space according to batch size?
+ explicit OrderedCommitSet(const browser_sync::ModelSafeRoutingInfo& routes)
+ : routes_(routes) {}
+
+ ~OrderedCommitSet() {}
+
+ bool HaveCommitItem(const int64 metahandle) const {
+ return inserted_metahandles_.count(metahandle) > 0;
+ }
+
+ void AddCommitItem(const int64 metahandle, const syncable::Id& commit_id,
+ syncable::ModelType type);
+
+ const std::vector<syncable::Id>& GetAllCommitIds() const {
+ return commit_ids_;
+ }
+
+ // Return the Id at index |position| in this OrderedCommitSet. Note that
+ // the index uniquely identifies the same logical item in each of:
+ // 1) this OrderedCommitSet
+ // 2) the CommitRequest sent to the server
+ // 3) the list of EntryResponse objects in the CommitResponse.
+ // These together allow re-association of the pre-commit Id with the
+ // actual committed entry.
+ const syncable::Id& GetCommitIdAt(const size_t position) const {
+ return commit_ids_[position];
+ }
+
+ // Same as above, but for ModelType of the item.
+ const syncable::ModelType GetModelTypeAt(const size_t position) const {
+ return types_[position];
+ }
+
+ // Get the projection of commit ids onto the space of commit ids
+ // belonging to |group|. This is useful when you need to process a commit
+ // response one ModelSafeGroup at a time. See GetCommitIdAt for how the
+ // indices contained in the returned Projection can be used.
+ const Projection& GetCommitIdProjection(browser_sync::ModelSafeGroup group) {
+ return projections_[group];
+ }
+
+ int Size() const {
+ return commit_ids_.size();
+ }
+
+ // Returns true iff any of the commit ids added to this set have model type
+ // BOOKMARKS.
+ bool HasBookmarkCommitId() const;
+
+ void AppendReverse(const OrderedCommitSet& other);
+ void Truncate(size_t max_size);
+
+ void operator=(const OrderedCommitSet& other);
+ private:
+ // A set of CommitIdProjections associated with particular ModelSafeGroups.
+ typedef std::map<browser_sync::ModelSafeGroup, Projection> Projections;
+
+ // Helper container for return value of GetCommitItemAt.
+ struct CommitItem {
+ int64 meta;
+ syncable::Id id;
+ syncable::ModelType group;
+ };
+
+ CommitItem GetCommitItemAt(const int position) const;
+
+ // These lists are different views of the same items; e.g they are
+ // isomorphic.
+ std::set<int64> inserted_metahandles_;
+ std::vector<syncable::Id> commit_ids_;
+ std::vector<int64> metahandle_order_;
+ Projections projections_;
+
+ // We need this because of operations like AppendReverse that take ids from
+ // one OrderedCommitSet and insert into another -- we need to know the
+ // group for each ID so that the insertion can update the appropriate
+ // projection. We could store it in commit_ids_, but sometimes we want
+ // to just return the vector of Ids, so this is more straightforward
+ // and shouldn't take up too much extra space since commit lists are small.
+ std::vector<syncable::ModelType> types_;
+
+ browser_sync::ModelSafeRoutingInfo routes_;
+};
+
+} // namespace sessions
+} // namespace browser_sync
+
+#endif // CHROME_BROWSER_SYNC_SESSIONS_ORDERED_COMMIT_SET_H_
+
diff --git a/chrome/browser/sync/sessions/ordered_commit_set_unittest.cc b/chrome/browser/sync/sessions/ordered_commit_set_unittest.cc
new file mode 100644
index 0000000..0c9db8e
--- /dev/null
+++ b/chrome/browser/sync/sessions/ordered_commit_set_unittest.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "chrome/browser/sync/sessions/ordered_commit_set.h"
+#include "chrome/test/sync/engine/test_id_factory.h"
+
+using std::vector;
+
+class OrderedCommitSetTest : public testing::Test {
+ public:
+ OrderedCommitSetTest() {
+ routes_[syncable::BOOKMARKS] = browser_sync::GROUP_UI;
+ routes_[syncable::PREFERENCES] = browser_sync::GROUP_UI;
+ routes_[syncable::AUTOFILL] = browser_sync::GROUP_DB;
+ routes_[syncable::TOP_LEVEL_FOLDER] = browser_sync::GROUP_PASSIVE;
+ }
+ protected:
+ browser_sync::TestIdFactory ids_;
+ browser_sync::ModelSafeRoutingInfo routes_;
+};
+
+namespace browser_sync {
+namespace sessions {
+
+TEST_F(OrderedCommitSetTest, Projections) {
+ vector<syncable::Id> expected;
+ for (int i = 0; i < 8; i++)
+ expected.push_back(ids_.NewLocalId());
+
+ OrderedCommitSet commit_set1(routes_), commit_set2(routes_);
+ commit_set1.AddCommitItem(0, expected[0], syncable::BOOKMARKS);
+ commit_set1.AddCommitItem(1, expected[1], syncable::BOOKMARKS);
+ commit_set1.AddCommitItem(2, expected[2], syncable::PREFERENCES);
+ // Duplicates should be dropped.
+ commit_set1.AddCommitItem(2, expected[2], syncable::PREFERENCES);
+ commit_set1.AddCommitItem(3, expected[3], syncable::TOP_LEVEL_FOLDER);
+ commit_set1.AddCommitItem(4, expected[4], syncable::TOP_LEVEL_FOLDER);
+ commit_set2.AddCommitItem(7, expected[7], syncable::AUTOFILL);
+ commit_set2.AddCommitItem(6, expected[6], syncable::AUTOFILL);
+ commit_set2.AddCommitItem(5, expected[5], syncable::AUTOFILL);
+ // Add something in set1 to set2, which should get dropped by AppendReverse.
+ commit_set2.AddCommitItem(0, expected[0], syncable::BOOKMARKS);
+ commit_set1.AppendReverse(commit_set2);
+
+ // First, we should verify the projections are correct. Second, we want to
+ // do the same verification after truncating by 1. Next, try truncating
+ // the set to a size of 4, so that the DB projection is wiped out and
+ // PASSIVE has one element removed. Finally, truncate to 1 so only UI is
+ // remaining.
+ int j = 0;
+ do {
+ SCOPED_TRACE(::testing::Message("Iteration j = ") << j);
+ vector<syncable::Id> all_ids = commit_set1.GetAllCommitIds();
+ EXPECT_EQ(expected.size(), all_ids.size());
+ for (size_t i = 0; i < expected.size(); i++) {
+ SCOPED_TRACE(::testing::Message("CommitSet mismatch at iteration i = ")
+ << i);
+ EXPECT_TRUE(expected[i] == all_ids[i]);
+ EXPECT_TRUE(expected[i] == commit_set1.GetCommitIdAt(i));
+ }
+
+ OrderedCommitSet::Projection p1, p2, p3;
+ p1 = commit_set1.GetCommitIdProjection(GROUP_UI);
+ p2 = commit_set1.GetCommitIdProjection(GROUP_PASSIVE);
+ p3 = commit_set1.GetCommitIdProjection(GROUP_DB);
+ EXPECT_TRUE(p1.size() + p2.size() + p3.size() == expected.size()) << "Sum"
+ << "of sizes of projections should equal full expected size!";
+
+ for (size_t i = 0; i < p1.size(); i++) {
+ SCOPED_TRACE(::testing::Message("UI projection mismatch at i = ") << i);
+ EXPECT_TRUE(expected[p1[i]] == commit_set1.GetCommitIdAt(p1[i]))
+ << "expected[p1[i]] = " << expected[p1[i]]
+ << ", commit_set1[p1[i]] = " << commit_set1.GetCommitIdAt(p1[i]);
+ }
+ for (size_t i = 0; i < p2.size(); i++) {
+ SCOPED_TRACE(::testing::Message("PASSIVE projection mismatch at i = ")
+ << i);
+ EXPECT_TRUE(expected[p2[i]] == commit_set1.GetCommitIdAt(p2[i]))
+ << "expected[p2[i]] = " << expected[p2[i]]
+ << ", commit_set1[p2[i]] = " << commit_set1.GetCommitIdAt(p2[i]);
+ }
+ for (size_t i = 0; i < p3.size(); i++) {
+ SCOPED_TRACE(::testing::Message("DB projection mismatch at i = ") << i);
+ EXPECT_TRUE(expected[p3[i]] == commit_set1.GetCommitIdAt(p3[i]))
+ << "expected[p3[i]] = " << expected[p3[i]]
+ << ", commit_set1[p3[i]] = " << commit_set1.GetCommitIdAt(p3[i]);
+ }
+
+ int cut_to_size = 7 - 3 * j++;
+ if (cut_to_size < 0)
+ break;
+
+ expected.resize(cut_to_size);
+ commit_set1.Truncate(cut_to_size);
+ } while (true);
+}
+
+TEST_F(OrderedCommitSetTest, HasBookmarkCommitId) {
+ OrderedCommitSet commit_set(routes_);
+
+ commit_set.AddCommitItem(0, ids_.NewLocalId(), syncable::AUTOFILL);
+ commit_set.AddCommitItem(1, ids_.NewLocalId(), syncable::TOP_LEVEL_FOLDER);
+ EXPECT_FALSE(commit_set.HasBookmarkCommitId());
+
+ commit_set.AddCommitItem(2, ids_.NewLocalId(), syncable::PREFERENCES);
+ commit_set.AddCommitItem(3, ids_.NewLocalId(), syncable::PREFERENCES);
+ EXPECT_FALSE(commit_set.HasBookmarkCommitId());
+
+ commit_set.AddCommitItem(4, ids_.NewLocalId(), syncable::BOOKMARKS);
+ EXPECT_TRUE(commit_set.HasBookmarkCommitId());
+
+ commit_set.Truncate(4);
+ EXPECT_FALSE(commit_set.HasBookmarkCommitId());
+}
+
+} // namespace sessions
+} // namespace browser_sync
+
diff --git a/chrome/browser/sync/sessions/session_state.h b/chrome/browser/sync/sessions/session_state.h
index 6079259..e4e479c 100644
--- a/chrome/browser/sync/sessions/session_state.h
+++ b/chrome/browser/sync/sessions/session_state.h
@@ -17,6 +17,7 @@
#include "base/basictypes.h"
#include "chrome/browser/sync/engine/syncer_types.h"
#include "chrome/browser/sync/engine/syncproto.h"
+#include "chrome/browser/sync/sessions/ordered_commit_set.h"
namespace syncable {
class DirectoryManager;
@@ -47,23 +48,16 @@ struct SyncerStatus {
bool syncer_stuck;
bool syncing;
int num_successful_commits;
+ // This is needed for monitoring extensions activity.
+ int num_successful_bookmark_commits;
};
// Counters for various errors that can occur repeatedly during a sync session.
struct ErrorCounters {
ErrorCounters() : num_conflicting_commits(0),
- consecutive_problem_get_updates(0),
- consecutive_problem_commits(0),
consecutive_transient_error_commits(0),
consecutive_errors(0) {}
int num_conflicting_commits;
- // Is reset when we get any updates (not on pings) and increments whenever
- // the request fails.
- int consecutive_problem_get_updates;
-
- // Consecutive_problem_commits_ resets whenever we commit any number of items
- // and increments whenever all commits fail for any reason.
- int consecutive_problem_commits;
// Number of commits hitting transient errors since the last successful
// commit.
diff --git a/chrome/browser/sync/sessions/status_controller.cc b/chrome/browser/sync/sessions/status_controller.cc
index eefead2..921bde7 100644
--- a/chrome/browser/sync/sessions/status_controller.cc
+++ b/chrome/browser/sync/sessions/status_controller.cc
@@ -10,12 +10,10 @@ namespace browser_sync {
namespace sessions {
StatusController::StatusController()
- : transient_(new Dirtyable<TransientState>()) {}
-
-void StatusController::ResetTransientState() {
- transient_.reset(new Dirtyable<TransientState>());
- syncer_status_.value()->over_quota = false;
-}
+ : commit_set_(ModelSafeRoutingInfo()),
+ transient_(new Dirtyable<TransientState>()),
+ group_restriction_in_effect_(false),
+ group_restriction_(GROUP_PASSIVE) {}
// Helper to set the 'dirty' bit in the container of the field being
// mutated.
@@ -43,21 +41,16 @@ bool StatusController::TestAndClearIsDirty() {
conflict_progress_.reset_progress_changed();
return is_dirty;
}
-void StatusController::set_num_conflicting_commits(int value) {
+void StatusController::increment_num_conflicting_commits_by(int value) {
+ int new_value = error_counters_.value()->num_conflicting_commits + value;
SetAndMarkDirtyIfChanged(&error_counters_.value()->num_conflicting_commits,
- value, &error_counters_);
-}
-
-void StatusController::set_num_consecutive_problem_get_updates(int value) {
- SetAndMarkDirtyIfChanged(
- &error_counters_.value()->consecutive_problem_get_updates, value,
+ new_value,
&error_counters_);
}
-void StatusController::set_num_consecutive_problem_commits(int value) {
- SetAndMarkDirtyIfChanged(
- &error_counters_.value()->consecutive_problem_commits, value,
- &error_counters_);
+void StatusController::reset_num_conflicting_commits() {
+ SetAndMarkDirtyIfChanged(&error_counters_.value()->num_conflicting_commits,
+ 0, &error_counters_);
}
void StatusController::set_num_consecutive_transient_error_commits(int value) {
@@ -109,6 +102,12 @@ void StatusController::set_syncing(bool syncing) {
&syncer_status_);
}
+void StatusController::set_num_successful_bookmark_commits(int value) {
+ SetAndMarkDirtyIfChanged(
+ &syncer_status_.value()->num_successful_bookmark_commits,
+ value, &syncer_status_);
+}
+
void StatusController::set_num_successful_commits(int value) {
SetAndMarkDirtyIfChanged(&syncer_status_.value()->num_successful_commits,
value, &syncer_status_);
@@ -120,16 +119,6 @@ void StatusController::set_unsynced_handles(
unsynced_handles, transient_.get());
}
-void StatusController::increment_num_consecutive_problem_get_updates() {
- set_num_consecutive_problem_get_updates(
- error_counters_.value()->consecutive_problem_get_updates + 1);
-}
-
-void StatusController::increment_num_consecutive_problem_commits() {
- set_num_consecutive_problem_commits(
- error_counters_.value()->consecutive_problem_commits + 1);
-}
-
void StatusController::increment_num_consecutive_errors() {
set_num_consecutive_errors(error_counters_.value()->consecutive_errors + 1);
}
@@ -140,15 +129,20 @@ void StatusController::increment_num_consecutive_errors_by(int value) {
value);
}
+void StatusController::increment_num_successful_bookmark_commits() {
+ set_num_successful_bookmark_commits(
+ syncer_status_.value()->num_successful_bookmark_commits + 1);
+}
+
void StatusController::increment_num_successful_commits() {
set_num_successful_commits(
syncer_status_.value()->num_successful_commits + 1);
}
// These setters don't affect the dirtiness of TransientState.
-void StatusController::set_commit_ids(
- const std::vector<syncable::Id>& commit_ids) {
- transient_->value()->commit_ids = commit_ids;
+void StatusController::set_commit_set(const OrderedCommitSet& commit_set) {
+ DCHECK(!group_restriction_in_effect_);
+ commit_set_ = commit_set;
}
void StatusController::set_conflict_sets_built(bool built) {
@@ -175,5 +169,11 @@ int64 StatusController::CountUpdates() const {
}
}
+bool StatusController::CurrentCommitIdProjectionHasIndex(size_t index) {
+ OrderedCommitSet::Projection proj =
+ commit_set_.GetCommitIdProjection(group_restriction_);
+ return std::binary_search(proj.begin(), proj.end(), index);
+}
+
} // namespace sessions
} // namespace browser_sync
diff --git a/chrome/browser/sync/sessions/status_controller.h b/chrome/browser/sync/sessions/status_controller.h
index aa177f8..40752f6 100644
--- a/chrome/browser/sync/sessions/status_controller.h
+++ b/chrome/browser/sync/sessions/status_controller.h
@@ -14,6 +14,7 @@
#define CHROME_BROWSER_SYNC_SESSIONS_STATUS_CONTROLLER_H_
#include "base/scoped_ptr.h"
+#include "chrome/browser/sync/sessions/ordered_commit_set.h"
#include "chrome/browser/sync/sessions/session_state.h"
namespace browser_sync {
@@ -27,12 +28,6 @@ class StatusController {
// since it was created or was last reset.
bool TestAndClearIsDirty();
- // Discards the current transient state components that should not carry over
- // to a subsequent sync cycle (a run between states in SyncShare), and keeps
- // everything else intact. After the call, |this| is ready for use
- // as part of a new sync cycle.
- void ResetTransientState();
-
ConflictProgress const* conflict_progress() const {
return &conflict_progress_;
}
@@ -70,7 +65,21 @@ class StatusController {
return change_progress_.value();
}
const std::vector<syncable::Id>& commit_ids() const {
- return transient_->value()->commit_ids;
+ DCHECK(!group_restriction_in_effect_) << "Group restriction in effect!";
+ return commit_set_.GetAllCommitIds();
+ }
+ const OrderedCommitSet::Projection& commit_id_projection() {
+ DCHECK(group_restriction_in_effect_)
+ << "No group restriction for projection.";
+ return commit_set_.GetCommitIdProjection(group_restriction_);
+ }
+ const syncable::Id& GetCommitIdAt(size_t index) {
+ DCHECK(CurrentCommitIdProjectionHasIndex(index));
+ return commit_set_.GetCommitIdAt(index);
+ }
+ const syncable::ModelType GetCommitIdModelTypeAt(size_t index) {
+ DCHECK(CurrentCommitIdProjectionHasIndex(index));
+ return commit_set_.GetModelTypeAt(index);
}
const std::vector<int64>& unsynced_handles() const {
return transient_->value()->unsynced_handles;
@@ -91,14 +100,17 @@ class StatusController {
// Returns the number of updates received from the sync server.
int64 CountUpdates() const;
+ // Returns true iff any of the commit ids added during this session are
+ // bookmark related.
+ bool HasBookmarkCommitActivity() const {
+ return commit_set_.HasBookmarkCommitId();
+ }
+
bool got_zero_updates() const { return CountUpdates() == 0; }
// A toolbelt full of methods for updating counters and flags.
- void set_num_conflicting_commits(int value);
- void set_num_consecutive_problem_get_updates(int value);
- void increment_num_consecutive_problem_get_updates();
- void set_num_consecutive_problem_commits(int value);
- void increment_num_consecutive_problem_commits();
+ void increment_num_conflicting_commits_by(int value);
+ void reset_num_conflicting_commits();
void set_num_consecutive_transient_error_commits(int value);
void increment_num_consecutive_transient_error_commits_by(int value);
void set_num_consecutive_errors(int value);
@@ -111,16 +123,24 @@ class StatusController {
void set_syncer_stuck(bool syncer_stuck);
void set_syncing(bool syncing);
void set_num_successful_commits(int value);
+ void set_num_successful_bookmark_commits(int value);
void increment_num_successful_commits();
+ void increment_num_successful_bookmark_commits();
void set_unsynced_handles(const std::vector<int64>& unsynced_handles);
- void set_commit_ids(const std::vector<syncable::Id>& commit_ids);
+ void set_commit_set(const OrderedCommitSet& commit_set);
void set_conflict_sets_built(bool built);
void set_conflicts_resolved(bool resolved);
void set_items_committed(bool items_committed);
void set_timestamp_dirty(bool dirty);
private:
+ friend class ScopedModelSafeGroupRestriction;
+
+ // Returns true iff the commit id projection for |group_restriction_|
+ // references position |index| into the full set of commit ids in play.
+ bool CurrentCommitIdProjectionHasIndex(size_t index);
+
// Dirtyable keeps a dirty bit that can be set, cleared, and checked to
// determine if a notification should be sent due to state change.
// This is useful when applied to any session state object if you want to know
@@ -138,6 +158,8 @@ class StatusController {
bool dirty_;
};
+ OrderedCommitSet commit_set_;
+
// Various pieces of state we track dirtiness of.
Dirtyable<ChangelogProgress> change_progress_;
Dirtyable<SyncerStatus> syncer_status_;
@@ -146,10 +168,17 @@ class StatusController {
// The transient parts of a sync session that can be reset during the session.
// For some parts of this state, we want to track whether changes occurred so
// we allocate a Dirtyable version.
+ // TODO(tim): Get rid of transient state since it has no valid use case
+ // anymore.
scoped_ptr<Dirtyable<TransientState> > transient_;
ConflictProgress conflict_progress_;
+ // Used to fail read/write operations on state that don't obey the current
+ // active ModelSafeWorker contract.
+ bool group_restriction_in_effect_;
+ ModelSafeGroup group_restriction_;
+
DISALLOW_COPY_AND_ASSIGN(StatusController);
};
diff --git a/chrome/browser/sync/sessions/status_controller_unittest.cc b/chrome/browser/sync/sessions/status_controller_unittest.cc
index 139fa70..95ee36d 100644
--- a/chrome/browser/sync/sessions/status_controller_unittest.cc
+++ b/chrome/browser/sync/sessions/status_controller_unittest.cc
@@ -12,24 +12,12 @@ typedef testing::Test StatusControllerTest;
TEST_F(StatusControllerTest, GetsDirty) {
StatusController status;
- status.set_num_conflicting_commits(1);
+ status.increment_num_conflicting_commits_by(1);
EXPECT_TRUE(status.TestAndClearIsDirty());
EXPECT_FALSE(status.TestAndClearIsDirty()); // Test that it actually resets.
- status.set_num_conflicting_commits(1);
+ status.increment_num_conflicting_commits_by(0);
EXPECT_FALSE(status.TestAndClearIsDirty());
- status.set_num_conflicting_commits(0);
- EXPECT_TRUE(status.TestAndClearIsDirty());
-
- status.set_num_consecutive_problem_get_updates(1);
- EXPECT_TRUE(status.TestAndClearIsDirty());
-
- status.increment_num_consecutive_problem_get_updates();
- EXPECT_TRUE(status.TestAndClearIsDirty());
-
- status.set_num_consecutive_problem_commits(1);
- EXPECT_TRUE(status.TestAndClearIsDirty());
-
- status.increment_num_consecutive_problem_commits();
+ status.increment_num_conflicting_commits_by(1);
EXPECT_TRUE(status.TestAndClearIsDirty());
status.set_num_consecutive_transient_error_commits(1);
@@ -77,7 +65,7 @@ TEST_F(StatusControllerTest, GetsDirty) {
status.set_syncing(false);
EXPECT_TRUE(status.TestAndClearIsDirty());
- status.set_num_successful_commits(1);
+ status.increment_num_successful_commits();
EXPECT_TRUE(status.TestAndClearIsDirty());
status.increment_num_successful_commits();
EXPECT_TRUE(status.TestAndClearIsDirty());
@@ -103,9 +91,11 @@ TEST_F(StatusControllerTest, StaysClean) {
status.set_items_committed(true);
EXPECT_FALSE(status.TestAndClearIsDirty());
- std::vector<syncable::Id> v;
- v.push_back(syncable::Id());
- status.set_commit_ids(v);
+ ModelSafeRoutingInfo routes;
+ routes[syncable::BOOKMARKS] = GROUP_UI;
+ OrderedCommitSet commits(routes);
+ commits.AddCommitItem(0, syncable::Id(), syncable::BOOKMARKS);
+ status.set_commit_set(commits);
EXPECT_FALSE(status.TestAndClearIsDirty());
}
@@ -114,19 +104,9 @@ TEST_F(StatusControllerTest, StaysClean) {
// method was actually setting |bar_| instead!).
TEST_F(StatusControllerTest, ReadYourWrites) {
StatusController status;
- status.set_num_conflicting_commits(1);
+ status.increment_num_conflicting_commits_by(1);
EXPECT_EQ(1, status.error_counters().num_conflicting_commits);
- status.set_num_consecutive_problem_get_updates(2);
- EXPECT_EQ(2, status.error_counters().consecutive_problem_get_updates);
- status.increment_num_consecutive_problem_get_updates();
- EXPECT_EQ(3, status.error_counters().consecutive_problem_get_updates);
-
- status.set_num_consecutive_problem_commits(4);
- EXPECT_EQ(4, status.error_counters().consecutive_problem_commits);
- status.increment_num_consecutive_problem_commits();
- EXPECT_EQ(5, status.error_counters().consecutive_problem_commits);
-
status.set_num_consecutive_transient_error_commits(6);
EXPECT_EQ(6, status.error_counters().consecutive_transient_error_commits);
status.increment_num_consecutive_transient_error_commits_by(1);
@@ -174,44 +154,6 @@ TEST_F(StatusControllerTest, ReadYourWrites) {
EXPECT_EQ(16, v[0]);
}
-TEST_F(StatusControllerTest, ResetTransientState) {
- StatusController status;
- status.set_conflict_sets_built(true);
- EXPECT_TRUE(status.conflict_sets_built());
- status.set_timestamp_dirty(true);
- status.set_items_committed(true);
- status.set_conflicts_resolved(true);
- sync_pb::SyncEntity entity;
- status.mutable_update_progress()->AddVerifyResult(VERIFY_SUCCESS, entity);
- status.mutable_commit_message()->mutable_commit(); // Lazy initialization.
- ASSERT_TRUE(status.mutable_commit_message()->has_commit());
- status.mutable_commit_response()->mutable_commit();
- ASSERT_TRUE(status.commit_response().has_commit());
- status.mutable_updates_response()->mutable_get_updates();
- ASSERT_TRUE(status.updates_response().has_get_updates());
-
- std::vector<int64> v;
- v.push_back(1);
- status.set_unsynced_handles(v);
-
- std::vector<syncable::Id> v2;
- v2.push_back(syncable::Id());
- status.set_commit_ids(v2);
-
- EXPECT_TRUE(status.TestAndClearIsDirty());
- status.ResetTransientState();
- EXPECT_FALSE(status.TestAndClearIsDirty());
-
- EXPECT_FALSE(status.conflict_sets_built());
- EXPECT_FALSE(status.timestamp_dirty());
- EXPECT_FALSE(status.did_commit_items());
- EXPECT_FALSE(status.conflicts_resolved());
- EXPECT_EQ(0, status.update_progress().VerifiedUpdatesSize());
- EXPECT_FALSE(status.mutable_commit_message()->has_commit());
- EXPECT_FALSE(status.commit_response().has_commit());
- EXPECT_FALSE(status.updates_response().has_get_updates());
-}
-
TEST_F(StatusControllerTest, HasConflictingUpdates) {
StatusController status;
EXPECT_FALSE(status.update_progress().HasConflictingUpdates());
diff --git a/chrome/browser/sync/sessions/sync_session.cc b/chrome/browser/sync/sessions/sync_session.cc
index 27e2235..a863a5e 100644
--- a/chrome/browser/sync/sessions/sync_session.cc
+++ b/chrome/browser/sync/sessions/sync_session.cc
@@ -12,8 +12,7 @@ SyncSession::SyncSession(SyncSessionContext* context, Delegate* delegate)
: context_(context),
source_(sync_pb::GetUpdatesCallerInfo::UNKNOWN),
write_transaction_(NULL),
- delegate_(delegate),
- auth_failure_occurred_(false) {
+ delegate_(delegate) {
context_->registrar()->GetWorkers(
const_cast<std::vector<ModelSafeWorker*>*>(&workers_));
@@ -30,8 +29,6 @@ SyncSession::SyncSession(SyncSessionContext* context, Delegate* delegate)
// synced) *continue* to be for this whole session, even though the
// ModelSafeWorkerRegistrar may be configured to route syncable::AUTOFILL to
// GROUP_DB now.
- group_restriction_in_effect_ = false;
- group_restriction_ = GROUP_PASSIVE;
}
SyncSessionSnapshot SyncSession::TakeSnapshot() const {
diff --git a/chrome/browser/sync/sessions/sync_session.h b/chrome/browser/sync/sessions/sync_session.h
index 196d256..5e49cec 100644
--- a/chrome/browser/sync/sessions/sync_session.h
+++ b/chrome/browser/sync/sessions/sync_session.h
@@ -20,6 +20,7 @@
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
+#include "chrome/browser/sync/sessions/ordered_commit_set.h"
#include "chrome/browser/sync/sessions/session_state.h"
#include "chrome/browser/sync/sessions/status_controller.h"
#include "chrome/browser/sync/sessions/sync_session_context.h"
@@ -90,10 +91,6 @@ class SyncSession {
return &extensions_activity_;
}
- bool auth_failure_occurred() const { return auth_failure_occurred_; }
- void set_auth_failure_occurred() { auth_failure_occurred_ = true; }
- void clear_auth_failure_occurred() { auth_failure_occurred_ = false; }
-
// Volatile reader for the source member of the sync session object. The
// value is set to the SYNC_CYCLE_CONTINUATION value to signal that it has
// been read.
@@ -110,7 +107,6 @@ class SyncSession {
// assignments. This way, the scope of these actions is explicit, they can't
// be overridden, and assigning is always accompanied by unassigning.
friend class ScopedSetSessionWriteTransaction;
- friend class ScopedModelSafeGroupRestriction;
// The context for this session, guaranteed to outlive |this|.
SyncSessionContext* const context_;
@@ -130,9 +126,6 @@ class SyncSession {
// Our controller for various status and error counters.
StatusController status_controller_;
- // Used to determine if an auth error notification should be sent out.
- bool auth_failure_occurred_;
-
// The set of active ModelSafeWorkers for the duration of this session.
const std::vector<ModelSafeWorker*> workers_;
@@ -141,11 +134,6 @@ class SyncSession {
// on those datatypes.
const ModelSafeRoutingInfo routing_info_;
- // Used to fail read/write operations on this SyncSession that don't obey the
- // currently active ModelSafeWorker contract.
- bool group_restriction_in_effect_;
- ModelSafeGroup group_restriction_;
-
DISALLOW_COPY_AND_ASSIGN(SyncSession);
};
@@ -175,12 +163,13 @@ class ScopedModelSafeGroupRestriction {
ScopedModelSafeGroupRestriction(SyncSession* to_restrict,
ModelSafeGroup restriction)
: session_(to_restrict) {
- DCHECK(!session_->group_restriction_in_effect_);
- session_->group_restriction_in_effect_ = true;
- session_->group_restriction_ = restriction;
+ DCHECK(!session_->status_controller()->group_restriction_in_effect_);
+ session_->status_controller()->group_restriction_ = restriction;
+ session_->status_controller()->group_restriction_in_effect_ = true;
}
~ScopedModelSafeGroupRestriction() {
- session_->group_restriction_in_effect_ = false;
+ DCHECK(session_->status_controller()->group_restriction_in_effect_);
+ session_->status_controller()->group_restriction_in_effect_ = false;
}
private:
SyncSession* session_;
diff --git a/chrome/browser/sync/sessions/sync_session_unittest.cc b/chrome/browser/sync/sessions/sync_session_unittest.cc
index 8c9cfe3..a50a06b 100644
--- a/chrome/browser/sync/sessions/sync_session_unittest.cc
+++ b/chrome/browser/sync/sessions/sync_session_unittest.cc
@@ -22,7 +22,9 @@ class SyncSessionTest : public testing::Test,
public SyncSession::Delegate,
public ModelSafeWorkerRegistrar {
public:
- SyncSessionTest() : controller_invocations_allowed_(false) {}
+ SyncSessionTest() : controller_invocations_allowed_(false) {
+ GetModelSafeRoutingInfo(&routes_);
+ }
virtual void SetUp() {
context_.reset(new SyncSessionContext(NULL, NULL, this));
session_.reset(new SyncSession(context_.get(), this));
@@ -50,7 +52,9 @@ class SyncSessionTest : public testing::Test,
// ModelSafeWorkerRegistrar implementation.
virtual void GetWorkers(std::vector<ModelSafeWorker*>* out) {}
- virtual void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) {}
+ virtual void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) {
+ (*out)[syncable::BOOKMARKS] = GROUP_UI;
+ }
StatusController* status() { return session_->status_controller(); }
protected:
@@ -61,6 +65,7 @@ class SyncSessionTest : public testing::Test,
bool controller_invocations_allowed_;
scoped_ptr<SyncSession> session_;
scoped_ptr<SyncSessionContext> context_;
+ ModelSafeRoutingInfo routes_;
};
TEST_F(SyncSessionTest, ScopedContextHelpers) {
@@ -107,9 +112,9 @@ TEST_F(SyncSessionTest, MoreToSyncIfUnsyncedGreaterThanCommitted) {
// more to sync. For example, this occurs if we had more commit ids
// than could fit in a single commit batch.
EXPECT_FALSE(session_->HasMoreToSync());
- std::vector<syncable::Id> commit_ids;
- commit_ids.push_back(syncable::Id());
- status()->set_commit_ids(commit_ids);
+ OrderedCommitSet commit_set(routes_);
+ commit_set.AddCommitItem(0, syncable::Id(), syncable::BOOKMARKS);
+ status()->set_commit_set(commit_set);
EXPECT_FALSE(session_->HasMoreToSync());
std::vector<int64> unsynced_handles;
@@ -119,8 +124,6 @@ TEST_F(SyncSessionTest, MoreToSyncIfUnsyncedGreaterThanCommitted) {
EXPECT_FALSE(session_->HasMoreToSync());
status()->increment_num_successful_commits();
EXPECT_TRUE(session_->HasMoreToSync());
- status()->ResetTransientState();
- EXPECT_FALSE(session_->HasMoreToSync());
}
TEST_F(SyncSessionTest, MoreToSyncIfConflictSetsBuilt) {
@@ -128,8 +131,6 @@ TEST_F(SyncSessionTest, MoreToSyncIfConflictSetsBuilt) {
// to get updates & commit again.
status()->set_conflict_sets_built(true);
EXPECT_TRUE(session_->HasMoreToSync());
- status()->ResetTransientState();
- EXPECT_FALSE(session_->HasMoreToSync());
}
TEST_F(SyncSessionTest, MoreToSyncIfDidNotGetZeroUpdates) {
@@ -142,8 +143,6 @@ TEST_F(SyncSessionTest, MoreToSyncIfDidNotGetZeroUpdates) {
EXPECT_FALSE(session_->HasMoreToSync());
status()->mutable_updates_response()->CopyFrom(response);
EXPECT_TRUE(session_->HasMoreToSync());
- status()->ResetTransientState();
- EXPECT_FALSE(session_->HasMoreToSync());
}
TEST_F(SyncSessionTest, MoreToSyncIfConflictsResolved) {
@@ -152,8 +151,6 @@ TEST_F(SyncSessionTest, MoreToSyncIfConflictsResolved) {
// that we have made forward progress.
status()->set_conflicts_resolved(true);
EXPECT_TRUE(session_->HasMoreToSync());
- status()->ResetTransientState();
- EXPECT_FALSE(session_->HasMoreToSync());
}
TEST_F(SyncSessionTest, MoreToSyncIfTimestampDirty) {
@@ -163,8 +160,6 @@ TEST_F(SyncSessionTest, MoreToSyncIfTimestampDirty) {
status()->set_timestamp_dirty(true);
status()->set_conflicts_resolved(true);
EXPECT_TRUE(session_->HasMoreToSync());
- status()->ResetTransientState();
- EXPECT_FALSE(session_->HasMoreToSync());
}