Commit 7757f824 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 9c1b50a6
......@@ -110,14 +110,25 @@ type LiveCacheControl interface {
// ---- class <-> type; new ghost ----
var class2Type = make(map[string]reflect.Type) // {} class -> (type, stateType)
var type2Class = make(map[reflect.Type]string) // {} type -> (class, stateType)
// zclass describes one ZODB class in relation to Go type.
type zclass struct {
class string
typ reflect.Type // application go type corresponding to class
stateType reflect.Type // *typ and *stateType are convertible; *stateType provides Statufl & co.
}
var classTab = make(map[string]*zclass) // {} class -> zclass
var typeTab = make(map[reflect.Type]*zclass) // {} type -> zclass
// zclassOf returns ZODB class of a Go object.
//
// If ZODB class was not registered for obj's type, "" is returned.
func zclassOf(obj IPersistent) string {
return type2Class[reflect.TypeOf(obj)]
zc, ok := typeTab[reflect.TypeOf(obj)]
if !ok {
return ""
}
return zc.class
}
var rIPersistent = reflect.TypeOf((*IPersistent)(nil)).Elem() // typeof(IPersistent)
......@@ -133,7 +144,7 @@ var rPyStateful = reflect.TypeOf((*PyStateful)(nil)).Elem() // typeof(PyStatef
// typ must be convertible to stateType; stateType must implement Ghostable and
// either Stateful or PyStateful(*)
//
// Must be called from global init().
// RegisterClass must be called from global init().
//
// (*) the rationale for stateType coming separately is that this way for
// application types it is possible not to expose Ghostable and Stateful
......@@ -147,8 +158,8 @@ func RegisterClass(class string, typ, stateType reflect.Type) {
if class == "" {
badf("class must be not empty")
}
if typ, already := class2Type[class]; already {
badf("class already registered for %q", typ)
if zc, already := classTab[class]; already {
badf("class already registered for %q", zc.typ)
}
// typ must have IPersistent embedded
......@@ -183,8 +194,9 @@ func RegisterClass(class string, typ, stateType reflect.Type) {
// XXX check if class was already registered
// XXX check class != ""
class2Type[class] = typ
type2Class[typ] = class
zc := &zclass{class: class, typ: typ, stateType: stateType}
classTab[class] = zc
typeTab[typ] = zc
}
......@@ -192,11 +204,11 @@ func RegisterClass(class string, typ, stateType reflect.Type) {
func (conn *Connection) newGhost(class string, oid Oid) IPersistent {
// switch on class and transform e.g. "zodb.BTree.Bucket" -> btree.Bucket
var xpobj reflect.Value // *typ
typ := class2Type[class]
if typ == nil {
zc := classTab[class]
if zc == nil {
xpobj = reflect.ValueOf(&Broken{class: class})
} else {
xpobj = reflect.New(typ)
xpobj = reflect.New(zc.typ)
}
base := &Persistent{jar: conn, oid: oid, serial: 0, state: GHOST}
......@@ -216,12 +228,14 @@ type Broken struct {
state *mem.Buf
}
func (b *Broken) DropState() {
type brokenState Broken
func (b *brokenState) DropState() {
b.state.XRelease()
b.state = nil
}
func (b *Broken) SetState(state *mem.Buf) error {
func (b *brokenState) SetState(state *mem.Buf) error {
b.state.XRelease()
state.Incref()
b.state = state
......
......@@ -110,7 +110,10 @@ const (
// no STICKY - we pin objects in RAM with PActivate
)
// Persistent is common base implementation for in-RAM representation of database objects.
// Persistent is common base IPersistent implementation for in-RAM
// representation of database objects.
//
// XXX it requires it to embed and provide Ghostable + Stateful.
type Persistent struct {
jar *Connection
oid Oid
......@@ -119,7 +122,10 @@ type Persistent struct {
mu sync.Mutex
state ObjectState
refcnt int32
instance interface{IPersistent; Ghostable; Stateful} // Persistent should be the base for the instance
// Persistent should be the base for the instance.
// instance is additionally either Stateful | PyStateful.
instance interface{IPersistent; Ghostable} // XXX Ghostable also not good here
loading *loadState
}
......@@ -203,7 +209,18 @@ func (obj *Persistent) PActivate(ctx context.Context) (err error) {
// try to pass loaded state to object
if err == nil {
err = obj.instance.SetState(state) // XXX err ctx
// XXX wrong: obj.instance is not Stateful (not to show it to public API)
switch inst := obj.instance.(type) {
case Stateful:
err = inst.SetState(state) // XXX err ctx
case PyStateful:
err = pySetState(inst, state) // XXX err ctx
default:
panic("!stateful instance")
}
state.Release()
if err == nil {
obj.state = UPTODATE
......
......@@ -24,14 +24,6 @@ import (
pickle "github.com/kisielk/og-rek"
)
// PyPersistent is common base implementation for in-RAM representation of ZODB Python objects.
type PyPersistent struct {
Persistent
}
//func (pyobj *PyPersistent) PyClass() pickle.Class { return pyobj.pyclass }
//func (pyobj *PyPersistent) PyState() interface{} { return pyobj.pystate }
// PyStateful is the interface describing in-RAM object whose data state can be
// exchanged as Python data.
type PyStateful interface {
......@@ -44,24 +36,15 @@ type PyStateful interface {
//PyGetState() interface{} TODO
}
// ---- PyPersistent <-> Persistent state exchange ----
// pyinstance returns .instance upcasted to XXXPy.
//
// this should be always safe because we always create pyObjects via
// newGhost which passes IPyPersistent as instance to IPersistent. XXX no longer true
func (pyobj *PyPersistent) pyinstance() interface {IPersistent; Ghostable; PyStateful} {
return pyobj.instance.(interface {IPersistent; Ghostable; PyStateful})
}
func (pyobj *PyPersistent) SetState(state *mem.Buf) error {
// pySetState decodes raw state as zodb/py serialized stream, and sets decoded
// state on PyStateful obj.
func pySetState(obj PyStateful, state *mem.Buf) error {
pyclass, pystate, err := PyData(state.Data).Decode()
if err != nil {
return err // XXX err ctx
}
class := pyclassPath(pyclass)
obj := pyobj.pyinstance()
if objClass := zclassOf(obj); class != objClass {
// complain that pyclass changed
......
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