Commit f795bdb9 authored by Graham Miller's avatar Graham Miller Committed by Russ Cox

bufio: do not cache Read errors

Reader previously had cached an error from the underlying reader
and would return it on every subsequent call to Read.  The Reader
will now return the error only once, and subsequent calls will result
in a new Read call to the underlying Reader.

Fixes #1934.

R=bradfitz, rogpeppe, rsc
CC=golang-dev
https://golang.org/cl/4528133
parent 3a4a581c
...@@ -103,6 +103,12 @@ func (b *Reader) fill() { ...@@ -103,6 +103,12 @@ func (b *Reader) fill() {
} }
} }
func (b *Reader) readErr() os.Error {
err := b.err
b.err = nil
return err
}
// Peek returns the next n bytes without advancing the reader. The bytes stop // Peek returns the next n bytes without advancing the reader. The bytes stop
// being valid at the next read call. If Peek returns fewer than n bytes, it // being valid at the next read call. If Peek returns fewer than n bytes, it
// also returns an error explaining why the read is short. The error is // also returns an error explaining why the read is short. The error is
...@@ -121,7 +127,7 @@ func (b *Reader) Peek(n int) ([]byte, os.Error) { ...@@ -121,7 +127,7 @@ func (b *Reader) Peek(n int) ([]byte, os.Error) {
if m > n { if m > n {
m = n m = n
} }
err := b.err err := b.readErr()
if m < n && err == nil { if m < n && err == nil {
err = ErrBufferFull err = ErrBufferFull
} }
...@@ -136,11 +142,11 @@ func (b *Reader) Peek(n int) ([]byte, os.Error) { ...@@ -136,11 +142,11 @@ func (b *Reader) Peek(n int) ([]byte, os.Error) {
func (b *Reader) Read(p []byte) (n int, err os.Error) { func (b *Reader) Read(p []byte) (n int, err os.Error) {
n = len(p) n = len(p)
if n == 0 { if n == 0 {
return 0, b.err return 0, b.readErr()
} }
if b.w == b.r { if b.w == b.r {
if b.err != nil { if b.err != nil {
return 0, b.err return 0, b.readErr()
} }
if len(p) >= len(b.buf) { if len(p) >= len(b.buf) {
// Large read, empty buffer. // Large read, empty buffer.
...@@ -150,11 +156,11 @@ func (b *Reader) Read(p []byte) (n int, err os.Error) { ...@@ -150,11 +156,11 @@ func (b *Reader) Read(p []byte) (n int, err os.Error) {
b.lastByte = int(p[n-1]) b.lastByte = int(p[n-1])
b.lastRuneSize = -1 b.lastRuneSize = -1
} }
return n, b.err return n, b.readErr()
} }
b.fill() b.fill()
if b.w == b.r { if b.w == b.r {
return 0, b.err return 0, b.readErr()
} }
} }
...@@ -174,7 +180,7 @@ func (b *Reader) ReadByte() (c byte, err os.Error) { ...@@ -174,7 +180,7 @@ func (b *Reader) ReadByte() (c byte, err os.Error) {
b.lastRuneSize = -1 b.lastRuneSize = -1
for b.w == b.r { for b.w == b.r {
if b.err != nil { if b.err != nil {
return 0, b.err return 0, b.readErr()
} }
b.fill() b.fill()
} }
...@@ -210,7 +216,7 @@ func (b *Reader) ReadRune() (rune int, size int, err os.Error) { ...@@ -210,7 +216,7 @@ func (b *Reader) ReadRune() (rune int, size int, err os.Error) {
} }
b.lastRuneSize = -1 b.lastRuneSize = -1
if b.r == b.w { if b.r == b.w {
return 0, 0, b.err return 0, 0, b.readErr()
} }
rune, size = int(b.buf[b.r]), 1 rune, size = int(b.buf[b.r]), 1
if rune >= 0x80 { if rune >= 0x80 {
...@@ -262,7 +268,7 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err os.Error) { ...@@ -262,7 +268,7 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err os.Error) {
if b.err != nil { if b.err != nil {
line := b.buf[b.r:b.w] line := b.buf[b.r:b.w]
b.r = b.w b.r = b.w
return line, b.err return line, b.readErr()
} }
n := b.Buffered() n := b.Buffered()
......
...@@ -53,11 +53,12 @@ func readBytes(buf *Reader) string { ...@@ -53,11 +53,12 @@ func readBytes(buf *Reader) string {
if e == os.EOF { if e == os.EOF {
break break
} }
if e != nil { if e == nil {
b[nb] = c
nb++
} else if e != iotest.ErrTimeout {
panic("Data: " + e.String()) panic("Data: " + e.String())
} }
b[nb] = c
nb++
} }
return string(b[0:nb]) return string(b[0:nb])
} }
...@@ -86,6 +87,7 @@ var readMakers = []readMaker{ ...@@ -86,6 +87,7 @@ var readMakers = []readMaker{
{"byte", iotest.OneByteReader}, {"byte", iotest.OneByteReader},
{"half", iotest.HalfReader}, {"half", iotest.HalfReader},
{"data+err", iotest.DataErrReader}, {"data+err", iotest.DataErrReader},
{"timeout", iotest.TimeoutReader},
} }
// Call ReadString (which ends up calling everything else) // Call ReadString (which ends up calling everything else)
...@@ -97,7 +99,7 @@ func readLines(b *Reader) string { ...@@ -97,7 +99,7 @@ func readLines(b *Reader) string {
if e == os.EOF { if e == os.EOF {
break break
} }
if e != nil { if e != nil && e != iotest.ErrTimeout {
panic("GetLines: " + e.String()) panic("GetLines: " + e.String())
} }
s += s1 s += s1
......
...@@ -58,7 +58,7 @@ func (r *dataErrReader) Read(p []byte) (n int, err os.Error) { ...@@ -58,7 +58,7 @@ func (r *dataErrReader) Read(p []byte) (n int, err os.Error) {
r.unread = r.data[0:n1] r.unread = r.data[0:n1]
err = err1 err = err1
} }
if n > 0 { if n > 0 || err != nil {
break break
} }
n = copy(p, r.unread) n = copy(p, r.unread)
...@@ -66,3 +66,22 @@ func (r *dataErrReader) Read(p []byte) (n int, err os.Error) { ...@@ -66,3 +66,22 @@ func (r *dataErrReader) Read(p []byte) (n int, err os.Error) {
} }
return return
} }
var ErrTimeout = os.NewError("timeout")
// TimeoutReader returns ErrTimeout on the second read
// with no data. Subsequent calls to read succeed.
func TimeoutReader(r io.Reader) io.Reader { return &timeoutReader{r, 0} }
type timeoutReader struct {
r io.Reader
count int
}
func (r *timeoutReader) Read(p []byte) (int, os.Error) {
r.count++
if r.count == 2 {
return 0, ErrTimeout
}
return r.r.Read(p)
}
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