Commit 8c199588 authored by Kirill Smelkov's avatar Kirill Smelkov

xbufio: put buf/pos to head of struct; avoid 1 temporaray

parent 675a9e86
...@@ -13,11 +13,11 @@ import ( ...@@ -13,11 +13,11 @@ import (
// SeqBufReader implements buffering for a io.ReaderAt optimized for sequential access // SeqBufReader implements buffering for a io.ReaderAt optimized for sequential access
// XXX -> xbufio.SeqReader // XXX -> xbufio.SeqReader
type SeqBufReader struct { type SeqBufReader struct {
r io.ReaderAt
// buffer for data at pos. cap(buf) - whole buffer capacity // buffer for data at pos. cap(buf) - whole buffer capacity
pos int64
buf []byte buf []byte
pos int64
r io.ReaderAt
} }
// TODO text about syscall / memcpy etc // TODO text about syscall / memcpy etc
...@@ -95,8 +95,7 @@ func (sb *SeqBufReader) ReadAt(p []byte, pos int64) (n int, err error) { ...@@ -95,8 +95,7 @@ func (sb *SeqBufReader) ReadAt(p []byte, pos int64) (n int, err error) {
} }
} }
buf := sb.buf[:cap(sb.buf)] nn, err := sb.r.ReadAt(sb.buf[:cap(sb.buf)], xpos)
nn, err := sb.r.ReadAt(buf, xpos)
// nothing read - just return the error // nothing read - just return the error
if nn == 0 { if nn == 0 {
...@@ -105,7 +104,7 @@ func (sb *SeqBufReader) ReadAt(p []byte, pos int64) (n int, err error) { ...@@ -105,7 +104,7 @@ func (sb *SeqBufReader) ReadAt(p []byte, pos int64) (n int, err error) {
// even if there was an error, but data partly read, we remember it in the buffer // even if there was an error, but data partly read, we remember it in the buffer
sb.pos = xpos sb.pos = xpos
sb.buf = buf[:nn] sb.buf = sb.buf[:nn]
// here we know: // here we know:
// - some data was read // - some data was read
......
...@@ -38,39 +38,41 @@ func (r *XReader) ReadAt(p []byte, pos int64) (n int, err error) { ...@@ -38,39 +38,41 @@ func (r *XReader) ReadAt(p []byte, pos int64) (n int, err error) {
return n, err return n, err
} }
// read @pos/len -> rb.pos, len(rb.buf)
var xSeqBufTestv = []struct {pos int64; Len int; bufPos int64; bufLen int} {
{40, 5, 40, 10}, // 1st access, forward by default
{45, 7, 50, 10}, // part taken from buf, part read next, forward
{52, 5, 50, 10}, // everything taken from buf
{57, 5, 60, 10}, // part taken from buf, part read next
{60, 11, 60, 10}, // access > cap(buf), buf skipped
{71, 11, 60, 10}, // access > cap(buf), once again
{82, 10, 82, 10}, // access = cap(buf), should refill buf
{92, 5, 92, 8}, // next access - should refill buffer, but only up to EIO range
{97, 4, 92, 8}, // this triggers user-visible EIO, buffer not refilled
{101, 5, 92, 8}, // EIO again
{105, 5, 105, 10}, // past EIO range - buffer refilled
{110,70, 105, 10}, // very big access forward, buf untouched
{180,70, 105, 10}, // big access ~ forward
{170,11, 105, 10}, // big access backward
{160,11, 105, 10}, // big access backward, once more
{155, 5, 155, 10}, // access backward - buffer refilled
// XXX refilled forward first time after big backward readings
{150, 5, 145, 10}, // next access backward - buffer refilled backward
{143, 7, 135, 10}, // backward once again - buffer refilled backward
{250, 4, 250, 6}, // access near EOF - buffer fill hits EOF, but not returns it to client
{254, 5, 250, 6}, // access overlapping EOF - EOF returned
{256, 1, 250, 6}, // access past EOF -> EOF
{257, 1, 250, 6}, // ----//----
}
func TestSeqBufReader(t *testing.T) { func TestSeqBufReader(t *testing.T) {
r := &XReader{} r := &XReader{}
rb := NewSeqBufReaderSize(r, 10) // with 10 it is easier to do/check math for a human rb := NewSeqBufReaderSize(r, 10) // with 10 it is easier to do/check math for a human
// read @pos/len -> rb.pos, len(rb.buf) for _, tt := range xSeqBufTestv {
testv := []struct {pos int64; Len int; bufPos int64; bufLen int} {
{40, 5, 40, 10}, // 1st access, forward by default
{45, 7, 50, 10}, // part taken from buf, part read next, forward
{52, 5, 50, 10}, // everything taken from buf
{57, 5, 60, 10}, // part taken from buf, part read next
{60, 11, 60, 10}, // access > cap(buf), buf skipped
{71, 11, 60, 10}, // access > cap(buf), once again
{82, 10, 82, 10}, // access = cap(buf), should refill buf
{92, 5, 92, 8}, // next access - should refill buffer, but only up to EIO range
{97, 4, 92, 8}, // this triggers user-visible EIO, buffer not refilled
{101, 5, 92, 8}, // EIO again
{105, 5, 105, 10}, // past EIO range - buffer refilled
{110,70, 105, 10}, // very big access forward, buf untouched
{180,70, 105, 10}, // big access ~ forward
{170,11, 105, 10}, // big access backward
{160,11, 105, 10}, // big access backward, once more
{155, 5, 155, 10}, // access backward - buffer refilled
// XXX refilled forward first time after big backward readings
{150, 5, 145, 10}, // next access backward - buffer refilled backward
{143, 7, 135, 10}, // backward once again - buffer refilled backward
{250, 4, 250, 6}, // access near EOF - buffer fill hits EOF, but not returns it to client
{254, 5, 250, 6}, // access overlapping EOF - EOF returned
{256, 1, 250, 6}, // access past EOF -> EOF
{257, 1, 250, 6}, // ----//----
}
for _, tt := range testv {
pOk := make([]byte, tt.Len) pOk := make([]byte, tt.Len)
pB := make([]byte, tt.Len) pB := make([]byte, tt.Len)
...@@ -91,3 +93,15 @@ func TestSeqBufReader(t *testing.T) { ...@@ -91,3 +93,15 @@ func TestSeqBufReader(t *testing.T) {
} }
} }
} }
func BenchmarkSeqBufReader(b *testing.B) {
r := &XReader{}
rb := NewSeqBufReaderSize(r, 10) // same as in TestSeqBufReader
buf := make([]byte, 128 /* > all .Len in xSeqBufTestv */)
for i := 0; i < b.N; i++ {
for _, tt := range xSeqBufTestv {
rb.ReadAt(buf[:tt.Len], tt.pos)
}
}
}
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