Commit 821a0afc authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent c31c4855
...@@ -11,8 +11,12 @@ ...@@ -11,8 +11,12 @@
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS // WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
// FOR A PARTICULAR PURPOSE // FOR A PARTICULAR PURPOSE
package main // Package btree provides B⁺ Trees for ZODB.
// ZODB BTree handling XXX -> zodb //
// It is modelled and data compatible with BTree/py package:
//
// https://github.com/zopefoundation/BTrees
package btree
import ( import (
"context" "context"
...@@ -27,7 +31,7 @@ import ( ...@@ -27,7 +31,7 @@ import (
type KEY int64 type KEY int64
// ZBucket mimics ?OBucket from btree/py, with ? being any integer. // Bucket mimics ?OBucket from btree/py, with ? being any integer.
// //
// py description: // py description:
// //
...@@ -36,10 +40,10 @@ type KEY int64 ...@@ -36,10 +40,10 @@ type KEY int64
// Bucket is used to implement a set. Buckets serving as leafs of BTrees // Bucket is used to implement a set. Buckets serving as leafs of BTrees
// are chained together via 'next', so that the entire BTree contents // are chained together via 'next', so that the entire BTree contents
// can be traversed in sorted order quickly and easily. // can be traversed in sorted order quickly and easily.
type ZBucket struct { type Bucket struct {
*zodb.PyPersistent *zodb.PyPersistent
next *ZBucket // the bucket with the next-larger keys next *Bucket // the bucket with the next-larger keys
keys []KEY // 'len' keys, in increasing order keys []KEY // 'len' keys, in increasing order
values []interface{} // 'len' corresponding values values []interface{} // 'len' corresponding values
} }
...@@ -47,20 +51,20 @@ type ZBucket struct { ...@@ -47,20 +51,20 @@ type ZBucket struct {
// zBTreeItem mimics BTreeItem from btree/py. // zBTreeItem mimics BTreeItem from btree/py.
type zBTreeItem struct { type zBTreeItem struct {
key KEY key KEY
child interface{} // ZBTree or ZBucket child interface{} // BTree or Bucket
} }
// ZBTree mimics ?OBTree from btree/py, with ? being any integer. // BTree mimics ?OBTree from btree/py, with ? being any integer.
// //
// See https://github.com/zopefoundation/BTrees/blob/4.5.0-1-gc8bf24e/BTrees/Development.txt#L198 // See https://github.com/zopefoundation/BTrees/blob/4.5.0-1-gc8bf24e/BTrees/Development.txt#L198
// for details. // for details.
type ZBTree struct { type BTree struct {
*zodb.PyPersistent *zodb.PyPersistent
// firstbucket points to the bucket containing the smallest key in // firstbucket points to the bucket containing the smallest key in
// the BTree. This is found by traversing leftmost child pointers // the BTree. This is found by traversing leftmost child pointers
// (data[0].child) until reaching a Bucket. // (data[0].child) until reaching a Bucket.
firstbucket *ZBucket firstbucket *Bucket
// The BTree points to 'len' children, via the "child" fields of the data // The BTree points to 'len' children, via the "child" fields of the data
// array. There are len-1 keys in the 'key' fields, stored in increasing // array. There are len-1 keys in the 'key' fields, stored in increasing
...@@ -74,7 +78,7 @@ type ZBTree struct { ...@@ -74,7 +78,7 @@ type ZBTree struct {
// Get searches BTree by key. // Get searches BTree by key.
// //
// It loads intermediate BTree nodes from database on demand as needed. // It loads intermediate BTree nodes from database on demand as needed.
func (t *ZBTree) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err error) { func (t *BTree) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err error) {
defer xerr.Contextf(&err, "btree(%s): get %s", t.POid(), key) // XXX + url? defer xerr.Contextf(&err, "btree(%s): get %s", t.POid(), key) // XXX + url?
err = t.PActivate(ctx) err = t.PActivate(ctx)
if err != nil { if err != nil {
...@@ -98,7 +102,7 @@ func (t *ZBTree) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err e ...@@ -98,7 +102,7 @@ func (t *ZBTree) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err e
}) })
switch child := t.data[i].child.(type) { switch child := t.data[i].child.(type) {
case *ZBTree: case *BTree:
t.PDeactivate() t.PDeactivate()
t = child t = child
err = t.PActivate(ctx) err = t.PActivate(ctx)
...@@ -106,7 +110,7 @@ func (t *ZBTree) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err e ...@@ -106,7 +110,7 @@ func (t *ZBTree) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err e
return nil, false, err return nil, false, err
} }
case *ZBucket: case *Bucket:
t.PDeactivate() t.PDeactivate()
return child.Get(ctx, key) return child.Get(ctx, key)
} }
...@@ -114,7 +118,7 @@ func (t *ZBTree) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err e ...@@ -114,7 +118,7 @@ func (t *ZBTree) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err e
} }
// Get searches Bucket by key. // Get searches Bucket by key.
func (b *ZBucket) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err error) { func (b *Bucket) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err error) {
defer xerr.Contextf(&err, "bucket(%s): get %s", b.POid(), key) // XXX + url? defer xerr.Contextf(&err, "bucket(%s): get %s", b.POid(), key) // XXX + url?
err = b.PActivate(ctx) err = b.PActivate(ctx)
if err != nil { if err != nil {
...@@ -129,7 +133,7 @@ func (b *ZBucket) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err ...@@ -129,7 +133,7 @@ func (b *ZBucket) Get(ctx context.Context, key KEY) (_ interface{}, _ bool, err
// get searches Bucket by key. // get searches Bucket by key.
// //
// no loading from database is done. The bucket must be already activated. // no loading from database is done. The bucket must be already activated.
func (b *ZBucket) get(key KEY) (interface{}, bool) { func (b *Bucket) get(key KEY) (interface{}, bool) {
// search i: K(i-1) < k ≤ K(i) ; K(-1) = -∞, K(len) = +∞ // search i: K(i-1) < k ≤ K(i) ; K(-1) = -∞, K(len) = +∞
i := sort.Search(len(b.keys), func(i int) bool { i := sort.Search(len(b.keys), func(i int) bool {
return key <= b.keys[i] return key <= b.keys[i]
...@@ -141,8 +145,8 @@ func (b *ZBucket) get(key KEY) (interface{}, bool) { ...@@ -141,8 +145,8 @@ func (b *ZBucket) get(key KEY) (interface{}, bool) {
return b.values[i], true return b.values[i], true
} }
// XXX ZBucket.MinKey ? // XXX Bucket.MinKey ?
// XXX ZBucket.MaxKey ? // XXX Bucket.MaxKey ?
// ---- serialization ---- // ---- serialization ----
...@@ -174,13 +178,13 @@ func (b *ZBucket) get(key KEY) (interface{}, bool) { ...@@ -174,13 +178,13 @@ func (b *ZBucket) get(key KEY) (interface{}, bool) {
// In the above, key[i] means self->data[i].key, and similarly for child[i]. // In the above, key[i] means self->data[i].key, and similarly for child[i].
// DropState implements Stateful. // DropState implements Stateful.
func (t *ZBTree) DropState() { func (t *BTree) DropState() {
t.firstbucket = nil t.firstbucket = nil
t.data = nil t.data = nil
} }
// PySetState implements PyStateful to set btree data from pystate. // PySetState implements PyStateful to set btree data from pystate.
func (bt *ZBTree) PySetState(pystate interface{}) error { func (bt *BTree) PySetState(pystate interface{}) error {
// empty btree // empty btree
if _, ok := pystate.(pickle.None); ok { if _, ok := pystate.(pickle.None); ok {
bt.firstbucket = nil bt.firstbucket = nil
...@@ -195,7 +199,7 @@ func (bt *ZBTree) PySetState(pystate interface{}) error { ...@@ -195,7 +199,7 @@ func (bt *ZBTree) PySetState(pystate interface{}) error {
// btree with 1 child bucket without oid // btree with 1 child bucket without oid
if len(t) == 1 { if len(t) == 1 {
bucket := &ZBucket{PyPersistent: nil /* FIXME */} bucket := &Bucket{PyPersistent: nil /* FIXME */}
err := bucket.PySetState(t[0]) err := bucket.PySetState(t[0])
if err != nil { if err != nil {
// XXX // XXX
...@@ -212,7 +216,7 @@ func (bt *ZBTree) PySetState(pystate interface{}) error { ...@@ -212,7 +216,7 @@ func (bt *ZBTree) PySetState(pystate interface{}) error {
// XXX // XXX
} }
bt.firstbucket, ok = t[1].(*ZBucket) bt.firstbucket, ok = t[1].(*Bucket)
if !ok { if !ok {
// XXX // XXX
} }
...@@ -236,8 +240,8 @@ func (bt *ZBTree) PySetState(pystate interface{}) error { ...@@ -236,8 +240,8 @@ func (bt *ZBTree) PySetState(pystate interface{}) error {
default: default:
// XXX // XXX
case *ZBTree: // ok case *BTree: // ok
case *ZBucket: // ok case *Bucket: // ok
} }
bt.data = append(bt.data, zBTreeItem{key: KEY(key), child: child}) bt.data = append(bt.data, zBTreeItem{key: KEY(key), child: child})
...@@ -261,14 +265,14 @@ func (bt *ZBTree) PySetState(pystate interface{}) error { ...@@ -261,14 +265,14 @@ func (bt *ZBTree) PySetState(pystate interface{}) error {
// ) // )
// DropState implements Stateful to discard bucket state. // DropState implements Stateful to discard bucket state.
func (b *ZBucket) DropState() { func (b *Bucket) DropState() {
b.next = nil b.next = nil
b.keys = nil b.keys = nil
b.values = nil b.values = nil
} }
// PySetState implements PyStateful to set bucket data from pystate. // PySetState implements PyStateful to set bucket data from pystate.
func (b *ZBucket) PySetState(pystate interface{}) error { func (b *Bucket) PySetState(pystate interface{}) error {
t, ok := pystate.(pickle.Tuple) t, ok := pystate.(pickle.Tuple)
if !ok || !(1 <= len(t) && len(t) <= 2) { if !ok || !(1 <= len(t) && len(t) <= 2) {
// XXX complain // XXX complain
...@@ -276,7 +280,7 @@ func (b *ZBucket) PySetState(pystate interface{}) error { ...@@ -276,7 +280,7 @@ func (b *ZBucket) PySetState(pystate interface{}) error {
// .next present // .next present
if len(t) == 2 { if len(t) == 2 {
next, ok := t[1].(*ZBucket) next, ok := t[1].(*Bucket)
if !ok { if !ok {
// XXX // XXX
} }
...@@ -312,8 +316,8 @@ func (b *ZBucket) PySetState(pystate interface{}) error { ...@@ -312,8 +316,8 @@ func (b *ZBucket) PySetState(pystate interface{}) error {
// ---- register classes to ZODB ---- // ---- register classes to ZODB ----
func bucketNew(base *zodb.PyPersistent) zodb.IPyPersistent { return &ZBucket{PyPersistent: base} } func bucketNew(base *zodb.PyPersistent) zodb.IPyPersistent { return &Bucket{PyPersistent: base} }
func btreeNew(base *zodb.PyPersistent) zodb.IPyPersistent { return &ZBTree{PyPersistent: base} } func btreeNew(base *zodb.PyPersistent) zodb.IPyPersistent { return &BTree{PyPersistent: base} }
func init() { func init() {
zodb.PyRegisterClass("zodb.BTree.LOBucket", bucketNew) zodb.PyRegisterClass("zodb.BTree.LOBucket", bucketNew)
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
// See COPYING file for full licensing terms. // See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
package main package btree
import ( import (
//"testing" //"testing"
......
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