Commit 922b606d authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 94e71512
...@@ -112,7 +112,7 @@ type LiveCacheControl interface { ...@@ -112,7 +112,7 @@ type LiveCacheControl interface {
// XXX type Class string ? // XXX type Class string ?
// function representing new of a class. // function representing new of a class.
type classNewFunc func(base *PyPersistent) IPyPersistent // XXX Py -> ø type classNewFunc func(base *Persistent) IPersistent
// {} class -> new(pyobj XXX) // {} class -> new(pyobj XXX)
var classTab = make(map[string]classNewFunc) var classTab = make(map[string]classNewFunc)
...@@ -129,36 +129,36 @@ func RegisterClass(class string, classNew classNewFunc) { ...@@ -129,36 +129,36 @@ func RegisterClass(class string, classNew classNewFunc) {
// newGhost creates new ghost object corresponding to class and oid. // newGhost creates new ghost object corresponding to class and oid.
func (conn *Connection) newGhost(class string, oid Oid) IPersistent { func (conn *Connection) newGhost(class string, oid Oid) IPersistent {
pyobj := &PyPersistent{ base := &Persistent{class: class, jar: conn, oid: oid, serial: 0, state: GHOST}
Persistent: Persistent{jar: conn, oid: oid, serial: 0, state: GHOST},
pyclass: pyclass,
}
// switch on pyclass and transform e.g. "zodb.BTree.Bucket" -> *ZBucket // switch on pyclass and transform e.g. "zodb.BTree.Bucket" -> *ZBucket
classNew := classTab[class] classNew := classTab[class]
var instance IPersistent var instance IPersistent
if classNew != nil { if classNew != nil {
instance = classNew(pyobj) instance = classNew(base)
} else { } else {
instance = &Broken{PyPersistent: pyobj} instance = &Broken{Persistent: base}
} }
pyobj.instance = instance base.instance = instance
return instance return instance
} }
// Broken is used for classes that were not registered. // Broken is used for classes that were not registered.
type Broken struct { type Broken struct {
*Persistent *Persistent
pystate interface{} // XXX py -> ø ? state *mem.Buf
} }
func (b *Broken) DropState() { func (b *Broken) DropState() {
b.pystate = nil b.state.XRelease()
b.state = nil
} }
func (b *Broken) PySetState(pystate interface{}) error { func (b *Broken) SetState(state *mem.Buf) error {
b.pystate = pystate b.state.XRelease()
state.Incref()
b.state = state
return nil return nil
} }
...@@ -206,7 +206,7 @@ func (conn *Connection) get(class string, oid Oid) (IPersistent, error) { ...@@ -206,7 +206,7 @@ func (conn *Connection) get(class string, oid Oid) (IPersistent, error) {
if checkClass { if checkClass {
// XXX get obj class via reflection? // XXX get obj class via reflection?
if cls := obj.PyClass(); class != cls { if cls := obj.zclass(); class != cls {
return nil, &OpError{ return nil, &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
......
...@@ -31,6 +31,8 @@ import ( ...@@ -31,6 +31,8 @@ import (
// //
// XXX safe to access from multiple goroutines simultaneously. // XXX safe to access from multiple goroutines simultaneously.
type IPersistent interface { type IPersistent interface {
zclass() string // ZODB class of this object. XXX remove from IPersistent?
PJar() *Connection // Connection this in-RAM object is part of. PJar() *Connection // Connection this in-RAM object is part of.
POid() Oid // object ID in the database. POid() Oid // object ID in the database.
...@@ -117,6 +119,8 @@ const ( ...@@ -117,6 +119,8 @@ const (
// Persistent is common base implementation for in-RAM representation of database objects. // Persistent is common base implementation for in-RAM representation of database objects.
type Persistent struct { type Persistent struct {
class string // zodb class of this object. XXX try not to store and retrieve via reflect?
jar *Connection jar *Connection
oid Oid oid Oid
serial Tid serial Tid
...@@ -128,6 +132,7 @@ type Persistent struct { ...@@ -128,6 +132,7 @@ type Persistent struct {
loading *loadState loading *loadState
} }
func (obj *Persistent) zclass() string { return obj.class }
func (obj *Persistent) PJar() *Connection { return obj.jar } func (obj *Persistent) PJar() *Connection { return obj.jar }
func (obj *Persistent) POid() Oid { return obj.oid } func (obj *Persistent) POid() Oid { return obj.oid }
func (obj *Persistent) PSerial() Tid { return obj.serial } func (obj *Persistent) PSerial() Tid { return obj.serial }
......
...@@ -28,7 +28,7 @@ import ( ...@@ -28,7 +28,7 @@ import (
type IPyPersistent interface { type IPyPersistent interface {
IPersistent IPersistent
PyClass() pickle.Class // python class of this object //PyClass() pickle.Class // python class of this object
// PyState() interface{} // object state. python passes this to pyclass.__new__().__setstate__() // PyState() interface{} // object state. python passes this to pyclass.__new__().__setstate__()
// IPyPersistent must be stateful for persistency to work // IPyPersistent must be stateful for persistency to work
...@@ -44,7 +44,7 @@ type PyPersistent struct { ...@@ -44,7 +44,7 @@ type PyPersistent struct {
pyclass pickle.Class pyclass pickle.Class
} }
func (pyobj *PyPersistent) PyClass() pickle.Class { return pyobj.pyclass } //func (pyobj *PyPersistent) PyClass() pickle.Class { return pyobj.pyclass }
//func (pyobj *PyPersistent) PyState() interface{} { return pyobj.pystate } //func (pyobj *PyPersistent) PyState() interface{} { return pyobj.pystate }
// PyStateful is the interface describing in-RAM object whose data state can be // PyStateful is the interface describing in-RAM object whose data state can be
...@@ -75,10 +75,11 @@ func (pyobj *PyPersistent) SetState(state *mem.Buf) error { ...@@ -75,10 +75,11 @@ func (pyobj *PyPersistent) SetState(state *mem.Buf) error {
return err // XXX err ctx return err // XXX err ctx
} }
if pyclass != pyobj.pyclass { class := pyclassPath(pyclass)
if class != pyobj.class {
// complain that pyclass changed // complain that pyclass changed
// (both ref and object data use pyclass so it indeed can be different) // (both ref and object data use pyclass so it indeed can be different)
return &wrongClassError{want: pyobj.pyclass, have: pyclass} // XXX + err ctx return &wrongClassError{want: pyobj.class, have: class} // XXX + err ctx
} }
return pyobj.pyinstance().PySetState(pystate) // XXX err ctx = ok? return pyobj.pyinstance().PySetState(pystate) // XXX err ctx = ok?
...@@ -143,6 +144,12 @@ func (d *dummyPyInstance) PySetState(pystate interface{}) error { ...@@ -143,6 +144,12 @@ func (d *dummyPyInstance) PySetState(pystate interface{}) error {
// ---------------------------------------- // ----------------------------------------
// pyclassPath returns full path for a python class.
//
// for example class "ABC" in module "wendelin.lib" has its full path as "wendelin.lib.ABC".
func pyclassPath(pyclass pickle.Class) string {
return pyclass.Module + "." + pyclass.Name
}
// loadpy loads object specified by oid and decodes it as a ZODB Python object. // loadpy loads object specified by oid and decodes it as a ZODB Python object.
// //
...@@ -156,11 +163,10 @@ func (conn *Connection) loadpy(ctx context.Context, oid Oid) (class string, pyst ...@@ -156,11 +163,10 @@ func (conn *Connection) loadpy(ctx context.Context, oid Oid) (class string, pyst
defer buf.Release() defer buf.Release()
pyclass, pystate, err = PyData(buf.Data).Decode() pyclass, pystate, err := PyData(buf.Data).Decode()
if err != nil { if err != nil {
return "", nil, 0, err // XXX err ctx return "", nil, 0, err // XXX err ctx
} }
class := pyclass.Module + "." + pyclass.Name // full pyclass path return pyclassPath(pyclass), pystate, serial, nil
return class, pystate, serial, nil
} }
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