Roll WebRTC 9846:9854, Libjingle 9845:9853
[chromium-blink-merge.git] / sync / syncable / syncable_write_transaction.cc
blob6a5557f2bbb8d8228c315c9c08bf429d82d0bc4c
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "sync/syncable/syncable_write_transaction.h"
7 #include "sync/syncable/directory.h"
8 #include "sync/syncable/directory_change_delegate.h"
9 #include "sync/syncable/mutable_entry.h"
10 #include "sync/syncable/transaction_observer.h"
11 #include "sync/syncable/write_transaction_info.h"
13 namespace syncer {
14 namespace syncable {
16 const int64 kInvalidTransactionVersion = -1;
18 WriteTransaction::WriteTransaction(const tracked_objects::Location& location,
19 WriterTag writer, Directory* directory)
20 : BaseWriteTransaction(location, "WriteTransaction", writer, directory),
21 transaction_version_(NULL) {
22 Lock();
25 WriteTransaction::WriteTransaction(const tracked_objects::Location& location,
26 Directory* directory,
27 int64* transaction_version)
28 : BaseWriteTransaction(location, "WriteTransaction", SYNCAPI, directory),
29 transaction_version_(transaction_version) {
30 Lock();
31 if (transaction_version_)
32 *transaction_version_ = kInvalidTransactionVersion;
35 void WriteTransaction::TrackChangesTo(const EntryKernel* entry) {
36 if (!entry) {
37 return;
39 // Insert only if it's not already there.
40 const int64 handle = entry->ref(META_HANDLE);
41 EntryKernelMutationMap::iterator it = mutations_.lower_bound(handle);
42 if (it == mutations_.end() || it->first != handle) {
43 mutations_[handle].original = *entry;
47 ImmutableEntryKernelMutationMap WriteTransaction::RecordMutations() {
48 directory_->kernel()->transaction_mutex.AssertAcquired();
49 for (syncable::EntryKernelMutationMap::iterator it = mutations_.begin();
50 it != mutations_.end();) {
51 EntryKernel* kernel = directory()->GetEntryByHandle(it->first);
52 if (!kernel) {
53 NOTREACHED();
54 continue;
56 if (kernel->is_dirty()) {
57 it->second.mutated = *kernel;
58 ++it;
59 } else {
60 DCHECK(!it->second.original.is_dirty());
61 // Not actually mutated, so erase from |mutations_|.
62 mutations_.erase(it++);
65 return ImmutableEntryKernelMutationMap(&mutations_);
68 void WriteTransaction::UnlockAndNotify(
69 const ImmutableEntryKernelMutationMap& mutations) {
70 // Work while transaction mutex is held.
71 ModelTypeSet models_with_changes;
72 bool has_mutations = !mutations.Get().empty();
73 if (has_mutations) {
74 models_with_changes = NotifyTransactionChangingAndEnding(mutations);
76 Unlock();
78 // Work after mutex is relased.
79 if (has_mutations) {
80 NotifyTransactionComplete(models_with_changes);
84 ModelTypeSet WriteTransaction::NotifyTransactionChangingAndEnding(
85 const ImmutableEntryKernelMutationMap& mutations) {
86 directory_->kernel()->transaction_mutex.AssertAcquired();
87 DCHECK(!mutations.Get().empty());
89 WriteTransactionInfo write_transaction_info(
90 directory_->kernel()->next_write_transaction_id,
91 from_here_, writer_, mutations);
92 ++directory_->kernel()->next_write_transaction_id;
94 ImmutableWriteTransactionInfo immutable_write_transaction_info(
95 &write_transaction_info);
96 DirectoryChangeDelegate* const delegate = directory_->kernel()->delegate;
97 std::vector<int64> entry_changed;
98 if (writer_ == syncable::SYNCAPI) {
99 delegate->HandleCalculateChangesChangeEventFromSyncApi(
100 immutable_write_transaction_info, this, &entry_changed);
101 } else {
102 delegate->HandleCalculateChangesChangeEventFromSyncer(
103 immutable_write_transaction_info, this, &entry_changed);
105 UpdateTransactionVersion(entry_changed);
107 ModelTypeSet models_with_changes =
108 delegate->HandleTransactionEndingChangeEvent(
109 immutable_write_transaction_info, this);
111 directory_->kernel()->transaction_observer.Call(FROM_HERE,
112 &TransactionObserver::OnTransactionWrite,
113 immutable_write_transaction_info, models_with_changes);
115 return models_with_changes;
118 void WriteTransaction::NotifyTransactionComplete(
119 ModelTypeSet models_with_changes) {
120 directory_->kernel()->delegate->HandleTransactionCompleteChangeEvent(
121 models_with_changes);
124 void WriteTransaction::UpdateTransactionVersion(
125 const std::vector<int64>& entry_changed) {
126 syncer::ModelTypeSet type_seen;
127 for (uint32 i = 0; i < entry_changed.size(); ++i) {
128 MutableEntry entry(this, GET_BY_HANDLE, entry_changed[i]);
129 if (entry.good()) {
130 ModelType type = GetModelTypeFromSpecifics(entry.GetSpecifics());
131 if (type < FIRST_REAL_MODEL_TYPE)
132 continue;
133 if (!type_seen.Has(type)) {
134 directory_->IncrementTransactionVersion(type);
135 type_seen.Put(type);
137 entry.UpdateTransactionVersion(directory_->GetTransactionVersion(type));
141 if (!type_seen.Empty() && transaction_version_) {
142 DCHECK_EQ(1u, type_seen.Size());
143 *transaction_version_ = directory_->GetTransactionVersion(
144 type_seen.First().Get());
148 WriteTransaction::~WriteTransaction() {
149 const ImmutableEntryKernelMutationMap& mutations = RecordMutations();
151 MetahandleSet modified_handles;
152 for (EntryKernelMutationMap::const_iterator i = mutations.Get().begin();
153 i != mutations.Get().end(); ++i) {
154 modified_handles.insert(i->first);
156 directory()->CheckInvariantsOnTransactionClose(this, modified_handles);
158 // |CheckTreeInvariants| could have thrown an unrecoverable error.
159 if (unrecoverable_error_set_) {
160 HandleUnrecoverableErrorIfSet();
161 Unlock();
162 return;
165 UnlockAndNotify(mutations);
168 #define ENUM_CASE(x) case x: return #x; break
170 std::string WriterTagToString(WriterTag writer_tag) {
171 switch (writer_tag) {
172 ENUM_CASE(INVALID);
173 ENUM_CASE(SYNCER);
174 ENUM_CASE(AUTHWATCHER);
175 ENUM_CASE(UNITTEST);
176 ENUM_CASE(VACUUM_AFTER_SAVE);
177 ENUM_CASE(HANDLE_SAVE_FAILURE);
178 ENUM_CASE(PURGE_ENTRIES);
179 ENUM_CASE(SYNCAPI);
181 NOTREACHED();
182 return std::string();
185 #undef ENUM_CASE
187 } // namespace syncable
188 } // namespace syncer