Skip to content

Commit 5069ac3

Browse files
authored
Optimized allocations for collection filter functions (#8896)
We were allocating some unnecessary objects for each item in the collection we attempt to filter with any, all and filter expression. introduced withExtension/removeExtension method to reduce those allocations
1 parent 2fe20fe commit 5069ac3

File tree

5 files changed

+107
-80
lines changed

5 files changed

+107
-80
lines changed

dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/CapturedContext.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,12 +182,14 @@ public ValueReferenceResolver withExtensions(Map<String, Object> extensions) {
182182
return new CapturedContext(this, extensions);
183183
}
184184

185-
public void removeExtension(String name) {
186-
extensions.remove(name);
185+
@Override
186+
public void addExtension(String name, Object value) {
187+
extensions.put(name, value);
187188
}
188189

189-
private void addExtension(String name, Object value) {
190-
extensions.put(name, value);
190+
@Override
191+
public void removeExtension(String name) {
192+
extensions.remove(name);
191193
}
192194

193195
public void addArguments(CapturedValue[] values) {

dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/el/ValueReferenceResolver.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ public interface ValueReferenceResolver {
88

99
Object getMember(Object target, String name);
1010

11+
default void addExtension(String name, Object value) {}
12+
13+
default void removeExtension(String name) {}
14+
1115
default ValueReferenceResolver withExtensions(Map<String, Object> extensions) {
1216
return this;
1317
}

dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/FilterCollectionExpression.java

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import datadog.trace.bootstrap.debugger.el.ValueReferences;
1818
import java.util.ArrayList;
1919
import java.util.Collection;
20-
import java.util.Collections;
2120
import java.util.HashMap;
2221
import java.util.HashSet;
2322
import java.util.Map;
@@ -48,41 +47,52 @@ public CollectionValue<?> evaluate(ValueReferenceResolver valueRefResolver) {
4847
checkSupportedList(materialized, this);
4948
Collection<Object> filtered = new ArrayList<>();
5049
int len = materialized.count();
51-
for (int i = 0; i < len; i++) {
52-
Object value = materialized.get(i).getValue();
53-
if (filterExpression.evaluate(
54-
valueRefResolver.withExtensions(
55-
Collections.singletonMap(ValueReferences.ITERATOR_EXTENSION_NAME, value)))) {
56-
filtered.add(value);
50+
try {
51+
for (int i = 0; i < len; i++) {
52+
Object value = materialized.get(i).getValue();
53+
valueRefResolver.addExtension(ValueReferences.ITERATOR_EXTENSION_NAME, value);
54+
if (filterExpression.evaluate(valueRefResolver)) {
55+
filtered.add(value);
56+
}
5757
}
58+
} finally {
59+
valueRefResolver.removeExtension(ValueReferences.ITERATOR_EXTENSION_NAME);
5860
}
5961
return new ListValue(filtered);
6062
} else if (collectionValue instanceof MapValue) {
6163
MapValue materialized = (MapValue) collectionValue;
6264
checkSupportedMap(materialized, this);
6365
Map<Object, Object> filtered = new HashMap<>();
64-
for (Value<?> key : materialized.getKeys()) {
65-
Value<?> value = key.isUndefined() ? Value.undefinedValue() : materialized.get(key);
66-
Map<String, Object> valueRefExtensions = new HashMap<>();
67-
valueRefExtensions.put(ValueReferences.KEY_EXTENSION_NAME, key);
68-
valueRefExtensions.put(ValueReferences.VALUE_EXTENSION_NAME, value);
69-
valueRefExtensions.put(
70-
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, value));
71-
if (filterExpression.evaluate(valueRefResolver.withExtensions(valueRefExtensions))) {
72-
filtered.put(key.getValue(), value.getValue());
66+
try {
67+
for (Value<?> key : materialized.getKeys()) {
68+
Value<?> value = key.isUndefined() ? Value.undefinedValue() : materialized.get(key);
69+
valueRefResolver.addExtension(ValueReferences.KEY_EXTENSION_NAME, key);
70+
valueRefResolver.addExtension(ValueReferences.VALUE_EXTENSION_NAME, value);
71+
valueRefResolver.addExtension(
72+
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, value));
73+
if (filterExpression.evaluate(valueRefResolver)) {
74+
filtered.put(key.getValue(), value.getValue());
75+
}
7376
}
77+
} finally {
78+
valueRefResolver.removeExtension(ValueReferences.KEY_EXTENSION_NAME);
79+
valueRefResolver.removeExtension(ValueReferences.VALUE_EXTENSION_NAME);
80+
valueRefResolver.removeExtension(ValueReferences.ITERATOR_EXTENSION_NAME);
7481
}
7582
return new MapValue(filtered);
7683
} else if (collectionValue instanceof SetValue) {
7784
SetValue materialized = (SetValue) collectionValue;
7885
Collection<Object> filtered = new HashSet<>();
7986
Set<?> setHolder = checkSupportedSet(materialized, this);
80-
for (Object value : setHolder) {
81-
if (filterExpression.evaluate(
82-
valueRefResolver.withExtensions(
83-
Collections.singletonMap(ValueReferences.ITERATOR_EXTENSION_NAME, value)))) {
84-
filtered.add(value);
87+
try {
88+
for (Object value : setHolder) {
89+
valueRefResolver.addExtension(ValueReferences.ITERATOR_EXTENSION_NAME, value);
90+
if (filterExpression.evaluate(valueRefResolver)) {
91+
filtered.add(value);
92+
}
8593
}
94+
} finally {
95+
valueRefResolver.removeExtension(ValueReferences.ITERATOR_EXTENSION_NAME);
8696
}
8797
return new SetValue(filtered);
8898
}

dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/HasAllExpression.java

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@
1414
import com.datadog.debugger.el.values.SetValue;
1515
import datadog.trace.bootstrap.debugger.el.ValueReferenceResolver;
1616
import datadog.trace.bootstrap.debugger.el.ValueReferences;
17-
import java.util.Collections;
18-
import java.util.HashMap;
19-
import java.util.Map;
2017
import java.util.Set;
2118

2219
/**
@@ -42,15 +39,17 @@ public Boolean evaluate(ValueReferenceResolver valueRefResolver) {
4239
return Boolean.TRUE;
4340
}
4441
int len = collection.count();
45-
for (int i = 0; i < len; i++) {
46-
Value<?> val = collection.get(i);
47-
if (!filterPredicateExpression.evaluate(
48-
valueRefResolver.withExtensions(
49-
Collections.singletonMap(ValueReferences.ITERATOR_EXTENSION_NAME, val)))) {
50-
return Boolean.FALSE;
42+
try {
43+
for (int i = 0; i < len; i++) {
44+
valueRefResolver.addExtension(ValueReferences.ITERATOR_EXTENSION_NAME, collection.get(i));
45+
if (!filterPredicateExpression.evaluate(valueRefResolver)) {
46+
return Boolean.FALSE;
47+
}
5148
}
49+
return Boolean.TRUE;
50+
} finally {
51+
valueRefResolver.removeExtension(ValueReferences.ITERATOR_EXTENSION_NAME);
5252
}
53-
return Boolean.TRUE;
5453
}
5554
if (value instanceof MapValue) {
5655
MapValue map = (MapValue) value;
@@ -59,19 +58,23 @@ public Boolean evaluate(ValueReferenceResolver valueRefResolver) {
5958
// always return TRUE for empty values (cf vacuous truth, see also Stream::allMatch)
6059
return Boolean.TRUE;
6160
}
62-
for (Value<?> key : map.getKeys()) {
63-
Value<?> val = key.isUndefined() ? Value.undefinedValue() : map.get(key);
64-
Map<String, Object> valueRefExtensions = new HashMap<>();
65-
valueRefExtensions.put(ValueReferences.KEY_EXTENSION_NAME, key);
66-
valueRefExtensions.put(ValueReferences.VALUE_EXTENSION_NAME, val);
67-
valueRefExtensions.put(
68-
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, val));
69-
if (!filterPredicateExpression.evaluate(
70-
valueRefResolver.withExtensions(valueRefExtensions))) {
71-
return Boolean.FALSE;
61+
try {
62+
for (Value<?> key : map.getKeys()) {
63+
Value<?> val = key.isUndefined() ? Value.undefinedValue() : map.get(key);
64+
valueRefResolver.addExtension(ValueReferences.KEY_EXTENSION_NAME, key);
65+
valueRefResolver.addExtension(ValueReferences.VALUE_EXTENSION_NAME, val);
66+
valueRefResolver.addExtension(
67+
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, val));
68+
if (!filterPredicateExpression.evaluate(valueRefResolver)) {
69+
return Boolean.FALSE;
70+
}
7271
}
72+
return Boolean.TRUE;
73+
} finally {
74+
valueRefResolver.removeExtension(ValueReferences.ITERATOR_EXTENSION_NAME);
75+
valueRefResolver.removeExtension(ValueReferences.KEY_EXTENSION_NAME);
76+
valueRefResolver.removeExtension(ValueReferences.VALUE_EXTENSION_NAME);
7377
}
74-
return Boolean.TRUE;
7578
}
7679
if (value instanceof SetValue) {
7780
SetValue set = (SetValue) value;
@@ -80,14 +83,17 @@ public Boolean evaluate(ValueReferenceResolver valueRefResolver) {
8083
// always return TRUE for empty values (cf vacuous truth, see also Stream::allMatch)
8184
return Boolean.TRUE;
8285
}
83-
for (Object val : setHolder) {
84-
if (!filterPredicateExpression.evaluate(
85-
valueRefResolver.withExtensions(
86-
Collections.singletonMap(ValueReferences.ITERATOR_EXTENSION_NAME, val)))) {
87-
return Boolean.FALSE;
86+
try {
87+
for (Object val : setHolder) {
88+
valueRefResolver.addExtension(ValueReferences.ITERATOR_EXTENSION_NAME, val);
89+
if (!filterPredicateExpression.evaluate(valueRefResolver)) {
90+
return Boolean.FALSE;
91+
}
8892
}
93+
return Boolean.TRUE;
94+
} finally {
95+
valueRefResolver.removeExtension(ValueReferences.ITERATOR_EXTENSION_NAME);
8996
}
90-
return Boolean.TRUE;
9197
}
9298
throw new EvaluationException(
9399
"Unsupported collection class: " + value.getValue().getClass().getTypeName(), print(this));

dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/HasAnyExpression.java

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@
1414
import com.datadog.debugger.el.values.SetValue;
1515
import datadog.trace.bootstrap.debugger.el.ValueReferenceResolver;
1616
import datadog.trace.bootstrap.debugger.el.ValueReferences;
17-
import java.util.Collections;
18-
import java.util.HashMap;
19-
import java.util.Map;
2017
import java.util.Set;
2118

2219
/**
@@ -43,51 +40,59 @@ public Boolean evaluate(ValueReferenceResolver valueRefResolver) {
4340
return Boolean.FALSE;
4441
}
4542
int len = collection.count();
46-
for (int i = 0; i < len; i++) {
47-
Value<?> val = collection.get(i);
48-
if (filterPredicateExpression.evaluate(
49-
valueRefResolver.withExtensions(
50-
Collections.singletonMap(ValueReferences.ITERATOR_EXTENSION_NAME, val)))) {
51-
return Boolean.TRUE;
43+
try {
44+
for (int i = 0; i < len; i++) {
45+
valueRefResolver.addExtension(ValueReferences.ITERATOR_EXTENSION_NAME, collection.get(i));
46+
if (filterPredicateExpression.evaluate(valueRefResolver)) {
47+
return Boolean.TRUE;
48+
}
5249
}
50+
return Boolean.FALSE;
51+
} finally {
52+
valueRefResolver.removeExtension(ValueReferences.ITERATOR_EXTENSION_NAME);
5353
}
54-
return Boolean.FALSE;
5554
}
5655
if (value instanceof MapValue) {
5756
MapValue map = (MapValue) value;
5857
checkSupportedMap(map, this);
5958
if (map.isEmpty()) {
6059
return Boolean.FALSE;
6160
}
62-
for (Value<?> key : map.getKeys()) {
63-
Value<?> val = key.isUndefined() ? Value.undefinedValue() : map.get(key);
64-
Map<String, Object> valueRefExtensions = new HashMap<>();
65-
valueRefExtensions.put(ValueReferences.KEY_EXTENSION_NAME, key);
66-
valueRefExtensions.put(ValueReferences.VALUE_EXTENSION_NAME, val);
67-
valueRefExtensions.put(
68-
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, val));
69-
if (filterPredicateExpression.evaluate(
70-
valueRefResolver.withExtensions(valueRefExtensions))) {
71-
return Boolean.TRUE;
61+
try {
62+
for (Value<?> key : map.getKeys()) {
63+
Value<?> val = key.isUndefined() ? Value.undefinedValue() : map.get(key);
64+
valueRefResolver.addExtension(ValueReferences.KEY_EXTENSION_NAME, key);
65+
valueRefResolver.addExtension(ValueReferences.VALUE_EXTENSION_NAME, val);
66+
valueRefResolver.addExtension(
67+
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, val));
68+
if (filterPredicateExpression.evaluate(valueRefResolver)) {
69+
return Boolean.TRUE;
70+
}
7271
}
72+
return Boolean.FALSE;
73+
} finally {
74+
valueRefResolver.removeExtension(ValueReferences.ITERATOR_EXTENSION_NAME);
75+
valueRefResolver.removeExtension(ValueReferences.KEY_EXTENSION_NAME);
76+
valueRefResolver.removeExtension(ValueReferences.VALUE_EXTENSION_NAME);
7377
}
74-
return Boolean.FALSE;
7578
}
7679
if (value instanceof SetValue) {
7780
SetValue set = (SetValue) value;
7881
Set<?> setHolder = checkSupportedSet(set, this);
7982
if (set.isEmpty()) {
8083
return Boolean.FALSE;
8184
}
82-
for (Object val : setHolder) {
83-
if (filterPredicateExpression.evaluate(
84-
valueRefResolver.withExtensions(
85-
Collections.singletonMap(
86-
ValueReferences.ITERATOR_EXTENSION_NAME, Value.of(val))))) {
87-
return Boolean.TRUE;
85+
try {
86+
for (Object val : setHolder) {
87+
valueRefResolver.addExtension(ValueReferences.ITERATOR_EXTENSION_NAME, Value.of(val));
88+
if (filterPredicateExpression.evaluate(valueRefResolver)) {
89+
return Boolean.TRUE;
90+
}
8891
}
92+
return Boolean.FALSE;
93+
} finally {
94+
valueRefResolver.removeExtension(ValueReferences.ITERATOR_EXTENSION_NAME);
8995
}
90-
return Boolean.FALSE;
9196
}
9297
throw new EvaluationException(
9398
"Unsupported collection class: " + value.getValue().getClass().getTypeName(), print(this));

0 commit comments

Comments
 (0)