Add tests to verify accelerators properly work on constrained window.
[chromium-blink-merge.git] / sync / syncable / syncable_write_transaction.cc
blob788d92205acec658cca7790451be30baec6a0e68
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 : BaseTransaction(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 : BaseTransaction(location, "WriteTransaction", SYNCAPI, directory),
29 transaction_version_(transaction_version) {
30 Lock();
31 if (transaction_version_)
32 *transaction_version_ = kInvalidTransactionVersion;
35 void WriteTransaction::SaveOriginal(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 EntryKernelMutation mutation;
44 mutation.original = *entry;
45 ignore_result(mutations_.insert(it, std::make_pair(handle, mutation)));
49 ImmutableEntryKernelMutationMap WriteTransaction::RecordMutations() {
50 directory_->kernel_->transaction_mutex.AssertAcquired();
51 for (syncable::EntryKernelMutationMap::iterator it = mutations_.begin();
52 it != mutations_.end();) {
53 EntryKernel* kernel = directory()->GetEntryByHandle(it->first);
54 if (!kernel) {
55 NOTREACHED();
56 continue;
58 if (kernel->is_dirty()) {
59 it->second.mutated = *kernel;
60 ++it;
61 } else {
62 DCHECK(!it->second.original.is_dirty());
63 // Not actually mutated, so erase from |mutations_|.
64 mutations_.erase(it++);
67 return ImmutableEntryKernelMutationMap(&mutations_);
70 void WriteTransaction::UnlockAndNotify(
71 const ImmutableEntryKernelMutationMap& mutations) {
72 // Work while transaction mutex is held.
73 ModelTypeSet models_with_changes;
74 bool has_mutations = !mutations.Get().empty();
75 if (has_mutations) {
76 models_with_changes = NotifyTransactionChangingAndEnding(mutations);
78 Unlock();
80 // Work after mutex is relased.
81 if (has_mutations) {
82 NotifyTransactionComplete(models_with_changes);
86 ModelTypeSet WriteTransaction::NotifyTransactionChangingAndEnding(
87 const ImmutableEntryKernelMutationMap& mutations) {
88 directory_->kernel_->transaction_mutex.AssertAcquired();
89 DCHECK(!mutations.Get().empty());
91 WriteTransactionInfo write_transaction_info(
92 directory_->kernel_->next_write_transaction_id,
93 from_here_, writer_, mutations);
94 ++directory_->kernel_->next_write_transaction_id;
96 ImmutableWriteTransactionInfo immutable_write_transaction_info(
97 &write_transaction_info);
98 DirectoryChangeDelegate* const delegate = directory_->kernel_->delegate;
99 std::vector<int64> entry_changed;
100 if (writer_ == syncable::SYNCAPI) {
101 delegate->HandleCalculateChangesChangeEventFromSyncApi(
102 immutable_write_transaction_info, this, &entry_changed);
103 } else {
104 delegate->HandleCalculateChangesChangeEventFromSyncer(
105 immutable_write_transaction_info, this, &entry_changed);
107 UpdateTransactionVersion(entry_changed);
109 ModelTypeSet models_with_changes =
110 delegate->HandleTransactionEndingChangeEvent(
111 immutable_write_transaction_info, this);
113 directory_->kernel_->transaction_observer.Call(FROM_HERE,
114 &TransactionObserver::OnTransactionWrite,
115 immutable_write_transaction_info, models_with_changes);
117 return models_with_changes;
120 void WriteTransaction::NotifyTransactionComplete(
121 ModelTypeSet models_with_changes) {
122 directory_->kernel_->delegate->HandleTransactionCompleteChangeEvent(
123 models_with_changes);
126 void WriteTransaction::UpdateTransactionVersion(
127 const std::vector<int64>& entry_changed) {
128 syncer::ModelTypeSet type_seen;
129 for (uint32 i = 0; i < entry_changed.size(); ++i) {
130 MutableEntry entry(this, GET_BY_HANDLE, entry_changed[i]);
131 if (entry.good()) {
132 ModelType type = GetModelTypeFromSpecifics(entry.Get(SPECIFICS));
133 if (type < FIRST_REAL_MODEL_TYPE)
134 continue;
135 if (!type_seen.Has(type)) {
136 directory_->IncrementTransactionVersion(type);
137 type_seen.Put(type);
139 entry.Put(TRANSACTION_VERSION, directory_->GetTransactionVersion(type));
143 if (!type_seen.Empty() && transaction_version_) {
144 DCHECK_EQ(1u, type_seen.Size());
145 *transaction_version_ = directory_->GetTransactionVersion(
146 type_seen.First().Get());
150 WriteTransaction::~WriteTransaction() {
151 const ImmutableEntryKernelMutationMap& mutations = RecordMutations();
152 directory()->CheckInvariantsOnTransactionClose(this, mutations.Get());
154 // |CheckTreeInvariants| could have thrown an unrecoverable error.
155 if (unrecoverable_error_set_) {
156 HandleUnrecoverableErrorIfSet();
157 Unlock();
158 return;
161 UnlockAndNotify(mutations);
164 #define ENUM_CASE(x) case x: return #x; break
166 std::string WriterTagToString(WriterTag writer_tag) {
167 switch (writer_tag) {
168 ENUM_CASE(INVALID);
169 ENUM_CASE(SYNCER);
170 ENUM_CASE(AUTHWATCHER);
171 ENUM_CASE(UNITTEST);
172 ENUM_CASE(VACUUM_AFTER_SAVE);
173 ENUM_CASE(HANDLE_SAVE_FAILURE);
174 ENUM_CASE(PURGE_ENTRIES);
175 ENUM_CASE(SYNCAPI);
177 NOTREACHED();
178 return "";
181 #undef ENUM_CASE
183 } // namespace syncable
184 } // namespace syncer