8107c8d1a9
It allows storing information about object in both ways at the same time: 1. Metabase should know if an object is covered by a tombstone (that is not expired yet); 2. It should be possible to physically delete objects covered by a tombstone immediately (mark with GC) but keep tombstone knowledge. Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
97 lines
2.1 KiB
Go
97 lines
2.1 KiB
Go
package meta
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
|
"go.etcd.io/bbolt"
|
|
)
|
|
|
|
// DeletedObject represents descriptor of the object that was
|
|
// marked to be deleted.
|
|
type DeletedObject struct {
|
|
addr *addressSDK.Address
|
|
}
|
|
|
|
// Address returns buried object address.
|
|
func (g *DeletedObject) Address() *addressSDK.Address {
|
|
return g.addr
|
|
}
|
|
|
|
// Handler is a DeletedObject handling function.
|
|
type Handler func(*DeletedObject) error
|
|
|
|
// IterateOverGarbage iterates over all objects
|
|
// marked with GC mark.
|
|
//
|
|
// If h returns ErrInterruptIterator, nil returns immediately.
|
|
// Returns other errors of h directly.
|
|
func (db *DB) IterateOverGarbage(h Handler) error {
|
|
return db.boltDB.View(func(tx *bbolt.Tx) error {
|
|
return db.iterateDeletedObj(tx, withGC, h)
|
|
})
|
|
}
|
|
|
|
// IterateOverGraveyard iterates over all graves in DB.
|
|
//
|
|
// If h returns ErrInterruptIterator, nil returns immediately.
|
|
// Returns other errors of h directly.
|
|
func (db *DB) IterateOverGraveyard(h Handler) error {
|
|
return db.boltDB.View(func(tx *bbolt.Tx) error {
|
|
return db.iterateDeletedObj(tx, grave, h)
|
|
})
|
|
}
|
|
|
|
type deletedType uint8
|
|
|
|
const (
|
|
_ deletedType = iota
|
|
grave
|
|
withGC
|
|
)
|
|
|
|
func (db *DB) iterateDeletedObj(tx *bbolt.Tx, t deletedType, h Handler) error {
|
|
var bkt *bbolt.Bucket
|
|
switch t {
|
|
case grave:
|
|
bkt = tx.Bucket(graveyardBucketName)
|
|
case withGC:
|
|
bkt = tx.Bucket(garbageBucketName)
|
|
default:
|
|
panic(fmt.Sprintf("metabase: unknown iteration object type: %d", t))
|
|
}
|
|
|
|
if bkt == nil {
|
|
return nil
|
|
}
|
|
|
|
// iterate over all deleted objects
|
|
err := bkt.ForEach(func(k, v []byte) error {
|
|
// parse deleted object
|
|
delObj, err := deletedObjectFromKV(k, v)
|
|
if err != nil {
|
|
return fmt.Errorf("could not parse Grave: %w", err)
|
|
}
|
|
|
|
// handler object
|
|
return h(delObj)
|
|
})
|
|
|
|
if errors.Is(err, ErrInterruptIterator) {
|
|
err = nil
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func deletedObjectFromKV(k, _ []byte) (*DeletedObject, error) {
|
|
addr, err := addressFromKey(k)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not parse address: %w", err)
|
|
}
|
|
|
|
return &DeletedObject{
|
|
addr: addr,
|
|
}, nil
|
|
}
|