Skip to content

fix(ducklake): disable data inlining by default, flush it in compaction, batch Line Protocol writes - #765

Merged
adubovikov merged 2 commits into
homer11from
fix/ducklake-inlining-and-lp-batching
May 30, 2026
Merged

fix(ducklake): disable data inlining by default, flush it in compaction, batch Line Protocol writes#765
adubovikov merged 2 commits into
homer11from
fix/ducklake-inlining-and-lp-batching

Conversation

@adubovikov

@adubovikov adubovikov commented May 30, 2026

Copy link
Copy Markdown
Member

Summary

Fixes a class of DuckLake memory / catalog-bloat issues in Homer's ingest stack (DuckDB/DuckLake + sqlite catalog + Parquet). The HEP write path is already well-batched (Appender + double-buffer + bulk flush) and is left untouched — but three real gaps remained:

1. Data inlining was effectively on by default

DuckLakeConfig.DataInliningRowLimit defaulted to -1 = "leave DuckLake's own default", which inlines small (~10-row) writes into the sqlite catalog instead of Parquet. Under streaming Line Protocol / OTLP / low-volume HEP subtypes this makes the catalog the dominant memory + disk consumer — the classic symptom is an 800 MB sqlite catalog backing only a few dozen Parquet files, with multi-GB RSS once DuckLake mirrors it in memory.

  • Default changed to 0 (inlining off, always write Parquet).
  • -1 (DuckLake default) and >0 (custom threshold) are still honoured for operators who explicitly want them.

2. CompactionService never flushed inlined data

The maintenance cycle ran merge -> expire -> cleanup -> delete_orphaned but never ducklake_flush_inlined_data, so anything already inlined (or inlined by an operator who re-enables it) stayed in the catalog forever.

  • Added a flush step at the start of the cycle (before merge, so merge/expire act on the freshly written Parquet).
  • Harmless no-op when inlining is disabled (the new default).

3. Line Protocol generic path did per-row micro-commits

The generic LP ingest path issued one stmt.ExecContext per row = one DuckLake transaction (snapshot + tiny write) per row — a micro-commit storm under load.

  • Replaced with chunked multi-row INSERT ... VALUES (500 rows/statement), collapsing per-row transaction/snapshot churn by up to 500x.
  • hep_proto_* LP and OTLP already batch per request and are unchanged.

Not changed

  • src/version.go — Homer's version is tag-driven (version-sync.yml rewrites it from the release tag), so the bump happens at release time, not in this PR.
  • HEP write path (already batched).

Test plan

  • go build ./config/... ./lineprotoreceiver/... ./writer/...
  • go vet ./config/... ./lineprotoreceiver/...
  • Run with Line Protocol load; confirm reduced snapshot count (ducklake_snapshots) per ingested batch.
  • Confirm sqlite catalog stays small (no ducklake_inlined_data_* growth) over a sustained ingest window.
  • Verify CompactionService logs Flush inlined data each maintenance cycle.

…ion + batch LP writes

Ports the memory/catalog-bloat fixes proven in the sibling ingest
service (hepic-lake-ingest) to Homer's DuckLake stack. Same storage
class (DuckDB/DuckLake + sqlite catalog + Parquet); the HEP write path
here is already well-batched (Appender + double-buffer + bulk flush),
but three gaps remained:

1. Data inlining default. DuckLakeConfig.DataInliningRowLimit defaulted
   to -1 ("leave DuckLake's own default", which inlines ~10-row writes
   into the catalog DB). Under streaming Line Protocol / OTLP / low-
   volume HEP subtypes this turns the catalog into the dominant memory +
   disk consumer (an 800 MB sqlite catalog backing only a few dozen
   Parquet files, multi-GB RSS when DuckLake mirrors it in memory).
   Default is now 0 (inlining off, always write Parquet). -1 and >0 are
   still honoured for operators who want them.

2. No inline flush in maintenance. The CompactionService ran merge /
   expire / cleanup / delete-orphaned but never ducklake_flush_inlined_data,
   so anything already inlined (or inlined by an operator who re-enables
   it) stayed in the catalog forever. Added a flush step at the start of
   the maintenance cycle (before merge, so merge/expire act on the
   freshly written Parquet). No-op when inlining is disabled.

3. Line Protocol micro-commits. The generic LP path issued one prepared
   stmt.ExecContext per row = one DuckLake transaction (snapshot + tiny
   write) per row. Replaced with chunked multi-row INSERT ... VALUES
   (500 rows/statement), collapsing the per-row transaction/snapshot
   churn by up to 500x. hep_proto_* LP and OTLP already batch per
   request and are unchanged.

version.go is intentionally untouched — Homer's version is tag-driven
(version-sync.yml updates it from the release tag).
@CLAassistant

CLAassistant commented May 30, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@adubovikov
adubovikov merged commit 924227c into homer11 May 30, 2026
9 of 10 checks passed
@adubovikov
adubovikov deleted the fix/ducklake-inlining-and-lp-batching branch May 30, 2026 22:36
n0obHere pushed a commit to n0obHere/homer that referenced this pull request Jun 22, 2026
PR sipcapture#765 added ducklake_flush_inlined_data to the CompactionService cycle,
but that service is opt-in (disabled by default). So a node that upgrades
to the new inlining-off default while leaving compaction off never drains
its legacy inline backlog: disabling inlining only stops NEW inlining, it
does not flush rows inlined earlier, which stay in the catalog and
resident in the DuckLake extension's memory. This is the same end symptom
fixed in the sibling ingest service (stuck inline backlog bloating the
extension heap).

- CompactionService now always starts: full merge/expire/cleanup when
  enabled, otherwise a lightweight inline-flush-only loop paced by
  CheckIntervalSec (first run ~1 min after startup so a backlog drains
  promptly).
- Extracted flushInlinedData() shared by the full cycle (step 0) and the
  flush-only loop; it reapplies S3 settings and is a no-op once nothing is
  inlined.

Bump 11.0.232 -> 11.0.233.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants