2022-10-16 11:39:47 +00:00
|
|
|
package shard
|
|
|
|
|
|
|
|
import (
|
2023-03-23 14:59:14 +00:00
|
|
|
"context"
|
2022-10-16 11:39:47 +00:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"testing"
|
|
|
|
|
2023-03-07 13:38:26 +00:00
|
|
|
objectCore "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/fstree"
|
|
|
|
meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/pilorama"
|
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
|
|
|
checksumtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum/test"
|
|
|
|
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
|
|
|
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
|
|
|
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
|
|
|
|
sessiontest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session/test"
|
|
|
|
usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
|
2022-10-16 11:39:47 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestShardReload(t *testing.T) {
|
2023-05-05 11:08:10 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2022-10-16 11:39:47 +00:00
|
|
|
p := t.Name()
|
|
|
|
defer os.RemoveAll(p)
|
2024-01-09 08:37:41 +00:00
|
|
|
l := test.NewLogger(t)
|
2022-10-16 11:39:47 +00:00
|
|
|
blobOpts := []blobstor.Option{
|
|
|
|
blobstor.WithLogger(l),
|
|
|
|
blobstor.WithStorages([]blobstor.SubStorage{
|
|
|
|
{
|
|
|
|
Storage: fstree.New(
|
|
|
|
fstree.WithPath(filepath.Join(p, "blob")),
|
|
|
|
fstree.WithDepth(1)),
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
|
|
|
metaOpts := []meta.Option{
|
|
|
|
meta.WithPath(filepath.Join(p, "meta")),
|
2023-10-31 11:56:55 +00:00
|
|
|
meta.WithEpochState(epochState{}),
|
|
|
|
}
|
2022-10-16 11:39:47 +00:00
|
|
|
|
|
|
|
opts := []Option{
|
2023-04-12 14:01:29 +00:00
|
|
|
WithID(NewIDFromBytes([]byte{})),
|
2022-10-16 11:39:47 +00:00
|
|
|
WithLogger(l),
|
|
|
|
WithBlobStorOptions(blobOpts...),
|
|
|
|
WithMetaBaseOptions(metaOpts...),
|
|
|
|
WithPiloramaOptions(
|
2023-10-31 11:56:55 +00:00
|
|
|
pilorama.WithPath(filepath.Join(p, "pilorama"))),
|
2024-10-14 14:25:00 +00:00
|
|
|
WithMetricsWriter(newMetricStore()),
|
2023-10-31 11:56:55 +00:00
|
|
|
}
|
2022-10-16 11:39:47 +00:00
|
|
|
|
|
|
|
sh := New(opts...)
|
2023-08-31 16:26:47 +00:00
|
|
|
require.NoError(t, sh.Open(context.Background()))
|
2023-03-23 14:59:14 +00:00
|
|
|
require.NoError(t, sh.Init(context.Background()))
|
2022-10-16 11:39:47 +00:00
|
|
|
|
2024-01-09 13:26:43 +00:00
|
|
|
defer func() {
|
2024-10-21 08:56:38 +00:00
|
|
|
require.NoError(t, sh.Close(context.Background()))
|
2024-01-09 13:26:43 +00:00
|
|
|
}()
|
|
|
|
|
2022-10-16 11:39:47 +00:00
|
|
|
objects := make([]objAddr, 5)
|
|
|
|
for i := range objects {
|
|
|
|
objects[i].obj = newObject()
|
|
|
|
objects[i].addr = objectCore.AddressOf(objects[i].obj)
|
|
|
|
require.NoError(t, putObject(sh, objects[i].obj))
|
|
|
|
}
|
|
|
|
|
|
|
|
checkHasObjects := func(t *testing.T, exists bool) {
|
|
|
|
for i := range objects {
|
|
|
|
var prm ExistsPrm
|
2024-05-30 06:26:06 +00:00
|
|
|
prm.Address = objects[i].addr
|
2022-10-16 11:39:47 +00:00
|
|
|
|
2023-03-13 11:37:35 +00:00
|
|
|
res, err := sh.Exists(context.Background(), prm)
|
2022-10-16 11:39:47 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, exists, res.Exists(), "object #%d is missing", i)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
checkHasObjects(t, true)
|
|
|
|
|
|
|
|
t.Run("same config, no-op", func(t *testing.T) {
|
2023-04-12 14:01:29 +00:00
|
|
|
require.NoError(t, sh.Reload(context.Background(), opts...))
|
2022-10-16 11:39:47 +00:00
|
|
|
checkHasObjects(t, true)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("open meta at new path", func(t *testing.T) {
|
|
|
|
newShardOpts := func(metaPath string, resync bool) []Option {
|
|
|
|
metaOpts := []meta.Option{meta.WithPath(metaPath), meta.WithEpochState(epochState{})}
|
|
|
|
return append(opts, WithMetaBaseOptions(metaOpts...), WithRefillMetabase(resync))
|
|
|
|
}
|
|
|
|
|
|
|
|
newOpts := newShardOpts(filepath.Join(p, "meta1"), false)
|
2023-04-12 14:01:29 +00:00
|
|
|
require.NoError(t, sh.Reload(context.Background(), newOpts...))
|
2022-10-16 11:39:47 +00:00
|
|
|
|
|
|
|
checkHasObjects(t, false) // new path, but no resync
|
|
|
|
|
|
|
|
t.Run("can put objects", func(t *testing.T) {
|
|
|
|
obj := newObject()
|
|
|
|
require.NoError(t, putObject(sh, obj))
|
|
|
|
objects = append(objects, objAddr{obj: obj, addr: objectCore.AddressOf(obj)})
|
|
|
|
})
|
|
|
|
|
|
|
|
newOpts = newShardOpts(filepath.Join(p, "meta2"), true)
|
2023-04-12 14:01:29 +00:00
|
|
|
require.NoError(t, sh.Reload(context.Background(), newOpts...))
|
2022-10-16 11:39:47 +00:00
|
|
|
|
|
|
|
checkHasObjects(t, true) // all objects are restored, including the new one
|
|
|
|
|
|
|
|
t.Run("reload failed", func(t *testing.T) {
|
|
|
|
badPath := filepath.Join(p, "meta3")
|
|
|
|
require.NoError(t, os.WriteFile(badPath, []byte{1}, 0))
|
|
|
|
|
|
|
|
newOpts = newShardOpts(badPath, true)
|
2023-04-12 14:01:29 +00:00
|
|
|
require.Error(t, sh.Reload(context.Background(), newOpts...))
|
2022-10-16 11:39:47 +00:00
|
|
|
|
|
|
|
// Cleanup is done, no panic.
|
|
|
|
obj := newObject()
|
|
|
|
require.ErrorIs(t, putObject(sh, obj), ErrReadOnlyMode)
|
|
|
|
|
|
|
|
// Old objects are still accessible.
|
|
|
|
checkHasObjects(t, true)
|
2022-10-16 13:11:29 +00:00
|
|
|
|
|
|
|
// Successive reload produces no undesired effects.
|
|
|
|
require.NoError(t, os.RemoveAll(badPath))
|
2023-04-12 14:01:29 +00:00
|
|
|
require.NoError(t, sh.Reload(context.Background(), newOpts...))
|
2022-10-16 13:11:29 +00:00
|
|
|
|
|
|
|
obj = newObject()
|
|
|
|
require.NoError(t, putObject(sh, obj))
|
|
|
|
|
|
|
|
objects = append(objects, objAddr{obj: obj, addr: objectCore.AddressOf(obj)})
|
|
|
|
checkHasObjects(t, true)
|
2022-10-16 11:39:47 +00:00
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func putObject(sh *Shard, obj *objectSDK.Object) error {
|
|
|
|
var prm PutPrm
|
|
|
|
prm.SetObject(obj)
|
|
|
|
|
2023-04-12 14:01:29 +00:00
|
|
|
_, err := sh.Put(context.Background(), prm)
|
2022-10-16 11:39:47 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func newObject() *objectSDK.Object {
|
|
|
|
x := objectSDK.New()
|
|
|
|
ver := version.Current()
|
|
|
|
|
|
|
|
x.SetID(oidtest.ID())
|
|
|
|
x.SetSessionToken(sessiontest.Object())
|
|
|
|
x.SetPayload([]byte{1, 2, 3})
|
|
|
|
x.SetPayloadSize(3)
|
|
|
|
x.SetOwnerID(usertest.ID())
|
|
|
|
x.SetContainerID(cidtest.ID())
|
|
|
|
x.SetType(objectSDK.TypeRegular)
|
|
|
|
x.SetVersion(&ver)
|
|
|
|
x.SetPayloadChecksum(checksumtest.Checksum())
|
|
|
|
x.SetPayloadHomomorphicHash(checksumtest.Checksum())
|
|
|
|
return x
|
|
|
|
}
|