2023-08-31 12:47:06 +00:00
|
|
|
package shard
|
2022-07-29 07:54:49 +00:00
|
|
|
|
|
|
|
import (
|
2023-11-17 07:58:04 +00:00
|
|
|
"bytes"
|
2023-03-13 11:37:35 +00:00
|
|
|
"context"
|
2022-07-29 08:11:55 +00:00
|
|
|
"math"
|
2022-07-11 12:34:17 +00:00
|
|
|
"path/filepath"
|
2022-07-29 07:54:49 +00:00
|
|
|
"testing"
|
|
|
|
|
2023-03-07 13:38:26 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/blobovniczatree"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/fstree"
|
2023-03-20 14:10:26 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
|
2023-12-22 09:58:20 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/writecache"
|
2023-08-23 07:53:42 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
|
2023-03-07 13:38:26 +00:00
|
|
|
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
|
|
|
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
2022-07-29 07:54:49 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestShard_GetRange(t *testing.T) {
|
2023-05-05 11:08:10 +00:00
|
|
|
t.Parallel()
|
2022-07-29 07:54:49 +00:00
|
|
|
t.Run("without write cache", func(t *testing.T) {
|
2023-05-05 11:08:10 +00:00
|
|
|
t.Parallel()
|
2022-07-29 07:54:49 +00:00
|
|
|
testShardGetRange(t, false)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("with write cache", func(t *testing.T) {
|
2023-05-05 11:08:10 +00:00
|
|
|
t.Parallel()
|
2022-07-29 07:54:49 +00:00
|
|
|
testShardGetRange(t, true)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func testShardGetRange(t *testing.T, hasWriteCache bool) {
|
|
|
|
type testCase struct {
|
|
|
|
hasErr bool
|
|
|
|
name string
|
|
|
|
payloadSize int
|
|
|
|
rng *objectSDK.Range
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
writeCacheMaxSize = 1024
|
|
|
|
smallObjectSize = 2048
|
|
|
|
)
|
|
|
|
|
|
|
|
newRange := func(off, ln uint64) *objectSDK.Range {
|
|
|
|
rng := objectSDK.NewRange()
|
|
|
|
rng.SetOffset(off)
|
|
|
|
rng.SetLength(ln)
|
|
|
|
return rng
|
|
|
|
}
|
|
|
|
|
|
|
|
testCases := []testCase{
|
|
|
|
{false, "small object, good", 1024, newRange(11, 123)},
|
2022-07-29 08:11:55 +00:00
|
|
|
{true, "small object, out of range, big len", 1024, newRange(10, 1020)},
|
|
|
|
{true, "small object, out of range, big offset", 1024, newRange(1025, math.MaxUint64-10)},
|
2022-07-29 07:54:49 +00:00
|
|
|
{false, "big object, good", 2048, newRange(11, 123)},
|
2022-07-29 08:11:55 +00:00
|
|
|
{true, "big object, out of range, big len", 2048, newRange(100, 2000)},
|
|
|
|
{true, "big object, out of range, big offset", 2048, newRange(2048, math.MaxUint64-10)},
|
2022-07-29 07:54:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if hasWriteCache {
|
|
|
|
testCases = append(testCases,
|
|
|
|
testCase{false, "object in write-cache, good", 100, newRange(2, 18)},
|
2022-07-29 08:11:55 +00:00
|
|
|
testCase{true, "object in write-cache, out of range, big len", 100, newRange(4, 99)},
|
|
|
|
testCase{true, "object in write-cache, out of range, big offset", 100, newRange(101, math.MaxUint64-10)})
|
2022-07-29 07:54:49 +00:00
|
|
|
}
|
|
|
|
|
2023-12-22 09:58:20 +00:00
|
|
|
wcOpts := []writecache.Option{
|
|
|
|
writecache.WithMaxObjectSize(writeCacheMaxSize),
|
2023-06-22 11:55:30 +00:00
|
|
|
}
|
|
|
|
|
2023-09-06 14:32:14 +00:00
|
|
|
sh := newCustomShard(t, hasWriteCache, shardOptions{
|
2023-09-06 14:48:00 +00:00
|
|
|
wcOpts: wcOpts,
|
2023-09-06 14:32:14 +00:00
|
|
|
bsOpts: []blobstor.Option{
|
|
|
|
blobstor.WithStorages([]blobstor.SubStorage{
|
|
|
|
{
|
|
|
|
Storage: blobovniczatree.NewBlobovniczaTree(
|
2024-03-01 11:43:26 +00:00
|
|
|
context.Background(),
|
2024-01-09 08:37:41 +00:00
|
|
|
blobovniczatree.WithLogger(test.NewLogger(t)),
|
2023-09-06 14:32:14 +00:00
|
|
|
blobovniczatree.WithRootPath(filepath.Join(t.TempDir(), "blob", "blobovnicza")),
|
|
|
|
blobovniczatree.WithBlobovniczaShallowDepth(1),
|
|
|
|
blobovniczatree.WithBlobovniczaShallowWidth(1)),
|
|
|
|
Policy: func(_ *objectSDK.Object, data []byte) bool {
|
|
|
|
return len(data) <= smallObjectSize
|
|
|
|
},
|
2022-07-11 12:34:17 +00:00
|
|
|
},
|
2023-09-06 14:32:14 +00:00
|
|
|
{
|
|
|
|
Storage: fstree.New(
|
|
|
|
fstree.WithPath(filepath.Join(t.TempDir(), "blob"))),
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
})
|
2024-10-21 08:56:38 +00:00
|
|
|
defer func() { require.NoError(t, sh.Close(context.Background())) }()
|
2022-07-29 07:54:49 +00:00
|
|
|
|
|
|
|
for _, tc := range testCases {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
2023-03-20 14:10:26 +00:00
|
|
|
obj := testutil.GenerateObject()
|
|
|
|
testutil.AddAttribute(obj, "foo", "bar")
|
|
|
|
testutil.AddPayload(obj, tc.payloadSize)
|
2022-07-29 07:54:49 +00:00
|
|
|
|
|
|
|
addr := object.AddressOf(obj)
|
2023-11-17 07:58:04 +00:00
|
|
|
payload := bytes.Clone(obj.Payload())
|
2022-07-29 07:54:49 +00:00
|
|
|
|
2023-08-31 12:47:06 +00:00
|
|
|
var putPrm PutPrm
|
2022-07-29 07:54:49 +00:00
|
|
|
putPrm.SetObject(obj)
|
|
|
|
|
2023-04-12 14:01:29 +00:00
|
|
|
_, err := sh.Put(context.Background(), putPrm)
|
2022-07-29 07:54:49 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2023-08-31 12:47:06 +00:00
|
|
|
var rngPrm RngPrm
|
2022-07-29 07:54:49 +00:00
|
|
|
rngPrm.SetAddress(addr)
|
|
|
|
rngPrm.SetRange(tc.rng.GetOffset(), tc.rng.GetLength())
|
|
|
|
|
2023-03-13 11:37:35 +00:00
|
|
|
res, err := sh.GetRange(context.Background(), rngPrm)
|
2022-07-29 07:54:49 +00:00
|
|
|
if tc.hasErr {
|
2023-08-04 11:14:07 +00:00
|
|
|
var target *apistatus.ObjectOutOfRange
|
|
|
|
require.ErrorAs(t, err, &target)
|
2022-07-29 07:54:49 +00:00
|
|
|
} else {
|
|
|
|
require.Equal(t,
|
|
|
|
payload[tc.rng.GetOffset():tc.rng.GetOffset()+tc.rng.GetLength()],
|
|
|
|
res.Object().Payload())
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|