metabase: Cache frequently accessed singleton buckets #1686

Merged
fyrchik merged 1 commit from fyrchik/frostfs-node:speedup-search-2 into master 2025-03-20 10:17:43 +00:00
4 changed files with 59 additions and 5 deletions

View file

@ -0,0 +1,45 @@
package meta
import (
"go.etcd.io/bbolt"
)
type bucketCache struct {
locked *bbolt.Bucket
graveyard *bbolt.Bucket
garbage *bbolt.Bucket
}
func newBucketCache() *bucketCache {
return &bucketCache{}
}
func getLockedBucket(bc *bucketCache, tx *bbolt.Tx) *bbolt.Bucket {
if bc == nil {
return tx.Bucket(bucketNameLocked)
}
return getBucket(&bc.locked, tx, bucketNameLocked)
}
func getGraveyardBucket(bc *bucketCache, tx *bbolt.Tx) *bbolt.Bucket {
if bc == nil {
return tx.Bucket(graveyardBucketName)
}
return getBucket(&bc.graveyard, tx, graveyardBucketName)
}
func getGarbageBucket(bc *bucketCache, tx *bbolt.Tx) *bbolt.Bucket {
if bc == nil {
return tx.Bucket(garbageBucketName)
}
return getBucket(&bc.garbage, tx, garbageBucketName)
}
func getBucket(cache **bbolt.Bucket, tx *bbolt.Tx, name []byte) *bbolt.Bucket {
if *cache != nil {
return *cache
}
*cache = tx.Bucket(name)
return *cache
}

View file

@ -153,8 +153,12 @@ func (db *DB) exists(tx *bbolt.Tx, addr oid.Address, ecParent oid.Address, currE
// - 2 if object is covered with tombstone;
// - 3 if object is expired.
func objectStatus(tx *bbolt.Tx, addr oid.Address, currEpoch uint64) (uint8, error) {
return objectStatusWithCache(nil, tx, addr, currEpoch)
}
func objectStatusWithCache(bc *bucketCache, tx *bbolt.Tx, addr oid.Address, currEpoch uint64) (uint8, error) {
// locked object could not be removed/marked with GC/expired
if objectLocked(tx, addr.Container(), addr.Object()) {
if objectLockedWithCache(bc, tx, addr.Container(), addr.Object()) {
return 0, nil
}
@ -167,8 +171,8 @@ func objectStatus(tx *bbolt.Tx, addr oid.Address, currEpoch uint64) (uint8, erro
return 3, nil
}
graveyardBkt := tx.Bucket(graveyardBucketName)
garbageBkt := tx.Bucket(garbageBucketName)
graveyardBkt := getGraveyardBucket(bc, tx)
garbageBkt := getGarbageBucket(bc, tx)
addrKey := addressKey(addr, make([]byte, addressKeySize))
return inGraveyardWithKey(addrKey, graveyardBkt, garbageBkt), nil
}

View file

@ -163,7 +163,11 @@ func (db *DB) FreeLockedBy(lockers []oid.Address) ([]oid.Address, error) {
// checks if specified object is locked in the specified container.
func objectLocked(tx *bbolt.Tx, idCnr cid.ID, idObj oid.ID) bool {
bucketLocked := tx.Bucket(bucketNameLocked)
return objectLockedWithCache(nil, tx, idCnr, idObj)
}
func objectLockedWithCache(bc *bucketCache, tx *bbolt.Tx, idCnr cid.ID, idObj oid.ID) bool {
bucketLocked := getLockedBucket(bc, tx)
if bucketLocked != nil {
key := make([]byte, cidSize)
idCnr.Encode(key)

View file

@ -131,6 +131,7 @@ func (db *DB) selectObjects(tx *bbolt.Tx, cnr cid.ID, fs objectSDK.SearchFilters
res := make([]oid.Address, 0, len(mAddr))
bc := newBucketCache()
for a, ind := range mAddr {
if ind != expLen {
continue // ignore objects with unmatched fast filters
@ -145,7 +146,7 @@ func (db *DB) selectObjects(tx *bbolt.Tx, cnr cid.ID, fs objectSDK.SearchFilters
var addr oid.Address
addr.SetContainer(cnr)
addr.SetObject(id)
st, err := objectStatus(tx, addr, currEpoch)
st, err := objectStatusWithCache(bc, tx, addr, currEpoch)
if err != nil {
return nil, err
}