Skip to content

Commit 71bf7e5

Browse files
committed
Attempt to make some operations cheaper (#125228)
1 parent 172f1b7 commit 71bf7e5

File tree

2 files changed

+30
-4
lines changed
  • x-pack/plugin
    • esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree
    • esql/src/main/java/org/elasticsearch/xpack/esql/plan

2 files changed

+30
-4
lines changed

x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/Node.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,11 @@ public List<T> children() {
6767
@SuppressWarnings("unchecked")
6868
public void forEachDown(Consumer<? super T> action) {
6969
action.accept((T) this);
70-
children().forEach(c -> c.forEachDown(action));
70+
// please do not refactor it to a for-each loop to avoid
71+
// allocating iterator that performs concurrent modification checks and extra stack frames
72+
for (int c = 0, size = children.size(); c < size; c++) {
73+
children.get(c).forEachDown(action);
74+
}
7175
}
7276

7377
@SuppressWarnings("unchecked")
@@ -81,7 +85,11 @@ public <E extends T> void forEachDown(Class<E> typeToken, Consumer<? super E> ac
8185

8286
@SuppressWarnings("unchecked")
8387
public void forEachUp(Consumer<? super T> action) {
84-
children().forEach(c -> c.forEachUp(action));
88+
// please do not refactor it to a for-each loop to avoid
89+
// allocating iterator that performs concurrent modification checks and extra stack frames
90+
for (int c = 0, size = children.size(); c < size; c++) {
91+
children.get(c).forEachUp(action);
92+
}
8593
action.accept((T) this);
8694
}
8795

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/QueryPlan.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,24 @@ private static Object doTransformExpression(Object arg, Function<Expression, ? e
140140
// preserving the type information is hacky and weird (a lot of context needs to be passed around and the lambda itself
141141
// has no type info so it's difficult to have automatic checking without having base classes).
142142

143-
if (arg instanceof Collection<?> c) {
143+
if (arg instanceof List<?> c) {
144+
List<Object> transformed = null;
145+
boolean hasChanged = false;
146+
// please do not refactor it to a for-each loop to avoid
147+
// allocating iterator that performs concurrent modification checks and extra stack frames
148+
for (int i = 0, size = c.size(); i < size; i++) {
149+
var e = c.get(i);
150+
Object next = doTransformExpression(e, traversal);
151+
if (e.equals(next) == false) {
152+
if (hasChanged == false) {
153+
hasChanged = true;
154+
transformed = new ArrayList<>(c);
155+
}
156+
transformed.set(i, next);
157+
}
158+
}
159+
return hasChanged ? transformed : arg;
160+
} else if (arg instanceof Collection<?> c) {
144161
List<Object> transformed = null;
145162
boolean hasChanged = false;
146163
int i = 0;
@@ -149,13 +166,14 @@ private static Object doTransformExpression(Object arg, Function<Expression, ? e
149166
if (e.equals(next) == false) {
150167
if (hasChanged == false) {
151168
hasChanged = true;
169+
// TODO if collection is a set then this silently changes its semantics by allowing duplicates
170+
// We should fix it or confirm this branch is never needed
152171
transformed = new ArrayList<>(c);
153172
}
154173
transformed.set(i, next);
155174
}
156175
i++;
157176
}
158-
159177
return hasChanged ? transformed : arg;
160178
}
161179

0 commit comments

Comments
 (0)