func (db *DB) putSync(batch *leveldb.Batch, binIDs map[uint8]uint64, item shed.Item) (exists bool, gcSizeChange int64, err error) {
	exists, err = db.retrievalDataIndex.Has(item)
	if err != nil {
		return false, 0, err
	}
	if exists {
		return true, 0, nil
	}
	previous, err := db.postageIndexIndex.Get(item)
	if err != nil {
		if !errors.Is(err, leveldb.ErrNotFound) {
			return false, 0, err
		}
	} else {
		if item.Immutable {
			return false, 0, ErrOverwrite
		}
		if !later(previous, item) {
			return false, 0, nil
		}
		_, err = db.setRemove(batch, previous, true)
		if err != nil {
			return false, 0, err
		}
		radius, err := db.postageRadiusIndex.Get(item)
		if err != nil {
			if !errors.Is(err, leveldb.ErrNotFound) {
				return false, 0, err
			}
		} else {
			if db.po(swarm.NewAddress(item.Address)) >= radius.Radius {
				if err := db.incReserveSizeInBatch(batch, -1); err != nil {
					return false, 0, err
				}
			}
		}
	}
	item.StoreTimestamp = now()
	item.BinID, err = db.incBinID(binIDs, db.po(swarm.NewAddress(item.Address)))
	if err != nil {
		return false, 0, err
	}
	err = db.retrievalDataIndex.PutInBatch(batch, item)
	if err != nil {
		return false, 0, err
	}
	err = db.pullIndex.PutInBatch(batch, item)
	if err != nil {
		return false, 0, err
	}
	err = db.postageChunksIndex.PutInBatch(batch, item)
	if err != nil {
		return false, 0, err
	}
	err = db.postageIndexIndex.PutInBatch(batch, item)
	if err != nil {
		return false, 0, err
	}
	item.AccessTimestamp = now()
	err = db.retrievalAccessIndex.PutInBatch(batch, item)
	if err != nil {
		return false, 0, err
	}
	gcSizeChangeNew, err := db.preserveOrCache(batch, item, false, false)
	if err != nil {
		return false, 0, err
	}
	return false, gcSizeChange + gcSizeChangeNew, nil
}
putSync adds an Item to the batch by updating required indexes:
- put to indexes: retrieve, pull, gc
The batch can be written to the database.
Provided batch and binID map are updated.
package localstore
import (
	"context"
	"encoding/binary"
	"errors"
	"time"
	"github.com/ethsana/sana/pkg/shed"
	"github.com/ethsana/sana/pkg/storage"
	"github.com/ethsana/sana/pkg/swarm"
	"github.com/syndtr/goleveldb/leveldb"
)
var (
	ErrOverwrite = errors.New("index already exists - double issuance on immutable batch")
)
func (db *DB) Put(ctx context.Context, mode storage.ModePut, chs ...swarm.Chunk) (exist []bool, err error) {
	db.metrics.ModePut.Inc()
	defer totalTimeMetric(db.metrics.TotalTimePut, time.Now())
	exist, err = db.put(mode, chs...)
	if err != nil {
		db.metrics.ModePutFailure.Inc()
	}
	return exist, err
}
func (db *DB) put(mode storage.ModePut, chs ...swarm.Chunk) (exist []bool, err error) {
	if len(chs) == 1 && mode != storage.ModePutRequestPin && mode != storage.ModePutUploadPin {
		has, err := db.retrievalDataIndex.Has(chunkToItem(chs[0]))
		if err != nil {
			return nil, err
		}
		if has {
			return []bool{true}, nil
		}
	}
	db.batchMu.Lock()
	defer db.batchMu.Unlock()
	if db.gcRunning {
		for _, ch := range chs {
			db.dirtyAddresses = append(db.dirtyAddresses, ch.Address())
		}
	}
	batch := new(leveldb.Batch)
	var gcSizeChange int64                       
	var triggerPushFeed bool                     
	triggerPullFeed := make(map[uint8]struct{})  
	exist = make([]bool, len(chs))
	binIDs := make(map[uint8]uint64)
	switch mode {
	case storage.ModePutRequest, storage.ModePutRequestPin, storage.ModePutRequestCache:
		for i, ch := range chs {
			if containsChunk(ch.Address(), chs[:i]...) {
				exist[i] = true
				continue
			}
			item := chunkToItem(ch)
			pin := mode == storage.ModePutRequestPin      
			cache := mode == storage.ModePutRequestCache  
			exists, c, err := db.putRequest(batch, binIDs, item, pin, cache)
			if err != nil {
				return nil, err
			}
			exist[i] = exists
			gcSizeChange += c
		}
	case storage.ModePutUpload, storage.ModePutUploadPin:
		for i, ch := range chs {
			if containsChunk(ch.Address(), chs[:i]...) {
				exist[i] = true
				continue
			}
			item := chunkToItem(ch)
			exists, c, err := db.putUpload(batch, binIDs, item)
			if err != nil {
				return nil, err
			}
			exist[i] = exists
			if !exists {
				triggerPullFeed[db.po(ch.Address())] = struct{}{}
				triggerPushFeed = true
			}
			gcSizeChange += c
			if mode == storage.ModePutUploadPin {
				c, err = db.setPin(batch, item)
				if err != nil {
					return nil, err
				}
				gcSizeChange += c
			}
		}
	case storage.ModePutSync:
		for i, ch := range chs {
			if containsChunk(ch.Address(), chs[:i]...) {
				exist[i] = true
				continue
			}
			exists, c, err := db.putSync(batch, binIDs, chunkToItem(ch))
			if err != nil {
				return nil, err
			}
			exist[i] = exists
			if !exists {
				triggerPullFeed[db.po(ch.Address())] = struct{}{}
			}
			gcSizeChange += c
		}
	default:
		return nil, ErrInvalidMode
	}
	for po, id := range binIDs {
		db.binIDs.PutInBatch(batch, uint64(po), id)
	}
	err = db.incGCSizeInBatch(batch, gcSizeChange)
	if err != nil {
		return nil, err
	}
	err = db.shed.WriteBatch(batch)
	if err != nil {
		return nil, err
	}
	for po := range triggerPullFeed {
		db.triggerPullSubscriptions(po)
	}
	if triggerPushFeed {
		db.triggerPushSubscriptions()
	}
	return exist, nil
}
func (db *DB) putRequest(batch *leveldb.Batch, binIDs map[uint8]uint64, item shed.Item, forcePin, forceCache bool) (exists bool, gcSizeChange int64, err error) {
	exists, err = db.retrievalDataIndex.Has(item)
	if err != nil {
		return false, 0, err
	}
	if exists {
		return true, 0, nil
	}
	previous, err := db.postageIndexIndex.Get(item)
	if err != nil {
		if !errors.Is(err, leveldb.ErrNotFound) {
			return false, 0, err
		}
	} else {
		if item.Immutable {
			return false, 0, ErrOverwrite
		}
		if !later(previous, item) {
			return false, 0, nil
		}
		gcSizeChange, err = db.setRemove(batch, previous, true)
		if err != nil {
			return false, 0, err
		}
		radius, err := db.postageRadiusIndex.Get(item)
		if err != nil {
			if !errors.Is(err, leveldb.ErrNotFound) {
				return false, 0, err
			}
		} else {
			if db.po(swarm.NewAddress(item.Address)) >= radius.Radius {
				if err := db.incReserveSizeInBatch(batch, -1); err != nil {
					return false, 0, err
				}
			}
		}
	}
	item.StoreTimestamp = now()
	item.BinID, err = db.incBinID(binIDs, db.po(swarm.NewAddress(item.Address)))
	if err != nil {
		return false, 0, err
	}
	err = db.retrievalDataIndex.PutInBatch(batch, item)
	if err != nil {
		return false, 0, err
	}
	err = db.postageChunksIndex.PutInBatch(batch, item)
	if err != nil {
		return false, 0, err
	}
	err = db.postageIndexIndex.PutInBatch(batch, item)
	if err != nil {
		return false, 0, err
	}
	item.AccessTimestamp = now()
	err = db.retrievalAccessIndex.PutInBatch(batch, item)
	if err != nil {
		return false, 0, err
	}
	gcSizeChangeNew, err := db.preserveOrCache(batch, item, forcePin, forceCache)
	if err != nil {
		return false, 0, err
	}
	if !forceCache {
		err = db.pullIndex.PutInBatch(batch, item)
		if err != nil {
			return false, 0, err
		}
	}
	return false, gcSizeChange + gcSizeChangeNew, nil
}
func (db *DB) putUpload(batch *leveldb.Batch, binIDs map[uint8]uint64, item shed.Item) (exists bool, gcSizeChange int64, err error) {
	exists, err = db.retrievalDataIndex.Has(item)
	if err != nil {
		return false, 0, err
	}
	if exists {
		return true, 0, nil
	}
	previous, err := db.postageIndexIndex.Get(item)
	if err != nil {
		if !errors.Is(err, leveldb.ErrNotFound) {
			return false, 0, err
		}
	} else {
		if item.Immutable {
			return false, 0, ErrOverwrite
		}
		if !later(previous, item) {
			return false, 0, nil
		}
		_, err = db.setRemove(batch, previous, true)
		if err != nil {
			return false, 0, err
		}
	}
	item.StoreTimestamp = now()
	item.BinID, err = db.incBinID(binIDs, db.po(swarm.NewAddress(item.Address)))
	if err != nil {
		return false, 0, err
	}
	err = db.retrievalDataIndex.PutInBatch(batch, item)
	if err != nil {
		return false, 0, err
	}
	err = db.pullIndex.PutInBatch(batch, item)
	if err != nil {
		return false, 0, err
	}
	err = db.pushIndex.PutInBatch(batch, item)
	if err != nil {
		return false, 0, err
	}
	err = db.postageIndexIndex.PutInBatch(batch, item)
	if err != nil {
		return false, 0, err
	}
	err = db.postageChunksIndex.PutInBatch(batch, item)
	if err != nil {
		return false, 0, err
	}
	return false, 0, nil
}