Add max_container_log_size
Signed-off-by: Lantao Liu <lantaol@google.com>
This commit is contained in:
@@ -16,7 +16,10 @@ limitations under the License.
|
||||
|
||||
package ioutil
|
||||
|
||||
import "io"
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// writeCloseInformer wraps passed in write closer with a close channel.
|
||||
// Caller could wait on the close channel for the write closer to be
|
||||
@@ -66,3 +69,34 @@ func (n *nopWriteCloser) Write(p []byte) (int, error) {
|
||||
func (n *nopWriteCloser) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// serialWriteCloser wraps a write closer and makes sure all writes
|
||||
// are done in serial.
|
||||
// Parallel write won't intersect with each other. Use case:
|
||||
// 1) Pipe: Write content longer than PIPE_BUF.
|
||||
// See http://man7.org/linux/man-pages/man7/pipe.7.html
|
||||
// 2) <3.14 Linux Kernel: write is not atomic
|
||||
// See http://man7.org/linux/man-pages/man2/write.2.html
|
||||
type serialWriteCloser struct {
|
||||
mu sync.Mutex
|
||||
wc io.WriteCloser
|
||||
}
|
||||
|
||||
// NewSerialWriteCloser creates a SerialWriteCloser from a write closer.
|
||||
func NewSerialWriteCloser(wc io.WriteCloser) io.WriteCloser {
|
||||
return &serialWriteCloser{wc: wc}
|
||||
}
|
||||
|
||||
// Write writes a group of byte arrays in order atomically.
|
||||
func (s *serialWriteCloser) Write(data []byte) (int, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.wc.Write(data)
|
||||
}
|
||||
|
||||
// Close closes the write closer.
|
||||
func (s *serialWriteCloser) Close() error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.wc.Close()
|
||||
}
|
||||
|
||||
@@ -17,9 +17,16 @@ limitations under the License.
|
||||
package ioutil
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestWriteCloseInformer(t *testing.T) {
|
||||
@@ -47,3 +54,55 @@ func TestWriteCloseInformer(t *testing.T) {
|
||||
assert.Fail(t, "write closer not closed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSerialWriteCloser(t *testing.T) {
|
||||
const (
|
||||
// Test 10 times to make sure it always pass.
|
||||
testCount = 10
|
||||
|
||||
goroutine = 10
|
||||
dataLen = 100000
|
||||
)
|
||||
for n := 0; n < testCount; n++ {
|
||||
testData := make([][]byte, goroutine)
|
||||
for i := 0; i < goroutine; i++ {
|
||||
testData[i] = []byte(repeatNumber(i, dataLen) + "\n")
|
||||
}
|
||||
|
||||
f, err := ioutil.TempFile("/tmp", "serial-write-closer")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(f.Name())
|
||||
defer f.Close()
|
||||
wc := NewSerialWriteCloser(f)
|
||||
defer wc.Close()
|
||||
|
||||
// Write data in parallel
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(goroutine)
|
||||
for i := 0; i < goroutine; i++ {
|
||||
go func(id int) {
|
||||
n, err := wc.Write(testData[id])
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, dataLen+1, n)
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
wc.Close()
|
||||
|
||||
// Check test result
|
||||
content, err := ioutil.ReadFile(f.Name())
|
||||
require.NoError(t, err)
|
||||
resultData := strings.Split(strings.TrimSpace(string(content)), "\n")
|
||||
require.Len(t, resultData, goroutine)
|
||||
sort.Strings(resultData)
|
||||
for i := 0; i < goroutine; i++ {
|
||||
expected := repeatNumber(i, dataLen)
|
||||
assert.Equal(t, expected, resultData[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func repeatNumber(num, count int) string {
|
||||
return strings.Repeat(strconv.Itoa(num), count)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user