[#1445] engine/test: Add test for GC handling of expired tombstones

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>
This commit is contained in:
Aleksey Savchuk 2024-12-19 13:47:31 +03:00
parent e119f35827
commit cee94aae33
Signed by: a-savchuk
GPG key ID: 70C0A7FF6F9C4639

View file

@ -0,0 +1,111 @@
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)
}