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 }