2022-02-15 11:35:13 +00:00
|
|
|
package meta_test
|
|
|
|
|
|
|
|
import (
|
2023-04-12 14:01:29 +00:00
|
|
|
"context"
|
2022-02-15 11:35:13 +00:00
|
|
|
"testing"
|
|
|
|
|
2023-03-07 13:38:26 +00:00
|
|
|
objectcore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
|
2023-03-20 14:10:26 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
|
2023-03-07 13:38:26 +00:00
|
|
|
meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase"
|
|
|
|
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
|
|
|
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
|
|
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
|
|
|
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
|
|
|
|
objecttest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/test"
|
2022-02-15 11:35:13 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestDB_Lock(t *testing.T) {
|
2023-05-05 14:02:27 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2022-05-12 16:37:46 +00:00
|
|
|
cnr := cidtest.ID()
|
2022-02-15 11:35:13 +00:00
|
|
|
db := newDB(t)
|
|
|
|
|
|
|
|
t.Run("empty locked list", func(t *testing.T) {
|
2023-04-12 14:01:29 +00:00
|
|
|
require.Panics(t, func() { _ = db.Lock(context.Background(), cnr, oid.ID{}, nil) })
|
|
|
|
require.Panics(t, func() { _ = db.Lock(context.Background(), cnr, oid.ID{}, []oid.ID{}) })
|
2022-02-15 11:35:13 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("(ir)regular", func(t *testing.T) {
|
|
|
|
for _, typ := range [...]object.Type{
|
|
|
|
object.TypeTombstone,
|
|
|
|
object.TypeLock,
|
|
|
|
object.TypeRegular,
|
|
|
|
} {
|
2022-03-05 08:49:19 +00:00
|
|
|
obj := objecttest.Object()
|
2022-02-15 11:35:13 +00:00
|
|
|
obj.SetType(typ)
|
2022-05-12 16:37:46 +00:00
|
|
|
obj.SetContainerID(cnr)
|
2022-02-15 11:35:13 +00:00
|
|
|
|
|
|
|
// save irregular object
|
2022-07-12 14:42:55 +00:00
|
|
|
err := metaPut(db, obj, nil)
|
2022-02-15 11:35:13 +00:00
|
|
|
require.NoError(t, err, typ)
|
|
|
|
|
2022-02-16 15:49:19 +00:00
|
|
|
var e apistatus.LockNonRegularObject
|
2022-02-15 22:17:40 +00:00
|
|
|
|
2022-05-12 16:37:46 +00:00
|
|
|
id, _ := obj.ID()
|
|
|
|
|
2022-02-15 11:35:13 +00:00
|
|
|
// try to lock it
|
2023-04-12 14:01:29 +00:00
|
|
|
err = db.Lock(context.Background(), cnr, oidtest.ID(), []oid.ID{id})
|
2022-02-15 11:35:13 +00:00
|
|
|
if typ == object.TypeRegular {
|
|
|
|
require.NoError(t, err, typ)
|
|
|
|
} else {
|
2022-02-15 22:17:40 +00:00
|
|
|
require.ErrorAs(t, err, &e, typ)
|
2022-02-15 11:35:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2022-03-10 17:58:58 +00:00
|
|
|
|
2022-06-06 12:17:21 +00:00
|
|
|
t.Run("removing lock object", func(t *testing.T) {
|
|
|
|
objs, lockObj := putAndLockObj(t, db, 1)
|
2022-03-10 17:58:58 +00:00
|
|
|
|
2022-06-06 12:17:21 +00:00
|
|
|
objAddr := objectcore.AddressOf(objs[0])
|
|
|
|
lockAddr := objectcore.AddressOf(lockObj)
|
2022-03-10 17:58:58 +00:00
|
|
|
|
2022-06-06 12:17:21 +00:00
|
|
|
var inhumePrm meta.InhumePrm
|
2022-07-12 14:59:37 +00:00
|
|
|
inhumePrm.SetGCMark()
|
2022-03-10 17:58:58 +00:00
|
|
|
|
2022-06-06 12:17:21 +00:00
|
|
|
// check locking relation
|
2022-03-10 17:58:58 +00:00
|
|
|
|
2022-07-12 14:59:37 +00:00
|
|
|
inhumePrm.SetAddresses(objAddr)
|
2023-04-12 14:01:29 +00:00
|
|
|
_, err := db.Inhume(context.Background(), inhumePrm)
|
2022-06-06 12:17:21 +00:00
|
|
|
require.ErrorAs(t, err, new(apistatus.ObjectLocked))
|
2022-05-12 16:37:46 +00:00
|
|
|
|
2022-07-12 14:59:37 +00:00
|
|
|
inhumePrm.SetTombstoneAddress(oidtest.Address())
|
2023-04-12 14:01:29 +00:00
|
|
|
_, err = db.Inhume(context.Background(), inhumePrm)
|
2022-06-06 12:17:21 +00:00
|
|
|
require.ErrorAs(t, err, new(apistatus.ObjectLocked))
|
2022-03-10 17:58:58 +00:00
|
|
|
|
2022-06-06 12:17:21 +00:00
|
|
|
// try to remove lock object
|
2022-07-12 14:59:37 +00:00
|
|
|
inhumePrm.SetAddresses(lockAddr)
|
2023-04-12 14:01:29 +00:00
|
|
|
_, err = db.Inhume(context.Background(), inhumePrm)
|
2022-06-06 12:17:21 +00:00
|
|
|
require.Error(t, err)
|
|
|
|
|
|
|
|
// check that locking relation has not been
|
|
|
|
// dropped
|
|
|
|
|
2022-07-12 14:59:37 +00:00
|
|
|
inhumePrm.SetAddresses(objAddr)
|
2023-04-12 14:01:29 +00:00
|
|
|
_, err = db.Inhume(context.Background(), inhumePrm)
|
2022-06-06 12:17:21 +00:00
|
|
|
require.ErrorAs(t, err, new(apistatus.ObjectLocked))
|
2022-03-10 17:58:58 +00:00
|
|
|
|
2022-07-12 14:59:37 +00:00
|
|
|
inhumePrm.SetTombstoneAddress(oidtest.Address())
|
2023-04-12 14:01:29 +00:00
|
|
|
_, err = db.Inhume(context.Background(), inhumePrm)
|
2022-06-06 12:17:21 +00:00
|
|
|
require.ErrorAs(t, err, new(apistatus.ObjectLocked))
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("lock-unlock scenario", func(t *testing.T) {
|
|
|
|
objs, lockObj := putAndLockObj(t, db, 1)
|
|
|
|
|
|
|
|
objAddr := objectcore.AddressOf(objs[0])
|
|
|
|
lockAddr := objectcore.AddressOf(lockObj)
|
2022-03-10 17:58:58 +00:00
|
|
|
|
|
|
|
// try to inhume locked object using tombstone
|
2022-07-12 14:42:55 +00:00
|
|
|
err := metaInhume(db, objAddr, lockAddr)
|
2022-03-10 17:58:58 +00:00
|
|
|
require.ErrorAs(t, err, new(apistatus.ObjectLocked))
|
|
|
|
|
2022-05-26 17:38:32 +00:00
|
|
|
// free locked object
|
2022-05-20 16:48:14 +00:00
|
|
|
var inhumePrm meta.InhumePrm
|
2022-07-12 14:59:37 +00:00
|
|
|
inhumePrm.SetAddresses(lockAddr)
|
|
|
|
inhumePrm.SetForceGCMark()
|
|
|
|
inhumePrm.SetLockObjectHandling()
|
2022-05-20 16:48:14 +00:00
|
|
|
|
2023-04-12 14:01:29 +00:00
|
|
|
res, err := db.Inhume(context.Background(), inhumePrm)
|
2022-03-10 17:58:58 +00:00
|
|
|
require.NoError(t, err)
|
2022-06-06 12:17:21 +00:00
|
|
|
require.Len(t, res.DeletedLockObjects(), 1)
|
|
|
|
require.Equal(t, objectcore.AddressOf(lockObj), res.DeletedLockObjects()[0])
|
2022-05-26 17:38:32 +00:00
|
|
|
|
2023-03-28 08:17:15 +00:00
|
|
|
_, err = db.FreeLockedBy([]oid.Address{lockAddr})
|
2022-05-26 17:38:32 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2022-07-12 14:59:37 +00:00
|
|
|
inhumePrm.SetAddresses(objAddr)
|
|
|
|
inhumePrm.SetGCMark()
|
2022-05-26 17:38:32 +00:00
|
|
|
|
2022-03-10 17:58:58 +00:00
|
|
|
// now we can inhume the object
|
2023-04-12 14:01:29 +00:00
|
|
|
_, err = db.Inhume(context.Background(), inhumePrm)
|
2022-03-10 17:58:58 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
})
|
2022-06-06 12:17:21 +00:00
|
|
|
|
|
|
|
t.Run("force removing lock objects", func(t *testing.T) {
|
|
|
|
const objsNum = 3
|
|
|
|
|
|
|
|
// put and lock `objsNum` objects
|
|
|
|
objs, lockObj := putAndLockObj(t, db, objsNum)
|
|
|
|
|
|
|
|
// force remove objects
|
|
|
|
|
|
|
|
var inhumePrm meta.InhumePrm
|
2022-07-12 14:59:37 +00:00
|
|
|
inhumePrm.SetForceGCMark()
|
|
|
|
inhumePrm.SetAddresses(objectcore.AddressOf(lockObj))
|
|
|
|
inhumePrm.SetLockObjectHandling()
|
2022-06-06 12:17:21 +00:00
|
|
|
|
2023-04-12 14:01:29 +00:00
|
|
|
res, err := db.Inhume(context.Background(), inhumePrm)
|
2022-06-06 12:17:21 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, res.DeletedLockObjects(), 1)
|
|
|
|
require.Equal(t, objectcore.AddressOf(lockObj), res.DeletedLockObjects()[0])
|
|
|
|
|
|
|
|
// unlock just objects that were locked by
|
|
|
|
// just removed locker
|
2023-03-28 08:17:15 +00:00
|
|
|
_, err = db.FreeLockedBy([]oid.Address{res.DeletedLockObjects()[0]})
|
2022-06-06 12:17:21 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// removing objects after unlock
|
|
|
|
|
2022-07-12 14:59:37 +00:00
|
|
|
inhumePrm.SetGCMark()
|
2022-06-06 12:17:21 +00:00
|
|
|
|
|
|
|
for i := 0; i < objsNum; i++ {
|
2022-07-12 14:59:37 +00:00
|
|
|
inhumePrm.SetAddresses(objectcore.AddressOf(objs[i]))
|
2022-06-06 12:17:21 +00:00
|
|
|
|
2023-04-12 14:01:29 +00:00
|
|
|
res, err = db.Inhume(context.Background(), inhumePrm)
|
2022-06-06 12:17:21 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, res.DeletedLockObjects(), 0)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("skipping lock object handling", func(t *testing.T) {
|
|
|
|
_, lockObj := putAndLockObj(t, db, 1)
|
|
|
|
|
|
|
|
var inhumePrm meta.InhumePrm
|
2022-07-12 14:59:37 +00:00
|
|
|
inhumePrm.SetForceGCMark()
|
|
|
|
inhumePrm.SetAddresses(objectcore.AddressOf(lockObj))
|
2022-06-06 12:17:21 +00:00
|
|
|
|
2023-04-12 14:01:29 +00:00
|
|
|
res, err := db.Inhume(context.Background(), inhumePrm)
|
2022-06-06 12:17:21 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, res.DeletedLockObjects(), 0)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-01-30 10:23:44 +00:00
|
|
|
func TestDB_Lock_Expired(t *testing.T) {
|
2023-05-05 14:02:27 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2023-01-30 10:23:44 +00:00
|
|
|
es := &epochState{e: 123}
|
|
|
|
|
|
|
|
db := newDB(t, meta.WithEpochState(es))
|
|
|
|
|
|
|
|
// put an object
|
|
|
|
addr := putWithExpiration(t, db, object.TypeRegular, 124)
|
|
|
|
|
|
|
|
// expire the obj
|
|
|
|
es.e = 125
|
|
|
|
_, err := metaGet(db, addr, false)
|
|
|
|
require.ErrorIs(t, err, meta.ErrObjectIsExpired)
|
|
|
|
|
|
|
|
// lock the obj
|
2023-04-12 14:01:29 +00:00
|
|
|
require.NoError(t, db.Lock(context.Background(), addr.Container(), oidtest.ID(), []oid.ID{addr.Object()}))
|
2023-01-30 10:23:44 +00:00
|
|
|
|
|
|
|
// object is expired but locked, thus, must be available
|
|
|
|
_, err = metaGet(db, addr, false)
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
2022-11-12 11:46:44 +00:00
|
|
|
func TestDB_IsLocked(t *testing.T) {
|
2023-05-05 14:02:27 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2022-11-12 11:46:44 +00:00
|
|
|
db := newDB(t)
|
|
|
|
|
|
|
|
// existing and locked objs
|
|
|
|
|
|
|
|
objs, _ := putAndLockObj(t, db, 5)
|
|
|
|
var prm meta.IsLockedPrm
|
|
|
|
|
|
|
|
for _, obj := range objs {
|
|
|
|
prm.SetAddress(objectcore.AddressOf(obj))
|
|
|
|
|
2023-04-12 14:01:29 +00:00
|
|
|
res, err := db.IsLocked(context.Background(), prm)
|
2022-11-12 11:46:44 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.True(t, res.Locked())
|
|
|
|
}
|
|
|
|
|
|
|
|
// some rand obj
|
|
|
|
|
|
|
|
prm.SetAddress(oidtest.Address())
|
|
|
|
|
2023-04-12 14:01:29 +00:00
|
|
|
res, err := db.IsLocked(context.Background(), prm)
|
2022-11-12 11:46:44 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.False(t, res.Locked())
|
|
|
|
|
|
|
|
// existing but not locked obj
|
|
|
|
|
|
|
|
obj := objecttest.Object()
|
|
|
|
|
|
|
|
var putPrm meta.PutPrm
|
|
|
|
putPrm.SetObject(obj)
|
|
|
|
|
2023-04-12 14:01:29 +00:00
|
|
|
_, err = db.Put(context.Background(), putPrm)
|
2022-11-12 11:46:44 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
prm.SetAddress(objectcore.AddressOf(obj))
|
|
|
|
|
2023-04-12 14:01:29 +00:00
|
|
|
res, err = db.IsLocked(context.Background(), prm)
|
2022-11-12 11:46:44 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.False(t, res.Locked())
|
|
|
|
}
|
|
|
|
|
2022-06-06 12:17:21 +00:00
|
|
|
// putAndLockObj puts object, returns it and its locker.
|
|
|
|
func putAndLockObj(t *testing.T, db *meta.DB, numOfLockedObjs int) ([]*object.Object, *object.Object) {
|
|
|
|
cnr := cidtest.ID()
|
|
|
|
|
|
|
|
lockedObjs := make([]*object.Object, 0, numOfLockedObjs)
|
|
|
|
lockedObjIDs := make([]oid.ID, 0, numOfLockedObjs)
|
|
|
|
|
|
|
|
for i := 0; i < numOfLockedObjs; i++ {
|
2023-03-20 14:10:26 +00:00
|
|
|
obj := testutil.GenerateObjectWithCID(cnr)
|
2022-06-06 12:17:21 +00:00
|
|
|
err := putBig(db, obj)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
id, _ := obj.ID()
|
|
|
|
|
|
|
|
lockedObjs = append(lockedObjs, obj)
|
|
|
|
lockedObjIDs = append(lockedObjIDs, id)
|
|
|
|
}
|
|
|
|
|
2023-03-20 14:10:26 +00:00
|
|
|
lockObj := testutil.GenerateObjectWithCID(cnr)
|
2022-06-06 12:17:21 +00:00
|
|
|
lockID, _ := lockObj.ID()
|
|
|
|
lockObj.SetType(object.TypeLock)
|
|
|
|
|
|
|
|
err := putBig(db, lockObj)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2023-04-12 14:01:29 +00:00
|
|
|
err = db.Lock(context.Background(), cnr, lockID, lockedObjIDs)
|
2022-06-06 12:17:21 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
return lockedObjs, lockObj
|
2022-02-15 11:35:13 +00:00
|
|
|
}
|