Commit fb9d0fce authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 2848c632
...@@ -24,49 +24,52 @@ import ( ...@@ -24,49 +24,52 @@ 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. // Object is the interface that every in-RAM object representing any ZODB object implements.
type Object interface { type Object interface {
Jar() *Connection PJar() *Connection
Oid() zodb.Oid POid() zodb.Oid
Serial() zodb.Tid PSerial() zodb.Tid
// XXX activate/deactivate/invalidate here? // XXX activate/deactivate/invalidate here?
} }
// PyObject is the interface that every object representing Python ZODB object implements. // PyObject is the interface that every in-RAM object representing Python ZODB object implements.
type PyObject interface { type PyObject interface {
Object Object
PyClass() pickle.Class PyClass() pickle.Class // python class of this object
// PyState? PyState() interface{} // object state. python passes this to pyclass.__new__().__setstate__()
} }
// object is common base for in-process representation of ZODB object. // object is common base for in-RAM representation of ZODB object.
type object struct { type object struct {
jar *Connection jar *Connection
oid zodb.Oid oid zodb.Oid
serial zodb.Tid serial zodb.Tid
} }
func (obj *object) Jar() *Connection { return obj.jar } func (obj *object) PJar() *Connection { return obj.jar }
func (obj *object) Oid() zodb.Oid { return obj.oid } func (obj *object) POid() zodb.Oid { return obj.oid }
func (obj *object) Serial() zodb.Tid { return obj.serial } func (obj *object) PSerial() zodb.Tid { return obj.serial }
// pyObject is common base for in-process representation of ZODB Python objects. // pyObject is common base for in-RAM representation of ZODB Python objects.
type pyObject struct { type pyObject struct {
object object
pyclass pickle.Class // python class of this object pyclass pickle.Class
pystate interface{} // object state. python passes this to pyclass.__new__().__setstate__() pystate interface{}
} }
func (pyobj *pyObject) PyClass() pickle.Class { return pyobj.pyclass } func (pyobj *pyObject) PyClass() pickle.Class { return pyobj.pyclass }
func (pyobj *pyObject) PyState() interface{} { return pyobj.pystate }
// 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.
// //
// XXX Connection changes are private and are isolated from changes in other Connections.
//
// XXX Connection, and {Py}Object methods that relate to it, are not safe for // XXX Connection, and {Py}Object methods that relate to it, are not safe for
// modifications from multiple goroutines simultaneously. // modifications from multiple goroutines simultaneously.
// //
...@@ -75,31 +78,31 @@ type Connection struct { ...@@ -75,31 +78,31 @@ type Connection struct {
stor zodb.IStorage // underlying storage stor zodb.IStorage // underlying storage
at zodb.Tid // current view of database at zodb.Tid // current view of database
// {} oid -> pyobj // {} oid -> obj
// //
// rationale: // rationale:
// //
// on invalidations: we need to go oid -> pyobj and invalidate it. // on invalidations: we need to go oid -> obj and invalidate it.
// -> Connection need to keep {} oid -> pyobj. // -> Connection need to keep {} oid -> obj.
// -> we can use that {} when loading a persistent Ref twice to get to the same object. // -> we can use that {} when loading a persistent Ref twice to get to the same object.
// //
// however: if Connection keeps strong link to pyobj, just // however: if Connection keeps strong link to obj, just
// pyobj.PDeactivate will not fully release pyobj if there are no // obj.PDeactivate will not fully release obj if there are no
// references to it from other objects: // references to it from other objects:
// //
// - deactivate will release pyobj state (ok) // - deactivate will release obj state (ok)
// - but there will be still reference from connection `oid -> pyobj` map to this object. // - but there will be still reference from connection `oid -> obj` map to this object.
// //
// -> we can solve it by using "weak" pointers in the map. // -> we can solve it by using "weak" pointers in the map.
// //
// NOTE we cannot use regular map and arbitrarily manually "gc" entries // NOTE we cannot use regular map and arbitrarily manually "gc" entries
// there periodically: since for a pyobj we don't know whether other // there periodically: since for an obj we don't know whether other
// objects are referencing it, we can't just remove pyobj's oid from // objects are referencing it, we can't just remove obj's oid from
// the map - if we do so and there are other live objects that // the map - if we do so and there are other live objects that
// reference pyobj, user code can still reach pyobj via those // reference obj, user code can still reach obj via those
// references. On the other hand, if another, not yet loaded, object // references. On the other hand, if another, not yet loaded, object
// also references pyobj and gets loaded, traversing reference from // also references obj and gets loaded, traversing reference from
// that loaded object will load second copy of pyobj, thus breaking 1 // that loaded object will load second copy of obj, thus breaking 1
// object in db <-> 1 live object invariant: // object in db <-> 1 live object invariant:
// //
// A → B → C // A → B → C
...@@ -123,8 +126,8 @@ type Connection struct { ...@@ -123,8 +126,8 @@ type Connection struct {
// NOTE2 finalizers don't run on when they are attached to an object in cycle. // 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 // Hopefully we don't have cycles with ZBtree/ZBucket XXX verify this
objmu sync.Mutex objmu sync.Mutex
objtab map[zodb.Oid]*WeakRef // oid -> WeakRef(PyObject)
//objtab map[zodb.Oid]interface{} // oid -> WeakRef(pyObject) | loadInProgress //objtab map[zodb.Oid]interface{} // oid -> WeakRef(pyObject) | loadInProgress
objtab map[zodb.Oid]*WeakRef
} }
/* /*
...@@ -144,11 +147,11 @@ type loadInProgress struct { ...@@ -144,11 +147,11 @@ type loadInProgress struct {
// If there is already in-RAM object that corresponds to oid, that in-RAM object is returned. // If there is already in-RAM object that corresponds to oid, that in-RAM object is returned.
// Otherwise new in-RAM object is created and filled with object's class loaded from the database. // Otherwise new in-RAM object is created and filled with object's class loaded from the database.
// //
// The scope of the object returned is the Connection. XXX ok?
//
// The object's data is not neccessarily loaded after Get returns. Use // The object's data is not neccessarily loaded after Get returns. Use
// PActivate to make sure the object ifs fully loaded. // PActivate to make sure the object ifs fully loaded.
func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (interface{} /*PyObject*/, error) { func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (interface{} /*PyObject*/, error) {
// XXX = load raw oid, get its class -> get(pyclass, oid)
conn.objmu.Lock() conn.objmu.Lock()
wobj := conn.objtab[oid] wobj := conn.objtab[oid]
var xobj interface{} var xobj interface{}
...@@ -179,7 +182,7 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (interface{} /*Py ...@@ -179,7 +182,7 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (interface{} /*Py
// TODO -> use (pystate, serial) to activate. // TODO -> use (pystate, serial) to activate.
_, _ = pystate, serial _, _ = pystate, serial
return xobj, nil return xobj, nil
}
/* /*
conn.objmu.Lock() // XXX -> rlock conn.objmu.Lock() // XXX -> rlock
...@@ -235,9 +238,8 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (interface{} /*Py ...@@ -235,9 +238,8 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (interface{} /*Py
conn.objtab[oid] = NewWeakRef(pyobj) conn.objtab[oid] = NewWeakRef(pyobj)
} }
*/ */
}
// wrongClassError is the error cause returned when object's class is wrong. // wrongClassError is the error cause returned when object's class is not what was expected.
type wrongClassError struct { type wrongClassError struct {
want, have pickle.Class want, have pickle.Class
} }
...@@ -254,6 +256,8 @@ func (e *wrongClassError) Error() string { ...@@ -254,6 +256,8 @@ func (e *wrongClassError) Error() string {
// The object's data is not neccessarily loaded after get returns. Use // The object's data is not neccessarily loaded after get returns. Use
// PActivate to make sure the object is fully loaded. // PActivate to make sure the object is fully loaded.
// //
// XXX object scope.
//
// 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) (PyObject, error) { func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (PyObject, error) {
......
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