Skip to content

Commit

Permalink
Fix a bytes counting race condition
Browse files Browse the repository at this point in the history
Before this change, if the file grew after we read it, but before we
noted its size, then tailing could misbehave.
  • Loading branch information
walles committed Jul 15, 2024
1 parent a7d00c0 commit 2781774
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 20 deletions.
15 changes: 15 additions & 0 deletions m/inspection-reader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package m

import "io"

// Pass-through reader that counts the number of bytes read.
type inspectionReader struct {
base io.Reader
bytesCount int64
}

func (r *inspectionReader) Read(p []byte) (n int, err error) {
n, err = r.base.Read(p)
r.bytesCount += int64(n)
return
}
26 changes: 6 additions & 20 deletions m/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ func (reader *Reader) readStream(stream io.Reader, formatter chroma.Formatter, l
func (reader *Reader) consumeLinesFromStream(stream io.Reader) {
reader.preAllocLines()

bufioReader := bufio.NewReader(stream)
inspectionReader := inspectionReader{base: stream}
bufioReader := bufio.NewReader(&inspectionReader)
completeLine := make([]byte, 0)
t0 := time.Now()
for {
Expand Down Expand Up @@ -199,19 +200,8 @@ func (reader *Reader) consumeLinesFromStream(stream io.Reader) {
}

if reader.fileName != nil {
// NOTE: It would be better to track this by counting the number of
// bytes read in the loop above, but since ReadLine() can skip zero to
// two bytes at the end of each line without telling us, we can't do
// that. So we stat the file afterwards instead.
fileStats, err := os.Stat(*reader.fileName)

reader.Lock()
if err != nil {
log.Warn("Failed to stat file ", *reader.fileName, ": ", err)
reader.bytesCount = -1
} else {
reader.bytesCount = fileStats.Size()
}
reader.bytesCount += inspectionReader.bytesCount
reader.Unlock()
}

Expand Down Expand Up @@ -239,13 +229,9 @@ func (reader *Reader) tailFile() error {
for {
// NOTE: We could use something like
// https://github.com/fsnotify/fsnotify instead of sleeping and polling
// here, but before that we need to fix the...
//
// reader.bytesCount = fileStats.Size()
//
// ... logic above, and ensure that if the current last line doesn't end
// with a newline, any new line read appends to the incomplete last
// line.
// here, but before that we need to ensure that if the current last line
// doesn't end with a newline, any new line read appends to the
// incomplete last line.
time.Sleep(1 * time.Second)

fileStats, err := os.Stat(*fileName)
Expand Down

0 comments on commit 2781774

Please sign in to comment.