func readFieldIndex(ctx context.Context, dir string, recRange biopb.CoordRange, field string) (index biopb.PAMFieldIndex, err error) {
	path := FieldDataPath(dir, recRange, field)
	in, err := file.Open(ctx, path)
	if err != nil {
		return index, err
	}
	defer file.CloseAndReport(ctx, in, &err)
	rio := recordio.NewScanner(in.Reader(ctx), recordio.ScannerOpts{})
	trailer := rio.Trailer()
	if len(trailer) == 0 {
		return index, errors.E(err, fmt.Sprintf("readfieldindex %v: file does not contain an index", path))
	}
	if err := index.Unmarshal(trailer); err != nil {
		return index, errors.E(err, fmt.Sprintf("%v: unmarshal field index for field '%s'", path, field))
	}
	err = validateFieldIndex(index)
	if e := rio.Finish(); e != nil && err == nil {
		err = e
	}
	return index, err
}
readFieldIndex reads the index for, "dir/recRange.field".
package pamutil
import (
	"context"
	"fmt"
	"runtime"
	"github.com/grailbio/base/errors"
	"github.com/grailbio/base/file"
	"github.com/grailbio/base/log"
	"github.com/grailbio/base/recordio"
	"github.com/grailbio/bio/biopb"
)
type ShardIndex struct {
	Range biopb.CoordRange
	ApproxFileBytes int64
	Blocks []biopb.PAMBlockIndexEntry
}
func validateFieldIndex(index biopb.PAMFieldIndex) error {
	for _, block := range index.Blocks {
		if block.NumRecords == 0 {
			return fmt.Errorf("corrupt block index: %+v", block)
		}
	}
	return nil
}
func fieldFileSize(ctx context.Context, dir string, recRange biopb.CoordRange, field string) int64 {
	path := FieldDataPath(dir, recRange, field)
	stat, err := file.Stat(ctx, path)
	if err != nil {
		log.Debug.Printf("stat %v: %v", path, err)
		return 0
	}
	return stat.Size()
}