]> Cypherpunks repositories - gostls13.git/commitdiff
bufio: do not cache Read errors
authorGraham Miller <graham.miller@gmail.com>
Mon, 27 Jun 2011 20:12:04 +0000 (16:12 -0400)
committerRuss Cox <rsc@golang.org>
Mon, 27 Jun 2011 20:12:04 +0000 (16:12 -0400)
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

src/pkg/bufio/bufio.go
src/pkg/bufio/bufio_test.go
src/pkg/testing/iotest/reader.go

index 497e770fb15e1c68f8062024e16fabb0a99f522a..cb2667b2832cf583b01bfa02b238a43f9506d762 100644 (file)
@@ -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
 // 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
@@ -121,7 +127,7 @@ func (b *Reader) Peek(n int) ([]byte, os.Error) {
        if m > n {
                m = n
        }
-       err := b.err
+       err := b.readErr()
        if m < n && err == nil {
                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) {
        n = len(p)
        if n == 0 {
-               return 0, b.err
+               return 0, b.readErr()
        }
        if b.w == b.r {
                if b.err != nil {
-                       return 0, b.err
+                       return 0, b.readErr()
                }
                if len(p) >= len(b.buf) {
                        // 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.lastRuneSize = -1
                        }
-                       return n, b.err
+                       return n, b.readErr()
                }
                b.fill()
                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
        for b.w == b.r {
                if b.err != nil {
-                       return 0, b.err
+                       return 0, b.readErr()
                }
                b.fill()
        }
@@ -210,7 +216,7 @@ func (b *Reader) ReadRune() (rune int, size int, err os.Error) {
        }
        b.lastRuneSize = -1
        if b.r == b.w {
-               return 0, 0, b.err
+               return 0, 0, b.readErr()
        }
        rune, size = int(b.buf[b.r]), 1
        if rune >= 0x80 {
@@ -262,7 +268,7 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err os.Error) {
                if b.err != nil {
                        line := b.buf[b.r:b.w]
                        b.r = b.w
-                       return line, b.err
+                       return line, b.readErr()
                }
 
                n := b.Buffered()
index 123adac29a4996b43f5e850fefe7635c190ae4d1..5709213c839a66d37c72ff39bcae0ec176b3581e 100644 (file)
@@ -53,11 +53,12 @@ func readBytes(buf *Reader) string {
                if e == os.EOF {
                        break
                }
-               if e != nil {
+               if e == nil {
+                       b[nb] = c
+                       nb++
+               } else if e != iotest.ErrTimeout {
                        panic("Data: " + e.String())
                }
-               b[nb] = c
-               nb++
        }
        return string(b[0:nb])
 }
@@ -86,6 +87,7 @@ var readMakers = []readMaker{
        {"byte", iotest.OneByteReader},
        {"half", iotest.HalfReader},
        {"data+err", iotest.DataErrReader},
+       {"timeout", iotest.TimeoutReader},
 }
 
 // Call ReadString (which ends up calling everything else)
@@ -97,7 +99,7 @@ func readLines(b *Reader) string {
                if e == os.EOF {
                        break
                }
-               if e != nil {
+               if e != nil && e != iotest.ErrTimeout {
                        panic("GetLines: " + e.String())
                }
                s += s1
index e4003d7445019cbfd65cf613261c1d8e8a88ab6e..daa6ede08e6d4967963835cb9a64f7e2825ef7dd 100644 (file)
@@ -58,7 +58,7 @@ func (r *dataErrReader) Read(p []byte) (n int, err os.Error) {
                        r.unread = r.data[0:n1]
                        err = err1
                }
-               if n > 0 {
+               if n > 0 || err != nil {
                        break
                }
                n = copy(p, r.unread)
@@ -66,3 +66,22 @@ func (r *dataErrReader) Read(p []byte) (n int, err os.Error) {
        }
        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)
+}