Use cznic/b for index store

$ benchcmp gollrb.bench b-gen.bench
benchmark                                   old ns/op       new ns/op	delta
BenchmarkNamePredicate                      1731218         1693373		-2.19%
BenchmarkLargeSetsNoIntersection            81290360        70205277	-13.64%
BenchmarkVeryLargeSetsSmallIntersection     768135620       442906243	-42.34%
BenchmarkHelplessContainsChecker            39477086024     35260603748	-10.68%
BenchmarkNetAndSpeed                        22510637        21587975	-4.10%
BenchmarkKeanuAndNet                        18018886        17795328	-1.24%
BenchmarkKeanuAndSpeed                      20336586        20560228	+1.10%
BenchmarkKeanuOther                         85495040        80718152	-5.59%
BenchmarkKeanuBullockOther                  95457792        83868434	-12.14%

Code gen from $GOPATH/src/github.com/cznic/b:

  make generic \
| sed -e 's/KEY/int64/g' -e 's/VALUE/struct{}/g' \
> $GOPATH/src/github.com/google/cayley/graph/memstore/b/keys.go

key_test.go manually edited.
This commit is contained in:
kortschak 2014-08-10 12:22:07 +09:30
parent aad21b0585
commit 2540ea8f87
4 changed files with 1492 additions and 114 deletions

View file

@ -18,11 +18,11 @@ import (
"fmt"
"github.com/barakmich/glog"
"github.com/google/cayley/graph"
"github.com/google/cayley/graph/iterator"
"github.com/google/cayley/graph/memstore/b"
"github.com/google/cayley/quad"
"github.com/petar/GoLLRB/llrb"
)
func init() {
@ -32,47 +32,36 @@ func init() {
}
type TripleDirectionIndex struct {
subject map[int64]*llrb.LLRB
predicate map[int64]*llrb.LLRB
object map[int64]*llrb.LLRB
label map[int64]*llrb.LLRB
index [4]map[int64]*b.Tree
}
func NewTripleDirectionIndex() *TripleDirectionIndex {
var tdi TripleDirectionIndex
tdi.subject = make(map[int64]*llrb.LLRB)
tdi.predicate = make(map[int64]*llrb.LLRB)
tdi.object = make(map[int64]*llrb.LLRB)
tdi.label = make(map[int64]*llrb.LLRB)
return &tdi
func NewTripleDirectionIndex() TripleDirectionIndex {
return TripleDirectionIndex{[...]map[int64]*b.Tree{
quad.Subject - 1: make(map[int64]*b.Tree),
quad.Predicate - 1: make(map[int64]*b.Tree),
quad.Object - 1: make(map[int64]*b.Tree),
quad.Label - 1: make(map[int64]*b.Tree),
}}
}
func (tdi *TripleDirectionIndex) GetForDir(d quad.Direction) map[int64]*llrb.LLRB {
switch d {
case quad.Subject:
return tdi.subject
case quad.Object:
return tdi.object
case quad.Predicate:
return tdi.predicate
case quad.Label:
return tdi.label
func (tdi TripleDirectionIndex) Tree(d quad.Direction, id int64) *b.Tree {
if d < quad.Subject || d > quad.Label {
panic("illegal direction")
}
panic("illegal direction")
}
func (tdi *TripleDirectionIndex) GetOrCreate(d quad.Direction, id int64) *llrb.LLRB {
directionIndex := tdi.GetForDir(d)
if _, ok := directionIndex[id]; !ok {
directionIndex[id] = llrb.New()
tree, ok := tdi.index[d-1][id]
if !ok {
tree = b.TreeNew(cmp)
tdi.index[d-1][id] = tree
}
return directionIndex[id]
return tree
}
func (tdi *TripleDirectionIndex) Get(d quad.Direction, id int64) (*llrb.LLRB, bool) {
directionIndex := tdi.GetForDir(d)
tree, exists := directionIndex[id]
return tree, exists
func (tdi TripleDirectionIndex) Get(d quad.Direction, id int64) (*b.Tree, bool) {
if d < quad.Subject || d > quad.Label {
panic("illegal direction")
}
tree, ok := tdi.index[d-1][id]
return tree, ok
}
type TripleStore struct {
@ -83,22 +72,22 @@ type TripleStore struct {
triples []quad.Quad
size int64
index TripleDirectionIndex
// vip_index map[string]map[int64]map[string]map[int64]*llrb.Tree
// vip_index map[string]map[int64]map[string]map[int64]*b.Tree
}
func newTripleStore() *TripleStore {
var ts TripleStore
ts.idMap = make(map[string]int64)
ts.revIdMap = make(map[int64]string)
ts.triples = make([]quad.Quad, 1, 200)
return &TripleStore{
idMap: make(map[string]int64),
revIdMap: make(map[int64]string),
// Sentinel null triple so triple indices start at 1
ts.triples[0] = quad.Quad{}
ts.size = 1
ts.index = *NewTripleDirectionIndex()
ts.idCounter = 1
ts.tripleIdCounter = 1
return &ts
// Sentinel null triple so triple indices start at 1
triples: make([]quad.Quad, 1, 200),
size: 1,
index: NewTripleDirectionIndex(),
idCounter: 1,
tripleIdCounter: 1,
}
}
func (ts *TripleStore) AddTripleSet(triples []quad.Quad) {
@ -107,47 +96,47 @@ func (ts *TripleStore) AddTripleSet(triples []quad.Quad) {
}
}
func (ts *TripleStore) tripleExists(t quad.Quad) (bool, int64) {
smallest := -1
var smallest_tree *llrb.LLRB
const maxInt = int(^uint(0) >> 1)
func (ts *TripleStore) indexOf(t quad.Quad) (int64, bool) {
min := maxInt
var tree *b.Tree
for d := quad.Subject; d <= quad.Label; d++ {
sid := t.Get(d)
if d == quad.Label && sid == "" {
continue
}
id, ok := ts.idMap[sid]
// If we've never heard about a node, it most not exist
// If we've never heard about a node, it must not exist
if !ok {
return false, 0
return 0, false
}
index, exists := ts.index.Get(d, id)
if !exists {
index, ok := ts.index.Get(d, id)
if !ok {
// If it's never been indexed in this direction, it can't exist.
return false, 0
return 0, false
}
if smallest == -1 || index.Len() < smallest {
smallest = index.Len()
smallest_tree = index
if l := index.Len(); l < min {
min, tree = l, index
}
}
it := NewLlrbIterator(smallest_tree, "")
it := NewIterator(tree, "")
for it.Next() {
val := it.Result()
if t == ts.triples[val.(int64)] {
return true, val.(int64)
return val.(int64), true
}
}
return false, 0
return 0, false
}
func (ts *TripleStore) AddTriple(t quad.Quad) {
if exists, _ := ts.tripleExists(t); exists {
if _, exists := ts.indexOf(t); exists {
return
}
var tripleID int64
ts.triples = append(ts.triples, t)
tripleID = ts.tripleIdCounter
tid := ts.tripleIdCounter
ts.size++
ts.tripleIdCounter++
@ -168,22 +157,20 @@ func (ts *TripleStore) AddTriple(t quad.Quad) {
continue
}
id := ts.idMap[t.Get(d)]
tree := ts.index.GetOrCreate(d, id)
tree.ReplaceOrInsert(Int64(tripleID))
tree := ts.index.Tree(d, id)
tree.Set(tid, struct{}{})
}
// TODO(barakmich): Add VIP indexing
}
func (ts *TripleStore) RemoveTriple(t quad.Quad) {
var tripleID int64
var exists bool
tripleID = 0
if exists, tripleID = ts.tripleExists(t); !exists {
tid, ok := ts.indexOf(t)
if !ok {
return
}
ts.triples[tripleID] = quad.Quad{}
ts.triples[tid] = quad.Quad{}
ts.size--
for d := quad.Subject; d <= quad.Label; d++ {
@ -191,8 +178,8 @@ func (ts *TripleStore) RemoveTriple(t quad.Quad) {
continue
}
id := ts.idMap[t.Get(d)]
tree := ts.index.GetOrCreate(d, id)
tree.Delete(Int64(tripleID))
tree := ts.index.Tree(d, id)
tree.Delete(tid)
}
for d := quad.Subject; d <= quad.Label; d++ {
@ -208,7 +195,7 @@ func (ts *TripleStore) RemoveTriple(t quad.Quad) {
if d == quad.Label && t.Get(d) == "" {
continue
}
nodeTree := ts.index.GetOrCreate(d, id)
nodeTree := ts.index.Tree(d, id)
if nodeTree.Len() != 0 {
stillExists = true
break
@ -229,7 +216,7 @@ func (ts *TripleStore) TripleIterator(d quad.Direction, value graph.Value) graph
index, ok := ts.index.Get(d, value.(int64))
data := fmt.Sprintf("dir:%s val:%d", d, value.(int64))
if ok {
return NewLlrbIterator(index, data)
return NewIterator(index, data)
}
return &iterator.Null{}
}
@ -271,4 +258,5 @@ func (ts *TripleStore) TripleDirection(val graph.Value, d quad.Direction) graph.
func (ts *TripleStore) NodesAllIterator() graph.Iterator {
return NewMemstoreAllIterator(ts)
}
func (ts *TripleStore) Close() {}