func (d *Datastore) Sync(ctx context.Context, prefix ds.Key) error {
	var merr error
	dstores, prefixes, rest := d.lookupAll(prefix)
	for i, suffix := range rest {
		if err := dstores[i].Sync(ctx, suffix); err != nil {
			merr = multierr.Append(merr, fmt.Errorf(
				"syncing datastore at %s: %w",
				prefixes[i].String(),
				err,
			))
		}
	}
	return merr
}
Sync implements Datastore.Sync
package mount
import (
	"container/heap"
	"context"
	"errors"
	"fmt"
	"sort"
	"strings"
	"sync"
	ds "github.com/ipfs/go-datastore"
	"github.com/ipfs/go-datastore/query"
	"go.uber.org/multierr"
)
var (
	ErrNoMount = errors.New("no datastore mounted for this key")
)
type Mount struct {
	Prefix    ds.Key
	Datastore ds.Datastore
}
func New(mounts []Mount) *Datastore {
	m := make([]Mount, len(mounts))
	copy(m, mounts)
	sort.Slice(m, func(i, j int) bool { return m[i].Prefix.String() > m[j].Prefix.String() })
	return &Datastore{mounts: m}
}
type Datastore struct {
	mounts []Mount
}
var _ ds.Datastore = (*Datastore)(nil)
func (d *Datastore) lookup(key ds.Key) (ds.Datastore, ds.Key, ds.Key) {
	for _, m := range d.mounts {
		if m.Prefix.IsAncestorOf(key) {
			s := strings.TrimPrefix(key.String(), m.Prefix.String())
			k := ds.NewKey(s)
			return m.Datastore, m.Prefix, k
		}
	}
	return nil, ds.NewKey("/"), key
}
type queryResults struct {
	mount   ds.Key
	results query.Results
	next    query.Result
}
func (qr *queryResults) advance() bool {
	if qr.results == nil {
		return false
	}
	qr.next = query.Result{}
	r, more := qr.results.NextSync()
	if !more {
		err := qr.results.Close()
		qr.results = nil
		if err != nil {
			qr.next = query.Result{Error: err}
			return true
		}
		return false
	}
	r.Key = qr.mount.Child(ds.RawKey(r.Key)).String()
	qr.next = r
	return true
}
type querySet struct {
	query query.Query
	heads []*queryResults
}
func (h *querySet) Len() int {
	return len(h.heads)
}
func (h *querySet) Less(i, j int) bool {
	return query.Less(h.query.Orders, h.heads[i].next.Entry, h.heads[j].next.Entry)
}
func (h *querySet) Swap(i, j int) {
	h.heads[i], h.heads[j] = h.heads[j], h.heads[i]
}
func (h *querySet) Push(x interface{}) {
	h.heads = append(h.heads, x.(*queryResults))
}
func (h *querySet) Pop() interface{} {
	i := len(h.heads) - 1
	last := h.heads[i]
	h.heads[i] = nil
	h.heads = h.heads[:i]
	return last
}
func (h *querySet) close() error {
	var errs []error
	for _, qr := range h.heads {
		err := qr.results.Close()
		if err != nil {
			errs = append(errs, err)
		}
	}
	h.heads = nil
	if len(errs) > 0 {
		return errs[0]
	}
	return nil
}
func (h *querySet) addResults(mount ds.Key, results query.Results) {
	r := &queryResults{
		results: results,
		mount:   mount,
	}
	if r.advance() {
		heap.Push(h, r)
	}
}
func (h *querySet) next() (query.Result, bool) {
	if len(h.heads) == 0 {
		return query.Result{}, false
	}
	head := h.heads[0]
	next := head.next
	if head.advance() {
		heap.Fix(h, 0)
	} else {
		heap.Remove(h, 0)
	}
	return next, true
}
func (d *Datastore) lookupAll(key ds.Key) (dst []ds.Datastore, mountpoint, rest []ds.Key) {
	for _, m := range d.mounts {
		if m.Prefix.IsDescendantOf(key) {
			dst = append(dst, m.Datastore)
			mountpoint = append(mountpoint, m.Prefix)
			rest = append(rest, ds.NewKey("/"))
		} else if m.Prefix.Equal(key) || m.Prefix.IsAncestorOf(key) {
			r := strings.TrimPrefix(key.String(), m.Prefix.String())
			dst = append(dst, m.Datastore)
			mountpoint = append(mountpoint, m.Prefix)
			rest = append(rest, ds.NewKey(r))
			break
		}
	}
	return dst, mountpoint, rest
}
func (d *Datastore) Put(ctx context.Context, key ds.Key, value []byte) error {
	cds, _, k := d.lookup(key)
	if cds == nil {
		return ErrNoMount
	}
	return cds.Put(ctx, k, value)
}