github.com/grafana/pyroscope@v1.18.0/pkg/phlaredb/tsdb/index/postings_test.go (about) 1 // Copyright 2017 The Prometheus Authors 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package index 15 16 import ( 17 "encoding/binary" 18 "fmt" 19 "math/rand" 20 "sort" 21 "strconv" 22 "testing" 23 24 "github.com/prometheus/prometheus/storage" 25 "github.com/stretchr/testify/require" 26 27 "github.com/grafana/pyroscope/pkg/iter" 28 phlaremodel "github.com/grafana/pyroscope/pkg/model" 29 ) 30 31 func TestMemPostings_addFor(t *testing.T) { 32 p := NewMemPostings() 33 p.m[allPostingsKey.Name] = map[string][]storage.SeriesRef{} 34 p.m[allPostingsKey.Name][allPostingsKey.Value] = []storage.SeriesRef{1, 2, 3, 4, 6, 7, 8} 35 36 p.addFor(5, allPostingsKey) 37 38 require.Equal(t, []storage.SeriesRef{1, 2, 3, 4, 5, 6, 7, 8}, p.m[allPostingsKey.Name][allPostingsKey.Value]) 39 } 40 41 func TestMemPostings_ensureOrder(t *testing.T) { 42 p := NewUnorderedMemPostings() 43 p.m["a"] = map[string][]storage.SeriesRef{} 44 45 for i := 0; i < 100; i++ { 46 l := make([]storage.SeriesRef, 100) 47 for j := range l { 48 l[j] = storage.SeriesRef(rand.Uint64()) 49 } 50 v := fmt.Sprintf("%d", i) 51 52 p.m["a"][v] = l 53 } 54 55 p.EnsureOrder() 56 57 for _, e := range p.m { 58 for _, l := range e { 59 ok := sort.SliceIsSorted(l, func(i, j int) bool { 60 return l[i] < l[j] 61 }) 62 if !ok { 63 t.Fatalf("postings list %v is not sorted", l) 64 } 65 } 66 } 67 } 68 69 func BenchmarkMemPostings_ensureOrder(b *testing.B) { 70 tests := map[string]struct { 71 numLabels int 72 numValuesPerLabel int 73 numRefsPerValue int 74 }{ 75 "many values per label": { 76 numLabels: 100, 77 numValuesPerLabel: 10000, 78 numRefsPerValue: 100, 79 }, 80 "few values per label": { 81 numLabels: 1000000, 82 numValuesPerLabel: 1, 83 numRefsPerValue: 100, 84 }, 85 "few refs per label value": { 86 numLabels: 1000, 87 numValuesPerLabel: 1000, 88 numRefsPerValue: 10, 89 }, 90 } 91 92 for testName, testData := range tests { 93 b.Run(testName, func(b *testing.B) { 94 p := NewUnorderedMemPostings() 95 96 // Generate postings. 97 for l := 0; l < testData.numLabels; l++ { 98 labelName := strconv.Itoa(l) 99 p.m[labelName] = map[string][]storage.SeriesRef{} 100 101 for v := 0; v < testData.numValuesPerLabel; v++ { 102 refs := make([]storage.SeriesRef, testData.numRefsPerValue) 103 for j := range refs { 104 refs[j] = storage.SeriesRef(rand.Uint64()) 105 } 106 107 labelValue := strconv.Itoa(v) 108 p.m[labelName][labelValue] = refs 109 } 110 } 111 112 b.ResetTimer() 113 114 for n := 0; n < b.N; n++ { 115 p.EnsureOrder() 116 p.ordered = false 117 } 118 }) 119 } 120 } 121 122 func TestIntersect(t *testing.T) { 123 a := iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3}) 124 b := iter.NewSliceSeekIterator([]storage.SeriesRef{2, 3, 4}) 125 126 cases := []struct { 127 in []Postings 128 129 res Postings 130 }{ 131 { 132 in: []Postings{}, 133 res: EmptyPostings(), 134 }, 135 { 136 in: []Postings{a, b, EmptyPostings()}, 137 res: EmptyPostings(), 138 }, 139 { 140 in: []Postings{b, a, EmptyPostings()}, 141 res: EmptyPostings(), 142 }, 143 { 144 in: []Postings{EmptyPostings(), b, a}, 145 res: EmptyPostings(), 146 }, 147 { 148 in: []Postings{EmptyPostings(), a, b}, 149 res: EmptyPostings(), 150 }, 151 { 152 in: []Postings{a, EmptyPostings(), b}, 153 res: EmptyPostings(), 154 }, 155 { 156 in: []Postings{b, EmptyPostings(), a}, 157 res: EmptyPostings(), 158 }, 159 { 160 in: []Postings{b, EmptyPostings(), a, a, b, a, a, a}, 161 res: EmptyPostings(), 162 }, 163 { 164 in: []Postings{ 165 iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3, 4, 5}), 166 iter.NewSliceSeekIterator([]storage.SeriesRef{6, 7, 8, 9, 10}), 167 }, 168 res: iter.NewSliceSeekIterator([]storage.SeriesRef{}), 169 }, 170 { 171 in: []Postings{ 172 iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3, 4, 5}), 173 iter.NewSliceSeekIterator([]storage.SeriesRef{4, 5, 6, 7, 8}), 174 }, 175 res: iter.NewSliceSeekIterator([]storage.SeriesRef{4, 5}), 176 }, 177 { 178 in: []Postings{ 179 iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3, 4, 9, 10}), 180 iter.NewSliceSeekIterator([]storage.SeriesRef{1, 4, 5, 6, 7, 8, 10, 11}), 181 }, 182 res: iter.NewSliceSeekIterator([]storage.SeriesRef{1, 4, 10}), 183 }, 184 { 185 in: []Postings{ 186 iter.NewSliceSeekIterator([]storage.SeriesRef{1}), 187 iter.NewSliceSeekIterator([]storage.SeriesRef{0, 1}), 188 }, 189 res: iter.NewSliceSeekIterator([]storage.SeriesRef{1}), 190 }, 191 { 192 in: []Postings{ 193 iter.NewSliceSeekIterator([]storage.SeriesRef{1}), 194 }, 195 res: iter.NewSliceSeekIterator([]storage.SeriesRef{1}), 196 }, 197 { 198 in: []Postings{ 199 iter.NewSliceSeekIterator([]storage.SeriesRef{1}), 200 iter.NewSliceSeekIterator([]storage.SeriesRef{}), 201 }, 202 res: iter.NewSliceSeekIterator([]storage.SeriesRef{}), 203 }, 204 { 205 in: []Postings{ 206 iter.NewSliceSeekIterator([]storage.SeriesRef{}), 207 iter.NewSliceSeekIterator([]storage.SeriesRef{}), 208 }, 209 res: iter.NewSliceSeekIterator([]storage.SeriesRef{}), 210 }, 211 } 212 213 for _, c := range cases { 214 t.Run("", func(t *testing.T) { 215 if c.res == nil { 216 t.Fatal("intersect result expectancy cannot be nil") 217 } 218 219 expected, err := ExpandPostings(c.res) 220 require.NoError(t, err) 221 222 i := Intersect(c.in...) 223 224 if c.res == EmptyPostings() { 225 require.Equal(t, EmptyPostings(), i) 226 return 227 } 228 229 if i == EmptyPostings() { 230 t.Fatal("intersect unexpected result: EmptyPostings sentinel") 231 } 232 233 res, err := ExpandPostings(i) 234 require.NoError(t, err) 235 require.Equal(t, expected, res) 236 }) 237 } 238 } 239 240 func TestMultiIntersect(t *testing.T) { 241 cases := []struct { 242 p [][]storage.SeriesRef 243 res []storage.SeriesRef 244 }{ 245 { 246 p: [][]storage.SeriesRef{ 247 {1, 2, 3, 4, 5, 6, 1000, 1001}, 248 {2, 4, 5, 6, 7, 8, 999, 1001}, 249 {1, 2, 5, 6, 7, 8, 1001, 1200}, 250 }, 251 res: []storage.SeriesRef{2, 5, 6, 1001}, 252 }, 253 // One of the reproducible cases for: 254 // https://github.com/prometheus/prometheus/issues/2616 255 // The initialisation of intersectPostings was moving the iterator forward 256 // prematurely making us miss some postings. 257 { 258 p: [][]storage.SeriesRef{ 259 {1, 2}, 260 {1, 2}, 261 {1, 2}, 262 {2}, 263 }, 264 res: []storage.SeriesRef{2}, 265 }, 266 } 267 268 for _, c := range cases { 269 ps := make([]Postings, 0, len(c.p)) 270 for _, postings := range c.p { 271 ps = append(ps, iter.NewSliceSeekIterator(postings)) 272 } 273 274 res, err := ExpandPostings(Intersect(ps...)) 275 276 require.NoError(t, err) 277 require.Equal(t, c.res, res) 278 } 279 } 280 281 func BenchmarkIntersect(t *testing.B) { 282 t.Run("LongPostings1", func(bench *testing.B) { 283 var a, b, c, d []storage.SeriesRef 284 285 for i := 0; i < 10000000; i += 2 { 286 a = append(a, storage.SeriesRef(i)) 287 } 288 for i := 5000000; i < 5000100; i += 4 { 289 b = append(b, storage.SeriesRef(i)) 290 } 291 for i := 5090000; i < 5090600; i += 4 { 292 b = append(b, storage.SeriesRef(i)) 293 } 294 for i := 4990000; i < 5100000; i++ { 295 c = append(c, storage.SeriesRef(i)) 296 } 297 for i := 4000000; i < 6000000; i++ { 298 d = append(d, storage.SeriesRef(i)) 299 } 300 301 i1 := iter.NewSliceSeekIterator(a) 302 i2 := iter.NewSliceSeekIterator(b) 303 i3 := iter.NewSliceSeekIterator(c) 304 i4 := iter.NewSliceSeekIterator(d) 305 306 bench.ResetTimer() 307 bench.ReportAllocs() 308 for i := 0; i < bench.N; i++ { 309 if _, err := ExpandPostings(Intersect(i1, i2, i3, i4)); err != nil { 310 bench.Fatal(err) 311 } 312 } 313 }) 314 315 t.Run("LongPostings2", func(bench *testing.B) { 316 var a, b, c, d []storage.SeriesRef 317 318 for i := 0; i < 12500000; i++ { 319 a = append(a, storage.SeriesRef(i)) 320 } 321 for i := 7500000; i < 12500000; i++ { 322 b = append(b, storage.SeriesRef(i)) 323 } 324 for i := 9000000; i < 20000000; i++ { 325 c = append(c, storage.SeriesRef(i)) 326 } 327 for i := 10000000; i < 12000000; i++ { 328 d = append(d, storage.SeriesRef(i)) 329 } 330 331 i1 := iter.NewSliceSeekIterator(a) 332 i2 := iter.NewSliceSeekIterator(b) 333 i3 := iter.NewSliceSeekIterator(c) 334 i4 := iter.NewSliceSeekIterator(d) 335 336 bench.ResetTimer() 337 bench.ReportAllocs() 338 for i := 0; i < bench.N; i++ { 339 if _, err := ExpandPostings(Intersect(i1, i2, i3, i4)); err != nil { 340 bench.Fatal(err) 341 } 342 } 343 }) 344 345 // Many matchers(k >> n). 346 t.Run("ManyPostings", func(bench *testing.B) { 347 var its []Postings 348 349 // 100000 matchers(k=100000). 350 for i := 0; i < 100000; i++ { 351 var temp []storage.SeriesRef 352 for j := storage.SeriesRef(1); j < 100; j++ { 353 temp = append(temp, j) 354 } 355 its = append(its, iter.NewSliceSeekIterator(temp)) 356 } 357 358 bench.ResetTimer() 359 bench.ReportAllocs() 360 for i := 0; i < bench.N; i++ { 361 if _, err := ExpandPostings(Intersect(its...)); err != nil { 362 bench.Fatal(err) 363 } 364 } 365 }) 366 } 367 368 func TestMultiMerge(t *testing.T) { 369 i1 := iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3, 4, 5, 6, 1000, 1001}) 370 i2 := iter.NewSliceSeekIterator([]storage.SeriesRef{2, 4, 5, 6, 7, 8, 999, 1001}) 371 i3 := iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 5, 6, 7, 8, 1001, 1200}) 372 373 res, err := ExpandPostings(Merge(i1, i2, i3)) 374 require.NoError(t, err) 375 require.Equal(t, []storage.SeriesRef{1, 2, 3, 4, 5, 6, 7, 8, 999, 1000, 1001, 1200}, res) 376 } 377 378 func TestMergedPostings(t *testing.T) { 379 cases := []struct { 380 in []Postings 381 382 res Postings 383 }{ 384 { 385 in: []Postings{}, 386 res: EmptyPostings(), 387 }, 388 { 389 in: []Postings{ 390 iter.NewSliceSeekIterator([]storage.SeriesRef{}), 391 iter.NewSliceSeekIterator([]storage.SeriesRef{}), 392 }, 393 res: EmptyPostings(), 394 }, 395 { 396 in: []Postings{ 397 iter.NewSliceSeekIterator([]storage.SeriesRef{}), 398 }, 399 res: iter.NewSliceSeekIterator([]storage.SeriesRef{}), 400 }, 401 { 402 in: []Postings{ 403 EmptyPostings(), 404 EmptyPostings(), 405 EmptyPostings(), 406 EmptyPostings(), 407 }, 408 res: EmptyPostings(), 409 }, 410 { 411 in: []Postings{ 412 iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3, 4, 5}), 413 iter.NewSliceSeekIterator([]storage.SeriesRef{6, 7, 8, 9, 10}), 414 }, 415 res: iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}), 416 }, 417 { 418 in: []Postings{ 419 iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3, 4, 5}), 420 iter.NewSliceSeekIterator([]storage.SeriesRef{4, 5, 6, 7, 8}), 421 }, 422 res: iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3, 4, 5, 6, 7, 8}), 423 }, 424 { 425 in: []Postings{ 426 iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3, 4, 9, 10}), 427 iter.NewSliceSeekIterator([]storage.SeriesRef{1, 4, 5, 6, 7, 8, 10, 11}), 428 }, 429 res: iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}), 430 }, 431 { 432 in: []Postings{ 433 iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3, 4, 9, 10}), 434 EmptyPostings(), 435 iter.NewSliceSeekIterator([]storage.SeriesRef{1, 4, 5, 6, 7, 8, 10, 11}), 436 }, 437 res: iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}), 438 }, 439 { 440 in: []Postings{ 441 iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2}), 442 iter.NewSliceSeekIterator([]storage.SeriesRef{}), 443 }, 444 res: iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2}), 445 }, 446 { 447 in: []Postings{ 448 iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2}), 449 EmptyPostings(), 450 }, 451 res: iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2}), 452 }, 453 } 454 455 for _, c := range cases { 456 t.Run("", func(t *testing.T) { 457 if c.res == nil { 458 t.Fatal("merge result expectancy cannot be nil") 459 } 460 461 expected, err := ExpandPostings(c.res) 462 require.NoError(t, err) 463 464 m := Merge(c.in...) 465 466 if c.res == EmptyPostings() { 467 require.Equal(t, EmptyPostings(), m) 468 return 469 } 470 471 if m == EmptyPostings() { 472 t.Fatal("merge unexpected result: EmptyPostings sentinel") 473 } 474 475 res, err := ExpandPostings(m) 476 require.NoError(t, err) 477 require.Equal(t, expected, res) 478 }) 479 } 480 } 481 482 func TestMergedPostingsSeek(t *testing.T) { 483 cases := []struct { 484 a, b []storage.SeriesRef 485 486 seek storage.SeriesRef 487 success bool 488 res []storage.SeriesRef 489 }{ 490 { 491 a: []storage.SeriesRef{2, 3, 4, 5}, 492 b: []storage.SeriesRef{6, 7, 8, 9, 10}, 493 494 seek: 1, 495 success: true, 496 res: []storage.SeriesRef{2, 3, 4, 5, 6, 7, 8, 9, 10}, 497 }, 498 { 499 a: []storage.SeriesRef{1, 2, 3, 4, 5}, 500 b: []storage.SeriesRef{6, 7, 8, 9, 10}, 501 502 seek: 2, 503 success: true, 504 res: []storage.SeriesRef{2, 3, 4, 5, 6, 7, 8, 9, 10}, 505 }, 506 { 507 a: []storage.SeriesRef{1, 2, 3, 4, 5}, 508 b: []storage.SeriesRef{4, 5, 6, 7, 8}, 509 510 seek: 9, 511 success: false, 512 res: nil, 513 }, 514 { 515 a: []storage.SeriesRef{1, 2, 3, 4, 9, 10}, 516 b: []storage.SeriesRef{1, 4, 5, 6, 7, 8, 10, 11}, 517 518 seek: 10, 519 success: true, 520 res: []storage.SeriesRef{10, 11}, 521 }, 522 } 523 524 for _, c := range cases { 525 a := iter.NewSliceSeekIterator(c.a) 526 b := iter.NewSliceSeekIterator(c.b) 527 528 p := Merge(a, b) 529 530 require.Equal(t, c.success, p.Seek(c.seek)) 531 532 // After Seek(), At() should be called. 533 if c.success { 534 start := p.At() 535 lst, err := ExpandPostings(p) 536 require.NoError(t, err) 537 538 lst = append([]storage.SeriesRef{start}, lst...) 539 require.Equal(t, c.res, lst) 540 } 541 } 542 } 543 544 func TestRemovedPostings(t *testing.T) { 545 cases := []struct { 546 a, b []storage.SeriesRef 547 res []storage.SeriesRef 548 }{ 549 { 550 a: nil, 551 b: nil, 552 res: []storage.SeriesRef(nil), 553 }, 554 { 555 a: []storage.SeriesRef{1, 2, 3, 4}, 556 b: nil, 557 res: []storage.SeriesRef{1, 2, 3, 4}, 558 }, 559 { 560 a: nil, 561 b: []storage.SeriesRef{1, 2, 3, 4}, 562 res: []storage.SeriesRef(nil), 563 }, 564 { 565 a: []storage.SeriesRef{1, 2, 3, 4, 5}, 566 b: []storage.SeriesRef{6, 7, 8, 9, 10}, 567 res: []storage.SeriesRef{1, 2, 3, 4, 5}, 568 }, 569 { 570 a: []storage.SeriesRef{1, 2, 3, 4, 5}, 571 b: []storage.SeriesRef{4, 5, 6, 7, 8}, 572 res: []storage.SeriesRef{1, 2, 3}, 573 }, 574 { 575 a: []storage.SeriesRef{1, 2, 3, 4, 9, 10}, 576 b: []storage.SeriesRef{1, 4, 5, 6, 7, 8, 10, 11}, 577 res: []storage.SeriesRef{2, 3, 9}, 578 }, 579 { 580 a: []storage.SeriesRef{1, 2, 3, 4, 9, 10}, 581 b: []storage.SeriesRef{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 582 res: []storage.SeriesRef(nil), 583 }, 584 } 585 586 for _, c := range cases { 587 a := iter.NewSliceSeekIterator(c.a) 588 b := iter.NewSliceSeekIterator(c.b) 589 590 res, err := ExpandPostings(newRemovedPostings(a, b)) 591 require.NoError(t, err) 592 require.Equal(t, c.res, res) 593 } 594 } 595 596 func TestRemovedNextStackoverflow(t *testing.T) { 597 var full []storage.SeriesRef 598 var remove []storage.SeriesRef 599 600 var i storage.SeriesRef 601 for i = 0; i < 1e7; i++ { 602 full = append(full, i) 603 remove = append(remove, i) 604 } 605 606 flp := iter.NewSliceSeekIterator(full) 607 rlp := iter.NewSliceSeekIterator(remove) 608 rp := newRemovedPostings(flp, rlp) 609 gotElem := false 610 for rp.Next() { 611 gotElem = true 612 } 613 614 require.NoError(t, rp.Err()) 615 require.False(t, gotElem) 616 } 617 618 func TestRemovedPostingsSeek(t *testing.T) { 619 cases := []struct { 620 a, b []storage.SeriesRef 621 622 seek storage.SeriesRef 623 success bool 624 res []storage.SeriesRef 625 }{ 626 { 627 a: []storage.SeriesRef{2, 3, 4, 5}, 628 b: []storage.SeriesRef{6, 7, 8, 9, 10}, 629 630 seek: 1, 631 success: true, 632 res: []storage.SeriesRef{2, 3, 4, 5}, 633 }, 634 { 635 a: []storage.SeriesRef{1, 2, 3, 4, 5}, 636 b: []storage.SeriesRef{6, 7, 8, 9, 10}, 637 638 seek: 2, 639 success: true, 640 res: []storage.SeriesRef{2, 3, 4, 5}, 641 }, 642 { 643 a: []storage.SeriesRef{1, 2, 3, 4, 5}, 644 b: []storage.SeriesRef{4, 5, 6, 7, 8}, 645 646 seek: 9, 647 success: false, 648 res: nil, 649 }, 650 { 651 a: []storage.SeriesRef{1, 2, 3, 4, 9, 10}, 652 b: []storage.SeriesRef{1, 4, 5, 6, 7, 8, 10, 11}, 653 654 seek: 10, 655 success: false, 656 res: nil, 657 }, 658 { 659 a: []storage.SeriesRef{1, 2, 3, 4, 9, 10}, 660 b: []storage.SeriesRef{1, 4, 5, 6, 7, 8, 11}, 661 662 seek: 4, 663 success: true, 664 res: []storage.SeriesRef{9, 10}, 665 }, 666 { 667 a: []storage.SeriesRef{1, 2, 3, 4, 9, 10}, 668 b: []storage.SeriesRef{1, 4, 5, 6, 7, 8, 11}, 669 670 seek: 5, 671 success: true, 672 res: []storage.SeriesRef{9, 10}, 673 }, 674 { 675 a: []storage.SeriesRef{1, 2, 3, 4, 9, 10}, 676 b: []storage.SeriesRef{1, 4, 5, 6, 7, 8, 11}, 677 678 seek: 10, 679 success: true, 680 res: []storage.SeriesRef{10}, 681 }, 682 } 683 684 for _, c := range cases { 685 a := iter.NewSliceSeekIterator(c.a) 686 b := iter.NewSliceSeekIterator(c.b) 687 688 p := newRemovedPostings(a, b) 689 690 require.Equal(t, c.success, p.Seek(c.seek)) 691 692 // After Seek(), At() should be called. 693 if c.success { 694 start := p.At() 695 lst, err := ExpandPostings(p) 696 require.NoError(t, err) 697 698 lst = append([]storage.SeriesRef{start}, lst...) 699 require.Equal(t, c.res, lst) 700 } 701 } 702 } 703 704 func TestBigEndian(t *testing.T) { 705 num := 1000 706 // mock a list as postings 707 ls := make([]uint32, num) 708 ls[0] = 2 709 for i := 1; i < num; i++ { 710 ls[i] = ls[i-1] + uint32(rand.Int31n(25)) + 2 711 } 712 713 beLst := make([]byte, num*4) 714 for i := 0; i < num; i++ { 715 b := beLst[i*4 : i*4+4] 716 binary.BigEndian.PutUint32(b, ls[i]) 717 } 718 719 t.Run("Iteration", func(t *testing.T) { 720 bep := newBigEndianPostings(beLst) 721 for i := 0; i < num; i++ { 722 require.True(t, bep.Next()) 723 require.Equal(t, storage.SeriesRef(ls[i]), bep.At()) 724 } 725 726 require.False(t, bep.Next()) 727 require.NoError(t, bep.Err()) 728 }) 729 730 t.Run("Seek", func(t *testing.T) { 731 table := []struct { 732 seek uint32 733 val uint32 734 found bool 735 }{ 736 { 737 ls[0] - 1, ls[0], true, 738 }, 739 { 740 ls[4], ls[4], true, 741 }, 742 { 743 ls[500] - 1, ls[500], true, 744 }, 745 { 746 ls[600] + 1, ls[601], true, 747 }, 748 { 749 ls[600] + 1, ls[601], true, 750 }, 751 { 752 ls[600] + 1, ls[601], true, 753 }, 754 { 755 ls[0], ls[601], true, 756 }, 757 { 758 ls[600], ls[601], true, 759 }, 760 { 761 ls[999], ls[999], true, 762 }, 763 { 764 ls[999] + 10, ls[999], false, 765 }, 766 } 767 768 bep := newBigEndianPostings(beLst) 769 770 for _, v := range table { 771 require.Equal(t, v.found, bep.Seek(storage.SeriesRef(v.seek))) 772 require.Equal(t, storage.SeriesRef(v.val), bep.At()) 773 require.NoError(t, bep.Err()) 774 } 775 }) 776 } 777 778 func TestIntersectWithMerge(t *testing.T) { 779 // One of the reproducible cases for: 780 // https://github.com/prometheus/prometheus/issues/2616 781 a := iter.NewSliceSeekIterator([]storage.SeriesRef{21, 22, 23, 24, 25, 30}) 782 783 b := Merge( 784 iter.NewSliceSeekIterator([]storage.SeriesRef{10, 20, 30}), 785 iter.NewSliceSeekIterator([]storage.SeriesRef{15, 26, 30}), 786 ) 787 788 p := Intersect(a, b) 789 res, err := ExpandPostings(p) 790 791 require.NoError(t, err) 792 require.Equal(t, []storage.SeriesRef{30}, res) 793 } 794 795 func TestWithoutPostings(t *testing.T) { 796 cases := []struct { 797 base Postings 798 drop Postings 799 800 res Postings 801 }{ 802 { 803 base: EmptyPostings(), 804 drop: EmptyPostings(), 805 806 res: EmptyPostings(), 807 }, 808 { 809 base: EmptyPostings(), 810 drop: iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2}), 811 812 res: EmptyPostings(), 813 }, 814 { 815 base: iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2}), 816 drop: EmptyPostings(), 817 818 res: iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2}), 819 }, 820 { 821 base: iter.NewSliceSeekIterator([]storage.SeriesRef{}), 822 drop: iter.NewSliceSeekIterator([]storage.SeriesRef{}), 823 824 res: iter.NewSliceSeekIterator([]storage.SeriesRef{}), 825 }, 826 { 827 base: iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3}), 828 drop: iter.NewSliceSeekIterator([]storage.SeriesRef{}), 829 830 res: iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3}), 831 }, 832 { 833 base: iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3}), 834 drop: iter.NewSliceSeekIterator([]storage.SeriesRef{4, 5, 6}), 835 836 res: iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3}), 837 }, 838 { 839 base: iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2, 3}), 840 drop: iter.NewSliceSeekIterator([]storage.SeriesRef{3, 4, 5}), 841 842 res: iter.NewSliceSeekIterator([]storage.SeriesRef{1, 2}), 843 }, 844 } 845 846 for _, c := range cases { 847 t.Run("", func(t *testing.T) { 848 if c.res == nil { 849 t.Fatal("without result expectancy cannot be nil") 850 } 851 852 expected, err := ExpandPostings(c.res) 853 require.NoError(t, err) 854 855 w := Without(c.base, c.drop) 856 857 if c.res == EmptyPostings() { 858 require.Equal(t, EmptyPostings(), w) 859 return 860 } 861 862 if w == EmptyPostings() { 863 t.Fatal("without unexpected result: EmptyPostings sentinel") 864 } 865 866 res, err := ExpandPostings(w) 867 require.NoError(t, err) 868 require.Equal(t, expected, res) 869 }) 870 } 871 } 872 873 func BenchmarkPostings_Stats(b *testing.B) { 874 p := NewMemPostings() 875 876 var seriesID storage.SeriesRef 877 878 createPostingsLabelValues := func(name, valuePrefix string, count int) { 879 for n := 1; n < count; n++ { 880 value := fmt.Sprintf("%s-%d", valuePrefix, n) 881 p.Add(seriesID, phlaremodel.LabelsFromStrings(name, value)) 882 seriesID++ 883 } 884 } 885 createPostingsLabelValues("__name__", "metrics_name_can_be_very_big_and_bad", 1e3) 886 for i := 0; i < 20; i++ { 887 createPostingsLabelValues(fmt.Sprintf("host-%d", i), "metrics_name_can_be_very_big_and_bad", 1e3) 888 createPostingsLabelValues(fmt.Sprintf("instance-%d", i), "10.0.IP.", 1e3) 889 createPostingsLabelValues(fmt.Sprintf("job-%d", i), "Small_Job_name", 1e3) 890 createPostingsLabelValues(fmt.Sprintf("err-%d", i), "avg_namespace-", 1e3) 891 createPostingsLabelValues(fmt.Sprintf("team-%d", i), "team-", 1e3) 892 createPostingsLabelValues(fmt.Sprintf("container_name-%d", i), "pod-", 1e3) 893 createPostingsLabelValues(fmt.Sprintf("cluster-%d", i), "newcluster-", 1e3) 894 createPostingsLabelValues(fmt.Sprintf("uid-%d", i), "123412312312312311-", 1e3) 895 createPostingsLabelValues(fmt.Sprintf("area-%d", i), "new_area_of_work-", 1e3) 896 createPostingsLabelValues(fmt.Sprintf("request_id-%d", i), "owner_name_work-", 1e3) 897 } 898 b.ResetTimer() 899 for n := 0; n < b.N; n++ { 900 p.Stats("__name__") 901 } 902 } 903 904 func TestMemPostings_Delete(t *testing.T) { 905 p := NewMemPostings() 906 p.Add(1, phlaremodel.LabelsFromStrings("lbl1", "a")) 907 p.Add(2, phlaremodel.LabelsFromStrings("lbl1", "b")) 908 p.Add(3, phlaremodel.LabelsFromStrings("lbl2", "a")) 909 910 before := p.Get(allPostingsKey.Name, allPostingsKey.Value) 911 p.Delete(map[storage.SeriesRef]struct{}{ 912 2: {}, 913 }) 914 after := p.Get(allPostingsKey.Name, allPostingsKey.Value) 915 916 // Make sure postings gotten before the delete have the old data when 917 // iterated over. 918 expanded, err := ExpandPostings(before) 919 require.NoError(t, err) 920 require.Equal(t, []storage.SeriesRef{1, 2, 3}, expanded) 921 922 // Make sure postings gotten after the delete have the new data when 923 // iterated over. 924 expanded, err = ExpandPostings(after) 925 require.NoError(t, err) 926 require.Equal(t, []storage.SeriesRef{1, 3}, expanded) 927 928 deleted := p.Get("lbl1", "b") 929 expanded, err = ExpandPostings(deleted) 930 require.NoError(t, err) 931 require.Equal(t, 0, len(expanded), "expected empty postings, got %v", expanded) 932 } 933 934 func TestShardedPostings(t *testing.T) { 935 offsets := FingerprintOffsets{ 936 {0, 0}, 937 {5, 0b1 << 62}, 938 {10, 0b1 << 63}, 939 {15, 0b11 << 62}, 940 } 941 shard := NewShard(0, 2) 942 var refs []storage.SeriesRef 943 for i := 0; i < 20; i++ { 944 refs = append(refs, storage.SeriesRef(i)) 945 } 946 ps := iter.NewSliceSeekIterator(refs) 947 shardedPostings := NewShardedPostings(ps, shard, offsets) 948 949 for i := 0; i < 10; i++ { 950 require.Equal(t, true, shardedPostings.Next()) 951 require.Equal(t, storage.SeriesRef(i), shardedPostings.At()) 952 } 953 require.Equal(t, false, shardedPostings.Next()) 954 }