Commit a65f9492 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 7b2dca36
......@@ -126,6 +126,11 @@ func (b *ZBucket) get(key KEY) (interface{}, bool) {
return b.values[i], true
}
// XXX ZBucket.MinKey ?
// XXX ZBucket.MaxKey ?
// ---- serialization ----
// from https://github.com/zopefoundation/BTrees/blob/4.5.0-1-gc8bf24e/BTrees/BTreeTemplate.c#L1087:
//
......@@ -153,22 +158,18 @@ func (b *ZBucket) get(key KEY) (interface{}, bool) {
//
// In the above, key[i] means self->data[i].key, and similarly for child[i].
func (t *ZBTree) PDeactivate() {
// XXX check if activated?
// DropState implements Stateful.
func (t *ZBTree) DropState() {
t.firstbucket = nil
t.data = nil
t.pyObject.PDeactivate()
}
func (t *ZBTree) PActivate(ctx context.Context) error {
// PySetState implements PyStateful to set btree data from pystate.
func (t *ZBTree) PySetState(pystate interface{}) error {
panic("TODO")
}
// XXX ZBucket.MinKey ?
// XXX ZBucket.MaxKey ?
// from https://github.com/zopefoundation/BTrees/blob/4.5.0-1-gc8bf24e/BTrees/BucketTemplate.c#L1195:
//
// For a mapping bucket (self->values is not NULL), a one-tuple or two-tuple.
......@@ -182,41 +183,16 @@ func (t *ZBTree) PActivate(ctx context.Context) error {
// <self->next iff non-NULL>
// )
// PDeactivate implements Object.
func (b *ZBucket) PDeactivate() {
// XXX check if activated
// b.pyObject.PDeactivate() ...
// DropState implements Stateful to discard bucket state.
func (b *ZBucket) DropState() {
b.next = nil
b.keys = nil
b.values = nil
b.pyObject.PDeactivate()
}
// PActivate implements Object.
func (b *ZBucket) PActivate(ctx context.Context) (bool, error) {
activated, err := b.pyObject.PActivate(ctx)
if err != nil {
return err
}
if !activated {
return false, nil
}
// FIXME other users must wait for first decode to complete
err = b.decode()
if err != nil {
b.pyObject.PDeactivate()
return false, err
}
return true, nil
}
func (b *ZBucket) decode() error {
t, ok := b.pyObject.pystate.(pickle.Tuple)
// PySetState implements PyStateful to set bucket data from pystate.
func (b *ZBucket) PySetState(pystate interface{}) error {
t, ok := pystate.(pickle.Tuple)
if !ok || !(1 <= len(t) && len(t) <= 2) {
// XXX complain
}
......@@ -256,7 +232,7 @@ func (b *ZBucket) decode() error {
}
// ----------------------------------------
// ---- register classes to ZODB ----
func bucketNew(pyobj *pyObject) PyObject {
return &ZBucket{pyObject: pyobj}
......
......@@ -468,7 +468,7 @@ func (bf *BigFile) Read(_ nodefs.File, dest []byte, off int64, _ fuse.Context) (
// TODO set it to Connection.CacheControl
type zodbCacheControl struct {}
func (cc *zodbCacheControl) WantEvict(obj Object) {
func (cc *zodbCacheControl) WantEvict(obj Object) bool {
switch obj.(type) {
default:
return true
......
......@@ -94,19 +94,16 @@ func (conn *zpyconn) loadZBigFile(ctx context.Context, oid zodb.Oid) (*ZBigFile,
*/
func (bf *ZBigFile) PDeactivate() {
if bf.blktab == nil {
return
}
// DropState implements Stateful.
func (bf *ZBigFile) DropState() {
bf.blksize = -1
bf.blktab = nil
bf.pyObject.PDeactivate()
}
func (bf *ZBigFile) PySetState(pystate interface{}) (err error) {
panic("TODO")
/* XXX reenable (pickletools)
func (bf *ZBigFile) PActivate(ctx context.Context) (err error) {
if bf.blktab != nil {
return nil
}
......@@ -137,8 +134,8 @@ func (bf *ZBigFile) PActivate(ctx context.Context) (err error) {
bf.blksize = blksize
bf.blktab = blktab
return nil
}
*/
}
// XXX -> newGhost
......
......@@ -48,7 +48,7 @@ type Object interface {
//
// Object data must be accessed only after corresponding PActivate
// call, which marks that object's data as being in use.
PActivate(ctx context.Context) (activated bool, _ error) // XXX ret semantics?
PActivate(ctx context.Context) error
// PDeactivate indicates that corresponding PActivate caller finished access to object's data.
//
......@@ -63,7 +63,7 @@ type Object interface {
//
// Besides exotic cases, the caller thus must not use object's data
// after PDeactivate call.
PDeactivate() // XXX + -> nuse ?
PDeactivate()
// PInvalidate requests in-RAM object data to be discarded.
//
......@@ -86,16 +86,36 @@ type Object interface {
PInvalidate()
}
// XXX
type Stateful interface {
// XXX
DropState()
}
// PyObject is the interface that every in-RAM object representing Python ZODB object implements.
type PyObject interface {
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__()
PyStateful
}
// XXX
type PyStateful interface {
Stateful
// PySetState should set Python state of the in-RAM object.
// Analog of __setstate__() in Python.
PySetState(pystate interface{}) error
// PyGetState should return Python state of in-RAM object.
// Analog of __getstate__() in Python.
//PyGetState() interface{} XXX
}
// object is common base for in-RAM representation of ZODB objects.
// object is common base for in-RAM implementations of ZODB objects.
type object struct {
jar *Connection
oid zodb.Oid
......@@ -108,18 +128,19 @@ 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-RAM representation of ZODB Python objects.
// pyObject is common base for in-RAM implementations of ZODB Python objects.
type pyObject struct {
object
pyclass pickle.Class
pystate interface{}
loaderr error // if there was error at state loading
ready chan struct{} // activation complete
pyclass pickle.Class
// pystate interface{}
instance PyStateful
loaderr error // if there was error at state loading
ready chan struct{} // activation complete
}
func (pyobj *pyObject) PyClass() pickle.Class { return pyobj.pyclass }
func (pyobj *pyObject) PyState() interface{} { return pyobj.pystate }
//func (pyobj *pyObject) PyState() interface{} { return pyobj.pystate }
// Connection represents a view of ZODB database.
......@@ -338,7 +359,7 @@ func (conn *Connection) newGhost(pyclass pickle.Class, oid zodb.Oid) PyObject {
pyobj := &pyObject{
object: object{jar: conn, oid: oid, serial: 0},
pyclass: pyclass,
pystate: nil,
//instance: nil,
}
// switch on pyclass and transform e.g. "zodb.BTree.Bucket" -> *ZBucket
......@@ -347,7 +368,9 @@ func (conn *Connection) newGhost(pyclass pickle.Class, oid zodb.Oid) PyObject {
return pyobj // XXX or return error here?
}
return classNew(pyobj)
obj := classNew(pyobj)
pyobj.instance = obj
return obj
}
......@@ -368,14 +391,18 @@ func (obj *object) PDeactivate() {
// object's pactivate & friends that only manage base activation state, without actually loading data.
func (obj *object) pactivate(ctx context.Context) error {
// XXX -> incref ?
func (obj *object) pactivate() (load bool) {
nuse := atomic.AddInt32(&obj.refcnt, +1)
if nuse == 1 {
// we become responsible for loading object's data.
// XXX check state
// XXX also check state (it could be already loaded, but with refcnt=0)
return true
}
return false
}
// XXX -> decref ?
func (obj *object) pdeactivate() (drop bool) {
nuse := atomic.AddInt32(&obj.refcnt, -1)
if nuse < 0 {
......@@ -389,14 +416,16 @@ func (obj *object) pdeactivate() (drop bool) {
// TODO state=modified -> don't drop.
drop = true
// XXX -> pyObject?
if drop {
if cc := obj.jar.cacheControl; cc != nil {
drop = cc.WantEvict(obj)
drop = cc.WantEvict(obj.instance)
}
}
if drop {
obj.serial = 0
//obj.insance.DropState()
}
return drop
......@@ -404,16 +433,23 @@ func (obj *object) pdeactivate() (drop bool) {
// PActivate implements Object.
func (pyobj *pyObject) PActivate(ctx context.Context) (bool, error) {
func (pyobj *pyObject) PActivate(ctx context.Context) (err error) {
load := pyobj.object.pactivate()
defer func() {
if err != nil {
// no need to check for drop - the state is already
// dropped - we just need to decref here.
pyobj.object.pdeactivate()
}
}()
if !load {
// someone else is already activated/activating the object.
// wait for its loading to complete and we are done.
select {
case <-ctx.Done:
return false, ctx.Err() // XXX err ctx
case <-ctx.Done():
return ctx.Err() // XXX err ctx
case <-pyobj.ready:
return (pyobj.loaderr == nil), pyobj.loaderr // XXX err ctx?
return pyobj.loaderr // XXX err ctx?
}
}
......@@ -427,10 +463,19 @@ func (pyobj *pyObject) PActivate(ctx context.Context) (bool, error) {
}
pyobj.serial = serial
pyobj.pystate = pystate
// pyobj.pystate = pystate
if err == nil {
err = pyobj.instance.PySetState(pystate) // XXX err ctx
}
if err != nil {
pyobj.instance.DropState()
}
pyobj.loaderr = err
close(pyobj.ready)
return true, err // XXX err ctx
return err // XXX err ctx
}
......@@ -443,12 +488,16 @@ func (pyobj *pyObject) PDeactivate() {
// we have to drop pyobject state
// XXX locking?
pyobj.pystate = nil
// pyobj.pystate = nil
pyobj.instance.DropState()
pyobj.loaderr = nil
pyobj.ready = make(chan struct{})
return drop
}
// XXX pyobj.PInvalidate() = deactivate without checking if state != modified
// XXX panic if refcnt != 0 (object being used)
func (pyobj *pyObject) PInvalidate() {
// XXX panic if refcnt != 0 (object being used)
pyobj.instance.DropState()
pyobj.loaderr = nil
pyobj.ready = make(chan struct{})
}
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