OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package memory | 5 package memory |
6 | 6 |
7 import ( | 7 import ( |
8 "bytes" | 8 "bytes" |
9 "sync" | 9 "sync" |
10 | 10 |
11 "github.com/luci/gae/service/datastore" | |
11 "github.com/luci/gae/service/datastore/serialize" | 12 "github.com/luci/gae/service/datastore/serialize" |
12 "github.com/luci/gkvlite" | 13 "github.com/luci/gkvlite" |
13 ) | 14 ) |
14 | 15 |
15 type iterDefinition struct { | 16 type iterDefinition struct { |
16 // The collection to iterate over | 17 // The collection to iterate over |
17 c *memCollection | 18 c *memCollection |
18 | 19 |
19 // The prefix to always assert for every row. A nil prefix matches every row. | 20 // The prefix to always assert for every row. A nil prefix matches every row. |
20 prefix []byte | 21 prefix []byte |
21 | 22 |
22 // prefixLen is the number of prefix bytes that the caller cares about. It | 23 // prefixLen is the number of prefix bytes that the caller cares about. It |
23 // may be <= len(prefix). When doing a multiIterator, this number will b e used | 24 // may be <= len(prefix). When doing a multiIterator, this number will b e used |
24 // to determine the amount of suffix to transfer accross iterators. This is | 25 // to determine the amount of suffix to transfer accross iterators. This is |
25 // used specifically when using builtin indexes to service ancestor quer ies. | 26 // used specifically when using builtin indexes to service ancestor quer ies. |
26 // The builtin index represents the ancestor key with prefix bytes, but in a | 27 // The builtin index represents the ancestor key with prefix bytes, but in a |
27 // multiIterator context, it wants the entire key to be included in the | 28 // multiIterator context, it wants the entire key to be included in the |
28 // suffix. | 29 // suffix. |
29 prefixLen int | 30 prefixLen int |
30 | 31 |
31 // The start cursor. It's appended to prefix to find the first row. | 32 // The start cursor. It's appended to prefix to find the first row. |
32 start []byte | 33 start []byte |
33 | 34 |
34 // The end cursor. It's appended to prefix to find the last row (which i s not | 35 // The end cursor. It's appended to prefix to find the last row (which i s not |
35 // included in the interation result). If this is nil, then there's no e nd | 36 // included in the interation result). If this is nil, then there's no e nd |
36 // except the natural end of the collection. | 37 // except the natural end of the collection. |
37 end []byte | 38 end []byte |
38 } | 39 } |
39 | 40 |
40 func multiIterate(defs []*iterDefinition, cb func(suffix []byte) bool) { | 41 func multiIterate(defs []*iterDefinition, cb func(suffix []byte) error) error { |
41 if len(defs) == 0 { | 42 if len(defs) == 0 { |
42 » » return | 43 » » return nil |
43 } | 44 } |
44 | 45 |
45 ts := make([]*iterator, len(defs)) | 46 ts := make([]*iterator, len(defs)) |
46 prefixLens := make([]int, len(defs)) | 47 prefixLens := make([]int, len(defs)) |
47 for i, def := range defs { | 48 for i, def := range defs { |
48 // bind i so that the defer below doesn't get goofed by the loop variable | 49 // bind i so that the defer below doesn't get goofed by the loop variable |
49 i := i | 50 i := i |
50 ts[i] = def.mkIter() | 51 ts[i] = def.mkIter() |
51 prefixLens[i] = def.prefixLen | 52 prefixLens[i] = def.prefixLen |
52 defer ts[i].stop() | 53 defer ts[i].stop() |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
85 // no point to restarting on the 0th index | 86 // no point to restarting on the 0th index |
86 restart = true | 87 restart = true |
87 } | 88 } |
88 } | 89 } |
89 }) | 90 }) |
90 if stop || restart { | 91 if stop || restart { |
91 break | 92 break |
92 } | 93 } |
93 } | 94 } |
94 if stop { | 95 if stop { |
95 » » » return | 96 » » » return nil |
96 } | 97 } |
97 if restart { | 98 if restart { |
98 continue | 99 continue |
99 } | 100 } |
100 | 101 |
101 » » if !cb(suffix) { | 102 » » if err := cb(suffix); err != nil { |
102 » » » return | 103 » » » if err == datastore.Stop { |
104 » » » » err = nil | |
dnj
2015/12/14 22:35:02
WDYT about just "return nil" here and elsewhere th
iannucci
2015/12/14 23:03:09
done
| |
105 » » » } | |
106 » » » return err | |
103 } | 107 } |
104 suffix = nil | 108 suffix = nil |
105 skip = -1 | 109 skip = -1 |
106 } | 110 } |
107 } | 111 } |
108 | 112 |
109 type cmd struct { | 113 type cmd struct { |
110 targ []byte | 114 targ []byte |
111 cb func(*gkvlite.Item) | 115 cb func(*gkvlite.Item) |
112 } | 116 } |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
207 t.ch <- &cmd{targ, func(i *gkvlite.Item) { | 211 t.ch <- &cmd{targ, func(i *gkvlite.Item) { |
208 defer close(waiter) | 212 defer close(waiter) |
209 | 213 |
210 if i == nil { | 214 if i == nil { |
211 t.stop() | 215 t.stop() |
212 } | 216 } |
213 cb(i) | 217 cb(i) |
214 }} | 218 }} |
215 <-waiter | 219 <-waiter |
216 } | 220 } |
OLD | NEW |