github.com/tsuna/gohbase@v0.0.0-20250731002811-4ffcadfba63e/region/compressor_test.go (about)

     1  // Copyright (C) 2020  The GoHBase Authors.  All rights reserved.
     2  // This file is part of GoHBase.
     3  // Use of this source code is governed by the Apache License 2.0
     4  // that can be found in the COPYING file.
     5  
     6  package region
     7  
     8  import (
     9  	"bytes"
    10  	"errors"
    11  	"fmt"
    12  	"math/rand"
    13  	"net"
    14  	"strconv"
    15  	"testing"
    16  
    17  	"github.com/tsuna/gohbase/test"
    18  )
    19  
    20  // mockCodec just takes the the source and appends it to destination
    21  type mockCodec struct{}
    22  
    23  func (mc mockCodec) Encode(src, dst []byte) ([]byte, uint32) {
    24  	return append(dst, src...), uint32(len(src))
    25  }
    26  
    27  func (mc mockCodec) Decode(src, dst []byte) ([]byte, uint32, error) {
    28  	return append(dst, src...), uint32(len(src)), nil
    29  }
    30  
    31  func (mc mockCodec) ChunkLen() uint32 {
    32  	return 10
    33  }
    34  
    35  func (mc mockCodec) CellBlockCompressorClass() string {
    36  	return "mock"
    37  }
    38  
    39  func TestCompressCellblocks(t *testing.T) {
    40  	tests := []struct {
    41  		cellblocks      net.Buffers
    42  		uncompressedLen uint32
    43  		out             []byte
    44  	}{
    45  		{
    46  			cellblocks:      nil,
    47  			uncompressedLen: 0,
    48  			out:             []byte("\x00\x00\x00\x00"),
    49  		},
    50  		{ // 1 chunk
    51  			cellblocks:      net.Buffers{[]byte("123"), []byte("456"), []byte("789")},
    52  			uncompressedLen: 9,
    53  			out:             []byte("\x00\x00\x00\t\x00\x00\x00\t123456789"),
    54  		},
    55  		{ // 1 chunk
    56  			cellblocks:      net.Buffers{[]byte("12345"), []byte("67890")},
    57  			uncompressedLen: 10,
    58  			out:             []byte("\x00\x00\x00\n\x00\x00\x00\n1234567890"),
    59  		},
    60  		{ // 2 chunks
    61  			cellblocks:      net.Buffers{[]byte("12345"), []byte("67890"), []byte("a")},
    62  			uncompressedLen: 11,
    63  			out:             []byte("\x00\x00\x00\v\x00\x00\x00\n1234567890\x00\x00\x00\x01a"),
    64  		},
    65  		{ // 2 chunks
    66  			cellblocks:      net.Buffers{[]byte("1234567890a")},
    67  			uncompressedLen: 11,
    68  			out:             []byte("\x00\x00\x00\v\x00\x00\x00\n1234567890\x00\x00\x00\x01a"),
    69  		},
    70  	}
    71  
    72  	for i, tcase := range tests {
    73  		t.Run(strconv.Itoa(i), func(t *testing.T) {
    74  			c := &compressor{Codec: mockCodec{}}
    75  			out := c.compressCellblocks(tcase.cellblocks, tcase.uncompressedLen)
    76  
    77  			if !bytes.Equal(tcase.out, out) {
    78  				t.Errorf("expected out %q, got %q", tcase.out, out)
    79  			}
    80  		})
    81  	}
    82  }
    83  
    84  func TestDecompressCellblocks(t *testing.T) {
    85  	tests := []struct {
    86  		in  []byte
    87  		out []byte
    88  		err error
    89  	}{
    90  		{
    91  			in: []byte("\x00\x00\x00\x00"),
    92  		},
    93  		{ // 1 chunk
    94  			in:  []byte("\x00\x00\x00\t\x00\x00\x00\t123456789"),
    95  			out: []byte("123456789"),
    96  		},
    97  		{ // 2 chunks
    98  			in:  []byte("\x00\x00\x00\v\x00\x00\x00\n1234567890\x00\x00\x00\x01a"),
    99  			out: []byte("1234567890a"),
   100  		},
   101  		{
   102  			in:  nil,
   103  			out: nil,
   104  		},
   105  		{
   106  			in: []byte("\x00\x00"),
   107  			err: errors.New(
   108  				"failed to read uncompressed block length: short read: want 4 bytes, got 2"),
   109  		},
   110  		{
   111  			in: []byte("\x00\x00\x00\v\x00"),
   112  			err: errors.New(
   113  				"failed to read compressed chunk block length: short read: want 4 bytes, got 1"),
   114  		},
   115  		{
   116  			in:  []byte("\x00\x00\x00\v\x00\x00\x00\n123"),
   117  			err: errors.New("failed to read compressed chunk: short read: want 10 bytes, got 3"),
   118  		},
   119  		{
   120  			in:  []byte("\x00\x00\x00\t\x00\x00\x00\n1234567890\x00\x00\x00\x01a"),
   121  			err: errors.New("uncompressed more than expected: expected 9, got 10 so far"),
   122  		},
   123  		{ // uncompressed block length is larger than chunk's uncompressed length
   124  			in: []byte("\x00\x00\x00\v\x00\x00\x00\t123456789"),
   125  			err: errors.New(
   126  				"failed to read compressed chunk block length: short read: want 4 bytes, got 0"),
   127  		},
   128  		{ // 2 blocks with 2 chunks each
   129  			in: []byte("\x00\x00\x00\v\x00\x00\x00\n1234567890\x00\x00\x00\x01a" +
   130  				"\x00\x00\x00\v\x00\x00\x00\n1234567890\x00\x00\x00\x01a"),
   131  			out: []byte("1234567890a1234567890a"),
   132  		},
   133  	}
   134  
   135  	for i, tcase := range tests {
   136  		t.Run(strconv.Itoa(i), func(t *testing.T) {
   137  			c := &compressor{Codec: mockCodec{}}
   138  			out, err := c.decompressCellblocks(tcase.in)
   139  
   140  			if !test.ErrEqual(tcase.err, err) {
   141  				t.Errorf("expected err %q, got %q", tcase.err, err)
   142  			}
   143  
   144  			if !bytes.Equal(tcase.out, out) {
   145  				t.Errorf("expected out %q, got %q", tcase.out, out)
   146  			}
   147  		})
   148  	}
   149  }
   150  
   151  var blockLenghts = []int{10, 100, 1000, 10000}
   152  
   153  func BenchmarkDecompressCellblocks1(b *testing.B) {
   154  	for _, bl := range blockLenghts {
   155  		b.Run(fmt.Sprintf("BlockLen%d", bl), func(b *testing.B) {
   156  			benchmarkDecompressCellblocks(b, bl, 1)
   157  		})
   158  	}
   159  }
   160  
   161  func BenchmarkDecompressCellblocks10(b *testing.B) {
   162  	for _, bl := range blockLenghts {
   163  		b.Run(fmt.Sprintf("BlockLen%d", bl), func(b *testing.B) {
   164  			benchmarkDecompressCellblocks(b, bl, 10)
   165  		})
   166  	}
   167  }
   168  
   169  func benchmarkDecompressCellblocks(b *testing.B, blockLen int, blocksCount int) {
   170  	b.ReportAllocs()
   171  
   172  	data := make([]byte, blockLen)
   173  	r := rand.New(rand.NewSource(42))
   174  
   175  	c := &compressor{Codec: mockCodec{}}
   176  
   177  	var compressedCellblocks []byte
   178  	for i := 0; i < blocksCount; i++ {
   179  		_, err := r.Read(data)
   180  		if err != nil {
   181  			b.FailNow()
   182  		}
   183  
   184  		cellblocks := c.compressCellblocks(net.Buffers{data}, uint32(blockLen))
   185  		compressedCellblocks = append(compressedCellblocks, cellblocks...)
   186  	}
   187  
   188  	uncompressedCellblocksLen := blockLen * blocksCount
   189  
   190  	b.ResetTimer()
   191  	for n := 0; n < b.N; n++ {
   192  		uncompressedCellblocks, err := c.decompressCellblocks(compressedCellblocks)
   193  		if err != nil || len(uncompressedCellblocks) != uncompressedCellblocksLen {
   194  			b.Fail()
   195  		}
   196  	}
   197  }