blob: 1390853034b5cc603816bc19c8153dc774d23a46 [file] [log] [blame]
Robin Thellendac59e972014-08-19 18:26:11 -07001package stats
2
3import (
4 "path"
5 "sort"
6 "time"
7
Jiri Simsa519c5072014-09-17 21:37:57 -07008 "veyron.io/veyron/veyron/lib/glob"
Robin Thellendac59e972014-08-19 18:26:11 -07009)
10
11// Glob returns the name and (optionally) the value of all the objects that
12// match the given pattern and have been updated since 'updatedSince'. The
13// 'root' argument is the name of the object where the pattern starts.
14// Example:
15// a/b/c
16// a/b/d
17// b/e/f
18// Glob("", "...", time.Time{}, true) will return "a/b/c", "a/b/d", "b/e/f" and
19// their values.
20// Glob("a/b", "*", time.Time{}, true) will return "c", "d" and their values.
21func Glob(root string, pattern string, updatedSince time.Time, includeValues bool) *GlobIterator {
22 g, err := glob.Parse(pattern)
23 if err != nil {
24 return &GlobIterator{err: err}
25 }
26 lock.RLock()
27 defer lock.RUnlock()
28 node := findNodeLocked(root, false)
29 if node == nil {
30 return &GlobIterator{err: ErrNotFound}
31 }
32 var out []KeyValue
33 globStepLocked("", g, node, updatedSince, includeValues, &out)
34 sort.Sort(keyValueSort(out))
35 return &GlobIterator{results: out}
36}
37
38// globStepLocked applies a glob recursively.
39func globStepLocked(prefix string, g *glob.Glob, n *node, updatedSince time.Time, includeValues bool, result *[]KeyValue) {
Robin Thellend14a09ef2014-08-29 13:55:19 -070040 if g.Len() == 0 {
41 if updatedSince.IsZero() || (n.object != nil && !n.object.LastUpdate().Before(updatedSince)) {
42 var v interface{}
43 if includeValues && n.object != nil {
44 v = n.object.Value()
45 }
46 *result = append(*result, KeyValue{prefix, v})
Robin Thellendac59e972014-08-19 18:26:11 -070047 }
Robin Thellendac59e972014-08-19 18:26:11 -070048 }
49 if g.Finished() {
50 return
51 }
52 for name, child := range n.children {
Tilak Sharma577ce8d2014-09-22 10:25:00 -070053 if ok, _, left := g.MatchInitialSegment(name); ok {
Robin Thellendac59e972014-08-19 18:26:11 -070054 globStepLocked(path.Join(prefix, name), left, child, updatedSince, includeValues, result)
55 }
56 }
57}
58
59// KeyValue stores a Key and a Value.
60type KeyValue struct {
61 Key string
62 Value interface{}
63}
64
65// keyValueSort is used to sort a slice of KeyValue objects.
66type keyValueSort []KeyValue
67
68func (s keyValueSort) Len() int {
69 return len(s)
70}
71
72func (s keyValueSort) Less(i, j int) bool {
73 return s[i].Key < s[j].Key
74}
75
76func (s keyValueSort) Swap(i, j int) {
77 s[i], s[j] = s[j], s[i]
78}
79
80type GlobIterator struct {
81 results []KeyValue
82 next KeyValue
83 err error
84}
85
86// Advance stages the next element so that the client can retrieve it with
87// Value(). It returns true iff there is an element to retrieve. The client
88// must call Advance() before calling Value(). Advance may block if an element
89// is not immediately available.
90func (i *GlobIterator) Advance() bool {
91 if len(i.results) == 0 {
92 return false
93 }
94 i.next = i.results[0]
95 i.results = i.results[1:]
96 return true
97}
98
99// Value returns the element that was staged by Advance. Value does not block.
100func (i GlobIterator) Value() KeyValue {
101 return i.next
102}
103
104// Err returns a non-nil error iff the stream encountered any errors. Err does
105// not block.
106func (i GlobIterator) Err() error {
107 return i.err
108}