Commit c31c4855 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 2f8b5e03
......@@ -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() {
registerPyClass("zodb.BTree.LOBucket", bucketNew)
registerPyClass("zodb.BTree.LOBtree", btreeNew)
zodb.PyRegisterClass("zodb.BTree.LOBucket", bucketNew)
zodb.PyRegisterClass("zodb.BTree.LOBtree", btreeNew)
}
......@@ -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 WeakRef points to.
// weakRefState represents current state of an object Ref points to.
type weakRefState int32
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
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.
// Weak references must not be attached to an object on which runtime.SetFinalizer is also used.
// Weak references must not be copied.
type WeakRef struct {
type Ref struct {
iface
// XXX try to do without mutex and only with atomics
......@@ -65,14 +63,14 @@ type WeakRef struct {
state weakRefState
}
// NewWeakRef creates new weak reference pointing to obj.
// NewRef creates new weak reference pointing to obj.
//
// 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
// pointers to uintptr and that won't prevent GC from garbage
// collecting the object.
w := &WeakRef{
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, 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
// 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 *WeakRef) Get() (obj interface{}) {
func (w *Ref) Get() (obj interface{}) {
w.mu.Lock()
if w.state != objReleased {
w.state = objGot
......
......@@ -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 := NewWeakRef(p)
w := NewRef(p)
pptr := uintptr(unsafe.Pointer(p))
assertEq := func(a, b interface{}) {
......
......@@ -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 -> WeakRef(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})
}
......@@ -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)
// registerPyClass registers python class to be transformed to Go instance
// PyRegisterClass registers python class to be transformed to Go instance
// created via classNew.
//
// must be called from global init().
func registerPyClass(pyClassPath string, classNew pyClassNewFunc) {
func PyRegisterClass(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] = NewWeakRef(pyobj)
conn.objtab[oid] = weak.NewRef(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
}
......
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