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 @@ ...@@ -27,6 +27,8 @@
// //
// BTree.FirstBucket() and Bucket.Next() allow to iterate through leaf B⁺ tree nodes. // 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 // (*) 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 { ...@@ -153,12 +153,23 @@ func (b *Bucket) Next() *Bucket {
// //
// t need not be activated beforehand for Get to work. // t need not be activated beforehand for Get to work.
func (t *BTree) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err error) { 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) 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 {
return nil, false, err return nil, false, err
} }
if visit != nil {
visit(t)
}
if len(t.data) == 0 { if len(t.data) == 0 {
// empty btree // empty btree
t.PDeactivate() t.PDeactivate()
...@@ -182,6 +193,10 @@ func (t *BTree) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err er ...@@ -182,6 +193,10 @@ func (t *BTree) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err er
return nil, false, err return nil, false, err
} }
if visit != nil {
visit(child)
}
switch child := child.(type) { switch child := child.(type) {
case *BTree: case *BTree:
t = child t = child
...@@ -216,12 +231,23 @@ func (b *Bucket) Get(key KEY) (interface{}, bool) { ...@@ -216,12 +231,23 @@ func (b *Bucket) Get(key KEY) (interface{}, bool) {
// If the tree is empty, ok=false is returned. // If the tree is empty, ok=false is returned.
// The tree does not need to be activated beforehand. // The tree does not need to be activated beforehand.
func (t *BTree) MinKey(ctx context.Context) (_ KEY, ok bool, err error) { 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()) defer xerr.Contextf(&err, "btree(%s): minkey", t.POid())
err = t.PActivate(ctx) err = t.PActivate(ctx)
if err != nil { if err != nil {
return 0, false, err return 0, false, err
} }
if visit != nil {
visit(t)
}
if len(t.data) == 0 { if len(t.data) == 0 {
// empty btree // empty btree
t.PDeactivate() t.PDeactivate()
...@@ -237,6 +263,10 @@ func (t *BTree) MinKey(ctx context.Context) (_ KEY, ok bool, err error) { ...@@ -237,6 +263,10 @@ func (t *BTree) MinKey(ctx context.Context) (_ KEY, ok bool, err error) {
return 0, false, err return 0, false, err
} }
if visit != nil {
visit(child)
}
switch child := child.(type) { switch child := child.(type) {
case *BTree: case *BTree:
t = child t = child
...@@ -254,12 +284,23 @@ func (t *BTree) MinKey(ctx context.Context) (_ KEY, ok bool, err error) { ...@@ -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. // If the tree is empty, ok=false is returned.
// The tree does not need to be activated beforehand. // The tree does not need to be activated beforehand.
func (t *BTree) MaxKey(ctx context.Context) (_ KEY, _ bool, err error) { 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()) defer xerr.Contextf(&err, "btree(%s): maxkey", t.POid())
err = t.PActivate(ctx) err = t.PActivate(ctx)
if err != nil { if err != nil {
return 0, false, err return 0, false, err
} }
if visit != nil {
visit(t)
}
l := len(t.data) l := len(t.data)
if l == 0 { if l == 0 {
// empty btree // empty btree
...@@ -275,6 +316,10 @@ func (t *BTree) MaxKey(ctx context.Context) (_ KEY, _ bool, err error) { ...@@ -275,6 +316,10 @@ func (t *BTree) MaxKey(ctx context.Context) (_ KEY, _ bool, err error) {
return 0, false, err return 0, false, err
} }
if visit != nil {
visit(child)
}
switch child := child.(type) { switch child := child.(type) {
case *BTree: case *BTree:
t = child t = child
......
...@@ -155,12 +155,23 @@ func (b *IOBucket) Next() *IOBucket { ...@@ -155,12 +155,23 @@ func (b *IOBucket) Next() *IOBucket {
// //
// t need not be activated beforehand for Get to work. // t need not be activated beforehand for Get to work.
func (t *IOBTree) Get(ctx context.Context, key int32) (_ interface{}, _ bool, err error) { 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) 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 {
return nil, false, err return nil, false, err
} }
if visit != nil {
visit(t)
}
if len(t.data) == 0 { if len(t.data) == 0 {
// empty btree // empty btree
t.PDeactivate() t.PDeactivate()
...@@ -184,6 +195,10 @@ func (t *IOBTree) Get(ctx context.Context, key int32) (_ interface{}, _ bool, er ...@@ -184,6 +195,10 @@ func (t *IOBTree) Get(ctx context.Context, key int32) (_ interface{}, _ bool, er
return nil, false, err return nil, false, err
} }
if visit != nil {
visit(child)
}
switch child := child.(type) { switch child := child.(type) {
case *IOBTree: case *IOBTree:
t = child t = child
...@@ -218,12 +233,23 @@ func (b *IOBucket) Get(key int32) (interface{}, bool) { ...@@ -218,12 +233,23 @@ func (b *IOBucket) Get(key int32) (interface{}, bool) {
// If the tree is empty, ok=false is returned. // If the tree is empty, ok=false is returned.
// The tree does not need to be activated beforehand. // The tree does not need to be activated beforehand.
func (t *IOBTree) MinKey(ctx context.Context) (_ int32, ok bool, err error) { 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()) defer xerr.Contextf(&err, "btree(%s): minkey", t.POid())
err = t.PActivate(ctx) err = t.PActivate(ctx)
if err != nil { if err != nil {
return 0, false, err return 0, false, err
} }
if visit != nil {
visit(t)
}
if len(t.data) == 0 { if len(t.data) == 0 {
// empty btree // empty btree
t.PDeactivate() t.PDeactivate()
...@@ -239,6 +265,10 @@ func (t *IOBTree) MinKey(ctx context.Context) (_ int32, ok bool, err error) { ...@@ -239,6 +265,10 @@ func (t *IOBTree) MinKey(ctx context.Context) (_ int32, ok bool, err error) {
return 0, false, err return 0, false, err
} }
if visit != nil {
visit(child)
}
switch child := child.(type) { switch child := child.(type) {
case *IOBTree: case *IOBTree:
t = child t = child
...@@ -256,12 +286,23 @@ func (t *IOBTree) MinKey(ctx context.Context) (_ int32, ok bool, err error) { ...@@ -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. // If the tree is empty, ok=false is returned.
// The tree does not need to be activated beforehand. // The tree does not need to be activated beforehand.
func (t *IOBTree) MaxKey(ctx context.Context) (_ int32, _ bool, err error) { 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()) defer xerr.Contextf(&err, "btree(%s): maxkey", t.POid())
err = t.PActivate(ctx) err = t.PActivate(ctx)
if err != nil { if err != nil {
return 0, false, err return 0, false, err
} }
if visit != nil {
visit(t)
}
l := len(t.data) l := len(t.data)
if l == 0 { if l == 0 {
// empty btree // empty btree
...@@ -277,6 +318,10 @@ func (t *IOBTree) MaxKey(ctx context.Context) (_ int32, _ bool, err error) { ...@@ -277,6 +318,10 @@ func (t *IOBTree) MaxKey(ctx context.Context) (_ int32, _ bool, err error) {
return 0, false, err return 0, false, err
} }
if visit != nil {
visit(child)
}
switch child := child.(type) { switch child := child.(type) {
case *IOBTree: case *IOBTree:
t = child t = child
......
...@@ -155,12 +155,23 @@ func (b *LOBucket) Next() *LOBucket { ...@@ -155,12 +155,23 @@ func (b *LOBucket) Next() *LOBucket {
// //
// t need not be activated beforehand for Get to work. // t need not be activated beforehand for Get to work.
func (t *LOBTree) Get(ctx context.Context, key int64) (_ interface{}, _ bool, err error) { 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) 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 {
return nil, false, err return nil, false, err
} }
if visit != nil {
visit(t)
}
if len(t.data) == 0 { if len(t.data) == 0 {
// empty btree // empty btree
t.PDeactivate() t.PDeactivate()
...@@ -184,6 +195,10 @@ func (t *LOBTree) Get(ctx context.Context, key int64) (_ interface{}, _ bool, er ...@@ -184,6 +195,10 @@ func (t *LOBTree) Get(ctx context.Context, key int64) (_ interface{}, _ bool, er
return nil, false, err return nil, false, err
} }
if visit != nil {
visit(child)
}
switch child := child.(type) { switch child := child.(type) {
case *LOBTree: case *LOBTree:
t = child t = child
...@@ -218,12 +233,23 @@ func (b *LOBucket) Get(key int64) (interface{}, bool) { ...@@ -218,12 +233,23 @@ func (b *LOBucket) Get(key int64) (interface{}, bool) {
// If the tree is empty, ok=false is returned. // If the tree is empty, ok=false is returned.
// The tree does not need to be activated beforehand. // The tree does not need to be activated beforehand.
func (t *LOBTree) MinKey(ctx context.Context) (_ int64, ok bool, err error) { 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()) defer xerr.Contextf(&err, "btree(%s): minkey", t.POid())
err = t.PActivate(ctx) err = t.PActivate(ctx)
if err != nil { if err != nil {
return 0, false, err return 0, false, err
} }
if visit != nil {
visit(t)
}
if len(t.data) == 0 { if len(t.data) == 0 {
// empty btree // empty btree
t.PDeactivate() t.PDeactivate()
...@@ -239,6 +265,10 @@ func (t *LOBTree) MinKey(ctx context.Context) (_ int64, ok bool, err error) { ...@@ -239,6 +265,10 @@ func (t *LOBTree) MinKey(ctx context.Context) (_ int64, ok bool, err error) {
return 0, false, err return 0, false, err
} }
if visit != nil {
visit(child)
}
switch child := child.(type) { switch child := child.(type) {
case *LOBTree: case *LOBTree:
t = child t = child
...@@ -256,12 +286,23 @@ func (t *LOBTree) MinKey(ctx context.Context) (_ int64, ok bool, err error) { ...@@ -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. // If the tree is empty, ok=false is returned.
// The tree does not need to be activated beforehand. // The tree does not need to be activated beforehand.
func (t *LOBTree) MaxKey(ctx context.Context) (_ int64, _ bool, err error) { 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()) defer xerr.Contextf(&err, "btree(%s): maxkey", t.POid())
err = t.PActivate(ctx) err = t.PActivate(ctx)
if err != nil { if err != nil {
return 0, false, err return 0, false, err
} }
if visit != nil {
visit(t)
}
l := len(t.data) l := len(t.data)
if l == 0 { if l == 0 {
// empty btree // empty btree
...@@ -277,6 +318,10 @@ func (t *LOBTree) MaxKey(ctx context.Context) (_ int64, _ bool, err error) { ...@@ -277,6 +318,10 @@ func (t *LOBTree) MaxKey(ctx context.Context) (_ int64, _ bool, err error) {
return 0, false, err return 0, false, err
} }
if visit != nil {
visit(child)
}
switch child := child.(type) { switch child := child.(type) {
case *LOBTree: case *LOBTree:
t = child 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