Order-preserving RepartitionExec fails with ResourcesExhausted on non-spillable merge reservation for Utf8View data
Mantenedores costumam responder em até 1 dia
Avaliação
Esta issue ainda não foi avaliada.
Descrição
Describe the bug
An order-preserving hash RepartitionExec fails with ResourcesExhausted on RepartitionExec[Merge N] reservations, which report can spill: false. The query returns only 7000 rows. The merge reservations grow until they fill the pool, whatever the pool size.
Commit: 34eb6dc5bf057a35c471a4fbfd2eece2a7937afe (main).
To Reproduce
Run with datafusion-cli -m 200M -f repro.sql:
COPY (SELECT value % 1000 AS k, repeat('x', 100) || (value % 7)::varchar AS s, value AS v
FROM generate_series(1, 2000000) ORDER BY k)
TO 'data.parquet' STORED AS PARQUET;
SET datafusion.execution.target_partitions = 8;
CREATE EXTERNAL TABLE t STORED AS PARQUET LOCATION 'data.parquet' WITH ORDER (k ASC);
SELECT count(*) FROM (SELECT k, s, count(*) FROM t GROUP BY k, s ORDER BY k);
The file is 5.6 MB. Error:
Resources exhausted: Additional allocation failed for RepartitionExec[Merge 6] with top memory consumers (across reservations) as:
RepartitionExec[Merge 3]#44(can spill: false) consumed 25.5 MB, peak 25.5 MB,
RepartitionExec[Merge 5]#43(can spill: false) consumed 25.3 MB, peak 25.3 MB,
RepartitionExec[Merge 0]#35(can spill: false) consumed 25.2 MB, peak 25.2 MB.
Error: Failed to allocate additional 640.0 B for RepartitionExec[Merge 6] with 24.8 MB already allocated for this reservation - 6.0 B remain available for the total memory pool: greedy(used: 200.0 MB, pool_size: 200.0 MB)
With -m 50M each merge holds about 6 MB. With -m 20M each holds about 2.5 MB. The query passes at -m 400M.
Plan (relevant part):
AggregateExec: mode=FinalPartitioned, gby=[k, s]
RepartitionExec: partitioning=Hash([k@0, s@1], 8), input_partitions=8, preserve_order=true, sort_exprs=k@0 ASC NULLS LAST
AggregateExec: mode=Partial, gby=[k, s], group_clustering_mode=Partial([0])
DataSourceExec: file_groups=8, format=parquet
EXPLAIN ANALYZE metrics without a limit:
| operator | output_rows | output_batches | output_bytes |
|---|---|---|---|
| DataSourceExec | 2.00 M | 245 | 46.1 MB |
| AggregateExec Partial | 7.01 K | 246 | 42.7 MB |
| RepartitionExec | 7.01 K | 8 | 330.1 MB |
If s is Utf8 (arrow_cast(s, 'Utf8')), the partial aggregate reports 1.7 MB, the repartition reports 828 KB, and the query passes at -m 10M.
Expected behavior
The query succeeds with a small limit. The data that the merge must hold is a few KB per output partition.
Additional context
Three effects combine.
- The partial aggregate emits
Utf8Viewbatches of about 28 rows that report about 174 KB each. The view data buffers dominate that size. - The hash partitioner uses
take_arrays(https://github.com/apache/datafusion/blob/34eb6dc5bf057a35c471a4fbfd2eece2a7937afe/datafusion/physical-plan/src/repartition/mod.rs#L1376). ForUtf8Viewcolumns,takecopies only the views and shares the data buffers. Each of the 8 output batches reports the full buffer size. The sum over all merges is about 8 times the real memory. BatchBuilderkeeps every input batch that has a row inindicesuntil it builds an output batch (https://github.com/apache/datafusion/blob/34eb6dc5bf057a35c471a4fbfd2eece2a7937afe/datafusion/physical-plan/src/sorts/builder.rs#L89-L95, https://github.com/apache/datafusion/blob/34eb6dc5bf057a35c471a4fbfd2eece2a7937afe/datafusion/physical-plan/src/sorts/builder.rs#L163-L170). Each output partition has fewer thanbatch_sizerows, so the merge never emits before the end and keeps all of its input batches. The reservation grows with the number of input batches. It is not bounded byN inputs x batch size.
The merge reservation is created at https://github.com/apache/datafusion/blob/34eb6dc5bf057a35c471a4fbfd2eece2a7937afe/datafusion/physical-plan/src/repartition/mod.rs#L1857-L1869 without with_can_spill(true). A refused try_grow in BatchBuilder::push_batch fails the query. The repartition channel spill path (https://github.com/apache/datafusion/blob/34eb6dc5bf057a35c471a4fbfd2eece2a7937afe/datafusion/physical-plan/src/repartition/mod.rs#L218-L230) does not help, because the memory is held after the channel. SortPreservingMergeExec uses the same StreamingMergeBuilder and BatchBuilder, so it has the same retention behavior.
Possible fixes:
- In
BatchBuilder, whenpush_batchcannot grow the reservation, emit the rows inindicesas a short batch, then release the dead batches and retry. This bounds the retained batches to about one per input stream. - Avoid the shared-buffer over-count: compact (
gc) view arrays aftertakein the hash partitioner, or account shared buffers once.
- Linguagem predominante
- Rust
- Estrelas
- 9.6k
- Forks
- 2.6k
- Merge médio
- 3d 4h
- PRs com merge (30d)
- 345
Preparar o ambiente
Inicia o contêiner de desenvolvimento do projeto no navegador, com a sua própria conta do GitHub.
- Sem Dockerfile nem arquivo Docker Compose
- Tem um modelo de pull request
- Ler o guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de apache/datafusion
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 72/100
apache/datafusion#27315 · 2 comentários ·
Mantenedores costumam responder em até 1 dia
-
bug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 76/100
apache/datafusion#27094 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
Substrait consumer doesn't recognise `shift_left` / `shift_right` from functions_arithmetic.yamlTalvez já em andamento @jonasHanhan assumiu há 9 dias. Abertabug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 76/100
apache/datafusion#27059 ·
Mantenedores costumam responder em até 1 dia
-
`ProjectionExprs::project_statistics` computes approximate `Statistics::total_byte_size` ignoring column statsTalvez já em andamento @joseph-isaacs assumiu há 10 dias. Abertabug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 72/100
apache/datafusion#27050 ·
Mantenedores costumam responder em até 1 dia
-
physical-plan: decoding an Unnest or Explain node with an unset field panicsTalvez já em andamento @geoHeil assumiu há 8 dias. Aberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 75/100
apache/datafusion#26999 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
Todas as issues de apache/datafusion
Issues semelhantes
-
P3
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 70/100
HerringtonDarkholme/hd-lang#1770 ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 82/100
jonathanong/no-mistakes#3332 ·
Mantenedores costumam responder em até 1 dia
-
bug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
swc-project/swc-next-issues#310 ·
-
bug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 72/100
swc-project/swc-ai-issues#653 ·
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 72/100
lbjlaq/Antigravity-Manager#3937 ·
Mantenedores costumam responder em até 1 dia