Commit eccf827f authored by Kirill Smelkov's avatar Kirill Smelkov

go/zodb/btree: Represent a tree node - either BTree or Bucket - by Node

This allows to use proper btree.Node type - not just zodb.IPersistent -
in places which expects a tree node.
parent adb2ada3
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
// kind: they are either all leafs or all intermediate nodes(+). // kind: they are either all leafs or all intermediate nodes(+).
// //
// BTree and Bucket represent an intermediate and a leaf tree node correspondingly. // BTree and Bucket represent an intermediate and a leaf tree node correspondingly.
// Node represents any of them.
// //
// node.Get(key) performs point-query. // node.Get(key) performs point-query.
// //
......
...@@ -29,6 +29,15 @@ import ( ...@@ -29,6 +29,15 @@ import (
"lab.nexedi.com/kirr/neo/go/zodb/internal/pickletools" "lab.nexedi.com/kirr/neo/go/zodb/internal/pickletools"
) )
// Node represents a tree node - either BTree or Bucket.
type Node interface {
zodb.IPersistent
node()
}
func (t *BTree) node() {}
func (b *Bucket) node() {}
// BTree is a non-leaf node of a B tree. // BTree is a non-leaf node of a B tree.
// //
// It contains []Entry in key order. // It contains []Entry in key order.
...@@ -61,7 +70,7 @@ type BTree struct { ...@@ -61,7 +70,7 @@ type BTree struct {
// Key limits child's keys - see BTree.Entryv for details. // Key limits child's keys - see BTree.Entryv for details.
type Entry struct { type Entry struct {
key KEY key KEY
child zodb.IPersistent // BTree or Bucket child Node // BTree or Bucket
} }
// Bucket is a leaf node of a B⁺ tree. // Bucket is a leaf node of a B⁺ tree.
...@@ -99,7 +108,7 @@ type BucketEntry struct { ...@@ -99,7 +108,7 @@ type BucketEntry struct {
func (e *Entry) Key() KEY { return e.key } func (e *Entry) Key() KEY { return e.key }
// Child returns BTree entry child. // Child returns BTree entry child.
func (e *Entry) Child() zodb.IPersistent { return e.child } func (e *Entry) Child() Node { return e.child }
// Entryv returns entries of a BTree node. // Entryv returns entries of a BTree node.
// //
...@@ -159,7 +168,7 @@ func (t *BTree) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err er ...@@ -159,7 +168,7 @@ func (t *BTree) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err er
// VGet is like Get but also calls visit while traversing the tree. // VGet is like Get but also calls visit while traversing the tree.
// //
// Visit is called with node being activated. // Visit is called with node being activated.
func (t *BTree) VGet(ctx context.Context, key KEY, visit func(node zodb.IPersistent)) (_ interface{}, _ bool, err error) { func (t *BTree) VGet(ctx context.Context, key KEY, visit func(node Node)) (_ interface{}, _ bool, err error) {
defer xerr.Contextf(&err, "btree(%s): get %v", t.POid(), key) defer xerr.Contextf(&err, "btree(%s): get %v", t.POid(), key)
err = t.PActivate(ctx) err = t.PActivate(ctx)
if err != nil { if err != nil {
...@@ -237,7 +246,7 @@ func (t *BTree) MinKey(ctx context.Context) (_ KEY, ok bool, err error) { ...@@ -237,7 +246,7 @@ func (t *BTree) MinKey(ctx context.Context) (_ KEY, ok bool, err error) {
// VMinKey is like MinKey but also calls visit while traversing the tree. // VMinKey is like MinKey but also calls visit while traversing the tree.
// //
// Visit is called with node being activated. // Visit is called with node being activated.
func (t *BTree) VMinKey(ctx context.Context, visit func(node zodb.IPersistent)) (_ KEY, ok bool, err error) { func (t *BTree) VMinKey(ctx context.Context, visit func(node Node)) (_ KEY, ok bool, err error) {
defer xerr.Contextf(&err, "btree(%s): minkey", t.POid()) defer xerr.Contextf(&err, "btree(%s): minkey", t.POid())
err = t.PActivate(ctx) err = t.PActivate(ctx)
if err != nil { if err != nil {
...@@ -256,7 +265,7 @@ func (t *BTree) VMinKey(ctx context.Context, visit func(node zodb.IPersistent)) ...@@ -256,7 +265,7 @@ func (t *BTree) VMinKey(ctx context.Context, visit func(node zodb.IPersistent))
// NOTE -> can also use t.firstbucket // NOTE -> can also use t.firstbucket
for { for {
child := t.data[0].child.(zodb.IPersistent) child := t.data[0].child
t.PDeactivate() t.PDeactivate()
err = child.PActivate(ctx) err = child.PActivate(ctx)
if err != nil { if err != nil {
...@@ -290,7 +299,7 @@ func (t *BTree) MaxKey(ctx context.Context) (_ KEY, _ bool, err error) { ...@@ -290,7 +299,7 @@ func (t *BTree) MaxKey(ctx context.Context) (_ KEY, _ bool, err error) {
// VMaxKey is like MaxKey but also calls visit while traversing the tree. // VMaxKey is like MaxKey but also calls visit while traversing the tree.
// //
// Visit is called with node being activated. // Visit is called with node being activated.
func (t *BTree) VMaxKey(ctx context.Context, visit func(node zodb.IPersistent)) (_ KEY, _ bool, err error) { func (t *BTree) VMaxKey(ctx context.Context, visit func(node Node)) (_ KEY, _ bool, err error) {
defer xerr.Contextf(&err, "btree(%s): maxkey", t.POid()) defer xerr.Contextf(&err, "btree(%s): maxkey", t.POid())
err = t.PActivate(ctx) err = t.PActivate(ctx)
if err != nil { if err != nil {
...@@ -309,7 +318,7 @@ func (t *BTree) VMaxKey(ctx context.Context, visit func(node zodb.IPersistent)) ...@@ -309,7 +318,7 @@ func (t *BTree) VMaxKey(ctx context.Context, visit func(node zodb.IPersistent))
} }
for { for {
child := t.data[l-1].child.(zodb.IPersistent) child := t.data[l-1].child
t.PDeactivate() t.PDeactivate()
err = child.PActivate(ctx) err = child.PActivate(ctx)
if err != nil { if err != nil {
...@@ -615,7 +624,7 @@ func (bt *btreeState) PySetState(pystate interface{}) (err error) { ...@@ -615,7 +624,7 @@ func (bt *btreeState) PySetState(pystate interface{}) (err error) {
fmt.Errorf("data: [%d]: children must be of the same type", i) fmt.Errorf("data: [%d]: children must be of the same type", i)
} }
bt.data = append(bt.data, Entry{key: kkey, child: child.(zodb.IPersistent)}) bt.data = append(bt.data, Entry{key: kkey, child: child.(Node)})
} }
return nil return nil
......
...@@ -38,6 +38,7 @@ sed \ ...@@ -38,6 +38,7 @@ sed \
-e "s/<KIND>/$KIND/g" \ -e "s/<KIND>/$KIND/g" \
-e "s/KEY/$KEY/g" \ -e "s/KEY/$KEY/g" \
-e "s/<Key>/$Key/g" \ -e "s/<Key>/$Key/g" \
-e "s/\bNode\b/${KIND}Node/g" \
-e "s/\bBTree\b/${KIND}BTree/g" \ -e "s/\bBTree\b/${KIND}BTree/g" \
-e "s/\bEntry\b/${KIND}Entry/g" \ -e "s/\bEntry\b/${KIND}Entry/g" \
-e "s/\bBucket\b/${KIND}Bucket/g" \ -e "s/\bBucket\b/${KIND}Bucket/g" \
......
...@@ -31,6 +31,15 @@ import ( ...@@ -31,6 +31,15 @@ import (
"lab.nexedi.com/kirr/neo/go/zodb/internal/pickletools" "lab.nexedi.com/kirr/neo/go/zodb/internal/pickletools"
) )
// IONode represents a tree node - either IOBTree or IOBucket.
type IONode interface {
zodb.IPersistent
node()
}
func (t *IOBTree) node() {}
func (b *IOBucket) node() {}
// IOBTree is a non-leaf node of a B⁺ tree. // IOBTree is a non-leaf node of a B⁺ tree.
// //
// It contains []IOEntry in ↑ key order. // It contains []IOEntry in ↑ key order.
...@@ -63,7 +72,7 @@ type IOBTree struct { ...@@ -63,7 +72,7 @@ type IOBTree struct {
// Key limits child's keys - see IOBTree.Entryv for details. // Key limits child's keys - see IOBTree.Entryv for details.
type IOEntry struct { type IOEntry struct {
key int32 key int32
child zodb.IPersistent // IOBTree or IOBucket child IONode // IOBTree or IOBucket
} }
// IOBucket is a leaf node of a B⁺ tree. // IOBucket is a leaf node of a B⁺ tree.
...@@ -101,7 +110,7 @@ type IOBucketEntry struct { ...@@ -101,7 +110,7 @@ type IOBucketEntry struct {
func (e *IOEntry) Key() int32 { return e.key } func (e *IOEntry) Key() int32 { return e.key }
// Child returns IOBTree entry child. // Child returns IOBTree entry child.
func (e *IOEntry) Child() zodb.IPersistent { return e.child } func (e *IOEntry) Child() IONode { return e.child }
// Entryv returns entries of a IOBTree node. // Entryv returns entries of a IOBTree node.
// //
...@@ -161,7 +170,7 @@ func (t *IOBTree) Get(ctx context.Context, key int32) (_ interface{}, _ bool, er ...@@ -161,7 +170,7 @@ func (t *IOBTree) Get(ctx context.Context, key int32) (_ interface{}, _ bool, er
// VGet is like Get but also calls visit while traversing the tree. // VGet is like Get but also calls visit while traversing the tree.
// //
// Visit is called with node being activated. // Visit is called with node being activated.
func (t *IOBTree) VGet(ctx context.Context, key int32, visit func(node zodb.IPersistent)) (_ interface{}, _ bool, err error) { func (t *IOBTree) VGet(ctx context.Context, key int32, visit func(node IONode)) (_ interface{}, _ bool, err error) {
defer xerr.Contextf(&err, "btree(%s): get %v", t.POid(), key) defer xerr.Contextf(&err, "btree(%s): get %v", t.POid(), key)
err = t.PActivate(ctx) err = t.PActivate(ctx)
if err != nil { if err != nil {
...@@ -239,7 +248,7 @@ func (t *IOBTree) MinKey(ctx context.Context) (_ int32, ok bool, err error) { ...@@ -239,7 +248,7 @@ func (t *IOBTree) MinKey(ctx context.Context) (_ int32, ok bool, err error) {
// VMinKey is like MinKey but also calls visit while traversing the tree. // VMinKey is like MinKey but also calls visit while traversing the tree.
// //
// Visit is called with node being activated. // Visit is called with node being activated.
func (t *IOBTree) VMinKey(ctx context.Context, visit func(node zodb.IPersistent)) (_ int32, ok bool, err error) { func (t *IOBTree) VMinKey(ctx context.Context, visit func(node IONode)) (_ int32, ok bool, err error) {
defer xerr.Contextf(&err, "btree(%s): minkey", t.POid()) defer xerr.Contextf(&err, "btree(%s): minkey", t.POid())
err = t.PActivate(ctx) err = t.PActivate(ctx)
if err != nil { if err != nil {
...@@ -258,7 +267,7 @@ func (t *IOBTree) VMinKey(ctx context.Context, visit func(node zodb.IPersistent) ...@@ -258,7 +267,7 @@ func (t *IOBTree) VMinKey(ctx context.Context, visit func(node zodb.IPersistent)
// NOTE -> can also use t.firstbucket // NOTE -> can also use t.firstbucket
for { for {
child := t.data[0].child.(zodb.IPersistent) child := t.data[0].child
t.PDeactivate() t.PDeactivate()
err = child.PActivate(ctx) err = child.PActivate(ctx)
if err != nil { if err != nil {
...@@ -292,7 +301,7 @@ func (t *IOBTree) MaxKey(ctx context.Context) (_ int32, _ bool, err error) { ...@@ -292,7 +301,7 @@ func (t *IOBTree) MaxKey(ctx context.Context) (_ int32, _ bool, err error) {
// VMaxKey is like MaxKey but also calls visit while traversing the tree. // VMaxKey is like MaxKey but also calls visit while traversing the tree.
// //
// Visit is called with node being activated. // Visit is called with node being activated.
func (t *IOBTree) VMaxKey(ctx context.Context, visit func(node zodb.IPersistent)) (_ int32, _ bool, err error) { func (t *IOBTree) VMaxKey(ctx context.Context, visit func(node IONode)) (_ int32, _ bool, err error) {
defer xerr.Contextf(&err, "btree(%s): maxkey", t.POid()) defer xerr.Contextf(&err, "btree(%s): maxkey", t.POid())
err = t.PActivate(ctx) err = t.PActivate(ctx)
if err != nil { if err != nil {
...@@ -311,7 +320,7 @@ func (t *IOBTree) VMaxKey(ctx context.Context, visit func(node zodb.IPersistent) ...@@ -311,7 +320,7 @@ func (t *IOBTree) VMaxKey(ctx context.Context, visit func(node zodb.IPersistent)
} }
for { for {
child := t.data[l-1].child.(zodb.IPersistent) child := t.data[l-1].child
t.PDeactivate() t.PDeactivate()
err = child.PActivate(ctx) err = child.PActivate(ctx)
if err != nil { if err != nil {
...@@ -617,7 +626,7 @@ func (bt *iobtreeState) PySetState(pystate interface{}) (err error) { ...@@ -617,7 +626,7 @@ func (bt *iobtreeState) PySetState(pystate interface{}) (err error) {
fmt.Errorf("data: [%d]: children must be of the same type", i) fmt.Errorf("data: [%d]: children must be of the same type", i)
} }
bt.data = append(bt.data, IOEntry{key: kkey, child: child.(zodb.IPersistent)}) bt.data = append(bt.data, IOEntry{key: kkey, child: child.(IONode)})
} }
return nil return nil
......
...@@ -31,6 +31,15 @@ import ( ...@@ -31,6 +31,15 @@ import (
"lab.nexedi.com/kirr/neo/go/zodb/internal/pickletools" "lab.nexedi.com/kirr/neo/go/zodb/internal/pickletools"
) )
// LONode represents a tree node - either LOBTree or LOBucket.
type LONode interface {
zodb.IPersistent
node()
}
func (t *LOBTree) node() {}
func (b *LOBucket) node() {}
// LOBTree is a non-leaf node of a B⁺ tree. // LOBTree is a non-leaf node of a B⁺ tree.
// //
// It contains []LOEntry in ↑ key order. // It contains []LOEntry in ↑ key order.
...@@ -63,7 +72,7 @@ type LOBTree struct { ...@@ -63,7 +72,7 @@ type LOBTree struct {
// Key limits child's keys - see LOBTree.Entryv for details. // Key limits child's keys - see LOBTree.Entryv for details.
type LOEntry struct { type LOEntry struct {
key int64 key int64
child zodb.IPersistent // LOBTree or LOBucket child LONode // LOBTree or LOBucket
} }
// LOBucket is a leaf node of a B⁺ tree. // LOBucket is a leaf node of a B⁺ tree.
...@@ -101,7 +110,7 @@ type LOBucketEntry struct { ...@@ -101,7 +110,7 @@ type LOBucketEntry struct {
func (e *LOEntry) Key() int64 { return e.key } func (e *LOEntry) Key() int64 { return e.key }
// Child returns LOBTree entry child. // Child returns LOBTree entry child.
func (e *LOEntry) Child() zodb.IPersistent { return e.child } func (e *LOEntry) Child() LONode { return e.child }
// Entryv returns entries of a LOBTree node. // Entryv returns entries of a LOBTree node.
// //
...@@ -161,7 +170,7 @@ func (t *LOBTree) Get(ctx context.Context, key int64) (_ interface{}, _ bool, er ...@@ -161,7 +170,7 @@ func (t *LOBTree) Get(ctx context.Context, key int64) (_ interface{}, _ bool, er
// VGet is like Get but also calls visit while traversing the tree. // VGet is like Get but also calls visit while traversing the tree.
// //
// Visit is called with node being activated. // Visit is called with node being activated.
func (t *LOBTree) VGet(ctx context.Context, key int64, visit func(node zodb.IPersistent)) (_ interface{}, _ bool, err error) { func (t *LOBTree) VGet(ctx context.Context, key int64, visit func(node LONode)) (_ interface{}, _ bool, err error) {
defer xerr.Contextf(&err, "btree(%s): get %v", t.POid(), key) defer xerr.Contextf(&err, "btree(%s): get %v", t.POid(), key)
err = t.PActivate(ctx) err = t.PActivate(ctx)
if err != nil { if err != nil {
...@@ -239,7 +248,7 @@ func (t *LOBTree) MinKey(ctx context.Context) (_ int64, ok bool, err error) { ...@@ -239,7 +248,7 @@ func (t *LOBTree) MinKey(ctx context.Context) (_ int64, ok bool, err error) {
// VMinKey is like MinKey but also calls visit while traversing the tree. // VMinKey is like MinKey but also calls visit while traversing the tree.
// //
// Visit is called with node being activated. // Visit is called with node being activated.
func (t *LOBTree) VMinKey(ctx context.Context, visit func(node zodb.IPersistent)) (_ int64, ok bool, err error) { func (t *LOBTree) VMinKey(ctx context.Context, visit func(node LONode)) (_ int64, ok bool, err error) {
defer xerr.Contextf(&err, "btree(%s): minkey", t.POid()) defer xerr.Contextf(&err, "btree(%s): minkey", t.POid())
err = t.PActivate(ctx) err = t.PActivate(ctx)
if err != nil { if err != nil {
...@@ -258,7 +267,7 @@ func (t *LOBTree) VMinKey(ctx context.Context, visit func(node zodb.IPersistent) ...@@ -258,7 +267,7 @@ func (t *LOBTree) VMinKey(ctx context.Context, visit func(node zodb.IPersistent)
// NOTE -> can also use t.firstbucket // NOTE -> can also use t.firstbucket
for { for {
child := t.data[0].child.(zodb.IPersistent) child := t.data[0].child
t.PDeactivate() t.PDeactivate()
err = child.PActivate(ctx) err = child.PActivate(ctx)
if err != nil { if err != nil {
...@@ -292,7 +301,7 @@ func (t *LOBTree) MaxKey(ctx context.Context) (_ int64, _ bool, err error) { ...@@ -292,7 +301,7 @@ func (t *LOBTree) MaxKey(ctx context.Context) (_ int64, _ bool, err error) {
// VMaxKey is like MaxKey but also calls visit while traversing the tree. // VMaxKey is like MaxKey but also calls visit while traversing the tree.
// //
// Visit is called with node being activated. // Visit is called with node being activated.
func (t *LOBTree) VMaxKey(ctx context.Context, visit func(node zodb.IPersistent)) (_ int64, _ bool, err error) { func (t *LOBTree) VMaxKey(ctx context.Context, visit func(node LONode)) (_ int64, _ bool, err error) {
defer xerr.Contextf(&err, "btree(%s): maxkey", t.POid()) defer xerr.Contextf(&err, "btree(%s): maxkey", t.POid())
err = t.PActivate(ctx) err = t.PActivate(ctx)
if err != nil { if err != nil {
...@@ -311,7 +320,7 @@ func (t *LOBTree) VMaxKey(ctx context.Context, visit func(node zodb.IPersistent) ...@@ -311,7 +320,7 @@ func (t *LOBTree) VMaxKey(ctx context.Context, visit func(node zodb.IPersistent)
} }
for { for {
child := t.data[l-1].child.(zodb.IPersistent) child := t.data[l-1].child
t.PDeactivate() t.PDeactivate()
err = child.PActivate(ctx) err = child.PActivate(ctx)
if err != nil { if err != nil {
...@@ -617,7 +626,7 @@ func (bt *lobtreeState) PySetState(pystate interface{}) (err error) { ...@@ -617,7 +626,7 @@ func (bt *lobtreeState) PySetState(pystate interface{}) (err error) {
fmt.Errorf("data: [%d]: children must be of the same type", i) fmt.Errorf("data: [%d]: children must be of the same type", i)
} }
bt.data = append(bt.data, LOEntry{key: kkey, child: child.(zodb.IPersistent)}) bt.data = append(bt.data, LOEntry{key: kkey, child: child.(LONode)})
} }
return nil return nil
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment