func (s *store) evictOuter(last *postage.Batch) error {
	if s.rs.Available >= 0 {
		return nil
	}
	err := s.store.Iterate(valueKeyPrefix, func(key, _ []byte) (bool, error) {
		batchID := valueKeyToID(key)
		b := last
		if !bytes.Equal(b.ID, batchID) {
			var err error
			b, err = s.Get(batchID)
			if err != nil {
				return true, fmt.Errorf("release get %x %v: %w", batchID, b, err)
			}
		}
		if b.Value.Cmp(s.rs.Outer) < 0 {
			return false, nil
		}
		if s.rs.Available >= 0 && s.rs.Outer.Cmp(b.Value) != 0 {
			return true, nil
		}
		s.rs.Available += exp2(uint(b.Depth) - uint(s.rs.Radius) - 1)
		s.rs.Outer.Set(b.Value)
		return false, s.unreserveFn(b.ID, s.rs.Radius)
	})
	if err != nil {
		return err
	}
	s.rs.Outer.Add(s.rs.Outer, big1)
	if s.rs.Available < 0 {
		s.rs.Radius++
		s.rs.Outer.Set(s.rs.Inner)  
		return s.evictOuter(last)
	}
	return s.store.Put(reserveStateKey, s.rs)
}
evictOuter is responsible for keeping capacity positive by unreserving lowest priority batches
package batchstore
import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"math/big"
	"strings"
	"github.com/ethersphere/bee/pkg/postage"
	"github.com/ethersphere/bee/pkg/storage"
	"github.com/ethersphere/bee/pkg/swarm"
)
var DefaultDepth = uint8(12)  
var Capacity = exp2(22)
var big1 = big.NewInt(1)
type reserveState struct {
	Radius uint8 `json:"radius"`
	StorageRadius uint8 `json:"storageRadius"`
	Available int64    `json:"available"`
	Outer     *big.Int `json:"outer"`  
	Inner     *big.Int `json:"inner"`  
}
func (s *store) unreserve(b []byte, radius uint8) error {
	c := s.queueIdx
	c++
	v := make([]byte, 8)
	binary.BigEndian.PutUint64(v, c)
	i := &UnreserveItem{BatchID: b, Radius: radius}
	if err := s.store.Put(fmt.Sprintf("%s_%s", unreserveQueueKey, string(v)), i); err != nil {
		return err
	}
	if err := s.putQueueCardinality(c); err != nil {
		return err
	}
	s.queueIdx = c
	return nil
}
func (s *store) Unreserve(cb postage.UnreserveIteratorFn) error {
	var entries []string  
	defer func() {
		for _, v := range entries {
			if err := s.store.Delete(v); err != nil {
				s.logger.Errorf("batchstore: unreserve entry delete: %v", err)
				return
			}
		}
	}()
	return s.store.Iterate(unreserveQueueKey, func(key, val []byte) (bool, error) {
		if !strings.HasPrefix(string(key), unreserveQueueKey) {
			return true, nil
		}
		v := &UnreserveItem{}
		err := v.UnmarshalBinary(val)
		if err != nil {
			return true, err
		}
		stop, err := cb(v.BatchID, v.Radius)
		if err != nil {
			return true, err
		}
		s.rsMtx.Lock()
		defer s.rsMtx.Unlock()
		if s.rs.StorageRadius+1 < v.Radius {
			s.rs.StorageRadius = v.Radius - 1
			s.metrics.StorageRadius.Set(float64(s.rs.StorageRadius))
			if err = s.store.Put(reserveStateKey, s.rs); err != nil {
				return true, err
			}
		}
		entries = append(entries, string(key))
		if stop {
			return true, nil
		}
		return false, nil
	})
}
func (s *store) evictExpired() error {
	var toDelete [][]byte
	until := new(big.Int)
	if s.rs.Inner.Cmp(big.NewInt(0)) > 0 && s.cs.TotalAmount.Cmp(s.rs.Inner) >= 0 {
		until.Add(s.cs.TotalAmount, big1)
	} else {
		until.Set(s.rs.Inner)
	}
	var multiplier int64
	err := s.store.Iterate(valueKeyPrefix, func(key, _ []byte) (bool, error) {
		b, err := s.Get(valueKeyToID(key))
		if err != nil {
			return true, err
		}
		if b.Value.Cmp(until) >= 0 {
			return true, nil
		}
		if multiplier == 0 && b.Value.Cmp(s.rs.Inner) >= 0 {
			multiplier = 1
		}
		if multiplier == 1 && b.Value.Cmp(s.rs.Outer) >= 0 {
			multiplier = 2
		}
		err = s.evictFn(b.ID)
		if err != nil {
			return true, err
		}
		s.rs.Available += multiplier * exp2(uint(b.Radius-s.rs.Radius-1))
		if b.Value.Cmp(s.cs.TotalAmount) <= 0 {
			toDelete = append(toDelete, b.ID)
		}
		return false, nil
	})
	if err != nil {
		return err
	}
	s.rs.Inner.Set(until)
	if s.rs.Outer.Cmp(until) < 0 {
		s.rs.Outer.Set(until)
	}
	if err = s.store.Put(reserveStateKey, s.rs); err != nil {
		return err
	}
	return s.delete(toDelete...)
}
type tier int
const (
	unreserved tier = iota  
	inner                   
	outer                   
)
func (rs *reserveState) change(oldv, newv *big.Int, oldDepth, newDepth uint8) (int64, uint8) {
	oldTier := rs.tier(oldv)
	newTier := rs.setLimits(newv, rs.tier(newv))
	oldSize := rs.size(oldDepth, oldTier)
	newSize := rs.size(newDepth, newTier)
	availableCapacityChange := oldSize - newSize
	reserveRadius := rs.radius(newTier)
	return availableCapacityChange, reserveRadius
}
func (rs *reserveState) size(depth uint8, t tier) int64 {
	size := exp2(uint(depth - rs.Radius - 1))
	switch t {
	case inner:
		return size
	case outer:
		return 2 * size
	default:
		return 0
	}
}
func (rs *reserveState) tier(x *big.Int) tier {
	if x.Cmp(rs.Inner) < 0 || rs.Inner.Cmp(big.NewInt(0)) == 0 {
		return unreserved
	}
	if x.Cmp(rs.Outer) < 0 {
		return inner
	}
	return outer
}
func (rs *reserveState) radius(t tier) uint8 {
	switch t {
	case unreserved:
		return swarm.MaxPO
	case inner:
		return rs.Radius
	default:
		return rs.Radius - 1
	}
}
func (rs *reserveState) setLimits(val *big.Int, newTier tier) tier {
	if newTier != unreserved {
		return newTier
	}
	var adjustedTier tier
	if rs.Inner.Cmp(big.NewInt(0)) == 0 || rs.Inner.Cmp(val) > 0 {
		adjustedTier = inner
		if rs.Outer.Cmp(rs.Inner) == 0 {
			rs.Outer.Set(val)
			adjustedTier = outer
		}
		rs.Inner.Set(val)
	}
	return adjustedTier
}
func (s *store) update(b *postage.Batch, oldDepth uint8, oldValue *big.Int) error {
	newValue := b.Value
	newDepth := b.Depth
	capacityChange, reserveRadius := s.rs.change(oldValue, newValue, oldDepth, newDepth)
	s.rs.Available += capacityChange
	if err := s.unreserveFn(b.ID, reserveRadius); err != nil {
		return err
	}
	err := s.evictOuter(b)
	if err != nil {
		return err
	}
	s.metrics.AvailableCapacity.Set(float64(s.rs.Available))
	s.metrics.Radius.Set(float64(s.rs.Radius))
	s.metrics.Inner.Set(float64(s.rs.Inner.Int64()))
	s.metrics.Outer.Set(float64(s.rs.Outer.Int64()))
	return nil
}