forked from TrueCloudLab/frostfs-node
222 lines
8 KiB
Go
222 lines
8 KiB
Go
//go:build integration
|
|
|
|
package meta
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
|
|
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object"
|
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
|
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
|
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
|
"github.com/stretchr/testify/require"
|
|
"golang.org/x/sync/errgroup"
|
|
)
|
|
|
|
const upgradeFilePath = "/path/to/metabase.v2"
|
|
|
|
func TestUpgradeV2ToV3(t *testing.T) {
|
|
path := createTempCopy(t, upgradeFilePath)
|
|
defer func() {
|
|
require.NoError(t, os.Remove(path))
|
|
}()
|
|
db := New(WithPath(path), WithEpochState(epochState{e: 1000}), WithLogger(test.NewLogger(t)))
|
|
require.NoError(t, db.Open(context.Background(), mode.ReadWrite))
|
|
require.ErrorIs(t, db.Init(context.Background()), ErrOutdatedVersion)
|
|
require.NoError(t, db.Close(context.Background()))
|
|
require.NoError(t, Upgrade(context.Background(), path, true, &testContainerInfoProvider{}, t.Log))
|
|
require.NoError(t, db.Open(context.Background(), mode.ReadWrite))
|
|
require.NoError(t, db.Init(context.Background()))
|
|
require.NoError(t, db.Close(context.Background()))
|
|
fmt.Println()
|
|
}
|
|
|
|
type testContainerInfoProvider struct{}
|
|
|
|
func (p *testContainerInfoProvider) Info(id cid.ID) (container.Info, error) {
|
|
return container.Info{}, nil
|
|
}
|
|
|
|
func createTempCopy(t *testing.T, path string) string {
|
|
src, err := os.Open(path)
|
|
require.NoError(t, err)
|
|
|
|
tmpPath := upgradeFilePath + time.Now().Format(time.RFC3339)
|
|
dest, err := os.Create(tmpPath)
|
|
require.NoError(t, err)
|
|
|
|
_, err = io.Copy(dest, src)
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, src.Close())
|
|
require.NoError(t, dest.Close())
|
|
|
|
return tmpPath
|
|
}
|
|
|
|
func TestGenerateMetabaseFile(t *testing.T) {
|
|
t.Skip("for generating db")
|
|
const (
|
|
containersCount = 10_000
|
|
simpleObjectsCount = 500_000
|
|
complexObjectsCount = 500_000 // x2
|
|
deletedByGCMarksCount = 100_000
|
|
deletedByTombstoneCount = 100_000 // x2
|
|
lockedCount = 100_000 // x2
|
|
|
|
allocSize = 128 << 20
|
|
generateWorkersCount = 1_000
|
|
minEpoch = 1_000
|
|
maxFilename = 1_000
|
|
maxStorageID = 10_000
|
|
)
|
|
|
|
db := New(WithPath(upgradeFilePath), WithEpochState(epochState{e: minEpoch}), WithLogger(test.NewLogger(t)))
|
|
require.NoError(t, db.Open(context.Background(), mode.ReadWrite))
|
|
db.boltDB.AllocSize = allocSize
|
|
db.boltDB.NoSync = true
|
|
require.NoError(t, db.Init(context.Background()))
|
|
containers := make([]cid.ID, containersCount)
|
|
for i := range containers {
|
|
containers[i] = cidtest.ID()
|
|
}
|
|
oc, err := db.ObjectCounters()
|
|
require.NoError(t, err)
|
|
require.True(t, oc.IsZero())
|
|
eg, ctx := errgroup.WithContext(context.Background())
|
|
eg.SetLimit(generateWorkersCount)
|
|
// simple objects
|
|
for i := range simpleObjectsCount {
|
|
i := i
|
|
eg.Go(func() error {
|
|
obj := testutil.GenerateObjectWithCID(containers[i%len(containers)])
|
|
testutil.AddAttribute(obj, objectSDK.AttributeFilePath, strconv.FormatInt(int64(i%maxFilename), 10))
|
|
testutil.AddAttribute(obj, objectV2.SysAttributeExpEpoch, strconv.FormatUint(uint64(i%minEpoch+minEpoch), 10))
|
|
_, err := db.Put(ctx, PutPrm{
|
|
obj: obj,
|
|
id: []byte(strconv.FormatInt(int64(i%maxStorageID), 10) + "/" + strconv.FormatInt(int64(i%maxStorageID), 10)),
|
|
})
|
|
require.NoError(t, err)
|
|
return nil
|
|
})
|
|
}
|
|
require.NoError(t, eg.Wait())
|
|
db.log.Info(ctx, "simple objects generated")
|
|
eg, ctx = errgroup.WithContext(context.Background())
|
|
eg.SetLimit(generateWorkersCount)
|
|
// complex objects
|
|
for i := range complexObjectsCount {
|
|
i := i
|
|
eg.Go(func() error {
|
|
parent := testutil.GenerateObjectWithCID(containers[i%len(containers)])
|
|
child := testutil.GenerateObjectWithCID(containers[i%len(containers)])
|
|
child.SetParent(parent)
|
|
idParent, _ := parent.ID()
|
|
child.SetParentID(idParent)
|
|
testutil.AddAttribute(child, objectSDK.AttributeFilePath, strconv.FormatInt(int64(i%maxFilename), 10))
|
|
testutil.AddAttribute(parent, objectSDK.AttributeFilePath, strconv.FormatInt(int64(i%maxFilename), 10))
|
|
testutil.AddAttribute(child, objectV2.SysAttributeExpEpoch, strconv.FormatUint(uint64(i%minEpoch+minEpoch), 10))
|
|
testutil.AddAttribute(parent, objectV2.SysAttributeExpEpoch, strconv.FormatUint(uint64(i%minEpoch+minEpoch), 10))
|
|
_, err := db.Put(ctx, PutPrm{
|
|
obj: child,
|
|
})
|
|
require.NoError(t, err)
|
|
return nil
|
|
})
|
|
}
|
|
require.NoError(t, eg.Wait())
|
|
db.log.Info(ctx, "complex objects generated")
|
|
eg, ctx = errgroup.WithContext(context.Background())
|
|
eg.SetLimit(generateWorkersCount)
|
|
// simple objects deleted by gc marks
|
|
for i := range deletedByGCMarksCount {
|
|
i := i
|
|
eg.Go(func() error {
|
|
obj := testutil.GenerateObjectWithCID(containers[i%len(containers)])
|
|
testutil.AddAttribute(obj, objectSDK.AttributeFilePath, strconv.FormatInt(int64(i%maxFilename), 10))
|
|
_, err := db.Put(ctx, PutPrm{
|
|
obj: obj,
|
|
id: []byte(strconv.FormatInt(int64(i%maxStorageID), 10) + "/" + strconv.FormatInt(int64(i%maxStorageID), 10)),
|
|
})
|
|
require.NoError(t, err)
|
|
_, err = db.Inhume(ctx, InhumePrm{
|
|
target: []oid.Address{object.AddressOf(obj)},
|
|
})
|
|
require.NoError(t, err)
|
|
return nil
|
|
})
|
|
}
|
|
require.NoError(t, eg.Wait())
|
|
db.log.Info(ctx, "simple objects deleted by gc marks generated")
|
|
eg, ctx = errgroup.WithContext(context.Background())
|
|
eg.SetLimit(10000)
|
|
// simple objects deleted by tombstones
|
|
for i := range deletedByTombstoneCount {
|
|
i := i
|
|
eg.Go(func() error {
|
|
obj := testutil.GenerateObjectWithCID(containers[i%len(containers)])
|
|
testutil.AddAttribute(obj, objectSDK.AttributeFilePath, strconv.FormatInt(int64(i%maxFilename), 10))
|
|
_, err := db.Put(ctx, PutPrm{
|
|
obj: obj,
|
|
id: []byte(strconv.FormatInt(int64(i%maxStorageID), 10) + "/" + strconv.FormatInt(int64(i%maxStorageID), 10)),
|
|
})
|
|
tomb := testutil.GenerateObjectWithCID(containers[i%len(containers)])
|
|
tomb.SetType(objectSDK.TypeTombstone)
|
|
_, err = db.Put(ctx, PutPrm{
|
|
obj: tomb,
|
|
id: []byte(strconv.FormatInt(int64(i%maxStorageID), 10) + "/" + strconv.FormatInt(int64(i%maxStorageID), 10)),
|
|
})
|
|
require.NoError(t, err)
|
|
tombAddr := object.AddressOf(tomb)
|
|
_, err = db.Inhume(ctx, InhumePrm{
|
|
target: []oid.Address{object.AddressOf(obj)},
|
|
tomb: &tombAddr,
|
|
})
|
|
require.NoError(t, err)
|
|
return nil
|
|
})
|
|
}
|
|
require.NoError(t, eg.Wait())
|
|
db.log.Info(ctx, "simple objects deleted by tombstones generated")
|
|
eg, ctx = errgroup.WithContext(context.Background())
|
|
eg.SetLimit(generateWorkersCount)
|
|
// simple objects locked by locks
|
|
for i := range lockedCount {
|
|
i := i
|
|
eg.Go(func() error {
|
|
obj := testutil.GenerateObjectWithCID(containers[i%len(containers)])
|
|
testutil.AddAttribute(obj, objectSDK.AttributeFilePath, strconv.FormatInt(int64(i%maxFilename), 10))
|
|
_, err := db.Put(ctx, PutPrm{
|
|
obj: obj,
|
|
id: []byte(strconv.FormatInt(int64(i%maxStorageID), 10) + "/" + strconv.FormatInt(int64(i%maxStorageID), 10)),
|
|
})
|
|
lock := testutil.GenerateObjectWithCID(containers[i%len(containers)])
|
|
lock.SetType(objectSDK.TypeLock)
|
|
testutil.AddAttribute(lock, objectV2.SysAttributeExpEpoch, strconv.FormatUint(uint64(i%minEpoch+minEpoch), 10))
|
|
_, err = db.Put(ctx, PutPrm{
|
|
obj: lock,
|
|
id: []byte(strconv.FormatInt(int64(i%maxStorageID), 10) + "/" + strconv.FormatInt(int64(i%maxStorageID), 10)),
|
|
})
|
|
require.NoError(t, err)
|
|
err = db.Lock(ctx, containers[i%len(containers)], object.AddressOf(lock).Object(), []oid.ID{object.AddressOf(obj).Object()})
|
|
require.NoError(t, err)
|
|
return nil
|
|
})
|
|
}
|
|
require.NoError(t, eg.Wait())
|
|
db.log.Info(ctx, "simple objects locked by locks generated")
|
|
require.NoError(t, db.boltDB.Sync())
|
|
require.NoError(t, db.Close(context.Background()))
|
|
}
|