func (db *DB) updateGC(item shed.Item) (err error) {
	db.batchMu.Lock()
	defer db.batchMu.Unlock()
	if db.gcRunning {
		db.dirtyAddresses = append(db.dirtyAddresses, swarm.NewAddress(item.Address))
	}
	batch := new(leveldb.Batch)
	i, err := db.retrievalAccessIndex.Get(item)
	switch {
	case err == nil:
		item.AccessTimestamp = i.AccessTimestamp
	case errors.Is(err, leveldb.ErrNotFound):
	default:
		return err
	}
	if item.AccessTimestamp == 0 {
		return nil
	}
	err = db.gcIndex.DeleteInBatch(batch, item)
	if err != nil {
		return err
	}
	_, err = db.gcIndex.Get(item)
	item.AccessTimestamp = now()
	if err == nil {
		err = db.gcIndex.PutInBatch(batch, item)
		if err != nil {
			return err
		}
	} else if !errors.Is(err, leveldb.ErrNotFound) {
		return err
	}
	err = db.retrievalAccessIndex.PutInBatch(batch, item)
	if err != nil {
		return err
	}
	return db.shed.WriteBatch(batch)
}
updateGC updates garbage collection index for
a single item. Provided item is expected to have
only Address and Data fields with non zero values,
which is ensured by the get function.
package localstore
import (
	"context"
	"errors"
	"time"
	"github.com/ethsana/sana/pkg/postage"
	"github.com/ethsana/sana/pkg/shed"
	"github.com/ethsana/sana/pkg/storage"
	"github.com/ethsana/sana/pkg/swarm"
	"github.com/syndtr/goleveldb/leveldb"
)
func (db *DB) Get(ctx context.Context, mode storage.ModeGet, addr swarm.Address) (ch swarm.Chunk, err error) {
	db.metrics.ModeGet.Inc()
	defer totalTimeMetric(db.metrics.TotalTimeGet, time.Now())
	defer func() {
		if err != nil {
			db.metrics.ModeGetFailure.Inc()
		}
	}()
	out, err := db.get(mode, addr)
	if err != nil {
		if errors.Is(err, leveldb.ErrNotFound) {
			return nil, storage.ErrNotFound
		}
		return nil, err
	}
	return swarm.NewChunk(swarm.NewAddress(out.Address), out.Data).
		WithStamp(postage.NewStamp(out.BatchID, out.Index, out.Timestamp, out.Sig)), nil
}
func (db *DB) get(mode storage.ModeGet, addr swarm.Address) (out shed.Item, err error) {
	item := addressToItem(addr)
	out, err = db.retrievalDataIndex.Get(item)
	if err != nil {
		return out, err
	}
	switch mode {
	case storage.ModeGetRequest:
		db.updateGCItems(out)
	case storage.ModeGetPin:
		pinnedItem, err := db.pinIndex.Get(item)
		if err != nil {
			return out, err
		}
		return pinnedItem, nil
	case storage.ModeGetSync:
	case storage.ModeGetLookup:
	default:
		return out, ErrInvalidMode
	}
	return out, nil
}
func (db *DB) updateGCItems(items ...shed.Item) {
	if db.updateGCSem != nil {
		db.updateGCSem <- struct{}{}
	}
	db.updateGCWG.Add(1)
	go func() {
		defer db.updateGCWG.Done()
		if db.updateGCSem != nil {
			defer func() { <-db.updateGCSem }()
		}
		db.metrics.GCUpdate.Inc()
		defer totalTimeMetric(db.metrics.TotalTimeUpdateGC, time.Now())
		for _, item := range items {
			err := db.updateGC(item)
			if err != nil {
				db.metrics.GCUpdateError.Inc()
				db.logger.Errorf("localstore update gc: %v", err)
			}
		}
		if testHookUpdateGC != nil {
			testHookUpdateGC()
		}
	}()
}