Skip to content

Commit e5da3c5

Browse files
author
Luis Fung
committed
Modifications to support byte array indexing and transactions for KV stores
1 parent b6b074a commit e5da3c5

File tree

9 files changed

+339
-20
lines changed

9 files changed

+339
-20
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ require (
1212
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 // indirect
1313
github.com/cznic/mathutil v0.0.0-20170313102836-1447ad269d64
1414
github.com/d4l3k/messagediff v1.2.1 // indirect
15+
github.com/deckarep/golang-set v1.7.1
1516
github.com/dennwc/graphql v0.0.0-20180603144102-12cfed44bc5d
1617
github.com/dgraph-io/badger v1.5.4
1718
github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f // indirect
@@ -20,6 +21,7 @@ require (
2021
github.com/docker/go-connections v0.4.0 // indirect
2122
github.com/docker/go-units v0.3.3 // indirect
2223
github.com/dop251/goja v0.0.0-20190105122144-6d5bf35058fa
24+
github.com/emirpasic/gods v1.12.0
2325
github.com/flimzy/diff v0.1.4 // indirect
2426
github.com/flimzy/kivik v1.8.1 // indirect
2527
github.com/flimzy/testy v0.0.13 // indirect

graph/kv/indexing.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ import (
2525

2626
"github.com/cayleygraph/cayley/clog"
2727
"github.com/cayleygraph/cayley/graph"
28-
"github.com/cayleygraph/cayley/graph/log"
28+
graphlog "github.com/cayleygraph/cayley/graph/log"
2929
"github.com/cayleygraph/cayley/graph/proto"
3030
"github.com/cayleygraph/cayley/quad"
3131
"github.com/cayleygraph/cayley/quad/pquads"
32-
"github.com/tylertreat/BoomFilters"
32+
boom "github.com/tylertreat/BoomFilters"
3333
)
3434

3535
var (
@@ -829,6 +829,9 @@ func (qs *QuadStore) resolveQuadValues(ctx context.Context, tx BucketTx, vals []
829829
} else if v == nil {
830830
continue
831831
}
832+
if bytes, ok := v.(quad.Bytes); ok {
833+
v = bytes.TypedString()
834+
}
832835
inds = append(inds, i)
833836
keys = append(keys, bucketKeyForVal(v))
834837
}

graph/transaction.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,17 @@
1414

1515
package graph
1616

17-
import "github.com/cayleygraph/cayley/quad"
17+
import (
18+
"github.com/cayleygraph/cayley/internal/mapset"
19+
"github.com/cayleygraph/cayley/quad"
20+
)
1821

1922
// Transaction stores a bunch of Deltas to apply together in an atomic step on the database.
2023
type Transaction struct {
2124
// Deltas stores the deltas in the right order
2225
Deltas []Delta
2326
// deltas stores the deltas in a map to avoid duplications
24-
deltas map[Delta]struct{}
27+
deltas mapset.Map
2528
}
2629

2730
// NewTransaction initialize a new transaction.
@@ -31,7 +34,7 @@ func NewTransaction() *Transaction {
3134

3235
// NewTransactionN initialize a new transaction with a predefined capacity.
3336
func NewTransactionN(n int) *Transaction {
34-
return &Transaction{Deltas: make([]Delta, 0, n), deltas: make(map[Delta]struct{}, n)}
37+
return &Transaction{Deltas: make([]Delta, 0, n), deltas: mapset.NewMapWithComparator(mapset.GenericComparator)}
3538
}
3639

3740
// AddQuad adds a new quad to the transaction if it is not already present in it.
@@ -40,8 +43,8 @@ func NewTransactionN(n int) *Transaction {
4043
func (t *Transaction) AddQuad(q quad.Quad) {
4144
ad, rd := createDeltas(q)
4245

43-
if _, adExists := t.deltas[ad]; !adExists {
44-
if _, rdExists := t.deltas[rd]; rdExists {
46+
if !t.deltas.Contains(ad) {
47+
if t.deltas.Contains(rd) {
4548
t.deleteDelta(rd)
4649
} else {
4750
t.addDelta(ad)
@@ -55,10 +58,10 @@ func (t *Transaction) AddQuad(q quad.Quad) {
5558
func (t *Transaction) RemoveQuad(q quad.Quad) {
5659
ad, rd := createDeltas(q)
5760

58-
if _, adExists := t.deltas[ad]; adExists {
61+
if t.deltas.Contains(ad) {
5962
t.deleteDelta(ad)
6063
} else {
61-
if _, rdExists := t.deltas[rd]; !rdExists {
64+
if !t.deltas.Contains(rd) {
6265
t.addDelta(rd)
6366
}
6467
}
@@ -78,11 +81,11 @@ func createDeltas(q quad.Quad) (ad, rd Delta) {
7881

7982
func (t *Transaction) addDelta(d Delta) {
8083
t.Deltas = append(t.Deltas, d)
81-
t.deltas[d] = struct{}{}
84+
t.deltas.Put(d, struct{}{})
8285
}
8386

8487
func (t *Transaction) deleteDelta(d Delta) {
85-
delete(t.deltas, d)
88+
t.deltas.Remove(d)
8689

8790
for i, id := range t.Deltas {
8891
if id == d {

internal/mapset/comparator.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package mapset
2+
3+
import (
4+
"time"
5+
6+
"github.com/emirpasic/gods/utils"
7+
)
8+
9+
var (
10+
ByteComparator = utils.ByteComparator
11+
StringComparator = utils.StringComparator
12+
RuneComparator = utils.RuneComparator
13+
TimeComparator = utils.TimeComparator
14+
15+
IntComparator = utils.IntComparator
16+
Int8Comparator = utils.Int8Comparator
17+
Int16Comparator = utils.Int16Comparator
18+
Int32Comparator = utils.Int32Comparator
19+
Int64Comparator = utils.Int64Comparator
20+
21+
UIntComparator = utils.UIntComparator
22+
UInt8Comparator = utils.UInt8Comparator
23+
UInt16Comparator = utils.UInt16Comparator
24+
UInt32Comparator = utils.UInt32Comparator
25+
UInt64Comparator = utils.UInt64Comparator
26+
27+
Float32Comparator = utils.Float32Comparator
28+
Float64Comparator = utils.Float64Comparator
29+
30+
GenericComparator = genericComparator
31+
)
32+
33+
func genericComparator(a, b interface{}) int {
34+
switch a.(type) {
35+
case string:
36+
return StringComparator(a, b)
37+
case rune:
38+
return RuneComparator(a, b)
39+
case []byte:
40+
return ByteComparator(a, b)
41+
case int:
42+
return IntComparator(a, b)
43+
case uint:
44+
return UIntComparator(a, b)
45+
case float32:
46+
return Float32Comparator(a, b)
47+
case float64:
48+
return Float64Comparator(a, b)
49+
case time.Time:
50+
return TimeComparator(a, b)
51+
}
52+
if a == b {
53+
return 0
54+
}
55+
return -2
56+
// panic(fmt.Sprintf("unknonw comparative type: %#v, %#v", a, b))
57+
}

internal/mapset/map.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package mapset
2+
3+
import (
4+
"github.com/emirpasic/gods/trees/btree"
5+
"github.com/emirpasic/gods/utils"
6+
)
7+
8+
type Map interface {
9+
Put(k, v interface{}) bool
10+
11+
Get(k interface{}) (interface{}, bool)
12+
13+
Remove(k interface{})
14+
15+
Contains(k ...interface{}) bool
16+
17+
Each(func(k, v interface{}) int)
18+
19+
Keys() []interface{}
20+
21+
Values() []interface{}
22+
23+
Size() int
24+
25+
Clear()
26+
27+
String() string
28+
}
29+
30+
func NewBytesMap() Map {
31+
return NewMapWithComparator(utils.ByteComparator)
32+
}
33+
34+
func NewMapWithComparator(cmp func(a, b interface{}) int) Map {
35+
m := &btreeMap{
36+
inner: btree.NewWith(10, cmp),
37+
}
38+
return m
39+
}
40+
41+
type btreeMap struct {
42+
inner *btree.Tree
43+
cmp func(a, b interface{}) int
44+
}
45+
46+
func (m btreeMap) Each(f func(k, v interface{}) int) {
47+
it := m.inner.Iterator()
48+
for it.Next() {
49+
f(it.Key(), it.Value())
50+
}
51+
}
52+
53+
func (m *btreeMap) Put(k, v interface{}) bool {
54+
m.inner.Put(k, v)
55+
return true
56+
}
57+
58+
func (m btreeMap) Get(k interface{}) (interface{}, bool) {
59+
return m.inner.Get(k)
60+
}
61+
62+
func (m *btreeMap) Remove(k interface{}) {
63+
m.inner.Remove(k)
64+
}
65+
66+
func (b *btreeMap) Contains(k ...interface{}) bool {
67+
for _, n := range k {
68+
if _, exists := b.inner.Get(n); exists {
69+
return true
70+
}
71+
}
72+
return false
73+
}
74+
75+
func (m *btreeMap) Clear() {
76+
m.inner.Clear()
77+
}
78+
79+
func (m btreeMap) Size() int {
80+
return m.inner.Size()
81+
}
82+
83+
func (m btreeMap) Keys() []interface{} {
84+
return m.inner.Keys()
85+
}
86+
87+
func (m btreeMap) Values() []interface{} {
88+
return m.inner.Values()
89+
}
90+
91+
func (m btreeMap) String() string {
92+
return m.inner.String()
93+
}

internal/mapset/map_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package mapset
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestMap(t *testing.T) {
8+
tree := NewMapWithComparator(func(a, b interface{}) int {
9+
aa := a.(int)
10+
bb := b.(int)
11+
switch {
12+
case aa > bb:
13+
return 1
14+
case aa < bb:
15+
return -1
16+
default:
17+
return 0
18+
}
19+
})
20+
tree.Put(1, "a")
21+
tree.Put(2, "b")
22+
tree.Put(3, "c")
23+
tree.Put(4, "d")
24+
tree.Put(5, "e")
25+
tree.Put(6, "f")
26+
tree.Put(7, "g")
27+
28+
tests := [][]interface{}{
29+
{0, nil, false},
30+
{1, "a", true},
31+
{2, "b", true},
32+
{3, "c", true},
33+
{4, "d", true},
34+
{5, "e", true},
35+
{6, "f", true},
36+
{7, "g", true},
37+
{8, nil, false},
38+
}
39+
40+
// Test values
41+
for _, test := range tests {
42+
if value, found := tree.Get(test[0]); value != test[1] || found != test[2] {
43+
t.Errorf("Got %v,%v expected %v,%v", value, found, test[1], test[2])
44+
}
45+
}
46+
47+
// Test updates
48+
sz := tree.Size()
49+
tree.Put(7, "g")
50+
tree.Put(7, "this doesn't matter either...")
51+
if sz != tree.Size() {
52+
t.Errorf("Got %v expected %v", tree.Size(), sz)
53+
}
54+
55+
// Test contains
56+
if !tree.Contains(7) {
57+
t.Errorf("Got false, expected true")
58+
}
59+
60+
if tree.Contains(10) {
61+
t.Errorf("Got true, expected false")
62+
}
63+
}

0 commit comments

Comments
 (0)