Commit 525305a0 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 7bf85a48
......@@ -18,40 +18,51 @@
// XXX name -> zbtree ?
package btree
// ZBucket mimics ?OBucket from btree/py, with ? being any integer.
import (
"context"
"sort"
"lab.nexedi.com/kirr/neo/go/zodb"
)
// XXX temp
type KEY int64
// Bucket mimics ?OBucket from btree/py, with ? being any integer.
//
// py description:
// original py description:
//
// A Bucket wraps contiguous vectors of keys and values. Keys are unique,
// and stored in sorted order. The 'values' pointer may be NULL if the
// Bucket is used to implement a set. Buckets serving as leafs of BTrees
// are chained together via 'next', so that the entire BTree contents
// can be traversed in sorted order quickly and easily.
type ZBucket struct {
type Bucket struct {
pyobj *zodb.PyObject
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
values []interface{} // 'len' corresponding values XXX merge k/v ?
}
// zBTreeItem mimics BTreeItem from btree/py.
type zBTreeItem {
type zBTreeItem struct {
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
// for details.
type ZBTree struct {
type BTree struct {
pyobj *zodb.PyObject
// firstbucket points to the bucket containing the smallest key in
// the BTree. This is found by traversing leftmost child pointers
// (data[0].child) until reaching a Bucket.
firstbucket *ZBucket
firstbucket *Bucket
// 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
......@@ -66,7 +77,7 @@ type ZBTree struct {
//
// It loads intermediate BTree nodes from database on demand as needed.
// XXX ok -> ErrKeyNotFound?
func (t *ZBTree) Get(ctx context.Context, key KEY) (interface{}, bool, error) {
func (t *BTree) Get(ctx context.Context, key KEY) (interface{}, bool, error) {
t.PActivate(ctx) // XXX err
if len(t.data) == 0 {
......@@ -85,14 +96,15 @@ func (t *ZBTree) Get(ctx context.Context, key KEY) (interface{}, bool, error) {
})
switch child := t.data[i].child.(type) {
case *ZBTree:
case *BTree:
// XXX t.PAllowDeactivate
t = child
t.PActivate(ctx) // XXX err
case *ZBucket:
case *Bucket:
child.PActivate(ctx) // XXX err
return child.Get(key), nil
x, ok := child.get(key)
return x, ok, nil
}
}
}
......@@ -100,12 +112,12 @@ func (t *ZBTree) Get(ctx context.Context, key KEY) (interface{}, bool, error) {
// get searches Bucket by key.
//
// 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) {
// XXX b.PActivate ? XXX better caller? (or inside if get -> Get)
// search i: K(i-1) < k ≤ K(i) ; K(-1) = -∞, K(len) = +∞
i := sort.Search(len(b.keys), func(i int) bool {
return key <= t.data[i].key
return key <= b.keys[i]
})
if i == len(b.keys) || b.keys[i] != key {
......@@ -142,10 +154,8 @@ func (b *ZBucket) get(key KEY) (interface{}, bool) {
// In the above, key[i] means self->data[i].key, and similarly for child[i].
// XXX ZBTree.Get(key)
// XXX ZBucket.MinKey ?
// XXX ZBucket.MaxKey ?
// XXX Bucket.MinKey ?
// XXX Bucket.MaxKey ?
// from https://github.com/zopefoundation/BTrees/blob/4.5.0-1-gc8bf24e/BTrees/BucketTemplate.c#L1195:
......
......@@ -35,6 +35,8 @@ import (
// TODO maintain nhit / nmiss + way to read cache stats
// TODO optimize cache more so that miss overhead becomes negligible
// TODO Drop(xid) -> make sure data for xid is no longer in cache
// Cache provides RAM caching layer that can be used over a storage.
type Cache struct {
loader interface {
......
......@@ -23,11 +23,68 @@ package zodb
import (
"bytes"
"errors"
"fmt"
//"fmt"
pickle "github.com/kisielk/og-rek"
)
// XXX move out of py
// Object is in-process representaion of a ZODB object.
type Object interface {
Jar() *Connection
Oid() Oid
Serial() Tid
Data() *mem.Buf // XXX for raw, py -> PyObject
// XXX register(jar, oid) - register to database ? (for Connection.Add)
// PActivate
// PDeactivate
// PInvalidate
}
// XXX
type DataManager interface {
//LoadObject(obj Object)
//LoadObject(oid Oid)
LoadState(obj)
// XXX oldstate(oid, tid)
// XXX register(obj)
}
// Connection represent client-visible part of a connection to ZODB database.
//
// XXX consitent view for some `at`.
// XXX not needed? (just DB.Open() -> root object and connection not be visible)?
type Connection interface {
// Get returns object by oid.
// XXX multiple calls to Get with same oid return the same object.
// XXX root object has oid=0.
Get(ctx context.Context, oid Oid) (Object, error)
// XXX Add(obj Object) -> add obj to database and assign it an oid
// obj must be not yet added
// XXX ReadCurrent(obj)
// XXX Close() error
}
// PyData represents raw data stored into ZODB by Python applications.
//
// The format is based on python pickles. Basically every serialized object has
......@@ -48,14 +105,15 @@ type PyData []byte
// PyObject represents persistent Python object.
//
// PyObject can be decoded from PyData.
// PyObject can be decoded from PyData. XXX
type PyObject struct {
//oid Oid
//serial Tid
Jar *Connection // XXX -> ro
Oid Oid // XXX -> ro
Serial Tid // XXX -> ro
// XXX + Oid, Serial ? (_p_oid, _p_serial)
pyClass pickle.Class // python class of this object XXX -> ro
State interface{} // object state. python passes this to pyclass.__new__().__setstate__()
PyClass pickle.Class // python class of this object XXX -> ro ?
PyState interface{} // object state. python passes this to pyclass.__new__().__setstate__()
}
......@@ -67,18 +125,19 @@ type PyLoader interface {
}
/*
// Decode decodes raw ZODB python data into PyObject. XXX -> (pyclass, pystate)
//func (d PyData) Decode() (*PyObject, error) {
func (d PyData) Decode() (pyclass PyClass, pystate interface{}, _ error) {
func (d PyData) Decode() (pyclass pickle.Class, pystate interface{}, _ error) {
p := pickle.NewDecoder(bytes.NewReader([]byte(d)))
xklass, err := p.Decode()
if err != nil {
return nil, fmt.Errorf("pydata: decode: class description: %s", err)
return nil, nil, fmt.Errorf("pydata: decode: class description: %s", err)
}
klass, err := normPyClass(xklass)
if err != nil {
return nil, fmt.Errorf("pydata: decode: class description: %s", err)
return nil, nil, fmt.Errorf("pydata: decode: class description: %s", err)
}
state, err := p.Decode()
......@@ -86,8 +145,10 @@ func (d PyData) Decode() (pyclass PyClass, pystate interface{}, _ error) {
return nil, fmt.Errorf("pydata: decode: object state: %s", err)
}
return &PyObject{pyClass: klass, State: state}, nil
//return &PyObject{pyClass: klass, State: state}, nil
return klass, state, nil
}
*/
// ClassName returns fully-qualified python class name used for object type.
......@@ -150,7 +211,7 @@ func normPyClass(xklass interface{}) (pickle.Class, error) {
return pickle.Class{}, errInvalidPyClass
}
// PyClass returns Python class of the object.
func (pyobj *PyObject) PyClass() pickle.Class {
return pyobj.pyClass
}
// // PyClass returns Python class of the object.
// func (pyobj *PyObject) PyClass() pickle.Class {
// return pyobj.pyClass
// }
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