Why does Go’s bufio.Reader.collectFragments ignore ErrBufferFull?

  Kiến thức lập trình

I was looking at Go source code and found that, in bufio.Reader.collectFragments (a helper used by ReadSlice and ReadString), the a seemingly serious ErrBufferFull is explicitly ignored, specifically:

func (b *Reader) collectFragments(delim byte) (fullBuffers [][]byte, finalFragment []byte, totalLen int, err error) {
    var frag []byte
    // Use ReadSlice to look for delim, accumulating full buffers.
    for {
        var e error
        frag, e = b.ReadSlice(delim)
        if e == nil { // got final fragment
            break
        }
        if e != ErrBufferFull { // unexpected error
        ^^^^^^^^^^^^^^^^^^^^^ This ensures that ErrBufferFull will not break the loop
            err = e
            break
        }

        // Make a copy of the buffer.
        buf := bytes.Clone(frag)
        fullBuffers = append(fullBuffers, buf)
        totalLen += len(buf)
    }

    totalLen += len(frag)
    return fullBuffers, frag, totalLen, err
}

(go/src/bufio/bufio.go, line 446, Go 1.22)

If ReadSlice returns an ErrBufferNull, it is ignored. The full buffer is copied, and a new iteration starts, which calls ReadSlice again.

However, ReadSlice ‘fails’ when the buffer is full, and doesn’t seem to have any logic to grow or clear a full buffer.

func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
    s := 0 // search start index
    for {
        // Search buffer.
        if i := bytes.IndexByte(b.buf[b.r+s:b.w], delim); i >= 0 {
            i += s
            line = b.buf[b.r : b.r+i+1]
            b.r += i + 1
            break
        }

        // Pending error?
        if b.err != nil {
            line = b.buf[b.r:b.w]
            b.r = b.w
            err = b.readErr()
            break
        }

        // Buffer full?
        if b.Buffered() >= len(b.buf) {
            b.r = b.w
            line = b.buf
            err = ErrBufferFull
            break
        }

        s = b.w - b.r // do not rescan area we scanned before

        b.fill() // buffer is not full
    }

    // Handle last byte, if any.
    if i := len(line) - 1; i >= 0 {
        b.lastByte = int(line[i])
        b.lastRuneSize = -1
    }

    return
}

(go/src/bufio/bufio.go, line 347, Go 1.22)

As far as I understand, this can cause the loop in collectFragments to run forever. However, since ErrBufferFull is explicitly ignored, I feel this is by design, and I’m missing something.

Can someone help me understand? Thanks!

LEAVE A COMMENT