From 3d23b08773cdb440d9082a035934299af66ce293 Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Mon, 17 Apr 2023 20:24:12 +0300 Subject: [PATCH] [#262] meta: Do not return old expired objects Signed-off-by: Pavel Karpy --- CHANGELOG.md | 1 + pkg/local_object_storage/metabase/db_test.go | 7 ++++++ pkg/local_object_storage/metabase/get.go | 13 +++++++++- pkg/local_object_storage/metabase/util.go | 25 ++++++++++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94018e357..738fb38e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Changelog for FrostFS Node ### Fixed - Take network settings into account during netmap contract update (#100) - Read config files from dir even if config file not provided via `--config` for node (#238) +- Expired by more than 1 epoch objects could be returned (#262) ### Removed ### Updated diff --git a/pkg/local_object_storage/metabase/db_test.go b/pkg/local_object_storage/metabase/db_test.go index 9ef7bf8bc..a3b26da79 100644 --- a/pkg/local_object_storage/metabase/db_test.go +++ b/pkg/local_object_storage/metabase/db_test.go @@ -73,6 +73,13 @@ func checkExpiredObjects(t *testing.T, db *meta.DB, f func(exp, nonExp *objectSD require.NoError(t, metaPut(db, nonExpObj, nil)) f(expObj, nonExpObj) + + oldExpObj := testutil.GenerateObject() + setExpiration(oldExpObj, 1) + + require.NoError(t, metaPut(db, oldExpObj, nil)) + + f(oldExpObj, nonExpObj) } func setExpiration(o *objectSDK.Object, epoch uint64) { diff --git a/pkg/local_object_storage/metabase/get.go b/pkg/local_object_storage/metabase/get.go index fff32d6ad..c3a5880bf 100644 --- a/pkg/local_object_storage/metabase/get.go +++ b/pkg/local_object_storage/metabase/get.go @@ -66,13 +66,24 @@ func (db *DB) Get(ctx context.Context, prm GetPrm) (res GetRes, err error) { } currEpoch := db.epochState.CurrentEpoch() + var obj *objectSDK.Object err = db.boltDB.View(func(tx *bbolt.Tx) error { key := make([]byte, addressKeySize) - res.hdr, err = db.get(tx, prm.addr, key, true, prm.raw, currEpoch) + obj, err = db.get(tx, prm.addr, key, true, prm.raw, currEpoch) return err }) + if err != nil { + return + } + + err = validate(obj, currEpoch) + if err != nil { + return + } + + res.hdr = obj return } diff --git a/pkg/local_object_storage/metabase/util.go b/pkg/local_object_storage/metabase/util.go index b60c97fd7..d4c93c750 100644 --- a/pkg/local_object_storage/metabase/util.go +++ b/pkg/local_object_storage/metabase/util.go @@ -4,7 +4,9 @@ import ( "bytes" "crypto/sha256" "fmt" + "strconv" + objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" @@ -259,3 +261,26 @@ func isLockObject(tx *bbolt.Tx, idCnr cid.ID, obj oid.ID) bool { bucketNameLockers(idCnr, make([]byte, bucketKeySize)), objectKey(obj, make([]byte, objectKeySize))) } + +// performs object validity checks. +func validate(obj *object.Object, currEpoch uint64) error { + for _, a := range obj.Attributes() { + if key := a.Key(); key != objectV2.SysAttributeExpEpoch && key != objectV2.SysAttributeExpEpochNeoFS { + continue + } + + expEpoch, err := strconv.ParseUint(a.Value(), 10, 64) + if err != nil { + // unexpected for already stored and valudated objects + return fmt.Errorf("expiration epoch parsing: %w", err) + } + + if expEpoch < currEpoch { + return ErrObjectIsExpired + } + + break + } + + return nil +}