diff --git a/posting/list.go b/posting/list.go new file mode 100644 index 0000000000000000000000000000000000000000..47a55a350389a17e137b7235ae76b3de1bc53756 --- /dev/null +++ b/posting/list.go @@ -0,0 +1,108 @@ +/* + * Copyright 2015 Manish R Jain <manishrjain@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package posting + +import ( + "github.com/google/flatbuffers/go" + "github.com/manishrjain/dgraph/posting/types" + "github.com/manishrjain/dgraph/x" +) + +type List struct { + TList *types.PostingList +} + +func addTripleToPosting(b *flatbuffers.Builder, + t x.Triple) flatbuffers.UOffsetT { + + // Do this before posting start. + so := b.CreateString(t.Source) + types.PostingStart(b) + types.PostingAddUid(b, t.ValueId) + + // so := b.CreateString(t.Source) + types.PostingAddSource(b, so) + + types.PostingAddTs(b, t.Timestamp.UnixNano()) + return types.PostingEnd(b) +} + +func addPosting(b *flatbuffers.Builder, p types.Posting) flatbuffers.UOffsetT { + // Do this before posting start. + so := b.CreateByteString(p.Source()) + + types.PostingStart(b) + types.PostingAddUid(b, p.Uid()) + + types.PostingAddSource(b, so) + + types.PostingAddTs(b, p.Ts()) + return types.PostingEnd(b) +} + +func (l *List) Init() { + b := flatbuffers.NewBuilder(0) + types.PostingListStart(b) + of := types.PostingListEnd(b) + b.Finish(of) + + l.TList = types.GetRootAsPostingList(b.Bytes, b.Head()) +} + +func (l *List) AddTriple(t x.Triple) { + b := flatbuffers.NewBuilder(0) + + num := l.TList.PostingsLength() + var offsets []flatbuffers.UOffsetT + + if num == 0 { + offsets = append(offsets, addTripleToPosting(b, t)) + + } else { + added := false + for i := 0; i < num; i++ { + var p types.Posting + l.TList.Postings(&p, i) + + // Put the triple just before the first posting which has a greater + // uid than itself. + if !added && p.Uid() > t.ValueId { + offsets = append(offsets, addTripleToPosting(b, t)) + added = true + } + offsets = append(offsets, addPosting(b, p)) + } + if !added { + // t.ValueId is the largest. So, add at end. + offsets = append(offsets, addTripleToPosting(b, t)) + added = true // useless, but consistent w/ behavior. + } + } + + types.PostingListStartPostingsVector(b, len(offsets)) + for i := len(offsets) - 1; i >= 0; i-- { + b.PrependUOffsetT(offsets[i]) + } + vend := b.EndVector(len(offsets)) + + types.PostingListStart(b) + types.PostingListAddPostings(b, vend) + end := types.PostingListEnd(b) + b.Finish(end) + + l.TList = types.GetRootAsPostingList(b.Bytes, b.Head()) +} diff --git a/posting/list_test.go b/posting/list_test.go new file mode 100644 index 0000000000000000000000000000000000000000..408c8c1d907c25cdc258acd4349c588c3d18644c --- /dev/null +++ b/posting/list_test.go @@ -0,0 +1,92 @@ +/* + * Copyright 2015 Manish R Jain <manishrjain@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package posting + +import ( + "testing" + "time" + + "github.com/manishrjain/dgraph/posting/types" + "github.com/manishrjain/dgraph/x" +) + +var uids = [...]uint64{ + 9, 49, 81, +} + +func TestAddTriple(t *testing.T) { + var l List + l.Init() + + triple := x.Triple{ + ValueId: 9, + Source: "testing", + Timestamp: time.Now(), + } + l.AddTriple(triple) + + if l.TList.PostingsLength() != 1 { + t.Error("Unable to find added elements in posting list") + } + var p types.Posting + if ok := l.TList.Postings(&p, 0); !ok { + t.Error("Unable to retrieve posting at 1st iter") + t.Fail() + } + if p.Uid() != 9 { + t.Errorf("Expected 9. Got: %v", p.Uid) + } + if string(p.Source()) != "testing" { + t.Errorf("Expected testing. Got: %v", string(p.Source())) + } + + // Add another triple now. + triple.ValueId = 81 + l.AddTriple(triple) + if l.TList.PostingsLength() != 2 { + t.Errorf("Length: %d", l.TList.PostingsLength()) + t.Fail() + } + + var uid uint64 + uid = 1 + for i := 0; i < l.TList.PostingsLength(); i++ { + if ok := l.TList.Postings(&p, i); !ok { + t.Error("Unable to retrieve posting at 2nd iter") + } + uid *= 9 + if p.Uid() != uid { + t.Errorf("Expected: %v. Got: %v", uid, p.Uid()) + } + } + + // Add another triple, in between the two above. + triple.ValueId = 49 + l.AddTriple(triple) + if l.TList.PostingsLength() != 3 { + t.Errorf("Length: %d", l.TList.PostingsLength()) + t.Fail() + } + for i := 0; i < len(uids); i++ { + if ok := l.TList.Postings(&p, i); !ok { + t.Error("Unable to retrieve posting at 2nd iter") + } + if p.Uid() != uids[i] { + t.Errorf("Expected: %v. Got: %v", uids[i], p.Uid()) + } + } +} diff --git a/posting/types.fbs b/posting/types.fbs new file mode 100644 index 0000000000000000000000000000000000000000..ce92157e58bf849e6b6567590a5db0886dedc3d8 --- /dev/null +++ b/posting/types.fbs @@ -0,0 +1,13 @@ +namespace types; + +table Posting { + uid:ulong; + source:string; + ts:long; +} + +table PostingList { + postings:[Posting]; +} + +root_type PostingList; diff --git a/posting/types/Posting.go b/posting/types/Posting.go new file mode 100644 index 0000000000000000000000000000000000000000..3a0644b5b9c071776319f76dcb29e8a65b11eeb8 --- /dev/null +++ b/posting/types/Posting.go @@ -0,0 +1,45 @@ +// automatically generated, do not modify + +package types + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) +type Posting struct { + _tab flatbuffers.Table +} + +func (rcv *Posting) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *Posting) Uid() uint64 { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.GetUint64(o + rcv._tab.Pos) + } + return 0 +} + +func (rcv *Posting) Source() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func (rcv *Posting) Ts() int64 { + o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) + if o != 0 { + return rcv._tab.GetInt64(o + rcv._tab.Pos) + } + return 0 +} + +func PostingStart(builder *flatbuffers.Builder) { builder.StartObject(3) } +func PostingAddUid(builder *flatbuffers.Builder, uid uint64) { builder.PrependUint64Slot(0, uid, 0) } +func PostingAddSource(builder *flatbuffers.Builder, source flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(source), 0) } +func PostingAddTs(builder *flatbuffers.Builder, ts int64) { builder.PrependInt64Slot(2, ts, 0) } +func PostingEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() } diff --git a/types/PostingList.go b/posting/types/PostingList.go similarity index 57% rename from types/PostingList.go rename to posting/types/PostingList.go index ffe2063b44f8d6a9d3d6c7ec5f6c1e7ce6ee6e3a..c1b54045bd73ecaa82d4295b66ac96f558dbee79 100644 --- a/types/PostingList.go +++ b/posting/types/PostingList.go @@ -21,16 +21,22 @@ func (rcv *PostingList) Init(buf []byte, i flatbuffers.UOffsetT) { rcv._tab.Pos = i } -func (rcv *PostingList) Ids(j int) uint64 { +func (rcv *PostingList) Postings(obj *Posting, j int) bool { o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) if o != 0 { - a := rcv._tab.Vector(o) - return rcv._tab.GetUint64(a + flatbuffers.UOffsetT(j * 8)) + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + if obj == nil { + obj = new(Posting) } - return 0 + obj.Init(rcv._tab.Bytes, x) + return true + } + return false } -func (rcv *PostingList) IdsLength() int { +func (rcv *PostingList) PostingsLength() int { o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) if o != 0 { return rcv._tab.VectorLen(o) @@ -39,7 +45,7 @@ func (rcv *PostingList) IdsLength() int { } func PostingListStart(builder *flatbuffers.Builder) { builder.StartObject(1) } -func PostingListAddIds(builder *flatbuffers.Builder, ids flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(ids), 0) } -func PostingListStartIdsVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { return builder.StartVector(8, numElems, 8) +func PostingListAddPostings(builder *flatbuffers.Builder, postings flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(postings), 0) } +func PostingListStartPostingsVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { return builder.StartVector(4, numElems, 4) } func PostingListEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() } diff --git a/types.fbs b/types.fbs deleted file mode 100644 index 53cdaa1bf9f4b4eb5ec6baa5dedd10bf43df4af2..0000000000000000000000000000000000000000 --- a/types.fbs +++ /dev/null @@ -1,7 +0,0 @@ -namespace types; - -table PostingList { - ids:[ulong]; -} - -root_type PostingList; diff --git a/x/x.go b/x/x.go index c757edf4ac9985f2cecda0c21f5197da52417bff..66da0a6214674345f837e6a1ba377ad7459d5e48 100644 --- a/x/x.go +++ b/x/x.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "net/http" + "time" "github.com/Sirupsen/logrus" ) @@ -27,6 +28,16 @@ type Status struct { Message string `json:"message"` } +type Triple struct { + Entity uint64 + EntityEid string + Attribute string + Value interface{} + ValueId uint64 + Source string + Timestamp time.Time +} + func Log(p string) *logrus.Entry { l := logrus.WithFields(logrus.Fields{ "package": p,