tsdb: faster CRC check by avoiding allocations (#10789)

Instead of creating a new hashing object every time, call `crc32.Checksum`
which computes the answer without allocations.

Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
This commit is contained in:
Bryan Boreham 2022-06-08 03:30:59 +01:00 committed by GitHub
parent 7a78897d0b
commit 9f79a6f4b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -15,7 +15,6 @@ package chunks
import ( import (
"bufio" "bufio"
"bytes"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"hash" "hash"
@ -166,6 +165,17 @@ func newCRC32() hash.Hash32 {
return crc32.New(castagnoliTable) return crc32.New(castagnoliTable)
} }
// Check if the CRC of data matches that stored in sum, computed when the chunk was stored.
func checkCRC32(data, sum []byte) error {
got := crc32.Checksum(data, castagnoliTable)
// This combination of shifts is the inverse of digest.Sum() in go/src/hash/crc32.
want := uint32(sum[0])<<24 + uint32(sum[1])<<16 + uint32(sum[2])<<8 + uint32(sum[3])
if got != want {
return errors.Errorf("checksum mismatch expected:%x, actual:%x", want, got)
}
return nil
}
// Writer implements the ChunkWriter interface for the standard // Writer implements the ChunkWriter interface for the standard
// serialization format. // serialization format.
type Writer struct { type Writer struct {
@ -547,7 +557,6 @@ func (s *Reader) Size() int64 {
// Chunk returns a chunk from a given reference. // Chunk returns a chunk from a given reference.
func (s *Reader) Chunk(ref ChunkRef) (chunkenc.Chunk, error) { func (s *Reader) Chunk(ref ChunkRef) (chunkenc.Chunk, error) {
sgmIndex, chkStart := BlockChunkRef(ref).Unpack() sgmIndex, chkStart := BlockChunkRef(ref).Unpack()
chkCRC32 := newCRC32()
if sgmIndex >= len(s.bs) { if sgmIndex >= len(s.bs) {
return nil, errors.Errorf("segment index %d out of range", sgmIndex) return nil, errors.Errorf("segment index %d out of range", sgmIndex)
@ -576,14 +585,10 @@ func (s *Reader) Chunk(ref ChunkRef) (chunkenc.Chunk, error) {
} }
sum := sgmBytes.Range(chkDataEnd, chkEnd) sum := sgmBytes.Range(chkDataEnd, chkEnd)
if _, err := chkCRC32.Write(sgmBytes.Range(chkEncStart, chkDataEnd)); err != nil { if err := checkCRC32(sgmBytes.Range(chkEncStart, chkDataEnd), sum); err != nil {
return nil, err return nil, err
} }
if act := chkCRC32.Sum(nil); !bytes.Equal(act, sum) {
return nil, errors.Errorf("checksum mismatch expected:%x, actual:%x", sum, act)
}
chkData := sgmBytes.Range(chkDataStart, chkDataEnd) chkData := sgmBytes.Range(chkDataStart, chkDataEnd)
chkEnc := sgmBytes.Range(chkEncStart, chkEncStart+ChunkEncodingSize)[0] chkEnc := sgmBytes.Range(chkEncStart, chkEncStart+ChunkEncodingSize)[0]
return s.pool.Get(chunkenc.Encoding(chkEnc), chkData) return s.pool.Get(chunkenc.Encoding(chkEnc), chkData)