mirror of
https://github.com/siderolabs/talos.git
synced 2025-08-21 14:41:12 +02:00
This replaces logging to files with inotify following to pure in-memory circular buffer which grows on demand capped at specified maximum capacity. The concern with previous approach was that logs on tmpfs were growing without any bound potentially consuming all the node memory. Signed-off-by: Andrey Smirnov <smirnov.andrey@gmail.com>
104 lines
1.8 KiB
Go
104 lines
1.8 KiB
Go
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
package circular
|
|
|
|
import (
|
|
"io"
|
|
"sync/atomic"
|
|
)
|
|
|
|
// Reader implements seekable reader with local position in the Buffer which
|
|
// reads from the fixed part of the buffer.
|
|
//
|
|
// Reader is not safe to be used with concurrent Read/Seek operations.
|
|
type Reader struct {
|
|
buf *Buffer
|
|
|
|
startOff, endOff int64
|
|
off int64
|
|
|
|
closed uint32
|
|
}
|
|
|
|
// Read implements io.Reader.
|
|
func (r *Reader) Read(p []byte) (n int, err error) {
|
|
if atomic.LoadUint32(&r.closed) > 0 {
|
|
err = ErrClosed
|
|
return
|
|
}
|
|
|
|
r.buf.mu.Lock()
|
|
defer r.buf.mu.Unlock()
|
|
|
|
if r.off < r.buf.off-int64(r.buf.opt.MaxCapacity) {
|
|
// reader is falling too much behind
|
|
err = ErrOutOfSync
|
|
|
|
return
|
|
}
|
|
|
|
if r.off == r.endOff {
|
|
err = io.EOF
|
|
|
|
return
|
|
}
|
|
|
|
if len(p) == 0 {
|
|
return
|
|
}
|
|
|
|
n = int(r.endOff - r.off)
|
|
if n > len(p) {
|
|
n = len(p)
|
|
}
|
|
|
|
i := int(r.off % int64(r.buf.opt.MaxCapacity))
|
|
l := r.buf.opt.MaxCapacity - i
|
|
|
|
if l < n {
|
|
copy(p, r.buf.data[i:])
|
|
copy(p[l:], r.buf.data[:n-l])
|
|
} else {
|
|
copy(p, r.buf.data[i:i+n])
|
|
}
|
|
|
|
r.off += int64(n)
|
|
|
|
return n, err
|
|
}
|
|
|
|
// Close implements io.Closer.
|
|
func (r *Reader) Close() error {
|
|
atomic.StoreUint32(&r.closed, 1)
|
|
|
|
return nil
|
|
}
|
|
|
|
// Seek implements io.Seeker.
|
|
func (r *Reader) Seek(offset int64, whence int) (int64, error) {
|
|
newOff := r.off
|
|
|
|
switch whence {
|
|
case io.SeekCurrent:
|
|
newOff += offset
|
|
case io.SeekEnd:
|
|
newOff = r.endOff + offset
|
|
case io.SeekStart:
|
|
newOff = r.startOff + offset
|
|
}
|
|
|
|
if newOff < r.startOff {
|
|
return r.off - r.startOff, ErrSeekBeforeStart
|
|
}
|
|
|
|
if newOff > r.endOff {
|
|
newOff = r.endOff
|
|
}
|
|
|
|
r.off = newOff
|
|
|
|
return r.off - r.startOff, nil
|
|
}
|