Commit a65f9492 authored by Kirill Smelkov's avatar Kirill Smelkov

.

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