Commit 6e858c16 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 6c9c45ec
......@@ -12,10 +12,11 @@
// FOR A PARTICULAR PURPOSE
package main
// ZODB BTree handling
// ZODB BTree handling XXX -> zodb
import (
"context"
"sort"
"lab.nexedi.com/kirr/neo/go/zodb"
)
......@@ -98,7 +99,8 @@ func (t *ZBTree) Get(ctx context.Context, key KEY) (interface{}, bool, error) {
case *ZBucket:
child.PActivate(ctx) // XXX err
return child.Get(key), nil
v, ok := child.get(key)
return v, ok, nil
}
}
}
......@@ -111,7 +113,7 @@ func (b *ZBucket) get(key KEY) (interface{}, bool) {
// search i: K(i-1) < k ≤ K(i) ; K(-1) = -∞, K(len) = +∞
i := sort.Search(len(b.keys), func(i int) bool {
return key <= t.data[i].key
return key <= b.keys[i]
})
if i == len(b.keys) || b.keys[i] != key {
......@@ -147,8 +149,14 @@ func (b *ZBucket) get(key KEY) (interface{}, bool) {
//
// In the above, key[i] means self->data[i].key, and similarly for child[i].
func (t *ZBTree) PDeactivate() {
// XXX check if activated?
t.firstbucket = nil
t.data = nil
t.pyobj.PDeactivate()
}
// XXX ZBTree.Get(key)
// XXX ZBucket.MinKey ?
// XXX ZBucket.MaxKey ?
......@@ -166,3 +174,54 @@ func (b *ZBucket) get(key KEY) (interface{}, bool) {
// keys[len-1], values[len-1]),
// <self->next iff non-NULL>
// )
func (b *ZBucket) PDeactivate() {
// XXX check if activated
b.next = nil
b.keys = nil
b.values = nil
b.pyobj.PDeactivate()
}
func (b *ZBucket) PActivate(ctx context.Context) error {
// XXX check if already activated
err := b.pyobj.PActivate(ctx)
if err != nil {
return err
}
t, ok := b.pyobj.pystate.(pickle.Tuple)
if !ok || !(1 <= len(q) && len(q) <= 2) {
// XXX complain
}
// .next present
if len(t) == 2 {
next, ok := t[1].(*ZBucket)
// XXX if !ok
b.next = next
}
// main part
t, ok = t[0].(picklet.Tuple)
// XXX if !ok || (len(t) % 2 != 0)
// reset arrays just in case
n := len(t) / 2
t.keys = make([]KEY, 0, n)
t.values = make([]interface{}, 0, n)
for i := 0; i < n; i++ {
xk := t[2*i]
v := t[2*i+1]
k, ok := xk.(int64) // XXX use KEY
// XXX if !ok
t.keys = append(t.keys, k)
t.values = append(t.values, v)
}
}
// Copyright (c) 2001, 2002 Zope Foundation and Contributors.
// All Rights Reserved.
//
// This software is subject to the provisions of the Zope Public License,
// Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
// FOR A PARTICULAR PURPOSE
//
// XXX clarify on licensing (ZPL for BTrees)
//
// Copyright (C) 2018 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
......@@ -59,6 +47,7 @@ type ZBigFile struct {
// module of Wendelin ZODB py objects
const zwendelin = "wendelin.bigfile.file_zodb"
/*
// loadZBigFile loads ZBigFile object from specified oid.
func (conn *zpyconn) loadZBigFile(ctx context.Context, oid zodb.Oid) (*ZBigFile, error) {
// ZBigFile
......@@ -101,3 +90,71 @@ func (conn *zpyconn) loadZBigFile(ctx context.Context, oid zodb.Oid) (*ZBigFile,
// XXX ok
}
*/
func (bf *ZBigFile) PDeactivate() {
if bf.blktab == nil {
return
}
bf.blksize = -1
bf.blktab = nil
bf.pyobj.PDeactivate()
}
func (bf *ZBigFile) PActivate(ctx context.Context) (err error) {
if bf.blktab != nil {
return nil
}
err = bf.pyobj.PActivate(ctx)
if err != nil {
return err
}
defer func() {
if err != nil {
// decoding went wrong
}
}()
// decode pystate
t, ok := pyobj.PyState.(pickle.Tuple)
if !ok || len(t) != 2 {
// XXX expected (.blksize, blktab)
}
blksize, ok = pickletools.Xint64(t[0])
// XXX if !ok
blktab, ok := t[1].(*ZBTree)
// XXX if !ok
bf.blksize = blksize
bf.blktab = blktab
return nil
}
// XXX -> newGhost
/*
tabref, ok := t[1].(pickle.Ref)
// XXX if !ok
t, ok = tabref.Pid.(pickle.Tuple)
if !ok || len(t) != 2 {
// XXX expected (oid, LOBTree)
}
taboid, err = decodeOID(t[0])
// XXX err
lobtreeClass := pickle.Class{Module: "BTrees.LOBTree", Name: "LOBTree"}
if t[1] != lobtreeClass {
// XXX err
}
*/
// Copyright (c) 2001, 2002 Zope Foundation and Contributors.
// All Rights Reserved.
//
// Copyright (C) 2018 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This software is subject to the provisions of the Zope Public License,
// Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
// FOR A PARTICULAR PURPOSE
package main
// Bits that should be in ZODB XXX -> zodb
import (
"context"
"lab.nexedi.com/kirr/neo/go/zodb"
pickle "github.com/kisielk/og-rek"
)
type Object struct {
jar *Connection
oid zodb.Oid
serial zodb.Tid
}
type PyObject struct {
Object
pyclass pickle.Class // python class of this object
pystate interface{} // object state. python passes this to pyclass.__new__().__setstate__()
}
// Connection represents a view of ZODB database.
//
// XXX Connection, and {Py}Object methods that relate to it, are not safe for
// modifications from multiple goroutines simultaneously.
type Connection struct {
stor zodb.IStorage // underlying storage
at zodb.Tid // current view of database
}
// Gets loads and decodes object from the database according to its current view.
//
// 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.
func (conn *Connection) Get(ctx context.Context, oid zodb.Oid) (*PyObject, error) {
buf, serial, err := stor.Load(ctx, zodb.Xid{Oid: oid, At: conn.at})
if err != nil {
return nil, err
}
pyclass, pystate, err := zodb.PyData(buf.Data()).Decode()
if err != nil {
return nil, err // XXX err ctx
}
buf.Release()
return &PyObject{
Object: Object{jar: conn,oid: oid, serial: serial},
pyclass: pyclass,
pystate: pystate,
}, nil
}
func (conn *Connection) loadpy(ctx context.Context, oid zodb.Oid) (pyclass pickle.Class, pystate interface{}, serial zodb.Tid, _ error) {
buf, serial, err := stor.Load(ctx, zodb.Xid{Oid: oid, At: conn.at})
if err != nil {
return nil, err
}
pyclass, pystate, err := zodb.PyData(buf.Data()).Decode()
if err != nil {
return nil, err // XXX err ctx
}
buf.Release()
return pyclass, pystate, serial, nil
}
// newGhost creates new ghost object.
func (conn *Connection) newGhost(pyclass pickle.Class, oid zodb.Oid) interface{} {
pyobj := PyObject{
Object: Object{jar: conn, oid: oid, serial: zodb.InvalidTID},
pyclass: pyclass,
pystate: nil,
}
// TODO switch on pyclass and transform e.g. "zodb.BTree.Bucket" -> *ZBucket
return &pyobj
}
// PDeactivates transforms object to ghost state.
//
// In ghost state object data is dropped and only oid/pyclass information is left in RAM.
//
// XXX if state=modified PDeactivate must be noop.
func (pyobj *PyObject) PDeactivate() {
pyobj.pystate = nil
pyobj.serial = zodb.InvalidTID
}
// PActivate brings object to live state.
//
// If object state is not in RAM - it is loaded from the database.
func (pyobj *PyObject) PActivate(ctx context.Context) error {
if pyobj.pystate != nil {
return nil // already loaded
}
pyclass, pystate, serial, err := pyobj.jar.loadpy(ctx, pyobj.oid)
if err != nil {
return err
}
if pyclass != pyobj.pyclass {
// XXX complain pyclass changed
// XXX both ref and object data uses pyclass so it indeed can be different
}
pyobj.serial = serial
pyobj.pystate = pystate
}
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