github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/encoding/m3tsz/iterator_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 m3tsz
    22  
    23  import (
    24  	"encoding/base64"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/m3db/m3/src/dbnode/encoding"
    29  	"github.com/m3db/m3/src/dbnode/ts"
    30  	"github.com/m3db/m3/src/dbnode/x/xio"
    31  	xtime "github.com/m3db/m3/src/x/time"
    32  
    33  	"github.com/stretchr/testify/require"
    34  )
    35  
    36  func getTestReaderIterator(rawBytes []byte) *readerIterator {
    37  	return NewReaderIterator(
    38  		xio.NewBytesReader64(rawBytes),
    39  		false,
    40  		encoding.NewOptions(),
    41  	).(*readerIterator)
    42  }
    43  
    44  func TestReaderIteratorReadNextTimestamp(t *testing.T) {
    45  	inputs := []struct {
    46  		previousTimeDelta time.Duration
    47  		timeUnit          xtime.Unit
    48  		rawBytes          []byte
    49  		expectedTimeDelta time.Duration
    50  	}{
    51  		{62 * time.Second, xtime.Second, []byte{0x0}, 62 * time.Second},
    52  		{65 * time.Second, xtime.Second, []byte{0xa0, 0x0}, time.Second},
    53  		{65 * time.Second, xtime.Second, []byte{0x90, 0x0}, 97 * time.Second},
    54  		{65 * time.Second, xtime.Second, []byte{0xd0, 0x0}, -191 * time.Second},
    55  		{65 * time.Second, xtime.Second, []byte{0xcf, 0xf0}, 320 * time.Second},
    56  		{65 * time.Second, xtime.Second, []byte{0xe8, 0x0}, -1983 * time.Second},
    57  		{65 * time.Second, xtime.Second, []byte{0xe7, 0xff}, 2112 * time.Second},
    58  		{65 * time.Second, xtime.Second, []byte{0xf0, 0x0, 0x1, 0x0, 0x0}, 4161 * time.Second},
    59  		{65 * time.Second, xtime.Second, []byte{0xff, 0xff, 0xff, 0x0, 0x0}, -4031 * time.Second},
    60  		{65 * time.Second, xtime.Nanosecond, []byte{0xff, 0xff, 0xff, 0xc4, 0x65, 0x36, 0x0, 0x0, 0x0}, -4031 * time.Second},
    61  		{65 * time.Second, xtime.Second, []byte{0x80, 0x40, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7d, 0x0}, 65000001 * time.Microsecond},
    62  	}
    63  
    64  	for _, input := range inputs {
    65  		stream := encoding.NewIStream(xio.NewBytesReader64(input.rawBytes))
    66  		it := NewTimestampIterator(encoding.NewOptions(), false)
    67  
    68  		it.TimeUnit = input.timeUnit
    69  		it.PrevTimeDelta = input.previousTimeDelta
    70  		tes, _ := it.timeEncodingSchemes.SchemeForUnit(it.TimeUnit)
    71  		it.timeEncodingScheme = tes
    72  
    73  		err := it.readNextTimestamp(stream)
    74  		require.NoError(t, err)
    75  		require.Equal(t, input.expectedTimeDelta, it.PrevTimeDelta)
    76  	}
    77  
    78  	stream := encoding.NewIStream(xio.NewBytesReader64([]byte{0x1}))
    79  	it := NewTimestampIterator(encoding.NewOptions(), false)
    80  	err := it.readFirstTimestamp(stream)
    81  	require.Error(t, err)
    82  
    83  	err = it.readNextTimestamp(stream)
    84  	require.Error(t, err)
    85  
    86  	err = it.readNextTimestamp(stream)
    87  	require.Error(t, err)
    88  }
    89  
    90  func TestReaderIteratorReadNextValue(t *testing.T) {
    91  	inputs := []struct {
    92  		previousValue    uint64
    93  		previousValueXOR uint64
    94  		rawBytes         []byte
    95  		expectedValueXOR uint64
    96  		expectedValue    uint64
    97  	}{
    98  		{0x1234, 0x4028000000000000, []byte{0x0}, 0x0, 0x1234},
    99  		{0xaaaaaa, 0x4028000000000000, []byte{0x80, 0x90}, 0x0120000000000000, 0x0120000000aaaaaa},
   100  		{0xdeadbeef, 0x0120000000000000, []byte{0xc1, 0x2e, 0x1, 0x40}, 0x4028000000000000, 0x40280000deadbeef},
   101  	}
   102  	for _, input := range inputs {
   103  		it := getTestReaderIterator(input.rawBytes)
   104  		it.floatIter.PrevFloatBits = input.previousValue
   105  		it.floatIter.PrevXOR = input.previousValueXOR
   106  		it.readNextValue()
   107  		require.Equal(t, input.expectedValueXOR, it.floatIter.PrevXOR)
   108  		require.Equal(t, input.expectedValue, it.floatIter.PrevFloatBits)
   109  		require.NoError(t, it.Err())
   110  	}
   111  
   112  	it := getTestReaderIterator([]byte{0xf0})
   113  	it.readNextValue()
   114  	require.Error(t, it.Err())
   115  }
   116  
   117  func TestReaderIteratorReadAnnotation(t *testing.T) {
   118  	inputs := []struct {
   119  		rawBytes           []byte
   120  		expectedAnnotation ts.Annotation
   121  	}{
   122  		{
   123  			[]byte{0x0, 0xff},
   124  			[]byte{0xff},
   125  		},
   126  		{
   127  			[]byte{0x2, 0x2, 0x3},
   128  			[]byte{0x2, 0x3},
   129  		},
   130  		{
   131  			[]byte{0xe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
   132  			[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
   133  		},
   134  		{
   135  			[]byte{0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
   136  			[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
   137  		},
   138  	}
   139  	for _, input := range inputs {
   140  		stream := encoding.NewIStream(xio.NewBytesReader64(input.rawBytes))
   141  		it := NewTimestampIterator(encoding.NewOptions(), false)
   142  
   143  		err := it.readAnnotation(stream)
   144  		require.NoError(t, err)
   145  		require.Equal(t, input.expectedAnnotation, it.PrevAnt)
   146  	}
   147  }
   148  
   149  func TestReaderIteratorReadTimeUnit(t *testing.T) {
   150  	inputs := []struct {
   151  		timeUnit                xtime.Unit
   152  		rawBytes                []byte
   153  		expectedTimeUnit        xtime.Unit
   154  		expectedTimeUnitChanged bool
   155  	}{
   156  		{
   157  			xtime.Millisecond,
   158  			[]byte{0x1},
   159  			xtime.Second,
   160  			true,
   161  		},
   162  		{
   163  			xtime.Second,
   164  			[]byte{0x0},
   165  			xtime.None,
   166  			false,
   167  		},
   168  	}
   169  	for _, input := range inputs {
   170  		stream := encoding.NewIStream(xio.NewBytesReader64(input.rawBytes))
   171  		it := NewTimestampIterator(encoding.NewOptions(), false)
   172  		it.TimeUnit = input.timeUnit
   173  
   174  		err := it.ReadTimeUnit(stream)
   175  		require.NoError(t, err)
   176  		require.Equal(t, input.expectedTimeUnit, it.TimeUnit)
   177  		require.Equal(t, input.expectedTimeUnitChanged, it.TimeUnitChanged)
   178  	}
   179  }
   180  
   181  func TestReaderIteratorNextNoAnnotation(t *testing.T) {
   182  	rawBytes := []byte{
   183  		0x13, 0xce, 0x4c, 0xa4, 0x30, 0xcb, 0x40, 0x0, 0x9f, 0x20, 0x14, 0x0, 0x0,
   184  		0x0, 0x0, 0x0, 0x0, 0x5f, 0x8c, 0xb0, 0x3a, 0x0, 0xe1, 0x0, 0x78, 0x0, 0x0,
   185  		0x40, 0x6, 0x58, 0x76, 0x8e, 0x0, 0x0,
   186  	}
   187  	startTime := xtime.FromSeconds(1427162462)
   188  	inputs := []ts.Datapoint{
   189  		{TimestampNanos: startTime, Value: 12},
   190  		{TimestampNanos: startTime.Add(time.Second * 60), Value: 12},
   191  		{TimestampNanos: startTime.Add(time.Second * 120), Value: 24},
   192  		{TimestampNanos: startTime.Add(-time.Second * 76), Value: 24},
   193  		{TimestampNanos: startTime.Add(-time.Second * 16), Value: 24},
   194  		{TimestampNanos: startTime.Add(time.Second * 2092), Value: 15},
   195  		{TimestampNanos: startTime.Add(time.Second * 4200), Value: 12},
   196  	}
   197  	it := getTestReaderIterator(rawBytes)
   198  	for i := 0; i < len(inputs); i++ {
   199  		require.True(t, it.Next())
   200  		v, u, a := it.Current()
   201  		require.Nil(t, a)
   202  		require.Equal(t, inputs[i].TimestampNanos, v.TimestampNanos)
   203  		require.Equal(t, inputs[i].Value, v.Value)
   204  		require.Equal(t, xtime.Second, u)
   205  		require.NoError(t, it.Err())
   206  		require.False(t, it.hasError())
   207  		require.False(t, it.isDone())
   208  	}
   209  
   210  	for i := 0; i < 2; i++ {
   211  		require.False(t, it.Next())
   212  		require.NoError(t, it.Err())
   213  		require.False(t, it.hasError())
   214  		require.True(t, it.isDone())
   215  	}
   216  
   217  	it = getTestReaderIterator([]byte{0xf0})
   218  	it.readNextValue()
   219  	require.False(t, it.Next())
   220  	require.False(t, it.isDone())
   221  	require.True(t, it.hasError())
   222  }
   223  
   224  func TestReaderIteratorNextWithAnnotation(t *testing.T) {
   225  	rawBytes := []byte{
   226  		0x13, 0xce, 0x4c, 0xa4, 0x30, 0xcb, 0x40, 0x0, 0x80, 0x20, 0x1, 0x53, 0xe4,
   227  		0x2, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xf1, 0x96, 0x7, 0x40, 0x10, 0x4,
   228  		0x8, 0x4, 0xb, 0x84, 0x1, 0xe0, 0x0, 0x1, 0x0, 0x19, 0x61, 0xda, 0x38, 0x0,
   229  	}
   230  	startTime := xtime.FromSeconds(1427162462)
   231  	inputs := []struct {
   232  		dp  ts.Datapoint
   233  		ant ts.Annotation
   234  	}{
   235  		{ts.Datapoint{TimestampNanos: startTime, Value: 12}, []byte{0xa}},
   236  		{ts.Datapoint{TimestampNanos: startTime.Add(time.Second * 60), Value: 12}, nil},
   237  		{ts.Datapoint{TimestampNanos: startTime.Add(time.Second * 120), Value: 24}, nil},
   238  		{ts.Datapoint{TimestampNanos: startTime.Add(-time.Second * 76), Value: 24}, nil},
   239  		{ts.Datapoint{TimestampNanos: startTime.Add(-time.Second * 16), Value: 24}, []byte{0x1, 0x2}},
   240  		{ts.Datapoint{TimestampNanos: startTime.Add(time.Second * 2092), Value: 15}, nil},
   241  		{ts.Datapoint{TimestampNanos: startTime.Add(time.Second * 4200), Value: 12}, nil},
   242  	}
   243  	it := getTestReaderIterator(rawBytes)
   244  	for i := 0; i < len(inputs); i++ {
   245  		require.True(t, it.Next())
   246  		v, u, a := it.Current()
   247  		require.Equal(t, inputs[i].ant, a)
   248  		require.Equal(t, inputs[i].dp.TimestampNanos, v.TimestampNanos)
   249  		require.Equal(t, inputs[i].dp.Value, v.Value)
   250  		require.Equal(t, xtime.Second, u)
   251  		require.NoError(t, it.Err())
   252  		require.False(t, it.hasError())
   253  		require.False(t, it.isDone())
   254  	}
   255  
   256  	for i := 0; i < 2; i++ {
   257  		require.False(t, it.Next())
   258  		require.NoError(t, it.Err())
   259  		require.False(t, it.hasError())
   260  		require.True(t, it.isDone())
   261  	}
   262  
   263  	it = getTestReaderIterator(
   264  		[]byte{0x0, 0x0, 0x0, 0x0, 0x55, 0x10, 0xc5, 0x20, 0x80, 0x20, 0x1, 0x50, 0x8},
   265  	)
   266  	require.False(t, it.Next())
   267  	require.False(t, it.isDone())
   268  	require.True(t, it.hasError())
   269  }
   270  
   271  func TestReaderIteratorNextWithTimeUnit(t *testing.T) {
   272  	rawBytes := []byte{
   273  		0x13, 0xce, 0x4c, 0xa4, 0x30, 0xcb, 0x40, 0x0, 0x9f, 0x20, 0x14, 0x0, 0x0,
   274  		0x0, 0x0, 0x0, 0x0, 0x5f, 0x8c, 0xb0, 0x3a, 0x0, 0xe1, 0x0, 0x40, 0x20,
   275  		0x4f, 0xff, 0xff, 0xff, 0x22, 0x58, 0x60, 0xd0, 0xc, 0xb0, 0xee, 0x1, 0x1,
   276  		0x0, 0x0, 0x0, 0x1, 0xa4, 0x36, 0x76, 0x80, 0x47, 0x0, 0x80, 0x7f, 0xff,
   277  		0xff, 0xff, 0x7f, 0xd9, 0x9a, 0x80, 0x11, 0x44, 0x0,
   278  	}
   279  	startTime := xtime.FromSeconds(1427162462)
   280  	inputs := []struct {
   281  		dp ts.Datapoint
   282  		tu xtime.Unit
   283  	}{
   284  		{ts.Datapoint{TimestampNanos: startTime, Value: 12}, xtime.Second},
   285  		{ts.Datapoint{TimestampNanos: startTime.Add(time.Second * 60), Value: 12}, xtime.Second},
   286  		{ts.Datapoint{TimestampNanos: startTime.Add(time.Second * 120), Value: 24}, xtime.Second},
   287  		{ts.Datapoint{TimestampNanos: startTime.Add(-time.Second * 76), Value: 24}, xtime.Second},
   288  		{ts.Datapoint{TimestampNanos: startTime.Add(-time.Second * 16), Value: 24}, xtime.Second},
   289  		{ts.Datapoint{TimestampNanos: startTime.Add(-time.Nanosecond * 15500000000), Value: 15}, xtime.Nanosecond},
   290  		{ts.Datapoint{TimestampNanos: startTime.Add(-time.Millisecond * 1400), Value: 12}, xtime.Millisecond},
   291  		{ts.Datapoint{TimestampNanos: startTime.Add(-time.Second * 10), Value: 12}, xtime.Second},
   292  		{ts.Datapoint{TimestampNanos: startTime.Add(time.Second * 10), Value: 12}, xtime.Second},
   293  	}
   294  	it := getTestReaderIterator(rawBytes)
   295  	for i := 0; i < len(inputs); i++ {
   296  		require.True(t, it.Next())
   297  		v, u, _ := it.Current()
   298  		require.Equal(t, inputs[i].dp.TimestampNanos, v.TimestampNanos)
   299  		require.Equal(t, inputs[i].dp.Value, v.Value)
   300  		require.Equal(t, inputs[i].tu, u)
   301  
   302  		require.NoError(t, it.Err())
   303  		require.False(t, it.hasError())
   304  		require.False(t, it.isDone())
   305  	}
   306  
   307  	for i := 0; i < 2; i++ {
   308  		require.False(t, it.Next())
   309  		require.NoError(t, it.Err())
   310  		require.False(t, it.hasError())
   311  		require.True(t, it.isDone())
   312  	}
   313  }
   314  
   315  func TestReaderIteratorNextWithAnnotationAndTimeUnit(t *testing.T) {
   316  	rawBytes := []byte{
   317  		0x13, 0xce, 0x4c, 0xa4, 0x30, 0xcb, 0x40, 0x0, 0x80, 0x20, 0x1, 0x53, 0xe4,
   318  		0x2, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xf1, 0x96, 0x6, 0x0, 0x81, 0x0,
   319  		0x81, 0x68, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1d, 0xcd, 0x65, 0x0, 0x0, 0x20,
   320  		0x8, 0x20, 0x18, 0x20, 0x2f, 0xf, 0xa6, 0x58, 0x77, 0x0, 0x80, 0x40, 0x0,
   321  		0x0, 0x0, 0xe, 0xe6, 0xb2, 0x80, 0x23, 0x80, 0x0,
   322  	}
   323  	startTime := xtime.FromSeconds(1427162462)
   324  	inputs := []struct {
   325  		dp  ts.Datapoint
   326  		ant ts.Annotation
   327  		tu  xtime.Unit
   328  	}{
   329  		{
   330  			ts.Datapoint{TimestampNanos: startTime, Value: 12},
   331  			[]byte{0xa},
   332  			xtime.Second,
   333  		},
   334  		{
   335  			dp:  ts.Datapoint{TimestampNanos: startTime.Add(time.Second * 60), Value: 12},
   336  			ant: nil,
   337  			tu:  xtime.Second,
   338  		},
   339  		{
   340  			dp:  ts.Datapoint{TimestampNanos: startTime.Add(time.Second * 120), Value: 24},
   341  			ant: nil,
   342  			tu:  xtime.Second,
   343  		},
   344  		{
   345  			dp:  ts.Datapoint{TimestampNanos: startTime.Add(-time.Second * 76), Value: 24},
   346  			ant: []byte{0x1, 0x2},
   347  			tu:  xtime.Second,
   348  		},
   349  		{
   350  			dp:  ts.Datapoint{TimestampNanos: startTime.Add(-time.Second * 16), Value: 24},
   351  			ant: nil,
   352  			tu:  xtime.Millisecond,
   353  		},
   354  		{
   355  			dp:  ts.Datapoint{TimestampNanos: startTime.Add(-time.Millisecond * 15500), Value: 15},
   356  			ant: []byte{0x3, 0x4, 0x5},
   357  			tu:  xtime.Millisecond,
   358  		},
   359  		{
   360  			dp:  ts.Datapoint{TimestampNanos: startTime.Add(-time.Millisecond * 14000), Value: 12},
   361  			ant: nil,
   362  			tu:  xtime.Second,
   363  		},
   364  	}
   365  	it := getTestReaderIterator(rawBytes)
   366  	for i := 0; i < len(inputs); i++ {
   367  		require.True(t, it.Next())
   368  		v, u, a := it.Current()
   369  		require.Equal(t, inputs[i].ant, a)
   370  		require.Equal(t, inputs[i].dp.TimestampNanos, v.TimestampNanos)
   371  		require.Equal(t, inputs[i].dp.Value, v.Value)
   372  		require.Equal(t, inputs[i].tu, u)
   373  
   374  		require.NoError(t, it.Err())
   375  		require.False(t, it.hasError())
   376  		require.False(t, it.isDone())
   377  	}
   378  
   379  	for i := 0; i < 2; i++ {
   380  		require.False(t, it.Next())
   381  		require.NoError(t, it.Err())
   382  		require.False(t, it.hasError())
   383  		require.True(t, it.isDone())
   384  	}
   385  }
   386  
   387  func TestReaderIteratorNextWithUnexpectedTimeUnit(t *testing.T) {
   388  	rawBytes := []byte{
   389  		0x0, 0x0, 0x0, 0x0, 0x55, 0x10, 0xc5, 0x20, 0x80, 0x41, 0x20, 0x0, 0x0,
   390  	}
   391  	it := getTestReaderIterator(rawBytes)
   392  	require.False(t, it.Next())
   393  	require.Error(t, it.Err())
   394  }
   395  
   396  func TestReaderIteratorDecodingRegression(t *testing.T) {
   397  	// This reproduces the regression that was introduced in
   398  	// https://github.com/m3db/m3/commit/abad1bb2e9a4de18afcb9a29e87fa3a39a694ef4
   399  	// by failing decoding (returns unexpected EOF error after the first call to Next()).
   400  	b64 := "FnLaQ5ZggACAIEEAUAgIAAAJ1XOXnQH+QAAAAAAAAAB4AAOpgUJ3igWXnNAAYAAAAAEuYPEbxWsXrvGZl9ZGm8J3+1YS3vGZjVZdm8RvK6xHuz1rxmZU2R6u8j/a+wE2rxmY02e2vEbzbsRuvGZtzZOq8J3ivYO6vIXOm8ZmL1lq7xG89rEWbxmfVWT/vAf9qrBFm8Zme1jq7yFxevEbzpsW6vGZivZOq8J39zYRuvGZm3Zba8RvGmxNqzr7xmY9WSpu+h+61gR7vGZldZ9m8RvGqxLe8Zm7VkabwneX1g+u8hcVrxmZc2XqvEbxfsSqvGZ/zZFa8B/yrsF/rxmZU2Ras/e8RvKqxFm8Zm91ku7wneK1h+m8ZmXVkb7xG92rEqbxmY7WPbvIXK67if/HmwBaq8Zma9kerxG/qbE3rxmY12W2vCd5s2EarO/vGZnVZFm8RvbaxOu8ZmL1nqbwH/PqwRXvGZtVZPmzrrxG8W7E9rxmbU2RavCd532HurxmY02TWvEb27sRuvGZmzY6q8hcd7vofm1YFqbxmY/WSrvEb/WsR5vGZlVZd+8J3jVYS5s9a8ZmNdkvrxG96bEWrxmZb2fqvAf8WbBK68Zm/dkVrxG8qbD+ryFyvvGZi1Zem8J3ltYRbvGZ/dgA" // nolint: lll
   401  
   402  	data, err := base64.StdEncoding.DecodeString(b64)
   403  	require.NoError(t, err)
   404  
   405  	it := NewReaderIterator(xio.NewBytesReader64(data), true, encoding.NewOptions())
   406  	for i := 0; it.Next(); i++ {
   407  		require.NoError(t, it.Err())
   408  		it.Current()
   409  	}
   410  
   411  	require.NoError(t, it.Err())
   412  }