Commit fb9d0fce authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 2848c632
......@@ -24,49 +24,52 @@ import (
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 {
Jar() *Connection
Oid() zodb.Oid
Serial() zodb.Tid
PJar() *Connection
POid() zodb.Oid
PSerial() zodb.Tid
// 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 {
Object
PyClass() pickle.Class
// PyState?
PyClass() pickle.Class // python class of this object
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 {
jar *Connection
oid zodb.Oid
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 }
func (obj *object) PJar() *Connection { return obj.jar }
func (obj *object) POid() zodb.Oid { return obj.oid }
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 {
object
pyclass pickle.Class // python class of this object
pystate interface{} // object state. python passes this to pyclass.__new__().__setstate__()
pyclass pickle.Class
pystate interface{}
}
func (pyobj *pyObject) PyClass() pickle.Class { return pyobj.pyclass }
func (pyobj *pyObject) PyState() interface{} { return pyobj.pystate }
// Connection represents a view of ZODB database.
//
// 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
// modifications from multiple goroutines simultaneously.
//
......@@ -75,31 +78,31 @@ type Connection struct {
stor zodb.IStorage // underlying storage
at zodb.Tid // current view of database
// {} oid -> pyobj
// {} oid -> obj
//
// rationale:
//
// on invalidations: we need to go oid -> pyobj and invalidate it.
// -> Connection need to keep {} oid -> pyobj.
// on invalidations: we need to go oid -> obj and invalidate it.
// -> Connection need to keep {} oid -> obj.
// -> 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
// pyobj.PDeactivate will not fully release pyobj if there are no
// however: if Connection keeps strong link to obj, just
// obj.PDeactivate will not fully release obj if there are no
// references to it from other objects:
//
// - deactivate will release pyobj state (ok)
// - but there will be still reference from connection `oid -> pyobj` map to this object.
// - deactivate will release obj state (ok)
// - 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.
//
// NOTE we cannot use regular map and arbitrarily manually "gc" entries
// there periodically: since for a pyobj we don't know whether other
// objects are referencing it, we can't just remove pyobj's oid from
// there periodically: since for an obj we don't know whether other
// 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
// 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
// also references pyobj and gets loaded, traversing reference from
// that loaded object will load second copy of pyobj, thus breaking 1
// also references obj and gets loaded, traversing reference from
// that loaded object will load second copy of obj, thus breaking 1
// object in db <-> 1 live object invariant:
//
// A → B → C
......@@ -123,8 +126,8 @@ 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]*WeakRef // oid -> WeakRef(PyObject)
//objtab map[zodb.Oid]interface{} // oid -> WeakRef(pyObject) | loadInProgress
objtab map[zodb.Oid]*WeakRef
}
/*
......@@ -144,11 +147,11 @@ type loadInProgress struct {
// 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.
//
// The scope of the object returned is the Connection. XXX ok?
//
// The object's data is not neccessarily loaded after Get returns. Use
// PActivate to make sure the object ifs fully loaded.
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()
wobj := conn.objtab[oid]
var xobj interface{}
......@@ -179,7 +182,7 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (interface{} /*Py
// TODO -> use (pystate, serial) to activate.
_, _ = pystate, serial
return xobj, nil
}
/*
conn.objmu.Lock() // XXX -> rlock
......@@ -235,9 +238,8 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (interface{} /*Py
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 {
want, have pickle.Class
}
......@@ -254,6 +256,8 @@ func (e *wrongClassError) Error() string {
// The object's data is not neccessarily loaded after get returns. Use
// 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
// without further loading anything.
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