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 }