prow/spyglass/lenses/lenses.go
func LastNLinesChunked(a Artifact, n, chunkSize int64) ([]string, error) {
	toRead := chunkSize + 1 // Add 1 for exclusive upper bound read range
	chunks := int64(1)
	var contents []byte
	var linesInContents int64
	artifactSize, err := a.Size()
	if err != nil {
		return nil, fmt.Errorf("error getting artifact size: %v", err)
	}
	offset := artifactSize - chunks*chunkSize
	lastOffset := offset
	var lastRead int64
	for linesInContents < n && offset != 0 {
		offset = lastOffset - lastRead
		if offset < 0 {
			toRead = offset + chunkSize + 1
			offset = 0
		}
		bytesRead := make([]byte, toRead)
		numBytesRead, err := a.ReadAt(bytesRead, offset)
		if err != nil && err != io.EOF {
			return nil, fmt.Errorf("error reading artifact: %v", err)
		}
		lastRead = int64(numBytesRead)
		lastOffset = offset
		bytesRead = bytes.Trim(bytesRead, "\x00")
		linesInContents += int64(bytes.Count(bytesRead, []byte("\n")))
		contents = append(bytesRead, contents...)
		chunks++
	}

	var lines []string
	scanner := bufio.NewScanner(bytes.NewReader(contents))
	scanner.Split(bufio.ScanLines)
	for scanner.Scan() {
		line := scanner.Text()
		lines = append(lines, line)
	}
	l := int64(len(lines))
	if l < n {
		return lines, nil
	}
	return lines[l-n:], nil
}
func LastNLinesChunked(a Artifact, n, chunkSize int64) ([]string, error) {
	toRead := chunkSize + 1 // Add 1 for exclusive upper bound read range
	chunks := int64(1)
	var contents []byte
	var linesInContents int64
	artifactSize, err := a.Size()
	if err != nil {
		return nil, fmt.Errorf("error getting artifact size: %v", err)
	}
	offset := artifactSize - chunks*chunkSize
	lastOffset := offset
	var lastRead int64
	for linesInContents < n && offset != 0 {
		offset = lastOffset - lastRead
		if offset < 0 {
			toRead = offset + chunkSize + 1
			offset = 0
		}
		bytesRead := make([]byte, toRead)
		numBytesRead, err := a.ReadAt(bytesRead, offset)
		if err != nil && err != io.EOF {
			return nil, fmt.Errorf("error reading artifact: %v", err)
		}
		lastRead = int64(numBytesRead)
		lastOffset = offset
		bytesRead = bytes.Trim(bytesRead, "\x00")
		linesInContents += int64(bytes.Count(bytesRead, []byte("\n")))
		contents = append(bytesRead, contents...)
		chunks++
	}

	var lines []string
	scanner := bufio.NewScanner(bytes.NewReader(contents))
	scanner.Split(bufio.ScanLines)
	for scanner.Scan() {
		line := scanner.Text()
		lines = append(lines, line)
	}
	l := int64(len(lines))
	if l < n {
		return lines, nil
	}
	return lines[l-n:], nil
}
func LastNLinesChunked ( a Artifact , n , chunkSize int64 ) ( [ ] string , error ) { toRead := chunkSize + 1 // Add 1 for exclusive upper bound read range chunks := int64 ( 1 ) var contents [ ] byte var linesInContents int64 artifactSize , err := a . Size ( ) if err != nil { return nil , fmt . Errorf ( " " , err ) } offset := artifactSize - chunks * chunkSize lastOffset := offset var lastRead int64 for linesInContents < n && offset != 0 { offset = lastOffset - lastRead if offset < 0 { toRead = offset + chunkSize + 1 offset = 0 } bytesRead := make ( [ ] byte , toRead ) numBytesRead , err := a . ReadAt ( bytesRead , offset ) if err != nil && err != io . EOF { return nil , fmt . Errorf ( " " , err ) } lastRead = int64 ( numBytesRead ) lastOffset = offset bytesRead = bytes . Trim ( bytesRead , " \x00 " ) linesInContents += int64 ( bytes . Count ( bytesRead , [ ] byte ( " \n " ) ) ) contents = append ( bytesRead , contents ... ) chunks ++ } var lines [ ] string scanner := bufio . NewScanner ( bytes . NewReader ( contents ) ) scanner . Split ( bufio . ScanLines ) for scanner . Scan ( ) { line := scanner . Text ( ) lines = append ( lines , line ) } l := int64 ( len ( lines ) ) if l < n { return lines , nil } return lines [ l - n : ] , nil }
// LastNLinesChunked reads the last n lines from an artifact by reading chunks of size chunkSize
// from the end of the artifact. Best performance is achieved by:
// argmin 0<chunkSize<INTMAX, f(chunkSize) = chunkSize - n * avgLineLength
LastNLinesChunked reads the last n lines from an artifact by reading chunks of size chunkSize from the end of the artifact . Best performance is achieved by : argmin 0<chunkSize<INTMAX f ( chunkSize ) = chunkSize - n * avgLineLength