2020-11-23 13:30:56 +00:00
|
|
|
package meta
|
|
|
|
|
|
|
|
import (
|
2021-02-19 09:49:23 +00:00
|
|
|
"bytes"
|
|
|
|
|
2020-11-23 13:30:56 +00:00
|
|
|
objectSDK "github.com/nspcc-dev/neofs-api-go/pkg/object"
|
2021-02-19 09:49:23 +00:00
|
|
|
"github.com/pkg/errors"
|
2020-11-23 13:30:56 +00:00
|
|
|
"go.etcd.io/bbolt"
|
|
|
|
)
|
|
|
|
|
2020-12-08 09:56:14 +00:00
|
|
|
// InhumePrm encapsulates parameters for Inhume operation.
|
|
|
|
type InhumePrm struct {
|
2021-02-15 11:50:21 +00:00
|
|
|
tomb *objectSDK.Address
|
|
|
|
|
|
|
|
target []*objectSDK.Address
|
2020-12-08 09:56:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// InhumeRes encapsulates results of Inhume operation.
|
|
|
|
type InhumeRes struct{}
|
|
|
|
|
2021-02-15 11:50:21 +00:00
|
|
|
// WithAddresses sets list of object addresses that should be inhumed.
|
|
|
|
func (p *InhumePrm) WithAddresses(addrs ...*objectSDK.Address) *InhumePrm {
|
2020-12-08 09:56:14 +00:00
|
|
|
if p != nil {
|
2021-02-15 11:50:21 +00:00
|
|
|
p.target = addrs
|
2020-12-08 09:56:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithTombstoneAddress sets tombstone address as the reason for inhume operation.
|
2021-02-15 11:11:10 +00:00
|
|
|
//
|
|
|
|
// addr should not be nil.
|
|
|
|
// Should not be called along with WithGCMark.
|
2020-12-08 09:56:14 +00:00
|
|
|
func (p *InhumePrm) WithTombstoneAddress(addr *objectSDK.Address) *InhumePrm {
|
|
|
|
if p != nil {
|
|
|
|
p.tomb = addr
|
|
|
|
}
|
|
|
|
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
2021-02-15 11:11:10 +00:00
|
|
|
// WithGCMark marks the object to be physically removed.
|
|
|
|
//
|
|
|
|
// Should not be called along with WithTombstoneAddress.
|
|
|
|
func (p *InhumePrm) WithGCMark() *InhumePrm {
|
|
|
|
if p != nil {
|
|
|
|
p.tomb = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
2020-12-08 09:56:14 +00:00
|
|
|
// Inhume inhumes the object by specified address.
|
2021-02-15 11:11:10 +00:00
|
|
|
//
|
|
|
|
// tomb should not be nil.
|
2020-12-08 09:56:14 +00:00
|
|
|
func Inhume(db *DB, target, tomb *objectSDK.Address) error {
|
|
|
|
_, err := db.Inhume(new(InhumePrm).
|
2021-02-15 11:50:21 +00:00
|
|
|
WithAddresses(target).
|
2020-12-08 09:56:14 +00:00
|
|
|
WithTombstoneAddress(tomb),
|
|
|
|
)
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-02-15 11:11:10 +00:00
|
|
|
const inhumeGCMarkValue = "GCMARK"
|
|
|
|
|
2021-02-19 09:49:23 +00:00
|
|
|
var errBreakBucketForEach = errors.New("bucket ForEach break")
|
|
|
|
|
2020-11-23 13:30:56 +00:00
|
|
|
// Inhume marks objects as removed but not removes it from metabase.
|
2020-12-08 09:56:14 +00:00
|
|
|
func (db *DB) Inhume(prm *InhumePrm) (res *InhumeRes, err error) {
|
|
|
|
err = db.boltDB.Update(func(tx *bbolt.Tx) error {
|
2020-11-23 13:30:56 +00:00
|
|
|
graveyard, err := tx.CreateBucketIfNotExists(graveyardBucketName)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-02-19 09:49:23 +00:00
|
|
|
var tombKey []byte
|
|
|
|
if prm.tomb != nil {
|
|
|
|
tombKey = addressKey(prm.tomb)
|
|
|
|
|
|
|
|
// it is forbidden to have a tomb-on-tomb in NeoFS,
|
|
|
|
// so graveyard keys must not be addresses of tombstones
|
|
|
|
|
|
|
|
// tombstones can be marked for GC in graveyard, so exclude this case
|
|
|
|
data := graveyard.Get(tombKey)
|
|
|
|
if data != nil && !bytes.Equal(data, []byte(inhumeGCMarkValue)) {
|
|
|
|
err := graveyard.Delete(tombKey)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "could not remove grave with tombstone key")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tombKey = []byte(inhumeGCMarkValue)
|
|
|
|
}
|
|
|
|
|
2021-02-15 11:50:21 +00:00
|
|
|
for i := range prm.target {
|
|
|
|
obj, err := db.get(tx, prm.target[i], false, true)
|
|
|
|
|
|
|
|
// if object is stored and it is regular object then update bucket
|
|
|
|
// with container size estimations
|
|
|
|
if err == nil && obj.Type() == objectSDK.TypeRegular {
|
|
|
|
err := changeContainerSize(
|
|
|
|
tx,
|
|
|
|
obj.ContainerID(),
|
|
|
|
obj.PayloadSize(),
|
|
|
|
false,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-19 09:49:23 +00:00
|
|
|
targetKey := addressKey(prm.target[i])
|
|
|
|
|
2021-02-15 11:50:21 +00:00
|
|
|
if prm.tomb != nil {
|
2021-02-19 09:49:23 +00:00
|
|
|
targetIsTomb := false
|
|
|
|
|
|
|
|
// iterate over graveyard and check if target address
|
|
|
|
// is the address of tombstone in graveyard.
|
|
|
|
err = graveyard.ForEach(func(k, v []byte) error {
|
|
|
|
// check if graveyard has record with key corresponding
|
|
|
|
// to tombstone address (at least one)
|
|
|
|
targetIsTomb = bytes.Equal(v, targetKey)
|
|
|
|
|
|
|
|
if targetIsTomb {
|
|
|
|
// break bucket iterator
|
|
|
|
return errBreakBucketForEach
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
if err != nil && !errors.Is(err, errBreakBucketForEach) {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// do not add grave if target is a tombstone
|
|
|
|
if targetIsTomb {
|
|
|
|
continue
|
|
|
|
}
|
2021-02-15 11:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// consider checking if target is already in graveyard?
|
2021-02-19 09:49:23 +00:00
|
|
|
err = graveyard.Put(targetKey, tombKey)
|
2021-01-22 11:07:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-15 11:50:21 +00:00
|
|
|
return nil
|
2020-11-23 13:30:56 +00:00
|
|
|
})
|
2020-12-08 09:56:14 +00:00
|
|
|
|
|
|
|
return
|
2020-11-23 13:30:56 +00:00
|
|
|
}
|