// MatchByPrefix returns the longest matching PrefixConfig. If the key // specified does not match an existing prefix, a panic will // result. Based on the comments in NewPrefixConfigMap, that example // will have a final list of PrefixConfig entries which look like: // // "/": config1 // "/db1": config2 // "/db1/table": config3 // "/db1/tablf": config2 // "/db2": config1 // "/db3": config4 // "/db4": config1 // // To find the longest matching prefix, we take the lower bound of the // specified key. func (p PrefixConfigMap) MatchByPrefix(key proto.Key) *PrefixConfig { n := sort.Search(len(p), func(i int) bool { return key.Compare(p[i].Prefix) < 0 }) if n == 0 || n > len(p) { panic("should never match a key outside of default range") } // If the matched prefix config is already canonical, return it immediately. pc := p[n-1] if pc.Canonical == nil { return pc } // Otherwise, search for the canonical prefix config. n = sort.Search(len(p), func(i int) bool { return pc.Canonical.Compare(p[i].Prefix) <= 0 }) // Should find an exact match every time. if n >= len(p) || !pc.Canonical.Equal(p[n].Prefix) { panic(fmt.Sprintf("canonical lookup for key %q failed", string(pc.Canonical))) } return p[n] }
// VisitPrefixes invokes the visitor function for each prefix overlapped // by the specified key range [start, end). If visitor returns done=true // or an error, the visitation is halted. func (p PrefixConfigMap) VisitPrefixes(start, end proto.Key, visitor func(start, end proto.Key, config gogoproto.Message) (bool, error)) error { comp := start.Compare(end) if comp > 0 { return util.Errorf("start key %q not less than or equal to end key %q", start, end) } startIdx := sort.Search(len(p), func(i int) bool { return start.Compare(p[i].Prefix) < 0 }) // Common case of start == end. endIdx := startIdx if comp != 0 { endIdx = sort.Search(len(p), func(i int) bool { return end.Compare(p[i].Prefix) < 0 }) } if startIdx > len(p) || endIdx > len(p) { return util.Errorf("start and/or end keys (%q, %q) fall outside prefix range; "+ "startIdx: %d, endIdx: %d, len(p): %d", start, end, startIdx, endIdx, len(p)) } if startIdx == endIdx { _, err := visitor(start, end, p[startIdx-1].Config) return err } for i := startIdx; i < endIdx; i++ { done, err := visitor(start, p[i].Prefix, p[i-1].Config) if done || err != nil { return err } if p[i].Prefix.Equal(end) { return nil } start = p[i].Prefix } done, err := visitor(start, end, p[endIdx-1].Config) if done || err != nil { return err } return nil }