github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/x/xio/segment_reader_test.go (about) 1 // Copyright (c) 2016 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package xio 22 23 import ( 24 "encoding/binary" 25 "io" 26 "testing" 27 28 "github.com/m3db/m3/src/dbnode/ts" 29 "github.com/m3db/m3/src/x/checked" 30 "github.com/m3db/m3/src/x/pool" 31 32 "github.com/stretchr/testify/require" 33 ) 34 35 var ( 36 head = []byte{ 37 0x20, 0xc5, 0x10, 0x55, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x0, 0x0, 0x0, 0x0, 38 0xa0, 0x90, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x28, 0x3f, 0x2f, 39 0xc0, 0x1, 0xf4, 0x1, 0x0, 0x0, 0x0, 0x2, 0x1, 0x2, 0x7, 0x10, 0x1e, 40 0x0, 0x1, 0x0, 0xe0, 0x65, 0x58, 41 } 42 tail = []byte{ 43 0xcd, 0x3, 0x0, 0x0, 0x0, 0x0, 44 } 45 46 expected = []byte{ 47 0x20, 0xc5, 0x10, 0x55, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x0, 0x0, 0x0, 0x0, 48 0xa0, 0x90, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x28, 0x3f, 0x2f, 49 0xc0, 0x1, 0xf4, 0x1, 0x0, 0x0, 0x0, 0x2, 0x1, 0x2, 0x7, 0x10, 0x1e, 50 0x0, 0x1, 0x0, 0xe0, 0x65, 0x58, 0xcd, 0x3, 0x0, 0x0, 0x0, 0x0, 51 } 52 ) 53 54 type byteFunc func(d []byte) checked.Bytes 55 56 func checkedNoPool(d []byte) checked.Bytes { 57 return checked.NewBytes(d, nil) 58 } 59 60 func testSegmentReader( 61 t *testing.T, 62 checkd byteFunc, 63 pool pool.CheckedBytesPool, 64 ) { 65 checksum := uint32(10) 66 segment := ts.NewSegment(checkd(head), checkd(tail), checksum, ts.FinalizeNone) 67 r := NewSegmentReader(segment) 68 bytes, err := ToBytes(r) 69 require.Equal(t, io.EOF, err) 70 require.Equal(t, expected, bytes) 71 72 seg, err := r.Segment() 73 require.NoError(t, err) 74 require.Equal(t, head, seg.Head.Bytes()) 75 require.Equal(t, tail, seg.Tail.Bytes()) 76 require.Equal(t, checksum, seg.CalculateChecksum()) 77 78 // Ensure cloned segment reader does not share original head and tail. 79 cloned, err := r.Clone(pool) 80 require.NoError(t, err) 81 82 segment.Head.Reset(tail) 83 segment.Tail.Reset(head) 84 85 seg, err = cloned.Segment() 86 require.NoError(t, err) 87 require.Equal(t, head, seg.Head.Bytes()) 88 require.Equal(t, tail, seg.Tail.Bytes()) 89 require.Equal(t, checksum, seg.CalculateChecksum()) 90 91 cloned.Finalize() 92 segment.Finalize() 93 } 94 95 func TestSegmentReaderNoPool(t *testing.T) { 96 testSegmentReader(t, checkedNoPool, nil) 97 } 98 99 func TestSegmentReaderWithPool(t *testing.T) { 100 bytesPool := pool.NewCheckedBytesPool([]pool.Bucket{{ 101 Capacity: 1024, 102 Count: 10, 103 }}, nil, func(s []pool.Bucket) pool.BytesPool { 104 return pool.NewBytesPool(s, nil) 105 }) 106 bytesPool.Init() 107 checkd := func(d []byte) checked.Bytes { 108 b := bytesPool.Get(len(d)) 109 b.IncRef() 110 b.Reset(d) 111 b.DecRef() 112 return b 113 } 114 115 testSegmentReader(t, checkd, bytesPool) 116 } 117 118 func TestSegmentReader64(t *testing.T) { 119 data := make([]byte, 32) 120 for i := range data { 121 data[i] = 100 + byte(i) 122 } 123 124 for headLen := 0; headLen < len(data); headLen++ { 125 for tailLen := 0; tailLen < len(data)-headLen; tailLen++ { 126 testSegmentReader64(t, data[:headLen], data[headLen:headLen+tailLen]) 127 } 128 } 129 } 130 131 func testSegmentReader64(t *testing.T, head []byte, tail []byte) { 132 t.Helper() 133 134 var expected []byte 135 expected = append(expected, head...) 136 expected = append(expected, tail...) 137 138 var ( 139 segment = ts.NewSegment(checkedNoPool(head), checkedNoPool(tail), 0, ts.FinalizeNone) 140 r = NewSegmentReader(segment) 141 peeked, read []byte 142 buf [8]byte 143 word uint64 144 n byte 145 err error 146 ) 147 148 for { 149 word, n, err = r.Peek64() 150 if err != nil { 151 break 152 } 153 binary.BigEndian.PutUint64(buf[:], word) 154 peeked = append(peeked, buf[:n]...) 155 156 word, n, err = r.Read64() 157 require.NoError(t, err) 158 159 binary.BigEndian.PutUint64(buf[:], word) 160 read = append(read, buf[:n]...) 161 } 162 163 require.Equal(t, io.EOF, err) 164 require.Equal(t, expected, peeked) 165 require.Equal(t, expected, read) 166 167 _, _, err = r.Read64() 168 require.Equal(t, io.EOF, err) 169 }