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