func (r *ring) apply(f func([]byte, *entry) error) error {
	var (
		wg  sync.WaitGroup
		res = make(chan error, len(r.partitions))
	)
	for _, p := range r.partitions {
		wg.Add(1)
		go func(p *partition) {
			defer wg.Done()
			p.mu.RLock()
			for k, e := range p.store {
				if err := f([]byte(k), e); err != nil {
					res <- err
					p.mu.RUnlock()
					return
				}
			}
			p.mu.RUnlock()
		}(p)
	}
	go func() {
		wg.Wait()
		close(res)
	}()
	for err := range res {
		if err != nil {
			return err
		}
	}
	return nil
}
apply applies the provided function to every entry in the ring under a read
lock using a separate goroutine for each partition. The provided function
will be called with each key and the corresponding entry. The first error
encountered will be returned, if any. apply is safe for use by multiple
goroutines.
package tsm1
import (
	"fmt"
	"sync"
	"sync/atomic"
	"github.com/cespare/xxhash"
	"github.com/influxdata/influxdb/pkg/bytesutil"
)
const partitions = 16
type ring struct {
	keysHint int64
	partitions []*partition
}
func newring(n int) (*ring, error) {
	if n <= 0 || n > partitions {
		return nil, fmt.Errorf("invalid number of paritions: %d", n)
	}
	r := ring{
		partitions: make([]*partition, n),  
	}
	for i := 0; i < len(r.partitions); i++ {
		r.partitions[i] = &partition{
			store: make(map[string]*entry),
		}
	}
	return &r, nil
}
func (r *ring) reset() {
	for _, partition := range r.partitions {
		partition.reset()
	}
	r.keysHint = 0
}
func (r *ring) getPartition(key []byte) *partition {
	return r.partitions[int(xxhash.Sum64(key)%partitions)]
}
func (r *ring) entry(key []byte) *entry {
	return r.getPartition(key).entry(key)
}
func (r *ring) write(key []byte, values Values) (bool, error) {
	return r.getPartition(key).write(key, values)
}
func (r *ring) add(key []byte, entry *entry) {
	r.getPartition(key).add(key, entry)
	atomic.AddInt64(&r.keysHint, 1)
}
func (r *ring) remove(key []byte) {
	r.getPartition(key).remove(key)
	if r.keysHint > 0 {
		atomic.AddInt64(&r.keysHint, -1)
	}
}
func (r *ring) keys(sorted bool) [][]byte {
	keys := make([][]byte, 0, atomic.LoadInt64(&r.keysHint))
	for _, p := range r.partitions {
		keys = append(keys, p.keys()...)
	}
	if sorted {
		bytesutil.Sort(keys)
	}
	return keys
}
func (r *ring) count() int {
	var n int
	for _, p := range r.partitions {
		n += p.count()
	}
	return n
}