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

.

parent 7bf85a48
...@@ -18,40 +18,51 @@ ...@@ -18,40 +18,51 @@
// XXX name -> zbtree ? // XXX name -> zbtree ?
package btree 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, // 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 // 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 // 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 {
pyobj *zodb.PyObject 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 keys []KEY // 'len' keys, in increasing order
values []interface{} // 'len' corresponding values XXX merge k/v ? values []interface{} // 'len' corresponding values XXX merge k/v ?
} }
// zBTreeItem mimics BTreeItem from btree/py. // zBTreeItem mimics BTreeItem from btree/py.
type zBTreeItem { 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 {
pyobj *zodb.PyObject pyobj *zodb.PyObject
// 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
...@@ -66,7 +77,7 @@ type ZBTree struct { ...@@ -66,7 +77,7 @@ type ZBTree struct {
// //
// It loads intermediate BTree nodes from database on demand as needed. // It loads intermediate BTree nodes from database on demand as needed.
// XXX ok -> ErrKeyNotFound? // 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 t.PActivate(ctx) // XXX err
if len(t.data) == 0 { if len(t.data) == 0 {
...@@ -85,14 +96,15 @@ func (t *ZBTree) Get(ctx context.Context, key KEY) (interface{}, bool, error) { ...@@ -85,14 +96,15 @@ func (t *ZBTree) Get(ctx context.Context, key KEY) (interface{}, bool, error) {
}) })
switch child := t.data[i].child.(type) { switch child := t.data[i].child.(type) {
case *ZBTree: case *BTree:
// XXX t.PAllowDeactivate // XXX t.PAllowDeactivate
t = child t = child
t.PActivate(ctx) // XXX err t.PActivate(ctx) // XXX err
case *ZBucket: case *Bucket:
child.PActivate(ctx) // XXX err 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) { ...@@ -100,12 +112,12 @@ func (t *ZBTree) Get(ctx context.Context, key KEY) (interface{}, bool, error) {
// 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) {
// XXX b.PActivate ? XXX better caller? (or inside if get -> Get) // XXX b.PActivate ? XXX better caller? (or inside if get -> Get)
// 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 <= t.data[i].key return key <= b.keys[i]
}) })
if i == len(b.keys) || b.keys[i] != key { if i == len(b.keys) || b.keys[i] != key {
...@@ -142,10 +154,8 @@ func (b *ZBucket) get(key KEY) (interface{}, bool) { ...@@ -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]. // In the above, key[i] means self->data[i].key, and similarly for child[i].
// XXX ZBTree.Get(key) // XXX Bucket.MinKey ?
// XXX Bucket.MaxKey ?
// XXX ZBucket.MinKey ?
// XXX ZBucket.MaxKey ?
// from https://github.com/zopefoundation/BTrees/blob/4.5.0-1-gc8bf24e/BTrees/BucketTemplate.c#L1195: // from https://github.com/zopefoundation/BTrees/blob/4.5.0-1-gc8bf24e/BTrees/BucketTemplate.c#L1195:
......
...@@ -35,6 +35,8 @@ import ( ...@@ -35,6 +35,8 @@ import (
// TODO maintain nhit / nmiss + way to read cache stats // TODO maintain nhit / nmiss + way to read cache stats
// TODO optimize cache more so that miss overhead becomes negligible // 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. // Cache provides RAM caching layer that can be used over a storage.
type Cache struct { type Cache struct {
loader interface { loader interface {
......
...@@ -23,11 +23,68 @@ package zodb ...@@ -23,11 +23,68 @@ package zodb
import ( import (
"bytes" "bytes"
"errors" "errors"
"fmt" //"fmt"
pickle "github.com/kisielk/og-rek" 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. // PyData represents raw data stored into ZODB by Python applications.
// //
// The format is based on python pickles. Basically every serialized object has // The format is based on python pickles. Basically every serialized object has
...@@ -48,14 +105,15 @@ type PyData []byte ...@@ -48,14 +105,15 @@ type PyData []byte
// PyObject represents persistent Python object. // PyObject represents persistent Python object.
// //
// PyObject can be decoded from PyData. // PyObject can be decoded from PyData. XXX
type PyObject struct { type PyObject struct {
//oid Oid Jar *Connection // XXX -> ro
//serial Tid Oid Oid // XXX -> ro
Serial Tid // XXX -> ro
// XXX + Oid, Serial ? (_p_oid, _p_serial) // XXX + Oid, Serial ? (_p_oid, _p_serial)
pyClass pickle.Class // python class of this object XXX -> ro PyClass pickle.Class // python class of this object XXX -> ro ?
State interface{} // object state. python passes this to pyclass.__new__().__setstate__() PyState interface{} // object state. python passes this to pyclass.__new__().__setstate__()
} }
...@@ -67,18 +125,19 @@ type PyLoader interface { ...@@ -67,18 +125,19 @@ type PyLoader interface {
} }
/*
// Decode decodes raw ZODB python data into PyObject. XXX -> (pyclass, pystate) // Decode decodes raw ZODB python data into PyObject. XXX -> (pyclass, pystate)
//func (d PyData) Decode() (*PyObject, error) { //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))) p := pickle.NewDecoder(bytes.NewReader([]byte(d)))
xklass, err := p.Decode() xklass, err := p.Decode()
if err != nil { 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) klass, err := normPyClass(xklass)
if err != nil { 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() state, err := p.Decode()
...@@ -86,8 +145,10 @@ func (d PyData) Decode() (pyclass PyClass, pystate interface{}, _ error) { ...@@ -86,8 +145,10 @@ func (d PyData) Decode() (pyclass PyClass, pystate interface{}, _ error) {
return nil, fmt.Errorf("pydata: decode: object state: %s", err) 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. // ClassName returns fully-qualified python class name used for object type.
...@@ -150,7 +211,7 @@ func normPyClass(xklass interface{}) (pickle.Class, error) { ...@@ -150,7 +211,7 @@ func normPyClass(xklass interface{}) (pickle.Class, error) {
return pickle.Class{}, errInvalidPyClass return pickle.Class{}, errInvalidPyClass
} }
// PyClass returns Python class of the object. // // PyClass returns Python class of the object.
func (pyobj *PyObject) PyClass() pickle.Class { // func (pyobj *PyObject) PyClass() pickle.Class {
return pyobj.pyClass // 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