oceanbase / oceanbase/seekdb

Fix memory leak in SqlPx module during LOAD DATA with Direct Load

Open
#693 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

dima type: bug
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

  1. Execute a LOAD DATA workload that triggers the Direct Load path (ObTableDirectInsertOp).
  2. Monitor the memory usage of the mod=SqlPx context.
  3. Observe that memory usage (hold and used) 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.