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
fb9d0fce
Commit
fb9d0fce
authored
Jul 16, 2018
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
2848c632
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
36 additions
and
32 deletions
+36
-32
wcfs/zodb.go
wcfs/zodb.go
+36
-32
No files found.
wcfs/zodb.go
View file @
fb9d0fce
...
...
@@ -24,49 +24,52 @@ import (
pickle
"github.com/kisielk/og-rek"
)
// Object is the interface that every object representing any ZODB object implements.
// Object is the interface that every
in-RAM
object representing any ZODB object implements.
type
Object
interface
{
Jar
()
*
Connection
Oid
()
zodb
.
Oid
Serial
()
zodb
.
Tid
P
Jar
()
*
Connection
P
Oid
()
zodb
.
Oid
P
Serial
()
zodb
.
Tid
// XXX activate/deactivate/invalidate here?
}
// PyObject is the interface that every object representing Python ZODB object implements.
// PyObject is the interface that every
in-RAM
object representing Python ZODB object implements.
type
PyObject
interface
{
Object
PyClass
()
pickle
.
Class
// PyState?
PyClass
()
pickle
.
Class
// python class of this object
PyState
()
interface
{}
// object state. python passes this to pyclass.__new__().__setstate__()
}
// object is common base for in-
process
representation of ZODB object.
// object is common base for in-
RAM
representation of ZODB object.
type
object
struct
{
jar
*
Connection
oid
zodb
.
Oid
serial
zodb
.
Tid
}
func
(
obj
*
object
)
Jar
()
*
Connection
{
return
obj
.
jar
}
func
(
obj
*
object
)
Oid
()
zodb
.
Oid
{
return
obj
.
oid
}
func
(
obj
*
object
)
Serial
()
zodb
.
Tid
{
return
obj
.
serial
}
func
(
obj
*
object
)
P
Jar
()
*
Connection
{
return
obj
.
jar
}
func
(
obj
*
object
)
P
Oid
()
zodb
.
Oid
{
return
obj
.
oid
}
func
(
obj
*
object
)
P
Serial
()
zodb
.
Tid
{
return
obj
.
serial
}
// pyObject is common base for in-
process
representation of ZODB Python objects.
// pyObject is common base for in-
RAM
representation of ZODB Python objects.
type
pyObject
struct
{
object
pyclass
pickle
.
Class
// python class of this object
pystate
interface
{}
// object state. python passes this to pyclass.__new__().__setstate__()
pyclass
pickle
.
Class
pystate
interface
{}
}
func
(
pyobj
*
pyObject
)
PyClass
()
pickle
.
Class
{
return
pyobj
.
pyclass
}
func
(
pyobj
*
pyObject
)
PyState
()
interface
{}
{
return
pyobj
.
pystate
}
// Connection represents a view of ZODB database.
//
// The view is representing state of ZODB objects as of `at` transaction.
//
// XXX Connection changes are private and are isolated from changes in other Connections.
//
// XXX Connection, and {Py}Object methods that relate to it, are not safe for
// modifications from multiple goroutines simultaneously.
//
...
...
@@ -75,31 +78,31 @@ type Connection struct {
stor
zodb
.
IStorage
// underlying storage
at
zodb
.
Tid
// current view of database
// {} oid ->
py
obj
// {} oid -> obj
//
// rationale:
//
// on invalidations: we need to go oid ->
py
obj and invalidate it.
// -> Connection need to keep {} oid ->
py
obj.
// on invalidations: we need to go oid -> obj and invalidate it.
// -> Connection need to keep {} oid -> obj.
// -> we can use that {} when loading a persistent Ref twice to get to the same object.
//
// however: if Connection keeps strong link to
py
obj, just
//
pyobj.PDeactivate will not fully release py
obj if there are no
// however: if Connection keeps strong link to obj, just
//
obj.PDeactivate will not fully release
obj if there are no
// references to it from other objects:
//
// - deactivate will release
py
obj state (ok)
// - but there will be still reference from connection `oid ->
py
obj` map to this object.
// - deactivate will release obj state (ok)
// - but there will be still reference from connection `oid -> obj` map to this object.
//
// -> we can solve it by using "weak" pointers in the map.
//
// NOTE we cannot use regular map and arbitrarily manually "gc" entries
// there periodically: since for a
py
obj we don't know whether other
// objects are referencing it, we can't just remove
py
obj's oid from
// there periodically: since for a
n
obj we don't know whether other
// objects are referencing it, we can't just remove obj's oid from
// the map - if we do so and there are other live objects that
// reference
pyobj, user code can still reach py
obj via those
// reference
obj, user code can still reach
obj via those
// references. On the other hand, if another, not yet loaded, object
// also references
py
obj and gets loaded, traversing reference from
// that loaded object will load second copy of
py
obj, thus breaking 1
// also references obj and gets loaded, traversing reference from
// that loaded object will load second copy of obj, thus breaking 1
// object in db <-> 1 live object invariant:
//
// A → B → C
...
...
@@ -123,8 +126,8 @@ type Connection struct {
// NOTE2 finalizers don't run on when they are attached to an object in cycle.
// Hopefully we don't have cycles with ZBtree/ZBucket XXX verify this
objmu
sync
.
Mutex
objtab
map
[
zodb
.
Oid
]
*
WeakRef
// oid -> WeakRef(PyObject)
//objtab map[zodb.Oid]interface{} // oid -> WeakRef(pyObject) | loadInProgress
objtab
map
[
zodb
.
Oid
]
*
WeakRef
}
/*
...
...
@@ -144,11 +147,11 @@ type loadInProgress struct {
// If there is already in-RAM object that corresponds to oid, that in-RAM object is returned.
// Otherwise new in-RAM object is created and filled with object's class loaded from the database.
//
// The scope of the object returned is the Connection. XXX ok?
//
// 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
)
{
// XXX = load raw oid, get its class -> get(pyclass, oid)
conn
.
objmu
.
Lock
()
wobj
:=
conn
.
objtab
[
oid
]
var
xobj
interface
{}
...
...
@@ -179,7 +182,7 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (interface{} /*Py
// TODO -> use (pystate, serial) to activate.
_
,
_
=
pystate
,
serial
return
xobj
,
nil
}
/*
conn.objmu.Lock() // XXX -> rlock
...
...
@@ -235,9 +238,8 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (interface{} /*Py
conn.objtab[oid] = NewWeakRef(pyobj)
}
*/
}
// wrongClassError is the error cause returned when object's class is
wrong
.
// wrongClassError is the error cause returned when object's class is
not what was expected
.
type
wrongClassError
struct
{
want
,
have
pickle
.
Class
}
...
...
@@ -254,6 +256,8 @@ func (e *wrongClassError) Error() string {
// The object's data is not neccessarily loaded after get returns. Use
// PActivate to make sure the object is fully loaded.
//
// XXX object scope.
//
// use-case: in ZODB references are (pyclass, oid), so new ghost is created
// without further loading anything.
func
(
conn
*
Connection
)
get
(
pyclass
pickle
.
Class
,
oid
zodb
.
Oid
)
(
PyObject
,
error
)
{
...
...
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