diff --git a/blobstore/blobnode/core/storage/datafile.go b/blobstore/blobnode/core/storage/datafile.go index 617b3627d..04c2bbd76 100644 --- a/blobstore/blobnode/core/storage/datafile.go +++ b/blobstore/blobnode/core/storage/datafile.go @@ -422,7 +422,8 @@ func (cd *datafile) Read(ctx context.Context, shard *core.Shard, from, to uint32 iosr := cd.qosReaderAt(ctx, ra) // new buffer - buffer := bytespool.Alloc(core.CrcBlockUnitSize) + buffSize := crc32block.DecoderBufferSize(int64(shard.Size)) + buffer := bytespool.Alloc(int(buffSize)) // decode crc decoder, err := crc32block.NewDecoderWithBlock(iosr, pos, int64(shard.Size), buffer, cd.conf.BlockBufferSize) diff --git a/blobstore/common/crc32block/util.go b/blobstore/common/crc32block/util.go index c75c64ae8..f2ef8208c 100644 --- a/blobstore/common/crc32block/util.go +++ b/blobstore/common/crc32block/util.go @@ -37,6 +37,11 @@ var ( ErrReadOnClosed = errors.New("crc32block: read on closed") ) +func DecoderBufferSize(shardSize int64) int64 { + buffSize := util.AlignedFull(EncodeSize(shardSize, gBlockSize), baseBlockLen) + return util.Min(buffSize, gBlockSize) +} + func isValidBlockLen(blockLen int64) bool { return blockLen > 0 && blockLen%baseBlockLen == 0 } diff --git a/blobstore/common/crc32block/util_test.go b/blobstore/common/crc32block/util_test.go index 1a1254ad4..dac7ce149 100644 --- a/blobstore/common/crc32block/util_test.go +++ b/blobstore/common/crc32block/util_test.go @@ -23,6 +23,34 @@ import ( "github.com/stretchr/testify/require" ) +func TestDecoderBufferSize(t *testing.T) { + testData := []struct { + shardSize int64 + description string + expected int64 + }{ + {shardSize: 1, description: "very small shard size", expected: baseBlockLen}, + {shardSize: int64(baseBlockLen - crc32Len), description: "shard smaller than baseBlockLen after accounting for CRC", expected: baseBlockLen}, + {shardSize: int64(baseBlockLen - crc32Len + 1), description: "shard equal to baseBlockLen after accounting for CRC", expected: baseBlockLen * 2}, + {shardSize: gBlockSize - crc32Len, description: "shard equal to gBlockSize after accounting for CRC (should be limited)", expected: gBlockSize}, + {shardSize: gBlockSize - crc32Len + 1, description: "shard larger than gBlockSize after accounting for CRC (should be limited)", expected: gBlockSize}, + } + + for _, tc := range testData { + t.Run(tc.description, func(t *testing.T) { + result := DecoderBufferSize(tc.shardSize) + + require.GreaterOrEqual(t, result, int64(baseBlockLen)) + require.LessOrEqual(t, result, gBlockSize) + require.Equal(t, int64(0), result%int64(baseBlockLen)) + + require.Equal(t, tc.expected, result, + "Expected %d for shardSize %d, but got %d", + tc.expected, tc.shardSize, result) + }) + } +} + func TestDecodeSize(t *testing.T) { datas := []struct { blockLen int64