github.com/m3db/m3@v1.5.0/src/dbnode/storage/block/block_proto_test.go (about)

     1  // Copyright (c) 2019 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 block
    22  
    23  import (
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/golang/mock/gomock"
    28  	"github.com/m3db/m3/src/dbnode/namespace"
    29  	"github.com/m3db/m3/src/dbnode/testdata/prototest"
    30  	"github.com/m3db/m3/src/dbnode/ts"
    31  	"github.com/m3db/m3/src/dbnode/x/xio"
    32  	"github.com/m3db/m3/src/x/ident"
    33  	xtime "github.com/m3db/m3/src/x/time"
    34  
    35  	"github.com/stretchr/testify/require"
    36  )
    37  
    38  var (
    39  	testNamespace     = ident.StringID("block_test_ns")
    40  	testSchemaHistory = prototest.NewSchemaHistory()
    41  	testSchema        = prototest.NewMessageDescriptor(testSchemaHistory)
    42  	testSchemaDesc    = namespace.GetTestSchemaDescr(testSchema)
    43  	testProtoMessages = prototest.NewProtoTestMessages(testSchema)
    44  )
    45  
    46  // TestDatabaseBlockMergeProto lazily merges two blocks and verifies that the correct
    47  // data is returned.
    48  func TestDatabaseBlockMergeProto(t *testing.T) {
    49  	ctrl := gomock.NewController(t)
    50  	defer ctrl.Finish()
    51  
    52  	// Test proto messages
    53  	piter := prototest.NewProtoMessageIterator(testProtoMessages)
    54  
    55  	// Test data
    56  	curr := xtime.Now()
    57  	data := []ts.Datapoint{
    58  		{
    59  			TimestampNanos: curr,
    60  			Value:          0,
    61  		},
    62  		{
    63  			TimestampNanos: curr.Add(time.Second),
    64  			Value:          0,
    65  		},
    66  	}
    67  	durations := []time.Duration{
    68  		time.Minute,
    69  		time.Hour,
    70  	}
    71  
    72  	testNamespaceCtx := namespace.Context{
    73  		ID:     testNamespace,
    74  		Schema: testSchemaDesc,
    75  	}
    76  
    77  	// Setup encoding pools.
    78  	blockOpts := NewOptions().
    79  		SetReaderIteratorPool(prototest.ProtoPools.ReaderIterPool).
    80  		SetEncoderPool(prototest.ProtoPools.EncoderPool).
    81  		SetMultiReaderIteratorPool(prototest.ProtoPools.MultiReaderIterPool)
    82  
    83  	// Create the two blocks we plan to merge
    84  	encoder := blockOpts.EncoderPool().Get()
    85  
    86  	encoder.Reset(data[0].TimestampNanos, 10, testSchemaDesc)
    87  	encoder.Encode(data[0], xtime.Second, piter.Next())
    88  	seg := encoder.Discard()
    89  	block1 := NewDatabaseBlock(data[0].TimestampNanos, durations[0], seg, blockOpts, testNamespaceCtx).(*dbBlock)
    90  
    91  	encoder.Reset(data[1].TimestampNanos, 10, testSchemaDesc)
    92  	encoder.Encode(data[1], xtime.Second, piter.Next())
    93  	seg = encoder.Discard()
    94  	block2 := NewDatabaseBlock(data[1].TimestampNanos, durations[1], seg, blockOpts, testNamespaceCtx).(*dbBlock)
    95  
    96  	// Lazily merge the two blocks
    97  	block1.Merge(block2)
    98  
    99  	// BlockSize should not change
   100  	require.Equal(t, durations[0], block1.BlockSize())
   101  
   102  	// Try and read the data back and verify it looks good
   103  	depCtx := block1.opts.ContextPool().Get()
   104  	stream, err := block1.Stream(depCtx)
   105  	require.NoError(t, err)
   106  	seg, err = stream.Segment()
   107  	require.NoError(t, err)
   108  	reader := xio.NewSegmentReader(seg)
   109  	iter := blockOpts.ReaderIteratorPool().Get()
   110  	iter.Reset(reader, testSchemaDesc)
   111  
   112  	piter.Reset()
   113  	i := 0
   114  	for iter.Next() {
   115  		dp, _, annotation := iter.Current()
   116  		require.True(t, data[i].Equal(dp))
   117  		prototest.RequireEqual(t, testSchema, piter.Next(), annotation)
   118  		i++
   119  	}
   120  	require.NoError(t, iter.Err())
   121  	require.Equal(t, 2, i)
   122  
   123  	// Make sure the checksum was updated
   124  	mergedChecksum, err := block1.Checksum()
   125  	require.NoError(t, err)
   126  	require.Equal(t, seg.CalculateChecksum(), mergedChecksum)
   127  
   128  	depCtx.BlockingClose()
   129  	block1.Close()
   130  	block2.Close()
   131  }