Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(828)

Side by Side Diff: impl/memory/gkvlite_iter.go

Issue 1300493002: Add single-collection gkvlite iterator. (Closed) Base URL: https://github.com/luci/gae.git@refactor_service
Patch Set: remove rewind check Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | impl/memory/gkvlite_iter_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 package memory
6
7 import (
8 "bytes"
9 "sync"
10
11 "github.com/luci/gkvlite"
12 )
13
14 // TODO(riannucci): Add a multi-iterator which allows:
15 // multiple collections
16 // sort smallest collection -> largest collection
17 // constant prefixes for each collection
18 // start + end partial suffixes
19 // * these are appended to the prefix for the collection to narrow the scan
20 // range. The collection scans will start at >= prefix+start suffix, and
21 // will scan until > prefix+end suffix (excluding this larger row).
22 // produces hits (a suffix+value) when all collections contain the same prefix
23 // and the same suffix
24 // * a hit value will have
25 // - a []byte suffix which is the matching suffix of every collection.
26 // The caller already knows the prefix for each collection. The caller
27 // may need to parse the suffix to separate the sort order(s) from the
28 // Key.
29 // dedup
30 // on each hit, the row values are concatenated and compared to the
31 // concatenated prefixes+startsuffix. If it's <=, it's skipped.
32
33 type cmd struct {
34 targ []byte
35 cb func(*gkvlite.Item)
36 }
37
38 type iterator struct {
39 stopper sync.Once
40
41 stopped bool
42 prev []byte
43 ch chan<- *cmd
44 }
45
46 func newIterable(coll *memCollection, end []byte) *iterator {
47 cmdChan := make(chan *cmd)
48 ret := &iterator{
49 ch: cmdChan,
50 }
51
52 go func() {
53 defer ret.stop()
54 c := (*cmd)(nil)
55 ensureCmd := func() bool {
56 if c == nil {
57 c = <-cmdChan
58 if c == nil { // stop()
59 return false
60 }
61 }
62 return true
63 }
64 for {
65 if !ensureCmd() {
66 return
67 }
68 previous := c.targ
69 needCallback := true
70 coll.VisitItemsAscend(c.targ, true, func(i *gkvlite.Item ) bool {
71 if !ensureCmd() {
72 return false
73 }
74 if !bytes.Equal(previous, c.targ) {
75 // we need to start a new ascention func tion
76 needCallback = false
77 return false
78 }
79 if end != nil && bytes.Compare(i.Key, end) >= 0 {
80 // we hit our cap
81 ret.stop()
82 return false
83 }
84 c.cb(i)
85 previous = i.Key
86 c = nil
87 return true
88 })
89 if c != nil && needCallback {
90 c.cb(nil)
91 c = nil
92 }
93 }
94 }()
95
96 return ret
97 }
98
99 func (t *iterator) stop() {
100 t.stopper.Do(func() {
101 t.stopped = true
102 close(t.ch)
103 })
104 }
105
106 func (t *iterator) next(targ []byte, cb func(*gkvlite.Item)) {
107 if t.stopped {
108 cb(nil)
109 return
110 }
111
112 if targ == nil {
113 targ = t.prev
114 if targ == nil {
115 targ = []byte{}
116 }
117 }
118
119 waiter := make(chan struct{})
120 t.ch <- &cmd{targ, func(i *gkvlite.Item) {
121 defer close(waiter)
122
123 cb(i)
124 if i == nil {
125 t.stop()
126 } else {
127 t.prev = i.Key
128 }
129 }}
130 <-waiter
131 }
OLDNEW
« no previous file with comments | « no previous file | impl/memory/gkvlite_iter_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698