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)) |
| 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 |