package blobovnicza import ( "encoding/binary" "fmt" "math" "math/bits" "strconv" ) const firstBucketBound = uint64(32 * 1 << 10) // 32KB func stringifyBounds(lower, upper uint64) string { return fmt.Sprintf("[%s:%s]", stringifyByteSize(lower), stringifyByteSize(upper), ) } func stringifyByteSize(sz uint64) string { return strconv.FormatUint(sz, 10) } func bucketKeyFromBounds(upperBound uint64) []byte { buf := make([]byte, binary.MaxVarintLen64) ln := binary.PutUvarint(buf, upperBound) return buf[:ln] } func bucketForSize(sz uint64) []byte { return bucketKeyFromBounds(upperPowerOfTwo(sz)) } func upperPowerOfTwo(v uint64) uint64 { if v <= firstBucketBound { return firstBucketBound } return 1 << bits.Len64(v-1) } 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) itemDeleted(itemSize uint64) { b.dataSize.Add(^(itemSize - 1)) b.itemsCount.Add(math.MaxUint64) b.metrics.SubOpenBlobovniczaSize(itemSize) b.metrics.SubOpenBlobovniczaItems(1) } func (b *Blobovnicza) IsFull() bool { return b.dataSize.Load() >= b.fullSizeLimit } func (b *Blobovnicza) FillPercent() int { return int(100.0 * (float64(b.dataSize.Load()) / float64(b.fullSizeLimit))) } func (b *Blobovnicza) IsOverflowed() bool { // put to blobovnicza is allowed if b.dataSize < b.fullSizeLimit (see `b.IsFull()`) // but several parallel Put requests can be processed simultaneously // so blobovnicza can store maximum `(b.fullSizeLimit - 1) + number of concurrent Put requests x b.objSizeLimit` bytes of data // as number of concurrent Put requests is unknown, assume blobovnicza is overflowed if it stores more than one object's size // bytes of data greater than limit return b.dataSize.Load() > (b.fullSizeLimit-1)+b.objSizeLimit }