Skip to content

Commit 34391a8

Browse files
markchandlera-maurice
authored andcommitted
Firebase cpp: Avoid potentially expensive copy of write tree for every write tree update
PiperOrigin-RevId: 278462144
1 parent 8e55cf6 commit 34391a8

File tree

3 files changed

+64
-13
lines changed

3 files changed

+64
-13
lines changed

database/src/desktop/core/compound_write.cc

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,15 @@ CompoundWrite CompoundWrite::EmptyWrite() { return CompoundWrite(); }
6060

6161
CompoundWrite CompoundWrite::AddWrite(const Path& path,
6262
const Optional<Variant>& variant) const {
63+
CompoundWrite target = *this;
64+
target.AddWriteInline(path, variant);
65+
return target;
66+
}
67+
68+
void CompoundWrite::AddWriteInline(const Path& path,
69+
const Optional<Variant>& variant) {
6370
if (path.empty()) {
64-
return CompoundWrite(Tree<Variant>(variant));
71+
*this = CompoundWrite(Tree<Variant>(variant));
6572
} else {
6673
Optional<Path> root_most_path = write_tree_.FindRootMostPathWithValue(path);
6774
if (root_most_path.has_value()) {
@@ -78,18 +85,13 @@ CompoundWrite CompoundWrite::AddWrite(const Path& path,
7885
if (!relative_path->empty() && IsPriorityKey(back) &&
7986
VariantIsEmpty(VariantGetChild(value, relative_path->GetParent()))) {
8087
// Ignore priority updates on empty variants
81-
return *this;
8288
} else {
83-
CompoundWrite result = *this;
8489
Variant updated_variant = *value;
8590
VariantUpdateChild(&updated_variant, *relative_path, *variant);
86-
result.write_tree_.SetValueAt(*root_most_path, updated_variant);
87-
return result;
91+
write_tree_.SetValueAt(*root_most_path, updated_variant);
8892
}
8993
} else {
90-
CompoundWrite result = *this;
91-
result.write_tree_.SetValueAt(path, variant);
92-
return result;
94+
write_tree_.SetValueAt(path, variant);
9395
}
9496
}
9597
}
@@ -109,6 +111,20 @@ CompoundWrite CompoundWrite::AddWrite(const std::string& key,
109111
return AddWrite(Path(key), Optional<Variant>(value));
110112
}
111113

114+
void CompoundWrite::AddWriteInline(const Path& path, const Variant& value) {
115+
AddWriteInline(path, Optional<Variant>(value));
116+
}
117+
118+
void CompoundWrite::AddWriteInline(const std::string& key,
119+
const Optional<Variant>& value) {
120+
AddWriteInline(Path(key), value);
121+
}
122+
123+
void CompoundWrite::AddWriteInline(const std::string& key,
124+
const Variant& value) {
125+
AddWriteInline(Path(key), Optional<Variant>(value));
126+
}
127+
112128
CompoundWrite CompoundWrite::AddWrites(const Path& path,
113129
const CompoundWrite& updates) const {
114130
return updates.write_tree_.Fold(
@@ -118,6 +134,15 @@ CompoundWrite CompoundWrite::AddWrites(const Path& path,
118134
});
119135
}
120136

137+
void CompoundWrite::AddWritesInline(const Path& path,
138+
const CompoundWrite& updates) {
139+
updates.write_tree_.Fold(
140+
0, [&path, this](Path relative_path, Variant value, int) {
141+
AddWriteInline(path.GetChild(relative_path), Optional<Variant>(value));
142+
return 0;
143+
});
144+
}
145+
121146
CompoundWrite CompoundWrite::RemoveWrite(const Path& path) const {
122147
if (path.empty()) {
123148
return CompoundWrite();
@@ -133,6 +158,18 @@ CompoundWrite CompoundWrite::RemoveWrite(const Path& path) const {
133158
return CompoundWrite();
134159
}
135160

161+
void CompoundWrite::RemoveWriteInline(const Path& path) {
162+
if (path.empty()) {
163+
*this = CompoundWrite();
164+
} else {
165+
Tree<Variant>* subtree = write_tree_.GetChild(path);
166+
if (subtree) {
167+
subtree->children().clear();
168+
subtree->value().reset();
169+
}
170+
}
171+
}
172+
136173
bool CompoundWrite::HasCompleteWrite(const Path& path) const {
137174
return GetCompleteVariant(path).has_value();
138175
}

database/src/desktop/core/compound_write.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,32 @@ class CompoundWrite {
6666
const Optional<Variant>& value) const;
6767
CompoundWrite AddWrite(const std::string& key, const Variant& value) const;
6868

69+
// Incorperate the new value to write at the given path.
70+
void AddWriteInline(const Path& path, const Optional<Variant>& variant);
71+
void AddWriteInline(const Path& path, const Variant& value);
72+
void AddWriteInline(const std::string& key,
73+
const Optional<Variant>& value);
74+
void AddWriteInline(const std::string& key, const Variant& value);
75+
6976
// Create a new CompoundWrite that incorperates all of the writes in the given
7077
// CompoundWrite at the given path.
7178
CompoundWrite AddWrites(const Path& path, const CompoundWrite& updates) const;
7279

80+
// Incorperate all of the writes in the given CompoundWrite at the given path.
81+
void AddWritesInline(const Path& path, const CompoundWrite& updates);
82+
7383
// Will remove a write at the given path and deeper paths. This will not
7484
// modify a write at a higher location, which must be removed by calling this
7585
// method with that path.
7686
//
7787
// Returns the new WriteCompound with the removed path
7888
CompoundWrite RemoveWrite(const Path& path) const;
7989

90+
// Will remove a write at the given path and deeper paths. This will not
91+
// modify a write at a higher location, which must be removed by calling this
92+
// method with that path.
93+
void RemoveWriteInline(const Path& path);
94+
8095
// Returns whether this CompoundWrite will fully overwrite a node at a given
8196
// location and can therefore be considered "complete".
8297
bool HasCompleteWrite(const Path& path) const;

database/src/desktop/core/write_tree.cc

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ void WriteTree::AddOverwrite(const Path& path, const Variant& snap,
4040
all_writes_.push_back(
4141
UserWriteRecord(write_id, path, snap, visibility == kOverwriteVisible));
4242
if (visibility == kOverwriteVisible) {
43-
visible_writes_ = visible_writes_.AddWrite(path, snap);
43+
visible_writes_.AddWriteInline(path, snap);
4444
}
4545
last_write_id_ = write_id;
4646
}
@@ -51,7 +51,7 @@ void WriteTree::AddMerge(const Path& path,
5151
// Stacking an older write on top of newer ones.
5252
FIREBASE_DEV_ASSERT(write_id > last_write_id_);
5353
all_writes_.push_back(UserWriteRecord(write_id, path, changed_children));
54-
visible_writes_ = visible_writes_.AddWrites(path, changed_children);
54+
visible_writes_.AddWritesInline(path, changed_children);
5555
last_write_id_ = write_id;
5656
}
5757

@@ -116,12 +116,11 @@ bool WriteTree::RemoveWrite(WriteId write_id) {
116116
// There's no shadowing. We can safely just remove the write(s) from
117117
// visible_writes_.
118118
if (write_to_remove.is_overwrite) {
119-
visible_writes_ = visible_writes_.RemoveWrite(write_to_remove.path);
119+
visible_writes_.RemoveWriteInline(write_to_remove.path);
120120
} else {
121121
for (auto& entry : write_to_remove.merge.write_tree().children()) {
122122
Path path(entry.first);
123-
visible_writes_ =
124-
visible_writes_.RemoveWrite(write_to_remove.path.GetChild(path));
123+
visible_writes_.RemoveWriteInline(write_to_remove.path.GetChild(path));
125124
}
126125
}
127126
return true;

0 commit comments

Comments
 (0)