Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neo
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
Kirill Smelkov
neo
Commits
c31c4855
Commit
c31c4855
authored
Jul 20, 2018
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
2f8b5e03
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
48 additions
and
50 deletions
+48
-50
go/zodb/btree/btree.go
go/zodb/btree/btree.go
+7
-7
go/zodb/internal/weak/weak.go
go/zodb/internal/weak/weak.go
+10
-12
go/zodb/internal/weak/weak_test.go
go/zodb/internal/weak/weak_test.go
+2
-2
go/zodb/persistent.go
go/zodb/persistent.go
+14
-14
go/zodb/zodbpy.go
go/zodb/zodbpy.go
+15
-15
No files found.
go/zodb/btree/btree.go
View file @
c31c4855
...
...
@@ -19,7 +19,7 @@ import (
"sort"
"lab.nexedi.com/kirr/go123/xerr"
//
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/kirr/neo/go/zodb"
pickle
"github.com/kisielk/og-rek"
)
...
...
@@ -37,7 +37,7 @@ type KEY int64
// are chained together via 'next', so that the entire BTree contents
// can be traversed in sorted order quickly and easily.
type
ZBucket
struct
{
*
PyPersistent
*
zodb
.
PyPersistent
next
*
ZBucket
// the bucket with the next-larger keys
keys
[]
KEY
// 'len' keys, in increasing order
...
...
@@ -55,7 +55,7 @@ type zBTreeItem struct {
// See https://github.com/zopefoundation/BTrees/blob/4.5.0-1-gc8bf24e/BTrees/Development.txt#L198
// for details.
type
ZBTree
struct
{
*
PyPersistent
*
zodb
.
PyPersistent
// firstbucket points to the bucket containing the smallest key in
// the BTree. This is found by traversing leftmost child pointers
...
...
@@ -312,10 +312,10 @@ func (b *ZBucket) PySetState(pystate interface{}) error {
// ---- register classes to ZODB ----
func
bucketNew
(
base
*
PyPersistent
)
IPyPersistent
{
return
&
ZBucket
{
PyPersistent
:
base
}
}
func
btreeNew
(
base
*
PyPersistent
)
IPyPersistent
{
return
&
ZBTree
{
PyPersistent
:
base
}
}
func
bucketNew
(
base
*
zodb
.
PyPersistent
)
zodb
.
IPyPersistent
{
return
&
ZBucket
{
PyPersistent
:
base
}
}
func
btreeNew
(
base
*
zodb
.
PyPersistent
)
zodb
.
IPyPersistent
{
return
&
ZBTree
{
PyPersistent
:
base
}
}
func
init
()
{
registerPy
Class
(
"zodb.BTree.LOBucket"
,
bucketNew
)
registerPy
Class
(
"zodb.BTree.LOBtree"
,
btreeNew
)
zodb
.
PyRegister
Class
(
"zodb.BTree.LOBucket"
,
bucketNew
)
zodb
.
PyRegister
Class
(
"zodb.BTree.LOBtree"
,
btreeNew
)
}
go/zodb/internal/weak/weak.go
View file @
c31c4855
...
...
@@ -22,8 +22,6 @@
// See https://www.nexedi.com/licensing for rationale and options.
// Package weak provides weak references for Go.
//
// XXX
package
weak
import
(
...
...
@@ -40,24 +38,24 @@ type iface struct {
data
uintptr
// data
}
// weakRefState represents current state of an object
Weak
Ref points to.
// weakRefState represents current state of an object Ref points to.
type
weakRefState
int32
const
(
objGot
weakRefState
=
+
1
//
Weak
Ref.Get returned !nil
objGot
weakRefState
=
+
1
// Ref.Get returned !nil
objLive
weakRefState
=
0
// object is alive, Get did not run yet in this GC cycle
objReleased
weakRefState
=
-
1
// the finalizer marked object as released
)
//
Weak
Ref is a weak reference.
// Ref is a weak reference.
//
// Create one with New
Weak
Ref and retrieve referenced object with Get.
// Create one with NewRef and retrieve referenced object with Get.
//
// There must be no more than 1 weak reference to any object.
// Weak references must not be attached to an object on which runtime.SetFinalizer is also used.
// Weak references must not be copied.
type
Weak
Ref
struct
{
type
Ref
struct
{
iface
// XXX try to do without mutex and only with atomics
...
...
@@ -65,14 +63,14 @@ type WeakRef struct {
state
weakRefState
}
// New
Weak
Ref creates new weak reference pointing to obj.
// NewRef creates new weak reference pointing to obj.
//
// XXX + onrelease callback?
func
New
WeakRef
(
obj
interface
{})
*
Weak
Ref
{
func
New
Ref
(
obj
interface
{})
*
Ref
{
// since starting from ~ Go1.4 the GC is precise, we can save interface
// pointers to uintptr and that won't prevent GC from garbage
// collecting the object.
w
:=
&
Weak
Ref
{
w
:=
&
Ref
{
iface
:
*
(
*
iface
)(
unsafe
.
Pointer
(
&
obj
)),
state
:
objLive
,
}
...
...
@@ -81,7 +79,7 @@ func NewWeakRef(obj interface{}) *WeakRef {
release
=
func
(
obj
interface
{})
{
// GC decided that the object is no longer reachable and
// scheduled us to run as finalizer. During the time till we
// actually run,
Weak
Ref.Get might have been come to run and
// actually run, Ref.Get might have been come to run and
// "rematerializing" the object for use. Check if we do not
// race with any Get in progress, and reschedule us to retry at
// next GC if we do.
...
...
@@ -103,7 +101,7 @@ func NewWeakRef(obj interface{}) *WeakRef {
//
// If original object is still alive - it is returned.
// If not - nil is returned.
func
(
w
*
Weak
Ref
)
Get
()
(
obj
interface
{})
{
func
(
w
*
Ref
)
Get
()
(
obj
interface
{})
{
w
.
mu
.
Lock
()
if
w
.
state
!=
objReleased
{
w
.
state
=
objGot
...
...
go/zodb/internal/weak/weak_test.go
View file @
c31c4855
...
...
@@ -17,7 +17,7 @@
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
package
main
package
weak
import
(
"runtime"
...
...
@@ -58,7 +58,7 @@ func TestWeakRef(t *testing.T) {
type
T
struct
{
_
[
8
]
int64
}
// large enough not to go into tinyalloc
p
:=
new
(
T
)
w
:=
New
Weak
Ref
(
p
)
w
:=
NewRef
(
p
)
pptr
:=
uintptr
(
unsafe
.
Pointer
(
p
))
assertEq
:=
func
(
a
,
b
interface
{})
{
...
...
go/zodb/persistent.go
View file @
c31c4855
...
...
@@ -11,15 +11,15 @@
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
// FOR A PARTICULAR PURPOSE
package
main
//
Bits that should be in ZODB XXX -> zodb
package
zodb
//
persistent objects.
import
(
"context"
"sync"
"lab.nexedi.com/kirr/go123/mem"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/kirr/neo/go/zodb
/internal/weak
"
)
// IPersistent is the interface that every in-RAM object representing any database object implements.
...
...
@@ -31,11 +31,11 @@ import (
// but is not exactly equal to it.
type
IPersistent
interface
{
PJar
()
*
Connection
// Connection this in-RAM object is part of.
POid
()
zodb
.
Oid
// object ID in the database.
POid
()
Oid
// object ID in the database.
// object serial in the database as of particular Connection (PJar) view.
// 0 (invalid tid) if not yet loaded (XXX ok?)
PSerial
()
zodb
.
Tid
PSerial
()
Tid
// PActivate brings object to live state.
...
...
@@ -117,8 +117,8 @@ const (
// Persistent is common base implementation for in-RAM representation of database objects.
type
Persistent
struct
{
jar
*
Connection
oid
zodb
.
Oid
serial
zodb
.
Tid
oid
Oid
serial
Tid
mu
sync
.
Mutex
state
ObjectState
...
...
@@ -128,8 +128,8 @@ type Persistent struct {
}
func
(
obj
*
Persistent
)
PJar
()
*
Connection
{
return
obj
.
jar
}
func
(
obj
*
Persistent
)
POid
()
zodb
.
Oid
{
return
obj
.
oid
}
func
(
obj
*
Persistent
)
PSerial
()
zodb
.
Tid
{
return
obj
.
serial
}
func
(
obj
*
Persistent
)
POid
()
Oid
{
return
obj
.
oid
}
func
(
obj
*
Persistent
)
PSerial
()
Tid
{
return
obj
.
serial
}
// loadState indicates object's load state/result.
//
...
...
@@ -172,8 +172,8 @@ type Stateful interface {
//
// XXX ^^^ better must be safe - use case: e.g. prefetch.
type
Connection
struct
{
stor
zodb
.
IStorage
// underlying storage
at
zodb
.
Tid
// current view of database
stor
IStorage
// underlying storage
at
Tid
// current view of database
// {} oid -> obj
//
...
...
@@ -223,7 +223,7 @@ 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 -> Weak
Ref(IPersistent)
objtab
map
[
Oid
]
*
weak
.
Ref
// oid -> weak.
Ref(IPersistent)
// hooks for application to influence live caching decisions.
cacheControl
LiveCacheControl
...
...
@@ -357,6 +357,6 @@ func (obj *Persistent) PInvalidate() {
// load loads object specified by oid.
//
// XXX must be called ... (XXX e.g. outside transaction boundary) so that there is no race on .at .
func
(
conn
*
Connection
)
load
(
ctx
context
.
Context
,
oid
zodb
.
Oid
)
(
_
*
mem
.
Buf
,
serial
zodb
.
Tid
,
_
error
)
{
return
conn
.
stor
.
Load
(
ctx
,
zodb
.
Xid
{
Oid
:
oid
,
At
:
conn
.
at
})
func
(
conn
*
Connection
)
load
(
ctx
context
.
Context
,
oid
Oid
)
(
_
*
mem
.
Buf
,
serial
Tid
,
_
error
)
{
return
conn
.
stor
.
Load
(
ctx
,
Xid
{
Oid
:
oid
,
At
:
conn
.
at
})
}
go/zodb/zodbpy.go
View file @
c31c4855
...
...
@@ -11,15 +11,15 @@
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
// FOR A PARTICULAR PURPOSE
package
main
//
Bits that should be in ZODB XXX -> zodb
package
zodb
//
Support for python objects/data in ZODB.
import
(
"context"
"fmt"
"lab.nexedi.com/kirr/go123/mem"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/kirr/neo/go/zodb
/internal/weak
"
pickle
"github.com/kisielk/og-rek"
)
...
...
@@ -70,7 +70,7 @@ func (pyobj *PyPersistent) pyinstance() IPyPersistent {
}
func
(
pyobj
*
PyPersistent
)
SetState
(
state
*
mem
.
Buf
)
error
{
pyclass
,
pystate
,
err
:=
zodb
.
PyData
(
state
.
Data
)
.
Decode
()
pyclass
,
pystate
,
err
:=
PyData
(
state
.
Data
)
.
Decode
()
if
err
!=
nil
{
return
err
// XXX err ctx
}
...
...
@@ -94,17 +94,17 @@ type pyClassNewFunc func(base *PyPersistent) IPyPersistent
// path(pyclass) -> new(pyobj)
var
pyClassTab
=
make
(
map
[
string
]
pyClassNewFunc
)
//
registerPy
Class registers python class to be transformed to Go instance
//
PyRegister
Class registers python class to be transformed to Go instance
// created via classNew.
//
// must be called from global init().
func
registerPy
Class
(
pyClassPath
string
,
classNew
pyClassNewFunc
)
{
func
PyRegister
Class
(
pyClassPath
string
,
classNew
pyClassNewFunc
)
{
pyClassTab
[
pyClassPath
]
=
classNew
// XXX + register so that
zodb.
PyData decode handles pyClassPath
// XXX + register so that PyData decode handles pyClassPath
}
// newGhost creates new ghost object corresponding to pyclass and oid.
func
(
conn
*
Connection
)
newGhost
(
pyclass
pickle
.
Class
,
oid
zodb
.
Oid
)
IPyPersistent
{
func
(
conn
*
Connection
)
newGhost
(
pyclass
pickle
.
Class
,
oid
Oid
)
IPyPersistent
{
pyobj
:=
&
PyPersistent
{
Persistent
:
Persistent
{
jar
:
conn
,
oid
:
oid
,
serial
:
0
,
state
:
GHOST
},
pyclass
:
pyclass
,
...
...
@@ -151,7 +151,7 @@ func (d *dummyPyInstance) PySetState(pystate interface{}) error {
//
// 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
)
(
IPyPersistent
,
error
)
{
func
(
conn
*
Connection
)
Get
(
ctx
context
.
Context
,
oid
Oid
)
(
IPyPersistent
,
error
)
{
conn
.
objmu
.
Lock
()
// XXX -> rlock
wobj
:=
conn
.
objtab
[
oid
]
var
xobj
interface
{}
...
...
@@ -205,7 +205,7 @@ func (e *wrongClassError) Error() string {
//
// 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
)
(
IPyPersistent
,
error
)
{
func
(
conn
*
Connection
)
get
(
pyclass
pickle
.
Class
,
oid
Oid
)
(
IPyPersistent
,
error
)
{
conn
.
objmu
.
Lock
()
// XXX -> rlock
wobj
:=
conn
.
objtab
[
oid
]
var
pyobj
IPyPersistent
...
...
@@ -217,7 +217,7 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (IPyPersistent,
}
if
pyobj
==
nil
{
pyobj
=
conn
.
newGhost
(
pyclass
,
oid
)
conn
.
objtab
[
oid
]
=
NewWeak
Ref
(
pyobj
)
conn
.
objtab
[
oid
]
=
weak
.
New
Ref
(
pyobj
)
}
else
{
checkClass
=
true
}
...
...
@@ -225,7 +225,7 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (IPyPersistent,
if
checkClass
{
if
cls
:=
pyobj
.
PyClass
();
pyclass
!=
cls
{
return
nil
,
&
zodb
.
OpError
{
return
nil
,
&
OpError
{
URL
:
conn
.
stor
.
URL
(),
Op
:
fmt
.
Sprintf
(
"@%s: get"
,
conn
.
at
),
// XXX abuse
Args
:
oid
,
...
...
@@ -241,15 +241,15 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (IPyPersistent,
//
// loadpy does not create any in-RAM object associated with Connection.
// It only returns decoded database data.
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
})
func
(
conn
*
Connection
)
loadpy
(
ctx
context
.
Context
,
oid
Oid
)
(
pyclass
pickle
.
Class
,
pystate
interface
{},
serial
Tid
,
_
error
)
{
buf
,
serial
,
err
:=
conn
.
stor
.
Load
(
ctx
,
Xid
{
Oid
:
oid
,
At
:
conn
.
at
})
if
err
!=
nil
{
return
pickle
.
Class
{},
nil
,
0
,
err
}
defer
buf
.
Release
()
pyclass
,
pystate
,
err
=
zodb
.
PyData
(
buf
.
Data
)
.
Decode
()
pyclass
,
pystate
,
err
=
PyData
(
buf
.
Data
)
.
Decode
()
if
err
!=
nil
{
return
pickle
.
Class
{},
nil
,
0
,
err
// XXX err ctx
}
...
...
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