Doris-Breakwater commented on issue #66298:
URL: https://github.com/apache/doris/issues/66298#issuecomment-5129983723

   ## Initial analysis
   
   **Judgment: confirmed bug on `4.1.0-rc03`, with high confidence.** The 
reported numbers are consistent with the code reaching the `ColumnString` 
uint32 offset ceiling while a non-streaming VARIANT writer accumulates one 
output segment. This is an availability issue: the same immutable inputs and 
row-count plan will fail again unless the segment layout or writer path 
changes. The retry amplification belongs in #66299, but it materially raises 
the operational severity of this issue.
   
   The issue currently has no labels or assignee. It should be triaged as a 
compaction/VARIANT correctness and availability bug rather than as a 
Ceph-specific problem.
   
   ### Code findings
   
   1. At `4.1.0-rc03`, `Compaction::get_avg_segment_rows()` uses 
`_input_rowsets_data_size`, which is compressed on-disk data, to derive a row 
limit from `vertical_compaction_max_segment_size` 
(`be/src/storage/compaction/compaction.cpp:319-335`). The units therefore do 
not protect an uncompressed in-memory column limit.
   
   2. `ColumnStr<UInt32>::check_chars_length()` rejects a character buffer 
above `0xffffffff` (`be/src/core/column/column_string.h:64-78`). The reported 
`total_length=4297424560` is 2,457,265 bytes above that limit and is exactly 
consistent with the next append crossing it.
   
   3. The important scope detail is that 4 GiB is a limit of one **in-memory 
`ColumnString`**, not inherently a limit on all uncompressed string bytes 
stored across a segment's pages. The non-streaming 
`VariantColumnWriterImpl::append_data()` repeatedly calls 
`_column->insert_range_from(...)` and retains that `ColumnVariant` until 
segment finalization 
(`be/src/storage/segment/variant/variant_column_writer_impl.cpp:1478-1495` at 
the tag). That segment-wide materialization turns the row-count sizing mismatch 
into this deterministic failure.
   
   4. Vertical compaction fixes output segment row boundaries while writing the 
key group. Later value groups must follow each key segment's `row_count()` 
(`vertical_beta_rowset_writer.cpp:65-114`). Consequently, a value/VARIANT group 
cannot simply open a new segment when it approaches 4 GiB without also changing 
the already-established boundaries for every column group. The current 
key-group check is also performed before appending the next whole block and 
uses `>` rather than `>=`, so the planned row limit can be exceeded by one 
input block; this is secondary here but should be covered by tests.
   
   5. The compressed-size estimator is still present on current master. 
However, master is not identical to the affected tag in every relevant respect:
      - Master propagates `input_rs_readers` into `RowsetWriterContext` and can 
use `VariantStreamingCompactionWriter` for nested-group, non-doc-mode VARIANT 
columns.
      - In `4.1.0-rc03`, `VariantColumnWriterImpl` has the same streaming 
predicate, but `Compaction::merge_input_rowsets()` does not populate 
`ctx.input_rs_readers`, so that predicate cannot be satisfied through this 
compaction path.
      - The master streaming path is only a partial mitigation. The fallback 
`VariantColumnWriterImpl`, `VariantSubcolumnWriter`, and 
`VariantDocCompactWriter` paths still accumulate a segment-wide 
`ColumnVariant`. The table properties and full stack are needed to identify 
which of these triggered this report.
   
   6. The statement that ordinary plain STRING columns reproduce the same 
segment-wide failure is not yet established by the supplied evidence. 
`ScalarColumnWriter` writes strings incrementally into pages rather than 
retaining a segment-wide `ColumnString`; a plain STRING failure would require a 
single merge block/converter column itself to exceed 4 GiB or a different 
accumulating operator. Please provide that failure's stack separately if it is 
part of the claimed scope.
   
   ### Recommended fix direction
   
   The most direct correctness fix is to extend chunked/streaming compaction 
writing to all affected VARIANT modes and extracted/doc subcolumn writer paths, 
so an output segment may contain more than 4 GiB of uncompressed string payload 
across encoded pages without constructing one `ColumnString` above the uint32 
limit. The streaming implementation must also split an incoming chunk before 
insertion if that chunk alone would cross the limit.
   
   Changing `get_avg_segment_rows()` to use footer `raw_data_bytes` or another 
uncompressed estimate is useful as a memory/segment-sizing guard, but it is not 
a proof of safety: averages do not cover skew, some VARIANT footer paths do not 
currently provide usable raw-byte statistics, and the key-group-first layout 
cannot discover a later value column's exact safe boundary dynamically. 
Compressed-byte sizing may remain as the on-disk target, but the in-memory 
writer invariant needs an independent enforcement mechanism.
   
   If maintainers instead choose dynamic segment cutting, the safe row 
boundaries must be determined before or while producing the key group and then 
replayed for all value groups. Cutting only inside the later VARIANT group 
would violate vertical segment row alignment.
   
   ### Information still needed
   
   - Full symbolized stack trace for the quoted E-3113, including the frames 
between `ColumnStr::insert_range_from` and the compaction entry point.
   - `SHOW CREATE TABLE`, especially VARIANT properties controlling doc mode, 
nested groups, typed/extracted paths, and maximum subcolumns.
   - Relevant BE settings: `enable_vertical_compaction`, 
`enable_vertical_compact_variant_subcolumns`, 
`vertical_compaction_max_segment_size`, 
`vertical_compaction_num_columns_per_group`, and `compaction_batch_size`.
   - The failing compaction's input rowset count, total rows, compressed data 
size, per-input segment row counts, and the logged `max_rows_per_segment`.
   - For the “plain STRING also works” claim, a separate DDL, minimal 
reproduction, error line, and stack trace.
   
   ### Suggested next steps
   
   1. Reproduce with a test-only low string-buffer threshold so the regression 
does not require allocating 4 GiB, covering regular VARIANT, doc mode, 
extracted subcolumns, and nested-group streaming.
   2. Verify that compaction succeeds and row counts/checksums match while the 
writer never retains more than the test threshold in one in-memory string 
column.
   3. Add a skewed-data case and a boundary case where the next merge block 
would cross the limit; also assert that all vertical column groups use 
identical segment row boundaries.
   4. Backport the writer fix to the affected 4.1 branch independently of the 
scheduler/backoff work in #66299.
   
   Breakwater-GitHub-Analysis-Slot: slot_9859ad160d24
   


-- 
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]

Reply via email to