Bumps [github.com/containerd/cgroups/v3](https://github.com/containerd/cgroups) from 3.0.2 to 3.0.3. - [Release notes](https://github.com/containerd/cgroups/releases) - [Commits](https://github.com/containerd/cgroups/compare/v3.0.2...v3.0.3) --- updated-dependencies: - dependency-name: github.com/containerd/cgroups/v3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
		
			
				
	
	
		
			129 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			129 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package internal
 | 
						|
 | 
						|
import (
 | 
						|
	"bufio"
 | 
						|
	"bytes"
 | 
						|
	"compress/gzip"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"os"
 | 
						|
	"path/filepath"
 | 
						|
	"sync"
 | 
						|
)
 | 
						|
 | 
						|
// NewBufferedSectionReader wraps an io.ReaderAt in an appropriately-sized
 | 
						|
// buffered reader. It is a convenience function for reading subsections of
 | 
						|
// ELF sections while minimizing the amount of read() syscalls made.
 | 
						|
//
 | 
						|
// Syscall overhead is non-negligible in continuous integration context
 | 
						|
// where ELFs might be accessed over virtual filesystems with poor random
 | 
						|
// access performance. Buffering reads makes sense because (sub)sections
 | 
						|
// end up being read completely anyway.
 | 
						|
//
 | 
						|
// Use instead of the r.Seek() + io.LimitReader() pattern.
 | 
						|
func NewBufferedSectionReader(ra io.ReaderAt, off, n int64) *bufio.Reader {
 | 
						|
	// Clamp the size of the buffer to one page to avoid slurping large parts
 | 
						|
	// of a file into memory. bufio.NewReader uses a hardcoded default buffer
 | 
						|
	// of 4096. Allow arches with larger pages to allocate more, but don't
 | 
						|
	// allocate a fixed 4k buffer if we only need to read a small segment.
 | 
						|
	buf := n
 | 
						|
	if ps := int64(os.Getpagesize()); n > ps {
 | 
						|
		buf = ps
 | 
						|
	}
 | 
						|
 | 
						|
	return bufio.NewReaderSize(io.NewSectionReader(ra, off, n), int(buf))
 | 
						|
}
 | 
						|
 | 
						|
// DiscardZeroes makes sure that all written bytes are zero
 | 
						|
// before discarding them.
 | 
						|
type DiscardZeroes struct{}
 | 
						|
 | 
						|
func (DiscardZeroes) Write(p []byte) (int, error) {
 | 
						|
	for _, b := range p {
 | 
						|
		if b != 0 {
 | 
						|
			return 0, errors.New("encountered non-zero byte")
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return len(p), nil
 | 
						|
}
 | 
						|
 | 
						|
// ReadAllCompressed decompresses a gzipped file into memory.
 | 
						|
func ReadAllCompressed(file string) ([]byte, error) {
 | 
						|
	fh, err := os.Open(file)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer fh.Close()
 | 
						|
 | 
						|
	gz, err := gzip.NewReader(fh)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer gz.Close()
 | 
						|
 | 
						|
	return io.ReadAll(gz)
 | 
						|
}
 | 
						|
 | 
						|
// ReadUint64FromFile reads a uint64 from a file.
 | 
						|
//
 | 
						|
// format specifies the contents of the file in fmt.Scanf syntax.
 | 
						|
func ReadUint64FromFile(format string, path ...string) (uint64, error) {
 | 
						|
	filename := filepath.Join(path...)
 | 
						|
	data, err := os.ReadFile(filename)
 | 
						|
	if err != nil {
 | 
						|
		return 0, fmt.Errorf("reading file %q: %w", filename, err)
 | 
						|
	}
 | 
						|
 | 
						|
	var value uint64
 | 
						|
	n, err := fmt.Fscanf(bytes.NewReader(data), format, &value)
 | 
						|
	if err != nil {
 | 
						|
		return 0, fmt.Errorf("parsing file %q: %w", filename, err)
 | 
						|
	}
 | 
						|
	if n != 1 {
 | 
						|
		return 0, fmt.Errorf("parsing file %q: expected 1 item, got %d", filename, n)
 | 
						|
	}
 | 
						|
 | 
						|
	return value, nil
 | 
						|
}
 | 
						|
 | 
						|
type uint64FromFileKey struct {
 | 
						|
	format, path string
 | 
						|
}
 | 
						|
 | 
						|
var uint64FromFileCache = struct {
 | 
						|
	sync.RWMutex
 | 
						|
	values map[uint64FromFileKey]uint64
 | 
						|
}{
 | 
						|
	values: map[uint64FromFileKey]uint64{},
 | 
						|
}
 | 
						|
 | 
						|
// ReadUint64FromFileOnce is like readUint64FromFile but memoizes the result.
 | 
						|
func ReadUint64FromFileOnce(format string, path ...string) (uint64, error) {
 | 
						|
	filename := filepath.Join(path...)
 | 
						|
	key := uint64FromFileKey{format, filename}
 | 
						|
 | 
						|
	uint64FromFileCache.RLock()
 | 
						|
	if value, ok := uint64FromFileCache.values[key]; ok {
 | 
						|
		uint64FromFileCache.RUnlock()
 | 
						|
		return value, nil
 | 
						|
	}
 | 
						|
	uint64FromFileCache.RUnlock()
 | 
						|
 | 
						|
	value, err := ReadUint64FromFile(format, filename)
 | 
						|
	if err != nil {
 | 
						|
		return 0, err
 | 
						|
	}
 | 
						|
 | 
						|
	uint64FromFileCache.Lock()
 | 
						|
	defer uint64FromFileCache.Unlock()
 | 
						|
 | 
						|
	if value, ok := uint64FromFileCache.values[key]; ok {
 | 
						|
		// Someone else got here before us, use what is cached.
 | 
						|
		return value, nil
 | 
						|
	}
 | 
						|
 | 
						|
	uint64FromFileCache.values[key] = value
 | 
						|
	return value, nil
 | 
						|
}
 |