mirror of
https://github.com/golang/go
synced 2024-11-22 08:24:41 -07:00
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
This commit is contained in:
parent
3a4a581c49
commit
f795bdb979
@ -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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
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) {
|
|||||||
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 {
|
|||||||
if e == os.EOF {
|
if e == os.EOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if e != nil {
|
if e == nil {
|
||||||
panic("Data: " + e.String())
|
|
||||||
}
|
|
||||||
b[nb] = c
|
b[nb] = c
|
||||||
nb++
|
nb++
|
||||||
|
} else if e != iotest.ErrTimeout {
|
||||||
|
panic("Data: " + e.String())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return string(b[0:nb])
|
return string(b[0:nb])
|
||||||
}
|
}
|
||||||
@ -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 {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
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)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user