github.com/m3db/m3@v1.5.0/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  }