Commit c31c4855 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 2f8b5e03
...@@ -19,7 +19,7 @@ import ( ...@@ -19,7 +19,7 @@ import (
"sort" "sort"
"lab.nexedi.com/kirr/go123/xerr" "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" pickle "github.com/kisielk/og-rek"
) )
...@@ -37,7 +37,7 @@ type KEY int64 ...@@ -37,7 +37,7 @@ type KEY int64
// are chained together via 'next', so that the entire BTree contents // are chained together via 'next', so that the entire BTree contents
// can be traversed in sorted order quickly and easily. // can be traversed in sorted order quickly and easily.
type ZBucket struct { type ZBucket struct {
*PyPersistent *zodb.PyPersistent
next *ZBucket // the bucket with the next-larger keys next *ZBucket // the bucket with the next-larger keys
keys []KEY // 'len' keys, in increasing order keys []KEY // 'len' keys, in increasing order
...@@ -55,7 +55,7 @@ type zBTreeItem struct { ...@@ -55,7 +55,7 @@ type zBTreeItem struct {
// See https://github.com/zopefoundation/BTrees/blob/4.5.0-1-gc8bf24e/BTrees/Development.txt#L198 // See https://github.com/zopefoundation/BTrees/blob/4.5.0-1-gc8bf24e/BTrees/Development.txt#L198
// for details. // for details.
type ZBTree struct { type ZBTree struct {
*PyPersistent *zodb.PyPersistent
// firstbucket points to the bucket containing the smallest key in // firstbucket points to the bucket containing the smallest key in
// the BTree. This is found by traversing leftmost child pointers // the BTree. This is found by traversing leftmost child pointers
...@@ -312,10 +312,10 @@ func (b *ZBucket) PySetState(pystate interface{}) error { ...@@ -312,10 +312,10 @@ func (b *ZBucket) PySetState(pystate interface{}) error {
// ---- register classes to ZODB ---- // ---- register classes to ZODB ----
func bucketNew(base *PyPersistent) IPyPersistent { return &ZBucket{PyPersistent: base} } func bucketNew(base *zodb.PyPersistent) zodb.IPyPersistent { return &ZBucket{PyPersistent: base} }
func btreeNew(base *PyPersistent) IPyPersistent { return &ZBTree{PyPersistent: base} } func btreeNew(base *zodb.PyPersistent) zodb.IPyPersistent { return &ZBTree{PyPersistent: base} }
func init() { func init() {
registerPyClass("zodb.BTree.LOBucket", bucketNew) zodb.PyRegisterClass("zodb.BTree.LOBucket", bucketNew)
registerPyClass("zodb.BTree.LOBtree", btreeNew) zodb.PyRegisterClass("zodb.BTree.LOBtree", btreeNew)
} }
...@@ -22,8 +22,6 @@ ...@@ -22,8 +22,6 @@
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
// Package weak provides weak references for Go. // Package weak provides weak references for Go.
//
// XXX
package weak package weak
import ( import (
...@@ -40,24 +38,24 @@ type iface struct { ...@@ -40,24 +38,24 @@ type iface struct {
data uintptr // data data uintptr // data
} }
// weakRefState represents current state of an object WeakRef points to. // weakRefState represents current state of an object Ref points to.
type weakRefState int32 type weakRefState int32
const ( const (
objGot weakRefState = +1 // WeakRef.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 objLive weakRefState = 0 // object is alive, Get did not run yet in this GC cycle
objReleased weakRefState = -1 // the finalizer marked object as released objReleased weakRefState = -1 // the finalizer marked object as released
) )
// WeakRef is a weak reference. // Ref is a weak reference.
// //
// Create one with NewWeakRef 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. // 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 attached to an object on which runtime.SetFinalizer is also used.
// Weak references must not be copied. // Weak references must not be copied.
type WeakRef struct { type Ref struct {
iface iface
// XXX try to do without mutex and only with atomics // XXX try to do without mutex and only with atomics
...@@ -65,14 +63,14 @@ type WeakRef struct { ...@@ -65,14 +63,14 @@ type WeakRef struct {
state weakRefState state weakRefState
} }
// NewWeakRef creates new weak reference pointing to obj. // NewRef creates new weak reference pointing to obj.
// //
// XXX + onrelease callback? // XXX + onrelease callback?
func NewWeakRef(obj interface{}) *WeakRef { func NewRef(obj interface{}) *Ref {
// since starting from ~ Go1.4 the GC is precise, we can save interface // since starting from ~ Go1.4 the GC is precise, we can save interface
// pointers to uintptr and that won't prevent GC from garbage // pointers to uintptr and that won't prevent GC from garbage
// collecting the object. // collecting the object.
w := &WeakRef{ w := &Ref{
iface: *(*iface)(unsafe.Pointer(&obj)), iface: *(*iface)(unsafe.Pointer(&obj)),
state: objLive, state: objLive,
} }
...@@ -81,7 +79,7 @@ func NewWeakRef(obj interface{}) *WeakRef { ...@@ -81,7 +79,7 @@ func NewWeakRef(obj interface{}) *WeakRef {
release = func(obj interface{}) { release = func(obj interface{}) {
// GC decided that the object is no longer reachable and // GC decided that the object is no longer reachable and
// scheduled us to run as finalizer. During the time till we // scheduled us to run as finalizer. During the time till we
// actually run, WeakRef.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 // "rematerializing" the object for use. Check if we do not
// race with any Get in progress, and reschedule us to retry at // race with any Get in progress, and reschedule us to retry at
// next GC if we do. // next GC if we do.
...@@ -103,7 +101,7 @@ func NewWeakRef(obj interface{}) *WeakRef { ...@@ -103,7 +101,7 @@ func NewWeakRef(obj interface{}) *WeakRef {
// //
// If original object is still alive - it is returned. // If original object is still alive - it is returned.
// If not - nil is returned. // If not - nil is returned.
func (w *WeakRef) Get() (obj interface{}) { func (w *Ref) Get() (obj interface{}) {
w.mu.Lock() w.mu.Lock()
if w.state != objReleased { if w.state != objReleased {
w.state = objGot w.state = objGot
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
// See COPYING file for full licensing terms. // See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
package main package weak
import ( import (
"runtime" "runtime"
...@@ -58,7 +58,7 @@ func TestWeakRef(t *testing.T) { ...@@ -58,7 +58,7 @@ func TestWeakRef(t *testing.T) {
type T struct { _ [8]int64 } // large enough not to go into tinyalloc type T struct { _ [8]int64 } // large enough not to go into tinyalloc
p := new(T) p := new(T)
w := NewWeakRef(p) w := NewRef(p)
pptr := uintptr(unsafe.Pointer(p)) pptr := uintptr(unsafe.Pointer(p))
assertEq := func(a, b interface{}) { assertEq := func(a, b interface{}) {
......
...@@ -11,15 +11,15 @@ ...@@ -11,15 +11,15 @@
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS // WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
// FOR A PARTICULAR PURPOSE // FOR A PARTICULAR PURPOSE
package main package zodb
// Bits that should be in ZODB XXX -> zodb // persistent objects.
import ( import (
"context" "context"
"sync" "sync"
"lab.nexedi.com/kirr/go123/mem" "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. // IPersistent is the interface that every in-RAM object representing any database object implements.
...@@ -31,11 +31,11 @@ import ( ...@@ -31,11 +31,11 @@ import (
// but is not exactly equal to it. // but is not exactly equal to it.
type IPersistent interface { type IPersistent interface {
PJar() *Connection // Connection this in-RAM object is part of. 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. // object serial in the database as of particular Connection (PJar) view.
// 0 (invalid tid) if not yet loaded (XXX ok?) // 0 (invalid tid) if not yet loaded (XXX ok?)
PSerial() zodb.Tid PSerial() Tid
// PActivate brings object to live state. // PActivate brings object to live state.
...@@ -117,8 +117,8 @@ const ( ...@@ -117,8 +117,8 @@ const (
// Persistent is common base implementation for in-RAM representation of database objects. // Persistent is common base implementation for in-RAM representation of database objects.
type Persistent struct { type Persistent struct {
jar *Connection jar *Connection
oid zodb.Oid oid Oid
serial zodb.Tid serial Tid
mu sync.Mutex mu sync.Mutex
state ObjectState state ObjectState
...@@ -128,8 +128,8 @@ type Persistent struct { ...@@ -128,8 +128,8 @@ type Persistent struct {
} }
func (obj *Persistent) PJar() *Connection { return obj.jar } func (obj *Persistent) PJar() *Connection { return obj.jar }
func (obj *Persistent) POid() zodb.Oid { return obj.oid } func (obj *Persistent) POid() Oid { return obj.oid }
func (obj *Persistent) PSerial() zodb.Tid { return obj.serial } func (obj *Persistent) PSerial() Tid { return obj.serial }
// loadState indicates object's load state/result. // loadState indicates object's load state/result.
// //
...@@ -172,8 +172,8 @@ type Stateful interface { ...@@ -172,8 +172,8 @@ type Stateful interface {
// //
// XXX ^^^ better must be safe - use case: e.g. prefetch. // XXX ^^^ better must be safe - use case: e.g. prefetch.
type Connection struct { type Connection struct {
stor zodb.IStorage // underlying storage stor IStorage // underlying storage
at zodb.Tid // current view of database at Tid // current view of database
// {} oid -> obj // {} oid -> obj
// //
...@@ -223,7 +223,7 @@ type Connection struct { ...@@ -223,7 +223,7 @@ type Connection struct {
// NOTE2 finalizers don't run on when they are attached to an object in cycle. // 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 // Hopefully we don't have cycles with ZBTree/ZBucket XXX verify this
objmu sync.Mutex objmu sync.Mutex
objtab map[zodb.Oid]*WeakRef // oid -> WeakRef(IPersistent) objtab map[Oid]*weak.Ref // oid -> weak.Ref(IPersistent)
// hooks for application to influence live caching decisions. // hooks for application to influence live caching decisions.
cacheControl LiveCacheControl cacheControl LiveCacheControl
...@@ -357,6 +357,6 @@ func (obj *Persistent) PInvalidate() { ...@@ -357,6 +357,6 @@ func (obj *Persistent) PInvalidate() {
// load loads object specified by oid. // load loads object specified by oid.
// //
// XXX must be called ... (XXX e.g. outside transaction boundary) so that there is no race on .at . // 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) { func (conn *Connection) load(ctx context.Context, oid Oid) (_ *mem.Buf, serial Tid, _ error) {
return conn.stor.Load(ctx, zodb.Xid{Oid: oid, At: conn.at}) return conn.stor.Load(ctx, Xid{Oid: oid, At: conn.at})
} }
...@@ -11,15 +11,15 @@ ...@@ -11,15 +11,15 @@
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS // WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
// FOR A PARTICULAR PURPOSE // FOR A PARTICULAR PURPOSE
package main package zodb
// Bits that should be in ZODB XXX -> zodb // Support for python objects/data in ZODB.
import ( import (
"context" "context"
"fmt" "fmt"
"lab.nexedi.com/kirr/go123/mem" "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" pickle "github.com/kisielk/og-rek"
) )
...@@ -70,7 +70,7 @@ func (pyobj *PyPersistent) pyinstance() IPyPersistent { ...@@ -70,7 +70,7 @@ func (pyobj *PyPersistent) pyinstance() IPyPersistent {
} }
func (pyobj *PyPersistent) SetState(state *mem.Buf) error { 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 { if err != nil {
return err // XXX err ctx return err // XXX err ctx
} }
...@@ -94,17 +94,17 @@ type pyClassNewFunc func(base *PyPersistent) IPyPersistent ...@@ -94,17 +94,17 @@ type pyClassNewFunc func(base *PyPersistent) IPyPersistent
// path(pyclass) -> new(pyobj) // path(pyclass) -> new(pyobj)
var pyClassTab = make(map[string]pyClassNewFunc) var pyClassTab = make(map[string]pyClassNewFunc)
// registerPyClass registers python class to be transformed to Go instance // PyRegisterClass registers python class to be transformed to Go instance
// created via classNew. // created via classNew.
// //
// must be called from global init(). // must be called from global init().
func registerPyClass(pyClassPath string, classNew pyClassNewFunc) { func PyRegisterClass(pyClassPath string, classNew pyClassNewFunc) {
pyClassTab[pyClassPath] = classNew 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. // 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{ pyobj := &PyPersistent{
Persistent: Persistent{jar: conn, oid: oid, serial: 0, state: GHOST}, Persistent: Persistent{jar: conn, oid: oid, serial: 0, state: GHOST},
pyclass: pyclass, pyclass: pyclass,
...@@ -151,7 +151,7 @@ func (d *dummyPyInstance) PySetState(pystate interface{}) error { ...@@ -151,7 +151,7 @@ func (d *dummyPyInstance) PySetState(pystate interface{}) error {
// //
// The object's data is not neccessarily loaded after Get returns. Use // The object's data is not neccessarily loaded after Get returns. Use
// PActivate to make sure the object ifs fully loaded. // 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 conn.objmu.Lock() // XXX -> rlock
wobj := conn.objtab[oid] wobj := conn.objtab[oid]
var xobj interface{} var xobj interface{}
...@@ -205,7 +205,7 @@ func (e *wrongClassError) Error() string { ...@@ -205,7 +205,7 @@ func (e *wrongClassError) Error() string {
// //
// Use-case: in ZODB references are (pyclass, oid), so new ghost is created // Use-case: in ZODB references are (pyclass, oid), so new ghost is created
// without further loading anything. // 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 conn.objmu.Lock() // XXX -> rlock
wobj := conn.objtab[oid] wobj := conn.objtab[oid]
var pyobj IPyPersistent var pyobj IPyPersistent
...@@ -217,7 +217,7 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (IPyPersistent, ...@@ -217,7 +217,7 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (IPyPersistent,
} }
if pyobj == nil { if pyobj == nil {
pyobj = conn.newGhost(pyclass, oid) pyobj = conn.newGhost(pyclass, oid)
conn.objtab[oid] = NewWeakRef(pyobj) conn.objtab[oid] = weak.NewRef(pyobj)
} else { } else {
checkClass = true checkClass = true
} }
...@@ -225,7 +225,7 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (IPyPersistent, ...@@ -225,7 +225,7 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (IPyPersistent,
if checkClass { if checkClass {
if cls := pyobj.PyClass(); pyclass != cls { if cls := pyobj.PyClass(); pyclass != cls {
return nil, &zodb.OpError{ return nil, &OpError{
URL: conn.stor.URL(), URL: conn.stor.URL(),
Op: fmt.Sprintf("@%s: get", conn.at), // XXX abuse Op: fmt.Sprintf("@%s: get", conn.at), // XXX abuse
Args: oid, Args: oid,
...@@ -241,15 +241,15 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (IPyPersistent, ...@@ -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. // loadpy does not create any in-RAM object associated with Connection.
// It only returns decoded database data. // 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) { func (conn *Connection) loadpy(ctx context.Context, oid Oid) (pyclass pickle.Class, pystate interface{}, serial Tid, _ error) {
buf, serial, err := conn.stor.Load(ctx, zodb.Xid{Oid: oid, At: conn.at}) buf, serial, err := conn.stor.Load(ctx, Xid{Oid: oid, At: conn.at})
if err != nil { if err != nil {
return pickle.Class{}, nil, 0, err return pickle.Class{}, nil, 0, err
} }
defer buf.Release() defer buf.Release()
pyclass, pystate, err = zodb.PyData(buf.Data).Decode() pyclass, pystate, err = PyData(buf.Data).Decode()
if err != nil { if err != nil {
return pickle.Class{}, nil, 0, err // XXX err ctx return pickle.Class{}, nil, 0, err // XXX err ctx
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment