Commit 2121ce8a authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent a57f4275
...@@ -45,6 +45,7 @@ func TestFsTail(t *testing.T) { ...@@ -45,6 +45,7 @@ func TestFsTail(t *testing.T) {
} }
func BenchmarkFsTail(b *testing.B) { func BenchmarkFsTail(b *testing.B) {
// FIXME small testdata/1.fs is not representative for benchmarking
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
err := fsTail(ioutil.Discard, "../../testdata/1.fs", 1000000) err := fsTail(ioutil.Discard, "../../testdata/1.fs", 1000000)
if err != nil { if err != nil {
......
...@@ -19,11 +19,11 @@ package fs1 ...@@ -19,11 +19,11 @@ package fs1
import ( import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"math/bits"
"io" "io"
"os" "os"
"../../zodb" "../../zodb"
"../../xcommon/xmath"
) )
// FileStorage is a ZODB storage which stores data in simple append-only file // FileStorage is a ZODB storage which stores data in simple append-only file
...@@ -315,7 +315,7 @@ func (txnh *TxnHeader) Load(r io.ReaderAt /* *os.File */, pos int64, flags TxnLo ...@@ -315,7 +315,7 @@ func (txnh *TxnHeader) Load(r io.ReaderAt /* *os.File */, pos int64, flags TxnLo
// NOTE we encode whole strings length into len(.workMem) // NOTE we encode whole strings length into len(.workMem)
if cap(txnh.workMem) < lstr { if cap(txnh.workMem) < lstr {
txnh.workMem = make([]byte, lstr, ceilPow2(uint64(lstr))) txnh.workMem = make([]byte, lstr, xmath.CeilPow2(uint64(lstr)))
} else { } else {
txnh.workMem = txnh.workMem[:lstr] txnh.workMem = txnh.workMem[:lstr]
} }
...@@ -635,12 +635,6 @@ func (dh *DataHeader) loadNext(r io.ReaderAt /* *os.File */, txnh *TxnHeader) er ...@@ -635,12 +635,6 @@ func (dh *DataHeader) loadNext(r io.ReaderAt /* *os.File */, txnh *TxnHeader) er
return nil return nil
} }
// XXX move me out of here
// ceilPow2 returns minimal y >= x, such as y = 2^i
func ceilPow2(x uint64) uint64 {
return 1 << uint(bits.Len64(x))
}
// LoadData loads data for the data record taking backpointers into account // LoadData loads data for the data record taking backpointers into account
// Data is loaded into *buf, which, if needed, is reallocated to hold all loading data size XXX // Data is loaded into *buf, which, if needed, is reallocated to hold all loading data size XXX
// NOTE on success dh state is changed to data header of original data transaction // NOTE on success dh state is changed to data header of original data transaction
...@@ -660,9 +654,7 @@ func (dh *DataHeader) LoadData(r io.ReaderAt /* *os.File */, buf *[]byte) error ...@@ -660,9 +654,7 @@ func (dh *DataHeader) LoadData(r io.ReaderAt /* *os.File */, buf *[]byte) error
// now read actual data // now read actual data
if int64(cap(*buf)) < dh.DataLen { if int64(cap(*buf)) < dh.DataLen {
// ceilPow2 reduces much allocations but is still not enogh to *buf = make([]byte, dh.DataLen, xmath.CeilPow2(uint64(dh.DataLen)))
// remove them all from BenchmarkIterate
*buf = make([]byte, dh.DataLen, ceilPow2(uint64(dh.DataLen)))
} else { } else {
*buf = (*buf)[:dh.DataLen] *buf = (*buf)[:dh.DataLen]
} }
......
// Package xcommon is a staging place for common utilities not yet sorted out
// to their proper homes
package xcommon
package xfmt
import (
"encoding/hex"
"../xslice"
)
// appendHex appends hex representation of x to b
func AppendHex(b []byte, x []byte) []byte {
lx := hex.EncodedLen(len(x))
lb := len(b)
b = xslice.Grow(b, lx)
hex.Encode(b[lb:], x)
return b
}
// Package xmath provides addons over std math package XXX text
package xmath
import (
"math/bits"
)
// CeilPow2 returns minimal y >= x, such that y = 2^i
// XXX naming to reflect it works on uint64 ? CeilPow264 looks ambigous
func CeilPow2(x uint64) uint64 {
switch bits.OnesCount64(x) {
case 0, 1:
return x // either 0 or 2^i already
default:
return 1 << uint(bits.Len64(x))
}
}
// XXX if needed: NextPow2 (y > x, such that y = 2^i) is
// 1 << bits.Len64(x)
package xmath
import (
"testing"
)
func TestCeilPow2(t *testing.T) {
testv := []struct {in, out uint64} {
{0, 0},
{1, 1},
{2, 2},
{3, 4},
{4, 4},
{5, 8},
{5, 8},
{6, 8},
{7, 8},
{8, 8},
{9, 16},
{10, 16},
{11, 16},
{12, 16},
{13, 16},
{14, 16},
{15, 16},
{16, 16},
{1<<62 - 1, 1<<62},
{1<<62, 1<<62},
{1<<62+1, 1<<63},
{1<<63 - 1, 1<<63},
{1<<63, 1<<63},
}
for _, tt := range testv {
out := CeilPow2(tt.in)
if out != tt.out {
t.Errorf("CeilPow(%v) -> %v ; want %v", tt.in, out, tt.out)
}
}
}
// Package xslice provides utilities for working with slices
package xslice
import (
"../xmath"
)
// Grow increase length of slice by n elements.
// If there is not enough capacity the slice is reallocated.
// The memory for grown elements are not initialized.
func Grow(b []byte, n int) []byte {
ln := len(b) + n
if ln <= cap(b) {
return b[:ln]
}
bb := make([]byte, ln, xmath.CeilPow2(uint64(ln)))
copy(bb, b)
return bb
}
// Resize resized the slice to be of length n.
// If slice length is increased and there is not enough capacity the slice is reallocated.
// The memory for grown elements, if any, is not initialized.
func Resize(b []byte, n int) []byte {
if cap(b) >= n {
return b[:n]
}
bb := make([]byte, n, xmath.CeilPow2(uint64(n)))
copy(bb, b)
return bb
}
// TODO Resize without copy ?
// // GrowSlice makes sure cap(b) >= n.
// // If not it reallocates/copies the slice appropriately.
// // len of returned slice remains original len(b).
// func GrowSlice(b []byte, n int) []byte {
// if cap(b) >= n {
// return b
// }
//
// bb := make([]byte, len(b), CeilPow2(uint64(n)))
// copy(bb, b)
// return bb
// }
//
// // makeRoom makes sure len([len(b):cap(b)]) >= n.
// // If it is not it reallocates the slice appropriately.
// // len of returned slice remains original len(b).
// func MakeRoom(b []byte, n int) []byte {
// return GrowSlice(b, len(b) + n)
// }
package xslice
//import (
// "testing"
//)
// TODO
// func TestGrowSlice(t *testing) {
// testv := []struct {in []byte, n int, Cap int} {
// {nil, 0, 0},
// }
//
// }
...@@ -55,9 +55,7 @@ func loadZdumpPy(t *testing.T, path string) string { ...@@ -55,9 +55,7 @@ func loadZdumpPy(t *testing.T, path string) string {
return string(dump) return string(dump)
} }
func withTestdata1Fs(t testing.TB, f func(fs *fs1.FileStorage)) {
func TestZodbDump(t *testing.T) {
buf := bytes.Buffer{}
fs, err := fs1.Open("../../../storage/fs1/testdata/1.fs") // XXX read-only, path? fs, err := fs1.Open("../../../storage/fs1/testdata/1.fs") // XXX read-only, path?
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
...@@ -65,14 +63,39 @@ func TestZodbDump(t *testing.T) { ...@@ -65,14 +63,39 @@ func TestZodbDump(t *testing.T) {
defer exc.XRun(fs.Close) defer exc.XRun(fs.Close)
err = zodbDump(&buf, fs, 0, zodb.TidMax, false) f(fs)
if err != nil { }
t.Fatal(err)
}
dumpOk := loadZdumpPy(t, "testdata/1.zdump.pyok") func TestZodbDump(t *testing.T) {
withTestdata1Fs(t, func(fs *fs1.FileStorage) {
buf := bytes.Buffer{}
if dumpOk != buf.String() { err := zodbDump(&buf, fs, 0, zodb.TidMax, false)
t.Errorf("dump different:\n%v", diff(dumpOk, buf.String())) if err != nil {
} t.Fatal(err)
}
dumpOk := loadZdumpPy(t, "testdata/1.zdump.pyok")
if dumpOk != buf.String() {
t.Errorf("dump different:\n%v", diff(dumpOk, buf.String()))
}
})
}
func BenchmarkZodbDump(b *testing.B) {
// FIXME small testdata/1.fs is not representative for benchmarking
withTestdata1Fs(b, func(fs *fs1.FileStorage) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
err := zodbDump(ioutil.Discard, fs, 0, zodb.TidMax, false)
if err != nil {
b.Fatal(err)
}
}
b.StopTimer()
})
} }
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