terraform/vendor/github.com/cihub/seelog/writers_bufferedwriter.go

162 lines
4.6 KiB
Go

// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package seelog
import (
"bufio"
"errors"
"fmt"
"io"
"sync"
"time"
)
// bufferedWriter stores data in memory and flushes it every flushPeriod or when buffer is full
type bufferedWriter struct {
flushPeriod time.Duration // data flushes interval (in microseconds)
bufferMutex *sync.Mutex // mutex for buffer operations syncronization
innerWriter io.Writer // inner writer
buffer *bufio.Writer // buffered wrapper for inner writer
bufferSize int // max size of data chunk in bytes
}
// NewBufferedWriter creates a new buffered writer struct.
// bufferSize -- size of memory buffer in bytes
// flushPeriod -- period in which data flushes from memory buffer in milliseconds. 0 - turn off this functionality
func NewBufferedWriter(innerWriter io.Writer, bufferSize int, flushPeriod time.Duration) (*bufferedWriter, error) {
if innerWriter == nil {
return nil, errors.New("argument is nil: innerWriter")
}
if flushPeriod < 0 {
return nil, fmt.Errorf("flushPeriod can not be less than 0. Got: %d", flushPeriod)
}
if bufferSize <= 0 {
return nil, fmt.Errorf("bufferSize can not be less or equal to 0. Got: %d", bufferSize)
}
buffer := bufio.NewWriterSize(innerWriter, bufferSize)
/*if err != nil {
return nil, err
}*/
newWriter := new(bufferedWriter)
newWriter.innerWriter = innerWriter
newWriter.buffer = buffer
newWriter.bufferSize = bufferSize
newWriter.flushPeriod = flushPeriod * 1e6
newWriter.bufferMutex = new(sync.Mutex)
if flushPeriod != 0 {
go newWriter.flushPeriodically()
}
return newWriter, nil
}
func (bufWriter *bufferedWriter) writeBigChunk(bytes []byte) (n int, err error) {
bufferedLen := bufWriter.buffer.Buffered()
n, err = bufWriter.flushInner()
if err != nil {
return
}
written, writeErr := bufWriter.innerWriter.Write(bytes)
return bufferedLen + written, writeErr
}
// Sends data to buffer manager. Waits until all buffers are full.
func (bufWriter *bufferedWriter) Write(bytes []byte) (n int, err error) {
bufWriter.bufferMutex.Lock()
defer bufWriter.bufferMutex.Unlock()
bytesLen := len(bytes)
if bytesLen > bufWriter.bufferSize {
return bufWriter.writeBigChunk(bytes)
}
if bytesLen > bufWriter.buffer.Available() {
n, err = bufWriter.flushInner()
if err != nil {
return
}
}
bufWriter.buffer.Write(bytes)
return len(bytes), nil
}
func (bufWriter *bufferedWriter) Close() error {
closer, ok := bufWriter.innerWriter.(io.Closer)
if ok {
return closer.Close()
}
return nil
}
func (bufWriter *bufferedWriter) Flush() {
bufWriter.bufferMutex.Lock()
defer bufWriter.bufferMutex.Unlock()
bufWriter.flushInner()
}
func (bufWriter *bufferedWriter) flushInner() (n int, err error) {
bufferedLen := bufWriter.buffer.Buffered()
flushErr := bufWriter.buffer.Flush()
return bufWriter.buffer.Buffered() - bufferedLen, flushErr
}
func (bufWriter *bufferedWriter) flushBuffer() {
bufWriter.bufferMutex.Lock()
defer bufWriter.bufferMutex.Unlock()
bufWriter.buffer.Flush()
}
func (bufWriter *bufferedWriter) flushPeriodically() {
if bufWriter.flushPeriod > 0 {
ticker := time.NewTicker(bufWriter.flushPeriod)
for {
<-ticker.C
bufWriter.flushBuffer()
}
}
}
func (bufWriter *bufferedWriter) String() string {
return fmt.Sprintf("bufferedWriter size: %d, flushPeriod: %d", bufWriter.bufferSize, bufWriter.flushPeriod)
}