From a83b7ea367c2cd72d140ca6d6a33a20be62bebb3 Mon Sep 17 00:00:00 2001 From: Jeremy Jay Date: Mon, 28 Jul 2014 11:26:33 -0400 Subject: [PATCH 1/9] fix non-pointer uintptr -> uint64, export NextUID Allows other iterator implementations to use global UID namespace. --- graph/iterator.go | 2 +- graph/iterator/iterator.go | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/graph/iterator.go b/graph/iterator.go index 27a6f02..42fb71a 100644 --- a/graph/iterator.go +++ b/graph/iterator.go @@ -114,7 +114,7 @@ type Iterator interface { Close() // UID returns the unique identifier of the iterator. - UID() uintptr + UID() uint64 } // FixedIterator wraps iterators that are modifiable by addition of fixed value sets. diff --git a/graph/iterator/iterator.go b/graph/iterator/iterator.go index e2029d5..93f5105 100644 --- a/graph/iterator/iterator.go +++ b/graph/iterator/iterator.go @@ -27,10 +27,10 @@ import ( "github.com/google/cayley/graph" ) -var nextIteratorID uintptr +var nextIteratorID uint64 -func nextID() uintptr { - return atomic.AddUintptr(&nextIteratorID, 1) - 1 +func NextUID() uint64 { + return atomic.AddUint64(&nextIteratorID, 1) - 1 } // The Base iterator is the iterator other iterators inherit from to get some @@ -40,7 +40,7 @@ type Base struct { tags []string fixedTags map[string]graph.Value canNext bool - uid uintptr + uid uint64 } // Called by subclases. @@ -48,11 +48,11 @@ func BaseInit(it *Base) { // Your basic iterator is nextable it.canNext = true if glog.V(2) { - it.uid = nextID() + it.uid = NextUID() } } -func (it *Base) UID() uintptr { +func (it *Base) UID() uint64 { return it.uid } From 1604dca73786644fa21a61dbd3fe59066347197c Mon Sep 17 00:00:00 2001 From: kortschak Date: Wed, 30 Jul 2014 10:15:22 +0930 Subject: [PATCH 2/9] Move tag handling out into graph.Tagger --- graph/iterator.go | 50 +++++++++++++---- graph/iterator/all_iterator.go | 20 ++++++- graph/iterator/and_iterator.go | 40 +++++++++----- graph/iterator/and_iterator_optimize.go | 11 ++-- graph/iterator/and_iterator_optimize_test.go | 18 +++---- graph/iterator/and_iterator_test.go | 6 +-- graph/iterator/fixed_iterator.go | 19 ++++++- graph/iterator/hasa_iterator.go | 18 +++++-- graph/iterator/iterator.go | 71 +++++++------------------ graph/iterator/linksto_iterator.go | 16 +++++- graph/iterator/optional_iterator.go | 9 +++- graph/iterator/or_iterator.go | 20 +++++-- graph/iterator/query_shape.go | 4 +- graph/iterator/query_shape_test.go | 8 +-- graph/iterator/value_comparison_iterator.go | 16 +++++- graph/leveldb/all_iterator.go | 19 ++++++- graph/leveldb/iterator.go | 19 ++++++- graph/leveldb/leveldb_test.go | 2 +- graph/leveldb/triplestore_iterator_optimize.go | 7 +-- graph/memstore/iterator.go | 23 ++++++-- graph/memstore/triplestore_iterator_optimize.go | 7 +-- graph/memstore/triplestore_test.go | 5 +- graph/mongo/iterator.go | 31 ++++++++--- graph/mongo/triplestore_iterator_optimize.go | 7 +-- graph/sexp/parser.go | 2 +- query/gremlin/build_iterator.go | 12 ++--- query/gremlin/finals.go | 10 ++-- query/mql/build_iterator.go | 4 +- 28 files changed, 315 insertions(+), 159 deletions(-) diff --git a/graph/iterator.go b/graph/iterator.go index 42fb71a..bb1faba 100644 --- a/graph/iterator.go +++ b/graph/iterator.go @@ -24,18 +24,46 @@ import ( "github.com/barakmich/glog" ) +type Tagger struct { + tags []string + fixedTags map[string]Value +} + +// Adds a tag to the iterator. +func (t *Tagger) Add(tag string) { + t.tags = append(t.tags, tag) +} + +func (t *Tagger) AddFixed(tag string, value Value) { + if t.fixedTags == nil { + t.fixedTags = make(map[string]Value) + } + t.fixedTags[tag] = value +} + +// Returns the tags. The returned value must not be mutated. +func (t *Tagger) Tags() []string { + return t.tags +} + +// Returns the fixed tags. The returned value must not be mutated. +func (t *Tagger) Fixed() map[string]Value { + return t.fixedTags +} + +func (t *Tagger) CopyFrom(src Iterator) { + for _, tag := range src.Tagger().Tags() { + t.Add(tag) + } + + for k, v := range src.Tagger().Fixed() { + t.AddFixed(k, v) + } + +} + type Iterator interface { - // Tags are the way we handle results. By adding a tag to an iterator, we can - // "name" it, in a sense, and at each step of iteration, get a named result. - // TagResults() is therefore the handy way of walking an iterator tree and - // getting the named results. - // - // Tag Accessors. - AddTag(string) - Tags() []string - AddFixedTag(string, Value) - FixedTags() map[string]Value - CopyTagsFrom(Iterator) + Tagger() *Tagger // Fills a tag-to-result-value map. TagResults(map[string]Value) diff --git a/graph/iterator/all_iterator.go b/graph/iterator/all_iterator.go index 22e0d1b..0548fa5 100644 --- a/graph/iterator/all_iterator.go +++ b/graph/iterator/all_iterator.go @@ -32,6 +32,7 @@ import ( // An All iterator across a range of int64 values, from `max` to `min`. type Int64 struct { Base + tags graph.Tagger max, min int64 at int64 } @@ -55,13 +56,28 @@ func (it *Int64) Close() {} func (it *Int64) Clone() graph.Iterator { out := NewInt64(it.min, it.max) - out.CopyTagsFrom(it) + out.tags.CopyFrom(it) return out } +func (it *Int64) Tagger() *graph.Tagger { + return &it.tags +} + +// Fill the map based on the tags assigned to this iterator. +func (it *Int64) TagResults(dst map[string]graph.Value) { + for _, tag := range it.tags.Tags() { + dst[tag] = it.Result() + } + + for tag, value := range it.tags.Fixed() { + dst[tag] = value + } +} + // Prints the All iterator as just an "all". func (it *Int64) DebugString(indent int) string { - return fmt.Sprintf("%s(%s tags: %v)", strings.Repeat(" ", indent), it.Type(), it.Tags()) + return fmt.Sprintf("%s(%s tags: %v)", strings.Repeat(" ", indent), it.Type(), it.tags.Tags()) } // Next() on an Int64 all iterator is a simple incrementing counter. diff --git a/graph/iterator/and_iterator.go b/graph/iterator/and_iterator.go index 819cb42..3f129cc 100644 --- a/graph/iterator/and_iterator.go +++ b/graph/iterator/and_iterator.go @@ -26,6 +26,7 @@ import ( // be Next()ed if next is called. type And struct { Base + tags graph.Tagger internalIterators []graph.Iterator itCount int primaryIt graph.Iterator @@ -50,10 +51,33 @@ func (it *And) Reset() { it.checkList = nil } +func (it *And) Tagger() *graph.Tagger { + return &it.tags +} + +// Overrides Base TagResults, as it needs to add it's own results and +// recurse down it's subiterators. +func (it *And) TagResults(dst map[string]graph.Value) { + for _, tag := range it.tags.Tags() { + dst[tag] = it.Result() + } + + for tag, value := range it.tags.Fixed() { + dst[tag] = value + } + + if it.primaryIt != nil { + it.primaryIt.TagResults(dst) + } + for _, sub := range it.internalIterators { + sub.TagResults(dst) + } +} + func (it *And) Clone() graph.Iterator { and := NewAnd() and.AddSubIterator(it.primaryIt.Clone()) - and.CopyTagsFrom(it) + and.tags.CopyFrom(it) for _, sub := range it.internalIterators { and.AddSubIterator(sub.Clone()) } @@ -71,18 +95,6 @@ func (it *And) SubIterators() []graph.Iterator { return iters } -// Overrides Base TagResults, as it needs to add it's own results and -// recurse down it's subiterators. -func (it *And) TagResults(dst map[string]graph.Value) { - it.Base.TagResults(dst) - if it.primaryIt != nil { - it.primaryIt.TagResults(dst) - } - for _, sub := range it.internalIterators { - sub.TagResults(dst) - } -} - // DEPRECATED Returns the ResultTree for this iterator, recurses to it's subiterators. func (it *And) ResultTree() *graph.ResultTree { tree := graph.NewResultTree(it.Result()) @@ -101,7 +113,7 @@ func (it *And) DebugString(indent int) string { total += fmt.Sprintf("%d:\n%s\n", i, sub.DebugString(indent+4)) } var tags string - for _, k := range it.Tags() { + for _, k := range it.tags.Tags() { tags += fmt.Sprintf("%s;", k) } spaces := strings.Repeat(" ", indent+2) diff --git a/graph/iterator/and_iterator_optimize.go b/graph/iterator/and_iterator_optimize.go index b556094..06def9f 100644 --- a/graph/iterator/and_iterator_optimize.go +++ b/graph/iterator/and_iterator_optimize.go @@ -82,7 +82,7 @@ func (it *And) Optimize() (graph.Iterator, bool) { } // Move the tags hanging on us (like any good replacement). - newAnd.CopyTagsFrom(it) + newAnd.tags.CopyFrom(it) newAnd.optimizeCheck() @@ -213,11 +213,11 @@ func (it *And) optimizeCheck() { func (it *And) getSubTags() map[string]struct{} { tags := make(map[string]struct{}) for _, sub := range it.SubIterators() { - for _, tag := range sub.Tags() { + for _, tag := range sub.Tagger().Tags() { tags[tag] = struct{}{} } } - for _, tag := range it.Tags() { + for _, tag := range it.tags.Tags() { tags[tag] = struct{}{} } return tags @@ -227,13 +227,14 @@ func (it *And) getSubTags() map[string]struct{} { // src itself, and moves them to dst. func moveTagsTo(dst graph.Iterator, src *And) { tags := src.getSubTags() - for _, tag := range dst.Tags() { + for _, tag := range dst.Tagger().Tags() { if _, ok := tags[tag]; ok { delete(tags, tag) } } + dt := dst.Tagger() for k := range tags { - dst.AddTag(k) + dt.Add(k) } } diff --git a/graph/iterator/and_iterator_optimize_test.go b/graph/iterator/and_iterator_optimize_test.go index e8d6a80..00b3807 100644 --- a/graph/iterator/and_iterator_optimize_test.go +++ b/graph/iterator/and_iterator_optimize_test.go @@ -32,9 +32,9 @@ func TestIteratorPromotion(t *testing.T) { a := NewAnd() a.AddSubIterator(all) a.AddSubIterator(fixed) - all.AddTag("a") - fixed.AddTag("b") - a.AddTag("c") + all.Tagger().Add("a") + fixed.Tagger().Add("b") + a.Tagger().Add("c") newIt, changed := a.Optimize() if !changed { t.Error("Iterator didn't optimize") @@ -43,7 +43,7 @@ func TestIteratorPromotion(t *testing.T) { t.Error("Expected fixed iterator") } tagsExpected := []string{"a", "b", "c"} - tags := newIt.Tags() + tags := newIt.Tagger().Tags() sort.Strings(tags) if !reflect.DeepEqual(tags, tagsExpected) { t.Fatal("Tags don't match") @@ -67,9 +67,9 @@ func TestNullIteratorAnd(t *testing.T) { func TestReorderWithTag(t *testing.T) { all := NewInt64(100, 300) - all.AddTag("good") + all.Tagger().Add("good") all2 := NewInt64(1, 30000) - all2.AddTag("slow") + all2.Tagger().Add("slow") a := NewAnd() // Make all2 the default iterator a.AddSubIterator(all2) @@ -82,7 +82,7 @@ func TestReorderWithTag(t *testing.T) { expectedTags := []string{"good", "slow"} tagsOut := make([]string, 0) for _, sub := range newIt.SubIterators() { - for _, x := range sub.Tags() { + for _, x := range sub.Tagger().Tags() { tagsOut = append(tagsOut, x) } } @@ -93,9 +93,9 @@ func TestReorderWithTag(t *testing.T) { func TestAndStatistics(t *testing.T) { all := NewInt64(100, 300) - all.AddTag("good") + all.Tagger().Add("good") all2 := NewInt64(1, 30000) - all2.AddTag("slow") + all2.Tagger().Add("slow") a := NewAnd() // Make all2 the default iterator a.AddSubIterator(all2) diff --git a/graph/iterator/and_iterator_test.go b/graph/iterator/and_iterator_test.go index 60633e1..82d290a 100644 --- a/graph/iterator/and_iterator_test.go +++ b/graph/iterator/and_iterator_test.go @@ -24,11 +24,11 @@ import ( func TestTag(t *testing.T) { fix1 := newFixed() fix1.Add(234) - fix1.AddTag("foo") + fix1.Tagger().Add("foo") and := NewAnd() and.AddSubIterator(fix1) - and.AddTag("bar") - out := fix1.Tags() + and.Tagger().Add("bar") + out := fix1.Tagger().Tags() if len(out) != 1 { t.Errorf("Expected length 1, got %d", len(out)) } diff --git a/graph/iterator/fixed_iterator.go b/graph/iterator/fixed_iterator.go index c69869b..760962f 100644 --- a/graph/iterator/fixed_iterator.go +++ b/graph/iterator/fixed_iterator.go @@ -31,6 +31,7 @@ import ( // an equality function. type Fixed struct { Base + tags graph.Tagger values []graph.Value lastIndex int cmp Equality @@ -68,12 +69,26 @@ func (it *Fixed) Reset() { func (it *Fixed) Close() {} +func (it *Fixed) Tagger() *graph.Tagger { + return &it.tags +} + +func (it *Fixed) TagResults(dst map[string]graph.Value) { + for _, tag := range it.tags.Tags() { + dst[tag] = it.Result() + } + + for tag, value := range it.tags.Fixed() { + dst[tag] = value + } +} + func (it *Fixed) Clone() graph.Iterator { out := NewFixedIteratorWithCompare(it.cmp) for _, val := range it.values { out.Add(val) } - out.CopyTagsFrom(it) + out.tags.CopyFrom(it) return out } @@ -92,7 +107,7 @@ func (it *Fixed) DebugString(indent int) string { return fmt.Sprintf("%s(%s tags: %s Size: %d id0: %d)", strings.Repeat(" ", indent), it.Type(), - it.FixedTags(), + it.tags.Fixed(), len(it.values), value, ) diff --git a/graph/iterator/hasa_iterator.go b/graph/iterator/hasa_iterator.go index b434288..07883e3 100644 --- a/graph/iterator/hasa_iterator.go +++ b/graph/iterator/hasa_iterator.go @@ -47,6 +47,7 @@ import ( // and a temporary holder for the iterator generated on Check(). type HasA struct { Base + tags graph.Tagger ts graph.TripleStore primaryIt graph.Iterator dir graph.Direction @@ -76,9 +77,13 @@ func (it *HasA) Reset() { } } +func (it *HasA) Tagger() *graph.Tagger { + return &it.tags +} + func (it *HasA) Clone() graph.Iterator { out := NewHasA(it.ts, it.primaryIt.Clone(), it.dir) - out.CopyTagsFrom(it) + out.tags.CopyFrom(it) return out } @@ -100,7 +105,14 @@ func (it *HasA) Optimize() (graph.Iterator, bool) { // Pass the TagResults down the chain. func (it *HasA) TagResults(dst map[string]graph.Value) { - it.Base.TagResults(dst) + for _, tag := range it.tags.Tags() { + dst[tag] = it.Result() + } + + for tag, value := range it.tags.Fixed() { + dst[tag] = value + } + it.primaryIt.TagResults(dst) } @@ -114,7 +126,7 @@ func (it *HasA) ResultTree() *graph.ResultTree { // Print some information about this iterator. func (it *HasA) DebugString(indent int) string { var tags string - for _, k := range it.Tags() { + for _, k := range it.tags.Tags() { tags += fmt.Sprintf("%s;", k) } return fmt.Sprintf("%s(%s %d tags:%s direction:%s\n%s)", strings.Repeat(" ", indent), it.Type(), it.UID(), tags, it.dir, it.primaryIt.DebugString(indent+4)) diff --git a/graph/iterator/iterator.go b/graph/iterator/iterator.go index 93f5105..24a7a7f 100644 --- a/graph/iterator/iterator.go +++ b/graph/iterator/iterator.go @@ -36,11 +36,9 @@ func NextUID() uint64 { // The Base iterator is the iterator other iterators inherit from to get some // default functionality. type Base struct { - Last graph.Value - tags []string - fixedTags map[string]graph.Value - canNext bool - uid uint64 + Last graph.Value + canNext bool + uid uint64 } // Called by subclases. @@ -56,41 +54,6 @@ func (it *Base) UID() uint64 { return it.uid } -// Adds a tag to the iterator. Most iterators don't need to override. -func (it *Base) AddTag(tag string) { - if it.tags == nil { - it.tags = make([]string, 0) - } - it.tags = append(it.tags, tag) -} - -func (it *Base) AddFixedTag(tag string, value graph.Value) { - if it.fixedTags == nil { - it.fixedTags = make(map[string]graph.Value) - } - it.fixedTags[tag] = value -} - -// Returns the tags. -func (it *Base) Tags() []string { - return it.tags -} - -func (it *Base) FixedTags() map[string]graph.Value { - return it.fixedTags -} - -func (it *Base) CopyTagsFrom(other_it graph.Iterator) { - for _, tag := range other_it.Tags() { - it.AddTag(tag) - } - - for k, v := range other_it.FixedTags() { - it.AddFixedTag(k, v) - } - -} - // Prints a silly debug string. Most classes override. func (it *Base) DebugString(indent int) string { return fmt.Sprintf("%s(base)", strings.Repeat(" ", indent)) @@ -140,18 +103,6 @@ func (it *Base) SubIterators() []graph.Iterator { // Accessor func (it *Base) CanNext() bool { return it.canNext } -// Fill the map based on the tags assigned to this iterator. Default -// functionality works well for most iterators. -func (it *Base) TagResults(dst map[string]graph.Value) { - for _, tag := range it.Tags() { - dst[tag] = it.Result() - } - - for tag, value := range it.FixedTags() { - dst[tag] = value - } -} - // Nothing to clean up. // func (it *Base) Close() {} @@ -164,6 +115,7 @@ func (it *Base) Reset() {} // so it's important to give it a special iterator. type Null struct { Base + tags graph.Tagger } // Fairly useless New function. @@ -171,6 +123,21 @@ func NewNull() *Null { return &Null{} } +func (it *Null) Tagger() *graph.Tagger { + return &it.tags +} + +// Fill the map based on the tags assigned to this iterator. +func (it *Null) TagResults(dst map[string]graph.Value) { + for _, tag := range it.tags.Tags() { + dst[tag] = it.Result() + } + + for tag, value := range it.tags.Fixed() { + dst[tag] = value + } +} + func (it *Null) Clone() graph.Iterator { return NewNull() } // Name the null iterator. diff --git a/graph/iterator/linksto_iterator.go b/graph/iterator/linksto_iterator.go index 8488954..63757ae 100644 --- a/graph/iterator/linksto_iterator.go +++ b/graph/iterator/linksto_iterator.go @@ -41,6 +41,7 @@ import ( // `next_it` is the tempoarary iterator held per result in `primary_it`. type LinksTo struct { Base + tags graph.Tagger ts graph.TripleStore primaryIt graph.Iterator dir graph.Direction @@ -67,9 +68,13 @@ func (it *LinksTo) Reset() { it.nextIt = &Null{} } +func (it *LinksTo) Tagger() *graph.Tagger { + return &it.tags +} + func (it *LinksTo) Clone() graph.Iterator { out := NewLinksTo(it.ts, it.primaryIt.Clone(), it.dir) - out.CopyTagsFrom(it) + out.tags.CopyFrom(it) return out } @@ -78,7 +83,14 @@ func (it *LinksTo) Direction() graph.Direction { return it.dir } // Tag these results, and our subiterator's results. func (it *LinksTo) TagResults(dst map[string]graph.Value) { - it.Base.TagResults(dst) + for _, tag := range it.tags.Tags() { + dst[tag] = it.Result() + } + + for tag, value := range it.tags.Fixed() { + dst[tag] = value + } + it.primaryIt.TagResults(dst) } diff --git a/graph/iterator/optional_iterator.go b/graph/iterator/optional_iterator.go index 46c6dd6..fc3c41b 100644 --- a/graph/iterator/optional_iterator.go +++ b/graph/iterator/optional_iterator.go @@ -39,6 +39,7 @@ import ( // and whether the last check we received was true or false. type Optional struct { Base + tags graph.Tagger subIt graph.Iterator lastCheck bool } @@ -61,9 +62,13 @@ func (it *Optional) Close() { it.subIt.Close() } +func (it *Optional) Tagger() *graph.Tagger { + return &it.tags +} + func (it *Optional) Clone() graph.Iterator { out := NewOptional(it.subIt.Clone()) - out.CopyTagsFrom(it) + out.tags.CopyFrom(it) return out } @@ -111,7 +116,7 @@ func (it *Optional) DebugString(indent int) string { return fmt.Sprintf("%s(%s tags:%s\n%s)", strings.Repeat(" ", indent), it.Type(), - it.Tags(), + it.tags.Tags(), it.subIt.DebugString(indent+4)) } diff --git a/graph/iterator/or_iterator.go b/graph/iterator/or_iterator.go index 31306eb..da1da5c 100644 --- a/graph/iterator/or_iterator.go +++ b/graph/iterator/or_iterator.go @@ -30,6 +30,7 @@ import ( type Or struct { Base + tags graph.Tagger isShortCircuiting bool internalIterators []graph.Iterator itCount int @@ -62,6 +63,10 @@ func (it *Or) Reset() { it.currentIterator = -1 } +func (it *Or) Tagger() *graph.Tagger { + return &it.tags +} + func (it *Or) Clone() graph.Iterator { var or *Or if it.isShortCircuiting { @@ -72,7 +77,7 @@ func (it *Or) Clone() graph.Iterator { for _, sub := range it.internalIterators { or.AddSubIterator(sub.Clone()) } - or.CopyTagsFrom(it) + or.tags.CopyFrom(it) return or } @@ -84,7 +89,14 @@ func (it *Or) SubIterators() []graph.Iterator { // Overrides BaseIterator TagResults, as it needs to add it's own results and // recurse down it's subiterators. func (it *Or) TagResults(dst map[string]graph.Value) { - it.Base.TagResults(dst) + for _, tag := range it.tags.Tags() { + dst[tag] = it.Result() + } + + for tag, value := range it.tags.Fixed() { + dst[tag] = value + } + it.internalIterators[it.currentIterator].TagResults(dst) } @@ -105,7 +117,7 @@ func (it *Or) DebugString(indent int) string { total += fmt.Sprintf("%d:\n%s\n", i, sub.DebugString(indent+4)) } var tags string - for _, k := range it.Tags() { + for _, k := range it.tags.Tags() { tags += fmt.Sprintf("%s;", k) } spaces := strings.Repeat(" ", indent+2) @@ -247,7 +259,7 @@ func (it *Or) Optimize() (graph.Iterator, bool) { } // Move the tags hanging on us (like any good replacement). - newOr.CopyTagsFrom(it) + newOr.tags.CopyFrom(it) // And close ourselves but not our subiterators -- some may still be alive in // the new And (they were unchanged upon calling Optimize() on them, at the diff --git a/graph/iterator/query_shape.go b/graph/iterator/query_shape.go index 3e7eba1..acdbfa8 100644 --- a/graph/iterator/query_shape.go +++ b/graph/iterator/query_shape.go @@ -107,10 +107,10 @@ func (qs *queryShape) StealNode(left *Node, right *Node) { func (qs *queryShape) MakeNode(it graph.Iterator) *Node { n := Node{Id: qs.nodeId} - for _, tag := range it.Tags() { + for _, tag := range it.Tagger().Tags() { n.Tags = append(n.Tags, tag) } - for k, _ := range it.FixedTags() { + for k, _ := range it.Tagger().Fixed() { n.Tags = append(n.Tags, k) } diff --git a/graph/iterator/query_shape_test.go b/graph/iterator/query_shape_test.go index a67ba62..6ebadab 100644 --- a/graph/iterator/query_shape_test.go +++ b/graph/iterator/query_shape_test.go @@ -26,7 +26,7 @@ func hasaWithTag(ts graph.TripleStore, tag string, target string) *HasA { obj := ts.FixedIterator() obj.Add(ts.ValueOf(target)) - obj.AddTag(tag) + obj.Tagger().Add(tag) and.AddSubIterator(NewLinksTo(ts, obj, graph.Object)) pred := ts.FixedIterator() @@ -48,7 +48,7 @@ func TestQueryShape(t *testing.T) { // Given a single linkage iterator's shape. hasa := hasaWithTag(ts, "tag", "cool") - hasa.AddTag("top") + hasa.Tagger().Add("top") shape := make(map[string]interface{}) OutputQueryShapeForIterator(hasa, ts, shape) @@ -93,11 +93,11 @@ func TestQueryShape(t *testing.T) { andInternal := NewAnd() hasa1 := hasaWithTag(ts, "tag1", "cool") - hasa1.AddTag("hasa1") + hasa1.Tagger().Add("hasa1") andInternal.AddSubIterator(hasa1) hasa2 := hasaWithTag(ts, "tag2", "fun") - hasa2.AddTag("hasa2") + hasa2.Tagger().Add("hasa2") andInternal.AddSubIterator(hasa2) pred := ts.FixedIterator() diff --git a/graph/iterator/value_comparison_iterator.go b/graph/iterator/value_comparison_iterator.go index 611d549..6b89cd7 100644 --- a/graph/iterator/value_comparison_iterator.go +++ b/graph/iterator/value_comparison_iterator.go @@ -47,6 +47,7 @@ const ( type Comparison struct { Base + tags graph.Tagger subIt graph.Iterator op Operator val interface{} @@ -111,9 +112,13 @@ func (it *Comparison) Reset() { it.subIt.Reset() } +func (it *Comparison) Tagger() *graph.Tagger { + return &it.tags +} + func (it *Comparison) Clone() graph.Iterator { out := NewComparison(it.subIt.Clone(), it.op, it.val, it.ts) - out.CopyTagsFrom(it) + out.tags.CopyFrom(it) return out } @@ -157,7 +162,14 @@ func (it *Comparison) Check(val graph.Value) bool { // If we failed the check, then the subiterator should not contribute to the result // set. Otherwise, go ahead and tag it. func (it *Comparison) TagResults(dst map[string]graph.Value) { - it.Base.TagResults(dst) + for _, tag := range it.tags.Tags() { + dst[tag] = it.Result() + } + + for tag, value := range it.tags.Fixed() { + dst[tag] = value + } + it.subIt.TagResults(dst) } diff --git a/graph/leveldb/all_iterator.go b/graph/leveldb/all_iterator.go index 88a1386..177eec0 100644 --- a/graph/leveldb/all_iterator.go +++ b/graph/leveldb/all_iterator.go @@ -28,6 +28,7 @@ import ( type AllIterator struct { iterator.Base + tags graph.Tagger prefix []byte dir graph.Direction open bool @@ -66,9 +67,23 @@ func (it *AllIterator) Reset() { } } +func (it *AllIterator) Tagger() *graph.Tagger { + return &it.tags +} + +func (it *AllIterator) TagResults(dst map[string]graph.Value) { + for _, tag := range it.tags.Tags() { + dst[tag] = it.Result() + } + + for tag, value := range it.tags.Fixed() { + dst[tag] = value + } +} + func (it *AllIterator) Clone() graph.Iterator { out := NewAllIterator(string(it.prefix), it.dir, it.ts) - out.CopyTagsFrom(it) + out.tags.CopyFrom(it) return out } @@ -115,7 +130,7 @@ func (it *AllIterator) Size() (int64, bool) { func (it *AllIterator) DebugString(indent int) string { size, _ := it.Size() - return fmt.Sprintf("%s(%s tags: %v leveldb size:%d %s %p)", strings.Repeat(" ", indent), it.Type(), it.Tags(), size, it.dir, it) + return fmt.Sprintf("%s(%s tags: %v leveldb size:%d %s %p)", strings.Repeat(" ", indent), it.Type(), it.tags.Tags(), size, it.dir, it) } func (it *AllIterator) Type() graph.Type { return graph.All } diff --git a/graph/leveldb/iterator.go b/graph/leveldb/iterator.go index 0e3f6e0..53301cc 100644 --- a/graph/leveldb/iterator.go +++ b/graph/leveldb/iterator.go @@ -28,6 +28,7 @@ import ( type Iterator struct { iterator.Base + tags graph.Tagger nextPrefix []byte checkId []byte dir graph.Direction @@ -72,9 +73,23 @@ func (it *Iterator) Reset() { } } +func (it *Iterator) Tagger() *graph.Tagger { + return &it.tags +} + +func (it *Iterator) TagResults(dst map[string]graph.Value) { + for _, tag := range it.tags.Tags() { + dst[tag] = it.Result() + } + + for tag, value := range it.tags.Fixed() { + dst[tag] = value + } +} + func (it *Iterator) Clone() graph.Iterator { out := NewIterator(it.originalPrefix, it.dir, it.checkId, it.ts) - out.CopyTagsFrom(it) + out.tags.CopyFrom(it) return out } @@ -192,7 +207,7 @@ func (it *Iterator) Size() (int64, bool) { func (it *Iterator) DebugString(indent int) string { size, _ := it.Size() - return fmt.Sprintf("%s(%s %d tags: %v dir: %s size:%d %s)", strings.Repeat(" ", indent), it.Type(), it.UID(), it.Tags(), it.dir, size, it.ts.NameOf(it.checkId)) + return fmt.Sprintf("%s(%s %d tags: %v dir: %s size:%d %s)", strings.Repeat(" ", indent), it.Type(), it.UID(), it.tags.Tags(), it.dir, size, it.ts.NameOf(it.checkId)) } var levelDBType graph.Type diff --git a/graph/leveldb/leveldb_test.go b/graph/leveldb/leveldb_test.go index 59b32b0..e2855fb 100644 --- a/graph/leveldb/leveldb_test.go +++ b/graph/leveldb/leveldb_test.go @@ -415,7 +415,7 @@ func TestOptimize(t *testing.T) { // With an linksto-fixed pair fixed := ts.FixedIterator() fixed.Add(ts.ValueOf("F")) - fixed.AddTag("internal") + fixed.Tagger().Add("internal") lto := iterator.NewLinksTo(ts, fixed, graph.Object) oldIt := lto.Clone() diff --git a/graph/leveldb/triplestore_iterator_optimize.go b/graph/leveldb/triplestore_iterator_optimize.go index 2234060..f449e0e 100644 --- a/graph/leveldb/triplestore_iterator_optimize.go +++ b/graph/leveldb/triplestore_iterator_optimize.go @@ -42,9 +42,10 @@ func (ts *TripleStore) optimizeLinksTo(it *iterator.LinksTo) (graph.Iterator, bo panic("Sizes lie") } newIt := ts.TripleIterator(it.Direction(), val) - newIt.CopyTagsFrom(it) - for _, tag := range primary.Tags() { - newIt.AddFixedTag(tag, val) + nt := newIt.Tagger() + nt.CopyFrom(it) + for _, tag := range primary.Tagger().Tags() { + nt.AddFixed(tag, val) } it.Close() return newIt, true diff --git a/graph/memstore/iterator.go b/graph/memstore/iterator.go index 3b7bfa8..a5db108 100644 --- a/graph/memstore/iterator.go +++ b/graph/memstore/iterator.go @@ -27,6 +27,7 @@ import ( type Iterator struct { iterator.Base + tags graph.Tagger tree *llrb.LLRB data string isRunning bool @@ -65,10 +66,24 @@ func (it *Iterator) Reset() { it.iterLast = Int64(-1) } +func (it *Iterator) Tagger() *graph.Tagger { + return &it.tags +} + +func (it *Iterator) TagResults(dst map[string]graph.Value) { + for _, tag := range it.tags.Tags() { + dst[tag] = it.Result() + } + + for tag, value := range it.tags.Fixed() { + dst[tag] = value + } +} + func (it *Iterator) Clone() graph.Iterator { - var new_it = NewLlrbIterator(it.tree, it.data) - new_it.CopyTagsFrom(it) - return new_it + m := NewLlrbIterator(it.tree, it.data) + m.tags.CopyFrom(it) + return m } func (it *Iterator) Close() {} @@ -98,7 +113,7 @@ func (it *Iterator) Check(v graph.Value) bool { func (it *Iterator) DebugString(indent int) string { size, _ := it.Size() - return fmt.Sprintf("%s(%s tags:%s size:%d %s)", strings.Repeat(" ", indent), it.Type(), it.Tags(), size, it.data) + return fmt.Sprintf("%s(%s tags:%s size:%d %s)", strings.Repeat(" ", indent), it.Type(), it.tags.Tags(), size, it.data) } var memType graph.Type diff --git a/graph/memstore/triplestore_iterator_optimize.go b/graph/memstore/triplestore_iterator_optimize.go index 1a89a16..d7510e3 100644 --- a/graph/memstore/triplestore_iterator_optimize.go +++ b/graph/memstore/triplestore_iterator_optimize.go @@ -42,9 +42,10 @@ func (ts *TripleStore) optimizeLinksTo(it *iterator.LinksTo) (graph.Iterator, bo panic("Sizes lie") } newIt := ts.TripleIterator(it.Direction(), val) - newIt.CopyTagsFrom(it) - for _, tag := range primary.Tags() { - newIt.AddFixedTag(tag, val) + nt := newIt.Tagger() + nt.CopyFrom(it) + for _, tag := range primary.Tagger().Tags() { + nt.AddFixed(tag, val) } return newIt, true } diff --git a/graph/memstore/triplestore_test.go b/graph/memstore/triplestore_test.go index 8b911f1..aa8f93b 100644 --- a/graph/memstore/triplestore_test.go +++ b/graph/memstore/triplestore_test.go @@ -150,7 +150,7 @@ func TestLinksToOptimization(t *testing.T) { fixed.Add(ts.ValueOf("cool")) lto := iterator.NewLinksTo(ts, fixed, graph.Object) - lto.AddTag("foo") + lto.Tagger().Add("foo") newIt, changed := lto.Optimize() if !changed { @@ -165,7 +165,8 @@ func TestLinksToOptimization(t *testing.T) { if v_clone.DebugString(0) != v.DebugString(0) { t.Fatal("Wrong iterator. Got ", v_clone.DebugString(0)) } - if len(v_clone.Tags()) < 1 || v_clone.Tags()[0] != "foo" { + vt := v_clone.Tagger() + if len(vt.Tags()) < 1 || vt.Tags()[0] != "foo" { t.Fatal("Tag on LinksTo did not persist") } } diff --git a/graph/mongo/iterator.go b/graph/mongo/iterator.go index fcf2c5d..4996572 100644 --- a/graph/mongo/iterator.go +++ b/graph/mongo/iterator.go @@ -28,6 +28,7 @@ import ( type Iterator struct { iterator.Base + tags graph.Tagger ts *TripleStore dir graph.Direction iter *mgo.Iter @@ -98,15 +99,29 @@ func (it *Iterator) Close() { it.iter.Close() } -func (it *Iterator) Clone() graph.Iterator { - var newM graph.Iterator - if it.isAll { - newM = NewAllIterator(it.ts, it.collection) - } else { - newM = NewIterator(it.ts, it.collection, it.dir, it.hash) +func (it *Iterator) Tagger() *graph.Tagger { + return &it.tags +} + +func (it *Iterator) TagResults(dst map[string]graph.Value) { + for _, tag := range it.tags.Tags() { + dst[tag] = it.Result() } - newM.CopyTagsFrom(it) - return newM + + for tag, value := range it.tags.Fixed() { + dst[tag] = value + } +} + +func (it *Iterator) Clone() graph.Iterator { + var m *Iterator + if it.isAll { + m = NewAllIterator(it.ts, it.collection) + } else { + m = NewIterator(it.ts, it.collection, it.dir, it.hash) + } + m.tags.CopyFrom(it) + return m } func (it *Iterator) Next() (graph.Value, bool) { diff --git a/graph/mongo/triplestore_iterator_optimize.go b/graph/mongo/triplestore_iterator_optimize.go index 766e84c..76c50d8 100644 --- a/graph/mongo/triplestore_iterator_optimize.go +++ b/graph/mongo/triplestore_iterator_optimize.go @@ -42,9 +42,10 @@ func (ts *TripleStore) optimizeLinksTo(it *iterator.LinksTo) (graph.Iterator, bo panic("Sizes lie") } newIt := ts.TripleIterator(it.Direction(), val) - newIt.CopyTagsFrom(it) - for _, tag := range primary.Tags() { - newIt.AddFixedTag(tag, val) + nt := newIt.Tagger() + nt.CopyFrom(it) + for _, tag := range primary.Tagger().Tags() { + nt.AddFixed(tag, val) } it.Close() return newIt, true diff --git a/graph/sexp/parser.go b/graph/sexp/parser.go index 5a3c86a..cfc4956 100644 --- a/graph/sexp/parser.go +++ b/graph/sexp/parser.go @@ -189,7 +189,7 @@ func buildIteratorTree(tree *peg.ExpressionTree, ts graph.TripleStore) graph.Ite nodeID := getIdentString(tree) if tree.Children[0].Name == "Variable" { allIt := ts.NodesAllIterator() - allIt.AddTag(nodeID) + allIt.Tagger().Add(nodeID) out = allIt } else { n := nodeID diff --git a/query/gremlin/build_iterator.go b/query/gremlin/build_iterator.go index 1634368..8231fbb 100644 --- a/query/gremlin/build_iterator.go +++ b/query/gremlin/build_iterator.go @@ -135,7 +135,7 @@ func buildInOutIterator(obj *otto.Object, ts graph.TripleStore, base graph.Itera tags = makeListOfStringsFromArrayValue(one.Object()) } for _, tag := range tags { - predicateNodeIterator.AddTag(tag) + predicateNodeIterator.Tagger().Add(tag) } } @@ -179,7 +179,7 @@ func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph. case "tag": it = subIt for _, tag := range stringArgs { - it.AddTag(tag) + it.Tagger().Add(tag) } case "save": all := ts.NodesAllIterator() @@ -187,9 +187,9 @@ func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph. return iterator.NewNull() } if len(stringArgs) == 2 { - all.AddTag(stringArgs[1]) + all.Tagger().Add(stringArgs[1]) } else { - all.AddTag(stringArgs[0]) + all.Tagger().Add(stringArgs[0]) } predFixed := ts.FixedIterator() predFixed.Add(ts.ValueOf(stringArgs[0])) @@ -207,9 +207,9 @@ func buildIteratorTreeHelper(obj *otto.Object, ts graph.TripleStore, base graph. return iterator.NewNull() } if len(stringArgs) == 2 { - all.AddTag(stringArgs[1]) + all.Tagger().Add(stringArgs[1]) } else { - all.AddTag(stringArgs[0]) + all.Tagger().Add(stringArgs[0]) } predFixed := ts.FixedIterator() predFixed.Add(ts.ValueOf(stringArgs[0])) diff --git a/query/gremlin/finals.go b/query/gremlin/finals.go index 7ad0886..414d780 100644 --- a/query/gremlin/finals.go +++ b/query/gremlin/finals.go @@ -38,7 +38,7 @@ func embedFinals(env *otto.Otto, ses *Session, obj *otto.Object) { func allFunc(env *otto.Otto, ses *Session, obj *otto.Object) func(otto.FunctionCall) otto.Value { return func(call otto.FunctionCall) otto.Value { it := buildIteratorTree(obj, ses.ts) - it.AddTag(TopResultTag) + it.Tagger().Add(TopResultTag) ses.limit = -1 ses.count = 0 runIteratorOnSession(it, ses) @@ -51,7 +51,7 @@ func limitFunc(env *otto.Otto, ses *Session, obj *otto.Object) func(otto.Functio if len(call.ArgumentList) > 0 { limitVal, _ := call.Argument(0).ToInteger() it := buildIteratorTree(obj, ses.ts) - it.AddTag(TopResultTag) + it.Tagger().Add(TopResultTag) ses.limit = int(limitVal) ses.count = 0 runIteratorOnSession(it, ses) @@ -63,7 +63,7 @@ func limitFunc(env *otto.Otto, ses *Session, obj *otto.Object) func(otto.Functio func toArrayFunc(env *otto.Otto, ses *Session, obj *otto.Object, withTags bool) func(otto.FunctionCall) otto.Value { return func(call otto.FunctionCall) otto.Value { it := buildIteratorTree(obj, ses.ts) - it.AddTag(TopResultTag) + it.Tagger().Add(TopResultTag) limit := -1 if len(call.ArgumentList) > 0 { limitParsed, _ := call.Argument(0).ToInteger() @@ -90,7 +90,7 @@ func toArrayFunc(env *otto.Otto, ses *Session, obj *otto.Object, withTags bool) func toValueFunc(env *otto.Otto, ses *Session, obj *otto.Object, withTags bool) func(otto.FunctionCall) otto.Value { return func(call otto.FunctionCall) otto.Value { it := buildIteratorTree(obj, ses.ts) - it.AddTag(TopResultTag) + it.Tagger().Add(TopResultTag) limit := 1 var val otto.Value var err error @@ -120,7 +120,7 @@ func toValueFunc(env *otto.Otto, ses *Session, obj *otto.Object, withTags bool) func mapFunc(env *otto.Otto, ses *Session, obj *otto.Object) func(otto.FunctionCall) otto.Value { return func(call otto.FunctionCall) otto.Value { it := buildIteratorTree(obj, ses.ts) - it.AddTag(TopResultTag) + it.Tagger().Add(TopResultTag) limit := -1 if len(call.ArgumentList) == 0 { return otto.NullValue() diff --git a/query/mql/build_iterator.go b/query/mql/build_iterator.go index 2a0d124..108d628 100644 --- a/query/mql/build_iterator.go +++ b/query/mql/build_iterator.go @@ -33,7 +33,7 @@ func (q *Query) buildFixed(s string) graph.Iterator { func (q *Query) buildResultIterator(path Path) graph.Iterator { all := q.ses.ts.NodesAllIterator() - all.AddTag(string(path)) + all.Tagger().Add(string(path)) return all } @@ -97,7 +97,7 @@ func (q *Query) buildIteratorTreeInternal(query interface{}, path Path) (it grap if err != nil { return nil, false, err } - it.AddTag(string(path)) + it.Tagger().Add(string(path)) return it, optional, nil } From 01b7278c3a6a7b667957fded5b595f4a49fe8a6a Mon Sep 17 00:00:00 2001 From: kortschak Date: Wed, 30 Jul 2014 11:44:36 +0930 Subject: [PATCH 3/9] Move UID handling from Base Also clean up some of the value creation code. --- graph/iterator/all_iterator.go | 15 +++++-- graph/iterator/and_iterator.go | 12 ++++-- graph/iterator/fixed_iterator.go | 14 ++++-- graph/iterator/hasa_iterator.go | 15 +++++-- graph/iterator/iterator.go | 17 +++----- graph/iterator/linksto_iterator.go | 17 +++++--- graph/iterator/optional_iterator.go | 6 +++ graph/iterator/or_iterator.go | 24 +++++++---- graph/iterator/value_comparison_iterator.go | 17 +++++--- graph/leveldb/all_iterator.go | 30 +++++++++---- graph/leveldb/iterator.go | 41 ++++++++++++------ graph/memstore/iterator.go | 15 +++++-- graph/mongo/iterator.go | 67 ++++++++++++++++++----------- 13 files changed, 198 insertions(+), 92 deletions(-) diff --git a/graph/iterator/all_iterator.go b/graph/iterator/all_iterator.go index 0548fa5..9bf6441 100644 --- a/graph/iterator/all_iterator.go +++ b/graph/iterator/all_iterator.go @@ -32,6 +32,7 @@ import ( // An All iterator across a range of int64 values, from `max` to `min`. type Int64 struct { Base + uid uint64 tags graph.Tagger max, min int64 at int64 @@ -39,14 +40,20 @@ type Int64 struct { // Creates a new Int64 with the given range. func NewInt64(min, max int64) *Int64 { - var all Int64 + all := Int64{ + uid: NextUID(), + min: min, + max: max, + at: min, + } BaseInit(&all.Base) - all.max = max - all.min = min - all.at = min return &all } +func (it *Int64) UID() uint64 { + return it.uid +} + // Start back at the beginning func (it *Int64) Reset() { it.at = it.min diff --git a/graph/iterator/and_iterator.go b/graph/iterator/and_iterator.go index 3f129cc..a7dce74 100644 --- a/graph/iterator/and_iterator.go +++ b/graph/iterator/and_iterator.go @@ -26,6 +26,7 @@ import ( // be Next()ed if next is called. type And struct { Base + uid uint64 tags graph.Tagger internalIterators []graph.Iterator itCount int @@ -35,13 +36,18 @@ type And struct { // Creates a new And iterator. func NewAnd() *And { - var and And + and := And{ + uid: NextUID(), + internalIterators: make([]graph.Iterator, 0, 20), + } BaseInit(&and.Base) - and.internalIterators = make([]graph.Iterator, 0, 20) - and.checkList = nil return &and } +func (it *And) UID() uint64 { + return it.uid +} + // Reset all internal iterators func (it *And) Reset() { it.primaryIt.Reset() diff --git a/graph/iterator/fixed_iterator.go b/graph/iterator/fixed_iterator.go index 760962f..61e9b50 100644 --- a/graph/iterator/fixed_iterator.go +++ b/graph/iterator/fixed_iterator.go @@ -31,6 +31,7 @@ import ( // an equality function. type Fixed struct { Base + uid uint64 tags graph.Tagger values []graph.Value lastIndex int @@ -55,14 +56,19 @@ func newFixed() *Fixed { // Creates a new Fixed iterator with a custom comparitor. func NewFixedIteratorWithCompare(compareFn Equality) *Fixed { - var it Fixed + it := Fixed{ + uid: NextUID(), + values: make([]graph.Value, 0, 20), + cmp: compareFn, + } BaseInit(&it.Base) - it.values = make([]graph.Value, 0, 20) - it.lastIndex = 0 - it.cmp = compareFn return &it } +func (it *Fixed) UID() uint64 { + return it.uid +} + func (it *Fixed) Reset() { it.lastIndex = 0 } diff --git a/graph/iterator/hasa_iterator.go b/graph/iterator/hasa_iterator.go index 07883e3..f883fd7 100644 --- a/graph/iterator/hasa_iterator.go +++ b/graph/iterator/hasa_iterator.go @@ -47,6 +47,7 @@ import ( // and a temporary holder for the iterator generated on Check(). type HasA struct { Base + uid uint64 tags graph.Tagger ts graph.TripleStore primaryIt graph.Iterator @@ -57,14 +58,20 @@ type HasA struct { // Construct a new HasA iterator, given the triple subiterator, and the triple // direction for which it stands. func NewHasA(ts graph.TripleStore, subIt graph.Iterator, d graph.Direction) *HasA { - var hasa HasA + hasa := HasA{ + uid: NextUID(), + ts: ts, + primaryIt: subIt, + dir: d, + } BaseInit(&hasa.Base) - hasa.ts = ts - hasa.primaryIt = subIt - hasa.dir = d return &hasa } +func (it *HasA) UID() uint64 { + return it.uid +} + // Return our sole subiterator. func (it *HasA) SubIterators() []graph.Iterator { return []graph.Iterator{it.primaryIt} diff --git a/graph/iterator/iterator.go b/graph/iterator/iterator.go index 24a7a7f..130dd6c 100644 --- a/graph/iterator/iterator.go +++ b/graph/iterator/iterator.go @@ -22,8 +22,6 @@ import ( "strings" "sync/atomic" - "github.com/barakmich/glog" - "github.com/google/cayley/graph" ) @@ -38,20 +36,12 @@ func NextUID() uint64 { type Base struct { Last graph.Value canNext bool - uid uint64 } // Called by subclases. func BaseInit(it *Base) { // Your basic iterator is nextable it.canNext = true - if glog.V(2) { - it.uid = NextUID() - } -} - -func (it *Base) UID() uint64 { - return it.uid } // Prints a silly debug string. Most classes override. @@ -115,12 +105,17 @@ func (it *Base) Reset() {} // so it's important to give it a special iterator. type Null struct { Base + uid uint64 tags graph.Tagger } // Fairly useless New function. func NewNull() *Null { - return &Null{} + return &Null{uid: NextUID()} +} + +func (it *Null) UID() uint64 { + return it.uid } func (it *Null) Tagger() *graph.Tagger { diff --git a/graph/iterator/linksto_iterator.go b/graph/iterator/linksto_iterator.go index 63757ae..e61dc09 100644 --- a/graph/iterator/linksto_iterator.go +++ b/graph/iterator/linksto_iterator.go @@ -41,6 +41,7 @@ import ( // `next_it` is the tempoarary iterator held per result in `primary_it`. type LinksTo struct { Base + uid uint64 tags graph.Tagger ts graph.TripleStore primaryIt graph.Iterator @@ -51,15 +52,21 @@ type LinksTo struct { // Construct a new LinksTo iterator around a direction and a subiterator of // nodes. func NewLinksTo(ts graph.TripleStore, it graph.Iterator, d graph.Direction) *LinksTo { - var lto LinksTo + lto := LinksTo{ + uid: NextUID(), + ts: ts, + primaryIt: it, + dir: d, + nextIt: &Null{}, + } BaseInit(<o.Base) - lto.ts = ts - lto.primaryIt = it - lto.dir = d - lto.nextIt = &Null{} return <o } +func (it *LinksTo) UID() uint64 { + return it.uid +} + func (it *LinksTo) Reset() { it.primaryIt.Reset() if it.nextIt != nil { diff --git a/graph/iterator/optional_iterator.go b/graph/iterator/optional_iterator.go index fc3c41b..defee8c 100644 --- a/graph/iterator/optional_iterator.go +++ b/graph/iterator/optional_iterator.go @@ -39,6 +39,7 @@ import ( // and whether the last check we received was true or false. type Optional struct { Base + uid uint64 tags graph.Tagger subIt graph.Iterator lastCheck bool @@ -50,9 +51,14 @@ func NewOptional(it graph.Iterator) *Optional { BaseInit(&o.Base) o.canNext = false o.subIt = it + o.uid = NextUID() return &o } +func (it *Optional) UID() uint64 { + return it.uid +} + func (it *Optional) Reset() { it.subIt.Reset() it.lastCheck = false diff --git a/graph/iterator/or_iterator.go b/graph/iterator/or_iterator.go index da1da5c..e84c629 100644 --- a/graph/iterator/or_iterator.go +++ b/graph/iterator/or_iterator.go @@ -30,6 +30,7 @@ import ( type Or struct { Base + uid uint64 tags graph.Tagger isShortCircuiting bool internalIterators []graph.Iterator @@ -38,23 +39,30 @@ type Or struct { } func NewOr() *Or { - var or Or + or := Or{ + uid: NextUID(), + internalIterators: make([]graph.Iterator, 0, 20), + currentIterator: -1, + } BaseInit(&or.Base) - or.internalIterators = make([]graph.Iterator, 0, 20) - or.isShortCircuiting = false - or.currentIterator = -1 return &or } func NewShortCircuitOr() *Or { - var or Or + or := Or{ + uid: NextUID(), + internalIterators: make([]graph.Iterator, 0, 20), + isShortCircuiting: true, + currentIterator: -1, + } BaseInit(&or.Base) - or.internalIterators = make([]graph.Iterator, 0, 20) - or.isShortCircuiting = true - or.currentIterator = -1 return &or } +func (it *Or) UID() uint64 { + return it.uid +} + // Reset all internal iterators func (it *Or) Reset() { for _, sub := range it.internalIterators { diff --git a/graph/iterator/value_comparison_iterator.go b/graph/iterator/value_comparison_iterator.go index 6b89cd7..c29fda0 100644 --- a/graph/iterator/value_comparison_iterator.go +++ b/graph/iterator/value_comparison_iterator.go @@ -47,6 +47,7 @@ const ( type Comparison struct { Base + uid uint64 tags graph.Tagger subIt graph.Iterator op Operator @@ -55,15 +56,21 @@ type Comparison struct { } func NewComparison(sub graph.Iterator, op Operator, val interface{}, ts graph.TripleStore) *Comparison { - var vc Comparison + vc := Comparison{ + uid: NextUID(), + subIt: sub, + op: op, + val: val, + ts: ts, + } BaseInit(&vc.Base) - vc.subIt = sub - vc.op = op - vc.val = val - vc.ts = ts return &vc } +func (it *Comparison) UID() uint64 { + return it.uid +} + // Here's the non-boilerplate part of the ValueComparison iterator. Given a value // and our operator, determine whether or not we meet the requirement. func (it *Comparison) doComparison(val graph.Value) bool { diff --git a/graph/leveldb/all_iterator.go b/graph/leveldb/all_iterator.go index 177eec0..84d815c 100644 --- a/graph/leveldb/all_iterator.go +++ b/graph/leveldb/all_iterator.go @@ -28,6 +28,7 @@ import ( type AllIterator struct { iterator.Base + uid uint64 tags graph.Tagger prefix []byte dir graph.Direction @@ -38,23 +39,36 @@ type AllIterator struct { } func NewAllIterator(prefix string, d graph.Direction, ts *TripleStore) *AllIterator { - var it AllIterator + opts := &opt.ReadOptions{ + DontFillCache: true, + } + + it := AllIterator{ + uid: iterator.NextUID(), + ro: opts, + iter: ts.db.NewIterator(nil, opts), + prefix: []byte(prefix), + dir: d, + open: true, + ts: ts, + } iterator.BaseInit(&it.Base) - it.ro = &opt.ReadOptions{} - it.ro.DontFillCache = true - it.iter = ts.db.NewIterator(nil, it.ro) - it.prefix = []byte(prefix) - it.dir = d - it.open = true - it.ts = ts + it.iter.Seek(it.prefix) if !it.iter.Valid() { + // FIXME(kortschak) What are the semantics here? Is this iterator usable? + // If not, we should return nil *Iterator and an error. it.open = false it.iter.Release() } + return &it } +func (it *AllIterator) UID() uint64 { + return it.uid +} + func (it *AllIterator) Reset() { if !it.open { it.iter = it.ts.db.NewIterator(nil, it.ro) diff --git a/graph/leveldb/iterator.go b/graph/leveldb/iterator.go index 53301cc..c4c98a3 100644 --- a/graph/leveldb/iterator.go +++ b/graph/leveldb/iterator.go @@ -28,6 +28,7 @@ import ( type Iterator struct { iterator.Base + uid uint64 tags graph.Tagger nextPrefix []byte checkId []byte @@ -40,27 +41,43 @@ type Iterator struct { } func NewIterator(prefix string, d graph.Direction, value graph.Value, ts *TripleStore) *Iterator { - var it Iterator + vb := value.([]byte) + p := make([]byte, 0, 2+ts.hasher.Size()) + p = append(p, []byte(prefix)...) + p = append(p, []byte(vb[1:])...) + + opts := &opt.ReadOptions{ + DontFillCache: true, + } + + it := Iterator{ + uid: iterator.NextUID(), + nextPrefix: p, + checkId: vb, + dir: d, + originalPrefix: prefix, + ro: opts, + iter: ts.db.NewIterator(nil, opts), + open: true, + ts: ts, + } iterator.BaseInit(&it.Base) - it.checkId = value.([]byte) - it.dir = d - it.originalPrefix = prefix - it.nextPrefix = make([]byte, 0, 2+ts.hasher.Size()) - it.nextPrefix = append(it.nextPrefix, []byte(prefix)...) - it.nextPrefix = append(it.nextPrefix, []byte(it.checkId[1:])...) - it.ro = &opt.ReadOptions{} - it.ro.DontFillCache = true - it.iter = ts.db.NewIterator(nil, it.ro) - it.open = true - it.ts = ts + ok := it.iter.Seek(it.nextPrefix) if !ok { + // FIXME(kortschak) What are the semantics here? Is this iterator usable? + // If not, we should return nil *Iterator and an error. it.open = false it.iter.Release() } + return &it } +func (it *Iterator) UID() uint64 { + return it.uid +} + func (it *Iterator) Reset() { if !it.open { it.iter = it.ts.db.NewIterator(nil, it.ro) diff --git a/graph/memstore/iterator.go b/graph/memstore/iterator.go index a5db108..7d08a09 100644 --- a/graph/memstore/iterator.go +++ b/graph/memstore/iterator.go @@ -27,6 +27,7 @@ import ( type Iterator struct { iterator.Base + uid uint64 tags graph.Tagger tree *llrb.LLRB data string @@ -54,14 +55,20 @@ func IterateOne(tree *llrb.LLRB, last Int64) Int64 { } func NewLlrbIterator(tree *llrb.LLRB, data string) *Iterator { - var it Iterator + it := Iterator{ + uid: iterator.NextUID(), + tree: tree, + iterLast: Int64(-1), + data: data, + } iterator.BaseInit(&it.Base) - it.tree = tree - it.iterLast = Int64(-1) - it.data = data return &it } +func (it *Iterator) UID() uint64 { + return it.uid +} + func (it *Iterator) Reset() { it.iterLast = Int64(-1) } diff --git a/graph/mongo/iterator.go b/graph/mongo/iterator.go index 4996572..a5b6dc7 100644 --- a/graph/mongo/iterator.go +++ b/graph/mongo/iterator.go @@ -28,6 +28,7 @@ import ( type Iterator struct { iterator.Base + uid uint64 tags graph.Tagger ts *TripleStore dir graph.Direction @@ -41,54 +42,72 @@ type Iterator struct { } func NewIterator(ts *TripleStore, collection string, d graph.Direction, val graph.Value) *Iterator { - var m Iterator - iterator.BaseInit(&m.Base) + name := ts.NameOf(val) - m.name = ts.NameOf(val) - m.collection = collection + var constraint bson.M switch d { case graph.Subject: - m.constraint = bson.M{"Subject": m.name} + constraint = bson.M{"Subject": name} case graph.Predicate: - m.constraint = bson.M{"Predicate": m.name} + constraint = bson.M{"Predicate": name} case graph.Object: - m.constraint = bson.M{"Object": m.name} + constraint = bson.M{"Object": name} case graph.Provenance: - m.constraint = bson.M{"Provenance": m.name} + constraint = bson.M{"Provenance": name} } - m.ts = ts - m.dir = d - m.iter = ts.db.C(collection).Find(m.constraint).Iter() - size, err := ts.db.C(collection).Find(m.constraint).Count() + size, err := ts.db.C(collection).Find(constraint).Count() if err != nil { + // FIXME(kortschak) This should be passed back rather than just logging. glog.Errorln("Trouble getting size for iterator! ", err) return nil } - m.size = int64(size) - m.hash = val.(string) - m.isAll = false + + m := Iterator{ + uid: iterator.NextUID(), + name: name, + constraint: constraint, + collection: collection, + ts: ts, + dir: d, + iter: ts.db.C(collection).Find(constraint).Iter(), + size: int64(size), + hash: val.(string), + isAll: false, + } + iterator.BaseInit(&m.Base) + return &m } func NewAllIterator(ts *TripleStore, collection string) *Iterator { - var m Iterator - m.ts = ts - m.dir = graph.Any - m.constraint = nil - m.collection = collection - m.iter = ts.db.C(collection).Find(nil).Iter() size, err := ts.db.C(collection).Count() if err != nil { + // FIXME(kortschak) This should be passed back rather than just logging. glog.Errorln("Trouble getting size for iterator! ", err) return nil } - m.size = int64(size) - m.hash = "" - m.isAll = true + + m := Iterator{ + uid: iterator.NextUID(), + ts: ts, + dir: graph.Any, + constraint: nil, + collection: collection, + iter: ts.db.C(collection).Find(nil).Iter(), + size: int64(size), + hash: "", + isAll: true, + } + // FIXME(kortschak) Was there supposed to be a BaseInit call here? + return &m } +func (it *Iterator) UID() uint64 { + return it.uid +} + func (it *Iterator) Reset() { it.iter.Close() it.iter = it.ts.db.C(it.collection).Find(it.constraint).Iter() From 189910c4b8a84e994e41ab73b1c42170ee3391d0 Mon Sep 17 00:00:00 2001 From: kortschak Date: Wed, 30 Jul 2014 12:08:44 +0930 Subject: [PATCH 4/9] Remove Base dependency from Null --- graph/iterator/iterator.go | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/graph/iterator/iterator.go b/graph/iterator/iterator.go index 130dd6c..6ec1533 100644 --- a/graph/iterator/iterator.go +++ b/graph/iterator/iterator.go @@ -85,26 +85,18 @@ func (it *Base) Size() (int64, bool) { return 0, true } -// No subiterators. Only those with subiterators need to do anything here. -func (it *Base) SubIterators() []graph.Iterator { - return nil -} - // Accessor func (it *Base) CanNext() bool { return it.canNext } // Nothing to clean up. // func (it *Base) Close() {} -func (it *Null) Close() {} - func (it *Base) Reset() {} -// Here we define the simplest base iterator -- the Null iterator. It contains nothing. +// Here we define the simplest iterator -- the Null iterator. It contains nothing. // It is the empty set. Often times, queries that contain one of these match nothing, // so it's important to give it a special iterator. type Null struct { - Base uid uint64 tags graph.Tagger } @@ -133,6 +125,10 @@ func (it *Null) TagResults(dst map[string]graph.Value) { } } +func (it *Null) Check(graph.Value) bool { + return false +} + func (it *Null) Clone() graph.Iterator { return NewNull() } // Name the null iterator. @@ -147,6 +143,37 @@ func (it *Null) DebugString(indent int) string { return strings.Repeat(" ", indent) + "(null)" } +func (it *Null) CanNext() bool { return true } + +func (it *Null) Next() (graph.Value, bool) { + return nil, false +} + +func (it *Null) Result() graph.Value { + return nil +} + +func (it *Null) ResultTree() *graph.ResultTree { + tree := graph.NewResultTree(it.Result()) + return tree +} + +func (it *Null) SubIterators() []graph.Iterator { + return nil +} + +func (it *Null) NextResult() bool { + return false +} + +func (it *Null) Size() (int64, bool) { + return 0, true +} + +func (it *Null) Reset() {} + +func (it *Null) Close() {} + // A null iterator costs nothing. Use it! func (it *Null) Stats() graph.IteratorStats { return graph.IteratorStats{} From 525230206a0ed079e1bdfaebf5ec280ec97d0140 Mon Sep 17 00:00:00 2001 From: kortschak Date: Wed, 30 Jul 2014 12:11:14 +0930 Subject: [PATCH 5/9] Move SubIterator handling out of Base --- graph/iterator/all_iterator.go | 5 +++++ graph/iterator/fixed_iterator.go | 5 +++++ graph/iterator/optional_iterator.go | 7 ++++++- graph/iterator/value_comparison_iterator.go | 5 +++++ graph/leveldb/all_iterator.go | 5 +++++ graph/leveldb/iterator.go | 5 +++++ graph/memstore/all_iterator.go | 5 +++++ graph/memstore/iterator.go | 5 +++++ graph/mongo/iterator.go | 5 +++++ 9 files changed, 46 insertions(+), 1 deletion(-) diff --git a/graph/iterator/all_iterator.go b/graph/iterator/all_iterator.go index 9bf6441..004bc68 100644 --- a/graph/iterator/all_iterator.go +++ b/graph/iterator/all_iterator.go @@ -103,6 +103,11 @@ func (it *Int64) Next() (graph.Value, bool) { return graph.NextLogOut(it, val, true) } +// No sub-iterators. +func (it *Int64) SubIterators() []graph.Iterator { + return nil +} + // The number of elements in an Int64 is the size of the range. // The size is exact. func (it *Int64) Size() (int64, bool) { diff --git a/graph/iterator/fixed_iterator.go b/graph/iterator/fixed_iterator.go index 61e9b50..23bf177 100644 --- a/graph/iterator/fixed_iterator.go +++ b/graph/iterator/fixed_iterator.go @@ -149,6 +149,11 @@ func (it *Fixed) Next() (graph.Value, bool) { return graph.NextLogOut(it, out, true) } +// No sub-iterators. +func (it *Fixed) SubIterators() []graph.Iterator { + return nil +} + // Optimize() for a Fixed iterator is simple. Returns a Null iterator if it's empty // (so that other iterators upstream can treat this as null) or there is no // optimization. diff --git a/graph/iterator/optional_iterator.go b/graph/iterator/optional_iterator.go index defee8c..fa9396d 100644 --- a/graph/iterator/optional_iterator.go +++ b/graph/iterator/optional_iterator.go @@ -35,7 +35,7 @@ import ( "github.com/google/cayley/graph" ) -// An optional iterator has the subconstraint iterator we wish to be optional +// An optional iterator has the sub-constraint iterator we wish to be optional // and whether the last check we received was true or false. type Optional struct { Base @@ -95,6 +95,11 @@ func (it *Optional) NextResult() bool { return false } +// No subiterators. +func (it *Optional) SubIterators() []graph.Iterator { + return nil +} + // Check() is the real hack of this iterator. It always returns true, regardless // of whether the subiterator matched. But we keep track of whether the subiterator // matched for results purposes. diff --git a/graph/iterator/value_comparison_iterator.go b/graph/iterator/value_comparison_iterator.go index c29fda0..c0631fe 100644 --- a/graph/iterator/value_comparison_iterator.go +++ b/graph/iterator/value_comparison_iterator.go @@ -159,6 +159,11 @@ func (it *Comparison) NextResult() bool { return true } +// No subiterators. +func (it *Comparison) SubIterators() []graph.Iterator { + return nil +} + func (it *Comparison) Check(val graph.Value) bool { if !it.doComparison(val) { return false diff --git a/graph/leveldb/all_iterator.go b/graph/leveldb/all_iterator.go index 84d815c..80046c3 100644 --- a/graph/leveldb/all_iterator.go +++ b/graph/leveldb/all_iterator.go @@ -121,6 +121,11 @@ func (it *AllIterator) Next() (graph.Value, bool) { return out, true } +// No subiterators. +func (it *AllIterator) SubIterators() []graph.Iterator { + return nil +} + func (it *AllIterator) Check(v graph.Value) bool { it.Last = v return true diff --git a/graph/leveldb/iterator.go b/graph/leveldb/iterator.go index c4c98a3..d677bcb 100644 --- a/graph/leveldb/iterator.go +++ b/graph/leveldb/iterator.go @@ -146,6 +146,11 @@ func (it *Iterator) Next() (graph.Value, bool) { return nil, false } +// No subiterators. +func (it *Iterator) SubIterators() []graph.Iterator { + return nil +} + func PositionOf(prefix []byte, d graph.Direction, ts *TripleStore) int { if bytes.Equal(prefix, []byte("sp")) { switch d { diff --git a/graph/memstore/all_iterator.go b/graph/memstore/all_iterator.go index 371a958..204a015 100644 --- a/graph/memstore/all_iterator.go +++ b/graph/memstore/all_iterator.go @@ -31,6 +31,11 @@ func NewMemstoreAllIterator(ts *TripleStore) *AllIterator { return &out } +// No subiterators. +func (it *AllIterator) SubIterators() []graph.Iterator { + return nil +} + func (it *AllIterator) Next() (graph.Value, bool) { next, out := it.Int64.Next() if !out { diff --git a/graph/memstore/iterator.go b/graph/memstore/iterator.go index 7d08a09..290fef6 100644 --- a/graph/memstore/iterator.go +++ b/graph/memstore/iterator.go @@ -105,6 +105,11 @@ func (it *Iterator) Next() (graph.Value, bool) { return graph.NextLogOut(it, it.Last, true) } +// No subiterators. +func (it *Iterator) SubIterators() []graph.Iterator { + return nil +} + func (it *Iterator) Size() (int64, bool) { return int64(it.tree.Len()), true } diff --git a/graph/mongo/iterator.go b/graph/mongo/iterator.go index a5b6dc7..3afe77e 100644 --- a/graph/mongo/iterator.go +++ b/graph/mongo/iterator.go @@ -162,6 +162,11 @@ func (it *Iterator) Next() (graph.Value, bool) { return result.Id, true } +// No subiterators. +func (it *Iterator) SubIterators() []graph.Iterator { + return nil +} + func (it *Iterator) Check(v graph.Value) bool { graph.CheckLogIn(it, v) if it.isAll { From ee6d4c8db727849ed2447bdba916f05d02454a2c Mon Sep 17 00:00:00 2001 From: kortschak Date: Wed, 30 Jul 2014 12:14:46 +0930 Subject: [PATCH 6/9] Move Size handling out of Base --- graph/iterator/hasa_iterator.go | 4 ++++ graph/iterator/iterator.go | 5 ----- graph/iterator/linksto_iterator.go | 4 ++++ graph/iterator/optional_iterator.go | 5 +++++ graph/iterator/value_comparison_iterator.go | 4 ++++ 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/graph/iterator/hasa_iterator.go b/graph/iterator/hasa_iterator.go index f883fd7..dc6eb66 100644 --- a/graph/iterator/hasa_iterator.go +++ b/graph/iterator/hasa_iterator.go @@ -240,3 +240,7 @@ func (it *HasA) Close() { // Register this iterator as a HasA. func (it *HasA) Type() graph.Type { return graph.HasA } + +func (it *HasA) Size() (int64, bool) { + return 0, true +} diff --git a/graph/iterator/iterator.go b/graph/iterator/iterator.go index 6ec1533..96153a2 100644 --- a/graph/iterator/iterator.go +++ b/graph/iterator/iterator.go @@ -80,11 +80,6 @@ func (it *Base) Result() graph.Value { return it.Last } -// If you're empty and you know it, clap your hands. -func (it *Base) Size() (int64, bool) { - return 0, true -} - // Accessor func (it *Base) CanNext() bool { return it.canNext } diff --git a/graph/iterator/linksto_iterator.go b/graph/iterator/linksto_iterator.go index e61dc09..403a799 100644 --- a/graph/iterator/linksto_iterator.go +++ b/graph/iterator/linksto_iterator.go @@ -200,3 +200,7 @@ func (it *LinksTo) Stats() graph.IteratorStats { Size: fanoutFactor * subitStats.Size, } } + +func (it *LinksTo) Size() (int64, bool) { + return 0, true +} diff --git a/graph/iterator/optional_iterator.go b/graph/iterator/optional_iterator.go index fa9396d..5dec887 100644 --- a/graph/iterator/optional_iterator.go +++ b/graph/iterator/optional_iterator.go @@ -151,3 +151,8 @@ func (it *Optional) Stats() graph.IteratorStats { Size: subStats.Size, } } + +// If you're empty and you know it, clap your hands. +func (it *Optional) Size() (int64, bool) { + return 0, true +} diff --git a/graph/iterator/value_comparison_iterator.go b/graph/iterator/value_comparison_iterator.go index c0631fe..e75e658 100644 --- a/graph/iterator/value_comparison_iterator.go +++ b/graph/iterator/value_comparison_iterator.go @@ -212,3 +212,7 @@ func (it *Comparison) Optimize() (graph.Iterator, bool) { func (it *Comparison) Stats() graph.IteratorStats { return it.subIt.Stats() } + +func (it *Base) Size() (int64, bool) { + return 0, true +} From 375d953d9341f4de161f60231df5161d69bc5416 Mon Sep 17 00:00:00 2001 From: kortschak Date: Wed, 30 Jul 2014 15:01:09 +0930 Subject: [PATCH 7/9] Move current result handling out of Base Delete majority of Base functionality. --- graph/iterator/all_iterator.go | 14 ++++++++-- graph/iterator/and_iterator.go | 13 ++++++--- graph/iterator/fixed_iterator.go | 14 ++++++++-- graph/iterator/hasa_iterator.go | 9 +++++-- graph/iterator/iterator.go | 42 +---------------------------- graph/iterator/linksto_iterator.go | 9 +++++-- graph/iterator/optional_iterator.go | 15 ++++++++++- graph/iterator/or_iterator.go | 11 +++++--- graph/iterator/value_comparison_iterator.go | 28 ++++++++++++------- graph/leveldb/all_iterator.go | 15 ++++++++--- graph/leveldb/iterator.go | 19 +++++++++---- graph/memstore/all_iterator.go | 1 - graph/memstore/iterator.go | 17 +++++++++--- graph/mongo/iterator.go | 15 ++++++++--- 14 files changed, 140 insertions(+), 82 deletions(-) diff --git a/graph/iterator/all_iterator.go b/graph/iterator/all_iterator.go index 004bc68..9466cb4 100644 --- a/graph/iterator/all_iterator.go +++ b/graph/iterator/all_iterator.go @@ -36,6 +36,7 @@ type Int64 struct { tags graph.Tagger max, min int64 at int64 + result graph.Value } // Creates a new Int64 with the given range. @@ -99,10 +100,19 @@ func (it *Int64) Next() (graph.Value, bool) { if it.at > it.max { it.at = -1 } - it.Last = val + it.result = val return graph.NextLogOut(it, val, true) } +// DEPRECATED +func (it *Int64) ResultTree() *graph.ResultTree { + return graph.NewResultTree(it.Result()) +} + +func (it *Int64) Result() graph.Value { + return it.result +} + // No sub-iterators. func (it *Int64) SubIterators() []graph.Iterator { return nil @@ -121,7 +131,7 @@ func (it *Int64) Check(tsv graph.Value) bool { graph.CheckLogIn(it, tsv) v := tsv.(int64) if it.min <= v && v <= it.max { - it.Last = v + it.result = v return graph.CheckLogOut(it, v, true) } return graph.CheckLogOut(it, v, false) diff --git a/graph/iterator/and_iterator.go b/graph/iterator/and_iterator.go index a7dce74..938d9f8 100644 --- a/graph/iterator/and_iterator.go +++ b/graph/iterator/and_iterator.go @@ -32,6 +32,7 @@ type And struct { itCount int primaryIt graph.Iterator checkList []graph.Iterator + result graph.Value } // Creates a new And iterator. @@ -167,11 +168,15 @@ func (it *And) Next() (graph.Value, bool) { return graph.NextLogOut(it, nil, false) } if it.checkSubIts(curr) { - it.Last = curr + it.result = curr return graph.NextLogOut(it, curr, true) } } - panic("Somehow broke out of Next() loop in And") + panic("unreachable") +} + +func (it *And) Result() graph.Value { + return it.result } // Checks a value against the non-primary iterators, in order. @@ -195,7 +200,7 @@ func (it *And) checkCheckList(val graph.Value) bool { } } if ok { - it.Last = val + it.result = val } return graph.CheckLogOut(it, val, ok) } @@ -214,7 +219,7 @@ func (it *And) Check(val graph.Value) bool { if !othersGood { return graph.CheckLogOut(it, val, false) } - it.Last = val + it.result = val return graph.CheckLogOut(it, val, true) } diff --git a/graph/iterator/fixed_iterator.go b/graph/iterator/fixed_iterator.go index 23bf177..82e308a 100644 --- a/graph/iterator/fixed_iterator.go +++ b/graph/iterator/fixed_iterator.go @@ -36,6 +36,7 @@ type Fixed struct { values []graph.Value lastIndex int cmp Equality + result graph.Value } // Define the signature of an equality function. @@ -130,7 +131,7 @@ func (it *Fixed) Check(v graph.Value) bool { graph.CheckLogIn(it, v) for _, x := range it.values { if it.cmp(x, v) { - it.Last = x + it.result = x return graph.CheckLogOut(it, v, true) } } @@ -144,11 +145,20 @@ func (it *Fixed) Next() (graph.Value, bool) { return graph.NextLogOut(it, nil, false) } out := it.values[it.lastIndex] - it.Last = out + it.result = out it.lastIndex++ return graph.NextLogOut(it, out, true) } +// DEPRECATED +func (it *Fixed) ResultTree() *graph.ResultTree { + return graph.NewResultTree(it.Result()) +} + +func (it *Fixed) Result() graph.Value { + return it.result +} + // No sub-iterators. func (it *Fixed) SubIterators() []graph.Iterator { return nil diff --git a/graph/iterator/hasa_iterator.go b/graph/iterator/hasa_iterator.go index dc6eb66..ea9d2cc 100644 --- a/graph/iterator/hasa_iterator.go +++ b/graph/iterator/hasa_iterator.go @@ -53,6 +53,7 @@ type HasA struct { primaryIt graph.Iterator dir graph.Direction resultIt graph.Iterator + result graph.Value } // Construct a new HasA iterator, given the triple subiterator, and the triple @@ -168,7 +169,7 @@ func (it *HasA) GetCheckResult() bool { glog.V(4).Infoln("Triple is", it.ts.Triple(linkVal)) } if it.primaryIt.Check(linkVal) { - it.Last = it.ts.TripleDirection(linkVal, it.dir) + it.result = it.ts.TripleDirection(linkVal, it.dir) return true } } @@ -205,10 +206,14 @@ func (it *HasA) Next() (graph.Value, bool) { } name := it.ts.Triple(tID).Get(it.dir) val := it.ts.ValueOf(name) - it.Last = val + it.result = val return graph.NextLogOut(it, val, true) } +func (it *HasA) Result() graph.Value { + return it.result +} + // GetStats() returns the statistics on the HasA iterator. This is curious. Next // cost is easy, it's an extra call or so on top of the subiterator Next cost. // CheckCost involves going to the graph.TripleStore, iterating out values, and hoping diff --git a/graph/iterator/iterator.go b/graph/iterator/iterator.go index 96153a2..cb06965 100644 --- a/graph/iterator/iterator.go +++ b/graph/iterator/iterator.go @@ -18,7 +18,6 @@ package iterator // iterators can "inherit" from to get default iterator functionality. import ( - "fmt" "strings" "sync/atomic" @@ -34,7 +33,6 @@ func NextUID() uint64 { // The Base iterator is the iterator other iterators inherit from to get some // default functionality. type Base struct { - Last graph.Value canNext bool } @@ -44,50 +42,13 @@ func BaseInit(it *Base) { it.canNext = true } -// Prints a silly debug string. Most classes override. -func (it *Base) DebugString(indent int) string { - return fmt.Sprintf("%s(base)", strings.Repeat(" ", indent)) -} - -// Nothing in a base iterator. -func (it *Base) Check(v graph.Value) bool { - return false -} - -// Base iterators should never appear in a tree if they are, select against -// them. -func (it *Base) Stats() graph.IteratorStats { - return graph.IteratorStats{100000, 100000, 100000} -} - -// DEPRECATED -func (it *Base) ResultTree() *graph.ResultTree { - tree := graph.NewResultTree(it.Result()) - return tree -} - -// Nothing in a base iterator. -func (it *Base) Next() (graph.Value, bool) { - return nil, false -} - func (it *Base) NextResult() bool { return false } -// Returns the last result of an iterator. -func (it *Base) Result() graph.Value { - return it.Last -} - // Accessor func (it *Base) CanNext() bool { return it.canNext } -// Nothing to clean up. -// func (it *Base) Close() {} - -func (it *Base) Reset() {} - // Here we define the simplest iterator -- the Null iterator. It contains nothing. // It is the empty set. Often times, queries that contain one of these match nothing, // so it's important to give it a special iterator. @@ -149,8 +110,7 @@ func (it *Null) Result() graph.Value { } func (it *Null) ResultTree() *graph.ResultTree { - tree := graph.NewResultTree(it.Result()) - return tree + return graph.NewResultTree(it.Result()) } func (it *Null) SubIterators() []graph.Iterator { diff --git a/graph/iterator/linksto_iterator.go b/graph/iterator/linksto_iterator.go index 403a799..80071c4 100644 --- a/graph/iterator/linksto_iterator.go +++ b/graph/iterator/linksto_iterator.go @@ -47,6 +47,7 @@ type LinksTo struct { primaryIt graph.Iterator dir graph.Direction nextIt graph.Iterator + result graph.Value } // Construct a new LinksTo iterator around a direction and a subiterator of @@ -121,7 +122,7 @@ func (it *LinksTo) Check(val graph.Value) bool { graph.CheckLogIn(it, val) node := it.ts.TripleDirection(val, it.dir) if it.primaryIt.Check(node) { - it.Last = val + it.result = val return graph.CheckLogOut(it, val, true) } return graph.CheckLogOut(it, val, false) @@ -169,10 +170,14 @@ func (it *LinksTo) Next() (graph.Value, bool) { // Recurse -- return the first in the next set. return it.Next() } - it.Last = val + it.result = val return graph.NextLogOut(it, val, ok) } +func (it *LinksTo) Result() graph.Value { + return it.result +} + // Close our subiterators. func (it *LinksTo) Close() { it.nextIt.Close() diff --git a/graph/iterator/optional_iterator.go b/graph/iterator/optional_iterator.go index 5dec887..e87549b 100644 --- a/graph/iterator/optional_iterator.go +++ b/graph/iterator/optional_iterator.go @@ -43,6 +43,7 @@ type Optional struct { tags graph.Tagger subIt graph.Iterator lastCheck bool + result graph.Value } // Creates a new optional iterator. @@ -78,6 +79,9 @@ func (it *Optional) Clone() graph.Iterator { return out } +// FIXME(kortschak) When we create a Nexter interface the +// following two methods need to go away. + // Nexting the iterator is unsupported -- error and return an empty set. // (As above, a reasonable alternative would be to Next() an all iterator) func (it *Optional) Next() (graph.Value, bool) { @@ -85,6 +89,15 @@ func (it *Optional) Next() (graph.Value, bool) { return nil, false } +// DEPRECATED +func (it *Optional) ResultTree() *graph.ResultTree { + return graph.NewResultTree(it.Result()) +} + +func (it *Optional) Result() graph.Value { + return it.result +} + // An optional iterator only has a next result if, (a) last time we checked // we had any results whatsoever, and (b) there was another subresult in our // optional subbranch. @@ -106,7 +119,7 @@ func (it *Optional) SubIterators() []graph.Iterator { func (it *Optional) Check(val graph.Value) bool { checked := it.subIt.Check(val) it.lastCheck = checked - it.Last = val + it.result = val return true } diff --git a/graph/iterator/or_iterator.go b/graph/iterator/or_iterator.go index e84c629..20318bf 100644 --- a/graph/iterator/or_iterator.go +++ b/graph/iterator/or_iterator.go @@ -36,6 +36,7 @@ type Or struct { internalIterators []graph.Iterator itCount int currentIterator int + result graph.Value } func NewOr() *Or { @@ -169,11 +170,15 @@ func (it *Or) Next() (graph.Value, bool) { return graph.NextLogOut(it, nil, false) } } else { - it.Last = curr + it.result = curr return graph.NextLogOut(it, curr, true) } } - panic("Somehow broke out of Next() loop in Or") + panic("unreachable") +} + +func (it *Or) Result() graph.Value { + return it.result } // Checks a value against the iterators, in order. @@ -196,7 +201,7 @@ func (it *Or) Check(val graph.Value) bool { if !anyGood { return graph.CheckLogOut(it, val, false) } - it.Last = val + it.result = val return graph.CheckLogOut(it, val, true) } diff --git a/graph/iterator/value_comparison_iterator.go b/graph/iterator/value_comparison_iterator.go index e75e658..6dfd7c5 100644 --- a/graph/iterator/value_comparison_iterator.go +++ b/graph/iterator/value_comparison_iterator.go @@ -47,12 +47,13 @@ const ( type Comparison struct { Base - uid uint64 - tags graph.Tagger - subIt graph.Iterator - op Operator - val interface{} - ts graph.TripleStore + uid uint64 + tags graph.Tagger + subIt graph.Iterator + op Operator + val interface{} + ts graph.TripleStore + result graph.Value } func NewComparison(sub graph.Iterator, op Operator, val interface{}, ts graph.TripleStore) *Comparison { @@ -141,10 +142,19 @@ func (it *Comparison) Next() (graph.Value, bool) { break } } - it.Last = val + it.result = val return val, ok } +// DEPRECATED +func (it *Comparison) ResultTree() *graph.ResultTree { + return graph.NewResultTree(it.Result()) +} + +func (it *Comparison) Result() graph.Value { + return it.result +} + func (it *Comparison) NextResult() bool { for { hasNext := it.subIt.NextResult() @@ -155,7 +165,7 @@ func (it *Comparison) NextResult() bool { return true } } - it.Last = it.subIt.Result() + it.result = it.subIt.Result() return true } @@ -213,6 +223,6 @@ func (it *Comparison) Stats() graph.IteratorStats { return it.subIt.Stats() } -func (it *Base) Size() (int64, bool) { +func (it *Comparison) Size() (int64, bool) { return 0, true } diff --git a/graph/leveldb/all_iterator.go b/graph/leveldb/all_iterator.go index 80046c3..27cb144 100644 --- a/graph/leveldb/all_iterator.go +++ b/graph/leveldb/all_iterator.go @@ -36,6 +36,7 @@ type AllIterator struct { iter ldbit.Iterator ts *TripleStore ro *opt.ReadOptions + result graph.Value } func NewAllIterator(prefix string, d graph.Direction, ts *TripleStore) *AllIterator { @@ -103,7 +104,7 @@ func (it *AllIterator) Clone() graph.Iterator { func (it *AllIterator) Next() (graph.Value, bool) { if !it.open { - it.Last = nil + it.result = nil return nil, false } var out []byte @@ -117,17 +118,25 @@ func (it *AllIterator) Next() (graph.Value, bool) { it.Close() return nil, false } - it.Last = out + it.result = out return out, true } +func (it *AllIterator) ResultTree() *graph.ResultTree { + return graph.NewResultTree(it.Result()) +} + +func (it *AllIterator) Result() graph.Value { + return it.result +} + // No subiterators. func (it *AllIterator) SubIterators() []graph.Iterator { return nil } func (it *AllIterator) Check(v graph.Value) bool { - it.Last = v + it.result = v return true } diff --git a/graph/leveldb/iterator.go b/graph/leveldb/iterator.go index d677bcb..1b6771e 100644 --- a/graph/leveldb/iterator.go +++ b/graph/leveldb/iterator.go @@ -38,6 +38,7 @@ type Iterator struct { ts *TripleStore ro *opt.ReadOptions originalPrefix string + result graph.Value } func NewIterator(prefix string, d graph.Direction, value graph.Value, ts *TripleStore) *Iterator { @@ -119,22 +120,22 @@ func (it *Iterator) Close() { func (it *Iterator) Next() (graph.Value, bool) { if it.iter == nil { - it.Last = nil + it.result = nil return nil, false } if !it.open { - it.Last = nil + it.result = nil return nil, false } if !it.iter.Valid() { - it.Last = nil + it.result = nil it.Close() return nil, false } if bytes.HasPrefix(it.iter.Key(), it.nextPrefix) { out := make([]byte, len(it.iter.Key())) copy(out, it.iter.Key()) - it.Last = out + it.result = out ok := it.iter.Next() if !ok { it.Close() @@ -142,10 +143,18 @@ func (it *Iterator) Next() (graph.Value, bool) { return out, true } it.Close() - it.Last = nil + it.result = nil return nil, false } +func (it *Iterator) ResultTree() *graph.ResultTree { + return graph.NewResultTree(it.Result()) +} + +func (it *Iterator) Result() graph.Value { + return it.result +} + // No subiterators. func (it *Iterator) SubIterators() []graph.Iterator { return nil diff --git a/graph/memstore/all_iterator.go b/graph/memstore/all_iterator.go index 204a015..658a4a1 100644 --- a/graph/memstore/all_iterator.go +++ b/graph/memstore/all_iterator.go @@ -46,6 +46,5 @@ func (it *AllIterator) Next() (graph.Value, bool) { if !ok { return it.Next() } - it.Last = next return next, out } diff --git a/graph/memstore/iterator.go b/graph/memstore/iterator.go index 290fef6..be6d1ff 100644 --- a/graph/memstore/iterator.go +++ b/graph/memstore/iterator.go @@ -33,6 +33,7 @@ type Iterator struct { data string isRunning bool iterLast Int64 + result graph.Value } type Int64 int64 @@ -97,12 +98,20 @@ func (it *Iterator) Close() {} func (it *Iterator) Next() (graph.Value, bool) { graph.NextLogIn(it) - if it.tree.Max() == nil || it.Last == int64(it.tree.Max().(Int64)) { + if it.tree.Max() == nil || it.result == int64(it.tree.Max().(Int64)) { return graph.NextLogOut(it, nil, false) } it.iterLast = IterateOne(it.tree, it.iterLast) - it.Last = int64(it.iterLast) - return graph.NextLogOut(it, it.Last, true) + it.result = int64(it.iterLast) + return graph.NextLogOut(it, it.result, true) +} + +func (it *Iterator) ResultTree() *graph.ResultTree { + return graph.NewResultTree(it.Result()) +} + +func (it *Iterator) Result() graph.Value { + return it.result } // No subiterators. @@ -117,7 +126,7 @@ func (it *Iterator) Size() (int64, bool) { func (it *Iterator) Check(v graph.Value) bool { graph.CheckLogIn(it, v) if it.tree.Has(Int64(v.(int64))) { - it.Last = v + it.result = v return graph.CheckLogOut(it, v, true) } return graph.CheckLogOut(it, v, false) diff --git a/graph/mongo/iterator.go b/graph/mongo/iterator.go index 3afe77e..ab752ef 100644 --- a/graph/mongo/iterator.go +++ b/graph/mongo/iterator.go @@ -39,6 +39,7 @@ type Iterator struct { isAll bool constraint bson.M collection string + result graph.Value } func NewIterator(ts *TripleStore, collection string, d graph.Direction, val graph.Value) *Iterator { @@ -158,10 +159,18 @@ func (it *Iterator) Next() (graph.Value, bool) { } return nil, false } - it.Last = result.Id + it.result = result.Id return result.Id, true } +func (it *Iterator) ResultTree() *graph.ResultTree { + return graph.NewResultTree(it.Result()) +} + +func (it *Iterator) Result() graph.Value { + return it.result +} + // No subiterators. func (it *Iterator) SubIterators() []graph.Iterator { return nil @@ -170,7 +179,7 @@ func (it *Iterator) SubIterators() []graph.Iterator { func (it *Iterator) Check(v graph.Value) bool { graph.CheckLogIn(it, v) if it.isAll { - it.Last = v + it.result = v return graph.CheckLogOut(it, v, true) } var offset int @@ -186,7 +195,7 @@ func (it *Iterator) Check(v graph.Value) bool { } val := v.(string)[offset : it.ts.hasher.Size()*2+offset] if val == it.hash { - it.Last = v + it.result = v return graph.CheckLogOut(it, v, true) } return graph.CheckLogOut(it, v, false) From b498a06a7b59e1e35af11ce6c66012c44dfbba14 Mon Sep 17 00:00:00 2001 From: kortschak Date: Wed, 30 Jul 2014 15:21:48 +0930 Subject: [PATCH 8/9] Intermediate step in removal of Base We are marking types that will be Nexters and ResultNexters (I want a better name for this one). --- graph/iterator/all_iterator.go | 8 +++++--- graph/iterator/and_iterator.go | 4 +--- graph/iterator/fixed_iterator.go | 8 +++++--- graph/iterator/hasa_iterator.go | 4 +--- graph/iterator/iterator.go | 13 +------------ graph/iterator/linksto_iterator.go | 4 +--- graph/iterator/optional_iterator.go | 13 ++++++------- graph/iterator/or_iterator.go | 8 ++------ graph/iterator/value_comparison_iterator.go | 4 +--- graph/leveldb/all_iterator.go | 5 ++++- graph/leveldb/iterator.go | 5 ++++- graph/memstore/iterator.go | 8 +++++--- graph/mongo/iterator.go | 14 ++++++-------- 13 files changed, 42 insertions(+), 56 deletions(-) diff --git a/graph/iterator/all_iterator.go b/graph/iterator/all_iterator.go index 9466cb4..8394a0e 100644 --- a/graph/iterator/all_iterator.go +++ b/graph/iterator/all_iterator.go @@ -41,14 +41,12 @@ type Int64 struct { // Creates a new Int64 with the given range. func NewInt64(min, max int64) *Int64 { - all := Int64{ + return &Int64{ uid: NextUID(), min: min, max: max, at: min, } - BaseInit(&all.Base) - return &all } func (it *Int64) UID() uint64 { @@ -113,6 +111,10 @@ func (it *Int64) Result() graph.Value { return it.result } +func (it *Int64) NextResult() bool { + return false +} + // No sub-iterators. func (it *Int64) SubIterators() []graph.Iterator { return nil diff --git a/graph/iterator/and_iterator.go b/graph/iterator/and_iterator.go index 938d9f8..ba7b70b 100644 --- a/graph/iterator/and_iterator.go +++ b/graph/iterator/and_iterator.go @@ -37,12 +37,10 @@ type And struct { // Creates a new And iterator. func NewAnd() *And { - and := And{ + return &And{ uid: NextUID(), internalIterators: make([]graph.Iterator, 0, 20), } - BaseInit(&and.Base) - return &and } func (it *And) UID() uint64 { diff --git a/graph/iterator/fixed_iterator.go b/graph/iterator/fixed_iterator.go index 82e308a..2caa8e9 100644 --- a/graph/iterator/fixed_iterator.go +++ b/graph/iterator/fixed_iterator.go @@ -57,13 +57,11 @@ func newFixed() *Fixed { // Creates a new Fixed iterator with a custom comparitor. func NewFixedIteratorWithCompare(compareFn Equality) *Fixed { - it := Fixed{ + return &Fixed{ uid: NextUID(), values: make([]graph.Value, 0, 20), cmp: compareFn, } - BaseInit(&it.Base) - return &it } func (it *Fixed) UID() uint64 { @@ -159,6 +157,10 @@ func (it *Fixed) Result() graph.Value { return it.result } +func (it *Fixed) NextResult() bool { + return false +} + // No sub-iterators. func (it *Fixed) SubIterators() []graph.Iterator { return nil diff --git a/graph/iterator/hasa_iterator.go b/graph/iterator/hasa_iterator.go index ea9d2cc..8d9ab46 100644 --- a/graph/iterator/hasa_iterator.go +++ b/graph/iterator/hasa_iterator.go @@ -59,14 +59,12 @@ type HasA struct { // Construct a new HasA iterator, given the triple subiterator, and the triple // direction for which it stands. func NewHasA(ts graph.TripleStore, subIt graph.Iterator, d graph.Direction) *HasA { - hasa := HasA{ + return &HasA{ uid: NextUID(), ts: ts, primaryIt: subIt, dir: d, } - BaseInit(&hasa.Base) - return &hasa } func (it *HasA) UID() uint64 { diff --git a/graph/iterator/iterator.go b/graph/iterator/iterator.go index cb06965..e290dc3 100644 --- a/graph/iterator/iterator.go +++ b/graph/iterator/iterator.go @@ -33,21 +33,10 @@ func NextUID() uint64 { // The Base iterator is the iterator other iterators inherit from to get some // default functionality. type Base struct { - canNext bool -} - -// Called by subclases. -func BaseInit(it *Base) { - // Your basic iterator is nextable - it.canNext = true -} - -func (it *Base) NextResult() bool { - return false } // Accessor -func (it *Base) CanNext() bool { return it.canNext } +func (it *Base) CanNext() bool { return true } // Here we define the simplest iterator -- the Null iterator. It contains nothing. // It is the empty set. Often times, queries that contain one of these match nothing, diff --git a/graph/iterator/linksto_iterator.go b/graph/iterator/linksto_iterator.go index 80071c4..fa7cf29 100644 --- a/graph/iterator/linksto_iterator.go +++ b/graph/iterator/linksto_iterator.go @@ -53,15 +53,13 @@ type LinksTo struct { // Construct a new LinksTo iterator around a direction and a subiterator of // nodes. func NewLinksTo(ts graph.TripleStore, it graph.Iterator, d graph.Direction) *LinksTo { - lto := LinksTo{ + return &LinksTo{ uid: NextUID(), ts: ts, primaryIt: it, dir: d, nextIt: &Null{}, } - BaseInit(<o.Base) - return <o } func (it *LinksTo) UID() uint64 { diff --git a/graph/iterator/optional_iterator.go b/graph/iterator/optional_iterator.go index e87549b..7b9435f 100644 --- a/graph/iterator/optional_iterator.go +++ b/graph/iterator/optional_iterator.go @@ -38,7 +38,6 @@ import ( // An optional iterator has the sub-constraint iterator we wish to be optional // and whether the last check we received was true or false. type Optional struct { - Base uid uint64 tags graph.Tagger subIt graph.Iterator @@ -48,14 +47,14 @@ type Optional struct { // Creates a new optional iterator. func NewOptional(it graph.Iterator) *Optional { - var o Optional - BaseInit(&o.Base) - o.canNext = false - o.subIt = it - o.uid = NextUID() - return &o + return &Optional{ + uid: NextUID(), + subIt: it, + } } +func (it *Optional) CanNext() bool { return false } + func (it *Optional) UID() uint64 { return it.uid } diff --git a/graph/iterator/or_iterator.go b/graph/iterator/or_iterator.go index 20318bf..db323ed 100644 --- a/graph/iterator/or_iterator.go +++ b/graph/iterator/or_iterator.go @@ -40,24 +40,20 @@ type Or struct { } func NewOr() *Or { - or := Or{ + return &Or{ uid: NextUID(), internalIterators: make([]graph.Iterator, 0, 20), currentIterator: -1, } - BaseInit(&or.Base) - return &or } func NewShortCircuitOr() *Or { - or := Or{ + return &Or{ uid: NextUID(), internalIterators: make([]graph.Iterator, 0, 20), isShortCircuiting: true, currentIterator: -1, } - BaseInit(&or.Base) - return &or } func (it *Or) UID() uint64 { diff --git a/graph/iterator/value_comparison_iterator.go b/graph/iterator/value_comparison_iterator.go index 6dfd7c5..ab5e698 100644 --- a/graph/iterator/value_comparison_iterator.go +++ b/graph/iterator/value_comparison_iterator.go @@ -57,15 +57,13 @@ type Comparison struct { } func NewComparison(sub graph.Iterator, op Operator, val interface{}, ts graph.TripleStore) *Comparison { - vc := Comparison{ + return &Comparison{ uid: NextUID(), subIt: sub, op: op, val: val, ts: ts, } - BaseInit(&vc.Base) - return &vc } func (it *Comparison) UID() uint64 { diff --git a/graph/leveldb/all_iterator.go b/graph/leveldb/all_iterator.go index 27cb144..673fbb9 100644 --- a/graph/leveldb/all_iterator.go +++ b/graph/leveldb/all_iterator.go @@ -53,7 +53,6 @@ func NewAllIterator(prefix string, d graph.Direction, ts *TripleStore) *AllItera open: true, ts: ts, } - iterator.BaseInit(&it.Base) it.iter.Seek(it.prefix) if !it.iter.Valid() { @@ -130,6 +129,10 @@ func (it *AllIterator) Result() graph.Value { return it.result } +func (it *AllIterator) NextResult() bool { + return false +} + // No subiterators. func (it *AllIterator) SubIterators() []graph.Iterator { return nil diff --git a/graph/leveldb/iterator.go b/graph/leveldb/iterator.go index 1b6771e..9f9b0bf 100644 --- a/graph/leveldb/iterator.go +++ b/graph/leveldb/iterator.go @@ -62,7 +62,6 @@ func NewIterator(prefix string, d graph.Direction, value graph.Value, ts *Triple open: true, ts: ts, } - iterator.BaseInit(&it.Base) ok := it.iter.Seek(it.nextPrefix) if !ok { @@ -155,6 +154,10 @@ func (it *Iterator) Result() graph.Value { return it.result } +func (it *Iterator) NextResult() bool { + return false +} + // No subiterators. func (it *Iterator) SubIterators() []graph.Iterator { return nil diff --git a/graph/memstore/iterator.go b/graph/memstore/iterator.go index be6d1ff..4be57db 100644 --- a/graph/memstore/iterator.go +++ b/graph/memstore/iterator.go @@ -56,14 +56,12 @@ func IterateOne(tree *llrb.LLRB, last Int64) Int64 { } func NewLlrbIterator(tree *llrb.LLRB, data string) *Iterator { - it := Iterator{ + return &Iterator{ uid: iterator.NextUID(), tree: tree, iterLast: Int64(-1), data: data, } - iterator.BaseInit(&it.Base) - return &it } func (it *Iterator) UID() uint64 { @@ -114,6 +112,10 @@ func (it *Iterator) Result() graph.Value { return it.result } +func (it *Iterator) NextResult() bool { + return false +} + // No subiterators. func (it *Iterator) SubIterators() []graph.Iterator { return nil diff --git a/graph/mongo/iterator.go b/graph/mongo/iterator.go index ab752ef..3389e9f 100644 --- a/graph/mongo/iterator.go +++ b/graph/mongo/iterator.go @@ -64,7 +64,7 @@ func NewIterator(ts *TripleStore, collection string, d graph.Direction, val grap return nil } - m := Iterator{ + return &Iterator{ uid: iterator.NextUID(), name: name, constraint: constraint, @@ -76,9 +76,6 @@ func NewIterator(ts *TripleStore, collection string, d graph.Direction, val grap hash: val.(string), isAll: false, } - iterator.BaseInit(&m.Base) - - return &m } func NewAllIterator(ts *TripleStore, collection string) *Iterator { @@ -89,7 +86,7 @@ func NewAllIterator(ts *TripleStore, collection string) *Iterator { return nil } - m := Iterator{ + return &Iterator{ uid: iterator.NextUID(), ts: ts, dir: graph.Any, @@ -100,9 +97,6 @@ func NewAllIterator(ts *TripleStore, collection string) *Iterator { hash: "", isAll: true, } - // FIXME(kortschak) Was there supposed to be a BaseInit call here? - - return &m } func (it *Iterator) UID() uint64 { @@ -171,6 +165,10 @@ func (it *Iterator) Result() graph.Value { return it.result } +func (it *Iterator) NextResult() bool { + return false +} + // No subiterators. func (it *Iterator) SubIterators() []graph.Iterator { return nil From d6f94be5141e13c147794609e2fc286b9e4c3c12 Mon Sep 17 00:00:00 2001 From: kortschak Date: Wed, 30 Jul 2014 16:06:46 +0930 Subject: [PATCH 9/9] Base nexting on interface satisfaction This is done unsubtlely at the moment and there is plenty of room for optimisation of assertion location to prevent repeated reasserting as is done now. --- graph/iterator.go | 31 ++++++++++++++++--------- graph/iterator/all_iterator.go | 1 - graph/iterator/and_iterator.go | 7 +++--- graph/iterator/and_iterator_optimize.go | 6 ++--- graph/iterator/fixed_iterator.go | 1 - graph/iterator/hasa_iterator.go | 5 ++-- graph/iterator/iterator.go | 13 +---------- graph/iterator/linksto_iterator.go | 5 ++-- graph/iterator/optional_iterator.go | 12 ---------- graph/iterator/or_iterator.go | 3 +-- graph/iterator/or_iterator_test.go | 2 +- graph/iterator/query_shape.go | 2 +- graph/iterator/value_comparison_iterator.go | 3 +-- graph/leveldb/all_iterator.go | 1 - graph/leveldb/iterator.go | 1 - graph/leveldb/leveldb_test.go | 10 ++++---- graph/leveldb/triplestore_iterator_optimize.go | 2 +- graph/memstore/iterator.go | 1 - graph/memstore/triplestore_iterator_optimize.go | 2 +- graph/memstore/triplestore_test.go | 2 +- graph/mongo/iterator.go | 1 - graph/mongo/triplestore_iterator_optimize.go | 2 +- graph/result_tree_evaluator.go | 4 ++-- graph/sexp/parser_test.go | 10 ++++---- graph/sexp/session.go | 2 +- query/gremlin/finals.go | 8 +++---- query/mql/session.go | 2 +- 27 files changed, 57 insertions(+), 82 deletions(-) diff --git a/graph/iterator.go b/graph/iterator.go index bb1faba..d28f43e 100644 --- a/graph/iterator.go +++ b/graph/iterator.go @@ -14,8 +14,7 @@ package graph -// Define the general iterator interface, as well as the Base iterator which all -// iterators can "inherit" from to get default iterator functionality. +// Define the general iterator interface. import ( "strings" @@ -86,19 +85,10 @@ type Iterator interface { // All of them should set iterator.Last to be the last returned value, to // make results work. // - // Next() advances the iterator and returns the next valid result. Returns - // (, true) or (nil, false) - Next() (Value, bool) - // NextResult() advances iterators that may have more than one valid result, // from the bottom up. NextResult() bool - // Return whether this iterator is reliably nextable. Most iterators are. - // However, some iterators, like "not" are, by definition, the whole database - // except themselves. Next() on these is unproductive, if impossible. - CanNext() bool - // Check(), given a value, returns whether or not that value is within the set // held by this iterator. Check(Value) bool @@ -145,6 +135,25 @@ type Iterator interface { UID() uint64 } +type Nexter interface { + // Next() advances the iterator and returns the next valid result. Returns + // (, true) or (nil, false) + Next() (Value, bool) + + Iterator +} + +// Next is a convenience function that conditionally calls the Next method +// of an Iterator if it is a Nexter. If the Iterator is not a Nexter, Next +// return a nil Value and false. +func Next(it Iterator) (Value, bool) { + if n, ok := it.(Nexter); ok { + return n.Next() + } + glog.Errorln("Nexting an un-nextable iterator") + return nil, false +} + // FixedIterator wraps iterators that are modifiable by addition of fixed value sets. type FixedIterator interface { Iterator diff --git a/graph/iterator/all_iterator.go b/graph/iterator/all_iterator.go index 8394a0e..ff1a869 100644 --- a/graph/iterator/all_iterator.go +++ b/graph/iterator/all_iterator.go @@ -31,7 +31,6 @@ import ( // An All iterator across a range of int64 values, from `max` to `min`. type Int64 struct { - Base uid uint64 tags graph.Tagger max, min int64 diff --git a/graph/iterator/and_iterator.go b/graph/iterator/and_iterator.go index ba7b70b..902b9a1 100644 --- a/graph/iterator/and_iterator.go +++ b/graph/iterator/and_iterator.go @@ -22,10 +22,9 @@ import ( "github.com/google/cayley/graph" ) -// The And iterator. Consists of a Base and a number of subiterators, the primary of which will +// The And iterator. Consists of a number of subiterators, the primary of which will // be Next()ed if next is called. type And struct { - Base uid uint64 tags graph.Tagger internalIterators []graph.Iterator @@ -60,7 +59,7 @@ func (it *And) Tagger() *graph.Tagger { return &it.tags } -// Overrides Base TagResults, as it needs to add it's own results and +// An extended TagResults, as it needs to add it's own results and // recurse down it's subiterators. func (it *And) TagResults(dst map[string]graph.Value) { for _, tag := range it.tags.Tags() { @@ -161,7 +160,7 @@ func (it *And) Next() (graph.Value, bool) { var curr graph.Value var exists bool for { - curr, exists = it.primaryIt.Next() + curr, exists = graph.Next(it.primaryIt) if !exists { return graph.NextLogOut(it, nil, false) } diff --git a/graph/iterator/and_iterator_optimize.go b/graph/iterator/and_iterator_optimize.go index 06def9f..20a4771 100644 --- a/graph/iterator/and_iterator_optimize.go +++ b/graph/iterator/and_iterator_optimize.go @@ -145,14 +145,14 @@ func optimizeOrder(its []graph.Iterator) []graph.Iterator { // all of it's contents, and to Check() each of those against everyone // else. for _, it := range its { - if !it.CanNext() { + if _, canNext := it.(graph.Nexter); !canNext { bad = append(bad, it) continue } rootStats := it.Stats() cost := rootStats.NextCost for _, f := range its { - if !f.CanNext() { + if _, canNext := it.(graph.Nexter); !canNext { continue } if f == it { @@ -177,7 +177,7 @@ func optimizeOrder(its []graph.Iterator) []graph.Iterator { // ... push everyone else after... for _, it := range its { - if !it.CanNext() { + if _, canNext := it.(graph.Nexter); !canNext { continue } if it != best { diff --git a/graph/iterator/fixed_iterator.go b/graph/iterator/fixed_iterator.go index 2caa8e9..6bfebb5 100644 --- a/graph/iterator/fixed_iterator.go +++ b/graph/iterator/fixed_iterator.go @@ -30,7 +30,6 @@ import ( // A Fixed iterator consists of it's values, an index (where it is in the process of Next()ing) and // an equality function. type Fixed struct { - Base uid uint64 tags graph.Tagger values []graph.Value diff --git a/graph/iterator/hasa_iterator.go b/graph/iterator/hasa_iterator.go index 8d9ab46..e6060b7 100644 --- a/graph/iterator/hasa_iterator.go +++ b/graph/iterator/hasa_iterator.go @@ -46,7 +46,6 @@ import ( // a primary subiterator, a direction in which the triples for that subiterator point, // and a temporary holder for the iterator generated on Check(). type HasA struct { - Base uid uint64 tags graph.Tagger ts graph.TripleStore @@ -159,7 +158,7 @@ func (it *HasA) Check(val graph.Value) bool { // another match is made. func (it *HasA) GetCheckResult() bool { for { - linkVal, ok := it.resultIt.Next() + linkVal, ok := graph.Next(it.resultIt) if !ok { break } @@ -198,7 +197,7 @@ func (it *HasA) Next() (graph.Value, bool) { } it.resultIt = &Null{} - tID, ok := it.primaryIt.Next() + tID, ok := graph.Next(it.primaryIt) if !ok { return graph.NextLogOut(it, 0, false) } diff --git a/graph/iterator/iterator.go b/graph/iterator/iterator.go index e290dc3..e80b56c 100644 --- a/graph/iterator/iterator.go +++ b/graph/iterator/iterator.go @@ -14,8 +14,7 @@ package iterator -// Define the general iterator interface, as well as the Base which all -// iterators can "inherit" from to get default iterator functionality. +// Define the general iterator interface. import ( "strings" @@ -30,14 +29,6 @@ func NextUID() uint64 { return atomic.AddUint64(&nextIteratorID, 1) - 1 } -// The Base iterator is the iterator other iterators inherit from to get some -// default functionality. -type Base struct { -} - -// Accessor -func (it *Base) CanNext() bool { return true } - // Here we define the simplest iterator -- the Null iterator. It contains nothing. // It is the empty set. Often times, queries that contain one of these match nothing, // so it's important to give it a special iterator. @@ -88,8 +79,6 @@ func (it *Null) DebugString(indent int) string { return strings.Repeat(" ", indent) + "(null)" } -func (it *Null) CanNext() bool { return true } - func (it *Null) Next() (graph.Value, bool) { return nil, false } diff --git a/graph/iterator/linksto_iterator.go b/graph/iterator/linksto_iterator.go index fa7cf29..e5f86cc 100644 --- a/graph/iterator/linksto_iterator.go +++ b/graph/iterator/linksto_iterator.go @@ -40,7 +40,6 @@ import ( // for each node) the subiterator, and the direction the iterator comes from. // `next_it` is the tempoarary iterator held per result in `primary_it`. type LinksTo struct { - Base uid uint64 tags graph.Tagger ts graph.TripleStore @@ -155,10 +154,10 @@ func (it *LinksTo) Optimize() (graph.Iterator, bool) { // Next()ing a LinksTo operates as described above. func (it *LinksTo) Next() (graph.Value, bool) { graph.NextLogIn(it) - val, ok := it.nextIt.Next() + val, ok := graph.Next(it.nextIt) if !ok { // Subiterator is empty, get another one - candidate, ok := it.primaryIt.Next() + candidate, ok := graph.Next(it.primaryIt) if !ok { // We're out of nodes in our subiterator, so we're done as well. return graph.NextLogOut(it, 0, false) diff --git a/graph/iterator/optional_iterator.go b/graph/iterator/optional_iterator.go index 7b9435f..bc6899c 100644 --- a/graph/iterator/optional_iterator.go +++ b/graph/iterator/optional_iterator.go @@ -30,8 +30,6 @@ import ( "fmt" "strings" - "github.com/barakmich/glog" - "github.com/google/cayley/graph" ) @@ -78,16 +76,6 @@ func (it *Optional) Clone() graph.Iterator { return out } -// FIXME(kortschak) When we create a Nexter interface the -// following two methods need to go away. - -// Nexting the iterator is unsupported -- error and return an empty set. -// (As above, a reasonable alternative would be to Next() an all iterator) -func (it *Optional) Next() (graph.Value, bool) { - glog.Errorln("Nexting an un-nextable iterator") - return nil, false -} - // DEPRECATED func (it *Optional) ResultTree() *graph.ResultTree { return graph.NewResultTree(it.Result()) diff --git a/graph/iterator/or_iterator.go b/graph/iterator/or_iterator.go index db323ed..13f28b8 100644 --- a/graph/iterator/or_iterator.go +++ b/graph/iterator/or_iterator.go @@ -29,7 +29,6 @@ import ( ) type Or struct { - Base uid uint64 tags graph.Tagger isShortCircuiting bool @@ -156,7 +155,7 @@ func (it *Or) Next() (graph.Value, bool) { firstTime = true } curIt := it.internalIterators[it.currentIterator] - curr, exists = curIt.Next() + curr, exists = graph.Next(curIt) if !exists { if it.isShortCircuiting && !firstTime { return graph.NextLogOut(it, nil, false) diff --git a/graph/iterator/or_iterator_test.go b/graph/iterator/or_iterator_test.go index 3b52ccd..78742eb 100644 --- a/graph/iterator/or_iterator_test.go +++ b/graph/iterator/or_iterator_test.go @@ -24,7 +24,7 @@ import ( func iterated(it graph.Iterator) []int { var res []int for { - val, ok := it.Next() + val, ok := graph.Next(it) if !ok { break } diff --git a/graph/iterator/query_shape.go b/graph/iterator/query_shape.go index acdbfa8..8af4a09 100644 --- a/graph/iterator/query_shape.go +++ b/graph/iterator/query_shape.go @@ -129,7 +129,7 @@ func (qs *queryShape) MakeNode(it graph.Iterator) *Node { case graph.Fixed: n.IsFixed = true for { - val, more := it.Next() + val, more := graph.Next(it) if !more { break } diff --git a/graph/iterator/value_comparison_iterator.go b/graph/iterator/value_comparison_iterator.go index ab5e698..2dfae3f 100644 --- a/graph/iterator/value_comparison_iterator.go +++ b/graph/iterator/value_comparison_iterator.go @@ -46,7 +46,6 @@ const ( ) type Comparison struct { - Base uid uint64 tags graph.Tagger subIt graph.Iterator @@ -132,7 +131,7 @@ func (it *Comparison) Next() (graph.Value, bool) { var val graph.Value var ok bool for { - val, ok = it.subIt.Next() + val, ok = graph.Next(it.subIt) if !ok { return nil, false } diff --git a/graph/leveldb/all_iterator.go b/graph/leveldb/all_iterator.go index 673fbb9..b337748 100644 --- a/graph/leveldb/all_iterator.go +++ b/graph/leveldb/all_iterator.go @@ -27,7 +27,6 @@ import ( ) type AllIterator struct { - iterator.Base uid uint64 tags graph.Tagger prefix []byte diff --git a/graph/leveldb/iterator.go b/graph/leveldb/iterator.go index 9f9b0bf..0b56854 100644 --- a/graph/leveldb/iterator.go +++ b/graph/leveldb/iterator.go @@ -27,7 +27,6 @@ import ( ) type Iterator struct { - iterator.Base uid uint64 tags graph.Tagger nextPrefix []byte diff --git a/graph/leveldb/leveldb_test.go b/graph/leveldb/leveldb_test.go index e2855fb..17c7ea7 100644 --- a/graph/leveldb/leveldb_test.go +++ b/graph/leveldb/leveldb_test.go @@ -45,7 +45,7 @@ func makeTripleSet() []*graph.Triple { func iteratedTriples(ts graph.TripleStore, it graph.Iterator) []*graph.Triple { var res ordered for { - val, ok := it.Next() + val, ok := graph.Next(it) if !ok { break } @@ -85,7 +85,7 @@ func (o ordered) Swap(i, j int) { o[i], o[j] = o[j], o[i] } func iteratedNames(ts graph.TripleStore, it graph.Iterator) []string { var res []string for { - val, ok := it.Next() + val, ok := graph.Next(it) if !ok { break } @@ -265,7 +265,7 @@ func TestIterator(t *testing.T) { it.Reset() it = ts.TriplesAllIterator() - edge, _ := it.Next() + edge, _ := graph.Next(it) triple := ts.Triple(edge) set := makeTripleSet() var ok bool @@ -433,10 +433,10 @@ func TestOptimize(t *testing.T) { t.Errorf("Optimized iteration does not match original") } - oldIt.Next() + graph.Next(oldIt) oldResults := make(map[string]graph.Value) oldIt.TagResults(oldResults) - newIt.Next() + graph.Next(newIt) newResults := make(map[string]graph.Value) newIt.TagResults(newResults) if !reflect.DeepEqual(newResults, oldResults) { diff --git a/graph/leveldb/triplestore_iterator_optimize.go b/graph/leveldb/triplestore_iterator_optimize.go index f449e0e..9aab0f2 100644 --- a/graph/leveldb/triplestore_iterator_optimize.go +++ b/graph/leveldb/triplestore_iterator_optimize.go @@ -37,7 +37,7 @@ func (ts *TripleStore) optimizeLinksTo(it *iterator.LinksTo) (graph.Iterator, bo if primary.Type() == graph.Fixed { size, _ := primary.Size() if size == 1 { - val, ok := primary.Next() + val, ok := graph.Next(primary) if !ok { panic("Sizes lie") } diff --git a/graph/memstore/iterator.go b/graph/memstore/iterator.go index 4be57db..7ec913a 100644 --- a/graph/memstore/iterator.go +++ b/graph/memstore/iterator.go @@ -26,7 +26,6 @@ import ( ) type Iterator struct { - iterator.Base uid uint64 tags graph.Tagger tree *llrb.LLRB diff --git a/graph/memstore/triplestore_iterator_optimize.go b/graph/memstore/triplestore_iterator_optimize.go index d7510e3..3dc2c2c 100644 --- a/graph/memstore/triplestore_iterator_optimize.go +++ b/graph/memstore/triplestore_iterator_optimize.go @@ -37,7 +37,7 @@ func (ts *TripleStore) optimizeLinksTo(it *iterator.LinksTo) (graph.Iterator, bo if primary.Type() == graph.Fixed { size, _ := primary.Size() if size == 1 { - val, ok := primary.Next() + val, ok := graph.Next(primary) if !ok { panic("Sizes lie") } diff --git a/graph/memstore/triplestore_test.go b/graph/memstore/triplestore_test.go index aa8f93b..80d9fdb 100644 --- a/graph/memstore/triplestore_test.go +++ b/graph/memstore/triplestore_test.go @@ -189,7 +189,7 @@ func TestRemoveTriple(t *testing.T) { hasa := iterator.NewHasA(ts, innerAnd, graph.Object) newIt, _ := hasa.Optimize() - _, ok := newIt.Next() + _, ok := graph.Next(newIt) if ok { t.Error("E should not have any followers.") } diff --git a/graph/mongo/iterator.go b/graph/mongo/iterator.go index 3389e9f..f65b324 100644 --- a/graph/mongo/iterator.go +++ b/graph/mongo/iterator.go @@ -27,7 +27,6 @@ import ( ) type Iterator struct { - iterator.Base uid uint64 tags graph.Tagger ts *TripleStore diff --git a/graph/mongo/triplestore_iterator_optimize.go b/graph/mongo/triplestore_iterator_optimize.go index 76c50d8..d2d1a05 100644 --- a/graph/mongo/triplestore_iterator_optimize.go +++ b/graph/mongo/triplestore_iterator_optimize.go @@ -37,7 +37,7 @@ func (ts *TripleStore) optimizeLinksTo(it *iterator.LinksTo) (graph.Iterator, bo if primary.Type() == graph.Fixed { size, _ := primary.Size() if size == 1 { - val, ok := primary.Next() + val, ok := graph.Next(primary) if !ok { panic("Sizes lie") } diff --git a/graph/result_tree_evaluator.go b/graph/result_tree_evaluator.go index e1588d2..e2feb33 100644 --- a/graph/result_tree_evaluator.go +++ b/graph/result_tree_evaluator.go @@ -40,7 +40,7 @@ func (t *ResultTree) AddSubtree(sub *ResultTree) { t.subtrees = append(t.subtrees, sub) } -func StringResultTreeEvaluator(it Iterator) string { +func StringResultTreeEvaluator(it Nexter) string { ok := true out := "" for { @@ -59,6 +59,6 @@ func StringResultTreeEvaluator(it Iterator) string { return out } -func PrintResultTreeEvaluator(it Iterator) { +func PrintResultTreeEvaluator(it Nexter) { fmt.Print(StringResultTreeEvaluator(it)) } diff --git a/graph/sexp/parser_test.go b/graph/sexp/parser_test.go index bd9c13b..bd2b319 100644 --- a/graph/sexp/parser_test.go +++ b/graph/sexp/parser_test.go @@ -65,7 +65,7 @@ func TestMemstoreBackedSexp(t *testing.T) { if it.Type() != test.typ { t.Errorf("Incorrect type for %s, got:%q expect %q", test.message, it.Type(), test.expect) } - got, ok := it.Next() + got, ok := graph.Next(it) if !ok { t.Errorf("Failed to %s", test.message) } @@ -86,7 +86,7 @@ func TestTreeConstraintParse(t *testing.T) { if it.Type() != graph.And { t.Error("Odd iterator tree. Got: %s", it.DebugString(0)) } - out, ok := it.Next() + out, ok := graph.Next(it) if !ok { t.Error("Got no results") } @@ -103,7 +103,7 @@ func TestTreeConstraintTagParse(t *testing.T) { "(:like\n" + "($a (:is :good))))" it := BuildIteratorTreeForQuery(ts, query) - _, ok := it.Next() + _, ok := graph.Next(it) if !ok { t.Error("Got no results") } @@ -133,14 +133,14 @@ func TestMultipleConstraintParse(t *testing.T) { if it.Type() != graph.And { t.Error("Odd iterator tree. Got: %s", it.DebugString(0)) } - out, ok := it.Next() + out, ok := graph.Next(it) if !ok { t.Error("Got no results") } if out != ts.ValueOf("i") { t.Errorf("Got %d, expected %d", out, ts.ValueOf("i")) } - _, ok = it.Next() + _, ok = graph.Next(it) if ok { t.Error("Too many results") } diff --git a/graph/sexp/session.go b/graph/sexp/session.go index 8d243f0..0fb4810 100644 --- a/graph/sexp/session.go +++ b/graph/sexp/session.go @@ -77,7 +77,7 @@ func (s *Session) ExecInput(input string, out chan interface{}, limit int) { } nResults := 0 for { - _, ok := it.Next() + _, ok := graph.Next(it) if !ok { break } diff --git a/query/gremlin/finals.go b/query/gremlin/finals.go index 414d780..022a394 100644 --- a/query/gremlin/finals.go +++ b/query/gremlin/finals.go @@ -151,7 +151,7 @@ func runIteratorToArray(it graph.Iterator, ses *Session, limit int) []map[string if ses.doHalt { return nil } - _, ok := it.Next() + _, ok := graph.Next(it) if !ok { break } @@ -187,7 +187,7 @@ func runIteratorToArrayNoTags(it graph.Iterator, ses *Session, limit int) []stri if ses.doHalt { return nil } - val, ok := it.Next() + val, ok := graph.Next(it) if !ok { break } @@ -208,7 +208,7 @@ func runIteratorWithCallback(it graph.Iterator, ses *Session, callback otto.Valu if ses.doHalt { return } - _, ok := it.Next() + _, ok := graph.Next(it) if !ok { break } @@ -249,7 +249,7 @@ func runIteratorOnSession(it graph.Iterator, ses *Session) { if ses.doHalt { return } - _, ok := it.Next() + _, ok := graph.Next(it) if !ok { break } diff --git a/query/mql/session.go b/query/mql/session.go index e5944d4..882c856 100644 --- a/query/mql/session.go +++ b/query/mql/session.go @@ -88,7 +88,7 @@ func (s *Session) ExecInput(input string, c chan interface{}, limit int) { glog.V(2).Infoln(it.DebugString(0)) } for { - _, ok := it.Next() + _, ok := graph.Next(it) if !ok { break }