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
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Joshua
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