forked from TrueCloudLab/frostfs-node
Aleksey Savchuk
432042c534
Currently, it's allowed to inhume or lock an expired object. Consider the following scenario: 1) An user inhumes or locks an object 2) The object expires 3) GC hasn't yet deleted the object 4) The node loses the associated tombstone or lock 5) Another node replicates tombstone or lock to the first node In this case, the second node succeeds, which is the desired behavior. Signed-off-by: Aleksey Savchuk <a.savchuk@yadro.com>
139 lines
3.9 KiB
Go
139 lines
3.9 KiB
Go
package engine
|
|
|
|
import (
|
|
"context"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"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"
|
|
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object"
|
|
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"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestStorageEngine_Inhume(t *testing.T) {
|
|
cnr := cidtest.ID()
|
|
splitID := objectSDK.NewSplitID()
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddRootFilter()
|
|
|
|
tombstoneID := object.AddressOf(testutil.GenerateObjectWithCID(cnr))
|
|
parent := testutil.GenerateObjectWithCID(cnr)
|
|
|
|
child := testutil.GenerateObjectWithCID(cnr)
|
|
child.SetParent(parent)
|
|
idParent, _ := parent.ID()
|
|
child.SetParentID(idParent)
|
|
child.SetSplitID(splitID)
|
|
|
|
link := testutil.GenerateObjectWithCID(cnr)
|
|
link.SetParent(parent)
|
|
link.SetParentID(idParent)
|
|
idChild, _ := child.ID()
|
|
link.SetChildren(idChild)
|
|
link.SetSplitID(splitID)
|
|
|
|
t.Run("delete small object", func(t *testing.T) {
|
|
t.Parallel()
|
|
e := testNewEngine(t).setShardsNum(t, 1).prepare(t).engine
|
|
defer func() { require.NoError(t, e.Close(context.Background())) }()
|
|
|
|
err := Put(context.Background(), e, parent, false)
|
|
require.NoError(t, err)
|
|
|
|
var inhumePrm InhumePrm
|
|
inhumePrm.WithTarget(tombstoneID, object.AddressOf(parent))
|
|
|
|
_, err = e.Inhume(context.Background(), inhumePrm)
|
|
require.NoError(t, err)
|
|
|
|
addrs, err := Select(context.Background(), e, cnr, false, fs)
|
|
require.NoError(t, err)
|
|
require.Empty(t, addrs)
|
|
})
|
|
|
|
t.Run("delete big object", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
te := testNewEngine(t).setShardsNum(t, 2).prepare(t)
|
|
e := te.engine
|
|
defer func() { require.NoError(t, e.Close(context.Background())) }()
|
|
|
|
s1, s2 := te.shards[0], te.shards[1]
|
|
|
|
var putChild shard.PutPrm
|
|
putChild.SetObject(child)
|
|
_, err := s1.Put(context.Background(), putChild)
|
|
require.NoError(t, err)
|
|
|
|
var putLink shard.PutPrm
|
|
putLink.SetObject(link)
|
|
_, err = s2.Put(context.Background(), putLink)
|
|
require.NoError(t, err)
|
|
|
|
var inhumePrm InhumePrm
|
|
inhumePrm.WithTarget(tombstoneID, object.AddressOf(parent))
|
|
|
|
_, err = e.Inhume(context.Background(), inhumePrm)
|
|
require.NoError(t, err)
|
|
|
|
addrs, err := Select(context.Background(), e, cnr, false, fs)
|
|
require.NoError(t, err)
|
|
require.Empty(t, addrs)
|
|
})
|
|
}
|
|
|
|
func TestInhumeExpiredRegularObject(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const currEpoch = 42
|
|
const objectExpiresAfter = currEpoch - 1
|
|
|
|
engine := testNewEngine(t).setShardsNumAdditionalOpts(t, 1, func(_ int) []shard.Option {
|
|
return []shard.Option{
|
|
shard.WithDisabledGC(),
|
|
shard.WithMetaBaseOptions(append(
|
|
testGetDefaultMetabaseOptions(t),
|
|
meta.WithEpochState(epochState{currEpoch}),
|
|
)...),
|
|
}
|
|
}).prepare(t).engine
|
|
|
|
cnr := cidtest.ID()
|
|
|
|
generateAndPutObject := func() *objectSDK.Object {
|
|
obj := testutil.GenerateObjectWithCID(cnr)
|
|
testutil.AddAttribute(obj, objectV2.SysAttributeExpEpoch, strconv.Itoa(objectExpiresAfter))
|
|
|
|
var putPrm PutPrm
|
|
putPrm.Object = obj
|
|
require.NoError(t, engine.Put(context.Background(), putPrm))
|
|
return obj
|
|
}
|
|
|
|
t.Run("inhume with tombstone", func(t *testing.T) {
|
|
obj := generateAndPutObject()
|
|
ts := oidtest.Address()
|
|
ts.SetContainer(cnr)
|
|
|
|
var prm InhumePrm
|
|
prm.WithTarget(ts, object.AddressOf(obj))
|
|
_, err := engine.Inhume(context.Background(), prm)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("inhume without tombstone", func(t *testing.T) {
|
|
obj := generateAndPutObject()
|
|
|
|
var prm InhumePrm
|
|
prm.MarkAsGarbage(object.AddressOf(obj))
|
|
_, err := engine.Inhume(context.Background(), prm)
|
|
require.NoError(t, err)
|
|
})
|
|
}
|