github.com/cayleygraph/cayley@v0.7.7/graph/kv/quad_iterator.go (about) 1 // Copyright 2016 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 "fmt" 20 21 "github.com/cayleygraph/cayley/graph" 22 "github.com/cayleygraph/cayley/graph/proto" 23 "github.com/hidal-go/hidalgo/kv" 24 ) 25 26 var _ graph.IteratorFuture = &QuadIterator{} 27 28 type QuadIterator struct { 29 it *quadIterator 30 graph.Iterator 31 } 32 33 func NewQuadIterator(qs *QuadStore, ind QuadIndex, vals []uint64) *QuadIterator { 34 it := &QuadIterator{ 35 it: newQuadIterator(qs, ind, vals), 36 } 37 it.Iterator = graph.NewLegacy(it.it, it) 38 return it 39 } 40 41 func (it *QuadIterator) AsShape() graph.IteratorShape { 42 it.Close() 43 return it.it 44 } 45 46 func (it *QuadIterator) Sorted() bool { return true } 47 48 var _ graph.IteratorShapeCompat = &quadIterator{} 49 50 type quadIterator struct { 51 qs *QuadStore 52 ind QuadIndex 53 vals []uint64 54 55 size graph.Size 56 err error 57 } 58 59 func newQuadIterator(qs *QuadStore, ind QuadIndex, vals []uint64) *quadIterator { 60 return &quadIterator{ 61 qs: qs, 62 ind: ind, 63 vals: vals, 64 size: graph.Size{Size: -1}, 65 } 66 } 67 68 func (it *quadIterator) Iterate() graph.Scanner { 69 return newQuadIteratorNext(it.qs, it.ind, it.vals) 70 } 71 72 func (it *quadIterator) Lookup() graph.Index { 73 return newQuadIteratorContains(it.qs, it.ind, it.vals) 74 } 75 76 func (it *quadIterator) AsLegacy() graph.Iterator { 77 it2 := &QuadIterator{it: it} 78 it2.Iterator = graph.NewLegacy(it, it2) 79 return it2 80 } 81 82 func (it *quadIterator) SubIterators() []graph.IteratorShape { 83 return nil 84 } 85 86 func (it *quadIterator) getSize(ctx context.Context) (graph.Size, error) { 87 if it.err != nil { 88 return graph.Size{}, it.err 89 } else if it.size.Size >= 0 { 90 return it.size, nil 91 } 92 if len(it.ind.Dirs) == len(it.vals) { 93 sz, err := it.qs.indexSize(ctx, it.ind, it.vals) 94 if err != nil { 95 it.err = err 96 return graph.Size{}, it.err 97 } 98 it.size = sz 99 return sz, nil 100 } 101 return graph.Size{Size: 1 + it.qs.Size()/2, Exact: false}, nil 102 } 103 104 func (it *quadIterator) String() string { 105 return fmt.Sprintf("KVQuads(%v)", it.ind) 106 } 107 108 func (it *quadIterator) Sorted() bool { return true } 109 110 func (it *quadIterator) Optimize(ctx context.Context) (graph.IteratorShape, bool) { 111 return it, false 112 } 113 114 func (it *quadIterator) Stats(ctx context.Context) (graph.IteratorCosts, error) { 115 s, err := it.getSize(ctx) 116 return graph.IteratorCosts{ 117 ContainsCost: 1, 118 NextCost: 2, 119 Size: s, 120 }, err 121 } 122 123 type quadIteratorNext struct { 124 qs *QuadStore 125 ind QuadIndex 126 vals []uint64 127 128 tx kv.Tx 129 it kv.Iterator 130 done bool 131 132 err error 133 off int 134 ids []uint64 135 buf []*proto.Primitive 136 prim *proto.Primitive 137 } 138 139 func newQuadIteratorNext(qs *QuadStore, ind QuadIndex, vals []uint64) *quadIteratorNext { 140 return &quadIteratorNext{ 141 qs: qs, 142 ind: ind, 143 vals: vals, 144 } 145 } 146 147 func (it *quadIteratorNext) TagResults(dst map[string]graph.Ref) {} 148 149 func (it *quadIteratorNext) Close() error { 150 if it.it != nil { 151 if err := it.it.Close(); err != nil && it.err == nil { 152 it.err = err 153 } 154 if err := it.tx.Close(); err != nil && it.err == nil { 155 it.err = err 156 } 157 it.it = nil 158 it.tx = nil 159 } 160 return it.err 161 } 162 163 func (it *quadIteratorNext) Err() error { 164 return it.err 165 } 166 167 func (it *quadIteratorNext) Result() graph.Ref { 168 if it.off < 0 || it.prim == nil { 169 return nil 170 } 171 return it.prim 172 } 173 174 func (it *quadIteratorNext) ensureTx() bool { 175 if it.tx != nil { 176 return true 177 } 178 it.tx, it.err = it.qs.db.Tx(false) 179 if it.err != nil { 180 return false 181 } 182 it.tx = wrapTx(it.tx) 183 return true 184 } 185 186 func (it *quadIteratorNext) Next(ctx context.Context) bool { 187 it.prim = nil 188 if it.err != nil || it.done { 189 return false 190 } 191 if it.it == nil { 192 if !it.ensureTx() { 193 return false 194 } 195 it.it = it.tx.Scan(it.ind.Key(it.vals)) 196 if err := it.Err(); err != nil { 197 it.err = err 198 return false 199 } 200 } 201 for { 202 if len(it.buf) == 0 { 203 for len(it.ids[it.off:]) == 0 { 204 it.off = 0 205 it.ids = nil 206 it.buf = nil 207 if !it.it.Next(ctx) { 208 it.Close() 209 it.done = true 210 return false 211 } 212 it.ids, it.err = decodeIndex(it.it.Val()) 213 if it.err != nil { 214 return false 215 } 216 } 217 ids := it.ids[it.off:] 218 if len(ids) > nextBatch { 219 ids = ids[:nextBatch] 220 } 221 it.buf, it.err = it.qs.getPrimitivesFromLog(ctx, it.tx, ids) 222 if it.err != nil { 223 return false 224 } 225 } else { 226 it.buf, it.off = it.buf[1:], it.off+1 227 } 228 for ; len(it.buf) > 0; it.buf, it.off = it.buf[1:], it.off+1 { 229 p := it.buf[0] 230 if p == nil || p.Deleted { 231 continue 232 } 233 // TODO(dennwc): shouldn't this check the horizon? 234 it.prim = p 235 return true 236 } 237 } 238 } 239 240 func (it *quadIteratorNext) NextPath(ctx context.Context) bool { 241 return false 242 } 243 244 func (it *quadIteratorNext) String() string { 245 return fmt.Sprintf("KVQuadsNext(%v)", it.ind) 246 } 247 248 func (it *quadIteratorNext) Sorted() bool { return true } 249 250 type quadIteratorContains struct { 251 qs *QuadStore 252 ind QuadIndex 253 vals []uint64 254 255 err error 256 prim *proto.Primitive 257 } 258 259 func newQuadIteratorContains(qs *QuadStore, ind QuadIndex, vals []uint64) *quadIteratorContains { 260 return &quadIteratorContains{ 261 qs: qs, 262 ind: ind, 263 vals: vals, 264 } 265 } 266 267 func (it *quadIteratorContains) TagResults(dst map[string]graph.Ref) {} 268 269 func (it *quadIteratorContains) Close() error { 270 return it.err 271 } 272 273 func (it *quadIteratorContains) Err() error { 274 return it.err 275 } 276 277 func (it *quadIteratorContains) Result() graph.Ref { 278 if it.prim == nil { 279 return nil 280 } 281 return it.prim 282 } 283 284 func (it *quadIteratorContains) NextPath(ctx context.Context) bool { 285 return false 286 } 287 288 func (it *quadIteratorContains) Contains(ctx context.Context, v graph.Ref) bool { 289 it.prim = nil 290 // TODO(dennwc): shouldn't this check the horizon? 291 p, ok := v.(*proto.Primitive) 292 if !ok { 293 return false 294 } 295 for i, v := range it.vals { 296 if p.GetDirection(it.ind.Dirs[i]) != v { 297 return false 298 } 299 } 300 it.prim = p 301 return true 302 } 303 304 func (it *quadIteratorContains) String() string { 305 return fmt.Sprintf("KVQuadsContains(%v)", it.ind) 306 } 307 308 func (it *quadIteratorContains) Sorted() bool { return true }