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
3ec95a81
Commit
3ec95a81
authored
Jul 16, 2018
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
e083af5b
Changes
2
Show 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 {
...
@@ -235,3 +235,19 @@ func (b *ZBucket) PActivate(ctx context.Context) error {
return
nil
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 {
...
@@ -39,6 +39,8 @@ type PyObject struct {
// Connection represents a view of ZODB database.
// 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
// XXX Connection, and {Py}Object methods that relate to it, are not safe for
// modifications from multiple goroutines simultaneously.
// modifications from multiple goroutines simultaneously.
//
//
...
@@ -98,22 +100,26 @@ type Connection struct {
...
@@ -98,22 +100,26 @@ type Connection struct {
objtab
map
[
zodb
.
Oid
]
interface
{}
// oid -> WeakRef(PyObject) | loadInProgress
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.
// that another goroutine is already in progress of loading it.
type
loadInProgress
struct
{
type
loadInProgress
struct
{
ready
chan
struct
{}
// closed when loading finishes
ready
chan
struct
{}
// closed when loading finishes
// result of the load
// result of the load
pyobj
*
PyObject
pyobj
interface
{}
// XXX -> PyObject iface
err
error
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.
// The object's data is not neccessarily loaded after Get returns. Use
// XXX this is needed if there are several persistent references to the same object.
// PActivate to make sure the object ifs fully loaded.
// however wendelin.core does not do this.
func
(
conn
*
Connection
)
Get
(
ctx
context
.
Context
,
oid
zodb
.
Oid
)
(
*
PyObject
,
error
)
{
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
conn
.
objmu
.
Lock
()
// XXX -> rlock
objentry
:=
conn
.
objtab
[
oid
]
objentry
:=
conn
.
objtab
[
oid
]
...
@@ -124,8 +130,73 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (*PyObject, error
...
@@ -124,8 +130,73 @@ func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (*PyObject, error
select
{
select
{
case
<-
ctx
.
Done
()
:
case
<-
ctx
.
Done
()
:
return
nil
,
ctx
.
Err
()
// XXX err ctx
return
nil
,
ctx
.
Err
()
// XXX err ctx
case
<-
xobj
.
ready
:
case
<-
load
.
ready
:
return
xobj
.
pyobj
,
err
// 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
...
@@ -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
)
{
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
})
buf
,
serial
,
err
:=
conn
.
stor
.
Load
(
ctx
,
zodb
.
Xid
{
Oid
:
oid
,
At
:
conn
.
at
})
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -205,16 +280,32 @@ func (conn *Connection) loadpy(ctx context.Context, oid zodb.Oid) (pyclass pickl
...
@@ -205,16 +280,32 @@ func (conn *Connection) loadpy(ctx context.Context, oid zodb.Oid) (pyclass pickl
return
pyclass
,
pystate
,
serial
,
nil
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
{}
{
func
(
conn
*
Connection
)
newGhost
(
pyclass
pickle
.
Class
,
oid
zodb
.
Oid
)
interface
{}
{
pyobj
:=
PyObject
{
pyobj
:=
&
PyObject
{
Object
:
Object
{
jar
:
conn
,
oid
:
oid
,
serial
:
0
},
Object
:
Object
{
jar
:
conn
,
oid
:
oid
,
serial
:
0
},
pyclass
:
pyclass
,
pyclass
:
pyclass
,
pystate
:
nil
,
pystate
:
nil
,
}
}
// TODO switch on pyclass and transform e.g. "zodb.BTree.Bucket" -> *ZBucket
// switch on pyclass and transform e.g. "zodb.BTree.Bucket" -> *ZBucket
return
&
pyobj
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