Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
W
wendelin.core
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
Kirill Smelkov
wendelin.core
Commits
f532e0f2
Commit
f532e0f2
authored
Jul 17, 2018
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
9605b703
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
97 additions
and
55 deletions
+97
-55
wcfs/zodb.go
wcfs/zodb.go
+97
-55
No files found.
wcfs/zodb.go
View file @
f532e0f2
...
@@ -86,12 +86,6 @@ type Object interface {
...
@@ -86,12 +86,6 @@ 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
...
@@ -99,21 +93,21 @@ type PyObject interface {
...
@@ -99,21 +93,21 @@ type PyObject interface {
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 want to hide from PyObject. Rationale: we do not want e.g. PySetState to
// be available to user who holds PyObject interface: it is confusing to have
// both PActivate and PySetState at the same time.
// PyStateful
}
}
// XXX
// ObjectState describe state of in-RAM object.
type
PyStateful
interface
{
type
ObjectState
int
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.
const
(
// Analog of __getstate__() in Python.
GHOST
ObjectState
=
-
1
//PyGetState() interface{} XXX
UPTODATE
=
0
}
CHANGED
=
1
// no STICKY - we pin objects in RAM with PActivate
)
// object is common base for in-RAM implementations of ZODB objects.
// object is common base for in-RAM implementations of ZODB objects.
type
object
struct
{
type
object
struct
{
...
@@ -121,6 +115,8 @@ type object struct {
...
@@ -121,6 +115,8 @@ type object struct {
oid
zodb
.
Oid
oid
zodb
.
Oid
serial
zodb
.
Tid
serial
zodb
.
Tid
mu
sync
.
Mutex
state
ObjectState
refcnt
int32
refcnt
int32
}
}
...
@@ -131,17 +127,50 @@ func (obj *object) PSerial() zodb.Tid { return obj.serial }
...
@@ -131,17 +127,50 @@ func (obj *object) PSerial() zodb.Tid { return obj.serial }
// pyObject is common base for in-RAM implementations 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
// protected by object.mu
// pystate interface{}
instance
PyStateful
instance
PyStateful
loaderr
error
// if there was error at state loading
loaded
*
loaded
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 }
// loaded indicates object's load state/result.
//
// when !ready the loading is in progress.
// when ready the loading has been completed.
type
loaded
struct
{
ready
chan
struct
{}
// closed when loading finishes
// error from the load.
// if there was no error loaded data goes to object state.
err
error
}
// XXX
type
Stateful
interface
{
// DropState should discard in-RAM object state.
DropState
()
}
// PyStateful is the interface describing in-RAM object whose data state can be
// exchanged as Python data.
type
PyStateful
interface
{
Stateful
// PySetState should set state of the in-RAM object from Python data.
// Analog of __setstate__() in Python.
PySetState
(
pystate
interface
{})
error
// PyGetState should return state of the in-RAM object as Python data.
// Analog of __getstate__() in Python.
//PyGetState() interface{} XXX
}
// Connection represents a view of ZODB database.
// Connection represents a view of ZODB database.
//
//
...
@@ -357,7 +386,7 @@ func registerClass(classPath string, classNew func(*pyObject)PyObject) {
...
@@ -357,7 +386,7 @@ func registerClass(classPath string, classNew func(*pyObject)PyObject) {
// newGhost creates new ghost object corresponding to pyclass and oid.
// newGhost creates new ghost object corresponding to pyclass and oid.
func
(
conn
*
Connection
)
newGhost
(
pyclass
pickle
.
Class
,
oid
zodb
.
Oid
)
PyObject
{
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
,
state
:
GHOST
},
pyclass
:
pyclass
,
pyclass
:
pyclass
,
}
}
...
@@ -392,22 +421,16 @@ func (d *dummyPyInstance) PySetState(pystate interface{}) error {
...
@@ -392,22 +421,16 @@ func (d *dummyPyInstance) PySetState(pystate interface{}) error {
// ----------------------------------------
// ----------------------------------------
/*
// object's activate & friends that only manage base activation state, without actually loading data.
func (obj *object) PActivate(ctx context.Context) error {
// XXX
}
func (obj *object) PDeactivate() {
// XXX
}
// PInvalidate
*/
// object's pactivate & friends that only manage base activation state, without actually loading data.
// activate increments object reference counter.
//
// XXX -> incref ?
// it returns whether object data needs to be loaded.
func
(
obj
*
object
)
pactivate
()
(
load
bool
)
{
// must be called with .mu held.
func
(
obj
*
object
)
activate
()
(
load
bool
)
{
obj
.
refcnt
++
return
(
obj
.
refcnt
==
1
&&
obj
.
state
==
GHOST
)
/*
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.
...
@@ -415,21 +438,28 @@ func (obj *object) pactivate() (load bool) {
...
@@ -415,21 +438,28 @@ func (obj *object) pactivate() (load bool) {
return true
return true
}
}
return false
return false
*/
}
}
// XXX -> decref ?
// deactivate decrements object reference counter.
func
(
obj
*
object
)
pdeactivate
()
(
drop
bool
)
{
//
nuse
:=
atomic
.
AddInt32
(
&
obj
.
refcnt
,
-
1
)
// it returns whether object data needs to be discarded.
if
nuse
<
0
{
// must be called with .mu held.
panic
(
"pdeactivate: nuse < 0"
)
func
(
obj
*
object
)
deactivate
()
(
drop
bool
)
{
//nuse := atomic.AddInt32(&obj.refcnt, -1)
obj
.
refcnt
--
if
obj
.
refcnt
<
0
{
panic
(
"deactivate: refcnt < 0"
)
}
}
if
nuse
>
0
{
if
obj
.
refcnt
>
0
{
return
// users still left
return
// users still left
}
}
// no users left. Let's see whether we should transition this object to ghost.
// no users left. Let's see whether we should transition this object to ghost.
// TODO state=modified -> don't drop.
drop
=
true
drop
=
true
if
obj
.
state
>=
CHANGED
{
drop
=
false
}
// XXX -> pyObject?
// XXX -> pyObject?
if
drop
{
if
drop
{
...
@@ -440,7 +470,7 @@ func (obj *object) pdeactivate() (drop bool) {
...
@@ -440,7 +470,7 @@ func (obj *object) pdeactivate() (drop bool) {
if
drop
{
if
drop
{
obj
.
serial
=
0
obj
.
serial
=
0
//obj.ins
ance.DropState()
obj
.
inst
ance
.
DropState
()
}
}
return
drop
return
drop
...
@@ -449,26 +479,35 @@ func (obj *object) pdeactivate() (drop bool) {
...
@@ -449,26 +479,35 @@ func (obj *object) pdeactivate() (drop bool) {
// PActivate implements Object.
// PActivate implements Object.
func
(
pyobj
*
pyObject
)
PActivate
(
ctx
context
.
Context
)
(
err
error
)
{
func
(
pyobj
*
pyObject
)
PActivate
(
ctx
context
.
Context
)
(
err
error
)
{
load
:=
pyobj
.
object
.
pactivate
()
pyobj
.
mu
.
Lock
()
doload
:=
pyobj
.
activate
()
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.
pyobj
.
object
.
pdeactivate
()
// XXX locking?
pyobj
.
deactivate
()
}
}
}()
}()
if
!
load
{
if
!
doload
{
loading
:=
pyobj
.
loading
pyobj
.
mu
.
Unlock
()
// 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
ctx
.
Err
()
// XXX err ctx
return
ctx
.
Err
()
// XXX err ctx
case
<-
pyobj
.
ready
:
case
<-
loading
.
ready
:
return
pyobj
.
loaderr
// XXX err ctx?
return
loading
.
err
// XXX err ctx?
}
}
}
}
// we become responsible for loading the object
// we become responsible for loading the object
loading
:=
&
loading
{
ready
:
make
(
chan
struct
{})}
pyobj
.
loading
=
loading
// XXX assert before it was = nil ?
pyobj
.
mu
.
Unlock
()
pyclass
,
pystate
,
serial
,
err
:=
pyobj
.
jar
.
loadpy
(
ctx
,
pyobj
.
oid
)
pyclass
,
pystate
,
serial
,
err
:=
pyobj
.
jar
.
loadpy
(
ctx
,
pyobj
.
oid
)
if
err
==
nil
&&
pyclass
!=
pyobj
.
pyclass
{
if
err
==
nil
&&
pyclass
!=
pyobj
.
pyclass
{
// complain pyclass changed
// complain pyclass changed
...
@@ -477,6 +516,8 @@ func (pyobj *pyObject) PActivate(ctx context.Context) (err error) {
...
@@ -477,6 +516,8 @@ func (pyobj *pyObject) PActivate(ctx context.Context) (err error) {
pystate
=
nil
pystate
=
nil
}
}
pyobj
.
mu
.
Lock
()
pyobj
.
serial
=
serial
pyobj
.
serial
=
serial
// pyobj.pystate = pystate
// pyobj.pystate = pystate
...
@@ -487,16 +528,17 @@ func (pyobj *pyObject) PActivate(ctx context.Context) (err error) {
...
@@ -487,16 +528,17 @@ func (pyobj *pyObject) PActivate(ctx context.Context) (err error) {
pyobj
.
instance
.
DropState
()
pyobj
.
instance
.
DropState
()
}
}
pyobj
.
loaderr
=
err
// XXX unlock
close
(
pyobj
.
ready
)
loading
.
err
=
err
close
(
loading
.
ready
)
return
err
// XXX err ctx
return
err
// XXX err ctx
}
}
// PDeactivate implements Object.
// PDeactivate implements Object.
func
(
pyobj
*
pyObject
)
PDeactivate
()
{
func
(
pyobj
*
pyObject
)
PDeactivate
()
{
drop
:=
pyobj
.
object
.
pdeactivate
()
drop
:=
pyobj
.
pdeactivate
()
if
!
drop
{
if
!
drop
{
return
return
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment