Commit f0931de9 authored by Kirill Smelkov's avatar Kirill Smelkov

.

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