github-actions[bot] commented on code in PR #67087:
URL: https://github.com/apache/doris/pull/67087#discussion_r3849310092
##########
be/src/exec/operator/spill_iceberg_table_sink_operator.cpp:
##########
@@ -36,17 +36,47 @@ Status SpillIcebergTableSinkLocalState::init(RuntimeState*
state, LocalSinkState
SCOPED_TIMER(_init_timer);
_init_spill_counters();
+ _writer = std::make_unique<VIcebergTableWriter>(info.tsink,
_output_vexpr_ctxs);
- auto& p = _parent->cast<Parent>();
- RETURN_IF_ERROR(_writer->init_properties(p._pool, p._row_desc));
+ auto& parent = _parent->cast<Parent>();
+ RETURN_IF_ERROR(_writer->init_properties(parent._pool, parent._row_desc));
return Status::OK();
}
Status SpillIcebergTableSinkLocalState::open(RuntimeState* state) {
SCOPED_TIMER(Base::exec_time_counter());
SCOPED_TIMER(Base::_open_timer);
RETURN_IF_ERROR(Base::open(state));
- return Status::OK();
+
+ auto& parent = _parent->cast<Parent>();
+ _output_vexpr_ctxs.resize(parent._output_vexpr_ctxs.size());
+ for (size_t i = 0; i < _output_vexpr_ctxs.size(); ++i) {
+ RETURN_IF_ERROR(parent._output_vexpr_ctxs[i]->clone(state,
_output_vexpr_ctxs[i]));
+ }
+ return _writer->open(state, operator_profile());
+}
+
+Status SpillIcebergTableSinkLocalState::close(RuntimeState* state, Status
exec_status) {
+ if (_closed) {
+ return Status::OK();
+ }
+
+ SCOPED_TIMER(exec_time_counter());
+ SCOPED_TIMER(_close_timer);
+
+ DCHECK(_writer);
+ Status final_status = exec_status;
+ Status writer_status = _writer->close(exec_status);
+ if (final_status.ok() && !writer_status.ok()) {
+ final_status = writer_status;
+ }
+ _writer.reset();
Review Comment:
**[P1] Keep the writer alive while revocable accounting can snapshot it**
Workload-group accounting calls the sink from outside the pipeline scheduler
after only sampling `PipelineTask::_running`. A scheduler thread can
subsequently set the task running and reach terminal close, so this reset can
occur between `get_revocable_mem_size()`'s `_writer` null check and its
`_writer->current_writer()` call (for example when cancellation races
paused-query accounting). That is a data race/use-after-free on the owning
`unique_ptr`; the atomic child snapshot only helps after the parent dereference
succeeds. Please keep the writer alive through local-state teardown, or fence
accounting and close with a shared owning snapshot/lock.
##########
be/src/exec/operator/iceberg_table_sink_operator.cpp:
##########
@@ -25,9 +25,46 @@ Status IcebergTableSinkLocalState::init(RuntimeState* state,
LocalSinkStateInfo&
RETURN_IF_ERROR(Base::init(state, info));
SCOPED_TIMER(exec_time_counter());
SCOPED_TIMER(_init_timer);
- auto& p = _parent->cast<Parent>();
- RETURN_IF_ERROR(_writer->init_properties(p._pool, p._row_desc));
+ _writer = std::make_unique<VIcebergTableWriter>(info.tsink,
_output_vexpr_ctxs);
+ auto& parent = _parent->cast<Parent>();
+ RETURN_IF_ERROR(_writer->init_properties(parent._pool, parent._row_desc));
return Status::OK();
}
+Status IcebergTableSinkLocalState::open(RuntimeState* state) {
+ SCOPED_TIMER(exec_time_counter());
+ SCOPED_TIMER(_open_timer);
+ RETURN_IF_ERROR(Base::open(state));
+
+ auto& parent = _parent->cast<Parent>();
+ _output_vexpr_ctxs.resize(parent._output_vexpr_ctxs.size());
+ for (size_t i = 0; i < _output_vexpr_ctxs.size(); ++i) {
+ RETURN_IF_ERROR(parent._output_vexpr_ctxs[i]->clone(state,
_output_vexpr_ctxs[i]));
+ }
+ return _writer->open(state, operator_profile());
+}
+
+Status IcebergTableSinkLocalState::close(RuntimeState* state, Status
exec_status) {
+ if (_closed) {
+ return Status::OK();
+ }
+
+ SCOPED_TIMER(exec_time_counter());
+ SCOPED_TIMER(_close_timer);
+
+ DCHECK(_writer);
+ Status final_status = exec_status;
+ Status writer_status = _writer->close(exec_status);
Review Comment:
**[P1] Preserve cancellation status before finalizing files**
Cancellation can arrive during the final `PipelineTask::execute()` after the
scheduler sampled the fragment as live. Its exit defer then marks the task done
because the fragment is cancelled, but the scheduler can still call this close
with an OK execution status. Forwarding that OK value makes partition close add
commit data and lets the table writer clear its cleanup list instead of
deleting the cancelled query's files. The removed async close normalized this
exact case through `state->cancel_reason()`. Please convert an OK `exec_status`
to the runtime cancellation reason before closing the writer here and in the
spill sink, while preserving any existing non-OK status.
##########
be/test/exec/operator/iceberg_table_sink_operator_test.cpp:
##########
@@ -0,0 +1,43 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "exec/operator/iceberg_table_sink_operator.h"
+
+#include <gtest/gtest.h>
+
+#include <type_traits>
+
+#include "exec/operator/spill_iceberg_table_sink_operator.h"
+#include "exec/sink/writer/async_result_writer.h"
+
+namespace doris {
+
+static_assert(!std::is_base_of_v<AsyncResultWriter, VIcebergTableWriter>);
+
+TEST(IcebergTableSinkOperatorTest,
SyncWritersUseBlockingSchedulerWithoutDependencies) {
Review Comment:
**[P2] Exercise the synchronous lifecycle in this test**
This test only constructs uninitialized local states and checks their
inheritance/scheduler-dependency shape, so it still passes if the new
`init`/`open`/inline `write`/EOS `close` sequence loses buffered rows or
mishandles write/close failures and cancellation cleanup. Those are the
behavioral changes in this PR, including the spill writer's final sort/merge.
Please add coverage that drives at least a successful non-empty/empty EOS and
the error/cleanup paths through the converted operator lifecycle.
--
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]