Since the GC behavior is changing drastically. This test is needed to ensure that the GC correctly deletes expired tombstones and graves. The test uses graves of both old and new formats. Signed-off-by: Aleksey Savchuk <a.savchuk@yadro.com>
111 lines
3.5 KiB
Go
111 lines
3.5 KiB
Go
package engine
|
|
|
|
import (
|
|
"context"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
objectCore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
|
|
meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util"
|
|
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
|
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/panjf2000/ants/v2"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func testPopulateWithObjects(t testing.TB, engine *StorageEngine, cnt cid.ID, objectCount int) (objects []*objectSDK.Object) {
|
|
require.Positive(t, objectCount)
|
|
|
|
var putPrm PutPrm
|
|
for range objectCount {
|
|
putPrm.Object = testutil.GenerateObjectWithCID(cnt)
|
|
require.NoError(t, engine.Put(context.Background(), putPrm))
|
|
objects = append(objects, putPrm.Object)
|
|
}
|
|
return objects
|
|
}
|
|
|
|
func testInhumeObjects(t testing.TB, engine *StorageEngine, objects []*objectSDK.Object, expEpoch uint64) (tombstone *objectSDK.Object) {
|
|
require.NotEmpty(t, objects)
|
|
cnt := objectCore.AddressOf(objects[0]).Container()
|
|
|
|
tombstone = testutil.GenerateObjectWithCID(cnt)
|
|
tombstone.SetType(objectSDK.TypeTombstone)
|
|
testutil.AddAttribute(tombstone, objectV2.SysAttributeExpEpoch, strconv.FormatUint(expEpoch, 10))
|
|
|
|
var putPrm PutPrm
|
|
putPrm.Object = tombstone
|
|
require.NoError(t, engine.Put(context.Background(), putPrm))
|
|
|
|
var addrs []oid.Address
|
|
for _, object := range objects {
|
|
addrs = append(addrs, objectCore.AddressOf(object))
|
|
}
|
|
tombstoneAddr := objectCore.AddressOf(tombstone)
|
|
|
|
pivot := len(objects) / 2
|
|
|
|
var inhumePrm InhumePrm
|
|
inhumePrm.WithTarget(tombstoneAddr, expEpoch, addrs[:pivot]...)
|
|
err := engine.Inhume(context.Background(), inhumePrm)
|
|
require.NoError(t, err)
|
|
|
|
inhumePrm.WithTarget(tombstoneAddr, meta.NoExpirationEpoch, addrs[pivot:]...)
|
|
err = engine.Inhume(context.Background(), inhumePrm)
|
|
require.NoError(t, err)
|
|
|
|
return
|
|
}
|
|
|
|
func TestGCHandleExpiredTombstones(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const (
|
|
numShards = 2
|
|
objectCount = 10 * numShards
|
|
expEpoch = 1
|
|
)
|
|
|
|
container := cidtest.ID()
|
|
|
|
engine := testNewEngine(t).
|
|
setShardsNumAdditionalOpts(t, numShards, func(_ int) []shard.Option {
|
|
return []shard.Option{
|
|
shard.WithGCWorkerPoolInitializer(func(sz int) util.WorkerPool {
|
|
pool, err := ants.NewPool(sz)
|
|
require.NoError(t, err)
|
|
return pool
|
|
}),
|
|
shard.WithTombstoneSource(tss{expEpoch}),
|
|
}
|
|
}).prepare(t).engine
|
|
defer func() { require.NoError(t, engine.Close(context.Background())) }()
|
|
|
|
objects := testPopulateWithObjects(t, engine, container, objectCount)
|
|
tombstone := testInhumeObjects(t, engine, objects, expEpoch)
|
|
|
|
engine.HandleNewEpoch(context.Background(), expEpoch+1)
|
|
|
|
var headPrm HeadPrm
|
|
require.Eventually(t, func() bool {
|
|
for _, object := range objects {
|
|
headPrm.WithAddress(objectCore.AddressOf(object))
|
|
_, err := engine.Head(context.Background(), headPrm)
|
|
if !client.IsErrObjectNotFound(err) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
headPrm.WithAddress(objectCore.AddressOf(tombstone))
|
|
_, err := engine.Head(context.Background(), headPrm)
|
|
return client.IsErrObjectNotFound(err)
|
|
}, 10*time.Second, 1*time.Second)
|
|
}
|