1
1
mirror of https://github.com/walles/moar.git synced 2024-11-22 03:14:56 +03:00

Fix a bytes counting race condition

Before this change, if the file grew after we read it, but before we
noted its size, then tailing could misbehave.
This commit is contained in:
Johan Walles 2024-07-15 07:03:06 +02:00
parent a7d00c079f
commit 27817741fc
2 changed files with 21 additions and 20 deletions

15
m/inspection-reader.go Normal file
View File

@ -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
}

View File

@ -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 {
@ -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()
}
@ -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)