Commit ac3e20cc authored by Kirill Smelkov's avatar Kirill Smelkov

go/zodb/btree: Add V<op> family of functions

This functions invoke visit callback on every BTree node they traverse.

Wendelin.core needs this to retrieve serials of not only looked up ZBlk
object, but also of every BTree nodes on the path to it.
parent 16146b5a
......@@ -27,6 +27,8 @@
//
// BTree.FirstBucket() and Bucket.Next() allow to iterate through leaf B⁺ tree nodes.
//
// BTree.V<op>(..., visit) performs <op> with calling visit on every accessed tree node.
//
// --------
//
// (*) https://github.com/zopefoundation/ZODB/blob/3.10.7-4-gb8d7a8567/src/BTrees/Development.txt#L211
......
......@@ -153,12 +153,23 @@ func (b *Bucket) Next() *Bucket {
//
// t need not be activated beforehand for Get to work.
func (t *BTree) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err error) {
return t.VGet(ctx, key, nil)
}
// VGet is like Get but also calls visit while traversing the tree.
//
// 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) {
defer xerr.Contextf(&err, "btree(%s): get %v", t.POid(), key)
err = t.PActivate(ctx)
if err != nil {
return nil, false, err
}
if visit != nil {
visit(t)
}
if len(t.data) == 0 {
// empty btree
t.PDeactivate()
......@@ -182,6 +193,10 @@ func (t *BTree) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err er
return nil, false, err
}
if visit != nil {
visit(child)
}
switch child := child.(type) {
case *BTree:
t = child
......@@ -216,12 +231,23 @@ func (b *Bucket) Get(key KEY) (interface{}, bool) {
// If the tree is empty, ok=false is returned.
// The tree does not need to be activated beforehand.
func (t *BTree) MinKey(ctx context.Context) (_ KEY, ok bool, err error) {
return t.VMinKey(ctx, nil)
}
// VMinKey is like MinKey but also calls visit while traversing the tree.
//
// Visit is called with node being activated.
func (t *BTree) VMinKey(ctx context.Context, visit func(node zodb.IPersistent)) (_ KEY, ok bool, err error) {
defer xerr.Contextf(&err, "btree(%s): minkey", t.POid())
err = t.PActivate(ctx)
if err != nil {
return 0, false, err
}
if visit != nil {
visit(t)
}
if len(t.data) == 0 {
// empty btree
t.PDeactivate()
......@@ -237,6 +263,10 @@ func (t *BTree) MinKey(ctx context.Context) (_ KEY, ok bool, err error) {
return 0, false, err
}
if visit != nil {
visit(child)
}
switch child := child.(type) {
case *BTree:
t = child
......@@ -254,12 +284,23 @@ func (t *BTree) MinKey(ctx context.Context) (_ KEY, ok bool, err error) {
// If the tree is empty, ok=false is returned.
// The tree does not need to be activated beforehand.
func (t *BTree) MaxKey(ctx context.Context) (_ KEY, _ bool, err error) {
return t.VMaxKey(ctx, nil)
}
// VMaxKey is like MaxKey but also calls visit while traversing the tree.
//
// Visit is called with node being activated.
func (t *BTree) VMaxKey(ctx context.Context, visit func(node zodb.IPersistent)) (_ KEY, _ bool, err error) {
defer xerr.Contextf(&err, "btree(%s): maxkey", t.POid())
err = t.PActivate(ctx)
if err != nil {
return 0, false, err
}
if visit != nil {
visit(t)
}
l := len(t.data)
if l == 0 {
// empty btree
......@@ -275,6 +316,10 @@ func (t *BTree) MaxKey(ctx context.Context) (_ KEY, _ bool, err error) {
return 0, false, err
}
if visit != nil {
visit(child)
}
switch child := child.(type) {
case *BTree:
t = child
......
......@@ -155,12 +155,23 @@ func (b *IOBucket) Next() *IOBucket {
//
// t need not be activated beforehand for Get to work.
func (t *IOBTree) Get(ctx context.Context, key int32) (_ interface{}, _ bool, err error) {
return t.VGet(ctx, key, nil)
}
// VGet is like Get but also calls visit while traversing the tree.
//
// 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) {
defer xerr.Contextf(&err, "btree(%s): get %v", t.POid(), key)
err = t.PActivate(ctx)
if err != nil {
return nil, false, err
}
if visit != nil {
visit(t)
}
if len(t.data) == 0 {
// empty btree
t.PDeactivate()
......@@ -184,6 +195,10 @@ func (t *IOBTree) Get(ctx context.Context, key int32) (_ interface{}, _ bool, er
return nil, false, err
}
if visit != nil {
visit(child)
}
switch child := child.(type) {
case *IOBTree:
t = child
......@@ -218,12 +233,23 @@ func (b *IOBucket) Get(key int32) (interface{}, bool) {
// If the tree is empty, ok=false is returned.
// The tree does not need to be activated beforehand.
func (t *IOBTree) MinKey(ctx context.Context) (_ int32, ok bool, err error) {
return t.VMinKey(ctx, nil)
}
// VMinKey is like MinKey but also calls visit while traversing the tree.
//
// Visit is called with node being activated.
func (t *IOBTree) VMinKey(ctx context.Context, visit func(node zodb.IPersistent)) (_ int32, ok bool, err error) {
defer xerr.Contextf(&err, "btree(%s): minkey", t.POid())
err = t.PActivate(ctx)
if err != nil {
return 0, false, err
}
if visit != nil {
visit(t)
}
if len(t.data) == 0 {
// empty btree
t.PDeactivate()
......@@ -239,6 +265,10 @@ func (t *IOBTree) MinKey(ctx context.Context) (_ int32, ok bool, err error) {
return 0, false, err
}
if visit != nil {
visit(child)
}
switch child := child.(type) {
case *IOBTree:
t = child
......@@ -256,12 +286,23 @@ func (t *IOBTree) MinKey(ctx context.Context) (_ int32, ok bool, err error) {
// If the tree is empty, ok=false is returned.
// The tree does not need to be activated beforehand.
func (t *IOBTree) MaxKey(ctx context.Context) (_ int32, _ bool, err error) {
return t.VMaxKey(ctx, nil)
}
// VMaxKey is like MaxKey but also calls visit while traversing the tree.
//
// Visit is called with node being activated.
func (t *IOBTree) VMaxKey(ctx context.Context, visit func(node zodb.IPersistent)) (_ int32, _ bool, err error) {
defer xerr.Contextf(&err, "btree(%s): maxkey", t.POid())
err = t.PActivate(ctx)
if err != nil {
return 0, false, err
}
if visit != nil {
visit(t)
}
l := len(t.data)
if l == 0 {
// empty btree
......@@ -277,6 +318,10 @@ func (t *IOBTree) MaxKey(ctx context.Context) (_ int32, _ bool, err error) {
return 0, false, err
}
if visit != nil {
visit(child)
}
switch child := child.(type) {
case *IOBTree:
t = child
......
......@@ -155,12 +155,23 @@ func (b *LOBucket) Next() *LOBucket {
//
// t need not be activated beforehand for Get to work.
func (t *LOBTree) Get(ctx context.Context, key int64) (_ interface{}, _ bool, err error) {
return t.VGet(ctx, key, nil)
}
// VGet is like Get but also calls visit while traversing the tree.
//
// 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) {
defer xerr.Contextf(&err, "btree(%s): get %v", t.POid(), key)
err = t.PActivate(ctx)
if err != nil {
return nil, false, err
}
if visit != nil {
visit(t)
}
if len(t.data) == 0 {
// empty btree
t.PDeactivate()
......@@ -184,6 +195,10 @@ func (t *LOBTree) Get(ctx context.Context, key int64) (_ interface{}, _ bool, er
return nil, false, err
}
if visit != nil {
visit(child)
}
switch child := child.(type) {
case *LOBTree:
t = child
......@@ -218,12 +233,23 @@ func (b *LOBucket) Get(key int64) (interface{}, bool) {
// If the tree is empty, ok=false is returned.
// The tree does not need to be activated beforehand.
func (t *LOBTree) MinKey(ctx context.Context) (_ int64, ok bool, err error) {
return t.VMinKey(ctx, nil)
}
// VMinKey is like MinKey but also calls visit while traversing the tree.
//
// Visit is called with node being activated.
func (t *LOBTree) VMinKey(ctx context.Context, visit func(node zodb.IPersistent)) (_ int64, ok bool, err error) {
defer xerr.Contextf(&err, "btree(%s): minkey", t.POid())
err = t.PActivate(ctx)
if err != nil {
return 0, false, err
}
if visit != nil {
visit(t)
}
if len(t.data) == 0 {
// empty btree
t.PDeactivate()
......@@ -239,6 +265,10 @@ func (t *LOBTree) MinKey(ctx context.Context) (_ int64, ok bool, err error) {
return 0, false, err
}
if visit != nil {
visit(child)
}
switch child := child.(type) {
case *LOBTree:
t = child
......@@ -256,12 +286,23 @@ func (t *LOBTree) MinKey(ctx context.Context) (_ int64, ok bool, err error) {
// If the tree is empty, ok=false is returned.
// The tree does not need to be activated beforehand.
func (t *LOBTree) MaxKey(ctx context.Context) (_ int64, _ bool, err error) {
return t.VMaxKey(ctx, nil)
}
// VMaxKey is like MaxKey but also calls visit while traversing the tree.
//
// Visit is called with node being activated.
func (t *LOBTree) VMaxKey(ctx context.Context, visit func(node zodb.IPersistent)) (_ int64, _ bool, err error) {
defer xerr.Contextf(&err, "btree(%s): maxkey", t.POid())
err = t.PActivate(ctx)
if err != nil {
return 0, false, err
}
if visit != nil {
visit(t)
}
l := len(t.data)
if l == 0 {
// empty btree
......@@ -277,6 +318,10 @@ func (t *LOBTree) MaxKey(ctx context.Context) (_ int64, _ bool, err error) {
return 0, false, err
}
if visit != nil {
visit(child)
}
switch child := child.(type) {
case *LOBTree:
t = child
......
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