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
3ec95a81
Commit
3ec95a81
authored
Jul 16, 2018
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
e083af5b
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
119 additions
and
12 deletions
+119
-12
wcfs/btree.go
wcfs/btree.go
+16
-0
wcfs/zodb.go
wcfs/zodb.go
+103
-12
No files found.
wcfs/btree.go
View file @
3ec95a81
...
...
@@ -235,3 +235,19 @@ func (b *ZBucket) PActivate(ctx context.Context) error {
return
nil
}
// ----------------------------------------
func
bucketNew
(
pyobj
*
PyObject
)
interface
{}
{
return
&
ZBucket
{
pyobj
:
pyobj
}
}
func
btreeNew
(
pyobj
*
PyObject
)
interface
{}
{
return
&
ZBtree
{
pyobj
:
pyobj
}
}
func
init
()
{
registerClass
(
"zodb.BTree.LOBucket"
,
bucketNew
)
registerClass
(
"zodb.BTree.LOBtree"
,
btreeNew
)
}
wcfs/zodb.go
View file @
3ec95a81
...
...
@@ -39,6 +39,8 @@ type PyObject struct {
// Connection represents a view of ZODB database.
//
// The view is representing state of ZODB objects as of `at` transaction.
//
// XXX Connection, and {Py}Object methods that relate to it, are not safe for
// modifications from multiple goroutines simultaneously.
//
...
...
@@ -98,22 +100,26 @@ type Connection struct {
objtab
map
[
zodb
.
Oid
]
interface
{}
// oid -> WeakRef(PyObject) | loadInProgress
}
// loadInProgress entry in Conn.objtab tells users
that try to get the entry
// 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
*
PyObject
pyobj
interface
{}
// XXX -> PyObject iface
err
error
}
// Gets loads and decodes object from the database according to its current view.
// Get returns in-RAM object corresponding to specified ZODB object according to current database view.
//
// 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.
//
// FIXME multiple calls to Get(oid) have to return the same instance.
// XXX this is needed if there are several persistent references to the same object.
// however wendelin.core does not do this.
// 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
)
(
*
PyObject
,
error
)
{
// XXX = load raw oid, get its class -> get(pyclass, oid)
conn
.
objmu
.
Lock
()
// XXX -> rlock
objentry
:=
conn
.
objtab
[
oid
]
...
...
@@ -124,8 +130,73 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (*PyObject, error
select
{
case
<-
ctx
.
Done
()
:
return
nil
,
ctx
.
Err
()
// XXX err ctx
case
<-
xobj
.
ready
:
return
xobj
.
pyobj
,
err
case
<-
load
.
ready
:
// XXX check pyclass match
return
load
.
pyobj
,
err
}
}
// noone else is loading the object. Investigate whether it is simply not
// in objtab, or it is lost weakref, and if so we have to initiate the load.
var
xobj
interface
{}
if
objentry
!=
nil
{
wobj
:=
objentry
.
(
*
WeakRef
)
xobj
=
wobj
.
Get
()
}
if
xpyobj
!=
nil
{
// the object is already there
conn
.
objmu
.
Unlock
()
return
xpyobj
,
nil
// XXX + activate?
}
// the object is not there, we have to (re)load it.
load
:=
&
loadInProgress
{
ready
:
make
(
chan
struct
)}
conn
.
objTab
[
oid
]
=
load
conn
.
objmu
.
Unlock
()
pyobj
,
err
=
conn
.
loadpy
(
ctx
,
oid
)
load
.
pyobj
=
pyobj
load
.
err
=
err
close
(
load
.
ready
)
// replace objtab entry with WeakRef
conn
.
objmu
.
Lock
()
defer
conn
.
objmu
.
Unlock
()
if
x
:=
conn
.
objtab
[
oid
];
x
!=
load
{
panic
(
fmt
.
Sprintf
(
"zodb.Conn: objtab[%s]: load finished, but it is: %#v"
,
oid
,
x
)
}
if
err
!=
nil
{
// it was loading error - remove the entry not to cause uncontrolled objtab growth.
// if this object is accessed next time - the load will be retried.
delete
(
conn
.
objtab
[
oid
])
}
else
{
conn
.
objtab
[
oid
]
=
NewWeakRef
(
pyobj
)
}
}
// get returns in-RAM object corresponding to specified ZODB object according to current database view.
//
// 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 object's data is not neccessarily loaded after get returns. Use
// PActivate to make sure the object ifs fully loaded.
//
// use-case: in ZODB references are (pyclass, oid), so new ghost is created without loading anything.
func
(
conn
*
Connection
)
get
(
ctx
context
.
Context
,
pyclass
pickle
.
Class
,
oid
zodb
.
Oid
)
(
*
PyObject
,
error
)
{
conn
.
objmu
.
Lock
()
// XXX -> rlock
objentry
:=
conn
.
objtab
[
oid
]
// someone else is already loading the object.
// we have to wait for that someone to finish the load.
if
load
,
ok
:=
objentry
.
(
*
loadInProgress
);
ok
{
conn
.
objmu
.
Unlock
()
select
{
case
<-
ctx
.
Done
()
:
return
nil
,
ctx
.
Err
()
// XXX err ctx
case
<-
load
.
ready
:
// XXX check pyclass match
return
load
.
pyobj
,
err
}
}
...
...
@@ -189,6 +260,10 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (*PyObject, error
*/
}
func
(
conn
*
Connection
)
load
(
ctx
context
.
Context
,
oid
zodb
.
Oid
)
(
*
PyObject
,
error
)
{
// XXX
}
func
(
conn
*
Connection
)
loadpy
(
ctx
context
.
Context
,
oid
zodb
.
Oid
)
(
pyclass
pickle
.
Class
,
pystate
interface
{},
serial
zodb
.
Tid
,
_
error
)
{
buf
,
serial
,
err
:=
conn
.
stor
.
Load
(
ctx
,
zodb
.
Xid
{
Oid
:
oid
,
At
:
conn
.
at
})
if
err
!=
nil
{
...
...
@@ -205,16 +280,32 @@ func (conn *Connection) loadpy(ctx context.Context, oid zodb.Oid) (pyclass pickl
return
pyclass
,
pystate
,
serial
,
nil
}
// newGhost creates new ghost object.
// path(class) -> new(pyobj)
var
classTab
=
map
[
string
]
func
(
*
PyObject
)
interface
{}
// registerClass registers python class to be transformed to Go instance
// created via classNew.
//
// must be called from global init().
func
registerClass
(
pyClassPath
string
,
classNew
func
(
*
PyObject
)
interface
{})
{
classTab
[
classPath
]
=
classNew
}
// newGhost creates new ghost object corresponding to pyclass and oid.
func
(
conn
*
Connection
)
newGhost
(
pyclass
pickle
.
Class
,
oid
zodb
.
Oid
)
interface
{}
{
pyobj
:=
PyObject
{
pyobj
:=
&
PyObject
{
Object
:
Object
{
jar
:
conn
,
oid
:
oid
,
serial
:
0
},
pyclass
:
pyclass
,
pystate
:
nil
,
}
// TODO switch on pyclass and transform e.g. "zodb.BTree.Bucket" -> *ZBucket
return
&
pyobj
// switch on pyclass and transform e.g. "zodb.BTree.Bucket" -> *ZBucket
classNew
:=
classTab
[
pyclass
.
Module
+
"."
+
pyclass
.
Name
]
if
classNew
==
nil
{
return
pyobj
// XXX or return error here?
}
return
classNew
(
pyobj
)
}
...
...
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