Commit 6ba3593d authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 7be36e9e
...@@ -36,7 +36,7 @@ type KEY int64 ...@@ -36,7 +36,7 @@ type KEY int64
// 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 ZBucket struct {
pyobj *pyObject *pyObject
next *ZBucket // the bucket with the next-larger keys next *ZBucket // the bucket with the next-larger keys
keys []KEY // 'len' keys, in increasing order keys []KEY // 'len' keys, in increasing order
...@@ -54,7 +54,7 @@ type zBTreeItem struct { ...@@ -54,7 +54,7 @@ type zBTreeItem struct {
// 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 ZBTree struct {
pyobj *pyObject *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
...@@ -154,7 +154,7 @@ func (t *ZBTree) PDeactivate() { ...@@ -154,7 +154,7 @@ func (t *ZBTree) PDeactivate() {
// XXX check if activated? // XXX check if activated?
t.firstbucket = nil t.firstbucket = nil
t.data = nil t.data = nil
t.pyobj.PDeactivate() t.pyObject.PDeactivate()
} }
func (t *ZBTree) PActivate(ctx context.Context) error { func (t *ZBTree) PActivate(ctx context.Context) error {
...@@ -186,18 +186,18 @@ func (b *ZBucket) PDeactivate() { ...@@ -186,18 +186,18 @@ func (b *ZBucket) PDeactivate() {
b.next = nil b.next = nil
b.keys = nil b.keys = nil
b.values = nil b.values = nil
b.pyobj.PDeactivate() b.pyObject.PDeactivate()
} }
func (b *ZBucket) PActivate(ctx context.Context) error { func (b *ZBucket) PActivate(ctx context.Context) error {
// XXX check if already activated // XXX check if already activated
err := b.pyobj.PActivate(ctx) err := b.pyObject.PActivate(ctx)
if err != nil { if err != nil {
return err return err
} }
t, ok := b.pyobj.pystate.(pickle.Tuple) t, ok := b.pyObject.pystate.(pickle.Tuple)
if !ok || !(1 <= len(t) && len(t) <= 2) { if !ok || !(1 <= len(t) && len(t) <= 2) {
// XXX complain // XXX complain
} }
...@@ -239,12 +239,12 @@ func (b *ZBucket) PActivate(ctx context.Context) error { ...@@ -239,12 +239,12 @@ func (b *ZBucket) PActivate(ctx context.Context) error {
// ---------------------------------------- // ----------------------------------------
func bucketNew(pyobj *pyObject) interface{} { func bucketNew(pyobj *pyObject) PyObject {
return &ZBucket{pyobj: pyobj} return &ZBucket{pyObject: pyobj}
} }
func btreeNew(pyobj *pyObject) interface{} { func btreeNew(pyobj *pyObject) PyObject {
return &ZBTree{pyobj: pyobj} return &ZBTree{pyObject: pyobj}
} }
func init() { func init() {
......
...@@ -24,6 +24,23 @@ import ( ...@@ -24,6 +24,23 @@ import (
pickle "github.com/kisielk/og-rek" pickle "github.com/kisielk/og-rek"
) )
// Object is the interface that every object representing any ZODB object implements.
type Object interface {
Jar() *Connection
Oid() zodb.Oid
Serial() zodb.Tid
// XXX activate/deactivate/invalidate here?
}
// PyObject is the interface that every object representing Python ZODB object implements.
type PyObject interface {
Object
PyClass() pickle.Class
// PyState?
}
// object is common base for in-process representation of ZODB object. // object is common base for in-process representation of ZODB object.
type object struct { type object struct {
jar *Connection jar *Connection
...@@ -31,6 +48,10 @@ type object struct { ...@@ -31,6 +48,10 @@ type object struct {
serial zodb.Tid serial zodb.Tid
} }
func (obj *object) Jar() *Connection { return obj.jar }
func (obj *object) Oid() zodb.Oid { return obj.oid }
func (obj *object) Serial() zodb.Tid { return obj.serial }
// pyObject is common base for in-process representation of ZODB Python objects. // pyObject is common base for in-process representation of ZODB Python objects.
type pyObject struct { type pyObject struct {
object object
...@@ -39,6 +60,9 @@ type pyObject struct { ...@@ -39,6 +60,9 @@ type pyObject struct {
pystate interface{} // object state. python passes this to pyclass.__new__().__setstate__() pystate interface{} // object state. python passes this to pyclass.__new__().__setstate__()
} }
func (pyobj *pyObject) PyClass() pickle.Class { return pyobj.pyclass }
// Connection represents a view of ZODB database. // Connection represents a view of ZODB database.
// //
// The view is representing state of ZODB objects as of `at` transaction. // The view is representing state of ZODB objects as of `at` transaction.
...@@ -232,24 +256,26 @@ func (e *wrongClassError) Error() string { ...@@ -232,24 +256,26 @@ func (e *wrongClassError) Error() string {
// //
// use-case: in ZODB references are (pyclass, oid), so new ghost is created // use-case: in ZODB references are (pyclass, oid), so new ghost is created
// without further loading anything. // without further loading anything.
func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (interface{}/*PyObject*/, error) { func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (PyObject, error) {
conn.objmu.Lock() // XXX -> rlock conn.objmu.Lock() // XXX -> rlock
wobj := conn.objtab[oid] wobj := conn.objtab[oid]
var xobj interface{} var pyobj PyObject
checkClass := false checkClass := false
if wobj != nil { if wobj != nil {
xobj = wobj.Get() if xobj := wobj.Get(); xobj != nil {
pyobj = xobj.(PyObject)
}
} }
if xobj == nil { if pyobj == nil {
xobj = conn.newGhost(pyclass, oid) pyobj = conn.newGhost(pyclass, oid)
conn.objtab[oid] = NewWeakRef(xobj) conn.objtab[oid] = NewWeakRef(pyobj)
} else { } else {
checkClass = true checkClass = true
} }
conn.objmu.Unlock() conn.objmu.Unlock()
if checkClass { if checkClass {
if cls := xobj.PyClass(); pyclass != cls { if cls := pyobj.PyClass(); pyclass != cls {
return nil, &zodb.OpError{ return nil, &zodb.OpError{
URL: conn.stor.URL(), URL: conn.stor.URL(),
Op: fmt.Sprintf("@%s: get", conn.at), // XXX abuse Op: fmt.Sprintf("@%s: get", conn.at), // XXX abuse
...@@ -259,7 +285,7 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (interface{}/*Py ...@@ -259,7 +285,7 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (interface{}/*Py
} }
} }
return xobj, nil return pyobj, nil
} }
...@@ -364,18 +390,18 @@ func (conn *Connection) loadpy(ctx context.Context, oid zodb.Oid) (pyclass pickl ...@@ -364,18 +390,18 @@ func (conn *Connection) loadpy(ctx context.Context, oid zodb.Oid) (pyclass pickl
} }
// path(class) -> new(pyobj) // path(class) -> new(pyobj)
var classTab = make(map[string]func(*pyObject)interface{}) var classTab = make(map[string]func(*pyObject)PyObject)
// registerClass registers python class to be transformed to Go instance // registerClass registers python class to be transformed to Go instance
// created via classNew. // created via classNew.
// //
// must be called from global init(). // must be called from global init().
func registerClass(classPath string, classNew func(*pyObject)interface{}) { func registerClass(classPath string, classNew func(*pyObject)PyObject) {
classTab[classPath] = classNew classTab[classPath] = classNew
} }
// newGhost creates new ghost object corresponding to pyclass and oid. // newGhost creates new ghost object corresponding to pyclass and oid.
func (conn *Connection) newGhost(pyclass pickle.Class, oid zodb.Oid) interface{} { func (conn *Connection) newGhost(pyclass pickle.Class, oid zodb.Oid) PyObject {
pyobj := &pyObject{ pyobj := &pyObject{
object: object{jar: conn, oid: oid, serial: 0}, object: object{jar: conn, oid: oid, serial: 0},
pyclass: pyclass, pyclass: 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