Commit 7be36e9e authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent a19787b9
......@@ -36,7 +36,7 @@ type KEY int64
// are chained together via 'next', so that the entire BTree contents
// can be traversed in sorted order quickly and easily.
type ZBucket struct {
pyobj *PyObject
pyobj *pyObject
next *ZBucket // the bucket with the next-larger keys
keys []KEY // 'len' keys, in increasing order
......@@ -54,7 +54,7 @@ type zBTreeItem struct {
// See https://github.com/zopefoundation/BTrees/blob/4.5.0-1-gc8bf24e/BTrees/Development.txt#L198
// for details.
type ZBTree struct {
pyobj *PyObject
pyobj *pyObject
// firstbucket points to the bucket containing the smallest key in
// the BTree. This is found by traversing leftmost child pointers
......@@ -239,11 +239,11 @@ func (b *ZBucket) PActivate(ctx context.Context) error {
// ----------------------------------------
func bucketNew(pyobj *PyObject) interface{} {
func bucketNew(pyobj *pyObject) interface{} {
return &ZBucket{pyobj: pyobj}
}
func btreeNew(pyobj *PyObject) interface{} {
func btreeNew(pyobj *pyObject) interface{} {
return &ZBTree{pyobj: pyobj}
}
......
......@@ -39,7 +39,7 @@ import (
// ZBigFile mimics ZBigFile from python.
type ZBigFile struct {
pyobj *PyObject
pyobj *pyObject
blksize int64
blktab *ZBTree // LOBtree{} blk -> ZBlk*(blkdata)
......
......@@ -16,6 +16,7 @@ package main
import (
"context"
"fmt"
"sync"
"lab.nexedi.com/kirr/neo/go/zodb"
......@@ -23,16 +24,16 @@ import (
pickle "github.com/kisielk/og-rek"
)
// Object is common base for in-process representation of ZODB object.
type Object struct {
// object is common base for in-process representation of ZODB object.
type object struct {
jar *Connection
oid zodb.Oid
serial zodb.Tid
}
// PyObject is common base for in-process representation of ZODB Python objects.
type PyObject struct {
Object
// pyObject is common base for in-process representation of ZODB Python objects.
type pyObject struct {
object
pyclass pickle.Class // python class of this object
pystate interface{} // object state. python passes this to pyclass.__new__().__setstate__()
......@@ -98,7 +99,7 @@ type Connection struct {
// NOTE2 finalizers don't run on when they are attached to an object in cycle.
// Hopefully we don't have cycles with ZBtree/ZBucket XXX verify this
objmu sync.Mutex
//objtab map[zodb.Oid]interface{} // oid -> WeakRef(PyObject) | loadInProgress
//objtab map[zodb.Oid]interface{} // oid -> WeakRef(pyObject) | loadInProgress
objtab map[zodb.Oid]*WeakRef
}
......@@ -109,7 +110,7 @@ type loadInProgress struct {
ready chan struct{} // closed when loading finishes
// result of the load
pyobj interface{} // XXX -> PyObject iface
pyobj interface{} // XXX -> pyObject iface
err error
}
*/
......@@ -143,7 +144,10 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (interface{} /*Py
return nil, err // XXX errctx
}
xobj = conn.get(pyclass, oid)
xobj, err = conn.get(pyclass, oid)
if err != nil {
return nil, err
}
// XXX we are dropping just loaded pystate. Usually Get should be used
// to only load root object, so maybe that is ok.
......@@ -209,6 +213,15 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (interface{} /*Py
*/
}
// wrongClassError is the error cause returned when object's class is wrong.
type wrongClassError struct {
want, have pickle.Class
}
func (e *wrongClassError) Error() string {
return fmt.Sprintf("wrong class: want %q; have %q", e.want, e.have)
}
// get returns in-RAM object corresponding to specified ZODB object according to current database view.
//
// If there is already in-RAM object that corresponds to oid, that in-RAM object is returned.
......@@ -219,20 +232,34 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (interface{} /*Py
//
// use-case: in ZODB references are (pyclass, oid), so new ghost is created
// without further loading anything.
func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) interface{}/*PyObject*/ {
func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (interface{}/*PyObject*/, error) {
conn.objmu.Lock() // XXX -> rlock
wobj := conn.objtab[oid]
var xobj interface{}
checkClass := false
if wobj != nil {
xobj = wobj.Get()
// XXX check pyclass match.
}
if xobj == nil {
xobj = conn.newGhost(pyclass, oid)
conn.objtab[oid] = NewWeakRef(xobj)
} else {
checkClass = true
}
conn.objmu.Unlock()
return xobj
if checkClass {
if cls := xobj.PyClass(); pyclass != cls {
return nil, &zodb.OpError{
URL: conn.stor.URL(),
Op: fmt.Sprintf("@%s: get", conn.at), // XXX abuse
Args: oid,
Err: &wrongClassError{pyclass, cls},
}
}
}
return xobj, nil
}
......@@ -306,8 +333,8 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) interface{}/*PyO
buf.Release()
return &PyObject{
Object: Object{jar: conn,oid: oid, serial: serial},
return &pyObject{
object: object{jar: conn,oid: oid, serial: serial},
pyclass: pyclass,
pystate: pystate,
}, nil
......@@ -315,7 +342,7 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) interface{}/*PyO
*/
/*
func (conn *Connection) load(ctx context.Context, oid zodb.Oid) (*PyObject, error) {
func (conn *Connection) load(ctx context.Context, oid zodb.Oid) (*pyObject, error) {
// XXX
}
*/
......@@ -337,20 +364,20 @@ func (conn *Connection) loadpy(ctx context.Context, oid zodb.Oid) (pyclass pickl
}
// path(class) -> new(pyobj)
var classTab = make(map[string]func(*PyObject)interface{})
var classTab = make(map[string]func(*pyObject)interface{})
// registerClass registers python class to be transformed to Go instance
// created via classNew.
//
// must be called from global init().
func registerClass(classPath string, classNew func(*PyObject)interface{}) {
func registerClass(classPath string, classNew func(*pyObject)interface{}) {
classTab[classPath] = classNew
}
// newGhost creates new ghost object corresponding to pyclass and oid.
func (conn *Connection) newGhost(pyclass pickle.Class, oid zodb.Oid) interface{} {
pyobj := &PyObject{
Object: Object{jar: conn, oid: oid, serial: 0},
pyobj := &pyObject{
object: object{jar: conn, oid: oid, serial: 0},
pyclass: pyclass,
pystate: nil,
}
......@@ -370,7 +397,7 @@ func (conn *Connection) newGhost(pyclass pickle.Class, oid zodb.Oid) interface{}
// PDeactivates transforms object to ghost state.
//
// In ghost state object data is dropped and only oid/pyclass information is left in RAM.
func (pyobj *PyObject) PDeactivate() {
func (pyobj *pyObject) PDeactivate() {
// FIXME if state=modified PDeactivate must be noop.
pyobj.pystate = nil
......@@ -380,7 +407,7 @@ func (pyobj *PyObject) PDeactivate() {
// PActivate brings object to live state.
//
// If object state is not in RAM - it is loaded from the database.
func (pyobj *PyObject) PActivate(ctx context.Context) error {
func (pyobj *pyObject) PActivate(ctx context.Context) error {
if pyobj.pystate != nil {
return nil // already loaded
}
......
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