forked from TrueCloudLab/frostfs-sdk-go
[#248] object: Introduce SplitByMaxChunkLength
method
* Add unit-test to test `SplitByMaxChunkLength`. Signed-off-by: Airat Arifullin <a.arifullin@yadro.com>
This commit is contained in:
parent
5e9cf6a8ae
commit
895a2ef0e2
2 changed files with 103 additions and 0 deletions
|
@ -78,6 +78,42 @@ type PayloadPatch struct {
|
||||||
Chunk []byte
|
Chunk []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SplitByMaxChunkLength splits a payload patch into a few payload patches if its `Chunk` size
|
||||||
|
// exceeds `maxChunkLen`.
|
||||||
|
func (p *PayloadPatch) SplitByMaxChunkLength(maxChunkLen int) []*PayloadPatch {
|
||||||
|
if len(p.Chunk) <= maxChunkLen {
|
||||||
|
return []*PayloadPatch{p}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []*PayloadPatch
|
||||||
|
remainingChunk := p.Chunk
|
||||||
|
currentOffset := p.Range.GetOffset()
|
||||||
|
remainingLength := p.Range.GetLength()
|
||||||
|
|
||||||
|
for len(remainingChunk) > 0 {
|
||||||
|
chunkSize := uint64(min(len(remainingChunk), maxChunkLen))
|
||||||
|
newLength := min(remainingLength, chunkSize)
|
||||||
|
|
||||||
|
rng := NewRange()
|
||||||
|
rng.SetOffset(currentOffset)
|
||||||
|
rng.SetLength(newLength)
|
||||||
|
|
||||||
|
newPatch := &PayloadPatch{
|
||||||
|
Range: rng,
|
||||||
|
Chunk: remainingChunk[:chunkSize],
|
||||||
|
}
|
||||||
|
result = append(result, newPatch)
|
||||||
|
|
||||||
|
remainingChunk = remainingChunk[chunkSize:]
|
||||||
|
currentOffset += chunkSize
|
||||||
|
if remainingLength > 0 {
|
||||||
|
remainingLength -= newLength
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func (p *PayloadPatch) ToV2() *v2object.PatchRequestBodyPatch {
|
func (p *PayloadPatch) ToV2() *v2object.PatchRequestBodyPatch {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -10,6 +10,73 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func newRange(offest, length uint64) *Range {
|
||||||
|
rng := &Range{}
|
||||||
|
rng.SetOffset(offest)
|
||||||
|
rng.SetLength(length)
|
||||||
|
return rng
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplitByMaxChunkLength(t *testing.T) {
|
||||||
|
t.Run("no break down", func(t *testing.T) {
|
||||||
|
payloadPatch := &PayloadPatch{
|
||||||
|
Range: newRange(0, 42),
|
||||||
|
Chunk: []byte("100000|010000|001000|000100|000010|000001|"),
|
||||||
|
}
|
||||||
|
|
||||||
|
payloadPatches := payloadPatch.SplitByMaxChunkLength(42)
|
||||||
|
|
||||||
|
require.Len(t, payloadPatches, 1)
|
||||||
|
require.Equal(t, []byte("100000|010000|001000|000100|000010|000001|"), payloadPatches[0].Chunk)
|
||||||
|
|
||||||
|
require.Equal(t, uint64(0), payloadPatches[0].Range.GetOffset())
|
||||||
|
require.Equal(t, uint64(42), payloadPatches[0].Range.GetLength())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("one replacing and two inserting patches", func(t *testing.T) {
|
||||||
|
payloadPatch := &PayloadPatch{
|
||||||
|
Range: newRange(0, 15),
|
||||||
|
Chunk: []byte("100000|010000|001000|000100|000010|000001|"),
|
||||||
|
}
|
||||||
|
|
||||||
|
payloadPatches := payloadPatch.SplitByMaxChunkLength(15)
|
||||||
|
|
||||||
|
require.Len(t, payloadPatches, 3)
|
||||||
|
|
||||||
|
require.Equal(t, []byte("100000|010000|0"), payloadPatches[0].Chunk)
|
||||||
|
require.Equal(t, uint64(0), payloadPatches[0].Range.GetOffset())
|
||||||
|
require.Equal(t, uint64(15), payloadPatches[0].Range.GetLength())
|
||||||
|
|
||||||
|
require.Equal(t, []byte("01000|000100|00"), payloadPatches[1].Chunk)
|
||||||
|
require.Equal(t, uint64(15), payloadPatches[1].Range.GetOffset())
|
||||||
|
require.Equal(t, uint64(0), payloadPatches[1].Range.GetLength())
|
||||||
|
|
||||||
|
require.Equal(t, []byte("0010|000001|"), payloadPatches[2].Chunk)
|
||||||
|
require.Equal(t, uint64(30), payloadPatches[2].Range.GetOffset())
|
||||||
|
require.Equal(t, uint64(0), payloadPatches[2].Range.GetLength())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("one replacing and one inserting patches", func(t *testing.T) {
|
||||||
|
payloadPatch := &PayloadPatch{
|
||||||
|
Range: newRange(0, 30),
|
||||||
|
Chunk: []byte("100000|010000|001000|000100|000010|000001|"),
|
||||||
|
}
|
||||||
|
|
||||||
|
payloadPatches := payloadPatch.SplitByMaxChunkLength(30)
|
||||||
|
|
||||||
|
require.Len(t, payloadPatches, 2)
|
||||||
|
require.Equal(t, []byte("100000|010000|001000|000100|00"), payloadPatches[0].Chunk)
|
||||||
|
|
||||||
|
require.Equal(t, uint64(0), payloadPatches[0].Range.GetOffset())
|
||||||
|
require.Equal(t, uint64(30), payloadPatches[0].Range.GetLength())
|
||||||
|
|
||||||
|
require.Equal(t, []byte("0010|000001|"), payloadPatches[1].Chunk)
|
||||||
|
|
||||||
|
require.Equal(t, uint64(30), payloadPatches[1].Range.GetOffset())
|
||||||
|
require.Equal(t, uint64(0), payloadPatches[1].Range.GetLength())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestPatch(t *testing.T) {
|
func TestPatch(t *testing.T) {
|
||||||
t.Run("to v2", func(t *testing.T) {
|
t.Run("to v2", func(t *testing.T) {
|
||||||
t.Run("only attributes", func(t *testing.T) {
|
t.Run("only attributes", func(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue