Commit f0931de9 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 0f146bcb
......@@ -243,6 +243,6 @@ func btreeNew(pyobj *pyObject) PyObject {
}
func init() {
registerClass("zodb.BTree.LOBucket", bucketNew)
registerClass("zodb.BTree.LOBtree", btreeNew)
registerPyClass("zodb.BTree.LOBucket", bucketNew)
registerPyClass("zodb.BTree.LOBtree", btreeNew)
}
package main
/*
// loadInProgress entry in Conn.objtab tells users, that try to get the entry,
// that another goroutine is already in progress of loading it.
type loadInProgress struct {
ready chan struct{} // closed when loading finishes
// result of the load
pyobj interface{} // XXX -> pyObject iface
err error
}
// XXX -> pyObject.SetState
/*
pyclass, pystate, serial, err := pyobj.jar.loadpy(ctx, pyobj.oid)
if err == nil && pyclass != pyobj.pyclass {
// complain pyclass changed
// (both ref and object data uses pyclass so it indeed can be different)
err = &wrongClassError{want: pyobj.pyclass, have: pyclass} // XXX + err ctx
pystate = nil
}
*/
/*
conn.objmu.Lock() // XXX -> rlock
objentry := conn.objtab[oid]
......@@ -122,32 +123,3 @@ type loadInProgress struct {
}
}
*/
/*
// XXX -> loadpy
buf, serial, err := conn.stor.Load(ctx, zodb.Xid{Oid: oid, At: conn.at})
if err != nil {
return nil, err
}
pyclass, pystate, err := zodb.PyData(buf.Data).Decode()
if err != nil {
return nil, err // XXX err ctx
}
buf.Release()
return &pyObject{
object: object{jar: conn,oid: oid, serial: serial},
pyclass: pyclass,
pystate: pystate,
}, nil
}
*/
/*
func (conn *Connection) load(ctx context.Context, oid zodb.Oid) (*pyObject, error) {
// XXX
}
*/
......@@ -165,5 +165,5 @@ func zbigfileNew(pyobj *pyObject) PyObject {
}
func init() {
registerClass(zwendelin + ".ZBigFile", zbigfileNew)
registerPyClass(zwendelin + ".ZBigFile", zbigfileNew)
}
......@@ -20,6 +20,7 @@ import (
"sync"
// "sync/atomic"
"lab.nexedi.com/kirr/go123/mem"
"lab.nexedi.com/kirr/neo/go/zodb"
pickle "github.com/kisielk/og-rek"
......@@ -115,9 +116,11 @@ type object struct {
oid zodb.Oid
serial zodb.Tid
mu sync.Mutex
state ObjectState
refcnt int32
mu sync.Mutex
state ObjectState
refcnt int32
instance Stateful
loading *loadState
}
func (obj *object) PJar() *Connection { return obj.jar }
......@@ -129,9 +132,9 @@ type pyObject struct {
object
pyclass pickle.Class
// protected by object.mu
instance PyStateful
loading *loadState
// // protected by object.mu
// instance PyStateful
// loading *loadState
}
func (pyobj *pyObject) PyClass() pickle.Class { return pyobj.pyclass }
......@@ -149,16 +152,26 @@ type loadState struct {
err error
}
// XXX
// Stateful is the interface describing in-RAM object whose data stat can be
// exchanged as raw bytes.
type Stateful interface {
// DropState should discard in-RAM object state.
// XXX move out of Stateful?
DropState()
// SetState should set state of the in-RAM object from raw data.
//
// SetState must incref state buffer, if it needs the buffer to stay dedicated XXX
SetState(state *mem.Buf) error
// GetState should return state of the in-RAM object as raw data.
//GetState() *mem.Buf
}
// PyStateful is the interface describing in-RAM object whose data state can be
// exchanged as Python data.
type PyStateful interface {
Stateful
//Stateful XXX no need here?
// PySetState should set state of the in-RAM object from Python data.
// Analog of __setstate__() in Python.
......@@ -260,7 +273,7 @@ type LiveCacheControl interface {
//
// 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) {
func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (PyObject, error) {
conn.objmu.Lock() // XXX -> rlock
wobj := conn.objtab[oid]
var xobj interface{}
......@@ -271,7 +284,7 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (interface{} /*Py
// object was already there in objtab.
if xobj != nil {
return xobj, nil
return xobj.(PyObject), nil
}
// object is not there in objtab - raw load it, get its class -> get(pyclass, oid)
......@@ -280,7 +293,7 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (interface{} /*Py
return nil, err // XXX errctx
}
xobj, err = conn.get(pyclass, oid)
obj, err := conn.get(pyclass, oid)
if err != nil {
return nil, err
}
......@@ -290,7 +303,7 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (interface{} /*Py
//
// TODO -> use (pystate, serial) to activate.
_, _ = pystate, serial
return xobj, nil
return obj, nil
}
......@@ -370,15 +383,15 @@ func (conn *Connection) loadpy(ctx context.Context, oid zodb.Oid) (pyclass pickl
// ---- pyclass -> new ghost ----
// path(class) -> new(pyobj)
var classTab = make(map[string]func(*pyObject)PyObject)
// path(pyclass) -> new(pyobj)
var classTab = make(map[string]func(base *pyObject)PyObject)
// registerClass registers python class to be transformed to Go instance
// registerPyClass registers python class to be transformed to Go instance
// created via classNew.
//
// must be called from global init().
func registerClass(classPath string, classNew func(*pyObject)PyObject) {
classTab[classPath] = classNew
func registerPyClass(pyClassPath string, classNew func(base *pyObject)PyObject) {
classTab[pyClassPath] = classNew
}
// newGhost creates new ghost object corresponding to pyclass and oid.
......@@ -420,7 +433,9 @@ func (d *dummyPyInstance) PySetState(pystate interface{}) error {
// ----------------------------------------
// object's activate & friends that only manage base activation state, without actually loading data.
// XXX ^^^ still relevant?
/*
// activate increments object reference counter.
//
// it returns whether object data needs to be loaded.
......@@ -430,16 +445,8 @@ func (d *dummyPyInstance) PySetState(pystate interface{}) error {
func (obj *object) activate() (load bool) {
obj.refcnt++
return (obj.refcnt == 1 && obj.state == GHOST)
/*
nuse := atomic.AddInt32(&obj.refcnt, +1)
if nuse == 1 {
// we become responsible for loading object's data.
// XXX also check state (it could be already loaded, but with refcnt=0)
return true
}
return false
*/
}
*/
// deactivate decrements object reference counter.
//
......@@ -490,23 +497,24 @@ func (obj *object) invalidate() {
// PActivate implements Object.
func (pyobj *pyObject) PActivate(ctx context.Context) (err error) {
pyobj.mu.Lock()
doload := pyobj.activate()
func (obj *object) PActivate(ctx context.Context) (err error) {
obj.mu.Lock()
ob.refcnt++
doload := (obj.refcnt == 1 && obj.state == GHOST)
defer func() {
if err != nil {
// no need to check for drop - the state is already
// dropped - we just need to decref here.
//
// XXX locking
pyobj.deactivate() // XXX -> drop?
obj.deactivate() // XXX -> drop?
}
}()
if !doload {
// someone else is already activated/activating the object.
// wait for its loading to complete and we are done.
loading := pyobj.loading
pyobj.mu.Unlock()
loading := obj.loading
obj.mu.Unlock()
select {
case <-ctx.Done():
......@@ -518,18 +526,18 @@ func (pyobj *pyObject) PActivate(ctx context.Context) (err error) {
// we become responsible for loading the object
loading := &loadState{ready: make(chan struct{})}
pyobj.loading = loading // XXX assert before it was = nil ?
pyobj.mu.Unlock()
obj.loading = loading // XXX assert before it was = nil ?
obj.mu.Unlock()
// do the loading outside of pyobj lock
pyclass, pystate, serial, err := pyobj.jar.loadpy(ctx, pyobj.oid)
if err == nil && pyclass != pyobj.pyclass {
// complain pyclass changed
// (both ref and object data uses pyclass so it indeed can be different)
err = &wrongClassError{want: pyobj.pyclass, have: pyclass} // XXX + err ctx
pystate = nil
// do the loading outside of obj lock
buf, serial, err := obj.jar.load(ctx, obj.oid)
if err == nil {
err = obj.instance.SetState(buf) // XXX err ctx
buf.Release()
}
// relock the object
pyobj.mu.Lock()
......
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