// Copyright (C) 2016-2017 Nexedi SA and Contributors. // Kirill Smelkov <kirr@nexedi.com> // // This program is free software: you can Use, Study, Modify and Redistribute // it under the terms of the GNU General Public License version 3, or (at your // option) any later version, as published by the Free Software Foundation. // // You can also Link and Combine this program with other software covered by // the terms of any of the Free Software licenses or any of the Open Source // Initiative approved licenses and Convey the resulting work. Corresponding // source of such a combination shall include the source code for all other // software used. // // This program is distributed WITHOUT ANY WARRANTY; without even the implied // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // // See COPYING file for full licensing terms. // See https://www.nexedi.com/licensing for rationale and options. // XXX partly based on ZODB/py // Package zodb defines types, interfaces and errors used in ZODB databases package zodb import ( "fmt" ) // ZODB types type Tid uint64 // transaction identifier type Oid uint64 // object identifier // XTid is "extended" transaction identifier. It defines a transaction for // oid lookup - either exactly by serial, or by < beforeTid. type XTid struct { Tid TidBefore bool // XXX merge into Tid itself (high bit) ? } // Xid is "extended" oid = oid + serial/beforeTid, completely specifying object address. type Xid struct { XTid Oid } const ( //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 // XXX do we need distinction in between ErrOidMissing & ErrXidMissing ? // (think how client should handle error from Load ?) type ErrOidMissing struct { Oid Oid } func (e ErrOidMissing) Error() string { return fmt.Sprintf("%v: no such oid", e.Oid) } // ErrXidMissing is an error which tells that oid exists in the database, // but there is no its revision satisfying xid.XTid search criteria. type ErrXidMissing struct { Xid Xid } func (e *ErrXidMissing) Error() string { return fmt.Sprintf("%v: no matching data record found", e.Xid) } // ---------------------------------------- // 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 { // StorageName returns storage name StorageName() string // Close closes storage Close() error // History(oid, size=1) // LastTid returns the id of the last committed transaction. // if no transactions have been committed yet, LastTid returns Tid zero value LastTid() (Tid, error) // 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 LastOid() (Oid, error) // LoadSerial and LoadBefore generalized into 1 Load (see Xid for details) // TODO data []byte -> something allocated from slab ? // XXX currently deleted data is returned as data=nil -- is it ok? // TODO specify error when data not found Load(xid Xid) (data []byte, tid Tid, err error) // XXX -> StorageRecordInformation ? // -> Prefetch(xid Xid) ... // PrefetchBefore(oidv []Oid, beforeTid Tid) error (?) // Store(oid Oid, serial Tid, data []byte, txn ITransaction) error // XXX Restore ? // CheckCurrentSerialInTransaction(oid Oid, serial Tid, txn ITransaction) // XXX naming // tpc_begin(txn) // tpc_vote(txn) // tpc_finish(txn, callback) XXX clarify about callback // tpc_abort(txn) // XXX text Iterate(tidMin, tidMax Tid) IStorageIterator // XXX , error ? } type IStorageIterator interface { // NextTxn yields information about next database transaction: // 1. transaction metadata, and // 2. iterator over transaction data records. // transaction metadata stays valid until next call to NextTxn(). // end of iteration is indicated with io.EOF NextTxn() (*TxnInfo, IStorageRecordIterator, error) } type IStorageRecordIterator interface { // XXX naming -> IRecordIterator // NextData yields information about next storage data record. // returned data stays valid until next call to NextData(). // end of iteration is indicated with io.EOF NextData() (*StorageRecordInformation, error) }