diff --git a/pkg/util/log/clog.go b/pkg/util/log/clog.go index c08f190a1f00..39cb16c8d5ea 100644 --- a/pkg/util/log/clog.go +++ b/pkg/util/log/clog.go @@ -484,7 +484,7 @@ func formatHeader( cp = nil } - buf := logging.getBuffer() + buf := getBuffer() if line < 0 { line = 0 // not a real line number, but acceptable to someDigits } @@ -700,13 +700,6 @@ type loggingT struct { // Level flag for output to files. fileThreshold Severity - // freeList is a list of byte buffers, maintained under freeListMu. - freeList *buffer - // freeListMu maintains the free list. It is separate from the main mutex - // so buffers can be grabbed and printed to without holding the main lock, - // for better parallelization. - freeListMu syncutil.Mutex - // mu protects the remaining elements of this structure and is // used to synchronize logging. mu syncutil.Mutex @@ -746,6 +739,12 @@ type loggingT struct { clusterID string } +var freeList struct { + syncutil.Mutex + // head is the head of a list of byte buffers, maintained under the mutex. + head *buffer +} + // buffer holds a byte Buffer for reuse. The zero value is ready for use. type buffer struct { bytes.Buffer @@ -796,13 +795,13 @@ func (l *loggingT) setVState(verbosity level, filter []modulePat, setFilter bool } // getBuffer returns a new, ready-to-use buffer. -func (l *loggingT) getBuffer() *buffer { - l.freeListMu.Lock() - b := l.freeList +func getBuffer() *buffer { + freeList.Lock() + b := freeList.head if b != nil { - l.freeList = b.next + freeList.head = b.next } - l.freeListMu.Unlock() + freeList.Unlock() if b == nil { b = new(buffer) } else { @@ -813,15 +812,15 @@ func (l *loggingT) getBuffer() *buffer { } // putBuffer returns a buffer to the free list. -func (l *loggingT) putBuffer(b *buffer) { +func putBuffer(b *buffer) { if b.Len() >= 256 { // Let big buffers die a natural death. return } - l.freeListMu.Lock() - b.next = l.freeList - l.freeList = b - l.freeListMu.Unlock() + freeList.Lock() + b.next = freeList.head + freeList.head = b + freeList.Unlock() } // ensureFile ensures that l.file is set and valid. @@ -942,10 +941,11 @@ func (l *loggingT) outputLogEntry(s Severity, file string, line int, msg string) if err := l.writeToFile(data); err != nil { l.exitLocked(err) l.mu.Unlock() + putBuffer(buf) return } - l.putBuffer(buf) + putBuffer(buf) } // Flush and exit on fatal logging. if s == Severity_FATAL { @@ -991,10 +991,11 @@ func (l *loggingT) printPanicToFile(r interface{}) { func (l *loggingT) outputToStderr(entry Entry, stacks []byte) { buf := l.processForStderr(entry, stacks) - if _, err := OrigStderr.Write(buf.Bytes()); err != nil { + _, err := OrigStderr.Write(buf.Bytes()) + putBuffer(buf) + if err != nil { l.exitLocked(err) } - l.putBuffer(buf) } // processForStderr formats a log entry for output to standard error. @@ -1157,11 +1158,11 @@ func (sb *syncBuffer) rotateFile(now time.Time) error { }, nil, nil) var n int n, err = sb.file.Write(buf.Bytes()) + putBuffer(buf) sb.nbytes += int64(n) if err != nil { return err } - logging.putBuffer(buf) } select { diff --git a/pkg/util/log/clog_test.go b/pkg/util/log/clog_test.go index ea4d1da0e8c3..ee3daa2e92bd 100644 --- a/pkg/util/log/clog_test.go +++ b/pkg/util/log/clog_test.go @@ -146,7 +146,7 @@ func TestEntryDecoder(t *testing.T) { buf := formatHeader(s, now, gid, file, line, nil) buf.WriteString(msg) buf.WriteString("\n") - defer logging.putBuffer(buf) + defer putBuffer(buf) return buf.String() } @@ -724,7 +724,7 @@ func TestExitOnFullDisk(t *testing.T) { func BenchmarkHeader(b *testing.B) { for i := 0; i < b.N; i++ { buf := formatHeader(Severity_INFO, timeutil.Now(), 200, "file.go", 100, nil) - logging.putBuffer(buf) + putBuffer(buf) } } diff --git a/pkg/util/log/log.go b/pkg/util/log/log.go index 8f9f1f9978cf..1e27fe256295 100644 --- a/pkg/util/log/log.go +++ b/pkg/util/log/log.go @@ -259,7 +259,7 @@ func MakeEntry(s Severity, t int64, file string, line int, msg string) Entry { // Format writes the log entry to the specified writer. func (e Entry) Format(w io.Writer) error { buf := formatLogEntry(e, nil, nil) - defer logging.putBuffer(buf) + defer putBuffer(buf) _, err := w.Write(buf.Bytes()) return err }