github.com/grafana/pyroscope@v1.18.0/pkg/phlaredb/bucketindex/loader_test.go (about) 1 // SPDX-License-Identifier: AGPL-3.0-only 2 // Provenance-includes-location: https://github.com/cortexproject/cortex/blob/master/pkg/storage/tsdb/bucketindex/loader_test.go 3 // Provenance-includes-license: Apache-2.0 4 // Provenance-includes-copyright: The Cortex Authors. 5 6 package bucketindex 7 8 import ( 9 "bytes" 10 "context" 11 "path" 12 "strings" 13 "testing" 14 "time" 15 16 "github.com/go-kit/log" 17 "github.com/grafana/dskit/services" 18 "github.com/grafana/dskit/test" 19 "github.com/oklog/ulid/v2" 20 "github.com/prometheus/client_golang/prometheus" 21 "github.com/prometheus/client_golang/prometheus/testutil" 22 "github.com/stretchr/testify/assert" 23 "github.com/stretchr/testify/require" 24 25 objstore_testutil "github.com/grafana/pyroscope/pkg/objstore/testutil" 26 ) 27 28 func TestLoader_GetIndex_ShouldLazyLoadBucketIndex(t *testing.T) { 29 ctx := context.Background() 30 reg := prometheus.NewPedanticRegistry() 31 bkt, _ := objstore_testutil.NewFilesystemBucket(t, ctx, t.TempDir()) 32 33 // Create a bucket index. 34 idx := &Index{ 35 Version: IndexVersion1, 36 Blocks: Blocks{ 37 {ID: ulid.MustNew(1, nil), MinTime: 10, MaxTime: 20}, 38 }, 39 BlockDeletionMarks: nil, 40 UpdatedAt: time.Now().Unix(), 41 } 42 require.NoError(t, WriteIndex(ctx, bkt, "user-1", nil, idx)) 43 44 // Create the loader. 45 loader := NewLoader(prepareLoaderConfig(), bkt, nil, log.NewNopLogger(), reg) 46 require.NoError(t, services.StartAndAwaitRunning(ctx, loader)) 47 t.Cleanup(func() { 48 require.NoError(t, services.StopAndAwaitTerminated(ctx, loader)) 49 }) 50 51 // Ensure no index has been loaded yet. 52 assert.NoError(t, testutil.GatherAndCompare(reg, bytes.NewBufferString(` 53 # HELP pyroscope_bucket_index_load_failures_total Total number of bucket index loading failures. 54 # TYPE pyroscope_bucket_index_load_failures_total counter 55 pyroscope_bucket_index_load_failures_total 0 56 # HELP pyroscope_bucket_index_loaded Number of bucket indexes currently loaded in-memory. 57 # TYPE pyroscope_bucket_index_loaded gauge 58 pyroscope_bucket_index_loaded 0 59 # HELP pyroscope_bucket_index_loads_total Total number of bucket index loading attempts. 60 # TYPE pyroscope_bucket_index_loads_total counter 61 pyroscope_bucket_index_loads_total 0 62 `), 63 "pyroscope_bucket_index_loads_total", 64 "pyroscope_bucket_index_load_failures_total", 65 "pyroscope_bucket_index_loaded", 66 )) 67 68 // Request the index multiple times. 69 for i := 0; i < 10; i++ { 70 actualIdx, err := loader.GetIndex(ctx, "user-1") 71 require.NoError(t, err) 72 assert.Equal(t, idx, actualIdx) 73 } 74 75 // Ensure metrics have been updated accordingly. 76 assert.NoError(t, testutil.GatherAndCompare(reg, bytes.NewBufferString(` 77 # HELP pyroscope_bucket_index_load_failures_total Total number of bucket index loading failures. 78 # TYPE pyroscope_bucket_index_load_failures_total counter 79 pyroscope_bucket_index_load_failures_total 0 80 # HELP pyroscope_bucket_index_loaded Number of bucket indexes currently loaded in-memory. 81 # TYPE pyroscope_bucket_index_loaded gauge 82 pyroscope_bucket_index_loaded 1 83 # HELP pyroscope_bucket_index_loads_total Total number of bucket index loading attempts. 84 # TYPE pyroscope_bucket_index_loads_total counter 85 pyroscope_bucket_index_loads_total 1 86 `), 87 "pyroscope_bucket_index_loads_total", 88 "pyroscope_bucket_index_load_failures_total", 89 "pyroscope_bucket_index_loaded", 90 )) 91 } 92 93 func TestLoader_GetIndex_ShouldCacheError(t *testing.T) { 94 ctx := context.Background() 95 reg := prometheus.NewPedanticRegistry() 96 bkt, _ := objstore_testutil.NewFilesystemBucket(t, ctx, t.TempDir()) 97 98 // Create the loader. 99 loader := NewLoader(prepareLoaderConfig(), bkt, nil, log.NewNopLogger(), reg) 100 require.NoError(t, services.StartAndAwaitRunning(ctx, loader)) 101 t.Cleanup(func() { 102 require.NoError(t, services.StopAndAwaitTerminated(ctx, loader)) 103 }) 104 105 // Write a corrupted index. 106 require.NoError(t, bkt.Upload(ctx, path.Join("user-1", "phlaredb/", IndexCompressedFilename), strings.NewReader("invalid!}"))) 107 108 // Request the index multiple times. 109 for i := 0; i < 10; i++ { 110 _, err := loader.GetIndex(ctx, "user-1") 111 require.Equal(t, ErrIndexCorrupted, err) 112 } 113 114 // Ensure metrics have been updated accordingly. 115 assert.NoError(t, testutil.GatherAndCompare(reg, bytes.NewBufferString(` 116 # HELP pyroscope_bucket_index_load_failures_total Total number of bucket index loading failures. 117 # TYPE pyroscope_bucket_index_load_failures_total counter 118 pyroscope_bucket_index_load_failures_total 1 119 # HELP pyroscope_bucket_index_loaded Number of bucket indexes currently loaded in-memory. 120 # TYPE pyroscope_bucket_index_loaded gauge 121 pyroscope_bucket_index_loaded 0 122 # HELP pyroscope_bucket_index_loads_total Total number of bucket index loading attempts. 123 # TYPE pyroscope_bucket_index_loads_total counter 124 pyroscope_bucket_index_loads_total 1 125 `), 126 "pyroscope_bucket_index_loads_total", 127 "pyroscope_bucket_index_load_failures_total", 128 "pyroscope_bucket_index_loaded", 129 )) 130 } 131 132 func TestLoader_GetIndex_ShouldCacheIndexNotFoundError(t *testing.T) { 133 ctx := context.Background() 134 reg := prometheus.NewPedanticRegistry() 135 bkt, _ := objstore_testutil.NewFilesystemBucket(t, ctx, t.TempDir()) 136 137 // Create the loader. 138 loader := NewLoader(prepareLoaderConfig(), bkt, nil, log.NewNopLogger(), reg) 139 require.NoError(t, services.StartAndAwaitRunning(ctx, loader)) 140 t.Cleanup(func() { 141 require.NoError(t, services.StopAndAwaitTerminated(ctx, loader)) 142 }) 143 144 // Request the index multiple times. 145 for i := 0; i < 10; i++ { 146 _, err := loader.GetIndex(ctx, "user-1") 147 require.Equal(t, ErrIndexNotFound, err) 148 } 149 150 // Ensure metrics have been updated accordingly. 151 assert.NoError(t, testutil.GatherAndCompare(reg, bytes.NewBufferString(` 152 # HELP pyroscope_bucket_index_load_failures_total Total number of bucket index loading failures. 153 # TYPE pyroscope_bucket_index_load_failures_total counter 154 pyroscope_bucket_index_load_failures_total 0 155 # HELP pyroscope_bucket_index_loaded Number of bucket indexes currently loaded in-memory. 156 # TYPE pyroscope_bucket_index_loaded gauge 157 pyroscope_bucket_index_loaded 0 158 # HELP pyroscope_bucket_index_loads_total Total number of bucket index loading attempts. 159 # TYPE pyroscope_bucket_index_loads_total counter 160 pyroscope_bucket_index_loads_total 1 161 `), 162 "pyroscope_bucket_index_loads_total", 163 "pyroscope_bucket_index_load_failures_total", 164 "pyroscope_bucket_index_loaded", 165 )) 166 } 167 168 func TestLoader_ShouldUpdateIndexInBackgroundOnPreviousLoadSuccess(t *testing.T) { 169 ctx := context.Background() 170 reg := prometheus.NewPedanticRegistry() 171 bkt, _ := objstore_testutil.NewFilesystemBucket(t, ctx, t.TempDir()) 172 173 // Create a bucket index. 174 idx := &Index{ 175 Version: IndexVersion1, 176 Blocks: Blocks{ 177 {ID: ulid.MustNew(1, nil), MinTime: 10, MaxTime: 20}, 178 }, 179 BlockDeletionMarks: nil, 180 UpdatedAt: time.Now().Unix(), 181 } 182 require.NoError(t, WriteIndex(ctx, bkt, "user-1", nil, idx)) 183 184 // Create the loader. 185 cfg := LoaderConfig{ 186 CheckInterval: time.Second, 187 UpdateOnStaleInterval: time.Second, 188 UpdateOnErrorInterval: time.Hour, // Intentionally high to not hit it. 189 IdleTimeout: time.Hour, // Intentionally high to not hit it. 190 } 191 192 loader := NewLoader(cfg, bkt, nil, log.NewNopLogger(), reg) 193 require.NoError(t, services.StartAndAwaitRunning(ctx, loader)) 194 t.Cleanup(func() { 195 require.NoError(t, services.StopAndAwaitTerminated(ctx, loader)) 196 }) 197 198 actualIdx, err := loader.GetIndex(ctx, "user-1") 199 require.NoError(t, err) 200 assert.Equal(t, idx, actualIdx) 201 202 // Update the bucket index. 203 idx.Blocks = append(idx.Blocks, &Block{ID: ulid.MustNew(2, nil), MinTime: 20, MaxTime: 30}) 204 require.NoError(t, WriteIndex(ctx, bkt, "user-1", nil, idx)) 205 206 // Wait until the index has been updated in background. 207 test.Poll(t, 3*time.Second, 2, func() interface{} { 208 actualIdx, err := loader.GetIndex(ctx, "user-1") 209 if err != nil { 210 return 0 211 } 212 return len(actualIdx.Blocks) 213 }) 214 215 actualIdx, err = loader.GetIndex(ctx, "user-1") 216 require.NoError(t, err) 217 assert.Equal(t, idx, actualIdx) 218 219 // Ensure metrics have been updated accordingly. 220 assert.NoError(t, testutil.GatherAndCompare(reg, bytes.NewBufferString(` 221 # HELP pyroscope_bucket_index_load_failures_total Total number of bucket index loading failures. 222 # TYPE pyroscope_bucket_index_load_failures_total counter 223 pyroscope_bucket_index_load_failures_total 0 224 # HELP pyroscope_bucket_index_loaded Number of bucket indexes currently loaded in-memory. 225 # TYPE pyroscope_bucket_index_loaded gauge 226 pyroscope_bucket_index_loaded 1 227 `), 228 "pyroscope_bucket_index_load_failures_total", 229 "pyroscope_bucket_index_loaded", 230 )) 231 } 232 233 func TestLoader_ShouldUpdateIndexInBackgroundOnPreviousLoadFailure(t *testing.T) { 234 ctx := context.Background() 235 reg := prometheus.NewPedanticRegistry() 236 bkt, _ := objstore_testutil.NewFilesystemBucket(t, ctx, t.TempDir()) 237 238 // Write a corrupted index. 239 require.NoError(t, bkt.Upload(ctx, path.Join("user-1", "phlaredb/", IndexCompressedFilename), strings.NewReader("invalid!}"))) 240 241 // Create the loader. 242 cfg := LoaderConfig{ 243 CheckInterval: time.Second, 244 UpdateOnStaleInterval: time.Hour, // Intentionally high to not hit it. 245 UpdateOnErrorInterval: time.Second, 246 IdleTimeout: time.Hour, // Intentionally high to not hit it. 247 } 248 249 loader := NewLoader(cfg, bkt, nil, log.NewNopLogger(), reg) 250 require.NoError(t, services.StartAndAwaitRunning(ctx, loader)) 251 t.Cleanup(func() { 252 require.NoError(t, services.StopAndAwaitTerminated(ctx, loader)) 253 }) 254 255 _, err := loader.GetIndex(ctx, "user-1") 256 assert.Equal(t, ErrIndexCorrupted, err) 257 258 // Upload the bucket index. 259 idx := &Index{ 260 Version: IndexVersion1, 261 Blocks: Blocks{ 262 {ID: ulid.MustNew(1, nil), MinTime: 10, MaxTime: 20}, 263 }, 264 BlockDeletionMarks: nil, 265 UpdatedAt: time.Now().Unix(), 266 } 267 require.NoError(t, WriteIndex(ctx, bkt, "user-1", nil, idx)) 268 269 // Wait until the index has been updated in background. 270 test.Poll(t, 3*time.Second, nil, func() interface{} { 271 _, err := loader.GetIndex(ctx, "user-1") 272 return err 273 }) 274 275 actualIdx, err := loader.GetIndex(ctx, "user-1") 276 require.NoError(t, err) 277 assert.Equal(t, idx, actualIdx) 278 279 // Ensure metrics have been updated accordingly. 280 assert.NoError(t, testutil.GatherAndCompare(reg, bytes.NewBufferString(` 281 # HELP pyroscope_bucket_index_loaded Number of bucket indexes currently loaded in-memory. 282 # TYPE pyroscope_bucket_index_loaded gauge 283 pyroscope_bucket_index_loaded 1 284 `), 285 "pyroscope_bucket_index_loaded", 286 )) 287 } 288 289 func TestLoader_ShouldUpdateIndexInBackgroundOnPreviousIndexNotFound(t *testing.T) { 290 ctx := context.Background() 291 reg := prometheus.NewPedanticRegistry() 292 bkt, _ := objstore_testutil.NewFilesystemBucket(t, ctx, t.TempDir()) 293 294 // Create the loader. 295 cfg := LoaderConfig{ 296 CheckInterval: time.Second, 297 UpdateOnStaleInterval: time.Second, 298 UpdateOnErrorInterval: time.Hour, // Intentionally high to not hit it. 299 IdleTimeout: time.Hour, // Intentionally high to not hit it. 300 } 301 302 loader := NewLoader(cfg, bkt, nil, log.NewNopLogger(), reg) 303 require.NoError(t, services.StartAndAwaitRunning(ctx, loader)) 304 t.Cleanup(func() { 305 require.NoError(t, services.StopAndAwaitTerminated(ctx, loader)) 306 }) 307 308 _, err := loader.GetIndex(ctx, "user-1") 309 assert.Equal(t, ErrIndexNotFound, err) 310 311 // Upload the bucket index. 312 idx := &Index{ 313 Version: IndexVersion1, 314 Blocks: Blocks{ 315 {ID: ulid.MustNew(1, nil), MinTime: 10, MaxTime: 20}, 316 }, 317 BlockDeletionMarks: nil, 318 UpdatedAt: time.Now().Unix(), 319 } 320 require.NoError(t, WriteIndex(ctx, bkt, "user-1", nil, idx)) 321 322 // Wait until the index has been updated in background. 323 test.Poll(t, 3*time.Second, nil, func() interface{} { 324 _, err := loader.GetIndex(ctx, "user-1") 325 return err 326 }) 327 328 actualIdx, err := loader.GetIndex(ctx, "user-1") 329 require.NoError(t, err) 330 assert.Equal(t, idx, actualIdx) 331 332 // Ensure metrics have been updated accordingly. 333 assert.NoError(t, testutil.GatherAndCompare(reg, bytes.NewBufferString(` 334 # HELP pyroscope_bucket_index_loaded Number of bucket indexes currently loaded in-memory. 335 # TYPE pyroscope_bucket_index_loaded gauge 336 pyroscope_bucket_index_loaded 1 337 `), 338 "pyroscope_bucket_index_loaded", 339 )) 340 } 341 342 func TestLoader_ShouldNotCacheCriticalErrorOnBackgroundUpdates(t *testing.T) { 343 ctx := context.Background() 344 reg := prometheus.NewPedanticRegistry() 345 bkt, _ := objstore_testutil.NewFilesystemBucket(t, ctx, t.TempDir()) 346 347 // Create a bucket index. 348 idx := &Index{ 349 Version: IndexVersion1, 350 Blocks: Blocks{ 351 {ID: ulid.MustNew(1, nil), MinTime: 10, MaxTime: 20}, 352 }, 353 BlockDeletionMarks: nil, 354 UpdatedAt: time.Now().Unix(), 355 } 356 require.NoError(t, WriteIndex(ctx, bkt, "user-1", nil, idx)) 357 358 // Create the loader. 359 cfg := LoaderConfig{ 360 CheckInterval: time.Second, 361 UpdateOnStaleInterval: time.Second, 362 UpdateOnErrorInterval: time.Second, 363 IdleTimeout: time.Hour, // Intentionally high to not hit it. 364 } 365 366 loader := NewLoader(cfg, bkt, nil, log.NewNopLogger(), reg) 367 require.NoError(t, services.StartAndAwaitRunning(ctx, loader)) 368 t.Cleanup(func() { 369 require.NoError(t, services.StopAndAwaitTerminated(ctx, loader)) 370 }) 371 372 actualIdx, err := loader.GetIndex(ctx, "user-1") 373 require.NoError(t, err) 374 assert.Equal(t, idx, actualIdx) 375 376 // Write a corrupted index. 377 require.NoError(t, bkt.Upload(ctx, path.Join("user-1", "phlaredb/", IndexCompressedFilename), strings.NewReader("invalid!}"))) 378 379 // Wait until the first failure has been tracked. 380 test.Poll(t, 3*time.Second, true, func() interface{} { 381 return testutil.ToFloat64(loader.loadFailures) > 0 382 }) 383 384 actualIdx, err = loader.GetIndex(ctx, "user-1") 385 require.NoError(t, err) 386 assert.Equal(t, idx, actualIdx) 387 388 // Ensure metrics have been updated accordingly. 389 assert.NoError(t, testutil.GatherAndCompare(reg, bytes.NewBufferString(` 390 # HELP pyroscope_bucket_index_loaded Number of bucket indexes currently loaded in-memory. 391 # TYPE pyroscope_bucket_index_loaded gauge 392 pyroscope_bucket_index_loaded 1 393 `), 394 "pyroscope_bucket_index_loaded", 395 )) 396 } 397 398 func TestLoader_ShouldCacheIndexNotFoundOnBackgroundUpdates(t *testing.T) { 399 ctx := context.Background() 400 reg := prometheus.NewPedanticRegistry() 401 bkt, _ := objstore_testutil.NewFilesystemBucket(t, ctx, t.TempDir()) 402 403 // Create a bucket index. 404 idx := &Index{ 405 Version: IndexVersion1, 406 Blocks: Blocks{ 407 {ID: ulid.MustNew(1, nil), MinTime: 10, MaxTime: 20}, 408 }, 409 BlockDeletionMarks: nil, 410 UpdatedAt: time.Now().Unix(), 411 } 412 require.NoError(t, WriteIndex(ctx, bkt, "user-1", nil, idx)) 413 414 // Create the loader. 415 cfg := LoaderConfig{ 416 CheckInterval: time.Second, 417 UpdateOnStaleInterval: time.Second, 418 UpdateOnErrorInterval: time.Second, 419 IdleTimeout: time.Hour, // Intentionally high to not hit it. 420 } 421 422 loader := NewLoader(cfg, bkt, nil, log.NewNopLogger(), reg) 423 require.NoError(t, services.StartAndAwaitRunning(ctx, loader)) 424 t.Cleanup(func() { 425 require.NoError(t, services.StopAndAwaitTerminated(ctx, loader)) 426 }) 427 428 actualIdx, err := loader.GetIndex(ctx, "user-1") 429 require.NoError(t, err) 430 assert.Equal(t, idx, actualIdx) 431 432 // Delete the bucket index. 433 require.NoError(t, DeleteIndex(ctx, bkt, "user-1", nil)) 434 435 // We expect the bucket index is not considered loaded because of the error. 436 test.Poll(t, 3*time.Second, nil, func() any { 437 return testutil.GatherAndCompare(reg, bytes.NewBufferString(` 438 # HELP pyroscope_bucket_index_loaded Number of bucket indexes currently loaded in-memory. 439 # TYPE pyroscope_bucket_index_loaded gauge 440 pyroscope_bucket_index_loaded 0 441 `), 442 "pyroscope_bucket_index_loaded", 443 ) 444 }) 445 446 // Try to get the index again. We expect no load attempt because the error has been cached. 447 test.Poll(t, 3*time.Second, true, func() any { 448 prevLoads := testutil.ToFloat64(loader.loadAttempts) 449 actualIdx, err = loader.GetIndex(ctx, "user-1") 450 loadAttemps := testutil.ToFloat64(loader.loadAttempts) 451 assert.Equal(t, ErrIndexNotFound, err) 452 assert.Nil(t, actualIdx) 453 return prevLoads == loadAttemps 454 }) 455 } 456 457 func TestLoader_ShouldOffloadIndexIfNotFoundDuringBackgroundUpdates(t *testing.T) { 458 ctx := context.Background() 459 reg := prometheus.NewPedanticRegistry() 460 bkt, _ := objstore_testutil.NewFilesystemBucket(t, ctx, t.TempDir()) 461 462 // Create a bucket index. 463 idx := &Index{ 464 Version: IndexVersion1, 465 Blocks: Blocks{ 466 {ID: ulid.MustNew(1, nil), MinTime: 10, MaxTime: 20}, 467 }, 468 BlockDeletionMarks: nil, 469 UpdatedAt: time.Now().Unix(), 470 } 471 require.NoError(t, WriteIndex(ctx, bkt, "user-1", nil, idx)) 472 473 // Create the loader. 474 cfg := LoaderConfig{ 475 CheckInterval: time.Second, 476 UpdateOnStaleInterval: time.Second, 477 UpdateOnErrorInterval: time.Second, 478 IdleTimeout: time.Hour, // Intentionally high to not hit it. 479 } 480 481 loader := NewLoader(cfg, bkt, nil, log.NewNopLogger(), reg) 482 require.NoError(t, services.StartAndAwaitRunning(ctx, loader)) 483 t.Cleanup(func() { 484 require.NoError(t, services.StopAndAwaitTerminated(ctx, loader)) 485 }) 486 487 actualIdx, err := loader.GetIndex(ctx, "user-1") 488 require.NoError(t, err) 489 assert.Equal(t, idx, actualIdx) 490 491 // Delete the index 492 require.NoError(t, DeleteIndex(ctx, bkt, "user-1", nil)) 493 494 // Wait until the index is offloaded. 495 test.Poll(t, 3*time.Second, float64(0), func() interface{} { 496 return testutil.ToFloat64(loader.loaded) 497 }) 498 499 _, err = loader.GetIndex(ctx, "user-1") 500 require.Equal(t, ErrIndexNotFound, err) 501 502 // Ensure metrics have been updated accordingly. 503 assert.NoError(t, testutil.GatherAndCompare(reg, bytes.NewBufferString(` 504 # HELP pyroscope_bucket_index_loaded Number of bucket indexes currently loaded in-memory. 505 # TYPE pyroscope_bucket_index_loaded gauge 506 pyroscope_bucket_index_loaded 0 507 `), 508 "pyroscope_bucket_index_loaded", 509 )) 510 } 511 512 func TestLoader_ShouldOffloadIndexIfIdleTimeoutIsReachedDuringBackgroundUpdates(t *testing.T) { 513 ctx := context.Background() 514 reg := prometheus.NewPedanticRegistry() 515 bkt, _ := objstore_testutil.NewFilesystemBucket(t, ctx, t.TempDir()) 516 517 // Create a bucket index. 518 idx := &Index{ 519 Version: IndexVersion1, 520 Blocks: Blocks{ 521 {ID: ulid.MustNew(1, nil), MinTime: 10, MaxTime: 20}, 522 }, 523 BlockDeletionMarks: nil, 524 UpdatedAt: time.Now().Unix(), 525 } 526 require.NoError(t, WriteIndex(ctx, bkt, "user-1", nil, idx)) 527 528 // Create the loader. 529 cfg := LoaderConfig{ 530 CheckInterval: time.Second, 531 UpdateOnStaleInterval: time.Second, 532 UpdateOnErrorInterval: time.Second, 533 IdleTimeout: 0, // Offload at first check. 534 } 535 536 loader := NewLoader(cfg, bkt, nil, log.NewNopLogger(), reg) 537 require.NoError(t, services.StartAndAwaitRunning(ctx, loader)) 538 t.Cleanup(func() { 539 require.NoError(t, services.StopAndAwaitTerminated(ctx, loader)) 540 }) 541 542 actualIdx, err := loader.GetIndex(ctx, "user-1") 543 require.NoError(t, err) 544 assert.Equal(t, idx, actualIdx) 545 546 // Wait until the index is offloaded. 547 test.Poll(t, 3*time.Second, float64(0), func() interface{} { 548 return testutil.ToFloat64(loader.loaded) 549 }) 550 551 // Ensure metrics have been updated accordingly. 552 assert.NoError(t, testutil.GatherAndCompare(reg, bytes.NewBufferString(` 553 # HELP pyroscope_bucket_index_loaded Number of bucket indexes currently loaded in-memory. 554 # TYPE pyroscope_bucket_index_loaded gauge 555 pyroscope_bucket_index_loaded 0 556 # HELP pyroscope_bucket_index_loads_total Total number of bucket index loading attempts. 557 # TYPE pyroscope_bucket_index_loads_total counter 558 pyroscope_bucket_index_loads_total 1 559 `), 560 "pyroscope_bucket_index_loaded", 561 "pyroscope_bucket_index_loads_total", 562 )) 563 564 // Load it again. 565 actualIdx, err = loader.GetIndex(ctx, "user-1") 566 require.NoError(t, err) 567 assert.Equal(t, idx, actualIdx) 568 569 // Ensure metrics have been updated accordingly. 570 assert.NoError(t, testutil.GatherAndCompare(reg, bytes.NewBufferString(` 571 # HELP pyroscope_bucket_index_loads_total Total number of bucket index loading attempts. 572 # TYPE pyroscope_bucket_index_loads_total counter 573 pyroscope_bucket_index_loads_total 2 574 `), 575 "pyroscope_bucket_index_loads_total", 576 )) 577 } 578 579 func prepareLoaderConfig() LoaderConfig { 580 return LoaderConfig{ 581 CheckInterval: time.Minute, 582 UpdateOnStaleInterval: 15 * time.Minute, 583 UpdateOnErrorInterval: time.Minute, 584 IdleTimeout: time.Hour, 585 } 586 }