Commit 11681541 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 1d321353
// 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 btree provides support for working with ZODB BTrees.
//
// XXX
//
// XXX name -> zbtree ?
package btree
import (
"context"
"sort"
"lab.nexedi.com/kirr/neo/go/zodb"
)
// XXX temp
type KEY int64
// Bucket mimics ?OBucket from btree/py, with ? being any integer.
//
// original py description:
//
// A Bucket wraps contiguous vectors of keys and values. Keys are unique,
// and stored in sorted order. The 'values' pointer may be NULL if the
// Bucket is used to implement a set. Buckets serving as leafs of BTrees
// are chained together via 'next', so that the entire BTree contents
// can be traversed in sorted order quickly and easily.
type Bucket struct {
pyobj *zodb.PyObject
next *Bucket // the bucket with the next-larger keys
keys []KEY // 'len' keys, in increasing order
values []interface{} // 'len' corresponding values XXX merge k/v ?
}
// zBTreeItem mimics BTreeItem from btree/py.
type zBTreeItem struct {
key KEY
child interface{} // BTree or Bucket
}
// BTree mimics ?OBTree from btree/py, with ? being any integer.
//
// See https://github.com/zopefoundation/BTrees/blob/4.5.0-1-gc8bf24e/BTrees/Development.txt#L198
// for details.
type BTree struct {
pyobj *zodb.PyObject
// firstbucket points to the bucket containing the smallest key in
// the BTree. This is found by traversing leftmost child pointers
// (data[0].child) until reaching a Bucket.
firstbucket *Bucket
// The BTree points to 'len' children, via the "child" fields of the data
// array. There are len-1 keys in the 'key' fields, stored in increasing
// order. data[0].key is unused. For i in 0 .. len-1, all keys reachable
// from data[i].child are >= data[i].key and < data[i+1].key, at the
// endpoints pretending that data[0].key is minus infinity and
// data[len].key is positive infinity.
data []zBTreeItem
}
// Get searches BTree by key.
//
// It loads intermediate BTree nodes from database on demand as needed.
// XXX ok -> ErrKeyNotFound?
func (t *BTree) Get(ctx context.Context, key KEY) (interface{}, bool, error) {
t.PActivate(ctx) // XXX err
if len(t.data) == 0 {
// empty btree
return nil, false, nil
}
for {
// search i: K(i) ≤ k < K(i+1) ; K(0) = -∞, K(len) = +∞
i := sort.Search(len(t.data), func(i int) bool {
j := i + 1
if j == len(t.data) {
return true // [len].key = +∞
}
return key < t.data[j].key
})
switch child := t.data[i].child.(type) {
case *BTree:
// XXX t.PAllowDeactivate
t = child
t.PActivate(ctx) // XXX err
case *Bucket:
child.PActivate(ctx) // XXX err
x, ok := child.get(key)
return x, ok, nil
}
}
}
// get searches Bucket by key.
//
// no loading from database is done. The bucket must be already activated.
func (b *Bucket) get(key KEY) (interface{}, bool) {
// XXX b.PActivate ? XXX better caller? (or inside if get -> Get)
// search i: K(i-1) < k ≤ K(i) ; K(-1) = -∞, K(len) = +∞
i := sort.Search(len(b.keys), func(i int) bool {
return key <= b.keys[i]
})
if i == len(b.keys) || b.keys[i] != key {
return nil, false // not found
}
return b.values[i], true
}
// from https://github.com/zopefoundation/BTrees/blob/4.5.0-1-gc8bf24e/BTrees/BTreeTemplate.c#L1087:
//
// For an empty BTree (self->len == 0), None.
//
// For a BTree with one child (self->len == 1), and that child is a bucket,
// and that bucket has a NULL oid, a one-tuple containing a one-tuple
// containing the bucket's state:
//
// (
// (
// child[0].__getstate__(),
// ),
// )
//
// Else a two-tuple. The first element is a tuple interleaving the BTree's
// keys and direct children, of size 2*self->len - 1 (key[0] is unused and
// is not saved). The second element is the firstbucket:
//
// (
// (child[0], key[1], child[1], key[2], child[2], ...,
// key[len-1], child[len-1]),
// self->firstbucket
// )
//
// In the above, key[i] means self->data[i].key, and similarly for child[i].
// XXX Bucket.MinKey ?
// XXX Bucket.MaxKey ?
// from https://github.com/zopefoundation/BTrees/blob/4.5.0-1-gc8bf24e/BTrees/BucketTemplate.c#L1195:
//
// For a mapping bucket (self->values is not NULL), a one-tuple or two-tuple.
// The first element is a tuple interleaving keys and values, of length
// 2 * self->len. The second element is the next bucket, present iff next is
// non-NULL:
//
// (
// (keys[0], values[0], keys[1], values[1], ...,
// keys[len-1], values[len-1]),
// <self->next iff non-NULL>
// )
......@@ -28,64 +28,6 @@ import (
pickle "github.com/kisielk/og-rek"
)
/*
// XXX move out of py
// Object is in-process representaion of a ZODB object.
type Object interface {
Jar() *Connection
Oid() Oid
Serial() Tid
Data() *mem.Buf // XXX for raw, py -> PyObject
// XXX register(jar, oid) - register to database ? (for Connection.Add)
// PActivate
// PDeactivate
// PInvalidate
}
// XXX
type DataManager interface {
//LoadObject(obj Object)
//LoadObject(oid Oid)
LoadState(obj)
// XXX oldstate(oid, tid)
// XXX register(obj)
}
// Connection represent client-visible part of a connection to ZODB database.
//
// XXX consitent view for some `at`.
// XXX not needed? (just DB.Open() -> root object and connection not be visible)?
type Connection interface {
// Get returns object by oid.
// XXX multiple calls to Get with same oid return the same object.
// XXX root object has oid=0.
Get(ctx context.Context, oid Oid) (Object, error)
// XXX Add(obj Object) -> add obj to database and assign it an oid
// obj must be not yet added
// XXX ReadCurrent(obj)
// XXX Close() error
}
*/
// PyData represents raw data stored into ZODB by Python applications.
//
// The format is based on python pickles. Basically every serialized object has
......@@ -104,28 +46,6 @@ type PyData []byte
//}
// XXX + String = Module + "." + Name
/*
// PyObject represents persistent Python object.
//
// PyObject can be decoded from PyData. XXX
type PyObject struct {
//Jar *Connection // XXX -> ro
Oid Oid // XXX -> ro
Serial Tid // XXX -> ro
// XXX + Oid, Serial ? (_p_oid, _p_serial)
PyClass pickle.Class // python class of this object XXX -> ro ?
PyState interface{} // object state. python passes this to pyclass.__new__().__setstate__()
}
// PyLoader is like Loader by returns decoded Python objects instead of raw data.
type PyLoader interface {
// XXX returned pyobject, contrary to Loader, can be modified, because
// it is not shared. right?
Load(ctx, xid Xid) (*PyObject, error)
}
*/
// Decode decodes raw ZODB python data into Python class and state.
......
......@@ -87,6 +87,8 @@ import (
// This way tid can also be used to specify whole database state constructed
// by all cumulated transaction changes from database beginning up to, and
// including, transaction specified by tid.
//
// 0 is invalid Tid.
type Tid uint64
// ZODB/py defines maxtid to be max signed int64 since Jun 7 2016:
......@@ -102,6 +104,8 @@ const TidMax Tid = 1<<63 - 1 // 0x7fffffffffffffff
// The combination of object identifier and particular transaction (serial)
// uniquely addresses corresponding data record.
//
// 0 is valid Oid and represents root database object.
//
// See also: Xid.
type Oid uint64
......@@ -191,7 +195,7 @@ func (e *NoDataError) Error() string {
}
}
// OpError is the error returned by IStorageDriver operations
// OpError is the error returned by IStorageDriver operations.
type OpError struct {
URL string // URL of the storage
Op string // operation that failed
......@@ -213,16 +217,14 @@ func (e *OpError) Cause() error {
}
// IStorage is the interface provided by opened ZODB storage
// IStorage is the interface provided by opened ZODB storage.
type IStorage interface {
IStorageDriver
//Loader
Prefetcher
//Iterator
}
// XXX
// Prefetcher provides functionality to prefetch objects.
type Prefetcher interface {
// Prefetch prefetches object addressed by xid.
//
......@@ -235,7 +237,7 @@ type Prefetcher interface {
Prefetch(ctx context.Context, xid Xid)
}
// IStorageDriver is the raw interface provided by ZODB storage drivers
// IStorageDriver is the raw interface provided by ZODB storage drivers.
type IStorageDriver interface {
// URL returns URL of how the storage was opened
URL() string
......@@ -252,7 +254,7 @@ type IStorageDriver interface {
Iterator
}
// Loader exposes functionality to load objects.
// Loader provides functionality to load objects.
type Loader interface {
// Load loads object data addressed by xid from database.
//
......@@ -299,7 +301,7 @@ type Loader interface {
Load(ctx context.Context, xid Xid) (buf *mem.Buf, serial Tid, err error)
}
// Committer exposes functionality to commit transactions.
// Committer provides functionality to commit transactions.
type Committer interface {
// TODO: write mode
......
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