Commit e6d7a736 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 89583030
...@@ -38,8 +38,9 @@ import ( ...@@ -38,8 +38,9 @@ import (
type PyData []byte type PyData []byte
// ClassName returns fully-qualified python class name used for object type. // ClassName returns fully-qualified python class name used for object type.
//
// The format is "module.class". // The format is "module.class".
// If pickle decoding fails "?.?" is returned. // If pickle decoding fails - "?.?" is returned.
func (d PyData) ClassName() string { func (d PyData) ClassName() string {
// see ObjectReader.getClassName & get_pickle_metadata in zodb/py // see ObjectReader.getClassName & get_pickle_metadata in zodb/py
p := pickle.NewDecoder(bytes.NewReader([]byte(d))) p := pickle.NewDecoder(bytes.NewReader([]byte(d)))
......
...@@ -54,6 +54,7 @@ type Dumper interface { ...@@ -54,6 +54,7 @@ type Dumper interface {
} }
// Dump dumps content of a FileStorage file @ path. // Dump dumps content of a FileStorage file @ path.
//
// To do so it reads file header and then iterates over all transactions in the file. // To do so it reads file header and then iterates over all transactions in the file.
// The logic to actually output information and, if needed read/process data, is implemented by Dumper d. // The logic to actually output information and, if needed read/process data, is implemented by Dumper d.
func Dump(w io.Writer, path string, dir fs1.IterDir, d Dumper) (err error) { func Dump(w io.Writer, path string, dir fs1.IterDir, d Dumper) (err error) {
...@@ -132,7 +133,6 @@ type DumperFsDump struct { ...@@ -132,7 +133,6 @@ type DumperFsDump struct {
// for loading data // for loading data
dhLoading fs1.DataHeader dhLoading fs1.DataHeader
// data []byte
} }
func (d *DumperFsDump) DumperName() string { func (d *DumperFsDump) DumperName() string {
...@@ -174,31 +174,27 @@ func (d *DumperFsDump) DumpTxn(buf *xfmt.Buffer, it *fs1.Iter) error { ...@@ -174,31 +174,27 @@ func (d *DumperFsDump) DumpTxn(buf *xfmt.Buffer, it *fs1.Iter) error {
// load actual data // load actual data
d.dhLoading = *dh d.dhLoading = *dh
dataBuf, err := d.dhLoading.LoadData(it.R) dbuf, err := d.dhLoading.LoadData(it.R)
if err != nil { if err != nil {
return err return err
} }
if dataBuf == nil { if dbuf.Data == nil {
buf .S(" class=undo or abort of object creation") buf .S(" class=undo or abort of object creation")
} else { } else {
fullclass := zodb.PyData(dataBuf.Data).ClassName() fullclass := zodb.PyData(dbuf.Data).ClassName()
buf .S(" size=") .D64(d.dhLoading.DataLen) buf .S(" size=") .D64(d.dhLoading.DataLen)
buf .S(" class=") .S(fullclass) buf .S(" class=") .S(fullclass)
} }
if dh.DataLen == 0 && dataBuf != nil { if dh.DataLen == 0 && dbuf.Data != nil {
// it was backpointer - print tid of transaction it points to // it was backpointer - print tid of transaction it points to
buf .S(" bp=") .V(d.dhLoading.Tid) buf .S(" bp=") .V(d.dhLoading.Tid)
} }
// XXX avoid `if != nil`
if dataBuf != nil {
dataBuf.Free()
}
buf .S("\n") buf .S("\n")
dbuf.Free()
} }
return nil return nil
......
...@@ -155,6 +155,7 @@ Error: ...@@ -155,6 +155,7 @@ Error:
} }
// ParseTidRange parses string of form "<tidmin>..<tidmax>" into tidMin, tidMax pair // ParseTidRange parses string of form "<tidmin>..<tidmax>" into tidMin, tidMax pair
//
// both <tidmin> and <tidmax> can be empty, in which case defaults 0 and TidMax are returned // both <tidmin> and <tidmax> can be empty, in which case defaults 0 and TidMax are returned
// XXX also check tidMin < tidMax here? or allow reverse ranges ? // XXX also check tidMin < tidMax here? or allow reverse ranges ?
func ParseTidRange(s string) (tidMin, tidMax Tid, err error) { func ParseTidRange(s string) (tidMin, tidMax Tid, err error) {
......
...@@ -26,7 +26,7 @@ import ( ...@@ -26,7 +26,7 @@ import (
// TimeStamp is the same as time.Time only .String() is adjusted to be the same as in ZODB/py. // TimeStamp is the same as time.Time only .String() is adjusted to be the same as in ZODB/py.
// //
// XXX get rid eventually of this // XXX get rid eventually of this and just use time.Time.
type TimeStamp struct { type TimeStamp struct {
time.Time time.Time
} }
......
...@@ -17,9 +17,12 @@ ...@@ -17,9 +17,12 @@
// 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.
// XXX partly based on ZODB/py // Package zodb defines types, interfaces and errors to work with ZODB databases.
//
// Package zodb defines types, interfaces and errors used in ZODB databases // ZODB (http://zodb.org) was originally created in Python world by Jim Fulton et al.
// Data model this package provides is partly based on ZODB/py
// (https://github.com/zopefoundation/ZODB) to maintain compatibility in
// between Python and Go implementations.
package zodb package zodb
import ( import (
...@@ -27,12 +30,65 @@ import ( ...@@ -27,12 +30,65 @@ import (
"fmt" "fmt"
) )
// ZODB types // ---- data model ----
type Tid uint64 // transaction identifier
type Oid uint64 // object identifier // Tid is transaction identifier.
//
// In ZODB transaction identifiers are unique 64-bit integer connected to time
// when corresponding transaction was created.
type Tid uint64
// ZODB/py defines maxtid to be max signed int64 since baee84a6 (Jun 7 2016)
// (XXX in neo: SQLite does not accept numbers above 2^63-1)
const TidMax Tid = 1<<63 - 1 // 0x7fffffffffffffff
// XTid is "extended" transaction identifier. It defines a transaction for // Oid is object identifier.
// oid lookup - either exactly by serial, or by < beforeTid. //
// In ZODB objects are uniquely identified by 64-bit integer.
// Every object can have several revisions - each committed in different transaction.
// The combination of object identifier and particular transaction (serial)
// uniquely addresses corresponding data record.
//
// See also: Xid.
type Oid uint64
// TxnMeta is metadata information about one transaction.
type TxnMeta struct {
Tid Tid
Status TxnStatus
User []byte
Description []byte
Extension []byte
}
// XXX +TxnInfo = TxnMeta + []DataInfo ?
// DataInfo represents information about one data record.
type DataInfo struct {
Oid Oid
Tid Tid
Data []byte // nil means: deleted XXX -> *Buf ?
// original tid data was committed (e.g. in case of undo)
//
// FIXME we don't really need this and this unnecessarily constraints interfaces.
DataTid Tid
}
// TxnStatus represents status of a transaction
type TxnStatus byte
const (
TxnComplete TxnStatus = ' ' // completed transaction that hasn't been packed
TxnPacked = 'p' // completed transaction that has been packed
TxnInprogress = 'c' // checkpoint -- a transaction in progress; it's been thru vote() but not finish()
)
// XTid is "extended" transaction identifier.
//
// It defines a transaction for oid lookup - either exactly by serial, or by < beforeTid.
type XTid struct { type XTid struct {
Tid Tid
TidBefore bool // XXX merge into Tid itself (high bit) ? TidBefore bool // XXX merge into Tid itself (high bit) ?
...@@ -46,27 +102,10 @@ type Xid struct { ...@@ -46,27 +102,10 @@ type Xid struct {
// XXX add XidBefore() and XidSerial() as syntax convenience? // XXX add XidBefore() and XidSerial() as syntax convenience?
const ( // ---- interfaces ----
//Tid0 Tid = 0 // XXX -> simply Tid(0) ?
TidMax Tid = 1<<63 - 1 // 0x7fffffffffffffff
// ZODB defines maxtid to be max signed int64 since baee84a6 (Jun 7 2016)
// (XXX in neo: SQLite does not accept numbers above 2^63-1)
//Oid0 Oid = 0 // XXX -> simply Oid(0)
)
func (tid Tid) Valid() bool {
// XXX if Tid becomes signed also check wrt 0
if tid <= TidMax {
return true
} else {
return false
}
}
// ----------------------------------------
// ErrOidMissing is an error which tells that there is no such oid in the database at all // ErrOidMissing is an error which tells that there is no such oid in the database at all
//
// XXX do we need distinction in between ErrOidMissing & ErrXidMissing ? // XXX do we need distinction in between ErrOidMissing & ErrXidMissing ?
// (think how client should handle error from Load ?) // (think how client should handle error from Load ?)
type ErrOidMissing struct { type ErrOidMissing struct {
...@@ -87,51 +126,7 @@ func (e *ErrXidMissing) Error() string { ...@@ -87,51 +126,7 @@ func (e *ErrXidMissing) Error() string {
return fmt.Sprintf("%v: no matching data record found", e.Xid) return fmt.Sprintf("%v: no matching data record found", e.Xid)
} }
// ---------------------------------------- // IStorage is the interface provided by ZODB storages
// TxnStatus represents status of a transaction
type TxnStatus byte
const (
TxnComplete TxnStatus = ' ' // completed transaction that hasn't been packed
TxnPacked = 'p' // completed transaction that has been packed
TxnInprogress = 'c' // checkpoint -- a transaction in progress; it's been thru vote() but not finish()
)
// Valid returns true if transaction status value is well-known and valid
func (ts TxnStatus) Valid() bool {
switch ts {
case TxnComplete, TxnPacked, TxnInprogress:
return true
default:
return false
}
}
// Metadata information about single transaction
type TxnInfo struct {
Tid Tid
Status TxnStatus
User []byte
Description []byte
Extension []byte
}
// Information about single storage record
// XXX naming
type StorageRecordInformation struct {
Oid Oid
Tid Tid
Data []byte // nil means: deleted
// original tid data was committed (e.g. in case of undo)
// XXX we don't really need this
DataTid Tid
}
type IStorage interface { type IStorage interface {
// XXX add invalidation channel // XXX add invalidation channel
...@@ -141,24 +136,30 @@ type IStorage interface { ...@@ -141,24 +136,30 @@ type IStorage interface {
// Close closes storage // Close closes storage
Close() error Close() error
// History(oid, size=1) // History(ctx, oid, size=1)
// LastTid returns the id of the last committed transaction. // LastTid returns the id of the last committed transaction.
//
// if no transactions have been committed yet, LastTid returns Tid zero value // if no transactions have been committed yet, LastTid returns Tid zero value
LastTid(ctx context.Context) (Tid, error) LastTid(ctx context.Context) (Tid, error)
// LastOid returns highest object id of objects committed to storage. // LastOid returns highest object id of objects committed to storage.
// if there is no data committed yet, LastOid returns Oid zero value //
// XXX ZODB/py does not define this in IStorage // if there is no data committed yet, LastOid returns Oid zero value XXX -> better -1
// XXX ZODB/py does not define this in IStorage.
LastOid(ctx context.Context) (Oid, error) LastOid(ctx context.Context) (Oid, error)
// LoadSerial and LoadBefore generalized into 1 Load (see Xid for details) // Load loads data from database.
// //
// XXX zodb.loadBefore() returns (data, serial, serial_next) -> add serial_next? // The object to load is addressed by xid.
// //
// XXX currently deleted data is returned as data.Data=nil -- is it ok? // NOTE ZODB/py provides 2 entrypoints in IStorage: LoadSerial and
// LoadBefore. Load generalizes them into one (see Xid for details).
//
// XXX zodb.loadBefore() returns (data, serial, serial_next) -> add serial_next?
// XXX currently deleted data is returned as buf.Data=nil -- is it ok?
// TODO specify error when data not found -> ErrOidMissing | ErrXidMissing // TODO specify error when data not found -> ErrOidMissing | ErrXidMissing
Load(ctx context.Context, xid Xid) (data *Buf, serial Tid, err error) // XXX -> StorageRecordInformation ? Load(ctx context.Context, xid Xid) (buf *Buf, serial Tid, err error) // XXX -> DataInfo ?
// Prefetch(ctx, xid Xid) (no error) // Prefetch(ctx, xid Xid) (no error)
...@@ -171,23 +172,49 @@ type IStorage interface { ...@@ -171,23 +172,49 @@ type IStorage interface {
// tpc_finish(txn, callback) XXX clarify about callback // tpc_finish(txn, callback) XXX clarify about callback
// tpc_abort(txn) // tpc_abort(txn)
// Iterate creates iterator to iterate storage in [tidMin, tidMax] range.
//
// XXX allow iteration both ways (forward & backward) // XXX allow iteration both ways (forward & backward)
// XXX text Iterate(tidMin, tidMax Tid) ITxnIterator // XXX ctx , error ?
Iterate(tidMin, tidMax Tid) IStorageIterator // XXX ctx , error ?
} }
type IStorageIterator interface { // ITxnIterator is the interface to iterate transactions.
type ITxnIterator interface {
// NextTxn yields information about next database transaction: // NextTxn yields information about next database transaction:
// 1. transaction metadata, and // 1. transaction metadata, and
// 2. iterator over transaction data records. // 2. iterator over transaction's data records.
// transaction metadata stays valid until next call to NextTxn(). // transaction metadata stays valid until next call to NextTxn().
// end of iteration is indicated with io.EOF // end of iteration is indicated with io.EOF
NextTxn() (*TxnInfo, IStorageRecordIterator, error) // XXX ctx NextTxn() (*TxnMeta, IDataIterator, error) // XXX ctx
} }
type IStorageRecordIterator interface { // XXX naming -> IRecordIterator // IDataIterator is the interface to iterate data records.
type IDataIterator interface {
// NextData yields information about next storage data record. // NextData yields information about next storage data record.
// returned data stays valid until next call to NextData(). // returned data stays valid until next call to NextData().
// end of iteration is indicated with io.EOF // end of iteration is indicated with io.EOF
NextData() (*StorageRecordInformation, error) // XXX ctx NextData() (*DataInfo, error) // XXX ctx
}
// ---- misc ----
// Valid returns whether tid is in valid transaction identifiers range
func (tid Tid) Valid() bool {
// XXX if Tid becomes signed also check wrt 0
if tid <= TidMax {
return true
} else {
return false
}
}
// Valid returns true if transaction status value is well-known and valid
func (ts TxnStatus) Valid() bool {
switch ts {
case TxnComplete, TxnPacked, TxnInprogress:
return true
default:
return false
}
} }
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