github.com/cayleygraph/cayley@v0.7.7/graph/kv/all_iterator.go (about) 1 // Copyright 2014 The Cayley Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package kv 16 17 import ( 18 "context" 19 20 "github.com/cayleygraph/cayley/graph" 21 "github.com/cayleygraph/cayley/graph/proto" 22 "github.com/cayleygraph/quad" 23 ) 24 25 var _ graph.IteratorFuture = &AllIterator{} 26 27 type AllIterator struct { 28 it *allIterator 29 graph.Iterator 30 } 31 32 type constraint struct { 33 dir quad.Direction 34 val Int64Value 35 } 36 37 func NewAllIterator(nodes bool, qs *QuadStore, cons *constraint) *AllIterator { 38 it := &AllIterator{ 39 it: newAllIterator(nodes, qs, cons), 40 } 41 it.Iterator = graph.NewLegacy(it.it, it) 42 return it 43 } 44 45 func (it *AllIterator) AsShape() graph.IteratorShape { 46 it.Close() 47 return it.it 48 } 49 50 func (it *AllIterator) Sorted() bool { return false } 51 52 var _ graph.IteratorShapeCompat = &allIterator{} 53 54 type allIterator struct { 55 nodes bool 56 qs *QuadStore 57 cons *constraint 58 } 59 60 func newAllIterator(nodes bool, qs *QuadStore, cons *constraint) *allIterator { 61 if nodes && cons != nil { 62 panic("cannot use a kv all iterator across nodes with a constraint") 63 } 64 return &allIterator{ 65 nodes: nodes, 66 qs: qs, 67 cons: cons, 68 } 69 } 70 71 func (it *allIterator) Iterate() graph.Scanner { 72 return newAllIteratorNext(it.nodes, it.qs, it.cons) 73 } 74 75 func (it *allIterator) Lookup() graph.Index { 76 return newAllIteratorContains(it.nodes, it.qs, it.cons) 77 } 78 79 func (it *allIterator) AsLegacy() graph.Iterator { 80 it2 := &AllIterator{it: it} 81 it2.Iterator = graph.NewLegacy(it, it2) 82 return it2 83 } 84 85 // No subiterators. 86 func (it *allIterator) SubIterators() []graph.IteratorShape { 87 return nil 88 } 89 90 func (it *allIterator) Size() (int64, bool) { 91 return it.qs.Size(), false 92 } 93 94 func (it *allIterator) String() string { 95 return "KVAll" 96 } 97 98 func (it *allIterator) Sorted() bool { return false } 99 100 func (it *allIterator) Optimize(ctx context.Context) (graph.IteratorShape, bool) { 101 return it, false 102 } 103 104 func (it *allIterator) Stats(ctx context.Context) (graph.IteratorCosts, error) { 105 return graph.IteratorCosts{ 106 ContainsCost: 1, 107 NextCost: 2, 108 Size: graph.Size{ 109 Size: it.qs.Size(), 110 Exact: false, 111 }, 112 }, nil 113 } 114 115 type allIteratorNext struct { 116 nodes bool 117 id uint64 118 buf []*proto.Primitive 119 prim *proto.Primitive 120 horizon int64 121 qs *QuadStore 122 err error 123 cons *constraint 124 } 125 126 func newAllIteratorNext(nodes bool, qs *QuadStore, cons *constraint) *allIteratorNext { 127 if nodes && cons != nil { 128 panic("cannot use a kv all iterator across nodes with a constraint") 129 } 130 return &allIteratorNext{ 131 nodes: nodes, 132 qs: qs, 133 horizon: qs.horizon(context.TODO()), 134 cons: cons, 135 } 136 } 137 138 func (it *allIteratorNext) TagResults(dst map[string]graph.Ref) {} 139 140 func (it *allIteratorNext) Close() error { 141 return nil 142 } 143 144 func (it *allIteratorNext) Err() error { 145 return it.err 146 } 147 148 func (it *allIteratorNext) Result() graph.Ref { 149 if it.id > uint64(it.horizon) { 150 return nil 151 } 152 if it.nodes { 153 return Int64Value(it.id) 154 } 155 if it.prim == nil { 156 return nil 157 } 158 return it.prim 159 } 160 161 const nextBatch = 100 162 163 func (it *allIteratorNext) Next(ctx context.Context) bool { 164 if it.err != nil { 165 return false 166 } 167 for { 168 if len(it.buf) == 0 { 169 if it.id+1 > uint64(it.horizon) { 170 return false 171 } 172 ids := make([]uint64, 0, nextBatch) 173 for i := 0; i < nextBatch; i++ { 174 it.id++ 175 if it.id > uint64(it.horizon) { 176 break 177 } 178 ids = append(ids, it.id) 179 } 180 if len(ids) == 0 { 181 return false 182 } 183 it.buf, it.err = it.qs.getPrimitives(ctx, ids) 184 if it.err != nil || len(it.buf) == 0 { 185 return false 186 } 187 } else { 188 it.buf = it.buf[1:] 189 } 190 for ; len(it.buf) > 0; it.buf = it.buf[1:] { 191 p := it.buf[0] 192 it.prim = p 193 if p == nil || p.Deleted { 194 continue 195 } 196 it.id = it.prim.ID 197 if p.IsNode() && it.nodes { 198 return true 199 } 200 if !p.IsNode() && !it.nodes { 201 if it.cons == nil { 202 return true 203 } 204 if Int64Value(p.GetDirection(it.cons.dir)) == it.cons.val { 205 return true 206 } 207 } 208 } 209 } 210 } 211 212 func (it *allIteratorNext) NextPath(ctx context.Context) bool { 213 return false 214 } 215 216 func (it *allIteratorNext) String() string { 217 return "KVAllNext" 218 } 219 220 func (it *allIteratorNext) Sorted() bool { return false } 221 222 type allIteratorContains struct { 223 nodes bool 224 id uint64 225 prim *proto.Primitive 226 horizon int64 227 qs *QuadStore 228 err error 229 cons *constraint 230 } 231 232 func newAllIteratorContains(nodes bool, qs *QuadStore, cons *constraint) *allIteratorContains { 233 if nodes && cons != nil { 234 panic("cannot use a kv all iterator across nodes with a constraint") 235 } 236 return &allIteratorContains{ 237 nodes: nodes, 238 qs: qs, 239 horizon: qs.horizon(context.TODO()), 240 cons: cons, 241 } 242 } 243 244 func (it *allIteratorContains) TagResults(dst map[string]graph.Ref) {} 245 246 func (it *allIteratorContains) Close() error { 247 return nil 248 } 249 250 func (it *allIteratorContains) Err() error { 251 return it.err 252 } 253 254 func (it *allIteratorContains) Result() graph.Ref { 255 if it.id > uint64(it.horizon) { 256 return nil 257 } 258 if it.nodes { 259 return Int64Value(it.id) 260 } 261 if it.prim == nil { 262 return nil 263 } 264 return it.prim 265 } 266 267 func (it *allIteratorContains) NextPath(ctx context.Context) bool { 268 return false 269 } 270 271 func (it *allIteratorContains) Contains(ctx context.Context, v graph.Ref) bool { 272 // TODO(dennwc): This method doesn't check if the primitive still exists in the store. 273 // It's okay if we assume we provide the snapshot of data, though. 274 // However, passing a hand-crafted Ref will cause invalid results. 275 // Same is true for QuadIterator. 276 if it.nodes { 277 x, ok := v.(Int64Value) 278 if !ok { 279 return false 280 } 281 it.id = uint64(x) 282 return it.id <= uint64(it.horizon) 283 } 284 p, ok := v.(*proto.Primitive) 285 if !ok { 286 return false 287 } 288 it.prim = p 289 it.id = it.prim.ID 290 if it.cons == nil { 291 return true 292 } 293 if Int64Value(it.prim.GetDirection(it.cons.dir)) != it.cons.val { 294 return false 295 } 296 return true 297 } 298 299 func (it *allIteratorContains) String() string { 300 return "KVAllContains" 301 } 302 303 func (it *allIteratorContains) Sorted() bool { return false }