From 7d0d781db1b1d674b319a012d653f2bb510f82ca Mon Sep 17 00:00:00 2001 From: Dmitrii Stepanov Date: Tue, 20 Aug 2024 12:59:59 +0300 Subject: [PATCH] [#1323] metabase: Drop user attribute index Signed-off-by: Dmitrii Stepanov --- pkg/local_object_storage/metabase/delete.go | 20 --- pkg/local_object_storage/metabase/put.go | 49 ------- pkg/local_object_storage/metabase/select.go | 151 +++++--------------- pkg/local_object_storage/metabase/util.go | 11 +- 4 files changed, 38 insertions(+), 193 deletions(-) diff --git a/pkg/local_object_storage/metabase/delete.go b/pkg/local_object_storage/metabase/delete.go index 683bd445..00c8d06e 100644 --- a/pkg/local_object_storage/metabase/delete.go +++ b/pkg/local_object_storage/metabase/delete.go @@ -341,11 +341,6 @@ func (db *DB) deleteObject( return fmt.Errorf("can't remove list indexes: %w", err) } - err = updateFKBTIndexes(tx, obj, delFKBTIndexItem) - if err != nil { - return fmt.Errorf("can't remove fake bucket tree indexes: %w", err) - } - if isParent { // remove record from the garbage bucket, because regular object deletion does nothing for virtual object garbageBKT := tx.Bucket(garbageBucketName) @@ -386,21 +381,6 @@ func delUniqueIndexItem(tx *bbolt.Tx, item namedBucketItem) { } } -func delFKBTIndexItem(tx *bbolt.Tx, item namedBucketItem) error { - bkt := tx.Bucket(item.name) - if bkt == nil { - return nil - } - - fkbtRoot := bkt.Bucket(item.key) - if fkbtRoot == nil { - return nil - } - - _ = fkbtRoot.Delete(item.val) // ignore error, best effort there - return nil -} - func delListIndexItem(tx *bbolt.Tx, item namedBucketItem) error { bkt := tx.Bucket(item.name) if bkt == nil { diff --git a/pkg/local_object_storage/metabase/put.go b/pkg/local_object_storage/metabase/put.go index 015f87f9..ff79a038 100644 --- a/pkg/local_object_storage/metabase/put.go +++ b/pkg/local_object_storage/metabase/put.go @@ -175,11 +175,6 @@ func (db *DB) insertObject(tx *bbolt.Tx, obj *objectSDK.Object, id []byte, si *o return fmt.Errorf("can't put list indexes: %w", err) } - err = updateFKBTIndexes(tx, obj, putFKBTIndexItem) - if err != nil { - return fmt.Errorf("can't put fake bucket tree indexes: %w", err) - } - // update container volume size estimation if obj.Type() == objectSDK.TypeRegular && !isParent { err = changeContainerSize(tx, cnr, obj.PayloadSize(), true) @@ -404,36 +399,6 @@ func hasExpirationEpoch(obj *objectSDK.Object) (uint64, bool) { return 0, false } -func updateFKBTIndexes(tx *bbolt.Tx, obj *objectSDK.Object, f updateIndexItemFunc) error { - id, _ := obj.ID() - cnr, _ := obj.ContainerID() - objKey := objectKey(id, make([]byte, objectKeySize)) - - key := make([]byte, bucketKeySize) - var attrs []objectSDK.Attribute - if obj.ECHeader() != nil { - attrs = obj.ECHeader().ParentAttributes() - objKey = objectKey(obj.ECHeader().Parent(), make([]byte, objectKeySize)) - } else { - attrs = obj.Attributes() - } - - // user specified attributes - for i := range attrs { - key = attributeBucketName(cnr, attrs[i].Key(), key) - err := f(tx, namedBucketItem{ - name: key, - key: []byte(attrs[i].Value()), - val: objKey, - }) - if err != nil { - return err - } - } - - return nil -} - type bucketContainer interface { Bucket([]byte) *bbolt.Bucket CreateBucket([]byte) (*bbolt.Bucket, error) @@ -464,20 +429,6 @@ func putUniqueIndexItem(tx *bbolt.Tx, item namedBucketItem) error { return updateUniqueIndexItem(tx, item, func(_, val []byte) ([]byte, error) { return val, nil }) } -func putFKBTIndexItem(tx *bbolt.Tx, item namedBucketItem) error { - bkt, err := createBucketLikelyExists(tx, item.name) - if err != nil { - return fmt.Errorf("can't create index %v: %w", item.name, err) - } - - fkbtRoot, err := createBucketLikelyExists(bkt, item.key) - if err != nil { - return fmt.Errorf("can't create fake bucket tree index %v: %w", item.key, err) - } - - return fkbtRoot.Put(item.val, zeroValue) -} - func putListIndexItem(tx *bbolt.Tx, item namedBucketItem) error { bkt, err := createBucketLikelyExists(tx, item.name) if err != nil { diff --git a/pkg/local_object_storage/metabase/select.go b/pkg/local_object_storage/metabase/select.go index 42737a41..1863fc25 100644 --- a/pkg/local_object_storage/metabase/select.go +++ b/pkg/local_object_storage/metabase/select.go @@ -198,9 +198,6 @@ func (db *DB) selectFastFilter( switch f.Header() { case v2object.FilterHeaderObjectID: db.selectObjectID(tx, f, cnr, to, fNum, currEpoch) - case v2object.FilterHeaderOwnerID, - v2object.FilterHeaderPayloadHash: - return // moved to slow filters case v2object.FilterHeaderObjectType: for _, bucketName := range bucketNamesForType(cnr, f.Operation(), f.Value()) { selectAllFromBucket(tx, bucketName, to, fNum) @@ -220,14 +217,7 @@ func (db *DB) selectFastFilter( selectAllFromBucket(tx, primaryBucketName(cnr, bucketName), to, fNum) selectAllFromBucket(tx, tombstoneBucketName(cnr, bucketName), to, fNum) selectAllFromBucket(tx, bucketNameLockers(cnr, bucketName), to, fNum) - default: // user attribute - bucketName := attributeBucketName(cnr, f.Header(), bucketName) - - if f.Operation() == objectSDK.MatchNotPresent { - selectOutsideFKBT(tx, allBucketNames(cnr), bucketName, to, fNum) - } else { - db.selectFromFKBT(tx, bucketName, f, to, fNum) - } + default: } } @@ -237,16 +227,6 @@ var mBucketNaming = map[string][]func(cid.ID, []byte) []byte{ v2object.TypeLock.String(): {bucketNameLockers}, } -func allBucketNames(cnr cid.ID) (names [][]byte) { - for _, fns := range mBucketNaming { - for _, fn := range fns { - names = append(names, fn(cnr, make([]byte, bucketKeySize))) - } - } - - return -} - func bucketNamesForType(cnr cid.ID, mType objectSDK.SearchMatchType, typeVal string) (names [][]byte) { appendNames := func(key string) { fns, ok := mBucketNaming[key] @@ -278,83 +258,6 @@ func bucketNamesForType(cnr cid.ID, mType objectSDK.SearchMatchType, typeVal str return } -// selectFromList looks into index to find list of addresses to add in -// resulting cache. -func (db *DB) selectFromFKBT( - tx *bbolt.Tx, - name []byte, // fkbt root bucket name - f objectSDK.SearchFilter, // filter for operation and value - to map[string]int, // resulting cache - fNum int, // index of filter -) { // - matchFunc, ok := db.matchers[f.Operation()] - if !ok { - db.log.Debug(logs.MetabaseMissingMatcher, zap.Uint32("operation", uint32(f.Operation()))) - - return - } - - fkbtRoot := tx.Bucket(name) - if fkbtRoot == nil { - return - } - - err := matchFunc.matchBucket(fkbtRoot, f.Header(), f.Value(), func(k, _ []byte) error { - fkbtLeaf := fkbtRoot.Bucket(k) - if fkbtLeaf == nil { - return nil - } - - return fkbtLeaf.ForEach(func(k, _ []byte) error { - markAddressInCache(to, fNum, string(k)) - - return nil - }) - }) - if err != nil { - db.log.Debug(logs.MetabaseErrorInFKBTSelection, zap.String("error", err.Error())) - } -} - -// selectOutsideFKBT looks into all incl buckets to find list of addresses outside to add in -// resulting cache. -func selectOutsideFKBT( - tx *bbolt.Tx, - incl [][]byte, // buckets - name []byte, // fkbt root bucket name - to map[string]int, // resulting cache - fNum int, // index of filter -) { - mExcl := make(map[string]struct{}) - - bktExcl := tx.Bucket(name) - if bktExcl != nil { - _ = bktExcl.ForEachBucket(func(k []byte) error { - exclBktLeaf := bktExcl.Bucket(k) - return exclBktLeaf.ForEach(func(k, _ []byte) error { - mExcl[string(k)] = struct{}{} - - return nil - }) - }) - } - - for i := range incl { - bktIncl := tx.Bucket(incl[i]) - if bktIncl == nil { - continue - } - - _ = bktIncl.ForEach(func(k, _ []byte) error { - if _, ok := mExcl[string(k)]; !ok { - markAddressInCache(to, fNum, string(k)) - } - - return nil - }) - } -} - // selectFromList looks into index to find list of addresses to add in // resulting cache. func (db *DB) selectFromList( @@ -491,13 +394,7 @@ func (db *DB) matchSlowFilters(tx *bbolt.Tx, addr oid.Address, f objectSDK.Searc } for i := range f { - matchFunc, ok := db.matchers[f[i].Operation()] - if !ok { - return false - } - var data []byte - switch f[i].Header() { case v2object.FilterHeaderVersion: data = []byte(obj.Version().String()) @@ -515,8 +412,18 @@ func (db *DB) matchSlowFilters(tx *bbolt.Tx, addr oid.Address, f objectSDK.Searc case v2object.FilterHeaderPayloadHash: cs, _ := obj.PayloadChecksum() data = cs.Value() - default: - continue // ignore unknown search attributes + default: // user attribute + v, ok := attributeValue(obj, f[i].Header()) + if ok { + data = []byte(v) + } else { + return f[i].Operation() == objectSDK.MatchNotPresent + } + } + + matchFunc, ok := db.matchers[f[i].Operation()] + if !ok { + return false } if !matchFunc.matchSlow(f[i].Header(), data, f[i].Value()) { @@ -527,6 +434,19 @@ func (db *DB) matchSlowFilters(tx *bbolt.Tx, addr oid.Address, f objectSDK.Searc return true } +func attributeValue(obj *objectSDK.Object, attribute string) (string, bool) { + objectAttributes := obj.Attributes() + if ech := obj.ECHeader(); ech != nil { + objectAttributes = ech.ParentAttributes() + } + for _, attr := range objectAttributes { + if attr.Key() == attribute { + return attr.Value(), true + } + } + return "", false +} + // groupFilters divides filters in two groups: fast and slow. Fast filters // processed by indexes and slow filters processed after by unmarshaling // object headers. @@ -545,16 +465,17 @@ func groupFilters(filters objectSDK.SearchFilters) (filterGroup, error) { } res.withCnrFilter = true - case // slow filters - v2object.FilterHeaderVersion, - v2object.FilterHeaderCreationEpoch, - v2object.FilterHeaderPayloadLength, - v2object.FilterHeaderHomomorphicHash, - v2object.FilterHeaderOwnerID, - v2object.FilterHeaderPayloadHash: - res.slowFilters = append(res.slowFilters, filters[i]) - default: // fast filters or user attributes if unknown + case // fast filters + v2object.FilterHeaderObjectID, + v2object.FilterHeaderObjectType, + v2object.FilterHeaderParent, + v2object.FilterHeaderSplitID, + v2object.FilterHeaderECParent, + v2object.FilterPropertyRoot, + v2object.FilterPropertyPhy: res.fastFilters = append(res.fastFilters, filters[i]) + default: + res.slowFilters = append(res.slowFilters, filters[i]) } } diff --git a/pkg/local_object_storage/metabase/util.go b/pkg/local_object_storage/metabase/util.go index 012c0dcc..9134616f 100644 --- a/pkg/local_object_storage/metabase/util.go +++ b/pkg/local_object_storage/metabase/util.go @@ -95,10 +95,10 @@ const ( // Key: owner ID // Value: bucket containing object IDs as keys _ - // userAttributePrefix is used for prefixing FKBT index buckets containing objects. + // userAttributePrefix was used for prefixing FKBT index buckets containing objects. // Key: attribute value // Value: bucket containing object IDs as keys - userAttributePrefix + _ // ==================== // List index buckets. @@ -167,13 +167,6 @@ func smallBucketName(cnr cid.ID, key []byte) []byte { return bucketName(cnr, smallPrefix, key) } -// attributeBucketName returns _attr_. -func attributeBucketName(cnr cid.ID, attributeKey string, key []byte) []byte { - key[0] = userAttributePrefix - cnr.Encode(key[1:]) - return append(key[:bucketKeySize], attributeKey...) -} - // rootBucketName returns _root. func rootBucketName(cnr cid.ID, key []byte) []byte { return bucketName(cnr, rootPrefix, key)