From 9f79a6f4b56fd879161ad26a17e4a2ca7eb849a9 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 8 Jun 2022 03:30:59 +0100 Subject: [PATCH] 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 --- tsdb/chunks/chunks.go | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/tsdb/chunks/chunks.go b/tsdb/chunks/chunks.go index 4f8f40587..72cb0311b 100644 --- a/tsdb/chunks/chunks.go +++ b/tsdb/chunks/chunks.go @@ -15,7 +15,6 @@ package chunks import ( "bufio" - "bytes" "encoding/binary" "fmt" "hash" @@ -166,6 +165,17 @@ func newCRC32() hash.Hash32 { 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 // serialization format. type Writer struct { @@ -547,7 +557,6 @@ func (s *Reader) Size() int64 { // Chunk returns a chunk from a given reference. func (s *Reader) Chunk(ref ChunkRef) (chunkenc.Chunk, error) { sgmIndex, chkStart := BlockChunkRef(ref).Unpack() - chkCRC32 := newCRC32() if sgmIndex >= len(s.bs) { 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) - if _, err := chkCRC32.Write(sgmBytes.Range(chkEncStart, chkDataEnd)); err != nil { + if err := checkCRC32(sgmBytes.Range(chkEncStart, chkDataEnd), sum); err != nil { 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) chkEnc := sgmBytes.Range(chkEncStart, chkEncStart+ChunkEncodingSize)[0] return s.pool.Get(chunkenc.Encoding(chkEnc), chkData)