summaryrefslogtreecommitdiffstats
path: root/sync
diff options
context:
space:
mode:
authorrlarocque@chromium.org <rlarocque@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-20 18:58:26 +0000
committerrlarocque@chromium.org <rlarocque@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-20 18:58:26 +0000
commit15732679ce96d261ff3e838d3f8cdb6ff86a2189 (patch)
tree00fe7e29bf4e67d4bd765be5d637811cee3bbaef /sync
parent77e4dc088d316a0507c6ff25b5d1f9f060cb30d8 (diff)
downloadchromium_src-15732679ce96d261ff3e838d3f8cdb6ff86a2189.zip
chromium_src-15732679ce96d261ff3e838d3f8cdb6ff86a2189.tar.gz
chromium_src-15732679ce96d261ff3e838d3f8cdb6ff86a2189.tar.bz2
Split syncable.{h,cc} into several files
The only functional change was to remove the dirkernel_ member from BaseTransaction, which was to reduce the number of includes required. Everything else is just moving code around, and updating includes, forward declarations, and 'using' statements. BUG=103332 TEST= Review URL: https://chromiumcodereview.appspot.com/10579036 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@143218 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sync')
-rw-r--r--sync/engine/apply_updates_command.cc4
-rw-r--r--sync/engine/apply_updates_command_unittest.cc5
-rw-r--r--sync/engine/build_commit_command.cc4
-rw-r--r--sync/engine/build_commit_command.h7
-rw-r--r--sync/engine/cleanup_disabled_types_command.cc2
-rw-r--r--sync/engine/commit.cc2
-rw-r--r--sync/engine/conflict_resolver.cc4
-rw-r--r--sync/engine/download_updates_command.cc2
-rw-r--r--sync/engine/get_commit_ids_command.cc4
-rw-r--r--sync/engine/get_commit_ids_command.h1
-rw-r--r--sync/engine/net/server_connection_manager.cc2
-rw-r--r--sync/engine/nigori_util.cc5
-rw-r--r--sync/engine/process_commit_response_command.cc6
-rw-r--r--sync/engine/process_commit_response_command_unittest.cc12
-rw-r--r--sync/engine/process_updates_command.cc5
-rw-r--r--sync/engine/resolve_conflicts_command.cc3
-rw-r--r--sync/engine/store_timestamps_command.cc2
-rw-r--r--sync/engine/syncer.cc5
-rw-r--r--sync/engine/syncer_proto_util.cc3
-rw-r--r--sync/engine/syncer_proto_util_unittest.cc3
-rw-r--r--sync/engine/syncer_unittest.cc6
-rw-r--r--sync/engine/syncer_util.cc12
-rw-r--r--sync/engine/syncer_util.h3
-rw-r--r--sync/engine/update_applicator.cc4
-rw-r--r--sync/engine/update_applicator.h7
-rw-r--r--sync/engine/verify_updates_command.cc7
-rw-r--r--sync/engine/verify_updates_command_unittest.cc5
-rw-r--r--sync/internal_api/base_node.cc3
-rw-r--r--sync/internal_api/base_transaction.cc2
-rw-r--r--sync/internal_api/change_reorder_buffer.cc6
-rw-r--r--sync/internal_api/public/base_transaction.h2
-rw-r--r--sync/internal_api/public/write_transaction.h2
-rw-r--r--sync/internal_api/read_node.cc3
-rw-r--r--sync/internal_api/read_transaction.cc2
-rw-r--r--sync/internal_api/sync_manager.cc3
-rw-r--r--sync/internal_api/syncapi_unittest.cc5
-rw-r--r--sync/internal_api/test/test_user_share.cc1
-rw-r--r--sync/internal_api/user_share.cc2
-rw-r--r--sync/internal_api/write_node.cc2
-rw-r--r--sync/internal_api/write_transaction.cc2
-rw-r--r--sync/sessions/sync_session.cc2
-rw-r--r--sync/sessions/sync_session_unittest.cc2
-rw-r--r--sync/sync.gyp26
-rw-r--r--sync/syncable/base_transaction.cc68
-rw-r--r--sync/syncable/base_transaction.h81
-rw-r--r--sync/syncable/directory.cc (renamed from sync/syncable/syncable.cc)1139
-rw-r--r--sync/syncable/directory.h (renamed from sync/syncable/syncable.h)798
-rw-r--r--sync/syncable/directory_backing_store.h3
-rw-r--r--sync/syncable/directory_backing_store_unittest.cc9
-rw-r--r--sync/syncable/directory_change_delegate.h2
-rw-r--r--sync/syncable/entry.cc143
-rw-r--r--sync/syncable/entry.h154
-rw-r--r--sync/syncable/entry_kernel.cc151
-rw-r--r--sync/syncable/entry_kernel.h323
-rw-r--r--sync/syncable/metahandle_set.h16
-rw-r--r--sync/syncable/mutable_entry.cc410
-rw-r--r--sync/syncable/mutable_entry.h119
-rw-r--r--sync/syncable/read_transaction.cc20
-rw-r--r--sync/syncable/read_transaction.h34
-rw-r--r--sync/syncable/scoped_index_updater.h55
-rw-r--r--sync/syncable/scoped_kernel_lock.h28
-rw-r--r--sync/syncable/syncable-inl.h2
-rw-r--r--sync/syncable/syncable_columns.h2
-rw-r--r--sync/syncable/syncable_enum_conversions.cc2
-rw-r--r--sync/syncable/syncable_enum_conversions.h4
-rw-r--r--sync/syncable/syncable_enum_conversions_unittest.cc2
-rw-r--r--sync/syncable/syncable_mock.h3
-rw-r--r--sync/syncable/syncable_unittest.cc11
-rw-r--r--sync/syncable/syncable_util.cc104
-rw-r--r--sync/syncable/syncable_util.h31
-rw-r--r--sync/syncable/transaction_observer.h2
-rw-r--r--sync/syncable/write_transaction.cc158
-rw-r--r--sync/syncable/write_transaction.h48
-rw-r--r--sync/syncable/write_transaction_info.cc46
-rw-r--r--sync/syncable/write_transaction_info.h40
-rw-r--r--sync/test/engine/mock_connection_manager.cc3
-rw-r--r--sync/test/engine/test_directory_setter_upper.cc3
-rw-r--r--sync/test/engine/test_syncable_utils.cc4
-rw-r--r--sync/test/engine/test_syncable_utils.h2
79 files changed, 2243 insertions, 1967 deletions
diff --git a/sync/engine/apply_updates_command.cc b/sync/engine/apply_updates_command.cc
index 79fd039..35490c3 100644
--- a/sync/engine/apply_updates_command.cc
+++ b/sync/engine/apply_updates_command.cc
@@ -7,7 +7,9 @@
#include "base/location.h"
#include "sync/engine/update_applicator.h"
#include "sync/sessions/sync_session.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/read_transaction.h"
+#include "sync/syncable/write_transaction.h"
namespace browser_sync {
diff --git a/sync/engine/apply_updates_command_unittest.cc b/sync/engine/apply_updates_command_unittest.cc
index 6ff6dae..e60c15f 100644
--- a/sync/engine/apply_updates_command_unittest.cc
+++ b/sync/engine/apply_updates_command_unittest.cc
@@ -14,8 +14,10 @@
#include "sync/protocol/bookmark_specifics.pb.h"
#include "sync/protocol/password_specifics.pb.h"
#include "sync/sessions/sync_session.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/mutable_entry.h"
+#include "sync/syncable/read_transaction.h"
#include "sync/syncable/syncable_id.h"
+#include "sync/syncable/write_transaction.h"
#include "sync/test/engine/fake_model_worker.h"
#include "sync/test/engine/syncer_command_test.h"
#include "sync/test/engine/test_id_factory.h"
@@ -27,7 +29,6 @@ namespace browser_sync {
using sessions::SyncSession;
using std::string;
-using syncable::Entry;
using syncable::Id;
using syncable::MutableEntry;
using syncable::ReadTransaction;
diff --git a/sync/engine/build_commit_command.cc b/sync/engine/build_commit_command.cc
index 974cd37..665613a 100644
--- a/sync/engine/build_commit_command.cc
+++ b/sync/engine/build_commit_command.cc
@@ -14,8 +14,10 @@
#include "sync/protocol/bookmark_specifics.pb.h"
#include "sync/sessions/ordered_commit_set.h"
#include "sync/sessions/sync_session.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/mutable_entry.h"
#include "sync/syncable/syncable_changes_version.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/write_transaction.h"
#include "sync/util/time.h"
using std::set;
diff --git a/sync/engine/build_commit_command.h b/sync/engine/build_commit_command.h
index 91eb3203..bdcefe1 100644
--- a/sync/engine/build_commit_command.h
+++ b/sync/engine/build_commit_command.h
@@ -8,9 +8,14 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
#include "sync/engine/syncer_command.h"
#include "sync/engine/syncproto.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/entry_kernel.h"
+
+namespace syncable {
+class Entry;
+}
namespace browser_sync {
diff --git a/sync/engine/cleanup_disabled_types_command.cc b/sync/engine/cleanup_disabled_types_command.cc
index 4a774b7..1a94663 100644
--- a/sync/engine/cleanup_disabled_types_command.cc
+++ b/sync/engine/cleanup_disabled_types_command.cc
@@ -9,7 +9,7 @@
#include "sync/internal_api/public/syncable/model_type.h"
#include "sync/sessions/sync_session.h"
#include "sync/sessions/sync_session_context.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
namespace browser_sync {
diff --git a/sync/engine/commit.cc b/sync/engine/commit.cc
index 2f39c23..abef162 100644
--- a/sync/engine/commit.cc
+++ b/sync/engine/commit.cc
@@ -10,6 +10,8 @@
#include "sync/engine/process_commit_response_command.h"
#include "sync/engine/syncer_proto_util.h"
#include "sync/sessions/sync_session.h"
+#include "sync/syncable/mutable_entry.h"
+#include "sync/syncable/write_transaction.h"
using syncable::SYNCER;
using syncable::WriteTransaction;
diff --git a/sync/engine/conflict_resolver.cc b/sync/engine/conflict_resolver.cc
index 3422f18..d775c1d 100644
--- a/sync/engine/conflict_resolver.cc
+++ b/sync/engine/conflict_resolver.cc
@@ -15,7 +15,9 @@
#include "sync/engine/syncer_util.h"
#include "sync/protocol/nigori_specifics.pb.h"
#include "sync/sessions/status_controller.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/mutable_entry.h"
+#include "sync/syncable/write_transaction.h"
#include "sync/util/cryptographer.h"
using std::list;
diff --git a/sync/engine/download_updates_command.cc b/sync/engine/download_updates_command.cc
index ef41a76..cc8cf4e 100644
--- a/sync/engine/download_updates_command.cc
+++ b/sync/engine/download_updates_command.cc
@@ -11,7 +11,7 @@
#include "sync/engine/syncer_proto_util.h"
#include "sync/engine/syncproto.h"
#include "sync/internal_api/public/syncable/model_type_payload_map.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
using sync_pb::DebugInfo;
diff --git a/sync/engine/get_commit_ids_command.cc b/sync/engine/get_commit_ids_command.cc
index e8653b2..6936cc7 100644
--- a/sync/engine/get_commit_ids_command.cc
+++ b/sync/engine/get_commit_ids_command.cc
@@ -11,7 +11,9 @@
#include "sync/engine/nigori_util.h"
#include "sync/engine/syncer_util.h"
#include "sync/engine/throttled_data_type_tracker.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/entry.h"
+#include "sync/syncable/mutable_entry.h"
+#include "sync/syncable/write_transaction.h"
#include "sync/util/cryptographer.h"
using std::set;
diff --git a/sync/engine/get_commit_ids_command.h b/sync/engine/get_commit_ids_command.h
index 9aca7cd..3e18f60 100644
--- a/sync/engine/get_commit_ids_command.h
+++ b/sync/engine/get_commit_ids_command.h
@@ -14,6 +14,7 @@
#include "sync/engine/syncer_util.h"
#include "sync/sessions/ordered_commit_set.h"
#include "sync/sessions/sync_session.h"
+#include "sync/syncable/directory.h"
using std::pair;
using std::vector;
diff --git a/sync/engine/net/server_connection_manager.cc b/sync/engine/net/server_connection_manager.cc
index c9a675f..5ffd6a7 100644
--- a/sync/engine/net/server_connection_manager.cc
+++ b/sync/engine/net/server_connection_manager.cc
@@ -18,7 +18,7 @@
#include "sync/engine/syncer.h"
#include "sync/engine/syncproto.h"
#include "sync/protocol/sync.pb.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
namespace browser_sync {
diff --git a/sync/engine/nigori_util.cc b/sync/engine/nigori_util.cc
index 78bb33c..0b34a02 100644
--- a/sync/engine/nigori_util.cc
+++ b/sync/engine/nigori_util.cc
@@ -10,7 +10,10 @@
#include "base/json/json_writer.h"
#include "sync/engine/syncer_util.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/entry.h"
+#include "sync/syncable/mutable_entry.h"
+#include "sync/syncable/write_transaction.h"
#include "sync/util/cryptographer.h"
namespace syncable {
diff --git a/sync/engine/process_commit_response_command.cc b/sync/engine/process_commit_response_command.cc
index dfecd39..fbfe941 100644
--- a/sync/engine/process_commit_response_command.cc
+++ b/sync/engine/process_commit_response_command.cc
@@ -15,7 +15,11 @@
#include "sync/engine/syncer_util.h"
#include "sync/engine/syncproto.h"
#include "sync/sessions/sync_session.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/entry.h"
+#include "sync/syncable/mutable_entry.h"
+#include "sync/syncable/read_transaction.h"
+#include "sync/syncable/syncable_util.h"
+#include "sync/syncable/write_transaction.h"
#include "sync/util/time.h"
using syncable::WriteTransaction;
diff --git a/sync/engine/process_commit_response_command_unittest.cc b/sync/engine/process_commit_response_command_unittest.cc
index 195d58a..bd1b661 100644
--- a/sync/engine/process_commit_response_command_unittest.cc
+++ b/sync/engine/process_commit_response_command_unittest.cc
@@ -2,19 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "sync/engine/process_commit_response_command.h"
+
#include <vector>
#include "base/location.h"
#include "base/stringprintf.h"
-#include "sync/engine/process_commit_response_command.h"
+#include "sync/protocol/bookmark_specifics.pb.h"
+#include "sync/protocol/sync.pb.h"
#include "sync/sessions/sync_session.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/entry.h"
+#include "sync/syncable/mutable_entry.h"
+#include "sync/syncable/read_transaction.h"
#include "sync/syncable/syncable_id.h"
+#include "sync/syncable/write_transaction.h"
#include "sync/test/engine/fake_model_worker.h"
#include "sync/test/engine/syncer_command_test.h"
#include "sync/test/engine/test_id_factory.h"
-#include "sync/protocol/bookmark_specifics.pb.h"
-#include "sync/protocol/sync.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace browser_sync {
diff --git a/sync/engine/process_updates_command.cc b/sync/engine/process_updates_command.cc
index 59c1d77..a7073a5 100644
--- a/sync/engine/process_updates_command.cc
+++ b/sync/engine/process_updates_command.cc
@@ -13,7 +13,10 @@
#include "sync/engine/syncer_util.h"
#include "sync/engine/syncproto.h"
#include "sync/sessions/sync_session.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/mutable_entry.h"
+#include "sync/syncable/syncable_util.h"
+#include "sync/syncable/write_transaction.h"
#include "sync/util/cryptographer.h"
using std::vector;
diff --git a/sync/engine/resolve_conflicts_command.cc b/sync/engine/resolve_conflicts_command.cc
index 457e4b7..bac365f 100644
--- a/sync/engine/resolve_conflicts_command.cc
+++ b/sync/engine/resolve_conflicts_command.cc
@@ -7,7 +7,8 @@
#include "sync/engine/conflict_resolver.h"
#include "sync/sessions/session_state.h"
#include "sync/sessions/sync_session.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/write_transaction.h"
namespace browser_sync {
diff --git a/sync/engine/store_timestamps_command.cc b/sync/engine/store_timestamps_command.cc
index e942328..6791ad2 100644
--- a/sync/engine/store_timestamps_command.cc
+++ b/sync/engine/store_timestamps_command.cc
@@ -7,7 +7,7 @@
#include "sync/internal_api/public/syncable/model_type.h"
#include "sync/sessions/status_controller.h"
#include "sync/sessions/sync_session.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
namespace browser_sync {
diff --git a/sync/engine/syncer.cc b/sync/engine/syncer.cc
index 01c8ae6..da4e27b 100644
--- a/sync/engine/syncer.cc
+++ b/sync/engine/syncer.cc
@@ -25,13 +25,12 @@
#include "sync/engine/syncproto.h"
#include "sync/engine/throttled_data_type_tracker.h"
#include "sync/engine/verify_updates_command.h"
+#include "sync/syncable/mutable_entry.h"
#include "sync/syncable/syncable-inl.h"
-#include "sync/syncable/syncable.h"
using base::Time;
using base::TimeDelta;
using sync_pb::ClientCommand;
-using syncable::Blob;
using syncable::IS_UNAPPLIED_UPDATE;
using syncable::SERVER_CTIME;
using syncable::SERVER_IS_DEL;
@@ -42,8 +41,6 @@ using syncable::SERVER_PARENT_ID;
using syncable::SERVER_POSITION_IN_PARENT;
using syncable::SERVER_SPECIFICS;
using syncable::SERVER_VERSION;
-using syncable::SYNCER;
-using syncable::WriteTransaction;
namespace browser_sync {
diff --git a/sync/engine/syncer_proto_util.cc b/sync/engine/syncer_proto_util.cc
index 294f0ef..116556f 100644
--- a/sync/engine/syncer_proto_util.cc
+++ b/sync/engine/syncer_proto_util.cc
@@ -16,8 +16,9 @@
#include "sync/protocol/sync_enums.pb.h"
#include "sync/protocol/sync_protocol_error.h"
#include "sync/sessions/sync_session.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/entry.h"
#include "sync/syncable/syncable-inl.h"
-#include "sync/syncable/syncable.h"
#include "sync/util/time.h"
using browser_sync::SyncProtocolErrorType;
diff --git a/sync/engine/syncer_proto_util_unittest.cc b/sync/engine/syncer_proto_util_unittest.cc
index fe9f0dc..7f81221 100644
--- a/sync/engine/syncer_proto_util_unittest.cc
+++ b/sync/engine/syncer_proto_util_unittest.cc
@@ -20,10 +20,9 @@
#include "sync/sessions/session_state.h"
#include "sync/sessions/sync_session_context.h"
#include "sync/syncable/blob.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
#include "sync/test/engine/mock_connection_manager.h"
#include "sync/test/engine/test_directory_setter_upper.h"
-
#include "testing/gtest/include/gtest/gtest.h"
using syncable::Blob;
diff --git a/sync/engine/syncer_unittest.cc b/sync/engine/syncer_unittest.cc
index cce69aa..81dfec5 100644
--- a/sync/engine/syncer_unittest.cc
+++ b/sync/engine/syncer_unittest.cc
@@ -41,7 +41,9 @@
#include "sync/protocol/preference_specifics.pb.h"
#include "sync/protocol/sync.pb.h"
#include "sync/sessions/sync_session_context.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/mutable_entry.h"
+#include "sync/syncable/read_transaction.h"
+#include "sync/syncable/write_transaction.h"
#include "sync/test/engine/fake_model_worker.h"
#include "sync/test/engine/mock_connection_manager.h"
#include "sync/test/engine/test_directory_setter_upper.h"
@@ -77,7 +79,6 @@ using syncable::WriteTransaction;
using syncable::BASE_VERSION;
using syncable::CREATE;
-using syncable::CREATE_NEW_UPDATE_ITEM;
using syncable::GET_BY_HANDLE;
using syncable::GET_BY_ID;
using syncable::GET_BY_CLIENT_TAG;
@@ -95,7 +96,6 @@ using syncable::PARENT_ID;
using syncable::PREV_ID;
using syncable::BASE_SERVER_SPECIFICS;
using syncable::SERVER_IS_DEL;
-using syncable::SERVER_NON_UNIQUE_NAME;
using syncable::SERVER_PARENT_ID;
using syncable::SERVER_POSITION_IN_PARENT;
using syncable::SERVER_SPECIFICS;
diff --git a/sync/engine/syncer_util.cc b/sync/engine/syncer_util.cc
index 4f184bd..0f734cd 100644
--- a/sync/engine/syncer_util.cc
+++ b/sync/engine/syncer_util.cc
@@ -21,20 +21,22 @@
#include "sync/protocol/nigori_specifics.pb.h"
#include "sync/protocol/password_specifics.pb.h"
#include "sync/protocol/sync.pb.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/entry.h"
+#include "sync/syncable/mutable_entry.h"
+#include "sync/syncable/read_transaction.h"
#include "sync/syncable/syncable_changes_version.h"
+#include "sync/syncable/syncable_util.h"
+#include "sync/syncable/write_transaction.h"
#include "sync/util/cryptographer.h"
#include "sync/util/time.h"
using syncable::BASE_VERSION;
-using syncable::Blob;
using syncable::CHANGES_VERSION;
-using syncable::CREATE;
using syncable::CREATE_NEW_UPDATE_ITEM;
using syncable::CTIME;
using syncable::Directory;
using syncable::Entry;
-using syncable::GetModelTypeFromSpecifics;
using syncable::GET_BY_HANDLE;
using syncable::GET_BY_ID;
using syncable::ID;
@@ -43,11 +45,9 @@ using syncable::IS_DIR;
using syncable::IS_UNAPPLIED_UPDATE;
using syncable::IS_UNSYNCED;
using syncable::Id;
-using syncable::IsRealDataType;
using syncable::META_HANDLE;
using syncable::MTIME;
using syncable::MutableEntry;
-using syncable::NEXT_ID;
using syncable::NON_UNIQUE_NAME;
using syncable::BASE_SERVER_SPECIFICS;
using syncable::PARENT_ID;
diff --git a/sync/engine/syncer_util.h b/sync/engine/syncer_util.h
index 39c03bf..546ac3ff 100644
--- a/sync/engine/syncer_util.h
+++ b/sync/engine/syncer_util.h
@@ -15,7 +15,8 @@
#include "sync/engine/syncer.h"
#include "sync/engine/syncer_types.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/entry_kernel.h"
+#include "sync/syncable/metahandle_set.h"
#include "sync/syncable/syncable_id.h"
namespace browser_sync {
diff --git a/sync/engine/update_applicator.cc b/sync/engine/update_applicator.cc
index 5f510f3..921cfb5 100644
--- a/sync/engine/update_applicator.cc
+++ b/sync/engine/update_applicator.cc
@@ -9,8 +9,10 @@
#include "base/logging.h"
#include "sync/engine/syncer_util.h"
#include "sync/sessions/session_state.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/entry.h"
+#include "sync/syncable/mutable_entry.h"
#include "sync/syncable/syncable_id.h"
+#include "sync/syncable/write_transaction.h"
using std::vector;
diff --git a/sync/engine/update_applicator.h b/sync/engine/update_applicator.h
index 0e28180..cbd2b5e 100644
--- a/sync/engine/update_applicator.h
+++ b/sync/engine/update_applicator.h
@@ -17,7 +17,12 @@
#include "base/basictypes.h"
#include "base/port.h"
#include "sync/internal_api/public/engine/model_safe_worker.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/syncable_id.h"
+
+namespace syncable {
+class WriteTransaction;
+class Entry;
+}
namespace browser_sync {
diff --git a/sync/engine/verify_updates_command.cc b/sync/engine/verify_updates_command.cc
index 0ba0d16..40c75cf 100644
--- a/sync/engine/verify_updates_command.cc
+++ b/sync/engine/verify_updates_command.cc
@@ -14,15 +14,16 @@
#include "sync/engine/syncproto.h"
#include "sync/internal_api/public/engine/model_safe_worker.h"
#include "sync/protocol/bookmark_specifics.pb.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/entry.h"
+#include "sync/syncable/mutable_entry.h"
+#include "sync/syncable/write_transaction.h"
namespace browser_sync {
-using syncable::WriteTransaction;
-
using syncable::GET_BY_ID;
using syncable::ModelTypeSet;
using syncable::SYNCER;
+using syncable::WriteTransaction;
namespace {
diff --git a/sync/engine/verify_updates_command_unittest.cc b/sync/engine/verify_updates_command_unittest.cc
index 5f7356e..15324f4 100644
--- a/sync/engine/verify_updates_command_unittest.cc
+++ b/sync/engine/verify_updates_command_unittest.cc
@@ -7,7 +7,7 @@
#include "sync/protocol/bookmark_specifics.pb.h"
#include "sync/sessions/session_state.h"
#include "sync/sessions/sync_session.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/mutable_entry.h"
#include "sync/syncable/syncable_id.h"
#include "sync/test/engine/fake_model_worker.h"
#include "sync/test/engine/syncer_command_test.h"
@@ -15,13 +15,10 @@
namespace browser_sync {
-using sessions::SyncSession;
using sessions::StatusController;
using std::string;
-using syncable::Entry;
using syncable::Id;
using syncable::MutableEntry;
-using syncable::ReadTransaction;
using syncable::UNITTEST;
using syncable::WriteTransaction;
diff --git a/sync/internal_api/base_node.cc b/sync/internal_api/base_node.cc
index cfcddcd..a66d452 100644
--- a/sync/internal_api/base_node.cc
+++ b/sync/internal_api/base_node.cc
@@ -20,7 +20,8 @@
#include "sync/protocol/session_specifics.pb.h"
#include "sync/protocol/theme_specifics.pb.h"
#include "sync/protocol/typed_url_specifics.pb.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/entry.h"
#include "sync/syncable/syncable_id.h"
#include "sync/util/time.h"
diff --git a/sync/internal_api/base_transaction.cc b/sync/internal_api/base_transaction.cc
index 5fedc64..23b6944 100644
--- a/sync/internal_api/base_transaction.cc
+++ b/sync/internal_api/base_transaction.cc
@@ -4,7 +4,7 @@
#include "sync/internal_api/public/base_transaction.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
#include "sync/util/cryptographer.h"
using browser_sync::Cryptographer;
diff --git a/sync/internal_api/change_reorder_buffer.cc b/sync/internal_api/change_reorder_buffer.cc
index 34e44f6..5a53763 100644
--- a/sync/internal_api/change_reorder_buffer.cc
+++ b/sync/internal_api/change_reorder_buffer.cc
@@ -8,17 +8,17 @@
#include <queue>
#include <set>
#include <utility> // for pair<>
-#include <vector>
#include "sync/internal_api/public/read_node.h"
#include "sync/internal_api/public/syncable/model_type.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/base_transaction.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/entry.h"
using std::numeric_limits;
using std::pair;
using std::queue;
using std::set;
-using std::vector;
namespace sync_api {
diff --git a/sync/internal_api/public/base_transaction.h b/sync/internal_api/public/base_transaction.h
index 77e102a..e2ed24a 100644
--- a/sync/internal_api/public/base_transaction.h
+++ b/sync/internal_api/public/base_transaction.h
@@ -26,7 +26,7 @@ namespace sync_api {
// API BaseTransaction is created from a UserShare object.
class BaseTransaction {
public:
- // Provide access to the underlying syncable.h objects from BaseNode.
+ // Provide access to the underlying syncable objects from BaseNode.
virtual syncable::BaseTransaction* GetWrappedTrans() const = 0;
browser_sync::Cryptographer* GetCryptographer() const;
diff --git a/sync/internal_api/public/write_transaction.h b/sync/internal_api/public/write_transaction.h
index 1321ed1..fcc372d 100644
--- a/sync/internal_api/public/write_transaction.h
+++ b/sync/internal_api/public/write_transaction.h
@@ -32,7 +32,7 @@ class WriteTransaction : public BaseTransaction {
UserShare* share);
virtual ~WriteTransaction();
- // Provide access to the syncable.h transaction from the API WriteNode.
+ // Provide access to the syncable transaction from the API WriteNode.
virtual syncable::BaseTransaction* GetWrappedTrans() const OVERRIDE;
syncable::WriteTransaction* GetWrappedWriteTrans() { return transaction_; }
diff --git a/sync/internal_api/read_node.cc b/sync/internal_api/read_node.cc
index 970f981..f09f5f8 100644
--- a/sync/internal_api/read_node.cc
+++ b/sync/internal_api/read_node.cc
@@ -6,7 +6,8 @@
#include "base/logging.h"
#include "sync/internal_api/public/base_transaction.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/base_transaction.h"
+#include "sync/syncable/entry.h"
namespace sync_api {
diff --git a/sync/internal_api/read_transaction.cc b/sync/internal_api/read_transaction.cc
index 1af6c21..256193c 100644
--- a/sync/internal_api/read_transaction.cc
+++ b/sync/internal_api/read_transaction.cc
@@ -4,7 +4,7 @@
#include "sync/internal_api/public/read_transaction.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/read_transaction.h"
namespace sync_api {
diff --git a/sync/internal_api/sync_manager.cc b/sync/internal_api/sync_manager.cc
index 6982750..96a1ceb 100644
--- a/sync/internal_api/sync_manager.cc
+++ b/sync/internal_api/sync_manager.cc
@@ -52,8 +52,9 @@
#include "sync/protocol/encryption.pb.h"
#include "sync/protocol/proto_value_conversions.h"
#include "sync/protocol/sync.pb.h"
+#include "sync/syncable/directory.h"
#include "sync/syncable/directory_change_delegate.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/entry.h"
#include "sync/util/cryptographer.h"
#include "sync/util/get_session_name.h"
#include "sync/util/time.h"
diff --git a/sync/internal_api/syncapi_unittest.cc b/sync/internal_api/syncapi_unittest.cc
index 2aa44f0..b12c048 100644
--- a/sync/internal_api/syncapi_unittest.cc
+++ b/sync/internal_api/syncapi_unittest.cc
@@ -52,8 +52,11 @@
#include "sync/protocol/proto_value_conversions.h"
#include "sync/protocol/sync.pb.h"
#include "sync/sessions/sync_session.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/entry.h"
+#include "sync/syncable/mutable_entry.h"
#include "sync/syncable/syncable_id.h"
+#include "sync/syncable/write_transaction.h"
#include "sync/test/fake_encryptor.h"
#include "sync/test/fake_extensions_activity_monitor.h"
#include "sync/util/cryptographer.h"
diff --git a/sync/internal_api/test/test_user_share.cc b/sync/internal_api/test/test_user_share.cc
index c028d66..2fc0d60 100644
--- a/sync/internal_api/test/test_user_share.cc
+++ b/sync/internal_api/test/test_user_share.cc
@@ -5,6 +5,7 @@
#include "sync/internal_api/public/test/test_user_share.h"
#include "base/compiler_specific.h"
+#include "sync/syncable/directory.h"
#include "sync/test/engine/test_directory_setter_upper.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/sync/internal_api/user_share.cc b/sync/internal_api/user_share.cc
index 9bf0b46..57b26bc 100644
--- a/sync/internal_api/user_share.cc
+++ b/sync/internal_api/user_share.cc
@@ -4,7 +4,7 @@
#include "sync/internal_api/public/user_share.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
namespace sync_api {
diff --git a/sync/internal_api/write_node.cc b/sync/internal_api/write_node.cc
index bbd3035..e281fcd 100644
--- a/sync/internal_api/write_node.cc
+++ b/sync/internal_api/write_node.cc
@@ -18,7 +18,7 @@
#include "sync/protocol/session_specifics.pb.h"
#include "sync/protocol/theme_specifics.pb.h"
#include "sync/protocol/typed_url_specifics.pb.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/mutable_entry.h"
#include "sync/util/cryptographer.h"
using browser_sync::Cryptographer;
diff --git a/sync/internal_api/write_transaction.cc b/sync/internal_api/write_transaction.cc
index a354bcd..867a88c 100644
--- a/sync/internal_api/write_transaction.cc
+++ b/sync/internal_api/write_transaction.cc
@@ -4,7 +4,7 @@
#include "sync/internal_api/public/write_transaction.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/write_transaction.h"
namespace sync_api {
diff --git a/sync/sessions/sync_session.cc b/sync/sessions/sync_session.cc
index 36bc2ca..eed4f88 100644
--- a/sync/sessions/sync_session.cc
+++ b/sync/sessions/sync_session.cc
@@ -9,7 +9,7 @@
#include "base/logging.h"
#include "sync/internal_api/public/syncable/model_type.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
namespace browser_sync {
namespace sessions {
diff --git a/sync/sessions/sync_session_unittest.cc b/sync/sessions/sync_session_unittest.cc
index aa3dd7e..fa5e986 100644
--- a/sync/sessions/sync_session_unittest.cc
+++ b/sync/sessions/sync_session_unittest.cc
@@ -14,8 +14,8 @@
#include "sync/internal_api/public/syncable/model_type.h"
#include "sync/sessions/session_state.h"
#include "sync/sessions/status_controller.h"
-#include "sync/syncable/syncable.h"
#include "sync/syncable/syncable_id.h"
+#include "sync/syncable/write_transaction.h"
#include "sync/test/engine/fake_model_worker.h"
#include "sync/test/engine/test_directory_setter_upper.h"
#include "sync/test/fake_extensions_activity_monitor.h"
diff --git a/sync/sync.gyp b/sync/sync.gyp
index 318f34a..8202ea2 100644
--- a/sync/sync.gyp
+++ b/sync/sync.gyp
@@ -148,26 +148,44 @@
'sessions/sync_session.h',
'sessions/sync_session_context.cc',
'sessions/sync_session_context.h',
+ 'syncable/base_transaction.cc',
+ 'syncable/base_transaction.h',
'syncable/blob.h',
+ 'syncable/dir_open_result.h',
+ 'syncable/directory.cc',
+ 'syncable/directory.h',
'syncable/directory_backing_store.cc',
'syncable/directory_backing_store.h',
'syncable/directory_change_delegate.h',
- 'syncable/dir_open_result.h',
+ 'syncable/entry.cc',
+ 'syncable/entry.h',
+ 'syncable/entry_kernel.cc',
+ 'syncable/entry_kernel.h',
'syncable/in_memory_directory_backing_store.cc',
'syncable/in_memory_directory_backing_store.h',
+ 'syncable/metahandle_set.h',
'syncable/model_type.cc',
+ 'syncable/mutable_entry.cc',
+ 'syncable/mutable_entry.h',
'syncable/on_disk_directory_backing_store.cc',
'syncable/on_disk_directory_backing_store.h',
- 'syncable/syncable.cc',
+ 'syncable/read_transaction.cc',
+ 'syncable/read_transaction.h',
+ 'syncable/scoped_kernel_lock.h',
+ 'syncable/syncable-inl.h',
'syncable/syncable_changes_version.h',
'syncable/syncable_columns.h',
'syncable/syncable_enum_conversions.cc',
'syncable/syncable_enum_conversions.h',
- 'syncable/syncable.h',
'syncable/syncable_id.cc',
'syncable/syncable_id.h',
- 'syncable/syncable-inl.h',
+ 'syncable/syncable_util.cc',
+ 'syncable/syncable_util.h',
'syncable/transaction_observer.h',
+ 'syncable/write_transaction.cc',
+ 'syncable/write_transaction.h',
+ 'syncable/write_transaction_info.cc',
+ 'syncable/write_transaction_info.h',
'util/cryptographer.cc',
'util/cryptographer.h',
diff --git a/sync/syncable/base_transaction.cc b/sync/syncable/base_transaction.cc
new file mode 100644
index 0000000..b27e31a
--- /dev/null
+++ b/sync/syncable/base_transaction.cc
@@ -0,0 +1,68 @@
+// Copyright (c) 2012 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 "sync/syncable/base_transaction.h"
+
+#include "base/debug/trace_event.h"
+#include "sync/syncable/directory.h"
+
+namespace syncable {
+
+void BaseTransaction::Lock() {
+ TRACE_EVENT2("sync_lock_contention", "AcquireLock",
+ "src_file", from_here_.file_name(),
+ "src_func", from_here_.function_name());
+
+ directory_->kernel_->transaction_mutex.Acquire();
+}
+
+void BaseTransaction::Unlock() {
+ directory_->kernel_->transaction_mutex.Release();
+}
+
+void BaseTransaction::OnUnrecoverableError(
+ const tracked_objects::Location& location,
+ const std::string& message) {
+ unrecoverable_error_set_ = true;
+ unrecoverable_error_location_ = location;
+ unrecoverable_error_msg_ = message;
+
+ // Note: We dont call the Directory's OnUnrecoverableError method right
+ // away. Instead we wait to unwind the stack and in the destructor of the
+ // transaction we would call the OnUnrecoverableError method.
+
+ directory()->ReportUnrecoverableError();
+}
+
+bool BaseTransaction::unrecoverable_error_set() const {
+ return unrecoverable_error_set_;
+}
+
+void BaseTransaction::HandleUnrecoverableErrorIfSet() {
+ if (unrecoverable_error_set_) {
+ directory()->OnUnrecoverableError(this,
+ unrecoverable_error_location_,
+ unrecoverable_error_msg_);
+ }
+}
+
+BaseTransaction::BaseTransaction(const tracked_objects::Location& from_here,
+ const char* name,
+ WriterTag writer,
+ Directory* directory)
+ : from_here_(from_here), name_(name), writer_(writer),
+ directory_(directory), unrecoverable_error_set_(false) {
+ // TODO(lipalani): Don't issue a good transaction if the directory has
+ // unrecoverable error set. And the callers have to check trans.good before
+ // proceeding.
+ TRACE_EVENT_BEGIN2("sync", name_,
+ "src_file", from_here_.file_name(),
+ "src_func", from_here_.function_name());
+}
+
+BaseTransaction::~BaseTransaction() {
+ TRACE_EVENT_END0("sync", name_);
+}
+
+} // namespace syncable
diff --git a/sync/syncable/base_transaction.h b/sync/syncable/base_transaction.h
new file mode 100644
index 0000000..2de4608
--- /dev/null
+++ b/sync/syncable/base_transaction.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2012 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 SYNC_SYNCABLE_BASE_TRANSACTION_H_
+#define SYNC_SYNCABLE_BASE_TRANSACTION_H_
+#pragma once
+
+#include "base/location.h"
+#include "sync/syncable/syncable_id.h"
+
+namespace syncable {
+
+class Directory;
+
+// A WriteTransaction has a writer tag describing which body of code is doing
+// the write. This is defined up here since WriteTransactionInfo also contains
+// one.
+enum WriterTag {
+ INVALID,
+ SYNCER,
+ AUTHWATCHER,
+ UNITTEST,
+ VACUUM_AFTER_SAVE,
+ PURGE_ENTRIES,
+ SYNCAPI
+};
+
+// Make sure to update this if you update WriterTag.
+std::string WriterTagToString(WriterTag writer_tag);
+
+class BaseTransaction {
+ public:
+ inline Directory* directory() const { return directory_; }
+ inline Id root_id() const { return Id(); }
+
+ virtual ~BaseTransaction();
+
+ // This should be called when a database corruption is detected and there is
+ // no way for us to recover short of wiping the database clean. When this is
+ // called we set a bool in the transaction. The caller has to unwind the
+ // stack. When the destructor for the transaction is called it acts upon the
+ // bool and calls the Directory to handle the unrecoverable error.
+ void OnUnrecoverableError(const tracked_objects::Location& location,
+ const std::string& message);
+
+ bool unrecoverable_error_set() const;
+
+ protected:
+ BaseTransaction(const tracked_objects::Location& from_here,
+ const char* name,
+ WriterTag writer,
+ Directory* directory);
+
+ void Lock();
+ void Unlock();
+
+ // This should be called before unlocking because it calls the Direcotry's
+ // OnUnrecoverableError method which is not protected by locks and could
+ // be called from any thread. Holding the transaction lock ensures only one
+ // thread could call the method at a time.
+ void HandleUnrecoverableErrorIfSet();
+
+ const tracked_objects::Location from_here_;
+ const char* const name_;
+ WriterTag writer_;
+ Directory* const directory_;
+
+ // Error information.
+ bool unrecoverable_error_set_;
+ tracked_objects::Location unrecoverable_error_location_;
+ std::string unrecoverable_error_msg_;
+
+ private:
+ friend class Entry;
+ DISALLOW_COPY_AND_ASSIGN(BaseTransaction);
+};
+
+}
+
+#endif // SYNC_SYNCABLE_BASE_TRANSACTION_H_
diff --git a/sync/syncable/syncable.cc b/sync/syncable/directory.cc
index 7bf16fc..40179b2 100644
--- a/sync/syncable/syncable.cc
+++ b/sync/syncable/directory.cc
@@ -2,61 +2,45 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "sync/syncable/syncable.h"
-
-#include <algorithm>
-#include <cstring>
-#include <functional>
-#include <iomanip>
-#include <iterator>
-#include <limits>
-#include <set>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/debug/trace_event.h"
+#include "sync/syncable/directory.h"
+
#include "base/debug/trace_event.h"
-#include "base/file_util.h"
-#include "base/hash_tables.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
#include "base/perftimer.h"
#include "base/stl_util.h"
#include "base/string_number_conversions.h"
-#include "base/string_util.h"
-#include "base/time.h"
-#include "base/utf_string_conversions.h"
-#include "base/values.h"
-#include "net/base/escape.h"
-#include "sync/internal_api/public/syncable/model_type.h"
-#include "sync/protocol/proto_value_conversions.h"
-#include "sync/syncable/directory_backing_store.h"
-#include "sync/syncable/directory_change_delegate.h"
+#include "sync/internal_api/public/util/unrecoverable_error_handler.h"
+#include "sync/syncable/base_transaction.h"
+#include "sync/syncable/entry.h"
+#include "sync/syncable/entry_kernel.h"
#include "sync/syncable/in_memory_directory_backing_store.h"
#include "sync/syncable/on_disk_directory_backing_store.h"
+#include "sync/syncable/read_transaction.h"
+#include "sync/syncable/scoped_index_updater.h"
#include "sync/syncable/syncable-inl.h"
#include "sync/syncable/syncable_changes_version.h"
-#include "sync/syncable/syncable_columns.h"
-#include "sync/syncable/syncable_enum_conversions.h"
-#include "sync/syncable/transaction_observer.h"
-#include "sync/util/cryptographer.h"
-#include "sync/util/logging.h"
-
-namespace {
+#include "sync/syncable/syncable_util.h"
+#include "sync/syncable/write_transaction.h"
-enum InvariantCheckLevel {
- OFF = 0,
- VERIFY_IN_MEMORY = 1,
- FULL_DB_VERIFICATION = 2
-};
+using browser_sync::Encryptor;
+using browser_sync::ReportUnrecoverableErrorFunction;
+using browser_sync::UnrecoverableErrorHandler;
+using std::string;
-const InvariantCheckLevel kInvariantCheckLevel = VERIFY_IN_MEMORY;
+namespace syncable {
+namespace {
// Max number of milliseconds to spend checking syncable entry invariants
const int kInvariantCheckMaxMs = 50;
+// Helper function to add an item to the index, if it ought to be added.
+template<typename Indexer>
+void InitializeIndexEntry(EntryKernel* entry,
+ typename Index<Indexer>::Set* index) {
+ if (Indexer::ShouldInclude(entry)) {
+ index->insert(entry);
+ }
+}
+
// This function checks to see if the given list of Metahandles has any nodes
// whose PREV_ID, PARENT_ID or NEXT_ID values refer to ID values that do not
// actually exist. Returns true on success.
@@ -92,161 +76,8 @@ bool VerifyReferenceIntegrityUnsafe(const syncable::MetahandlesIndex &index) {
return is_ok;
}
-} // namespace
-
-using std::string;
-using browser_sync::Encryptor;
-using browser_sync::ReportUnrecoverableErrorFunction;
-using browser_sync::UnrecoverableErrorHandler;
-
-namespace syncable {
-
-namespace {
-
-// Function to handle runtime failures on syncable code. Rather than crashing,
-// if the |condition| is false the following will happen:
-// 1. Sets unrecoverable error on transaction.
-// 2. Returns false.
-bool SyncAssert(bool condition,
- const tracked_objects::Location& location,
- const char* msg,
- BaseTransaction* trans) {
- if (!condition) {
- trans->OnUnrecoverableError(location, msg);
- return false;
- }
- return true;
-}
-
-} // namespace
-
-#define ENUM_CASE(x) case x: return #x; break
-
-std::string WriterTagToString(WriterTag writer_tag) {
- switch (writer_tag) {
- ENUM_CASE(INVALID);
- ENUM_CASE(SYNCER);
- ENUM_CASE(AUTHWATCHER);
- ENUM_CASE(UNITTEST);
- ENUM_CASE(VACUUM_AFTER_SAVE);
- ENUM_CASE(PURGE_ENTRIES);
- ENUM_CASE(SYNCAPI);
- };
- NOTREACHED();
- return "";
-}
-
-#undef ENUM_CASE
-
-WriteTransactionInfo::WriteTransactionInfo(
- int64 id,
- tracked_objects::Location location,
- WriterTag writer,
- ImmutableEntryKernelMutationMap mutations)
- : id(id),
- location_string(location.ToString()),
- writer(writer),
- mutations(mutations) {}
-
-WriteTransactionInfo::WriteTransactionInfo()
- : id(-1), writer(INVALID) {}
-
-WriteTransactionInfo::~WriteTransactionInfo() {}
-
-base::DictionaryValue* WriteTransactionInfo::ToValue(
- size_t max_mutations_size) const {
- DictionaryValue* dict = new DictionaryValue();
- dict->SetString("id", base::Int64ToString(id));
- dict->SetString("location", location_string);
- dict->SetString("writer", WriterTagToString(writer));
- Value* mutations_value = NULL;
- const size_t mutations_size = mutations.Get().size();
- if (mutations_size <= max_mutations_size) {
- mutations_value = EntryKernelMutationMapToValue(mutations.Get());
- } else {
- mutations_value =
- Value::CreateStringValue(
- base::Uint64ToString(static_cast<uint64>(mutations_size)) +
- " mutations");
- }
- dict->Set("mutations", mutations_value);
- return dict;
-}
-
-DictionaryValue* EntryKernelMutationToValue(
- const EntryKernelMutation& mutation) {
- DictionaryValue* dict = new DictionaryValue();
- dict->Set("original", mutation.original.ToValue());
- dict->Set("mutated", mutation.mutated.ToValue());
- return dict;
-}
-
-ListValue* EntryKernelMutationMapToValue(
- const EntryKernelMutationMap& mutations) {
- ListValue* list = new ListValue();
- for (EntryKernelMutationMap::const_iterator it = mutations.begin();
- it != mutations.end(); ++it) {
- list->Append(EntryKernelMutationToValue(it->second));
- }
- return list;
-}
-
-namespace {
-
-// A ScopedIndexUpdater temporarily removes an entry from an index,
-// and restores it to the index when the scope exits. This simplifies
-// the common pattern where items need to be removed from an index
-// before updating the field.
-//
-// This class is parameterized on the Indexer traits type, which
-// must define a Comparator and a static bool ShouldInclude
-// function for testing whether the item ought to be included
-// in the index.
-template<typename Indexer>
-class ScopedIndexUpdater {
- public:
- ScopedIndexUpdater(const ScopedKernelLock& proof_of_lock,
- EntryKernel* entry,
- typename Index<Indexer>::Set* index)
- : entry_(entry),
- index_(index) {
- // First call to ShouldInclude happens before the field is updated.
- if (Indexer::ShouldInclude(entry_)) {
- // TODO(lipalani): Replace this CHECK with |SyncAssert| by refactorting
- // this class into a function.
- CHECK(index_->erase(entry_));
- }
- }
-
- ~ScopedIndexUpdater() {
- // Second call to ShouldInclude happens after the field is updated.
- if (Indexer::ShouldInclude(entry_)) {
- // TODO(lipalani): Replace this CHECK with |SyncAssert| by refactorting
- // this class into a function.
- CHECK(index_->insert(entry_).second);
- }
- }
- private:
- // The entry that was temporarily removed from the index.
- EntryKernel* entry_;
- // The index which we are updating.
- typename Index<Indexer>::Set* const index_;
-};
-
-// Helper function to add an item to the index, if it ought to be added.
-template<typename Indexer>
-void InitializeIndexEntry(EntryKernel* entry,
- typename Index<Indexer>::Set* index) {
- if (Indexer::ShouldInclude(entry)) {
- index->insert(entry);
- }
}
-} // namespace
-
-///////////////////////////////////////////////////////////////////////////
-// Comparator and filter functions for the indices.
-
// static
bool ClientTagIndexer::ShouldInclude(const EntryKernel* a) {
return !a->ref(UNIQUE_CLIENT_TAG).empty();
@@ -275,132 +106,6 @@ bool ParentIdAndHandleIndexer::ShouldInclude(const EntryKernel* a) {
return !a->ref(IS_DEL) && !a->ref(ID).IsRoot();
}
-///////////////////////////////////////////////////////////////////////////
-// EntryKernel
-
-EntryKernel::EntryKernel() : dirty_(false) {
- // Everything else should already be default-initialized.
- for (int i = INT64_FIELDS_BEGIN; i < INT64_FIELDS_END; ++i) {
- int64_fields[i] = 0;
- }
-}
-
-EntryKernel::~EntryKernel() {}
-
-syncable::ModelType EntryKernel::GetServerModelType() const {
- ModelType specifics_type = GetModelTypeFromSpecifics(ref(SERVER_SPECIFICS));
- if (specifics_type != UNSPECIFIED)
- return specifics_type;
- if (ref(ID).IsRoot())
- return TOP_LEVEL_FOLDER;
- // Loose check for server-created top-level folders that aren't
- // bound to a particular model type.
- if (!ref(UNIQUE_SERVER_TAG).empty() && ref(SERVER_IS_DIR))
- return TOP_LEVEL_FOLDER;
-
- return UNSPECIFIED;
-}
-
-namespace {
-
-// Utility function to loop through a set of enum values and add the
-// field keys/values in the kernel to the given dictionary.
-//
-// V should be convertible to Value.
-template <class T, class U, class V>
-void SetFieldValues(const EntryKernel& kernel,
- DictionaryValue* dictionary_value,
- const char* (*enum_key_fn)(T),
- V* (*enum_value_fn)(U),
- int field_key_min, int field_key_max) {
- DCHECK_LE(field_key_min, field_key_max);
- for (int i = field_key_min; i <= field_key_max; ++i) {
- T field = static_cast<T>(i);
- const std::string& key = enum_key_fn(field);
- V* value = enum_value_fn(kernel.ref(field));
- dictionary_value->Set(key, value);
- }
-}
-
-// Helper functions for SetFieldValues().
-
-StringValue* Int64ToValue(int64 i) {
- return Value::CreateStringValue(base::Int64ToString(i));
-}
-
-StringValue* TimeToValue(const base::Time& t) {
- return Value::CreateStringValue(browser_sync::GetTimeDebugString(t));
-}
-
-StringValue* IdToValue(const Id& id) {
- return id.ToValue();
-}
-
-} // namespace
-
-DictionaryValue* EntryKernel::ToValue() const {
- DictionaryValue* kernel_info = new DictionaryValue();
- kernel_info->SetBoolean("isDirty", is_dirty());
- kernel_info->Set("serverModelType", ModelTypeToValue(GetServerModelType()));
-
- // Int64 fields.
- SetFieldValues(*this, kernel_info,
- &GetMetahandleFieldString, &Int64ToValue,
- INT64_FIELDS_BEGIN, META_HANDLE);
- SetFieldValues(*this, kernel_info,
- &GetBaseVersionString, &Int64ToValue,
- META_HANDLE + 1, BASE_VERSION);
- SetFieldValues(*this, kernel_info,
- &GetInt64FieldString, &Int64ToValue,
- BASE_VERSION + 1, INT64_FIELDS_END - 1);
-
- // Time fields.
- SetFieldValues(*this, kernel_info,
- &GetTimeFieldString, &TimeToValue,
- TIME_FIELDS_BEGIN, TIME_FIELDS_END - 1);
-
- // ID fields.
- SetFieldValues(*this, kernel_info,
- &GetIdFieldString, &IdToValue,
- ID_FIELDS_BEGIN, ID_FIELDS_END - 1);
-
- // Bit fields.
- SetFieldValues(*this, kernel_info,
- &GetIndexedBitFieldString, &Value::CreateBooleanValue,
- BIT_FIELDS_BEGIN, INDEXED_BIT_FIELDS_END - 1);
- SetFieldValues(*this, kernel_info,
- &GetIsDelFieldString, &Value::CreateBooleanValue,
- INDEXED_BIT_FIELDS_END, IS_DEL);
- SetFieldValues(*this, kernel_info,
- &GetBitFieldString, &Value::CreateBooleanValue,
- IS_DEL + 1, BIT_FIELDS_END - 1);
-
- // String fields.
- {
- // Pick out the function overload we want.
- StringValue* (*string_to_value)(const std::string&) =
- &Value::CreateStringValue;
- SetFieldValues(*this, kernel_info,
- &GetStringFieldString, string_to_value,
- STRING_FIELDS_BEGIN, STRING_FIELDS_END - 1);
- }
-
- // Proto fields.
- SetFieldValues(*this, kernel_info,
- &GetProtoFieldString, &browser_sync::EntitySpecificsToValue,
- PROTO_FIELDS_BEGIN, PROTO_FIELDS_END - 1);
-
- // Bit temps.
- SetFieldValues(*this, kernel_info,
- &GetBitTempString, &Value::CreateBooleanValue,
- BIT_TEMPS_BEGIN, BIT_TEMPS_END - 1);
-
- return kernel_info;
-}
-
-///////////////////////////////////////////////////////////////////////////
-// Directory
-
// static
const FilePath::CharType Directory::kSyncDatabaseFilename[] =
FILE_PATH_LITERAL("SyncData.sqlite3");
@@ -1161,7 +866,6 @@ void Directory::GetUnappliedUpdateMetaHandles(
}
}
-
class IdFilter {
public:
virtual ~IdFilter() { }
@@ -1370,613 +1074,6 @@ bool Directory::CheckTreeInvariants(syncable::BaseTransaction* trans,
return true;
}
-///////////////////////////////////////////////////////////////////////////////
-// ScopedKernelLock
-
-ScopedKernelLock::ScopedKernelLock(const Directory* dir)
- : scoped_lock_(dir->kernel_->mutex), dir_(const_cast<Directory*>(dir)) {
-}
-
-///////////////////////////////////////////////////////////////////////////
-// Transactions
-
-void BaseTransaction::Lock() {
- TRACE_EVENT2("sync_lock_contention", "AcquireLock",
- "src_file", from_here_.file_name(),
- "src_func", from_here_.function_name());
-
- dirkernel_->transaction_mutex.Acquire();
-}
-
-void BaseTransaction::Unlock() {
- dirkernel_->transaction_mutex.Release();
-}
-
-void BaseTransaction::OnUnrecoverableError(
- const tracked_objects::Location& location,
- const std::string& message) {
- unrecoverable_error_set_ = true;
- unrecoverable_error_location_ = location;
- unrecoverable_error_msg_ = message;
-
- // Note: We dont call the Directory's OnUnrecoverableError method right
- // away. Instead we wait to unwind the stack and in the destructor of the
- // transaction we would call the OnUnrecoverableError method.
-
- directory()->ReportUnrecoverableError();
-}
-
-bool BaseTransaction::unrecoverable_error_set() const {
- return unrecoverable_error_set_;
-}
-
-void BaseTransaction::HandleUnrecoverableErrorIfSet() {
- if (unrecoverable_error_set_) {
- directory()->OnUnrecoverableError(this,
- unrecoverable_error_location_,
- unrecoverable_error_msg_);
- }
-}
-
-BaseTransaction::BaseTransaction(const tracked_objects::Location& from_here,
- const char* name,
- WriterTag writer,
- Directory* directory)
- : from_here_(from_here), name_(name), writer_(writer),
- directory_(directory), dirkernel_(directory->kernel_),
- unrecoverable_error_set_(false) {
- // TODO(lipalani): Don't issue a good transaction if the directory has
- // unrecoverable error set. And the callers have to check trans.good before
- // proceeding.
- TRACE_EVENT_BEGIN2("sync", name_,
- "src_file", from_here_.file_name(),
- "src_func", from_here_.function_name());
-}
-
-BaseTransaction::~BaseTransaction() {
- TRACE_EVENT_END0("sync", name_);
-}
-
-ReadTransaction::ReadTransaction(const tracked_objects::Location& location,
- Directory* directory)
- : BaseTransaction(location, "ReadTransaction", INVALID, directory) {
- Lock();
-}
-
-ReadTransaction::~ReadTransaction() {
- HandleUnrecoverableErrorIfSet();
- Unlock();
-}
-
-WriteTransaction::WriteTransaction(const tracked_objects::Location& location,
- WriterTag writer, Directory* directory)
- : BaseTransaction(location, "WriteTransaction", writer, directory) {
- Lock();
-}
-
-void WriteTransaction::SaveOriginal(const EntryKernel* entry) {
- if (!entry) {
- return;
- }
- // Insert only if it's not already there.
- const int64 handle = entry->ref(META_HANDLE);
- EntryKernelMutationMap::iterator it = mutations_.lower_bound(handle);
- if (it == mutations_.end() || it->first != handle) {
- EntryKernelMutation mutation;
- mutation.original = *entry;
- ignore_result(mutations_.insert(it, std::make_pair(handle, mutation)));
- }
-}
-
-ImmutableEntryKernelMutationMap WriteTransaction::RecordMutations() {
- dirkernel_->transaction_mutex.AssertAcquired();
- for (syncable::EntryKernelMutationMap::iterator it = mutations_.begin();
- it != mutations_.end();) {
- EntryKernel* kernel = directory()->GetEntryByHandle(it->first);
- if (!kernel) {
- NOTREACHED();
- continue;
- }
- if (kernel->is_dirty()) {
- it->second.mutated = *kernel;
- ++it;
- } else {
- DCHECK(!it->second.original.is_dirty());
- // Not actually mutated, so erase from |mutations_|.
- mutations_.erase(it++);
- }
- }
- return ImmutableEntryKernelMutationMap(&mutations_);
-}
-
-void WriteTransaction::UnlockAndNotify(
- const ImmutableEntryKernelMutationMap& mutations) {
- // Work while transaction mutex is held.
- ModelTypeSet models_with_changes;
- bool has_mutations = !mutations.Get().empty();
- if (has_mutations) {
- models_with_changes = NotifyTransactionChangingAndEnding(mutations);
- }
- Unlock();
-
- // Work after mutex is relased.
- if (has_mutations) {
- NotifyTransactionComplete(models_with_changes);
- }
-}
-
-ModelTypeSet WriteTransaction::NotifyTransactionChangingAndEnding(
- const ImmutableEntryKernelMutationMap& mutations) {
- dirkernel_->transaction_mutex.AssertAcquired();
- DCHECK(!mutations.Get().empty());
-
- WriteTransactionInfo write_transaction_info(
- dirkernel_->next_write_transaction_id, from_here_, writer_, mutations);
- ++dirkernel_->next_write_transaction_id;
-
- ImmutableWriteTransactionInfo immutable_write_transaction_info(
- &write_transaction_info);
- DirectoryChangeDelegate* const delegate = dirkernel_->delegate;
- if (writer_ == syncable::SYNCAPI) {
- delegate->HandleCalculateChangesChangeEventFromSyncApi(
- immutable_write_transaction_info, this);
- } else {
- delegate->HandleCalculateChangesChangeEventFromSyncer(
- immutable_write_transaction_info, this);
- }
-
- ModelTypeSet models_with_changes =
- delegate->HandleTransactionEndingChangeEvent(
- immutable_write_transaction_info, this);
-
- dirkernel_->transaction_observer.Call(FROM_HERE,
- &TransactionObserver::OnTransactionWrite,
- immutable_write_transaction_info, models_with_changes);
-
- return models_with_changes;
-}
-
-void WriteTransaction::NotifyTransactionComplete(
- ModelTypeSet models_with_changes) {
- dirkernel_->delegate->HandleTransactionCompleteChangeEvent(
- models_with_changes);
-}
-
-WriteTransaction::~WriteTransaction() {
- const ImmutableEntryKernelMutationMap& mutations = RecordMutations();
-
- if (!unrecoverable_error_set_) {
- if (OFF != kInvariantCheckLevel) {
- const bool full_scan = (FULL_DB_VERIFICATION == kInvariantCheckLevel);
- if (full_scan)
- directory()->CheckTreeInvariants(this, full_scan);
- else
- directory()->CheckTreeInvariants(this, mutations.Get());
- }
- }
-
- // |CheckTreeInvariants| could have thrown an unrecoverable error.
- if (unrecoverable_error_set_) {
- HandleUnrecoverableErrorIfSet();
- Unlock();
- return;
- }
-
- UnlockAndNotify(mutations);
-}
-
-///////////////////////////////////////////////////////////////////////////
-// Entry
-
-Entry::Entry(BaseTransaction* trans, GetById, const Id& id)
- : basetrans_(trans) {
- kernel_ = trans->directory()->GetEntryById(id);
-}
-
-Entry::Entry(BaseTransaction* trans, GetByClientTag, const string& tag)
- : basetrans_(trans) {
- kernel_ = trans->directory()->GetEntryByClientTag(tag);
-}
-
-Entry::Entry(BaseTransaction* trans, GetByServerTag, const string& tag)
- : basetrans_(trans) {
- kernel_ = trans->directory()->GetEntryByServerTag(tag);
-}
-
-Entry::Entry(BaseTransaction* trans, GetByHandle, int64 metahandle)
- : basetrans_(trans) {
- kernel_ = trans->directory()->GetEntryByHandle(metahandle);
-}
-
-Directory* Entry::dir() const {
- return basetrans_->directory();
-}
-
-Id Entry::ComputePrevIdFromServerPosition(const Id& parent_id) const {
- return dir()->ComputePrevIdFromServerPosition(kernel_, parent_id);
-}
-
-DictionaryValue* Entry::ToValue() const {
- DictionaryValue* entry_info = new DictionaryValue();
- entry_info->SetBoolean("good", good());
- if (good()) {
- entry_info->Set("kernel", kernel_->ToValue());
- entry_info->Set("modelType",
- ModelTypeToValue(GetModelType()));
- entry_info->SetBoolean("existsOnClientBecauseNameIsNonEmpty",
- ExistsOnClientBecauseNameIsNonEmpty());
- entry_info->SetBoolean("isRoot", IsRoot());
- }
- return entry_info;
-}
-
-const string& Entry::Get(StringField field) const {
- DCHECK(kernel_);
- return kernel_->ref(field);
-}
-
-syncable::ModelType Entry::GetServerModelType() const {
- ModelType specifics_type = kernel_->GetServerModelType();
- if (specifics_type != UNSPECIFIED)
- return specifics_type;
-
- // Otherwise, we don't have a server type yet. That should only happen
- // if the item is an uncommitted locally created item.
- // It's possible we'll need to relax these checks in the future; they're
- // just here for now as a safety measure.
- DCHECK(Get(IS_UNSYNCED));
- DCHECK_EQ(Get(SERVER_VERSION), 0);
- DCHECK(Get(SERVER_IS_DEL));
- // Note: can't enforce !Get(ID).ServerKnows() here because that could
- // actually happen if we hit AttemptReuniteLostCommitResponses.
- return UNSPECIFIED;
-}
-
-syncable::ModelType Entry::GetModelType() const {
- ModelType specifics_type = GetModelTypeFromSpecifics(Get(SPECIFICS));
- if (specifics_type != UNSPECIFIED)
- return specifics_type;
- if (IsRoot())
- return TOP_LEVEL_FOLDER;
- // Loose check for server-created top-level folders that aren't
- // bound to a particular model type.
- if (!Get(UNIQUE_SERVER_TAG).empty() && Get(IS_DIR))
- return TOP_LEVEL_FOLDER;
-
- return UNSPECIFIED;
-}
-
-///////////////////////////////////////////////////////////////////////////
-// MutableEntry
-
-MutableEntry::MutableEntry(WriteTransaction* trans, Create,
- const Id& parent_id, const string& name)
- : Entry(trans),
- write_transaction_(trans) {
- Init(trans, parent_id, name);
-}
-
-
-void MutableEntry::Init(WriteTransaction* trans, const Id& parent_id,
- const string& name) {
- scoped_ptr<EntryKernel> kernel(new EntryKernel);
- kernel_ = NULL;
-
- kernel->put(ID, trans->directory_->NextId());
- kernel->put(META_HANDLE, trans->directory_->NextMetahandle());
- kernel->mark_dirty(trans->directory_->kernel_->dirty_metahandles);
- kernel->put(PARENT_ID, parent_id);
- kernel->put(NON_UNIQUE_NAME, name);
- const base::Time& now = base::Time::Now();
- kernel->put(CTIME, now);
- kernel->put(MTIME, now);
- // We match the database defaults here
- kernel->put(BASE_VERSION, CHANGES_VERSION);
- if (!trans->directory()->InsertEntry(trans, kernel.get())) {
- return; // We failed inserting, nothing more to do.
- }
- // Because this entry is new, it was originally deleted.
- kernel->put(IS_DEL, true);
- trans->SaveOriginal(kernel.get());
- kernel->put(IS_DEL, false);
-
- // Now swap the pointers.
- kernel_ = kernel.release();
-}
-
-MutableEntry::MutableEntry(WriteTransaction* trans, CreateNewUpdateItem,
- const Id& id)
- : Entry(trans), write_transaction_(trans) {
- Entry same_id(trans, GET_BY_ID, id);
- kernel_ = NULL;
- if (same_id.good()) {
- return; // already have an item with this ID.
- }
- scoped_ptr<EntryKernel> kernel(new EntryKernel());
-
- kernel->put(ID, id);
- kernel->put(META_HANDLE, trans->directory_->NextMetahandle());
- kernel->mark_dirty(trans->directory_->kernel_->dirty_metahandles);
- kernel->put(IS_DEL, true);
- // We match the database defaults here
- kernel->put(BASE_VERSION, CHANGES_VERSION);
- if (!trans->directory()->InsertEntry(trans, kernel.get())) {
- return; // Failed inserting.
- }
- trans->SaveOriginal(kernel.get());
-
- kernel_ = kernel.release();
-}
-
-MutableEntry::MutableEntry(WriteTransaction* trans, GetById, const Id& id)
- : Entry(trans, GET_BY_ID, id), write_transaction_(trans) {
-}
-
-MutableEntry::MutableEntry(WriteTransaction* trans, GetByHandle,
- int64 metahandle)
- : Entry(trans, GET_BY_HANDLE, metahandle), write_transaction_(trans) {
-}
-
-MutableEntry::MutableEntry(WriteTransaction* trans, GetByClientTag,
- const std::string& tag)
- : Entry(trans, GET_BY_CLIENT_TAG, tag), write_transaction_(trans) {
-}
-
-MutableEntry::MutableEntry(WriteTransaction* trans, GetByServerTag,
- const string& tag)
- : Entry(trans, GET_BY_SERVER_TAG, tag), write_transaction_(trans) {
-}
-
-bool MutableEntry::PutIsDel(bool is_del) {
- DCHECK(kernel_);
- write_transaction_->SaveOriginal(kernel_);
- if (is_del == kernel_->ref(IS_DEL)) {
- return true;
- }
- if (is_del) {
- if (!UnlinkFromOrder()) {
- return false;
- }
-
- // If the server never knew about this item and it's deleted then we don't
- // need to keep it around. Unsetting IS_UNSYNCED will:
- // - Ensure that the item is never committed to the server.
- // - Allow any items with the same UNIQUE_CLIENT_TAG created on other
- // clients to override this entry.
- // - Let us delete this entry permanently through
- // DirectoryBackingStore::DropDeletedEntries() when we next restart sync.
- // This will save memory and avoid crbug.com/125381.
- if (!Get(ID).ServerKnows()) {
- Put(IS_UNSYNCED, false);
- }
- }
-
- {
- ScopedKernelLock lock(dir());
- // Some indices don't include deleted items and must be updated
- // upon a value change.
- ScopedIndexUpdater<ParentIdAndHandleIndexer> updater(lock, kernel_,
- dir()->kernel_->parent_id_child_index);
-
- kernel_->put(IS_DEL, is_del);
- kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
- }
-
- if (!is_del)
- // Restores position to the 0th index.
- if (!PutPredecessor(Id())) {
- // TODO(lipalani) : Propagate the error to caller. crbug.com/100444.
- NOTREACHED();
- }
-
- return true;
-}
-
-bool MutableEntry::Put(Int64Field field, const int64& value) {
- DCHECK(kernel_);
- write_transaction_->SaveOriginal(kernel_);
- if (kernel_->ref(field) != value) {
- ScopedKernelLock lock(dir());
- if (SERVER_POSITION_IN_PARENT == field) {
- ScopedIndexUpdater<ParentIdAndHandleIndexer> updater(lock, kernel_,
- dir()->kernel_->parent_id_child_index);
- kernel_->put(field, value);
- } else {
- kernel_->put(field, value);
- }
- kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
- }
- return true;
-}
-
-bool MutableEntry::Put(TimeField field, const base::Time& value) {
- DCHECK(kernel_);
- write_transaction_->SaveOriginal(kernel_);
- if (kernel_->ref(field) != value) {
- kernel_->put(field, value);
- kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
- }
- return true;
-}
-
-bool MutableEntry::Put(IdField field, const Id& value) {
- DCHECK(kernel_);
- write_transaction_->SaveOriginal(kernel_);
- if (kernel_->ref(field) != value) {
- if (ID == field) {
- if (!dir()->ReindexId(write_transaction(), kernel_, value))
- return false;
- } else if (PARENT_ID == field) {
- PutParentIdPropertyOnly(value); // Makes sibling order inconsistent.
- // Fixes up the sibling order inconsistency.
- if (!PutPredecessor(Id())) {
- // TODO(lipalani) : Propagate the error to caller. crbug.com/100444.
- NOTREACHED();
- }
- } else {
- kernel_->put(field, value);
- }
- kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
- }
- return true;
-}
-
-void MutableEntry::PutParentIdPropertyOnly(const Id& parent_id) {
- write_transaction_->SaveOriginal(kernel_);
- dir()->ReindexParentId(write_transaction(), kernel_, parent_id);
- kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
-}
-
-bool MutableEntry::Put(BaseVersion field, int64 value) {
- DCHECK(kernel_);
- write_transaction_->SaveOriginal(kernel_);
- if (kernel_->ref(field) != value) {
- kernel_->put(field, value);
- kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
- }
- return true;
-}
-
-bool MutableEntry::Put(StringField field, const string& value) {
- DCHECK(kernel_);
- write_transaction_->SaveOriginal(kernel_);
- if (field == UNIQUE_CLIENT_TAG) {
- return PutUniqueClientTag(value);
- }
-
- if (kernel_->ref(field) != value) {
- kernel_->put(field, value);
- kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
- }
- return true;
-}
-
-bool MutableEntry::Put(ProtoField field,
- const sync_pb::EntitySpecifics& value) {
- DCHECK(kernel_);
- write_transaction_->SaveOriginal(kernel_);
- // TODO(ncarter): This is unfortunately heavyweight. Can we do
- // better?
- if (kernel_->ref(field).SerializeAsString() != value.SerializeAsString()) {
- const bool update_unapplied_updates_index =
- (field == SERVER_SPECIFICS) && kernel_->ref(IS_UNAPPLIED_UPDATE);
- if (update_unapplied_updates_index) {
- // Remove ourselves from unapplied_update_metahandles with our
- // old server type.
- const syncable::ModelType old_server_type =
- kernel_->GetServerModelType();
- const int64 metahandle = kernel_->ref(META_HANDLE);
- size_t erase_count =
- dir()->kernel_->unapplied_update_metahandles[old_server_type]
- .erase(metahandle);
- DCHECK_EQ(erase_count, 1u);
- }
-
- kernel_->put(field, value);
- kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
-
- if (update_unapplied_updates_index) {
- // Add ourselves back into unapplied_update_metahandles with our
- // new server type.
- const syncable::ModelType new_server_type =
- kernel_->GetServerModelType();
- const int64 metahandle = kernel_->ref(META_HANDLE);
- dir()->kernel_->unapplied_update_metahandles[new_server_type]
- .insert(metahandle);
- }
- }
- return true;
-}
-
-bool MutableEntry::Put(BitField field, bool value) {
- DCHECK(kernel_);
- write_transaction_->SaveOriginal(kernel_);
- if (kernel_->ref(field) != value) {
- kernel_->put(field, value);
- kernel_->mark_dirty(GetDirtyIndexHelper());
- }
- return true;
-}
-
-MetahandleSet* MutableEntry::GetDirtyIndexHelper() {
- return dir()->kernel_->dirty_metahandles;
-}
-
-bool MutableEntry::PutUniqueClientTag(const string& new_tag) {
- write_transaction_->SaveOriginal(kernel_);
- // There is no SERVER_UNIQUE_CLIENT_TAG. This field is similar to ID.
- string old_tag = kernel_->ref(UNIQUE_CLIENT_TAG);
- if (old_tag == new_tag) {
- return true;
- }
-
- ScopedKernelLock lock(dir());
- if (!new_tag.empty()) {
- // Make sure your new value is not in there already.
- EntryKernel lookup_kernel_ = *kernel_;
- lookup_kernel_.put(UNIQUE_CLIENT_TAG, new_tag);
- bool new_tag_conflicts =
- (dir()->kernel_->client_tag_index->count(&lookup_kernel_) > 0);
- if (new_tag_conflicts) {
- return false;
- }
- }
-
- {
- ScopedIndexUpdater<ClientTagIndexer> index_updater(lock, kernel_,
- dir()->kernel_->client_tag_index);
- kernel_->put(UNIQUE_CLIENT_TAG, new_tag);
- kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
- }
- return true;
-}
-
-bool MutableEntry::Put(IndexedBitField field, bool value) {
- DCHECK(kernel_);
- write_transaction_->SaveOriginal(kernel_);
- if (kernel_->ref(field) != value) {
- MetahandleSet* index;
- if (IS_UNSYNCED == field) {
- index = dir()->kernel_->unsynced_metahandles;
- } else {
- // Use kernel_->GetServerModelType() instead of
- // GetServerModelType() as we may trigger some DCHECKs in the
- // latter.
- index =
- &dir()->kernel_->unapplied_update_metahandles[
- kernel_->GetServerModelType()];
- }
-
- ScopedKernelLock lock(dir());
- if (value) {
- if (!SyncAssert(index->insert(kernel_->ref(META_HANDLE)).second,
- FROM_HERE,
- "Could not insert",
- write_transaction())) {
- return false;
- }
- } else {
- if (!SyncAssert(1U == index->erase(kernel_->ref(META_HANDLE)),
- FROM_HERE,
- "Entry Not succesfully erased",
- write_transaction())) {
- return false;
- }
- }
- kernel_->put(field, value);
- kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
- }
- return true;
-}
-
-bool MutableEntry::UnlinkFromOrder() {
- ScopedKernelLock lock(dir());
- return dir()->UnlinkEntryFromOrder(kernel_,
- write_transaction(),
- &lock,
- NODE_MANIPULATION);
-}
-
bool Directory::UnlinkEntryFromOrder(EntryKernel* entry,
WriteTransaction* trans,
ScopedKernelLock* lock,
@@ -2047,71 +1144,6 @@ bool Directory::UnlinkEntryFromOrder(EntryKernel* entry,
return true;
}
-bool MutableEntry::PutPredecessor(const Id& predecessor_id) {
- if (!UnlinkFromOrder())
- return false;
-
- if (Get(IS_DEL)) {
- DCHECK(predecessor_id.IsNull());
- return true;
- }
-
- // TODO(ncarter): It should be possible to not maintain position for
- // non-bookmark items. However, we'd need to robustly handle all possible
- // permutations of setting IS_DEL and the SPECIFICS to identify the
- // object type; or else, we'd need to add a ModelType to the
- // MutableEntry's Create ctor.
- // if (!ShouldMaintainPosition()) {
- // return false;
- // }
-
- // This is classic insert-into-doubly-linked-list from CS 101 and your last
- // job interview. An "IsRoot" Id signifies the head or tail.
- Id successor_id;
- if (!predecessor_id.IsRoot()) {
- MutableEntry predecessor(write_transaction(), GET_BY_ID, predecessor_id);
- if (!predecessor.good()) {
- LOG(ERROR) << "Predecessor is not good : "
- << predecessor_id.GetServerId();
- return false;
- }
- if (predecessor.Get(PARENT_ID) != Get(PARENT_ID))
- return false;
- successor_id = predecessor.Get(NEXT_ID);
- predecessor.Put(NEXT_ID, Get(ID));
- } else {
- syncable::Directory* dir = trans()->directory();
- if (!dir->GetFirstChildId(trans(), Get(PARENT_ID), &successor_id)) {
- return false;
- }
- }
- if (!successor_id.IsRoot()) {
- MutableEntry successor(write_transaction(), GET_BY_ID, successor_id);
- if (!successor.good()) {
- LOG(ERROR) << "Successor is not good: "
- << successor_id.GetServerId();
- return false;
- }
- if (successor.Get(PARENT_ID) != Get(PARENT_ID))
- return false;
- successor.Put(PREV_ID, Get(ID));
- }
- DCHECK(predecessor_id != Get(ID));
- DCHECK(successor_id != Get(ID));
- Put(PREV_ID, predecessor_id);
- Put(NEXT_ID, successor_id);
- return true;
-}
-
-bool MutableEntry::Put(BitTemp field, bool value) {
- DCHECK(kernel_);
- kernel_->put(field, value);
- return true;
-}
-
-///////////////////////////////////////////////////////////////////////////
-// High-level functions
-
int64 Directory::NextMetahandle() {
ScopedKernelLock lock(this);
int64 metahandle = (kernel_->next_metahandle)++;
@@ -2229,82 +1261,6 @@ Id Directory::ComputePrevIdFromServerPosition(
return Id();
}
-bool IsLegalNewParent(BaseTransaction* trans, const Id& entry_id,
- const Id& new_parent_id) {
- if (entry_id.IsRoot())
- return false;
- // we have to ensure that the entry is not an ancestor of the new parent.
- Id ancestor_id = new_parent_id;
- while (!ancestor_id.IsRoot()) {
- if (entry_id == ancestor_id)
- return false;
- Entry new_parent(trans, GET_BY_ID, ancestor_id);
- if (!SyncAssert(new_parent.good(),
- FROM_HERE,
- "Invalid new parent",
- trans))
- return false;
- ancestor_id = new_parent.Get(PARENT_ID);
- }
- return true;
-}
-
-// This function sets only the flags needed to get this entry to sync.
-bool MarkForSyncing(syncable::MutableEntry* e) {
- DCHECK_NE(static_cast<MutableEntry*>(NULL), e);
- DCHECK(!e->IsRoot()) << "We shouldn't mark a permanent object for syncing.";
- if (!(e->Put(IS_UNSYNCED, true)))
- return false;
- e->Put(SYNCING, false);
- return true;
-}
-
-std::ostream& operator<<(std::ostream& os, const Entry& entry) {
- int i;
- EntryKernel* const kernel = entry.kernel_;
- for (i = BEGIN_FIELDS; i < INT64_FIELDS_END; ++i) {
- os << g_metas_columns[i].name << ": "
- << kernel->ref(static_cast<Int64Field>(i)) << ", ";
- }
- for ( ; i < TIME_FIELDS_END; ++i) {
- os << g_metas_columns[i].name << ": "
- << browser_sync::GetTimeDebugString(
- kernel->ref(static_cast<TimeField>(i))) << ", ";
- }
- for ( ; i < ID_FIELDS_END; ++i) {
- os << g_metas_columns[i].name << ": "
- << kernel->ref(static_cast<IdField>(i)) << ", ";
- }
- os << "Flags: ";
- for ( ; i < BIT_FIELDS_END; ++i) {
- if (kernel->ref(static_cast<BitField>(i)))
- os << g_metas_columns[i].name << ", ";
- }
- for ( ; i < STRING_FIELDS_END; ++i) {
- const string& field = kernel->ref(static_cast<StringField>(i));
- os << g_metas_columns[i].name << ": " << field << ", ";
- }
- for ( ; i < PROTO_FIELDS_END; ++i) {
- os << g_metas_columns[i].name << ": "
- << net::EscapePath(
- kernel->ref(static_cast<ProtoField>(i)).SerializeAsString())
- << ", ";
- }
- os << "TempFlags: ";
- for ( ; i < BIT_TEMPS_END; ++i) {
- if (kernel->ref(static_cast<BitTemp>(i)))
- os << "#" << i - BIT_TEMPS_BEGIN << ", ";
- }
- return os;
-}
-
-std::ostream& operator<<(std::ostream& s, const Blob& blob) {
- for (Blob::const_iterator i = blob.begin(); i != blob.end(); ++i)
- s << std::hex << std::setw(2)
- << std::setfill('0') << static_cast<unsigned int>(*i);
- return s << std::dec;
-}
-
Directory::ParentIdChildIndex::iterator Directory::LocateInParentChildIndex(
const ScopedKernelLock& lock,
const Id& parent_id,
@@ -2395,47 +1351,8 @@ EntryKernel* Directory::GetPossibleLastChildForTest(
return NULL;
}
-void ChangeEntryIDAndUpdateChildren(
- syncable::WriteTransaction* trans,
- syncable::MutableEntry* entry,
- const syncable::Id& new_id) {
- syncable::Id old_id = entry->Get(ID);
- if (!entry->Put(ID, new_id)) {
- Entry old_entry(trans, GET_BY_ID, new_id);
- CHECK(old_entry.good());
- LOG(FATAL) << "Attempt to change ID to " << new_id
- << " conflicts with existing entry.\n\n"
- << *entry << "\n\n" << old_entry;
- }
- if (entry->Get(IS_DIR)) {
- // Get all child entries of the old id.
- syncable::Directory::ChildHandles children;
- trans->directory()->GetChildHandlesById(trans, old_id, &children);
- Directory::ChildHandles::iterator i = children.begin();
- while (i != children.end()) {
- MutableEntry child_entry(trans, GET_BY_HANDLE, *i++);
- CHECK(child_entry.good());
- // Use the unchecked setter here to avoid touching the child's NEXT_ID
- // and PREV_ID fields (which Put(PARENT_ID) would normally do to
- // maintain linked-list invariants). In this case, NEXT_ID and PREV_ID
- // among the children will be valid after the loop, since we update all
- // the children at once.
- child_entry.PutParentIdPropertyOnly(new_id);
- }
- }
- // Update Id references on the previous and next nodes in the sibling
- // order. Do this by reinserting into the linked list; the first
- // step in PutPredecessor is to Unlink from the existing order, which
- // will overwrite the stale Id value from the adjacent nodes.
- if (entry->Get(PREV_ID) == entry->Get(NEXT_ID) &&
- entry->Get(PREV_ID) == old_id) {
- // We just need a shallow update to |entry|'s fields since it is already
- // self looped.
- entry->Put(NEXT_ID, new_id);
- entry->Put(PREV_ID, new_id);
- } else {
- entry->PutPredecessor(entry->Get(PREV_ID));
- }
+ScopedKernelLock::ScopedKernelLock(const Directory* dir)
+ : scoped_lock_(dir->kernel_->mutex), dir_(const_cast<Directory*>(dir)) {
}
-} // namespace syncable
+}
diff --git a/sync/syncable/syncable.h b/sync/syncable/directory.h
index 0cab389..dc47732 100644
--- a/sync/syncable/syncable.h
+++ b/sync/syncable/directory.h
@@ -2,656 +2,38 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SYNC_SYNCABLE_SYNCABLE_H_
-#define SYNC_SYNCABLE_SYNCABLE_H_
+#ifndef SYNC_SYNCABLE_DIRECTORY_H_
+#define SYNC_SYNCABLE_DIRECTORY_H_
#pragma once
-#include <algorithm>
-#include <bitset>
-#include <cstddef>
-#include <iosfwd>
-#include <limits>
-#include <map>
#include <set>
#include <string>
#include <vector>
-#include "base/atomicops.h"
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/file_path.h"
+#include "base/file_util.h"
#include "base/gtest_prod_util.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
-#include "base/time.h"
-#include "sync/internal_api/public/syncable/model_type.h"
-#include "sync/internal_api/public/util/immutable.h"
#include "sync/internal_api/public/util/report_unrecoverable_error_function.h"
-#include "sync/internal_api/public/util/unrecoverable_error_handler.h"
#include "sync/internal_api/public/util/weak_handle.h"
-#include "sync/protocol/sync.pb.h"
-#include "sync/syncable/blob.h"
#include "sync/syncable/dir_open_result.h"
-#include "sync/syncable/syncable_id.h"
+#include "sync/syncable/entry_kernel.h"
+#include "sync/syncable/metahandle_set.h"
+#include "sync/syncable/scoped_kernel_lock.h"
#include "sync/util/cryptographer.h"
-#include "sync/util/time.h"
-
-namespace base {
-class DictionaryValue;
-class ListValue;
-}
namespace browser_sync {
class Encryptor;
-} // namespace browser_sync
-
-namespace sync_api {
-class ReadTransaction;
-class WriteNode;
-class ReadNode;
-} // sync_api
+class UnrecoverableErrorHandler;
+}
namespace syncable {
+
class DirectoryChangeDelegate;
class TransactionObserver;
-class Entry;
-
-std::ostream& operator<<(std::ostream& s, const Entry& e);
-
-class DirectoryBackingStore;
-
-static const int64 kInvalidMetaHandle = 0;
-
-// Things you need to update if you change any of the fields below:
-// - EntryKernel struct in syncable.h (this file)
-// - syncable_columns.h
-// - syncable_enum_conversions{.h,.cc,_unittest.cc}
-// - EntryKernel::EntryKernel(), EntryKernel::ToValue(), operator<<
-// for Entry in syncable.cc
-// - BindFields() and UnpackEntry() in directory_backing_store.cc
-// - TestSimpleFieldsPreservedDuringSaveChanges in syncable_unittest.cc
-
-enum {
- BEGIN_FIELDS = 0,
- INT64_FIELDS_BEGIN = BEGIN_FIELDS
-};
-
-enum MetahandleField {
- // Primary key into the table. Keep this as a handle to the meta entry
- // across transactions.
- META_HANDLE = INT64_FIELDS_BEGIN
-};
-
-enum BaseVersion {
- // After initial upload, the version is controlled by the server, and is
- // increased whenever the data or metadata changes on the server.
- BASE_VERSION = META_HANDLE + 1,
-};
-
-enum Int64Field {
- SERVER_VERSION = BASE_VERSION + 1,
-
- // A numeric position value that indicates the relative ordering of
- // this object among its siblings.
- SERVER_POSITION_IN_PARENT,
-
- LOCAL_EXTERNAL_ID, // ID of an item in the external local storage that this
- // entry is associated with. (such as bookmarks.js)
-
- INT64_FIELDS_END
-};
-
-enum {
- INT64_FIELDS_COUNT = INT64_FIELDS_END - INT64_FIELDS_BEGIN,
- TIME_FIELDS_BEGIN = INT64_FIELDS_END,
-};
-
-enum TimeField {
- MTIME = TIME_FIELDS_BEGIN,
- SERVER_MTIME,
- CTIME,
- SERVER_CTIME,
- TIME_FIELDS_END,
-};
-
-enum {
- TIME_FIELDS_COUNT = TIME_FIELDS_END - TIME_FIELDS_BEGIN,
- ID_FIELDS_BEGIN = TIME_FIELDS_END,
-};
-
-enum IdField {
- // Code in InitializeTables relies on ID being the first IdField value.
- ID = ID_FIELDS_BEGIN,
- PARENT_ID,
- SERVER_PARENT_ID,
-
- PREV_ID,
- NEXT_ID,
- ID_FIELDS_END
-};
-
-enum {
- ID_FIELDS_COUNT = ID_FIELDS_END - ID_FIELDS_BEGIN,
- BIT_FIELDS_BEGIN = ID_FIELDS_END
-};
-
-enum IndexedBitField {
- IS_UNSYNCED = BIT_FIELDS_BEGIN,
- IS_UNAPPLIED_UPDATE,
- INDEXED_BIT_FIELDS_END,
-};
-
-enum IsDelField {
- IS_DEL = INDEXED_BIT_FIELDS_END,
-};
-
-enum BitField {
- IS_DIR = IS_DEL + 1,
- SERVER_IS_DIR,
- SERVER_IS_DEL,
- BIT_FIELDS_END
-};
-
-enum {
- BIT_FIELDS_COUNT = BIT_FIELDS_END - BIT_FIELDS_BEGIN,
- STRING_FIELDS_BEGIN = BIT_FIELDS_END
-};
-
-enum StringField {
- // Name, will be truncated by server. Can be duplicated in a folder.
- NON_UNIQUE_NAME = STRING_FIELDS_BEGIN,
- // The server version of |NON_UNIQUE_NAME|.
- SERVER_NON_UNIQUE_NAME,
-
- // A tag string which identifies this node as a particular top-level
- // permanent object. The tag can be thought of as a unique key that
- // identifies a singleton instance.
- UNIQUE_SERVER_TAG, // Tagged by the server
- UNIQUE_CLIENT_TAG, // Tagged by the client
- STRING_FIELDS_END,
-};
-
-enum {
- STRING_FIELDS_COUNT = STRING_FIELDS_END - STRING_FIELDS_BEGIN,
- PROTO_FIELDS_BEGIN = STRING_FIELDS_END
-};
-
-// From looking at the sqlite3 docs, it's not directly stated, but it
-// seems the overhead for storing a NULL blob is very small.
-enum ProtoField {
- SPECIFICS = PROTO_FIELDS_BEGIN,
- SERVER_SPECIFICS,
- BASE_SERVER_SPECIFICS,
- PROTO_FIELDS_END,
-};
-
-enum {
- PROTO_FIELDS_COUNT = PROTO_FIELDS_END - PROTO_FIELDS_BEGIN
-};
-
-enum {
- FIELD_COUNT = PROTO_FIELDS_END,
- // Past this point we have temporaries, stored in memory only.
- BEGIN_TEMPS = PROTO_FIELDS_END,
- BIT_TEMPS_BEGIN = BEGIN_TEMPS,
-};
-
-enum BitTemp {
- // Not to be confused with IS_UNSYNCED, this bit is used to detect local
- // changes to items that happen during the server Commit operation.
- SYNCING = BIT_TEMPS_BEGIN,
- BIT_TEMPS_END,
-};
-
-enum {
- BIT_TEMPS_COUNT = BIT_TEMPS_END - BIT_TEMPS_BEGIN
-};
-
class BaseTransaction;
class WriteTransaction;
-class ReadTransaction;
-class Directory;
-
-// Instead of:
-// Entry e = transaction.GetById(id);
-// use:
-// Entry e(transaction, GET_BY_ID, id);
-//
-// Why? The former would require a copy constructor, and it would be difficult
-// to enforce that an entry never outlived its transaction if there were a copy
-// constructor.
-enum GetById {
- GET_BY_ID
-};
-
-enum GetByClientTag {
- GET_BY_CLIENT_TAG
-};
-
-enum GetByServerTag {
- GET_BY_SERVER_TAG
-};
-
-enum GetByHandle {
- GET_BY_HANDLE
-};
-
-enum Create {
- CREATE
-};
-
-enum CreateNewUpdateItem {
- CREATE_NEW_UPDATE_ITEM
-};
-
-typedef std::set<int64> MetahandleSet;
-
-// Reason for unlinking.
-enum UnlinkReason {
- NODE_MANIPULATION, // To be used by any operation manipulating the linked
- // list.
- DATA_TYPE_PURGE // To be used when purging a dataype.
-};
-
-// TODO(akalin): Move EntryKernel and related into its own header file.
-
-// Why the singular enums? So the code compile-time dispatches instead of
-// runtime dispatches as it would with a single enum and an if() statement.
-
-// The EntryKernel class contains the actual data for an entry.
-struct EntryKernel {
- private:
- std::string string_fields[STRING_FIELDS_COUNT];
- sync_pb::EntitySpecifics specifics_fields[PROTO_FIELDS_COUNT];
- int64 int64_fields[INT64_FIELDS_COUNT];
- base::Time time_fields[TIME_FIELDS_COUNT];
- Id id_fields[ID_FIELDS_COUNT];
- std::bitset<BIT_FIELDS_COUNT> bit_fields;
- std::bitset<BIT_TEMPS_COUNT> bit_temps;
-
- public:
- EntryKernel();
- ~EntryKernel();
-
- // Set the dirty bit, and optionally add this entry's metahandle to
- // a provided index on dirty bits in |dirty_index|. Parameter may be null,
- // and will result only in setting the dirty bit of this entry.
- inline void mark_dirty(syncable::MetahandleSet* dirty_index) {
- if (!dirty_ && dirty_index) {
- DCHECK_NE(0, ref(META_HANDLE));
- dirty_index->insert(ref(META_HANDLE));
- }
- dirty_ = true;
- }
-
- // Clear the dirty bit, and optionally remove this entry's metahandle from
- // a provided index on dirty bits in |dirty_index|. Parameter may be null,
- // and will result only in clearing dirty bit of this entry.
- inline void clear_dirty(syncable::MetahandleSet* dirty_index) {
- if (dirty_ && dirty_index) {
- DCHECK_NE(0, ref(META_HANDLE));
- dirty_index->erase(ref(META_HANDLE));
- }
- dirty_ = false;
- }
-
- inline bool is_dirty() const {
- return dirty_;
- }
-
- // Setters.
- inline void put(MetahandleField field, int64 value) {
- int64_fields[field - INT64_FIELDS_BEGIN] = value;
- }
- inline void put(Int64Field field, int64 value) {
- int64_fields[field - INT64_FIELDS_BEGIN] = value;
- }
- inline void put(TimeField field, const base::Time& value) {
- // Round-trip to proto time format and back so that we have
- // consistent time resolutions (ms).
- time_fields[field - TIME_FIELDS_BEGIN] =
- browser_sync::ProtoTimeToTime(
- browser_sync::TimeToProtoTime(value));
- }
- inline void put(IdField field, const Id& value) {
- id_fields[field - ID_FIELDS_BEGIN] = value;
- }
- inline void put(BaseVersion field, int64 value) {
- int64_fields[field - INT64_FIELDS_BEGIN] = value;
- }
- inline void put(IndexedBitField field, bool value) {
- bit_fields[field - BIT_FIELDS_BEGIN] = value;
- }
- inline void put(IsDelField field, bool value) {
- bit_fields[field - BIT_FIELDS_BEGIN] = value;
- }
- inline void put(BitField field, bool value) {
- bit_fields[field - BIT_FIELDS_BEGIN] = value;
- }
- inline void put(StringField field, const std::string& value) {
- string_fields[field - STRING_FIELDS_BEGIN] = value;
- }
- inline void put(ProtoField field, const sync_pb::EntitySpecifics& value) {
- specifics_fields[field - PROTO_FIELDS_BEGIN].CopyFrom(value);
- }
- inline void put(BitTemp field, bool value) {
- bit_temps[field - BIT_TEMPS_BEGIN] = value;
- }
-
- // Const ref getters.
- inline int64 ref(MetahandleField field) const {
- return int64_fields[field - INT64_FIELDS_BEGIN];
- }
- inline int64 ref(Int64Field field) const {
- return int64_fields[field - INT64_FIELDS_BEGIN];
- }
- inline const base::Time& ref(TimeField field) const {
- return time_fields[field - TIME_FIELDS_BEGIN];
- }
- inline const Id& ref(IdField field) const {
- return id_fields[field - ID_FIELDS_BEGIN];
- }
- inline int64 ref(BaseVersion field) const {
- return int64_fields[field - INT64_FIELDS_BEGIN];
- }
- inline bool ref(IndexedBitField field) const {
- return bit_fields[field - BIT_FIELDS_BEGIN];
- }
- inline bool ref(IsDelField field) const {
- return bit_fields[field - BIT_FIELDS_BEGIN];
- }
- inline bool ref(BitField field) const {
- return bit_fields[field - BIT_FIELDS_BEGIN];
- }
- inline const std::string& ref(StringField field) const {
- return string_fields[field - STRING_FIELDS_BEGIN];
- }
- inline const sync_pb::EntitySpecifics& ref(ProtoField field) const {
- return specifics_fields[field - PROTO_FIELDS_BEGIN];
- }
- inline bool ref(BitTemp field) const {
- return bit_temps[field - BIT_TEMPS_BEGIN];
- }
-
- // Non-const, mutable ref getters for object types only.
- inline std::string& mutable_ref(StringField field) {
- return string_fields[field - STRING_FIELDS_BEGIN];
- }
- inline sync_pb::EntitySpecifics& mutable_ref(ProtoField field) {
- return specifics_fields[field - PROTO_FIELDS_BEGIN];
- }
- inline Id& mutable_ref(IdField field) {
- return id_fields[field - ID_FIELDS_BEGIN];
- }
-
- syncable::ModelType GetServerModelType() const;
-
- // Dumps all kernel info into a DictionaryValue and returns it.
- // Transfers ownership of the DictionaryValue to the caller.
- base::DictionaryValue* ToValue() const;
-
- private:
- // Tracks whether this entry needs to be saved to the database.
- bool dirty_;
-};
-
-// A read-only meta entry.
-class Entry {
- friend class Directory;
- friend std::ostream& operator << (std::ostream& s, const Entry& e);
-
- public:
- // After constructing, you must check good() to test whether the Get
- // succeeded.
- Entry(BaseTransaction* trans, GetByHandle, int64 handle);
- Entry(BaseTransaction* trans, GetById, const Id& id);
- Entry(BaseTransaction* trans, GetByServerTag, const std::string& tag);
- Entry(BaseTransaction* trans, GetByClientTag, const std::string& tag);
-
- bool good() const { return 0 != kernel_; }
-
- BaseTransaction* trans() const { return basetrans_; }
-
- // Field accessors.
- inline int64 Get(MetahandleField field) const {
- DCHECK(kernel_);
- return kernel_->ref(field);
- }
- inline Id Get(IdField field) const {
- DCHECK(kernel_);
- return kernel_->ref(field);
- }
- inline int64 Get(Int64Field field) const {
- DCHECK(kernel_);
- return kernel_->ref(field);
- }
- inline const base::Time& Get(TimeField field) const {
- DCHECK(kernel_);
- return kernel_->ref(field);
- }
- inline int64 Get(BaseVersion field) const {
- DCHECK(kernel_);
- return kernel_->ref(field);
- }
- inline bool Get(IndexedBitField field) const {
- DCHECK(kernel_);
- return kernel_->ref(field);
- }
- inline bool Get(IsDelField field) const {
- DCHECK(kernel_);
- return kernel_->ref(field);
- }
- inline bool Get(BitField field) const {
- DCHECK(kernel_);
- return kernel_->ref(field);
- }
- const std::string& Get(StringField field) const;
- inline const sync_pb::EntitySpecifics& Get(ProtoField field) const {
- DCHECK(kernel_);
- return kernel_->ref(field);
- }
- inline bool Get(BitTemp field) const {
- DCHECK(kernel_);
- return kernel_->ref(field);
- }
-
- ModelType GetServerModelType() const;
- ModelType GetModelType() const;
-
- inline bool ExistsOnClientBecauseNameIsNonEmpty() const {
- DCHECK(kernel_);
- return !kernel_->ref(NON_UNIQUE_NAME).empty();
- }
-
- inline bool IsRoot() const {
- DCHECK(kernel_);
- return kernel_->ref(ID).IsRoot();
- }
-
- Directory* dir() const;
-
- const EntryKernel GetKernelCopy() const {
- return *kernel_;
- }
-
- // Compute a local predecessor position for |update_item|, based on its
- // absolute server position. The returned ID will be a valid predecessor
- // under SERVER_PARENT_ID that is consistent with the
- // SERVER_POSITION_IN_PARENT ordering.
- Id ComputePrevIdFromServerPosition(const Id& parent_id) const;
-
- // Dumps all entry info into a DictionaryValue and returns it.
- // Transfers ownership of the DictionaryValue to the caller.
- base::DictionaryValue* ToValue() const;
-
- protected: // Don't allow creation on heap, except by sync API wrappers.
- friend class sync_api::ReadNode;
- void* operator new(size_t size) { return (::operator new)(size); }
-
- inline explicit Entry(BaseTransaction* trans)
- : basetrans_(trans),
- kernel_(NULL) { }
-
- protected:
- BaseTransaction* const basetrans_;
-
- EntryKernel* kernel_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Entry);
-};
-
-// A mutable meta entry. Changes get committed to the database when the
-// WriteTransaction is destroyed.
-class MutableEntry : public Entry {
- friend class WriteTransaction;
- friend class Directory;
- void Init(WriteTransaction* trans, const Id& parent_id,
- const std::string& name);
-
- public:
- MutableEntry(WriteTransaction* trans, Create, const Id& parent_id,
- const std::string& name);
- MutableEntry(WriteTransaction* trans, CreateNewUpdateItem, const Id& id);
- MutableEntry(WriteTransaction* trans, GetByHandle, int64);
- MutableEntry(WriteTransaction* trans, GetById, const Id&);
- MutableEntry(WriteTransaction* trans, GetByClientTag, const std::string& tag);
- MutableEntry(WriteTransaction* trans, GetByServerTag, const std::string& tag);
-
- inline WriteTransaction* write_transaction() const {
- return write_transaction_;
- }
-
- // Field Accessors. Some of them trigger the re-indexing of the entry.
- // Return true on success, return false on failure, which means
- // that putting the value would have caused a duplicate in the index.
- // TODO(chron): Remove some of these unecessary return values.
- bool Put(Int64Field field, const int64& value);
- bool Put(TimeField field, const base::Time& value);
- bool Put(IdField field, const Id& value);
-
- // Do a simple property-only update if the PARENT_ID field. Use with caution.
- //
- // The normal Put(IS_PARENT) call will move the item to the front of the
- // sibling order to maintain the linked list invariants when the parent
- // changes. That's usually what you want to do, but it's inappropriate
- // when the caller is trying to change the parent ID of a the whole set
- // of children (e.g. because the ID changed during a commit). For those
- // cases, there's this function. It will corrupt the sibling ordering
- // if you're not careful.
- void PutParentIdPropertyOnly(const Id& parent_id);
-
- bool Put(StringField field, const std::string& value);
- bool Put(BaseVersion field, int64 value);
-
- bool Put(ProtoField field, const sync_pb::EntitySpecifics& value);
- bool Put(BitField field, bool value);
- inline bool Put(IsDelField field, bool value) {
- return PutIsDel(value);
- }
- bool Put(IndexedBitField field, bool value);
-
- // Sets the position of this item, and updates the entry kernels of the
- // adjacent siblings so that list invariants are maintained. Returns false
- // and fails if |predecessor_id| does not identify a sibling. Pass the root
- // ID to put the node in first position.
- bool PutPredecessor(const Id& predecessor_id);
-
- bool Put(BitTemp field, bool value);
-
- protected:
- syncable::MetahandleSet* GetDirtyIndexHelper();
-
- bool PutIsDel(bool value);
-
- private: // Don't allow creation on heap, except by sync API wrappers.
- friend class sync_api::WriteNode;
- void* operator new(size_t size) { return (::operator new)(size); }
-
- bool PutUniqueClientTag(const std::string& value);
-
- // Adjusts the successor and predecessor entries so that they no longer
- // refer to this entry.
- bool UnlinkFromOrder();
-
- // Kind of redundant. We should reduce the number of pointers
- // floating around if at all possible. Could we store this in Directory?
- // Scope: Set on construction, never changed after that.
- WriteTransaction* const write_transaction_;
-
- protected:
- MutableEntry();
-
- DISALLOW_COPY_AND_ASSIGN(MutableEntry);
-};
-
-template <typename FieldType, FieldType field_index> class LessField;
-
-class EntryKernelLessByMetaHandle {
- public:
- inline bool operator()(const EntryKernel& a,
- const EntryKernel& b) const {
- return a.ref(META_HANDLE) < b.ref(META_HANDLE);
- }
-};
-typedef std::set<EntryKernel, EntryKernelLessByMetaHandle> EntryKernelSet;
-
-struct EntryKernelMutation {
- EntryKernel original, mutated;
-};
-typedef std::map<int64, EntryKernelMutation> EntryKernelMutationMap;
-
-typedef browser_sync::Immutable<EntryKernelMutationMap>
- ImmutableEntryKernelMutationMap;
-
-// A WriteTransaction has a writer tag describing which body of code is doing
-// the write. This is defined up here since WriteTransactionInfo also contains
-// one.
-enum WriterTag {
- INVALID,
- SYNCER,
- AUTHWATCHER,
- UNITTEST,
- VACUUM_AFTER_SAVE,
- PURGE_ENTRIES,
- SYNCAPI
-};
-
-// Make sure to update this if you update WriterTag.
-std::string WriterTagToString(WriterTag writer_tag);
-
-struct WriteTransactionInfo {
- WriteTransactionInfo(int64 id,
- tracked_objects::Location location,
- WriterTag writer,
- ImmutableEntryKernelMutationMap mutations);
- WriteTransactionInfo();
- ~WriteTransactionInfo();
-
- // Caller owns the return value.
- base::DictionaryValue* ToValue(size_t max_mutations_size) const;
-
- int64 id;
- // If tracked_objects::Location becomes assignable, we can use that
- // instead.
- std::string location_string;
- WriterTag writer;
- ImmutableEntryKernelMutationMap mutations;
-};
-
-typedef
- browser_sync::Immutable<WriteTransactionInfo>
- ImmutableWriteTransactionInfo;
-
-// Caller owns the return value.
-base::DictionaryValue* EntryKernelMutationToValue(
- const EntryKernelMutation& mutation);
-
-// Caller owns the return value.
-base::ListValue* EntryKernelMutationMapToValue(
- const EntryKernelMutationMap& mutations);
+class ScopedKernelLock;
+class DirectoryBackingStore;
+class IdFilter;
// How syncable indices & Indexers work.
//
@@ -670,6 +52,8 @@ base::ListValue* EntryKernelMutationMapToValue(
// index, the traits are grouped into a class called an Indexer which
// can be used as a template type parameter.
+template <typename FieldType, FieldType field_index> class LessField;
+
// Traits type for metahandle index.
struct MetahandleIndexer {
// This index is of the metahandle field values.
@@ -723,25 +107,21 @@ struct Index {
typedef std::set<EntryKernel*, typename Indexer::Comparator> Set;
};
-// The name Directory in this case means the entire directory
-// structure within a single user account.
-//
-// The db is protected against concurrent modification by a reader/
-// writer lock, negotiated by the ReadTransaction and WriteTransaction
-// friend classes. The in-memory indices are protected against
-// concurrent modification by the kernel lock.
-//
-// All methods which require the reader/writer lock to be held either
-// are protected and only called from friends in a transaction
-// or are public and take a Transaction* argument.
-//
-// All methods which require the kernel lock to be already held take a
-// ScopeKernelLock* argument.
-//
-// To prevent deadlock, the reader writer transaction lock must always
-// be held before acquiring the kernel lock.
-class ScopedKernelLock;
-class IdFilter;
+// Reason for unlinking.
+enum UnlinkReason {
+ NODE_MANIPULATION, // To be used by any operation manipulating the linked
+ // list.
+ DATA_TYPE_PURGE // To be used when purging a dataype.
+};
+
+class EntryKernelLessByMetaHandle {
+ public:
+ inline bool operator()(const EntryKernel& a,
+ const EntryKernel& b) const {
+ return a.ref(META_HANDLE) < b.ref(META_HANDLE);
+ }
+};
+typedef std::set<EntryKernel, EntryKernelLessByMetaHandle> EntryKernelSet;
class Directory {
friend class BaseTransaction;
@@ -1237,122 +617,6 @@ class Directory {
bool unrecoverable_error_set_;
};
-class ScopedKernelLock {
- public:
- explicit ScopedKernelLock(const Directory*);
- ~ScopedKernelLock() {}
-
- base::AutoLock scoped_lock_;
- Directory* const dir_;
- DISALLOW_COPY_AND_ASSIGN(ScopedKernelLock);
-};
-
-// Transactions are now processed FIFO with a straight lock
-class BaseTransaction {
- friend class Entry;
- public:
- inline Directory* directory() const { return directory_; }
- inline Id root_id() const { return Id(); }
-
- virtual ~BaseTransaction();
-
- // This should be called when a database corruption is detected and there is
- // no way for us to recover short of wiping the database clean. When this is
- // called we set a bool in the transaction. The caller has to unwind the
- // stack. When the destructor for the transaction is called it acts upon the
- // bool and calls the Directory to handle the unrecoverable error.
- void OnUnrecoverableError(const tracked_objects::Location& location,
- const std::string& message);
-
- bool unrecoverable_error_set() const;
-
- protected:
- BaseTransaction(const tracked_objects::Location& from_here,
- const char* name,
- WriterTag writer,
- Directory* directory);
-
- void Lock();
- void Unlock();
-
- // This should be called before unlocking because it calls the Direcotry's
- // OnUnrecoverableError method which is not protected by locks and could
- // be called from any thread. Holding the transaction lock ensures only one
- // thread could call the method at a time.
- void HandleUnrecoverableErrorIfSet();
-
- const tracked_objects::Location from_here_;
- const char* const name_;
- WriterTag writer_;
- Directory* const directory_;
- Directory::Kernel* const dirkernel_; // for brevity
-
- // Error information.
- bool unrecoverable_error_set_;
- tracked_objects::Location unrecoverable_error_location_;
- std::string unrecoverable_error_msg_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(BaseTransaction);
-};
-
-// Locks db in constructor, unlocks in destructor.
-class ReadTransaction : public BaseTransaction {
- public:
- ReadTransaction(const tracked_objects::Location& from_here,
- Directory* directory);
-
- virtual ~ReadTransaction();
-
- protected: // Don't allow creation on heap, except by sync API wrapper.
- friend class sync_api::ReadTransaction;
- void* operator new(size_t size) { return (::operator new)(size); }
-
- DISALLOW_COPY_AND_ASSIGN(ReadTransaction);
-};
-
-// Locks db in constructor, unlocks in destructor.
-class WriteTransaction : public BaseTransaction {
- friend class MutableEntry;
- public:
- WriteTransaction(const tracked_objects::Location& from_here,
- WriterTag writer, Directory* directory);
-
- virtual ~WriteTransaction();
-
- void SaveOriginal(const EntryKernel* entry);
-
- protected:
- // Overridden by tests.
- virtual void NotifyTransactionComplete(ModelTypeSet models_with_changes);
-
- private:
- // Clears |mutations_|.
- ImmutableEntryKernelMutationMap RecordMutations();
-
- void UnlockAndNotify(const ImmutableEntryKernelMutationMap& mutations);
-
- ModelTypeSet NotifyTransactionChangingAndEnding(
- const ImmutableEntryKernelMutationMap& mutations);
-
- // Only the original fields are filled in until |RecordMutations()|.
- // We use a mutation map instead of a kernel set to avoid copying.
- EntryKernelMutationMap mutations_;
-
- DISALLOW_COPY_AND_ASSIGN(WriteTransaction);
-};
-
-bool IsLegalNewParent(BaseTransaction* trans, const Id& id, const Id& parentid);
-
-// This function sets only the flags needed to get this entry to sync.
-bool MarkForSyncing(syncable::MutableEntry* e);
-
-void ChangeEntryIDAndUpdateChildren(syncable::WriteTransaction* trans,
- syncable::MutableEntry* entry,
- const syncable::Id& new_id);
-
-} // namespace syncable
-
-std::ostream& operator <<(std::ostream&, const syncable::Blob&);
+} // namespace syncable
-#endif // SYNC_SYNCABLE_SYNCABLE_H_
+#endif // SYNC_SYNCABLE_DIRECTORY_H_
diff --git a/sync/syncable/directory_backing_store.h b/sync/syncable/directory_backing_store.h
index 7e86eb9..2463521 100644
--- a/sync/syncable/directory_backing_store.h
+++ b/sync/syncable/directory_backing_store.h
@@ -14,7 +14,8 @@
#include "sql/statement.h"
#include "sync/internal_api/public/syncable/model_type.h"
#include "sync/syncable/dir_open_result.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/metahandle_set.h"
namespace sync_pb {
class EntitySpecifics;
diff --git a/sync/syncable/directory_backing_store_unittest.cc b/sync/syncable/directory_backing_store_unittest.cc
index 5161817..62b7ccf 100644
--- a/sync/syncable/directory_backing_store_unittest.cc
+++ b/sync/syncable/directory_backing_store_unittest.cc
@@ -12,16 +12,15 @@
#include "base/scoped_temp_dir.h"
#include "base/stl_util.h"
#include "base/string_number_conversions.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "sync/protocol/bookmark_specifics.pb.h"
+#include "sync/protocol/sync.pb.h"
#include "sync/syncable/directory_backing_store.h"
#include "sync/syncable/on_disk_directory_backing_store.h"
#include "sync/syncable/syncable-inl.h"
-#include "sync/syncable/syncable.h"
#include "sync/test/test_directory_backing_store.h"
#include "sync/util/time.h"
-#include "sql/connection.h"
-#include "sql/statement.h"
-#include "sync/protocol/bookmark_specifics.pb.h"
-#include "sync/protocol/sync.pb.h"
#include "testing/gtest/include/gtest/gtest-param-test.h"
namespace syncable {
diff --git a/sync/syncable/directory_change_delegate.h b/sync/syncable/directory_change_delegate.h
index a86b770..fdd7294 100644
--- a/sync/syncable/directory_change_delegate.h
+++ b/sync/syncable/directory_change_delegate.h
@@ -7,7 +7,7 @@
#pragma once
#include "sync/internal_api/public/syncable/model_type.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/write_transaction_info.h"
namespace syncable {
diff --git a/sync/syncable/entry.cc b/sync/syncable/entry.cc
new file mode 100644
index 0000000..3f3e785
--- /dev/null
+++ b/sync/syncable/entry.cc
@@ -0,0 +1,143 @@
+// Copyright (c) 2012 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 "sync/syncable/entry.h"
+
+#include <iomanip>
+
+#include "net/base/escape.h"
+#include "sync/syncable/base_transaction.h"
+#include "sync/syncable/blob.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/syncable_columns.h"
+
+using std::string;
+
+namespace syncable {
+
+Entry::Entry(BaseTransaction* trans, GetById, const Id& id)
+ : basetrans_(trans) {
+ kernel_ = trans->directory()->GetEntryById(id);
+}
+
+Entry::Entry(BaseTransaction* trans, GetByClientTag, const string& tag)
+ : basetrans_(trans) {
+ kernel_ = trans->directory()->GetEntryByClientTag(tag);
+}
+
+Entry::Entry(BaseTransaction* trans, GetByServerTag, const string& tag)
+ : basetrans_(trans) {
+ kernel_ = trans->directory()->GetEntryByServerTag(tag);
+}
+
+Entry::Entry(BaseTransaction* trans, GetByHandle, int64 metahandle)
+ : basetrans_(trans) {
+ kernel_ = trans->directory()->GetEntryByHandle(metahandle);
+}
+
+Directory* Entry::dir() const {
+ return basetrans_->directory();
+}
+
+Id Entry::ComputePrevIdFromServerPosition(const Id& parent_id) const {
+ return dir()->ComputePrevIdFromServerPosition(kernel_, parent_id);
+}
+
+DictionaryValue* Entry::ToValue() const {
+ DictionaryValue* entry_info = new DictionaryValue();
+ entry_info->SetBoolean("good", good());
+ if (good()) {
+ entry_info->Set("kernel", kernel_->ToValue());
+ entry_info->Set("modelType",
+ ModelTypeToValue(GetModelType()));
+ entry_info->SetBoolean("existsOnClientBecauseNameIsNonEmpty",
+ ExistsOnClientBecauseNameIsNonEmpty());
+ entry_info->SetBoolean("isRoot", IsRoot());
+ }
+ return entry_info;
+}
+
+const string& Entry::Get(StringField field) const {
+ DCHECK(kernel_);
+ return kernel_->ref(field);
+}
+
+syncable::ModelType Entry::GetServerModelType() const {
+ ModelType specifics_type = kernel_->GetServerModelType();
+ if (specifics_type != UNSPECIFIED)
+ return specifics_type;
+
+ // Otherwise, we don't have a server type yet. That should only happen
+ // if the item is an uncommitted locally created item.
+ // It's possible we'll need to relax these checks in the future; they're
+ // just here for now as a safety measure.
+ DCHECK(Get(IS_UNSYNCED));
+ DCHECK_EQ(Get(SERVER_VERSION), 0);
+ DCHECK(Get(SERVER_IS_DEL));
+ // Note: can't enforce !Get(ID).ServerKnows() here because that could
+ // actually happen if we hit AttemptReuniteLostCommitResponses.
+ return UNSPECIFIED;
+}
+
+syncable::ModelType Entry::GetModelType() const {
+ ModelType specifics_type = GetModelTypeFromSpecifics(Get(SPECIFICS));
+ if (specifics_type != UNSPECIFIED)
+ return specifics_type;
+ if (IsRoot())
+ return TOP_LEVEL_FOLDER;
+ // Loose check for server-created top-level folders that aren't
+ // bound to a particular model type.
+ if (!Get(UNIQUE_SERVER_TAG).empty() && Get(IS_DIR))
+ return TOP_LEVEL_FOLDER;
+
+ return UNSPECIFIED;
+}
+
+std::ostream& operator<<(std::ostream& s, const Blob& blob) {
+ for (Blob::const_iterator i = blob.begin(); i != blob.end(); ++i)
+ s << std::hex << std::setw(2)
+ << std::setfill('0') << static_cast<unsigned int>(*i);
+ return s << std::dec;
+}
+
+std::ostream& operator<<(std::ostream& os, const Entry& entry) {
+ int i;
+ EntryKernel* const kernel = entry.kernel_;
+ for (i = BEGIN_FIELDS; i < INT64_FIELDS_END; ++i) {
+ os << g_metas_columns[i].name << ": "
+ << kernel->ref(static_cast<Int64Field>(i)) << ", ";
+ }
+ for ( ; i < TIME_FIELDS_END; ++i) {
+ os << g_metas_columns[i].name << ": "
+ << browser_sync::GetTimeDebugString(
+ kernel->ref(static_cast<TimeField>(i))) << ", ";
+ }
+ for ( ; i < ID_FIELDS_END; ++i) {
+ os << g_metas_columns[i].name << ": "
+ << kernel->ref(static_cast<IdField>(i)) << ", ";
+ }
+ os << "Flags: ";
+ for ( ; i < BIT_FIELDS_END; ++i) {
+ if (kernel->ref(static_cast<BitField>(i)))
+ os << g_metas_columns[i].name << ", ";
+ }
+ for ( ; i < STRING_FIELDS_END; ++i) {
+ const std::string& field = kernel->ref(static_cast<StringField>(i));
+ os << g_metas_columns[i].name << ": " << field << ", ";
+ }
+ for ( ; i < PROTO_FIELDS_END; ++i) {
+ os << g_metas_columns[i].name << ": "
+ << net::EscapePath(
+ kernel->ref(static_cast<ProtoField>(i)).SerializeAsString())
+ << ", ";
+ }
+ os << "TempFlags: ";
+ for ( ; i < BIT_TEMPS_END; ++i) {
+ if (kernel->ref(static_cast<BitTemp>(i)))
+ os << "#" << i - BIT_TEMPS_BEGIN << ", ";
+ }
+ return os;
+}
+
+} // namespace syncable
diff --git a/sync/syncable/entry.h b/sync/syncable/entry.h
new file mode 100644
index 0000000..3974902
--- /dev/null
+++ b/sync/syncable/entry.h
@@ -0,0 +1,154 @@
+// Copyright (c) 2012 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 SYNC_SYNCABLE_ENTRY_H_
+#define SYNC_SYNCABLE_ENTRY_H_
+#pragma once
+
+#include "sync/syncable/entry_kernel.h"
+
+namespace sync_api {
+class ReadNode;
+}
+
+namespace syncable {
+
+class Directory;
+class BaseTransaction;
+
+// A read-only meta entry
+// Instead of:
+// Entry e = transaction.GetById(id);
+// use:
+// Entry e(transaction, GET_BY_ID, id);
+//
+// Why? The former would require a copy constructor, and it would be difficult
+// to enforce that an entry never outlived its transaction if there were a copy
+// constructor.
+enum GetById {
+ GET_BY_ID
+};
+
+enum GetByClientTag {
+ GET_BY_CLIENT_TAG
+};
+
+enum GetByServerTag {
+ GET_BY_SERVER_TAG
+};
+
+enum GetByHandle {
+ GET_BY_HANDLE
+};
+
+class Entry {
+ public:
+ // After constructing, you must check good() to test whether the Get
+ // succeeded.
+ Entry(BaseTransaction* trans, GetByHandle, int64 handle);
+ Entry(BaseTransaction* trans, GetById, const Id& id);
+ Entry(BaseTransaction* trans, GetByServerTag, const std::string& tag);
+ Entry(BaseTransaction* trans, GetByClientTag, const std::string& tag);
+
+ bool good() const { return 0 != kernel_; }
+
+ BaseTransaction* trans() const { return basetrans_; }
+
+ // Field accessors.
+ inline int64 Get(MetahandleField field) const {
+ DCHECK(kernel_);
+ return kernel_->ref(field);
+ }
+ inline Id Get(IdField field) const {
+ DCHECK(kernel_);
+ return kernel_->ref(field);
+ }
+ inline int64 Get(Int64Field field) const {
+ DCHECK(kernel_);
+ return kernel_->ref(field);
+ }
+ inline const base::Time& Get(TimeField field) const {
+ DCHECK(kernel_);
+ return kernel_->ref(field);
+ }
+ inline int64 Get(BaseVersion field) const {
+ DCHECK(kernel_);
+ return kernel_->ref(field);
+ }
+ inline bool Get(IndexedBitField field) const {
+ DCHECK(kernel_);
+ return kernel_->ref(field);
+ }
+ inline bool Get(IsDelField field) const {
+ DCHECK(kernel_);
+ return kernel_->ref(field);
+ }
+ inline bool Get(BitField field) const {
+ DCHECK(kernel_);
+ return kernel_->ref(field);
+ }
+ const std::string& Get(StringField field) const;
+ inline const sync_pb::EntitySpecifics& Get(ProtoField field) const {
+ DCHECK(kernel_);
+ return kernel_->ref(field);
+ }
+ inline bool Get(BitTemp field) const {
+ DCHECK(kernel_);
+ return kernel_->ref(field);
+ }
+
+ ModelType GetServerModelType() const;
+ ModelType GetModelType() const;
+
+ inline bool ExistsOnClientBecauseNameIsNonEmpty() const {
+ DCHECK(kernel_);
+ return !kernel_->ref(NON_UNIQUE_NAME).empty();
+ }
+
+ inline bool IsRoot() const {
+ DCHECK(kernel_);
+ return kernel_->ref(ID).IsRoot();
+ }
+
+ Directory* dir() const;
+
+ const EntryKernel GetKernelCopy() const {
+ return *kernel_;
+ }
+
+ // Compute a local predecessor position for |update_item|, based on its
+ // absolute server position. The returned ID will be a valid predecessor
+ // under SERVER_PARENT_ID that is consistent with the
+ // SERVER_POSITION_IN_PARENT ordering.
+ Id ComputePrevIdFromServerPosition(const Id& parent_id) const;
+
+ // Dumps all entry info into a DictionaryValue and returns it.
+ // Transfers ownership of the DictionaryValue to the caller.
+ base::DictionaryValue* ToValue() const;
+
+ protected: // Don't allow creation on heap, except by sync API wrappers.
+ void* operator new(size_t size) { return (::operator new)(size); }
+
+ inline explicit Entry(BaseTransaction* trans)
+ : basetrans_(trans),
+ kernel_(NULL) { }
+
+ protected:
+ BaseTransaction* const basetrans_;
+
+ EntryKernel* kernel_;
+
+ private:
+ friend class Directory;
+ friend class sync_api::ReadNode;
+ friend std::ostream& operator << (std::ostream& s, const Entry& e);
+
+ DISALLOW_COPY_AND_ASSIGN(Entry);
+};
+
+std::ostream& operator<<(std::ostream& os, const Entry& entry);
+
+} // namespace syncable
+
+#endif // SYNC_SYNCABLE_ENTRY_H_
diff --git a/sync/syncable/entry_kernel.cc b/sync/syncable/entry_kernel.cc
new file mode 100644
index 0000000..0ea3d4e
--- /dev/null
+++ b/sync/syncable/entry_kernel.cc
@@ -0,0 +1,151 @@
+// Copyright (c) 2012 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 "sync/syncable/entry_kernel.h"
+
+#include "base/string_number_conversions.h"
+#include "sync/protocol/proto_value_conversions.h"
+#include "sync/syncable/syncable_enum_conversions.h"
+
+namespace syncable {
+
+EntryKernel::EntryKernel() : dirty_(false) {
+ // Everything else should already be default-initialized.
+ for (int i = INT64_FIELDS_BEGIN; i < INT64_FIELDS_END; ++i) {
+ int64_fields[i] = 0;
+ }
+}
+
+EntryKernel::~EntryKernel() {}
+
+syncable::ModelType EntryKernel::GetServerModelType() const {
+ ModelType specifics_type = GetModelTypeFromSpecifics(ref(SERVER_SPECIFICS));
+ if (specifics_type != UNSPECIFIED)
+ return specifics_type;
+ if (ref(ID).IsRoot())
+ return TOP_LEVEL_FOLDER;
+ // Loose check for server-created top-level folders that aren't
+ // bound to a particular model type.
+ if (!ref(UNIQUE_SERVER_TAG).empty() && ref(SERVER_IS_DIR))
+ return TOP_LEVEL_FOLDER;
+
+ return UNSPECIFIED;
+}
+
+namespace {
+
+// Utility function to loop through a set of enum values and add the
+// field keys/values in the kernel to the given dictionary.
+//
+// V should be convertible to Value.
+template <class T, class U, class V>
+void SetFieldValues(const EntryKernel& kernel,
+ DictionaryValue* dictionary_value,
+ const char* (*enum_key_fn)(T),
+ V* (*enum_value_fn)(U),
+ int field_key_min, int field_key_max) {
+ DCHECK_LE(field_key_min, field_key_max);
+ for (int i = field_key_min; i <= field_key_max; ++i) {
+ T field = static_cast<T>(i);
+ const std::string& key = enum_key_fn(field);
+ V* value = enum_value_fn(kernel.ref(field));
+ dictionary_value->Set(key, value);
+ }
+}
+
+// Helper functions for SetFieldValues().
+
+StringValue* Int64ToValue(int64 i) {
+ return Value::CreateStringValue(base::Int64ToString(i));
+}
+
+StringValue* TimeToValue(const base::Time& t) {
+ return Value::CreateStringValue(browser_sync::GetTimeDebugString(t));
+}
+
+StringValue* IdToValue(const Id& id) {
+ return id.ToValue();
+}
+
+} // namespace
+
+DictionaryValue* EntryKernel::ToValue() const {
+ DictionaryValue* kernel_info = new DictionaryValue();
+ kernel_info->SetBoolean("isDirty", is_dirty());
+ kernel_info->Set("serverModelType", ModelTypeToValue(GetServerModelType()));
+
+ // Int64 fields.
+ SetFieldValues(*this, kernel_info,
+ &GetMetahandleFieldString, &Int64ToValue,
+ INT64_FIELDS_BEGIN, META_HANDLE);
+ SetFieldValues(*this, kernel_info,
+ &GetBaseVersionString, &Int64ToValue,
+ META_HANDLE + 1, BASE_VERSION);
+ SetFieldValues(*this, kernel_info,
+ &GetInt64FieldString, &Int64ToValue,
+ BASE_VERSION + 1, INT64_FIELDS_END - 1);
+
+ // Time fields.
+ SetFieldValues(*this, kernel_info,
+ &GetTimeFieldString, &TimeToValue,
+ TIME_FIELDS_BEGIN, TIME_FIELDS_END - 1);
+
+ // ID fields.
+ SetFieldValues(*this, kernel_info,
+ &GetIdFieldString, &IdToValue,
+ ID_FIELDS_BEGIN, ID_FIELDS_END - 1);
+
+ // Bit fields.
+ SetFieldValues(*this, kernel_info,
+ &GetIndexedBitFieldString, &Value::CreateBooleanValue,
+ BIT_FIELDS_BEGIN, INDEXED_BIT_FIELDS_END - 1);
+ SetFieldValues(*this, kernel_info,
+ &GetIsDelFieldString, &Value::CreateBooleanValue,
+ INDEXED_BIT_FIELDS_END, IS_DEL);
+ SetFieldValues(*this, kernel_info,
+ &GetBitFieldString, &Value::CreateBooleanValue,
+ IS_DEL + 1, BIT_FIELDS_END - 1);
+
+ // String fields.
+ {
+ // Pick out the function overload we want.
+ StringValue* (*string_to_value)(const std::string&) =
+ &Value::CreateStringValue;
+ SetFieldValues(*this, kernel_info,
+ &GetStringFieldString, string_to_value,
+ STRING_FIELDS_BEGIN, STRING_FIELDS_END - 1);
+ }
+
+ // Proto fields.
+ SetFieldValues(*this, kernel_info,
+ &GetProtoFieldString, &browser_sync::EntitySpecificsToValue,
+ PROTO_FIELDS_BEGIN, PROTO_FIELDS_END - 1);
+
+ // Bit temps.
+ SetFieldValues(*this, kernel_info,
+ &GetBitTempString, &Value::CreateBooleanValue,
+ BIT_TEMPS_BEGIN, BIT_TEMPS_END - 1);
+
+ return kernel_info;
+}
+
+ListValue* EntryKernelMutationMapToValue(
+ const EntryKernelMutationMap& mutations) {
+ ListValue* list = new ListValue();
+ for (EntryKernelMutationMap::const_iterator it = mutations.begin();
+ it != mutations.end(); ++it) {
+ list->Append(EntryKernelMutationToValue(it->second));
+ }
+ return list;
+}
+
+DictionaryValue* EntryKernelMutationToValue(
+ const EntryKernelMutation& mutation) {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->Set("original", mutation.original.ToValue());
+ dict->Set("mutated", mutation.mutated.ToValue());
+ return dict;
+}
+
+}
diff --git a/sync/syncable/entry_kernel.h b/sync/syncable/entry_kernel.h
new file mode 100644
index 0000000..5c16f1d
--- /dev/null
+++ b/sync/syncable/entry_kernel.h
@@ -0,0 +1,323 @@
+// Copyright (c) 2012 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 SYNC_SYNCABLE_ENTRY_KERNEL_H_
+#define SYNC_SYNCABLE_ENTRY_KERNEL_H_
+#pragma once
+
+#include "base/time.h"
+#include "base/values.h"
+#include "sync/internal_api/public/syncable/model_type.h"
+#include "sync/internal_api/public/util/immutable.h"
+#include "sync/protocol/sync.pb.h"
+#include "sync/syncable/metahandle_set.h"
+#include "sync/syncable/syncable_id.h"
+#include "sync/util/time.h"
+
+namespace syncable {
+
+// Things you need to update if you change any of the fields below:
+// - EntryKernel struct in this file
+// - syncable_columns.h
+// - syncable_enum_conversions{.h,.cc,_unittest.cc}
+// - EntryKernel::EntryKernel(), EntryKernel::ToValue(), operator<<
+// for Entry in syncable.cc
+// - BindFields() and UnpackEntry() in directory_backing_store.cc
+// - TestSimpleFieldsPreservedDuringSaveChanges in syncable_unittest.cc
+
+static const int64 kInvalidMetaHandle = 0;
+
+enum {
+ BEGIN_FIELDS = 0,
+ INT64_FIELDS_BEGIN = BEGIN_FIELDS
+};
+
+enum MetahandleField {
+ // Primary key into the table. Keep this as a handle to the meta entry
+ // across transactions.
+ META_HANDLE = INT64_FIELDS_BEGIN
+};
+
+enum BaseVersion {
+ // After initial upload, the version is controlled by the server, and is
+ // increased whenever the data or metadata changes on the server.
+ BASE_VERSION = META_HANDLE + 1,
+};
+
+enum Int64Field {
+ SERVER_VERSION = BASE_VERSION + 1,
+
+ // A numeric position value that indicates the relative ordering of
+ // this object among its siblings.
+ SERVER_POSITION_IN_PARENT,
+
+ LOCAL_EXTERNAL_ID, // ID of an item in the external local storage that this
+ // entry is associated with. (such as bookmarks.js)
+
+ INT64_FIELDS_END
+};
+
+enum {
+ INT64_FIELDS_COUNT = INT64_FIELDS_END - INT64_FIELDS_BEGIN,
+ TIME_FIELDS_BEGIN = INT64_FIELDS_END,
+};
+
+enum TimeField {
+ MTIME = TIME_FIELDS_BEGIN,
+ SERVER_MTIME,
+ CTIME,
+ SERVER_CTIME,
+ TIME_FIELDS_END,
+};
+
+enum {
+ TIME_FIELDS_COUNT = TIME_FIELDS_END - TIME_FIELDS_BEGIN,
+ ID_FIELDS_BEGIN = TIME_FIELDS_END,
+};
+
+enum IdField {
+ // Code in InitializeTables relies on ID being the first IdField value.
+ ID = ID_FIELDS_BEGIN,
+ PARENT_ID,
+ SERVER_PARENT_ID,
+
+ PREV_ID,
+ NEXT_ID,
+ ID_FIELDS_END
+};
+
+enum {
+ ID_FIELDS_COUNT = ID_FIELDS_END - ID_FIELDS_BEGIN,
+ BIT_FIELDS_BEGIN = ID_FIELDS_END
+};
+
+enum IndexedBitField {
+ IS_UNSYNCED = BIT_FIELDS_BEGIN,
+ IS_UNAPPLIED_UPDATE,
+ INDEXED_BIT_FIELDS_END,
+};
+
+enum IsDelField {
+ IS_DEL = INDEXED_BIT_FIELDS_END,
+};
+
+enum BitField {
+ IS_DIR = IS_DEL + 1,
+ SERVER_IS_DIR,
+ SERVER_IS_DEL,
+ BIT_FIELDS_END
+};
+
+enum {
+ BIT_FIELDS_COUNT = BIT_FIELDS_END - BIT_FIELDS_BEGIN,
+ STRING_FIELDS_BEGIN = BIT_FIELDS_END
+};
+
+enum StringField {
+ // Name, will be truncated by server. Can be duplicated in a folder.
+ NON_UNIQUE_NAME = STRING_FIELDS_BEGIN,
+ // The server version of |NON_UNIQUE_NAME|.
+ SERVER_NON_UNIQUE_NAME,
+
+ // A tag string which identifies this node as a particular top-level
+ // permanent object. The tag can be thought of as a unique key that
+ // identifies a singleton instance.
+ UNIQUE_SERVER_TAG, // Tagged by the server
+ UNIQUE_CLIENT_TAG, // Tagged by the client
+ STRING_FIELDS_END,
+};
+
+enum {
+ STRING_FIELDS_COUNT = STRING_FIELDS_END - STRING_FIELDS_BEGIN,
+ PROTO_FIELDS_BEGIN = STRING_FIELDS_END
+};
+
+// From looking at the sqlite3 docs, it's not directly stated, but it
+// seems the overhead for storing a NULL blob is very small.
+enum ProtoField {
+ SPECIFICS = PROTO_FIELDS_BEGIN,
+ SERVER_SPECIFICS,
+ BASE_SERVER_SPECIFICS,
+ PROTO_FIELDS_END,
+};
+
+enum {
+ FIELD_COUNT = PROTO_FIELDS_END,
+ // Past this point we have temporaries, stored in memory only.
+ BEGIN_TEMPS = PROTO_FIELDS_END,
+ BIT_TEMPS_BEGIN = BEGIN_TEMPS,
+};
+
+enum BitTemp {
+ // Not to be confused with IS_UNSYNCED, this bit is used to detect local
+ // changes to items that happen during the server Commit operation.
+ SYNCING = BIT_TEMPS_BEGIN,
+ BIT_TEMPS_END,
+};
+
+enum {
+ BIT_TEMPS_COUNT = BIT_TEMPS_END - BIT_TEMPS_BEGIN
+};
+
+enum {
+ PROTO_FIELDS_COUNT = PROTO_FIELDS_END - PROTO_FIELDS_BEGIN
+};
+
+
+struct EntryKernel {
+ private:
+ std::string string_fields[STRING_FIELDS_COUNT];
+ sync_pb::EntitySpecifics specifics_fields[PROTO_FIELDS_COUNT];
+ int64 int64_fields[INT64_FIELDS_COUNT];
+ base::Time time_fields[TIME_FIELDS_COUNT];
+ Id id_fields[ID_FIELDS_COUNT];
+ std::bitset<BIT_FIELDS_COUNT> bit_fields;
+ std::bitset<BIT_TEMPS_COUNT> bit_temps;
+
+ public:
+ EntryKernel();
+ ~EntryKernel();
+
+ // Set the dirty bit, and optionally add this entry's metahandle to
+ // a provided index on dirty bits in |dirty_index|. Parameter may be null,
+ // and will result only in setting the dirty bit of this entry.
+ inline void mark_dirty(syncable::MetahandleSet* dirty_index) {
+ if (!dirty_ && dirty_index) {
+ DCHECK_NE(0, ref(META_HANDLE));
+ dirty_index->insert(ref(META_HANDLE));
+ }
+ dirty_ = true;
+ }
+
+ // Clear the dirty bit, and optionally remove this entry's metahandle from
+ // a provided index on dirty bits in |dirty_index|. Parameter may be null,
+ // and will result only in clearing dirty bit of this entry.
+ inline void clear_dirty(syncable::MetahandleSet* dirty_index) {
+ if (dirty_ && dirty_index) {
+ DCHECK_NE(0, ref(META_HANDLE));
+ dirty_index->erase(ref(META_HANDLE));
+ }
+ dirty_ = false;
+ }
+
+ inline bool is_dirty() const {
+ return dirty_;
+ }
+
+ // Setters.
+ inline void put(MetahandleField field, int64 value) {
+ int64_fields[field - INT64_FIELDS_BEGIN] = value;
+ }
+ inline void put(Int64Field field, int64 value) {
+ int64_fields[field - INT64_FIELDS_BEGIN] = value;
+ }
+ inline void put(TimeField field, const base::Time& value) {
+ // Round-trip to proto time format and back so that we have
+ // consistent time resolutions (ms).
+ time_fields[field - TIME_FIELDS_BEGIN] =
+ browser_sync::ProtoTimeToTime(
+ browser_sync::TimeToProtoTime(value));
+ }
+ inline void put(IdField field, const Id& value) {
+ id_fields[field - ID_FIELDS_BEGIN] = value;
+ }
+ inline void put(BaseVersion field, int64 value) {
+ int64_fields[field - INT64_FIELDS_BEGIN] = value;
+ }
+ inline void put(IndexedBitField field, bool value) {
+ bit_fields[field - BIT_FIELDS_BEGIN] = value;
+ }
+ inline void put(IsDelField field, bool value) {
+ bit_fields[field - BIT_FIELDS_BEGIN] = value;
+ }
+ inline void put(BitField field, bool value) {
+ bit_fields[field - BIT_FIELDS_BEGIN] = value;
+ }
+ inline void put(StringField field, const std::string& value) {
+ string_fields[field - STRING_FIELDS_BEGIN] = value;
+ }
+ inline void put(ProtoField field, const sync_pb::EntitySpecifics& value) {
+ specifics_fields[field - PROTO_FIELDS_BEGIN].CopyFrom(value);
+ }
+ inline void put(BitTemp field, bool value) {
+ bit_temps[field - BIT_TEMPS_BEGIN] = value;
+ }
+
+ // Const ref getters.
+ inline int64 ref(MetahandleField field) const {
+ return int64_fields[field - INT64_FIELDS_BEGIN];
+ }
+ inline int64 ref(Int64Field field) const {
+ return int64_fields[field - INT64_FIELDS_BEGIN];
+ }
+ inline const base::Time& ref(TimeField field) const {
+ return time_fields[field - TIME_FIELDS_BEGIN];
+ }
+ inline const Id& ref(IdField field) const {
+ return id_fields[field - ID_FIELDS_BEGIN];
+ }
+ inline int64 ref(BaseVersion field) const {
+ return int64_fields[field - INT64_FIELDS_BEGIN];
+ }
+ inline bool ref(IndexedBitField field) const {
+ return bit_fields[field - BIT_FIELDS_BEGIN];
+ }
+ inline bool ref(IsDelField field) const {
+ return bit_fields[field - BIT_FIELDS_BEGIN];
+ }
+ inline bool ref(BitField field) const {
+ return bit_fields[field - BIT_FIELDS_BEGIN];
+ }
+ inline const std::string& ref(StringField field) const {
+ return string_fields[field - STRING_FIELDS_BEGIN];
+ }
+ inline const sync_pb::EntitySpecifics& ref(ProtoField field) const {
+ return specifics_fields[field - PROTO_FIELDS_BEGIN];
+ }
+ inline bool ref(BitTemp field) const {
+ return bit_temps[field - BIT_TEMPS_BEGIN];
+ }
+
+ // Non-const, mutable ref getters for object types only.
+ inline std::string& mutable_ref(StringField field) {
+ return string_fields[field - STRING_FIELDS_BEGIN];
+ }
+ inline sync_pb::EntitySpecifics& mutable_ref(ProtoField field) {
+ return specifics_fields[field - PROTO_FIELDS_BEGIN];
+ }
+ inline Id& mutable_ref(IdField field) {
+ return id_fields[field - ID_FIELDS_BEGIN];
+ }
+
+ syncable::ModelType GetServerModelType() const;
+
+ // Dumps all kernel info into a DictionaryValue and returns it.
+ // Transfers ownership of the DictionaryValue to the caller.
+ base::DictionaryValue* ToValue() const;
+
+ private:
+ // Tracks whether this entry needs to be saved to the database.
+ bool dirty_;
+};
+
+struct EntryKernelMutation {
+ EntryKernel original, mutated;
+};
+
+typedef std::map<int64, EntryKernelMutation> EntryKernelMutationMap;
+
+typedef browser_sync::Immutable<EntryKernelMutationMap>
+ ImmutableEntryKernelMutationMap;
+
+// Caller owns the return value.
+base::DictionaryValue* EntryKernelMutationToValue(
+ const EntryKernelMutation& mutation);
+
+// Caller owns the return value.
+base::ListValue* EntryKernelMutationMapToValue(
+ const EntryKernelMutationMap& mutations);
+
+} // namespace syncable
+
+#endif // SYNC_SYNCABLE_ENTRY_KERNEL_H_
diff --git a/sync/syncable/metahandle_set.h b/sync/syncable/metahandle_set.h
new file mode 100644
index 0000000..42fd04f
--- /dev/null
+++ b/sync/syncable/metahandle_set.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2012 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 SYNC_SYNCABLE_METAHANDLE_SET_
+#define SYNC_SYNCABLE_METAHANDLE_SET_
+
+#include "base/basictypes.h"
+
+namespace syncable {
+
+typedef std::set<int64> MetahandleSet;
+
+}
+
+#endif // SYNC_SYNCABLE_METAHANDLE_SET_
diff --git a/sync/syncable/mutable_entry.cc b/sync/syncable/mutable_entry.cc
new file mode 100644
index 0000000..77aa32c
--- /dev/null
+++ b/sync/syncable/mutable_entry.cc
@@ -0,0 +1,410 @@
+// Copyright (c) 2012 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 "sync/syncable/mutable_entry.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/scoped_index_updater.h"
+#include "sync/syncable/scoped_kernel_lock.h"
+#include "sync/syncable/syncable-inl.h"
+#include "sync/syncable/syncable_changes_version.h"
+#include "sync/syncable/syncable_util.h"
+#include "sync/syncable/write_transaction.h"
+
+using std::string;
+
+namespace syncable {
+
+MutableEntry::MutableEntry(WriteTransaction* trans, Create,
+ const Id& parent_id, const string& name)
+ : Entry(trans),
+ write_transaction_(trans) {
+ Init(trans, parent_id, name);
+}
+
+
+void MutableEntry::Init(WriteTransaction* trans, const Id& parent_id,
+ const string& name) {
+ scoped_ptr<EntryKernel> kernel(new EntryKernel);
+ kernel_ = NULL;
+
+ kernel->put(ID, trans->directory_->NextId());
+ kernel->put(META_HANDLE, trans->directory_->NextMetahandle());
+ kernel->mark_dirty(trans->directory_->kernel_->dirty_metahandles);
+ kernel->put(PARENT_ID, parent_id);
+ kernel->put(NON_UNIQUE_NAME, name);
+ const base::Time& now = base::Time::Now();
+ kernel->put(CTIME, now);
+ kernel->put(MTIME, now);
+ // We match the database defaults here
+ kernel->put(BASE_VERSION, CHANGES_VERSION);
+ if (!trans->directory()->InsertEntry(trans, kernel.get())) {
+ return; // We failed inserting, nothing more to do.
+ }
+ // Because this entry is new, it was originally deleted.
+ kernel->put(IS_DEL, true);
+ trans->SaveOriginal(kernel.get());
+ kernel->put(IS_DEL, false);
+
+ // Now swap the pointers.
+ kernel_ = kernel.release();
+}
+
+MutableEntry::MutableEntry(WriteTransaction* trans, CreateNewUpdateItem,
+ const Id& id)
+ : Entry(trans), write_transaction_(trans) {
+ Entry same_id(trans, GET_BY_ID, id);
+ kernel_ = NULL;
+ if (same_id.good()) {
+ return; // already have an item with this ID.
+ }
+ scoped_ptr<EntryKernel> kernel(new EntryKernel());
+
+ kernel->put(ID, id);
+ kernel->put(META_HANDLE, trans->directory_->NextMetahandle());
+ kernel->mark_dirty(trans->directory_->kernel_->dirty_metahandles);
+ kernel->put(IS_DEL, true);
+ // We match the database defaults here
+ kernel->put(BASE_VERSION, CHANGES_VERSION);
+ if (!trans->directory()->InsertEntry(trans, kernel.get())) {
+ return; // Failed inserting.
+ }
+ trans->SaveOriginal(kernel.get());
+
+ kernel_ = kernel.release();
+}
+
+MutableEntry::MutableEntry(WriteTransaction* trans, GetById, const Id& id)
+ : Entry(trans, GET_BY_ID, id), write_transaction_(trans) {
+}
+
+MutableEntry::MutableEntry(WriteTransaction* trans, GetByHandle,
+ int64 metahandle)
+ : Entry(trans, GET_BY_HANDLE, metahandle), write_transaction_(trans) {
+}
+
+MutableEntry::MutableEntry(WriteTransaction* trans, GetByClientTag,
+ const std::string& tag)
+ : Entry(trans, GET_BY_CLIENT_TAG, tag), write_transaction_(trans) {
+}
+
+MutableEntry::MutableEntry(WriteTransaction* trans, GetByServerTag,
+ const string& tag)
+ : Entry(trans, GET_BY_SERVER_TAG, tag), write_transaction_(trans) {
+}
+
+bool MutableEntry::PutIsDel(bool is_del) {
+ DCHECK(kernel_);
+ write_transaction_->SaveOriginal(kernel_);
+ if (is_del == kernel_->ref(IS_DEL)) {
+ return true;
+ }
+ if (is_del) {
+ if (!UnlinkFromOrder()) {
+ return false;
+ }
+
+ // If the server never knew about this item and it's deleted then we don't
+ // need to keep it around. Unsetting IS_UNSYNCED will:
+ // - Ensure that the item is never committed to the server.
+ // - Allow any items with the same UNIQUE_CLIENT_TAG created on other
+ // clients to override this entry.
+ // - Let us delete this entry permanently through
+ // DirectoryBackingStore::DropDeletedEntries() when we next restart sync.
+ // This will save memory and avoid crbug.com/125381.
+ if (!Get(ID).ServerKnows()) {
+ Put(IS_UNSYNCED, false);
+ }
+ }
+
+ {
+ ScopedKernelLock lock(dir());
+ // Some indices don't include deleted items and must be updated
+ // upon a value change.
+ ScopedIndexUpdater<ParentIdAndHandleIndexer> updater(lock, kernel_,
+ dir()->kernel_->parent_id_child_index);
+
+ kernel_->put(IS_DEL, is_del);
+ kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
+ }
+
+ if (!is_del)
+ // Restores position to the 0th index.
+ if (!PutPredecessor(Id())) {
+ // TODO(lipalani) : Propagate the error to caller. crbug.com/100444.
+ NOTREACHED();
+ }
+
+ return true;
+}
+
+bool MutableEntry::Put(Int64Field field, const int64& value) {
+ DCHECK(kernel_);
+ write_transaction_->SaveOriginal(kernel_);
+ if (kernel_->ref(field) != value) {
+ ScopedKernelLock lock(dir());
+ if (SERVER_POSITION_IN_PARENT == field) {
+ ScopedIndexUpdater<ParentIdAndHandleIndexer> updater(lock, kernel_,
+ dir()->kernel_->parent_id_child_index);
+ kernel_->put(field, value);
+ } else {
+ kernel_->put(field, value);
+ }
+ kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
+ }
+ return true;
+}
+
+bool MutableEntry::Put(TimeField field, const base::Time& value) {
+ DCHECK(kernel_);
+ write_transaction_->SaveOriginal(kernel_);
+ if (kernel_->ref(field) != value) {
+ kernel_->put(field, value);
+ kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
+ }
+ return true;
+}
+
+bool MutableEntry::Put(IdField field, const Id& value) {
+ DCHECK(kernel_);
+ write_transaction_->SaveOriginal(kernel_);
+ if (kernel_->ref(field) != value) {
+ if (ID == field) {
+ if (!dir()->ReindexId(write_transaction(), kernel_, value))
+ return false;
+ } else if (PARENT_ID == field) {
+ PutParentIdPropertyOnly(value); // Makes sibling order inconsistent.
+ // Fixes up the sibling order inconsistency.
+ if (!PutPredecessor(Id())) {
+ // TODO(lipalani) : Propagate the error to caller. crbug.com/100444.
+ NOTREACHED();
+ }
+ } else {
+ kernel_->put(field, value);
+ }
+ kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
+ }
+ return true;
+}
+
+void MutableEntry::PutParentIdPropertyOnly(const Id& parent_id) {
+ write_transaction_->SaveOriginal(kernel_);
+ dir()->ReindexParentId(write_transaction(), kernel_, parent_id);
+ kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
+}
+
+bool MutableEntry::Put(BaseVersion field, int64 value) {
+ DCHECK(kernel_);
+ write_transaction_->SaveOriginal(kernel_);
+ if (kernel_->ref(field) != value) {
+ kernel_->put(field, value);
+ kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
+ }
+ return true;
+}
+
+bool MutableEntry::Put(StringField field, const string& value) {
+ DCHECK(kernel_);
+ write_transaction_->SaveOriginal(kernel_);
+ if (field == UNIQUE_CLIENT_TAG) {
+ return PutUniqueClientTag(value);
+ }
+
+ if (kernel_->ref(field) != value) {
+ kernel_->put(field, value);
+ kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
+ }
+ return true;
+}
+
+bool MutableEntry::Put(ProtoField field,
+ const sync_pb::EntitySpecifics& value) {
+ DCHECK(kernel_);
+ write_transaction_->SaveOriginal(kernel_);
+ // TODO(ncarter): This is unfortunately heavyweight. Can we do
+ // better?
+ if (kernel_->ref(field).SerializeAsString() != value.SerializeAsString()) {
+ const bool update_unapplied_updates_index =
+ (field == SERVER_SPECIFICS) && kernel_->ref(IS_UNAPPLIED_UPDATE);
+ if (update_unapplied_updates_index) {
+ // Remove ourselves from unapplied_update_metahandles with our
+ // old server type.
+ const syncable::ModelType old_server_type =
+ kernel_->GetServerModelType();
+ const int64 metahandle = kernel_->ref(META_HANDLE);
+ size_t erase_count =
+ dir()->kernel_->unapplied_update_metahandles[old_server_type]
+ .erase(metahandle);
+ DCHECK_EQ(erase_count, 1u);
+ }
+
+ kernel_->put(field, value);
+ kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
+
+ if (update_unapplied_updates_index) {
+ // Add ourselves back into unapplied_update_metahandles with our
+ // new server type.
+ const syncable::ModelType new_server_type =
+ kernel_->GetServerModelType();
+ const int64 metahandle = kernel_->ref(META_HANDLE);
+ dir()->kernel_->unapplied_update_metahandles[new_server_type]
+ .insert(metahandle);
+ }
+ }
+ return true;
+}
+
+bool MutableEntry::Put(BitField field, bool value) {
+ DCHECK(kernel_);
+ write_transaction_->SaveOriginal(kernel_);
+ if (kernel_->ref(field) != value) {
+ kernel_->put(field, value);
+ kernel_->mark_dirty(GetDirtyIndexHelper());
+ }
+ return true;
+}
+
+MetahandleSet* MutableEntry::GetDirtyIndexHelper() {
+ return dir()->kernel_->dirty_metahandles;
+}
+
+bool MutableEntry::PutUniqueClientTag(const string& new_tag) {
+ write_transaction_->SaveOriginal(kernel_);
+ // There is no SERVER_UNIQUE_CLIENT_TAG. This field is similar to ID.
+ string old_tag = kernel_->ref(UNIQUE_CLIENT_TAG);
+ if (old_tag == new_tag) {
+ return true;
+ }
+
+ ScopedKernelLock lock(dir());
+ if (!new_tag.empty()) {
+ // Make sure your new value is not in there already.
+ EntryKernel lookup_kernel_ = *kernel_;
+ lookup_kernel_.put(UNIQUE_CLIENT_TAG, new_tag);
+ bool new_tag_conflicts =
+ (dir()->kernel_->client_tag_index->count(&lookup_kernel_) > 0);
+ if (new_tag_conflicts) {
+ return false;
+ }
+ }
+
+ {
+ ScopedIndexUpdater<ClientTagIndexer> index_updater(lock, kernel_,
+ dir()->kernel_->client_tag_index);
+ kernel_->put(UNIQUE_CLIENT_TAG, new_tag);
+ kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
+ }
+ return true;
+}
+
+bool MutableEntry::Put(IndexedBitField field, bool value) {
+ DCHECK(kernel_);
+ write_transaction_->SaveOriginal(kernel_);
+ if (kernel_->ref(field) != value) {
+ MetahandleSet* index;
+ if (IS_UNSYNCED == field) {
+ index = dir()->kernel_->unsynced_metahandles;
+ } else {
+ // Use kernel_->GetServerModelType() instead of
+ // GetServerModelType() as we may trigger some DCHECKs in the
+ // latter.
+ index =
+ &dir()->kernel_->unapplied_update_metahandles[
+ kernel_->GetServerModelType()];
+ }
+
+ ScopedKernelLock lock(dir());
+ if (value) {
+ if (!SyncAssert(index->insert(kernel_->ref(META_HANDLE)).second,
+ FROM_HERE,
+ "Could not insert",
+ write_transaction())) {
+ return false;
+ }
+ } else {
+ if (!SyncAssert(1U == index->erase(kernel_->ref(META_HANDLE)),
+ FROM_HERE,
+ "Entry Not succesfully erased",
+ write_transaction())) {
+ return false;
+ }
+ }
+ kernel_->put(field, value);
+ kernel_->mark_dirty(dir()->kernel_->dirty_metahandles);
+ }
+ return true;
+}
+
+bool MutableEntry::UnlinkFromOrder() {
+ ScopedKernelLock lock(dir());
+ return dir()->UnlinkEntryFromOrder(kernel_,
+ write_transaction(),
+ &lock,
+ NODE_MANIPULATION);
+}
+
+bool MutableEntry::PutPredecessor(const Id& predecessor_id) {
+ if (!UnlinkFromOrder())
+ return false;
+
+ if (Get(IS_DEL)) {
+ DCHECK(predecessor_id.IsNull());
+ return true;
+ }
+
+ // TODO(ncarter): It should be possible to not maintain position for
+ // non-bookmark items. However, we'd need to robustly handle all possible
+ // permutations of setting IS_DEL and the SPECIFICS to identify the
+ // object type; or else, we'd need to add a ModelType to the
+ // MutableEntry's Create ctor.
+ // if (!ShouldMaintainPosition()) {
+ // return false;
+ // }
+
+ // This is classic insert-into-doubly-linked-list from CS 101 and your last
+ // job interview. An "IsRoot" Id signifies the head or tail.
+ Id successor_id;
+ if (!predecessor_id.IsRoot()) {
+ MutableEntry predecessor(write_transaction(), GET_BY_ID, predecessor_id);
+ if (!predecessor.good()) {
+ LOG(ERROR) << "Predecessor is not good : "
+ << predecessor_id.GetServerId();
+ return false;
+ }
+ if (predecessor.Get(PARENT_ID) != Get(PARENT_ID))
+ return false;
+ successor_id = predecessor.Get(NEXT_ID);
+ predecessor.Put(NEXT_ID, Get(ID));
+ } else {
+ syncable::Directory* dir = trans()->directory();
+ if (!dir->GetFirstChildId(trans(), Get(PARENT_ID), &successor_id)) {
+ return false;
+ }
+ }
+ if (!successor_id.IsRoot()) {
+ MutableEntry successor(write_transaction(), GET_BY_ID, successor_id);
+ if (!successor.good()) {
+ LOG(ERROR) << "Successor is not good: "
+ << successor_id.GetServerId();
+ return false;
+ }
+ if (successor.Get(PARENT_ID) != Get(PARENT_ID))
+ return false;
+ successor.Put(PREV_ID, Get(ID));
+ }
+ DCHECK(predecessor_id != Get(ID));
+ DCHECK(successor_id != Get(ID));
+ Put(PREV_ID, predecessor_id);
+ Put(NEXT_ID, successor_id);
+ return true;
+}
+
+bool MutableEntry::Put(BitTemp field, bool value) {
+ DCHECK(kernel_);
+ kernel_->put(field, value);
+ return true;
+}
+
+}
diff --git a/sync/syncable/mutable_entry.h b/sync/syncable/mutable_entry.h
new file mode 100644
index 0000000..4ead080
--- /dev/null
+++ b/sync/syncable/mutable_entry.h
@@ -0,0 +1,119 @@
+// Copyright (c) 2012 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 SYNC_SYNCABLE_MUTABLE_ENTRY_H_
+#define SYNC_SYNCABLE_MUTABLE_ENTRY_H_
+#pragma once
+
+#include "sync/syncable/entry.h"
+#include "sync/syncable/metahandle_set.h"
+
+namespace sync_api {
+class WriteNode;
+}
+
+namespace syncable {
+
+class WriteTransaction;
+
+enum Create {
+ CREATE
+};
+
+enum CreateNewUpdateItem {
+ CREATE_NEW_UPDATE_ITEM
+};
+
+// A mutable meta entry. Changes get committed to the database when the
+// WriteTransaction is destroyed.
+class MutableEntry : public Entry {
+ void Init(WriteTransaction* trans, const Id& parent_id,
+ const std::string& name);
+
+ public:
+ MutableEntry(WriteTransaction* trans, Create, const Id& parent_id,
+ const std::string& name);
+ MutableEntry(WriteTransaction* trans, CreateNewUpdateItem, const Id& id);
+ MutableEntry(WriteTransaction* trans, GetByHandle, int64);
+ MutableEntry(WriteTransaction* trans, GetById, const Id&);
+ MutableEntry(WriteTransaction* trans, GetByClientTag, const std::string& tag);
+ MutableEntry(WriteTransaction* trans, GetByServerTag, const std::string& tag);
+
+ inline WriteTransaction* write_transaction() const {
+ return write_transaction_;
+ }
+
+ // Field Accessors. Some of them trigger the re-indexing of the entry.
+ // Return true on success, return false on failure, which means
+ // that putting the value would have caused a duplicate in the index.
+ // TODO(chron): Remove some of these unecessary return values.
+ bool Put(Int64Field field, const int64& value);
+ bool Put(TimeField field, const base::Time& value);
+ bool Put(IdField field, const Id& value);
+
+ // Do a simple property-only update if the PARENT_ID field. Use with caution.
+ //
+ // The normal Put(IS_PARENT) call will move the item to the front of the
+ // sibling order to maintain the linked list invariants when the parent
+ // changes. That's usually what you want to do, but it's inappropriate
+ // when the caller is trying to change the parent ID of a the whole set
+ // of children (e.g. because the ID changed during a commit). For those
+ // cases, there's this function. It will corrupt the sibling ordering
+ // if you're not careful.
+ void PutParentIdPropertyOnly(const Id& parent_id);
+
+ bool Put(StringField field, const std::string& value);
+ bool Put(BaseVersion field, int64 value);
+
+ bool Put(ProtoField field, const sync_pb::EntitySpecifics& value);
+ bool Put(BitField field, bool value);
+ inline bool Put(IsDelField field, bool value) {
+ return PutIsDel(value);
+ }
+ bool Put(IndexedBitField field, bool value);
+
+ // Sets the position of this item, and updates the entry kernels of the
+ // adjacent siblings so that list invariants are maintained. Returns false
+ // and fails if |predecessor_id| does not identify a sibling. Pass the root
+ // ID to put the node in first position.
+ bool PutPredecessor(const Id& predecessor_id);
+
+ bool Put(BitTemp field, bool value);
+
+ protected:
+ syncable::MetahandleSet* GetDirtyIndexHelper();
+
+ bool PutIsDel(bool value);
+
+ private:
+ friend class Directory;
+ friend class WriteTransaction;
+ friend class sync_api::WriteNode;
+
+ // Don't allow creation on heap, except by sync API wrappers.
+ void* operator new(size_t size) { return (::operator new)(size); }
+
+ bool PutUniqueClientTag(const std::string& value);
+
+ // Adjusts the successor and predecessor entries so that they no longer
+ // refer to this entry.
+ bool UnlinkFromOrder();
+
+ // Kind of redundant. We should reduce the number of pointers
+ // floating around if at all possible. Could we store this in Directory?
+ // Scope: Set on construction, never changed after that.
+ WriteTransaction* const write_transaction_;
+
+ protected:
+ MutableEntry();
+
+ DISALLOW_COPY_AND_ASSIGN(MutableEntry);
+};
+
+// This function sets only the flags needed to get this entry to sync.
+bool MarkForSyncing(syncable::MutableEntry* e);
+
+} // namespace syncable
+
+#endif // SYNC_SYNCABLE_MUTABLE_ENTRY_H_
diff --git a/sync/syncable/read_transaction.cc b/sync/syncable/read_transaction.cc
new file mode 100644
index 0000000..a71f1b3
--- /dev/null
+++ b/sync/syncable/read_transaction.cc
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 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 "sync/syncable/read_transaction.h"
+
+namespace syncable {
+
+ReadTransaction::ReadTransaction(const tracked_objects::Location& location,
+ Directory* directory)
+ : BaseTransaction(location, "ReadTransaction", INVALID, directory) {
+ Lock();
+}
+
+ReadTransaction::~ReadTransaction() {
+ HandleUnrecoverableErrorIfSet();
+ Unlock();
+}
+
+} // namespace syncable
diff --git a/sync/syncable/read_transaction.h b/sync/syncable/read_transaction.h
new file mode 100644
index 0000000..37241ff
--- /dev/null
+++ b/sync/syncable/read_transaction.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 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 SYNC_SYNCABLE_READ_TRANSACTION_H_
+#define SYNC_SYNCABLE_READ_TRANSACTION_H_
+#pragma once
+
+#include "sync/syncable/base_transaction.h"
+
+namespace sync_api {
+class ReadTransaction;
+}
+
+namespace syncable {
+
+// Locks db in constructor, unlocks in destructor.
+class ReadTransaction : public BaseTransaction {
+ public:
+ ReadTransaction(const tracked_objects::Location& from_here,
+ Directory* directory);
+
+ virtual ~ReadTransaction();
+
+ protected: // Don't allow creation on heap, except by sync API wrapper.
+ friend class sync_api::ReadTransaction;
+ void* operator new(size_t size) { return (::operator new)(size); }
+
+ DISALLOW_COPY_AND_ASSIGN(ReadTransaction);
+};
+
+}
+
+#endif // SYNC_SYNCABLE_READ_TRANSACTION_H_
diff --git a/sync/syncable/scoped_index_updater.h b/sync/syncable/scoped_index_updater.h
new file mode 100644
index 0000000..f24d0d2
--- /dev/null
+++ b/sync/syncable/scoped_index_updater.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 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 SYNC_SYNCABLE_SCOPED_INDEX_UPDATER_H_
+#define SYNC_SYNCABLE_SCOPED_INDEX_UPDATER_H_
+
+#include "sync/syncable/directory.h"
+
+namespace syncable {
+class ScopedKernelLock;
+
+// A ScopedIndexUpdater temporarily removes an entry from an index,
+// and restores it to the index when the scope exits. This simplifies
+// the common pattern where items need to be removed from an index
+// before updating the field.
+//
+// This class is parameterized on the Indexer traits type, which
+// must define a Comparator and a static bool ShouldInclude
+// function for testing whether the item ought to be included
+// in the index.
+template<typename Indexer>
+class ScopedIndexUpdater {
+ public:
+ ScopedIndexUpdater(const ScopedKernelLock& proof_of_lock,
+ EntryKernel* entry,
+ typename Index<Indexer>::Set* index)
+ : entry_(entry),
+ index_(index) {
+ // First call to ShouldInclude happens before the field is updated.
+ if (Indexer::ShouldInclude(entry_)) {
+ // TODO(lipalani): Replace this CHECK with |SyncAssert| by refactorting
+ // this class into a function.
+ CHECK(index_->erase(entry_));
+ }
+ }
+
+ ~ScopedIndexUpdater() {
+ // Second call to ShouldInclude happens after the field is updated.
+ if (Indexer::ShouldInclude(entry_)) {
+ // TODO(lipalani): Replace this CHECK with |SyncAssert| by refactorting
+ // this class into a function.
+ CHECK(index_->insert(entry_).second);
+ }
+ }
+ private:
+ // The entry that was temporarily removed from the index.
+ EntryKernel* entry_;
+ // The index which we are updating.
+ typename Index<Indexer>::Set* const index_;
+};
+
+} // namespace syncable
+
+#endif // SYNC_SYNCABLE_SCOPED_INDEX_UPDATER_H_
diff --git a/sync/syncable/scoped_kernel_lock.h b/sync/syncable/scoped_kernel_lock.h
new file mode 100644
index 0000000..aaac150
--- /dev/null
+++ b/sync/syncable/scoped_kernel_lock.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 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 SYNC_SYNCABLE_SCOPED_KERNEL_LOCK_H_
+#define SYNC_SYNCABLE_SCOPED_KERNEL_LOCK_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/synchronization/lock.h"
+
+namespace syncable {
+
+class Directory;
+
+class ScopedKernelLock {
+ public:
+ explicit ScopedKernelLock(const Directory* dir);
+ ~ScopedKernelLock() {}
+
+ base::AutoLock scoped_lock_;
+ Directory* const dir_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedKernelLock);
+};
+
+} // namespace syncable
+
+#endif // SYNC_SYNCABLE_SCOPED_KERNEL_LOCK_H_
diff --git a/sync/syncable/syncable-inl.h b/sync/syncable/syncable-inl.h
index 1b28139..5b8046b 100644
--- a/sync/syncable/syncable-inl.h
+++ b/sync/syncable/syncable-inl.h
@@ -6,7 +6,7 @@
#define SYNC_SYNCABLE_SYNCABLE_INL_H_
#pragma once
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/entry_kernel.h"
namespace syncable {
diff --git a/sync/syncable/syncable_columns.h b/sync/syncable/syncable_columns.h
index 18a0215..faf0da7 100644
--- a/sync/syncable/syncable_columns.h
+++ b/sync/syncable/syncable_columns.h
@@ -6,7 +6,7 @@
#define SYNC_SYNCABLE_SYNCABLE_COLUMNS_H_
#pragma once
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/entry_kernel.h"
#include "sync/syncable/syncable_changes_version.h"
namespace syncable {
diff --git a/sync/syncable/syncable_enum_conversions.cc b/sync/syncable/syncable_enum_conversions.cc
index eaf5edd..e3131c3 100644
--- a/sync/syncable/syncable_enum_conversions.cc
+++ b/sync/syncable/syncable_enum_conversions.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Keep this file in sync with syncable.h.
+// Keep this file in sync with entry_kernel.h.
#include "sync/syncable/syncable_enum_conversions.h"
diff --git a/sync/syncable/syncable_enum_conversions.h b/sync/syncable/syncable_enum_conversions.h
index ae251c8..1c058408 100644
--- a/sync/syncable/syncable_enum_conversions.h
+++ b/sync/syncable/syncable_enum_conversions.h
@@ -6,9 +6,9 @@
#define SYNC_SYNCABLE_SYNCABLE_ENUM_CONVERSIONS_H_
#pragma once
-// Keep this file in sync with syncable.h.
+// Keep this file in sync with entry_kernel.h.
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/entry_kernel.h"
// Utility functions to get the string equivalent for some syncable
// enums.
diff --git a/sync/syncable/syncable_enum_conversions_unittest.cc b/sync/syncable/syncable_enum_conversions_unittest.cc
index 8ce4a40..bba88ea 100644
--- a/sync/syncable/syncable_enum_conversions_unittest.cc
+++ b/sync/syncable/syncable_enum_conversions_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Keep this file in sync with syncable.h.
+// Keep this file in sync with entry_kernel.h.
#include "sync/syncable/syncable_enum_conversions.h"
diff --git a/sync/syncable/syncable_mock.h b/sync/syncable/syncable_mock.h
index 27fcee8..0dec075 100644
--- a/sync/syncable/syncable_mock.h
+++ b/sync/syncable/syncable_mock.h
@@ -8,7 +8,8 @@
#include <string>
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/write_transaction.h"
#include "sync/test/fake_encryptor.h"
#include "sync/test/null_directory_change_delegate.h"
#include "testing/gmock/include/gmock/gmock.h"
diff --git a/sync/syncable/syncable_unittest.cc b/sync/syncable/syncable_unittest.cc
index c6f44d3..bc821bf 100644
--- a/sync/syncable/syncable_unittest.cc
+++ b/sync/syncable/syncable_unittest.cc
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "sync/syncable/syncable.h"
-
#include <string>
#include "base/compiler_specific.h"
@@ -20,16 +18,21 @@
#include "base/threading/platform_thread.h"
#include "base/values.h"
#include "sync/engine/syncproto.h"
-#include "sync/util/test_unrecoverable_error_handler.h"
+#include "sync/protocol/bookmark_specifics.pb.h"
#include "sync/syncable/directory_backing_store.h"
#include "sync/syncable/directory_change_delegate.h"
+#include "sync/syncable/metahandle_set.h"
+#include "sync/syncable/mutable_entry.h"
#include "sync/syncable/on_disk_directory_backing_store.h"
+#include "sync/syncable/read_transaction.h"
+#include "sync/syncable/syncable_util.h"
+#include "sync/syncable/write_transaction.h"
#include "sync/test/engine/test_id_factory.h"
#include "sync/test/engine/test_syncable_utils.h"
#include "sync/test/fake_encryptor.h"
#include "sync/test/null_directory_change_delegate.h"
#include "sync/test/null_transaction_observer.h"
-#include "sync/protocol/bookmark_specifics.pb.h"
+#include "sync/util/test_unrecoverable_error_handler.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::ExpectDictBooleanValue;
diff --git a/sync/syncable/syncable_util.cc b/sync/syncable/syncable_util.cc
new file mode 100644
index 0000000..cf5af08
--- /dev/null
+++ b/sync/syncable/syncable_util.cc
@@ -0,0 +1,104 @@
+// Copyright (c) 2012 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 "sync/syncable/syncable_util.h"
+
+#include "base/location.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/entry.h"
+#include "sync/syncable/mutable_entry.h"
+#include "sync/syncable/syncable_id.h"
+#include "sync/syncable/write_transaction.h"
+
+namespace syncable {
+
+bool IsLegalNewParent(BaseTransaction* trans, const Id& entry_id,
+ const Id& new_parent_id) {
+ if (entry_id.IsRoot())
+ return false;
+ // we have to ensure that the entry is not an ancestor of the new parent.
+ Id ancestor_id = new_parent_id;
+ while (!ancestor_id.IsRoot()) {
+ if (entry_id == ancestor_id)
+ return false;
+ Entry new_parent(trans, GET_BY_ID, ancestor_id);
+ if (!SyncAssert(new_parent.good(),
+ FROM_HERE,
+ "Invalid new parent",
+ trans))
+ return false;
+ ancestor_id = new_parent.Get(PARENT_ID);
+ }
+ return true;
+}
+
+// This function sets only the flags needed to get this entry to sync.
+bool MarkForSyncing(syncable::MutableEntry* e) {
+ DCHECK_NE(static_cast<MutableEntry*>(NULL), e);
+ DCHECK(!e->IsRoot()) << "We shouldn't mark a permanent object for syncing.";
+ if (!(e->Put(IS_UNSYNCED, true)))
+ return false;
+ e->Put(SYNCING, false);
+ return true;
+}
+
+void ChangeEntryIDAndUpdateChildren(
+ syncable::WriteTransaction* trans,
+ syncable::MutableEntry* entry,
+ const syncable::Id& new_id) {
+ syncable::Id old_id = entry->Get(ID);
+ if (!entry->Put(ID, new_id)) {
+ Entry old_entry(trans, GET_BY_ID, new_id);
+ CHECK(old_entry.good());
+ LOG(FATAL) << "Attempt to change ID to " << new_id
+ << " conflicts with existing entry.\n\n"
+ << *entry << "\n\n" << old_entry;
+ }
+ if (entry->Get(IS_DIR)) {
+ // Get all child entries of the old id.
+ syncable::Directory::ChildHandles children;
+ trans->directory()->GetChildHandlesById(trans, old_id, &children);
+ Directory::ChildHandles::iterator i = children.begin();
+ while (i != children.end()) {
+ MutableEntry child_entry(trans, GET_BY_HANDLE, *i++);
+ CHECK(child_entry.good());
+ // Use the unchecked setter here to avoid touching the child's NEXT_ID
+ // and PREV_ID fields (which Put(PARENT_ID) would normally do to
+ // maintain linked-list invariants). In this case, NEXT_ID and PREV_ID
+ // among the children will be valid after the loop, since we update all
+ // the children at once.
+ child_entry.PutParentIdPropertyOnly(new_id);
+ }
+ }
+ // Update Id references on the previous and next nodes in the sibling
+ // order. Do this by reinserting into the linked list; the first
+ // step in PutPredecessor is to Unlink from the existing order, which
+ // will overwrite the stale Id value from the adjacent nodes.
+ if (entry->Get(PREV_ID) == entry->Get(NEXT_ID) &&
+ entry->Get(PREV_ID) == old_id) {
+ // We just need a shallow update to |entry|'s fields since it is already
+ // self looped.
+ entry->Put(NEXT_ID, new_id);
+ entry->Put(PREV_ID, new_id);
+ } else {
+ entry->PutPredecessor(entry->Get(PREV_ID));
+ }
+}
+
+// Function to handle runtime failures on syncable code. Rather than crashing,
+// if the |condition| is false the following will happen:
+// 1. Sets unrecoverable error on transaction.
+// 2. Returns false.
+bool SyncAssert(bool condition,
+ const tracked_objects::Location& location,
+ const char* msg,
+ BaseTransaction* trans) {
+ if (!condition) {
+ trans->OnUnrecoverableError(location, msg);
+ return false;
+ }
+ return true;
+}
+
+} // namespace syncable
diff --git a/sync/syncable/syncable_util.h b/sync/syncable/syncable_util.h
new file mode 100644
index 0000000..133f5ad
--- /dev/null
+++ b/sync/syncable/syncable_util.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 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 SYNC_SYNCABLE_SYNCABLE_UTIL_H_
+#define SYNC_SYNCABLE_SYNCABLE_UTIL_H_
+
+namespace tracked_objects {
+class Location;
+}
+
+namespace syncable {
+
+class BaseTransaction;
+class WriteTransaction;
+class MutableEntry;
+class Id;
+
+void ChangeEntryIDAndUpdateChildren(syncable::WriteTransaction* trans,
+ syncable::MutableEntry* entry,
+ const syncable::Id& new_id);
+
+bool IsLegalNewParent(BaseTransaction* trans, const Id& id, const Id& parentid);
+
+bool SyncAssert(bool condition,
+ const tracked_objects::Location& location,
+ const char* msg,
+ BaseTransaction* trans);
+} // namespace syncable
+
+#endif // SYNC_SYNCABLE_SYNCABLE_UTIL_H_
diff --git a/sync/syncable/transaction_observer.h b/sync/syncable/transaction_observer.h
index 28db7a0..f5430ba 100644
--- a/sync/syncable/transaction_observer.h
+++ b/sync/syncable/transaction_observer.h
@@ -7,7 +7,7 @@
#pragma once
#include "sync/internal_api/public/syncable/model_type.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/write_transaction_info.h"
namespace syncable {
diff --git a/sync/syncable/write_transaction.cc b/sync/syncable/write_transaction.cc
new file mode 100644
index 0000000..d624ae6
--- /dev/null
+++ b/sync/syncable/write_transaction.cc
@@ -0,0 +1,158 @@
+// Copyright (c) 2012 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 "sync/syncable/write_transaction.h"
+
+#include "sync/syncable/directory.h"
+#include "sync/syncable/directory_change_delegate.h"
+#include "sync/syncable/transaction_observer.h"
+#include "sync/syncable/write_transaction_info.h"
+
+namespace syncable {
+
+enum InvariantCheckLevel {
+ OFF = 0,
+ VERIFY_IN_MEMORY = 1,
+ FULL_DB_VERIFICATION = 2
+};
+
+const InvariantCheckLevel kInvariantCheckLevel = VERIFY_IN_MEMORY;
+
+WriteTransaction::WriteTransaction(const tracked_objects::Location& location,
+ WriterTag writer, Directory* directory)
+ : BaseTransaction(location, "WriteTransaction", writer, directory) {
+ Lock();
+}
+
+void WriteTransaction::SaveOriginal(const EntryKernel* entry) {
+ if (!entry) {
+ return;
+ }
+ // Insert only if it's not already there.
+ const int64 handle = entry->ref(META_HANDLE);
+ EntryKernelMutationMap::iterator it = mutations_.lower_bound(handle);
+ if (it == mutations_.end() || it->first != handle) {
+ EntryKernelMutation mutation;
+ mutation.original = *entry;
+ ignore_result(mutations_.insert(it, std::make_pair(handle, mutation)));
+ }
+}
+
+ImmutableEntryKernelMutationMap WriteTransaction::RecordMutations() {
+ directory_->kernel_->transaction_mutex.AssertAcquired();
+ for (syncable::EntryKernelMutationMap::iterator it = mutations_.begin();
+ it != mutations_.end();) {
+ EntryKernel* kernel = directory()->GetEntryByHandle(it->first);
+ if (!kernel) {
+ NOTREACHED();
+ continue;
+ }
+ if (kernel->is_dirty()) {
+ it->second.mutated = *kernel;
+ ++it;
+ } else {
+ DCHECK(!it->second.original.is_dirty());
+ // Not actually mutated, so erase from |mutations_|.
+ mutations_.erase(it++);
+ }
+ }
+ return ImmutableEntryKernelMutationMap(&mutations_);
+}
+
+void WriteTransaction::UnlockAndNotify(
+ const ImmutableEntryKernelMutationMap& mutations) {
+ // Work while transaction mutex is held.
+ ModelTypeSet models_with_changes;
+ bool has_mutations = !mutations.Get().empty();
+ if (has_mutations) {
+ models_with_changes = NotifyTransactionChangingAndEnding(mutations);
+ }
+ Unlock();
+
+ // Work after mutex is relased.
+ if (has_mutations) {
+ NotifyTransactionComplete(models_with_changes);
+ }
+}
+
+ModelTypeSet WriteTransaction::NotifyTransactionChangingAndEnding(
+ const ImmutableEntryKernelMutationMap& mutations) {
+ directory_->kernel_->transaction_mutex.AssertAcquired();
+ DCHECK(!mutations.Get().empty());
+
+ WriteTransactionInfo write_transaction_info(
+ directory_->kernel_->next_write_transaction_id,
+ from_here_, writer_, mutations);
+ ++directory_->kernel_->next_write_transaction_id;
+
+ ImmutableWriteTransactionInfo immutable_write_transaction_info(
+ &write_transaction_info);
+ DirectoryChangeDelegate* const delegate = directory_->kernel_->delegate;
+ if (writer_ == syncable::SYNCAPI) {
+ delegate->HandleCalculateChangesChangeEventFromSyncApi(
+ immutable_write_transaction_info, this);
+ } else {
+ delegate->HandleCalculateChangesChangeEventFromSyncer(
+ immutable_write_transaction_info, this);
+ }
+
+ ModelTypeSet models_with_changes =
+ delegate->HandleTransactionEndingChangeEvent(
+ immutable_write_transaction_info, this);
+
+ directory_->kernel_->transaction_observer.Call(FROM_HERE,
+ &TransactionObserver::OnTransactionWrite,
+ immutable_write_transaction_info, models_with_changes);
+
+ return models_with_changes;
+}
+
+void WriteTransaction::NotifyTransactionComplete(
+ ModelTypeSet models_with_changes) {
+ directory_->kernel_->delegate->HandleTransactionCompleteChangeEvent(
+ models_with_changes);
+}
+
+WriteTransaction::~WriteTransaction() {
+ const ImmutableEntryKernelMutationMap& mutations = RecordMutations();
+
+ if (!unrecoverable_error_set_) {
+ if (OFF != kInvariantCheckLevel) {
+ const bool full_scan = (FULL_DB_VERIFICATION == kInvariantCheckLevel);
+ if (full_scan)
+ directory()->CheckTreeInvariants(this, full_scan);
+ else
+ directory()->CheckTreeInvariants(this, mutations.Get());
+ }
+ }
+
+ // |CheckTreeInvariants| could have thrown an unrecoverable error.
+ if (unrecoverable_error_set_) {
+ HandleUnrecoverableErrorIfSet();
+ Unlock();
+ return;
+ }
+
+ UnlockAndNotify(mutations);
+}
+
+#define ENUM_CASE(x) case x: return #x; break
+
+std::string WriterTagToString(WriterTag writer_tag) {
+ switch (writer_tag) {
+ ENUM_CASE(INVALID);
+ ENUM_CASE(SYNCER);
+ ENUM_CASE(AUTHWATCHER);
+ ENUM_CASE(UNITTEST);
+ ENUM_CASE(VACUUM_AFTER_SAVE);
+ ENUM_CASE(PURGE_ENTRIES);
+ ENUM_CASE(SYNCAPI);
+ };
+ NOTREACHED();
+ return "";
+}
+
+#undef ENUM_CASE
+
+} // namespace syncable
diff --git a/sync/syncable/write_transaction.h b/sync/syncable/write_transaction.h
new file mode 100644
index 0000000..685e447
--- /dev/null
+++ b/sync/syncable/write_transaction.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2012 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 SYNC_SYNCABLE_WRITE_TRANSACTION_H_
+#define SYNC_SYNCABLE_WRITE_TRANSACTION_H_
+#pragma once
+
+#include "sync/syncable/base_transaction.h"
+#include "sync/syncable/entry_kernel.h"
+
+namespace syncable {
+
+// Locks db in constructor, unlocks in destructor.
+class WriteTransaction : public BaseTransaction {
+ public:
+ WriteTransaction(const tracked_objects::Location& from_here,
+ WriterTag writer, Directory* directory);
+
+ virtual ~WriteTransaction();
+
+ void SaveOriginal(const EntryKernel* entry);
+
+ protected:
+ // Overridden by tests.
+ virtual void NotifyTransactionComplete(ModelTypeSet models_with_changes);
+
+ private:
+ friend class MutableEntry;
+
+ // Clears |mutations_|.
+ ImmutableEntryKernelMutationMap RecordMutations();
+
+ void UnlockAndNotify(const ImmutableEntryKernelMutationMap& mutations);
+
+ ModelTypeSet NotifyTransactionChangingAndEnding(
+ const ImmutableEntryKernelMutationMap& mutations);
+
+ // Only the original fields are filled in until |RecordMutations()|.
+ // We use a mutation map instead of a kernel set to avoid copying.
+ EntryKernelMutationMap mutations_;
+
+ DISALLOW_COPY_AND_ASSIGN(WriteTransaction);
+};
+
+} // namespace syncable
+
+#endif // SYNC_SYNCABLE_WRITE_TRANSACTION_H_
diff --git a/sync/syncable/write_transaction_info.cc b/sync/syncable/write_transaction_info.cc
new file mode 100644
index 0000000..0d6cef2
--- /dev/null
+++ b/sync/syncable/write_transaction_info.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 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 "sync/syncable/write_transaction_info.h"
+
+#include "base/string_number_conversions.h"
+
+namespace syncable {
+
+WriteTransactionInfo::WriteTransactionInfo(
+ int64 id,
+ tracked_objects::Location location,
+ WriterTag writer,
+ ImmutableEntryKernelMutationMap mutations)
+ : id(id),
+ location_string(location.ToString()),
+ writer(writer),
+ mutations(mutations) {}
+
+WriteTransactionInfo::WriteTransactionInfo()
+ : id(-1), writer(INVALID) {}
+
+WriteTransactionInfo::~WriteTransactionInfo() {}
+
+base::DictionaryValue* WriteTransactionInfo::ToValue(
+ size_t max_mutations_size) const {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetString("id", base::Int64ToString(id));
+ dict->SetString("location", location_string);
+ dict->SetString("writer", WriterTagToString(writer));
+ Value* mutations_value = NULL;
+ const size_t mutations_size = mutations.Get().size();
+ if (mutations_size <= max_mutations_size) {
+ mutations_value = EntryKernelMutationMapToValue(mutations.Get());
+ } else {
+ mutations_value =
+ Value::CreateStringValue(
+ base::Uint64ToString(static_cast<uint64>(mutations_size)) +
+ " mutations");
+ }
+ dict->Set("mutations", mutations_value);
+ return dict;
+}
+
+} // namespace syncable
diff --git a/sync/syncable/write_transaction_info.h b/sync/syncable/write_transaction_info.h
new file mode 100644
index 0000000..9441bf5
--- /dev/null
+++ b/sync/syncable/write_transaction_info.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 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 SYNC_SYNCABLE_WRITE_TRANSACTION_INFO_H_
+#define SYNC_SYNCABLE_WRITE_TRANSACTION_INFO_H_
+#pragma once
+
+#include "sync/syncable/base_transaction.h"
+#include "sync/syncable/entry_kernel.h"
+
+namespace syncable {
+
+// A struct describing the changes made during a transaction.
+struct WriteTransactionInfo {
+ WriteTransactionInfo(int64 id,
+ tracked_objects::Location location,
+ WriterTag writer,
+ ImmutableEntryKernelMutationMap mutations);
+ WriteTransactionInfo();
+ ~WriteTransactionInfo();
+
+ // Caller owns the return value.
+ base::DictionaryValue* ToValue(size_t max_mutations_size) const;
+
+ int64 id;
+ // If tracked_objects::Location becomes assignable, we can use that
+ // instead.
+ std::string location_string;
+ WriterTag writer;
+ ImmutableEntryKernelMutationMap mutations;
+};
+
+typedef
+ browser_sync::Immutable<WriteTransactionInfo>
+ ImmutableWriteTransactionInfo;
+
+} // namespace syncable
+
+#endif // SYNC_SYNCABLE_WRITE_TRANSACTION_INFO_H_
diff --git a/sync/test/engine/mock_connection_manager.cc b/sync/test/engine/mock_connection_manager.cc
index 84a07dd..f7ecac0 100644
--- a/sync/test/engine/mock_connection_manager.cc
+++ b/sync/test/engine/mock_connection_manager.cc
@@ -12,7 +12,8 @@
#include "base/stringprintf.h"
#include "sync/engine/syncer_proto_util.h"
#include "sync/protocol/bookmark_specifics.pb.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/write_transaction.h"
#include "sync/test/engine/test_id_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/sync/test/engine/test_directory_setter_upper.cc b/sync/test/engine/test_directory_setter_upper.cc
index 01fef5d..5303bea 100644
--- a/sync/test/engine/test_directory_setter_upper.cc
+++ b/sync/test/engine/test_directory_setter_upper.cc
@@ -8,7 +8,8 @@
#include "base/file_util.h"
#include "base/location.h"
#include "base/string_util.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/read_transaction.h"
#include "sync/test/null_transaction_observer.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/sync/test/engine/test_syncable_utils.cc b/sync/test/engine/test_syncable_utils.cc
index ab07e4c..c899ad3 100644
--- a/sync/test/engine/test_syncable_utils.cc
+++ b/sync/test/engine/test_syncable_utils.cc
@@ -6,7 +6,9 @@
#include "sync/test/engine/test_syncable_utils.h"
-#include "sync/syncable/syncable.h"
+#include "sync/syncable/base_transaction.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/entry.h"
using std::string;
diff --git a/sync/test/engine/test_syncable_utils.h b/sync/test/engine/test_syncable_utils.h
index 1095fc0..c10b5e2 100644
--- a/sync/test/engine/test_syncable_utils.h
+++ b/sync/test/engine/test_syncable_utils.h
@@ -11,8 +11,6 @@
#include <string>
-#include "sync/syncable/syncable.h"
-
namespace syncable {
class BaseTransaction;