func (d *Diskstore) Wait(ctx context.Context) error {
	select {
	case <-ctx.Done():
		return ctx.Err()
	case <-d.warm:
		return nil
	}
}
Wait waits for the disk to read all files.

When the disk is initialized it will spawn a goroutine
to read all files in the configured path, if there are many
files it will typically take a while.

The method returns the context's error if canceled, otherwise
it will block until the disk cache is warm.
package antcache
import (
	"context"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"sync"
	"time"
	"github.com/golang/snappy"
)
type file struct {
	key   uint64
	path  string
	mtime time.Time
	size  int64
}
type DiskOption func(*Diskstore) error
func Maxage(age time.Duration) DiskOption {
	return func(ds *Diskstore) error {
		ds.maxage = age
		return nil
	}
}
func Maxsize(size int64) DiskOption {
	return func(ds *Diskstore) error {
		ds.maxsize = size
		return nil
	}
}
func SweepEvery(d time.Duration) DiskOption {
	return func(ds *Diskstore) error {
		if d > 0 {
			ds.ticker = time.NewTicker(d)
		} else {
			ds.ticker.Stop()
			ds.ticker = nil
		}
		return nil
	}
}
func Compress() DiskOption {
	return func(ds *Diskstore) error {
		ds.compress = true
		return nil
	}
}
type DebugFunc func(format string, args ...interface{})
func Debug(f DebugFunc) DiskOption {
	return func(ds *Diskstore) error {
		ds.debug = f
		return nil
	}
}
type Diskstore struct {
	path     string
	dir      *os.File
	maxage   time.Duration
	maxsize  int64
	stop     chan struct{}
	warm     chan struct{}
	wg       sync.WaitGroup
	ticker   *time.Ticker
	readymu  sync.RWMutex
	ready    map[uint64]file
	now      func() time.Time
	debug    DebugFunc
	compress bool
}
func Open(path string, opts ...DiskOption) (*Diskstore, error) {
	disk := &Diskstore{
		path:     path,
		maxage:   24 * time.Hour,
		maxsize:  1 << 30,
		stop:     make(chan struct{}),
		wg:       sync.WaitGroup{},
		warm:     make(chan struct{}),
		readymu:  sync.RWMutex{},
		ready:    make(map[uint64]file),
		ticker:   time.NewTicker(5 * time.Minute),
		now:      time.Now,
		debug:    nil,
		compress: false,
	}
	for _, opt := range opts {
		if err := opt(disk); err != nil {
			return nil, err
		}
	}
	if err := disk.init(); err != nil {
		return nil, err
	}
	disk.wg.Add(1)
	go disk.warmup()
	if disk.ticker != nil {
		disk.wg.Add(1)
		go disk.sweeper()
	}
	return disk, nil
}
func (d *Diskstore) debugf(format string, args ...interface{}) {
	if d.debug != nil {
		d.debug("antcache/disk: "+format, args...)
	}
}
func (d *Diskstore) init() error {
	if !filepath.IsAbs(d.path) {
		return fmt.Errorf("antcache: disk expects an absolute path, got %q", d.path)
	}
	f, err := os.Open(d.path)
	if err != nil {
		return fmt.Errorf("antcache: disk %w", err)
	}
	stat, err := f.Stat()
	if err != nil {
		f.Close()
		return fmt.Errorf("antcache: disk stat %q - %w", d.path, err)
	}
	if !stat.IsDir() {
		f.Close()
		return fmt.Errorf("antcache: disk expected a directory")
	}
	d.debugf("opened root %s", d.path)
	d.dir = f
	return nil
}