Fix memory leak in SqlPx module during LOAD DATA with Direct Load
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 2.9k
- Forks
- 339
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 52
Description
Environment
- Version: observer (OceanBase seekdb) source revision 1-582476f8947aede859005587d600f4afe78d8bfa
- Build Branch: master
- Build Time: Apr 27 2026 23:37:32
- Build Flags: RelWithDebInfo|Sanity
- Build Info: obbuild-sanity-master-100973
- Is this a temporary version provided by RD?: No
- Reproducibility: Always reproducible
Description
During a LOAD DATA operation combined with Direct Load (ObTableDirectInsertOp), the ObPxFifoReceiveOp fails to release DTL channel buffers (ObDtlLinkedBuffer, each ~8KB) after they are received and processed by ObTableDirectInsertOp. This causes all buffers to remain alive within the SqlPx memory context until the task finishes, leading to a memory leak.
Steps to Reproduce
- Execute a LOAD DATA workload that triggers the Direct Load path (
ObTableDirectInsertOp). - Monitor the memory usage of the
mod=SqlPxcontext. - Observe that memory usage (
holdandused) continuously increases during the operation and is only released when the task completes.
Environment Information
- Machine: work
- Database logs:
/obdata/data/ddl_lite/2/log - Stack traces:
/obdata/data/obstack1339897_2.log,/obdata/data/obstack1339897.log - Database connection string:
obclient -h -P7001 -uroot@sys(session ended)
Logs & Evidence
Memory Context Growth
Memory usage for mod=SqlPx shows a steady increase in hold, used, and count (number of blocks).
[MEMORY] hold= 16,424,579,776 used= 15,994,048,992 count= 2,004,814 avg_used= 7,977 block_cnt= 2,004,814 chunk_cnt= 8,065 mod=SqlPx
[MEMORY] hold= 16,428,837,696 used= 15,998,195,312 count= 2,005,334 avg_used= 7,977 block_cnt= 2,005,334 chunk_cnt= 8,067 mod=SqlPx
[MEMORY] hold= 16,434,462,976 used= 16,003,673,184 count= 2,006,021 avg_used= 7,977 block_cnt= 2,006,021 chunk_cnt= 8,070 mod=SqlPx
...
Stack Traces
PX Worker threads (e.g., 1343146, 1343147, 1343886, 1343887, 1344665) are stuck in a spin-wait, with the call stack pointing to the suspected location of the unreleased buffer.
Threads (1343146-T1_PX_G0, 1343147-T1_PX_G0, 1344665-T1_PX_G0)
#3 ob_usleep<ObWaitEventIds::87> ← Spinning/waiting, stuck here
#4 ObPxFifoReceiveOp::fetch_rows ob_px_receive_op.cpp:709 ← Suspected location of unreleased buffer
#5 ObPxFifoReceiveOp::inner_get_next_batch :649
#7 ObTableDirectInsertOp::next_vector ob_table_direct_insert_op.cpp:168 ← LOAD DATA consumption path
#9 ObPxTransmitOp::next_vector ob_px_transmit_op.cpp:482
#11 ObPxTransmitOp::fetch_first_row :267
#12 ObPxTransmitOp::inner_open
#13 ObPxReduceTransmitOp::inner_open ob_px_reduce_transmit_op.cpp:38
#15 ObPxTaskProcess::execute ob_px_task_process.cpp:314
#16 ObPxTaskProcess::do_process :485
#17 ObPxTaskProcess::process :176
#18 ObPxTaskProcess::run :104
#19 PxWorkerFunctor::operator
#20 ObPxPool::handle
#21 ObPxPool::run1
Task Completion and Memory Release
At 2026-04-29 10:28:51, all 5 PX workers finish simultaneously, and memory held by mod=SqlPx drops from ~16.8GB to ~43MB, confirming the buffers were tied to the task lifecycle.
[T1_PX_G0][ob_table_load_store.cpp:958] store px finish trans (segment_id:{id:1}, trans_gid:1)
[T1_PX_G0][ob_table_load_store.cpp:958] store px finish trans (segment_id:{id:2}, trans_gid:1)
[T1_PX_G0][ob_table_load_store.cpp:958] store px finish trans (segment_id:{id:3}, trans_gid:1)
[T1_PX_G0][ob_table_load_store.cpp:958] store px finish trans (segment_id:{id:4}, trans_gid:1)
[T1_PX_G0][ob_table_load_store.cpp:958] store px finish trans (segment_id:{id:5}, trans_gid:1)
[T1_PX_G0][ob_table_load_trans_ctx.cpp:65] LOAD DATA TRANS advance status trans_status:3→4
Impact
This memory leak can lead to significant and uncontrolled memory growth during large LOAD DATA operations using the Direct Load path, potentially causing out-of-memory errors or performance degradation on the PX workers.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at ObPxFifoReceiveOp::fetch_rows in ob_px_receive_op.cpp:709 and trace how buffers are handed to ObTableDirectInsertOp::next_vector in ob_table_direct_insert_op.cpp:168. Reproduce the LOAD DATA Direct Load workload while monitoring the SqlPx memory context and inspect the receive/consume lifecycle. Done means processed DTL channel buffers are released before task completion and SqlPx memory no longer grows continuously.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- sql
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100