2020-12-03 11:29:33 +00:00
|
|
|
package meta
|
|
|
|
|
|
|
|
import (
|
2021-01-22 11:07:08 +00:00
|
|
|
"encoding/binary"
|
2020-12-03 11:29:33 +00:00
|
|
|
|
2021-11-10 07:08:33 +00:00
|
|
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
2020-12-03 11:29:33 +00:00
|
|
|
"go.etcd.io/bbolt"
|
|
|
|
)
|
|
|
|
|
2022-05-31 17:00:41 +00:00
|
|
|
func (db *DB) Containers() (list []cid.ID, err error) {
|
2022-07-21 13:26:25 +00:00
|
|
|
db.modeMtx.RLock()
|
|
|
|
defer db.modeMtx.RUnlock()
|
|
|
|
|
2020-12-03 11:29:33 +00:00
|
|
|
err = db.boltDB.View(func(tx *bbolt.Tx) error {
|
|
|
|
list, err = db.containers(tx)
|
|
|
|
|
|
|
|
return err
|
|
|
|
})
|
|
|
|
|
|
|
|
return list, err
|
|
|
|
}
|
|
|
|
|
2022-05-31 17:00:41 +00:00
|
|
|
func (db *DB) containers(tx *bbolt.Tx) ([]cid.ID, error) {
|
|
|
|
result := make([]cid.ID, 0)
|
2021-10-27 10:52:12 +00:00
|
|
|
unique := make(map[string]struct{})
|
2022-05-31 17:00:41 +00:00
|
|
|
var cnr cid.ID
|
2020-12-03 11:29:33 +00:00
|
|
|
|
|
|
|
err := tx.ForEach(func(name []byte, _ *bbolt.Bucket) error {
|
2022-05-31 17:00:41 +00:00
|
|
|
if parseContainerID(&cnr, name, unique) {
|
|
|
|
result = append(result, cnr)
|
2022-09-08 11:54:21 +00:00
|
|
|
unique[string(name[1:bucketKeySize])] = struct{}{}
|
2020-12-03 11:29:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
return result, err
|
|
|
|
}
|
|
|
|
|
2022-05-31 17:00:41 +00:00
|
|
|
func (db *DB) ContainerSize(id cid.ID) (size uint64, err error) {
|
2021-01-22 11:07:08 +00:00
|
|
|
err = db.boltDB.Update(func(tx *bbolt.Tx) error {
|
|
|
|
size, err = db.containerSize(tx, id)
|
|
|
|
|
|
|
|
return err
|
|
|
|
})
|
|
|
|
|
|
|
|
return size, err
|
|
|
|
}
|
|
|
|
|
2022-05-31 17:00:41 +00:00
|
|
|
func (db *DB) containerSize(tx *bbolt.Tx, id cid.ID) (uint64, error) {
|
2021-01-22 11:07:08 +00:00
|
|
|
containerVolume, err := tx.CreateBucketIfNotExists(containerVolumeBucketName)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2022-09-08 11:54:21 +00:00
|
|
|
key := make([]byte, cidSize)
|
2022-05-12 16:37:46 +00:00
|
|
|
id.Encode(key)
|
2021-01-22 11:07:08 +00:00
|
|
|
|
|
|
|
return parseContainerSize(containerVolume.Get(key)), nil
|
|
|
|
}
|
|
|
|
|
2022-05-31 17:00:41 +00:00
|
|
|
func parseContainerID(dst *cid.ID, name []byte, ignore map[string]struct{}) bool {
|
2022-09-08 11:54:21 +00:00
|
|
|
if len(name) != bucketKeySize {
|
2022-05-31 17:00:41 +00:00
|
|
|
return false
|
2020-12-03 11:29:33 +00:00
|
|
|
}
|
2022-09-08 11:54:21 +00:00
|
|
|
if _, ok := ignore[string(name[1:bucketKeySize])]; ok {
|
2022-05-31 17:00:41 +00:00
|
|
|
return false
|
2021-10-27 10:52:12 +00:00
|
|
|
}
|
2022-09-08 11:54:21 +00:00
|
|
|
return dst.Decode(name[1:bucketKeySize]) == nil
|
2020-12-03 11:29:33 +00:00
|
|
|
}
|
2021-01-22 11:07:08 +00:00
|
|
|
|
|
|
|
func parseContainerSize(v []byte) uint64 {
|
|
|
|
if len(v) == 0 {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
return binary.LittleEndian.Uint64(v)
|
|
|
|
}
|
|
|
|
|
2022-05-31 17:00:41 +00:00
|
|
|
func changeContainerSize(tx *bbolt.Tx, id cid.ID, delta uint64, increase bool) error {
|
2021-01-22 11:07:08 +00:00
|
|
|
containerVolume, err := tx.CreateBucketIfNotExists(containerVolumeBucketName)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-09-08 11:54:21 +00:00
|
|
|
key := make([]byte, cidSize)
|
2022-05-12 16:37:46 +00:00
|
|
|
id.Encode(key)
|
|
|
|
|
2021-01-22 11:07:08 +00:00
|
|
|
size := parseContainerSize(containerVolume.Get(key))
|
|
|
|
|
|
|
|
if increase {
|
|
|
|
size += delta
|
|
|
|
} else if size > delta {
|
|
|
|
size -= delta
|
|
|
|
} else {
|
|
|
|
size = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
buf := make([]byte, 8) // consider using sync.Pool to decrease allocations
|
|
|
|
binary.LittleEndian.PutUint64(buf, size)
|
|
|
|
|
|
|
|
return containerVolume.Put(key, buf)
|
|
|
|
}
|