github-actions[bot] commented on code in PR #64366:
URL: https://github.com/apache/doris/pull/64366#discussion_r3607321509
##########
fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java:
##########
@@ -336,6 +336,9 @@ public void executeQuery(String originStmt) throws
Exception {
StatementBase parsedStmt = stmts.get(i);
parsedStmt.setOrigStmt(new OriginStatement(auditStmt,
usingOrigSingleStmt ? 0 : i));
parsedStmt.setUserInfo(ctx.getCurrentUserIdentity());
+ if (parsedStmt instanceof LogicalPlanAdapter) {
+ ((LogicalPlanAdapter)
parsedStmt).getStatementContext().resetStatementStartTime();
Review Comment:
[P1] Isolate later-statement hints before refreshing this context
`executeQuery()` parses the whole packet before this loop, and
`LogicalPlanBuilder.withHints()` calls `setVarOnceInSql()` while parsing each
statement. A future statement can therefore leave the shared `SessionVariable`
modified when this reset processes an earlier statement. With base `+08:00`,
`select now(); select /*+ SET_VAR(time_zone='+00:00') */ 1` reaches this line
with UTC installed, so the first statement is refreshed from the second
statement's hint; its executor then reverts that value before the hinted
statement runs. Restore/isolate parse-time hints per statement or defer
applying them, and add this two-statement regression.
##########
be/src/service/point_query_executor.cpp:
##########
@@ -308,6 +331,8 @@ Status PointQueryExecutor::init(const
PTabletKeyLookupRequest* request,
_tablet = DORIS_TRY(ExecEnv::get_tablet(request->tablet_id()));
if (cache_handle != nullptr) {
_reusable = cache_handle;
+ _reusable_execution_lock = _reusable->acquire_execution_lock();
Review Comment:
[P1] Do not block light-pool workers behind the execution lease
`tablet_fetch_data()` runs on the bounded shared `_light_work_pool`, whose
own contract says handlers must not lock or access disk. A hit now blocks here
and holds the lease through storage lookup, output, and profiling. FE timeout
cancels only its Future, while the BE lambda never checks
`controller->IsCanceled()`, so later executions of that UUID can occupy more
light workers waiting, time out themselves, and still execute obsolete lookups
serially. Enough sessions can exhaust the pool and stall unrelated light RPCs.
Use execution-local state or nonblocking/rescheduled admission with
cancellation checks, and cover real executor/RPC overlap rather than only
`try_lock()`.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/load/NereidsBrokerLoadTask.java:
##########
@@ -25,12 +25,15 @@
import org.apache.doris.thrift.TFileFormatType;
import org.apache.doris.thrift.TFileType;
+import java.time.Instant;
import java.util.List;
/**
* Nereids Broker Load Task
*/
public class NereidsBrokerLoadTask implements NereidsLoadTaskInfo {
+ private final Instant statementStartTime = Instant.now();
Review Comment:
[P1] Share one instant across the broker-load job
This initializer runs once per `NereidsBrokerLoadTask`, while
`BrokerLoadJob.createLoadingTask()` splits one submitted job into one
sequentially planned `LoadLoadingTask` per `FileGroupAggKey`. A multi-table or
disjoint-partition broker load therefore gives sibling fragments different
instants, so two `SET(ts=now(6))` data descriptions can commit different
timestamps. The earlier broker-load threads align planning and execution within
one sibling; they do not align siblings of the same job. Capture one instant
before the key loop, pass it through both shared-nothing and cloud task
creation, and assert equality in a two-key test.
##########
be/src/service/point_query_executor.cpp:
##########
@@ -216,6 +214,28 @@ void Reusable::return_block(std::unique_ptr<Block>& block)
{
}
}
+void Reusable::_update_runtime_state(const PTabletKeyLookupRequest& request) {
+ if (request.has_time_zone() && !request.time_zone().empty()) {
+ _runtime_state->set_timezone(request.time_zone());
+ }
+ if (request.has_timestamp_ms()) {
+ _runtime_state->set_query_time(request.timestamp_ms(),
request.nano_seconds());
+ }
+}
+
+Status Reusable::_rebuild_output_exprs() {
+ RETURN_IF_ERROR(VExpr::create_expr_trees(_output_exprs,
_output_exprs_ctxs));
+ RowDescriptor row_desc(tuple_desc());
+ RETURN_IF_ERROR(VExpr::prepare(_output_exprs_ctxs, _runtime_state.get(),
row_desc));
+ return VExpr::open(_output_exprs_ctxs, _runtime_state.get());
+}
+
+Status Reusable::refresh(const PTabletKeyLookupRequest& request) {
Review Comment:
[P2] Preserve the cache-hit fast path for request-independent expressions
Every hit unconditionally clears all contexts and then recreates every saved
Thrift expression tree, runs `prepare()`, and runs `open()`. Slot-only
projections and other request-global-independent outputs therefore pay the full
allocation/tree-walk cost on the latency-sensitive lookup-cache path, and this
work also lengthens the new execution critical section. Refreshing stale
constant-derived function state is necessary, but it does not require
rebuilding request-independent trees. Keep an immutable prepared shape with
execution-local mutable state, or gate rebuilding on global dependency, and add
a representative cache-hit benchmark/counter guard.
##########
fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java:
##########
@@ -227,6 +229,22 @@ public class StmtExecutor {
// this constructor is mainly for proxy
public StmtExecutor(ConnectContext context, OriginStatement originStmt,
boolean isProxy) {
+ this(context, originStmt, isProxy, Instant.now());
Review Comment:
[P1] Keep one StatementContext through raw parsing
This constructor retains context A in the executor, but `parseByNereids()`
invokes the normal parser, whose multi-statement visitor creates and installs
context B in the same `ConnectContext`; it stores only the parsed statement and
never updates the executor field. `new NereidsPlanner(statementContext)` then
folds with A, while `CoordinatorContext.createQueryGlobals()` reaches B through
the connection. A proxy query such as `now(6), now(kint)` can consequently use
different FE and BE instants, and explicit-time internal constructors lose
their supplied instant on the BE side. Reuse/copy one context through parsing
and add a parse-to-coordinator globals test.
##########
fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java:
##########
@@ -336,6 +336,9 @@ public void executeQuery(String originStmt) throws
Exception {
StatementBase parsedStmt = stmts.get(i);
parsedStmt.setOrigStmt(new OriginStatement(auditStmt,
usingOrigSingleStmt ? 0 : i));
parsedStmt.setUserInfo(ctx.getCurrentUserIdentity());
+ if (parsedStmt instanceof LogicalPlanAdapter) {
+ ((LogicalPlanAdapter)
parsedStmt).getStatementContext().resetStatementStartTime();
Review Comment:
[P1] Keep cache validation on the execution timestamp
`parseFromSqlCache()` creates this adapter's `StatementContext` at T0, and
`nondeterministicFunctionChanged()` validates cached `now()`/`current_date()`
folds against T0 before the remaining policy checks and possible
`SqlCache.getCacheData()` RPC. This reset happens only afterward and changes
the same context to T1. If lookup crosses a second boundary (or local
midnight), a cached T0 `now(0)` row is accepted and returned for a statement
whose execution context is T1. Establish the per-statement instant before cache
validation, or preserve the validation instant on a hit, and cover the boundary
with an injected clock.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]