Skip to content

Commit 69b89ae

Browse files
authored
[8.x] Implement delay() function for debug purposes (#115882) (#116452)
* Implement delay() function for debug purposes (#115882) * Implement delay() function for debug purposes (cherry picked from commit f2a5295) * Fix compile error
1 parent 9fbeb7d commit 69b89ae

File tree

7 files changed

+227
-1
lines changed

7 files changed

+227
-1
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
DELAY
2+
required_capability: delay_debug_fn
3+
row a = 1 | where delay(1ms);
4+
5+
a:integer
6+
1
7+
;

x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/util/DelayEvaluator.java

Lines changed: 91 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,7 @@ public enum Cap {
469469
*/
470470
ADD_LIMIT_INSIDE_MV_EXPAND,
471471

472+
DELAY_DEBUG_FN(Build.current().isSnapshot()),
472473
/**
473474
* WIP on Join planning
474475
* - Introduce BinaryPlan and co

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@
136136
import org.elasticsearch.xpack.esql.expression.function.scalar.string.ToLower;
137137
import org.elasticsearch.xpack.esql.expression.function.scalar.string.ToUpper;
138138
import org.elasticsearch.xpack.esql.expression.function.scalar.string.Trim;
139+
import org.elasticsearch.xpack.esql.expression.function.scalar.util.Delay;
139140
import org.elasticsearch.xpack.esql.session.Configuration;
140141

141142
import java.lang.reflect.Constructor;
@@ -399,6 +400,9 @@ private FunctionDefinition[][] functions() {
399400
private static FunctionDefinition[][] snapshotFunctions() {
400401
return new FunctionDefinition[][] {
401402
new FunctionDefinition[] {
403+
// The delay() function is for debug/snapshot environments only and should never be enabled in a non-snapshot build.
404+
// This is an experimental function and can be removed without notice.
405+
def(Delay.class, Delay::new, "delay"),
402406
def(Categorize.class, Categorize::new, "categorize"),
403407
def(Rate.class, Rate::withUnresolvedTimestamp, "rate") } };
404408
}

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/UnaryScalarFunction.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import org.elasticsearch.xpack.esql.expression.function.scalar.string.Space;
6363
import org.elasticsearch.xpack.esql.expression.function.scalar.string.Trim;
6464
import org.elasticsearch.xpack.esql.expression.function.scalar.string.WildcardLike;
65+
import org.elasticsearch.xpack.esql.expression.function.scalar.util.Delay;
6566
import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Neg;
6667
import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput;
6768

@@ -123,6 +124,7 @@ public static List<NamedWriteableRegistry.Entry> getNamedWriteables() {
123124
entries.add(ToVersion.ENTRY);
124125
entries.add(Trim.ENTRY);
125126
entries.add(WildcardLike.ENTRY);
127+
entries.add(Delay.ENTRY);
126128
entries.addAll(AbstractMultivalueFunction.getNamedWriteables());
127129
return entries;
128130
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
package org.elasticsearch.xpack.esql.expression.function.scalar.util;
9+
10+
import org.elasticsearch.Build;
11+
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
12+
import org.elasticsearch.common.io.stream.StreamInput;
13+
import org.elasticsearch.compute.ann.Evaluator;
14+
import org.elasticsearch.compute.ann.Fixed;
15+
import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator;
16+
import org.elasticsearch.xpack.esql.core.expression.Expression;
17+
import org.elasticsearch.xpack.esql.core.expression.Nullability;
18+
import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
19+
import org.elasticsearch.xpack.esql.core.tree.Source;
20+
import org.elasticsearch.xpack.esql.core.type.DataType;
21+
import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper;
22+
import org.elasticsearch.xpack.esql.expression.function.Param;
23+
import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction;
24+
25+
import java.io.IOException;
26+
import java.time.Duration;
27+
import java.util.List;
28+
29+
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST;
30+
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType;
31+
32+
/**
33+
* Slowdown function - for debug purposes only.
34+
* Syntax: WAIT(ms) - will sleep for ms milliseconds.
35+
*/
36+
public class Delay extends UnaryScalarFunction {
37+
public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(Expression.class, "Delay", Delay::new);
38+
39+
public Delay(Source source, @Param(name = "ms", type = { "time_duration" }, description = "For how long") Expression ms) {
40+
super(source, ms);
41+
}
42+
43+
private Delay(StreamInput in) throws IOException {
44+
super(in);
45+
}
46+
47+
@Override
48+
public Expression replaceChildren(List<Expression> newChildren) {
49+
return new Delay(source(), newChildren.get(0));
50+
}
51+
52+
@Override
53+
public String getWriteableName() {
54+
return ENTRY.name;
55+
}
56+
57+
@Override
58+
public DataType dataType() {
59+
return DataType.BOOLEAN;
60+
}
61+
62+
@Override
63+
protected TypeResolution resolveType() {
64+
if (childrenResolved() == false) {
65+
return new TypeResolution("Unresolved children");
66+
}
67+
68+
return isType(field(), t -> t == DataType.TIME_DURATION, sourceText(), FIRST, "time_duration");
69+
}
70+
71+
@Override
72+
public Nullability nullable() {
73+
return Nullability.FALSE;
74+
}
75+
76+
@Override
77+
protected NodeInfo<? extends Expression> info() {
78+
return NodeInfo.create(this, Delay::new, field());
79+
}
80+
81+
@Override
82+
public boolean foldable() {
83+
return false;
84+
}
85+
86+
@Override
87+
public Object fold() {
88+
return null;
89+
}
90+
91+
private long msValue() {
92+
if (field().foldable() == false) {
93+
throw new IllegalArgumentException("function [" + sourceText() + "] has invalid argument [" + field().sourceText() + "]");
94+
}
95+
var ms = field().fold();
96+
if (ms instanceof Duration duration) {
97+
return duration.toMillis();
98+
}
99+
return ((Number) ms).longValue();
100+
}
101+
102+
@Override
103+
public ExpressionEvaluator.Factory toEvaluator(EvaluatorMapper.ToEvaluator toEvaluator) {
104+
return new DelayEvaluator.Factory(source(), msValue());
105+
}
106+
107+
@Evaluator
108+
static boolean process(@Fixed long ms) {
109+
// Only activate in snapshot builds
110+
if (Build.current().isSnapshot()) {
111+
try {
112+
Thread.sleep(ms);
113+
} catch (InterruptedException e) {
114+
return true;
115+
}
116+
} else {
117+
throw new IllegalArgumentException("Delay function is only available in snapshot builds");
118+
}
119+
return true;
120+
}
121+
}

x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_usage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ setup:
9191
- match: {esql.functions.cos: $functions_cos}
9292
- gt: {esql.functions.to_long: $functions_to_long}
9393
- match: {esql.functions.coalesce: $functions_coalesce}
94-
- length: {esql.functions: 118} # check the "sister" test below for a likely update to the same esql.functions length check
94+
- length: {esql.functions: 119} # check the "sister" test below for a likely update to the same esql.functions length check
9595

9696
---
9797
"Basic ESQL usage output (telemetry) non-snapshot version":

0 commit comments

Comments
 (0)