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

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

Issue 2604943002: impl/memory: Replace gkvlite with "treapstore". (Closed)
Patch Set: Update API for get/create. Created 3 years, 11 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
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698