OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The LUCI Authors. All rights reserved. | |
2 // Use of this source code is governed under the Apache License, Version 2.0 | |
3 // that can be found in the LICENSE file. | |
4 | |
5 package memory | |
6 | |
7 import ( | |
8 "bytes" | |
9 | |
10 "github.com/luci/gae/service/datastore/serialize" | |
11 ) | |
12 | |
13 type iterDefinition struct { | |
14 // The collection to iterate over | |
15 c memCollection | |
16 | |
17 // The prefix to always assert for every row. A nil prefix matches every row. | |
18 prefix []byte | |
19 | |
20 // prefixLen is the number of prefix bytes that the caller cares about. It | |
21 // may be <= len(prefix). When doing a multiIterator, this number will b e used | |
22 // to determine the amount of suffix to transfer accross iterators. This is | |
23 // used specifically when using builtin indexes to service ancestor quer ies. | |
24 // The builtin index represents the ancestor key with prefix bytes, but in a | |
25 // multiIterator context, it wants the entire key to be included in the | |
26 // suffix. | |
27 prefixLen int | |
28 | |
29 // The start cursor. It's appended to prefix to find the first row. | |
30 start []byte | |
31 | |
32 // The end cursor. It's appended to prefix to find the last row (which i s not | |
33 // included in the interation result). If this is nil, then there's no e nd | |
34 // except the natural end of the collection. | |
35 end []byte | |
36 } | |
37 | |
38 func multiIterate(defs []*iterDefinition, cb func(suffix []byte) error) error { | |
39 if len(defs) == 0 { | |
40 return nil | |
41 } | |
42 | |
43 ts := make([]*iterator, len(defs)) | |
44 prefixLens := make([]int, len(defs)) | |
45 for i, def := range defs { | |
46 // bind i so that the defer below doesn't get goofed by the loop variable | |
47 i := i | |
48 ts[i] = def.mkIter() | |
49 prefixLens[i] = def.prefixLen | |
50 } | |
51 | |
52 suffix := []byte(nil) | |
53 skip := -1 | |
54 | |
55 MainLoop: | |
56 for { | |
57 for idx, it := range ts { | |
58 if skip >= 0 && skip == idx { | |
59 continue | |
60 } | |
61 | |
62 pfxLen := prefixLens[idx] | |
63 it.skip(serialize.Join(it.def.prefix[:pfxLen], suffix)) | |
iannucci
2017/01/07 19:06:17
:O
\o/
dnj
2017/01/08 03:38:14
:D Yeah I think we both disliked the complexity of
| |
64 ent := it.next() | |
65 if ent == nil { | |
66 // we hit the end of an iterator, we're now done with the whole | |
67 // query. | |
68 return nil | |
69 } | |
70 sfxRO := ent.key[pfxLen:] | |
71 | |
72 if bytes.Compare(sfxRO, suffix) > 0 { | |
73 // this row has a higher suffix than anything we 've seen before. Set | |
74 // ourself to be the skip, and resart this loop from the top. | |
75 suffix = append(suffix[:0], sfxRO...) | |
76 skip = idx | |
77 if idx != 0 { | |
78 // no point to restarting on the 0th ind ex | |
79 continue MainLoop | |
80 } | |
81 } | |
82 } | |
83 | |
84 if err := cb(suffix); err != nil { | |
85 return err | |
86 } | |
87 suffix = nil | |
88 skip = -1 | |
89 } | |
90 } | |
91 | |
92 type iterator struct { | |
93 def *iterDefinition | |
94 base memIterator | |
95 | |
96 start []byte | |
97 end []byte | |
98 lastKey []byte | |
99 } | |
100 | |
101 func (def *iterDefinition) mkIter() *iterator { | |
102 if !def.c.IsReadOnly() { | |
103 panic("attempting to make an iterator with r/w collection") | |
104 } | |
105 | |
106 it := iterator{ | |
107 def: def, | |
108 } | |
109 | |
110 // convert the suffixes from the iterDefinition into full rows for the | |
111 // underlying storage. | |
112 it.start = serialize.Join(def.prefix, def.start) | |
113 if def.end != nil { | |
114 it.end = serialize.Join(def.prefix, def.end) | |
115 } | |
116 return &it | |
117 } | |
118 | |
119 func (it *iterator) skip(targ []byte) { | |
120 if bytes.Compare(targ, it.start) < 0 { | |
121 targ = it.start | |
122 } | |
123 if it.base == nil || bytes.Compare(targ, it.lastKey) > 0 { | |
124 // If our skip target is >= our last key, then create a new Iter ator | |
125 // starting from that target. | |
126 it.base = it.def.c.Iterator(targ) | |
127 } | |
128 } | |
129 | |
130 func (it *iterator) next() *storeEntry { | |
131 if it.base == nil { | |
132 it.skip(nil) | |
133 } | |
134 | |
135 ent := it.base.Next() | |
136 switch { | |
137 case ent == nil: | |
138 return nil | |
139 | |
140 case !bytes.HasPrefix(ent.key, it.def.prefix): | |
141 // we're no longer in prefix, terminate | |
142 return nil | |
143 | |
144 case it.end != nil && bytes.Compare(ent.key, it.end) >= 0: | |
145 // we hit our cap, terminate. | |
146 return nil | |
147 | |
148 default: | |
149 it.lastKey = ent.key | |
150 return ent | |
151 } | |
152 } | |
OLD | NEW |