@@ -25,12 +25,17 @@ import (
2525)
2626
2727const (
28+ // Maximum size of a segment payload in bytes
2829 maxSegmentPayloadSize = 1 << 17 - 1
2930
30- compressedHeaderSize = 5 + crc24Size
31+ // Size of compressed segment header in bytes
32+ compressedHeaderSize = 5 + crc24Size
33+ // Size of uncompressed segment header in bytes
3134 uncompressedHeaderSize = 3 + crc24Size
3235
36+ // Size of header checksum in bytes
3337 crc24Size = 3
38+ // Size of payload checksum in bytes
3439 crc32Size = 4
3540)
3641
@@ -51,9 +56,17 @@ func (segment *segmentHeader) String() string {
5156 segment .isSelfContained )
5257}
5358
59+ // segmentCodec is responsible for encoding and decoding segments.
60+ // It supports both compressed and uncompressed segment formats.
61+ // Decode path is not thread safe as it uses reusable buffers for decoding segment header and payload crc32.
62+ // It is expected to be used within a single instance of [Conn].
5463type segmentCodec struct {
5564 compressor Compressor
5665 compressed bool
66+ // Reusable buffer for decoding segment header, at most 8 bytes
67+ readHeaderBuf [compressedHeaderSize ]byte
68+ // Reusable buffer for decoding segment payload crc32, at most 4 bytes
69+ readChecksumBuf [crc32Size ]byte
5770}
5871
5972func newSegmentCodec (compressor Compressor ) segmentCodec {
@@ -108,7 +121,7 @@ func (sc *segmentCodec) encodeCompressedSegmentHeader(compressedLen, uncompresse
108121 combined |= 1 << 34
109122 }
110123
111- binary .LittleEndian .PutUint64 (dest [:] , combined )
124+ binary .LittleEndian .PutUint64 (dest , combined )
112125
113126 headerCRC24 := Crc24 (dest [:5 ])
114127 dest [5 ] = byte (headerCRC24 )
@@ -224,9 +237,8 @@ func (sc *segmentCodec) verifySegmentPayloadChecksum(data []byte, expected uint3
224237
225238// decodeCompressedSegmentHeader reads and verifies the header of a compressed segment from the given reader.
226239func (sc * segmentCodec ) decodeCompressedSegmentHeader (r io.Reader ) (* segmentHeader , error ) {
227- var headerBuf [8 ]byte // TODO: potentially optimize allocation, could be stored in segmentCodec and reused if the codec is a specific for each Conn
228-
229- if _ , err := io .ReadFull (r , headerBuf [:8 ]); err != nil {
240+ headerBuf := sc .readHeaderBuf [:compressedHeaderSize ]
241+ if _ , err := io .ReadFull (r , headerBuf ); err != nil {
230242 return nil , err
231243 }
232244
@@ -249,19 +261,18 @@ func (sc *segmentCodec) decodeCompressedSegmentHeader(r io.Reader) (*segmentHead
249261
250262// decodeUncompressedSegmentHeader reads and verifies the header of an uncompressed segment from the given reader.
251263func (sc * segmentCodec ) decodeUncompressedSegmentHeader (r io.Reader ) (* segmentHeader , error ) {
252- var header [6 ]byte
253-
254- if _ , err := io .ReadFull (r , header [:]); err != nil {
264+ headerBuf := sc .readHeaderBuf [:uncompressedHeaderSize ]
265+ if _ , err := io .ReadFull (r , headerBuf ); err != nil {
255266 return nil , err
256267 }
257268
258- readHeaderCRC24 := uint32 (header [3 ]) | uint32 (header [4 ])<< 8 | uint32 (header [5 ])<< 16
259- err := sc .verifySegmentHeaderChecksum (header [:3 ], readHeaderCRC24 )
269+ readHeaderCRC24 := uint32 (headerBuf [3 ]) | uint32 (headerBuf [4 ])<< 8 | uint32 (headerBuf [5 ])<< 16
270+ err := sc .verifySegmentHeaderChecksum (headerBuf [:3 ], readHeaderCRC24 )
260271 if err != nil {
261272 return nil , err
262273 }
263274
264- headerInt := uint32 (header [0 ]) | uint32 (header [1 ])<< 8 | uint32 (header [2 ])<< 16
275+ headerInt := uint32 (headerBuf [0 ]) | uint32 (headerBuf [1 ])<< 8 | uint32 (headerBuf [2 ])<< 16
265276 payloadLen := int (headerInt & maxSegmentPayloadSize )
266277 isSelfContained := (headerInt & (1 << 17 )) != 0
267278
@@ -278,12 +289,12 @@ func (sc *segmentCodec) decodePayload(r io.Reader, header *segmentHeader) ([]byt
278289 return nil , err
279290 }
280291
281- var crcBuf [ 4 ] byte
282- if _ , err := io .ReadFull (r , crcBuf [:] ); err != nil {
292+ crcBuf := sc . readChecksumBuf [:]
293+ if _ , err := io .ReadFull (r , crcBuf ); err != nil {
283294 return nil , fmt .Errorf ("gocql: failed to read segment payload crc32, err: %w" , err )
284295 }
285296
286- readPayloadCRC32 := binary .LittleEndian .Uint32 (crcBuf [:] )
297+ readPayloadCRC32 := binary .LittleEndian .Uint32 (crcBuf )
287298 err := sc .verifySegmentPayloadChecksum (payload , readPayloadCRC32 )
288299 if err != nil {
289300 return nil , err
0 commit comments