diff --git a/pkg/local_object_storage/blobovnicza/blobovnicza.go b/pkg/local_object_storage/blobovnicza/blobovnicza.go index 22168de22..c787f9d5e 100644 --- a/pkg/local_object_storage/blobovnicza/blobovnicza.go +++ b/pkg/local_object_storage/blobovnicza/blobovnicza.go @@ -16,7 +16,8 @@ import ( type Blobovnicza struct { cfg - dataSize atomic.Uint64 + dataSize atomic.Uint64 + itemsCount atomic.Uint64 boltDB *bbolt.DB diff --git a/pkg/local_object_storage/blobovnicza/control.go b/pkg/local_object_storage/blobovnicza/control.go index aa6be6025..ad554a0ad 100644 --- a/pkg/local_object_storage/blobovnicza/control.go +++ b/pkg/local_object_storage/blobovnicza/control.go @@ -68,8 +68,10 @@ func (b *Blobovnicza) Init() error { zap.Uint64("storage size limit", b.fullSizeLimit), ) - if size := b.dataSize.Load(); size != 0 { - b.log.Debug(logs.BlobovniczaAlreadyInitialized, zap.Uint64("size", size)) + size := b.dataSize.Load() + items := b.itemsCount.Load() + if size != 0 || items != 0 { + b.log.Debug(logs.BlobovniczaAlreadyInitialized, zap.Uint64("size", size), zap.Uint64("items", items)) return nil } @@ -96,14 +98,17 @@ func (b *Blobovnicza) Init() error { } } - return b.initializeSize() + return b.initializeCounters() } -func (b *Blobovnicza) initializeSize() error { +func (b *Blobovnicza) initializeCounters() error { var size uint64 + var items uint64 err := b.boltDB.View(func(tx *bbolt.Tx) error { return b.iterateAllBuckets(tx, func(lower, upper uint64, b *bbolt.Bucket) (bool, error) { - size += uint64(b.Stats().KeyN) * upper + keysN := uint64(b.Stats().KeyN) + size += keysN * upper + items += keysN return false, nil }) }) @@ -111,7 +116,9 @@ func (b *Blobovnicza) initializeSize() error { return fmt.Errorf("can't determine DB size: %w", err) } b.dataSize.Store(size) + b.itemsCount.Store(items) b.metrics.AddOpenBlobovniczaSize(size) + b.metrics.AddOpenBlobovniczaItems(items) return nil } @@ -136,7 +143,9 @@ func (b *Blobovnicza) Close() error { b.metrics.DecOpenBlobovniczaCount() b.metrics.SubOpenBlobovniczaSize(b.dataSize.Load()) + b.metrics.SubOpenBlobovniczaItems(b.itemsCount.Load()) b.dataSize.Store(0) + b.itemsCount.Store(0) b.opened = false diff --git a/pkg/local_object_storage/blobovnicza/delete.go b/pkg/local_object_storage/blobovnicza/delete.go index f332173c1..5a5da235f 100644 --- a/pkg/local_object_storage/blobovnicza/delete.go +++ b/pkg/local_object_storage/blobovnicza/delete.go @@ -74,7 +74,7 @@ func (b *Blobovnicza) Delete(ctx context.Context, prm DeletePrm) (DeleteRes, err zap.String("binary size", stringifyByteSize(dataSize)), zap.String("range", stringifyBounds(sizeLowerBound, sizeUpperBound)), ) - b.decSize(sizeUpperBound) + b.itemDeleted(sizeUpperBound) } return DeleteRes{}, err diff --git a/pkg/local_object_storage/blobovnicza/metrics.go b/pkg/local_object_storage/blobovnicza/metrics.go index 9ce703201..37352b083 100644 --- a/pkg/local_object_storage/blobovnicza/metrics.go +++ b/pkg/local_object_storage/blobovnicza/metrics.go @@ -6,11 +6,16 @@ type Metrics interface { AddOpenBlobovniczaSize(size uint64) SubOpenBlobovniczaSize(size uint64) + + AddOpenBlobovniczaItems(items uint64) + SubOpenBlobovniczaItems(items uint64) } type NoopMetrics struct{} -func (m *NoopMetrics) IncOpenBlobovniczaCount() {} -func (m *NoopMetrics) DecOpenBlobovniczaCount() {} -func (m *NoopMetrics) AddOpenBlobovniczaSize(uint64) {} -func (m *NoopMetrics) SubOpenBlobovniczaSize(uint64) {} +func (m *NoopMetrics) IncOpenBlobovniczaCount() {} +func (m *NoopMetrics) DecOpenBlobovniczaCount() {} +func (m *NoopMetrics) AddOpenBlobovniczaSize(uint64) {} +func (m *NoopMetrics) SubOpenBlobovniczaSize(uint64) {} +func (m *NoopMetrics) AddOpenBlobovniczaItems(uint64) {} +func (m *NoopMetrics) SubOpenBlobovniczaItems(uint64) {} diff --git a/pkg/local_object_storage/blobovnicza/put.go b/pkg/local_object_storage/blobovnicza/put.go index b8cc9954a..e43b89ec6 100644 --- a/pkg/local_object_storage/blobovnicza/put.go +++ b/pkg/local_object_storage/blobovnicza/put.go @@ -85,7 +85,7 @@ func (b *Blobovnicza) Put(ctx context.Context, prm PutPrm) (PutRes, error) { return nil }) if err == nil { - b.incSize(upperBound) + b.itemAdded(upperBound) } return PutRes{}, err diff --git a/pkg/local_object_storage/blobovnicza/sizes.go b/pkg/local_object_storage/blobovnicza/sizes.go index a2f558f55..290df9c93 100644 --- a/pkg/local_object_storage/blobovnicza/sizes.go +++ b/pkg/local_object_storage/blobovnicza/sizes.go @@ -3,6 +3,7 @@ package blobovnicza import ( "encoding/binary" "fmt" + "math" "math/bits" "strconv" ) @@ -40,14 +41,18 @@ func upperPowerOfTwo(v uint64) uint64 { return 1 << bits.Len64(v-1) } -func (b *Blobovnicza) incSize(sz uint64) { - b.dataSize.Add(sz) - b.metrics.AddOpenBlobovniczaSize(sz) +func (b *Blobovnicza) itemAdded(itemSize uint64) { + b.dataSize.Add(itemSize) + b.itemsCount.Add(1) + b.metrics.AddOpenBlobovniczaSize(itemSize) + b.metrics.AddOpenBlobovniczaItems(1) } -func (b *Blobovnicza) decSize(sz uint64) { - b.dataSize.Add(^(sz - 1)) - b.metrics.SubOpenBlobovniczaSize(sz) +func (b *Blobovnicza) itemDeleted(itemSize uint64) { + b.dataSize.Add(^(itemSize - 1)) + b.itemsCount.Add(math.MaxUint64) + b.metrics.SubOpenBlobovniczaSize(itemSize) + b.metrics.SubOpenBlobovniczaItems(1) } func (b *Blobovnicza) full() bool { diff --git a/pkg/local_object_storage/metrics/blobovnicza.go b/pkg/local_object_storage/metrics/blobovnicza.go index 5261f4080..0d0318b3b 100644 --- a/pkg/local_object_storage/metrics/blobovnicza.go +++ b/pkg/local_object_storage/metrics/blobovnicza.go @@ -96,3 +96,11 @@ func (m *blobovniczaMetrics) IncOpenBlobovniczaCount() { func (m *blobovniczaMetrics) DecOpenBlobovniczaCount() { m.m.DecOpenBlobovniczaCount(m.shardID(), m.path) } + +func (m *blobovniczaMetrics) AddOpenBlobovniczaItems(items uint64) { + m.m.AddOpenBlobovniczaItems(m.shardID(), m.path, items) +} + +func (m *blobovniczaMetrics) SubOpenBlobovniczaItems(items uint64) { + m.m.SubOpenBlobovniczaItems(m.shardID(), m.path, items) +} diff --git a/pkg/metrics/blobovnicza.go b/pkg/metrics/blobovnicza.go index 9c5e17520..a1ecbc700 100644 --- a/pkg/metrics/blobovnicza.go +++ b/pkg/metrics/blobovnicza.go @@ -18,6 +18,9 @@ type BlobobvnizcaMetrics interface { AddOpenBlobovniczaSize(shardID, path string, size uint64) SubOpenBlobovniczaSize(shardID, path string, size uint64) + AddOpenBlobovniczaItems(shardID, path string, items uint64) + SubOpenBlobovniczaItems(shardID, path string, items uint64) + IncOpenBlobovniczaCount(shardID, path string) DecOpenBlobovniczaCount(shardID, path string) } @@ -28,6 +31,7 @@ type blobovnicza struct { treePut *prometheus.CounterVec treeGet *prometheus.CounterVec treeOpenSize *prometheus.GaugeVec + treeOpenItems *prometheus.GaugeVec treeOpenCounter *prometheus.GaugeVec } @@ -59,6 +63,12 @@ func newBlobovnicza() *blobovnicza { Name: "open_blobovnicza_size_bytes", Help: "Size of opened blobovniczas of Blobovnicza tree", }, []string{shardIDLabel, pathLabel}), + treeOpenItems: metrics.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: namespace, + Subsystem: blobovniczaTreeSubSystem, + Name: "open_blobovnicza_items_total", + Help: "Count of items in opened blobovniczas of Blobovnicza tree", + }, []string{shardIDLabel, pathLabel}), treeOpenCounter: metrics.NewGaugeVec(prometheus.GaugeOpts{ Namespace: namespace, Subsystem: blobovniczaTreeSubSystem, @@ -139,3 +149,17 @@ func (b *blobovnicza) DecOpenBlobovniczaCount(shardID, path string) { pathLabel: path, }).Dec() } + +func (b *blobovnicza) AddOpenBlobovniczaItems(shardID, path string, items uint64) { + b.treeOpenItems.With(prometheus.Labels{ + shardIDLabel: shardID, + pathLabel: path, + }).Add(float64(items)) +} + +func (b *blobovnicza) SubOpenBlobovniczaItems(shardID, path string, items uint64) { + b.treeOpenItems.With(prometheus.Labels{ + shardIDLabel: shardID, + pathLabel: path, + }).Sub(float64(items)) +}