Skip to content

[BUG]: DeserializeAsync(rowGroupIndex:) allocates a result list sized to the whole file, causing OOM on large files #764

Description

@svenclaesson

Library Version

6.0.3
This worked as expected on on 5.4

.NET Runtime

.NET 10

OS and Architecture

macOS (Apple Silicon)

How to reproduce?

// File with many row groups, tens of millions of rows total.
var result = await ParquetSerializer.DeserializeAsync(stream, rowGroupIndex: 0);
// OOM in ParquetSerializer.GetList, or a list pre-sized to the whole file.

Expected:
Reading a single row group should allocate a list sized to that group only

Failing test

[Fact]
    public async Task Deserialize_per_row_group_does_not_over_allocate() {
        int records = 100;
        int rowGroupSize = 20;

        var data = Enumerable.Range(0, records).Select(i => new Record {
            Timestamp = DateTime.UtcNow.AddSeconds(i),
            EventName = i % 2 == 0 ? "on" : "off",
            MeterValue = i
        }).ToList();

        using var ms = new MemoryStream();
        await ParquetSerializer.SerializeAsync(data, ms, new ParquetOptions { RowGroupSize = rowGroupSize });

        ms.Position = 0;
        IList<Record> single = (await ParquetSerializer.DeserializeAsync<Record>(ms, rowGroupIndex: 0)).Data;

        // Reading one row group must size the backing list to that group, not to every row in the file.
        // Before the fix this list was pre-allocated with capacity == sum of all row groups (here 100).
        Assert.Equal(rowGroupSize, single.Count);
        Assert.Equal(rowGroupSize, ((List<Record>)single).Capacity);
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions