Skip to content

Commit 695014a

Browse files
committed
api: Reduce allocations of Attributes.Builder
Modifying existing Attributes was virtually guaranteed to allocate within build(), just because `base` was not considered for the new map size. Discard was also allocation-heavy because it often created a new map. Using a regular copy-on-write approach is enough to avoid the unnecessary allocations in both cases. This was noticed in a profile that included xds's AddressFilter.setPathFilter(), where Attributes.Builder.build() allocated 6x the memory of Attributes.Builder.data(). b/435208946#comment41
1 parent ca8f4df commit 695014a

File tree

1 file changed

+10
-12
lines changed

1 file changed

+10
-12
lines changed

api/src/main/java/io/grpc/Attributes.java

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ public int hashCode() {
215215
* The helper class to build an Attributes instance.
216216
*/
217217
public static final class Builder {
218+
// Exactly one of base and newdata will be set
218219
private Attributes base;
219220
private IdentityHashMap<Key<?>, Object> newdata;
220221

@@ -225,8 +226,11 @@ private Builder(Attributes base) {
225226

226227
private IdentityHashMap<Key<?>, Object> data(int size) {
227228
if (newdata == null) {
228-
newdata = new IdentityHashMap<>(size);
229+
newdata = new IdentityHashMap<>(base.data.size() + size);
230+
newdata.putAll(base.data);
231+
base = null;
229232
}
233+
assert base == null;
230234
return newdata;
231235
}
232236

@@ -243,12 +247,11 @@ public <T> Builder set(Key<T> key, T value) {
243247
* @return this
244248
*/
245249
public <T> Builder discard(Key<T> key) {
246-
if (base.data.containsKey(key)) {
247-
IdentityHashMap<Key<?>, Object> newBaseData = new IdentityHashMap<>(base.data);
248-
newBaseData.remove(key);
249-
base = new Attributes(newBaseData);
250-
}
251-
if (newdata != null) {
250+
if (base != null) {
251+
if (base.data.containsKey(key)) {
252+
data(0).remove(key);
253+
}
254+
} else {
252255
newdata.remove(key);
253256
}
254257
return this;
@@ -264,11 +267,6 @@ public Builder setAll(Attributes other) {
264267
*/
265268
public Attributes build() {
266269
if (newdata != null) {
267-
for (Map.Entry<Key<?>, Object> entry : base.data.entrySet()) {
268-
if (!newdata.containsKey(entry.getKey())) {
269-
newdata.put(entry.getKey(), entry.getValue());
270-
}
271-
}
272270
base = new Attributes(newdata);
273271
newdata = null;
274272
}

0 commit comments

Comments
 (0)