Commit e6f9c797 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 929332cd
...@@ -41,14 +41,19 @@ var _ zodb.IStorage = (*FileStorage)(nil) ...@@ -41,14 +41,19 @@ var _ zodb.IStorage = (*FileStorage)(nil)
// TxnHeader represents header of a transaction record // TxnHeader represents header of a transaction record
type TxnHeader struct { type TxnHeader struct {
// XXX consider reorder with zodb.TxnInfo ? // XXX -> TxnPos, TxnLen, PrevTxnLen ?
PrevRecLenm8 uint64 // 0 if no previous record Pos int64 // position of transaction start
RecLenm8 uint64 PrevLen int64 // whole previous transaction record length
// (0 if there is no previous txn record)
Len int64 // whole transaction record length
// XXX recheck ^^^ Len are validated on load
// transaction metadata tself
zodb.TxnInfo zodb.TxnInfo
// underlying storage for user/desc/extension // underlying storage for user/desc/extension
stringsRam []byte stringsMem []byte
} }
const ( const (
...@@ -100,23 +105,26 @@ func (e *ErrDataRecord) Error() string { ...@@ -100,23 +105,26 @@ func (e *ErrDataRecord) Error() string {
var ErrVersionNonZero = errors.New("non-zero version") var ErrVersionNonZero = errors.New("non-zero version")
// decode reads and decodes transaction record header from a readerAt // load reads and decodes transaction record header from a readerAt
// pos: points to header begin XXX text // pos: points to header begin XXX text
// no requirements are made to previous th state XXX text // no requirements are made to previous th state XXX text
// XXX io.ReaderAt -> *os.File (if iface conv costly) // XXX io.ReaderAt -> *os.File (if iface conv costly)
func (th *TxnHeader) decode(r io.ReaderAt, pos int64, tmpBuf *[txnXHeaderFixSize]byte) (n int, err error) { //func (th *TxnHeader) load(r io.ReaderAt, pos int64, tmpBuf *[txnXHeaderFixSize]byte) (n int, err error) {
func (th *TxnHeader) load(r io.ReaderAt, pos int64, tmpBuf *[txnXHeaderFixSize]byte) error {
th.Pos = pos
if pos > 4 + 8 { // XXX -> magic if pos > 4 + 8 { // XXX -> magic
// read together with previous's txn record redundand length // read together with previous's txn record redundand length
n, err = r.ReadAt(tmpBuf[:], pos - 8) n, err = r.ReadAt(tmpBuf[:], pos - 8)
n -= 8 // relative to pos n -= 8 // relative to pos
if n >= 0 { if n >= 0 {
th.PrevRecLenm8 = uint64(binary.BigEndian.Uint64(tmpBuf[8-8:])) th.PrevLenm8 = uint64(binary.BigEndian.Uint64(tmpBuf[8-8:]))
if th.PrevRecLenm8 < txnHeaderFixSize { if th.PrevLenm8 < txnHeaderFixSize {
panic("too small txn prev record length") // XXX panic("too small txn prev record length") // XXX
} }
} }
} else { } else {
th.PrevRecLenm8 = 0 th.PrevLenm8 = 0
n, err = r.ReadAt(tmpBuf[8:], pos) n, err = r.ReadAt(tmpBuf[8:], pos)
} }
...@@ -135,10 +143,10 @@ func (th *TxnHeader) decode(r io.ReaderAt, pos int64, tmpBuf *[txnXHeaderFixSize ...@@ -135,10 +143,10 @@ func (th *TxnHeader) decode(r io.ReaderAt, pos int64, tmpBuf *[txnXHeaderFixSize
} }
th.Tid = zodb.Tid(binary.BigEndian.Uint64(tmpBuf[8+0:])) th.Tid = zodb.Tid(binary.BigEndian.Uint64(tmpBuf[8+0:]))
th.RecLenm8 = uint64(binary.BigEndian.Uint64(tmpBuf[8+8:])) th.Lenm8 = uint64(binary.BigEndian.Uint64(tmpBuf[8+8:]))
th.Status = zodb.TxnStatus(tmpBuf[8+16]) th.Status = zodb.TxnStatus(tmpBuf[8+16])
if th.RecLenm8 < txnHeaderFixSize { if th.Lenm8 < txnHeaderFixSize {
panic("too small txn record length") // XXX panic("too small txn record length") // XXX
} }
...@@ -146,56 +154,42 @@ func (th *TxnHeader) decode(r io.ReaderAt, pos int64, tmpBuf *[txnXHeaderFixSize ...@@ -146,56 +154,42 @@ func (th *TxnHeader) decode(r io.ReaderAt, pos int64, tmpBuf *[txnXHeaderFixSize
ldesc := binary.BigEndian.Uint16(tmpBuf[8+19:]) ldesc := binary.BigEndian.Uint16(tmpBuf[8+19:])
lext := binary.BigEndian.Uint16(tmpBuf[8+21:]) lext := binary.BigEndian.Uint16(tmpBuf[8+21:])
// XXX load strings only optionally
lstr := int(luser) + int(ldesc) + int(lext) lstr := int(luser) + int(ldesc) + int(lext)
if lstr <= cap(th.stringsRam) { if lstr <= cap(th.stringsMem) {
th.stringsRam = th.stringsRam[:lstr] th.stringsMem = th.stringsMem[:lstr]
} else { } else {
th.stringsRam = make([]byte, lstr) th.stringsMem = make([]byte, lstr)
} }
nstr, err = r.ReadAt(th.stringsRam, pos + txnHeaderFixSize) nstr, err = r.ReadAt(th.stringsMem, pos + txnHeaderFixSize)
// XXX EOF after txn header is not good // XXX EOF after txn header is not good
if err != nil { if err != nil {
return 0, &ErrTxnRecord{pos, "read", noEof(err)} return 0, &ErrTxnRecord{pos, "read", noEof(err)}
} }
th.User = th.stringsRam[0:luser] th.User = th.stringsMem[0:luser]
th.Description = th.stringsRam[luser:luser+ldesc] th.Description = th.stringsMem[luser:luser+ldesc]
th.Extension = th.stringsRam[luser+ldesc:luser+ldesc+lext] th.Extension = th.stringsMem[luser+ldesc:luser+ldesc+lext]
return txnHeaderFixSize + lstr, nil return txnHeaderFixSize + lstr, nil
} }
// decodePrev reads and decodes transaction record header from a readerAt XXX from next ... // loadPrev reads and decodes previous transaction record header from a readerAt
// pos: points to header begin XXX text // txnh should be already initialized by previous call to load()
// th should be already initialized by previous call to decode() func (txnh *TxnHeader) loadPrev(r io.ReaderAt, tmpBuf *[txnXHeaderFixSize]byte) error {
func (th *TxnHeader) decodePrev(r io.ReaderAt, pos int64, tmpBuf *[txnXHeaderFixSize]byte) (posPrev int64, n int, err error) { if txnh.PrevLen == 0 {
if th.PrevRecLenm8 == 0 { return io.EOF
panic("no prev") // TODO
}
n, err = r.ReadAt(tmpBuf[:8], pos - 8)
if n == 8 {
// -> to readAt() utility
err = nil // we are ok to get EOF after reading it all
}
if err != nil {
panic(err) // XXX
}
recLenm8 := binary.BigEndian.Uint64(tmpBuf[0:])
posPrev = pos - 8 - int64(recLenm8) // XXX overflow ?
n, err = th.decode(r, posPrev, tmpBuf)
if err != nil {
return 0, 0, err // XXX +context
} }
if th.RecLenm8 != recLenm8 { return txnh.load(r, txnh.Pos - txnh.PrevLen, tmpBuf)
panic("redunant length mismatch") // XXX }
}
return posPrev, n, nil // loadNext reads and decodes next transaction record header from a readerAt
// txnh should be already initialized by previous call to load()
func (txnh *TxnHeader) loadNext(r io.ReaderAt, tmpBuf *[txnXHeaderFixSize]byte) error {
return txnh.load(r, txnh.Pos + txnh.Len, tmpBuf)
} }
// XXX do we need Decode when decode() is there? // XXX do we need Decode when decode() is there?
......
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