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 }