func (w *Whisper) Find(query string) []Glob {
	w.RLock()
	defer w.RUnlock()
	var star int
	if star = strings.Index(query, "*"); star == -1 {
		if _, ok := w.l.Find(query); !ok {
			return nil
		}
		return []Glob{{Metric: query, IsLeaf: true}}
	}
	var response []Glob
	if star == len(query)-1 {
		query = strings.TrimSuffix(query, "*")
		l := len(query)
		seen := make(map[string]bool)
		w.l.Prefix(query, func(k string, v interface{}) bool {
			dot := strings.IndexByte(k[l:], '.')
			var leaf bool
			m := k
			if dot == -1 {
				leaf = true
			} else {
				m = k[:dot+l]
			}
			if !seen[m] {
				seen[m] = true
				response = append(response, Glob{Metric: m, IsLeaf: leaf})
			}
			return false
		})
	} else {
		query = strings.Replace(query, ".", "/", -1)
		paths := w.l.QueryPath(query)
		for _, p := range paths {
			m := strings.Replace(p, "/", ".", -1)
			var leaf bool
			if strings.HasSuffix(p, ".wsp") {
				m = strings.TrimSuffix(m, ".wsp")
				leaf = true
			}
			response = append(response, Glob{Metric: m, IsLeaf: leaf})
		}
	}
	sort.Sort(globByName(response))
	return response
}
TODO(dgryski): this needs most of the logic in grobian/carbsonerver:findHandler()
Find expands a glob query across the metrics in the store
package mwhisper
import (
	"math"
	"path/filepath"
	"sort"
	"strings"
	"sync"
	"github.com/armon/go-radix"
	"github.com/dgryski/go-trigram"
	"github.com/wangjohn/quickselect"
)
type MetricID uint32
type Count uint32
type Whisper struct {
	sync.RWMutex
	t0 int32
	idx    int
	epochs []map[MetricID]Count
	midx    int
	minutes []map[MetricID]Count
	l *lookup
}
func NewWhisper(t0 int32, ecap, cap int, options ...func(*Whisper) error) *Whisper {
	t0 = t0 - (t0 % 60)
	epochs := make([]map[MetricID]Count, ecap)
	epochs[0] = make(map[MetricID]Count)
	minutes := make([]map[MetricID]Count, cap/60)
	minutes[0] = make(map[MetricID]Count)
	w := &Whisper{
		t0:      t0,
		epochs:  epochs,
		minutes: minutes,
		l:       newLookup(),
	}
	for _, o := range options {
		o(w)
	}
	return w
}
func TrigramCutoff(cutoff int) func(*Whisper) error {
	return func(w *Whisper) error {
		w.l.trigramCutoff = cutoff
		return nil
	}
}
func (w *Whisper) Set(t int32, metric string, val uint64) {
	count := Count(val)
	w.Lock()
	defer w.Unlock()
	if t == w.t0 {
		id := w.l.FindOrAdd(metric)
		m := w.epochs[w.idx]
		mm := w.minutes[w.midx]
		v := m[id]
		_, ok := mm[id]
		if !ok {
			w.l.AddRef(id)
		}
		m[id] = count
		mm[id] += count - v
		return
	}
	if t > w.t0 {
		for w.t0 < t {
			w.t0++
			w.idx++
			if w.idx >= len(w.epochs) {
				w.idx = 0
			}
			w.epochs[w.idx] = nil
			if w.t0%60 == 0 {
				w.midx++
				if w.midx >= len(w.minutes) {
					w.midx = 0
				}
				mm := w.minutes[w.midx]
				for id := range mm {
					w.l.DelRef(id)
				}
				w.minutes[w.midx] = nil
			}
		}
		id := w.l.FindOrAdd(metric)
		w.epochs[w.idx] = map[MetricID]Count{id: count}
		if mm := w.minutes[w.midx]; mm == nil {
			w.l.AddRef(id)
			w.minutes[w.midx] = map[MetricID]Count{id: count}
		} else {
			_, ok := mm[id]
			if !ok {
				w.l.AddRef(id)
			}
			mm[id] += count
		}
		return
	}
	back := int(w.t0 - t)
	if back >= len(w.epochs) {
		return
	}
	idx := w.idx - back
	if idx < 0 {
		idx += len(w.epochs)
	}
	m := w.epochs[idx]
	if m == nil {
		m = make(map[MetricID]Count)
		w.epochs[idx] = m
	}
	midx := w.midx - back/60
	if midx < 0 {
		midx += len(w.minutes)
	}
	mm := w.minutes[midx]
	if mm == nil {
		mm = make(map[MetricID]Count)
		w.minutes[midx] = mm
	}
	id := w.l.FindOrAdd(metric)
	v := m[id]
	_, ok := mm[id]
	if !ok {
		w.l.AddRef(id)
	}
	m[id] = count
	mm[id] += count - v
}
type Fetched struct {
	From   int32
	Until  int32
	Step   int32
	Values []float64
}
func (w *Whisper) Fetch(metric string, from int32, until int32) *Fetched {
	w.RLock()
	defer w.RUnlock()
	if from > w.t0 {
		return nil
	}
	id, ok := w.l.Find(metric)
	if !ok {
		return nil
	}
	if !w.l.Active(id) {
		return nil
	}
	if until < from {
		return nil
	}
	step := int32(1)
	maps := w.epochs
	idx := w.idx
	if min := w.t0 - int32(len(maps)) + 1; from < min {
		maps = w.minutes
		step = 60
		idx = w.midx
		if min = (w.t0 - w.t0%60) - int32(len(maps))*60 + 60; from < min {
			from = min
		}
	}
	idx -= int((w.t0 - from) / step)
	if idx < 0 {
		idx += len(maps)
	}
	if until > w.t0 {
		until = w.t0
	}
	from = from - (from % step)
	until = until - (until % step)
	points := (until - from + step) / step  
	if points < 0 {
		return nil
	}
	r := &Fetched{
		From:   from,
		Until:  until,
		Step:   step,
		Values: make([]float64, points),
	}
	l := len(maps)
	for p, t := 0, idx; p < int(points); p, t = p+1, t+1 {
		if t >= l {
			t = 0
		}
		m := maps[t]
		if v, ok := m[id]; ok {
			r.Values[p] = float64(v)
		} else {
			r.Values[p] = math.NaN()
		}
	}
	return r
}
type Glob struct {
	Metric string
	IsLeaf bool
}
type globByName []Glob
func (g globByName) Len() int           { return len(g) }
func (g globByName) Swap(i, j int)      { g[i], g[j] = g[j], g[i] }
func (g globByName) Less(i, j int) bool { return g[i].Metric < g[j].Metric }