metabase: Cache frequently accessed singleton buckets #1686
4 changed files with 59 additions and 5 deletions
45
pkg/local_object_storage/metabase/bucket_cache.go
Normal file
45
pkg/local_object_storage/metabase/bucket_cache.go
Normal 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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue