github.com/thanos-io/thanos@v0.32.5/pkg/block/indexheader/reader_pool_test.go (about)

     1  // Copyright (c) The Thanos Authors.
     2  // Licensed under the Apache License 2.0.
     3  
     4  package indexheader
     5  
     6  import (
     7  	"context"
     8  	"path/filepath"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/go-kit/log"
    13  	promtestutil "github.com/prometheus/client_golang/prometheus/testutil"
    14  	"github.com/prometheus/prometheus/model/labels"
    15  	"github.com/thanos-io/objstore/providers/filesystem"
    16  
    17  	"github.com/efficientgo/core/testutil"
    18  	"github.com/thanos-io/thanos/pkg/block"
    19  	"github.com/thanos-io/thanos/pkg/block/metadata"
    20  	"github.com/thanos-io/thanos/pkg/testutil/e2eutil"
    21  )
    22  
    23  func TestReaderPool_NewBinaryReader(t *testing.T) {
    24  	tests := map[string]struct {
    25  		lazyReaderEnabled     bool
    26  		lazyReaderIdleTimeout time.Duration
    27  	}{
    28  		"lazy reader is disabled": {
    29  			lazyReaderEnabled: false,
    30  		},
    31  		"lazy reader is enabled but close on idle timeout is disabled": {
    32  			lazyReaderEnabled:     true,
    33  			lazyReaderIdleTimeout: 0,
    34  		},
    35  		"lazy reader and close on idle timeout are both enabled": {
    36  			lazyReaderEnabled:     true,
    37  			lazyReaderIdleTimeout: time.Minute,
    38  		},
    39  	}
    40  
    41  	ctx := context.Background()
    42  
    43  	tmpDir := t.TempDir()
    44  
    45  	bkt, err := filesystem.NewBucket(filepath.Join(tmpDir, "bkt"))
    46  	testutil.Ok(t, err)
    47  	defer func() { testutil.Ok(t, bkt.Close()) }()
    48  
    49  	// Create block.
    50  	blockID, err := e2eutil.CreateBlock(ctx, tmpDir, []labels.Labels{
    51  		{{Name: "a", Value: "1"}},
    52  		{{Name: "a", Value: "2"}},
    53  	}, 100, 0, 1000, labels.Labels{{Name: "ext1", Value: "1"}}, 124, metadata.NoneFunc)
    54  	testutil.Ok(t, err)
    55  	testutil.Ok(t, block.Upload(ctx, log.NewNopLogger(), bkt, filepath.Join(tmpDir, blockID.String()), metadata.NoneFunc))
    56  
    57  	for testName, testData := range tests {
    58  		t.Run(testName, func(t *testing.T) {
    59  			pool := NewReaderPool(log.NewNopLogger(), testData.lazyReaderEnabled, testData.lazyReaderIdleTimeout, NewReaderPoolMetrics(nil))
    60  			defer pool.Close()
    61  
    62  			r, err := pool.NewBinaryReader(ctx, log.NewNopLogger(), bkt, tmpDir, blockID, 3)
    63  			testutil.Ok(t, err)
    64  			defer func() { testutil.Ok(t, r.Close()) }()
    65  
    66  			// Ensure it can read data.
    67  			labelNames, err := r.LabelNames()
    68  			testutil.Ok(t, err)
    69  			testutil.Equals(t, []string{"a"}, labelNames)
    70  		})
    71  	}
    72  }
    73  
    74  func TestReaderPool_ShouldCloseIdleLazyReaders(t *testing.T) {
    75  	const idleTimeout = time.Second
    76  
    77  	ctx := context.Background()
    78  
    79  	tmpDir := t.TempDir()
    80  
    81  	bkt, err := filesystem.NewBucket(filepath.Join(tmpDir, "bkt"))
    82  	testutil.Ok(t, err)
    83  	defer func() { testutil.Ok(t, bkt.Close()) }()
    84  
    85  	// Create block.
    86  	blockID, err := e2eutil.CreateBlock(ctx, tmpDir, []labels.Labels{
    87  		{{Name: "a", Value: "1"}},
    88  		{{Name: "a", Value: "2"}},
    89  	}, 100, 0, 1000, labels.Labels{{Name: "ext1", Value: "1"}}, 124, metadata.NoneFunc)
    90  	testutil.Ok(t, err)
    91  	testutil.Ok(t, block.Upload(ctx, log.NewNopLogger(), bkt, filepath.Join(tmpDir, blockID.String()), metadata.NoneFunc))
    92  
    93  	metrics := NewReaderPoolMetrics(nil)
    94  	pool := NewReaderPool(log.NewNopLogger(), true, idleTimeout, metrics)
    95  	defer pool.Close()
    96  
    97  	r, err := pool.NewBinaryReader(ctx, log.NewNopLogger(), bkt, tmpDir, blockID, 3)
    98  	testutil.Ok(t, err)
    99  	defer func() { testutil.Ok(t, r.Close()) }()
   100  
   101  	// Ensure it can read data.
   102  	labelNames, err := r.LabelNames()
   103  	testutil.Ok(t, err)
   104  	testutil.Equals(t, []string{"a"}, labelNames)
   105  	testutil.Equals(t, float64(1), promtestutil.ToFloat64(metrics.lazyReader.loadCount))
   106  	testutil.Equals(t, float64(0), promtestutil.ToFloat64(metrics.lazyReader.unloadCount))
   107  
   108  	// Wait enough time before checking it.
   109  	time.Sleep(idleTimeout * 2)
   110  
   111  	// We expect the reader has been closed, but not released from the pool.
   112  	testutil.Assert(t, pool.isTracking(r.(*LazyBinaryReader)))
   113  	testutil.Equals(t, float64(1), promtestutil.ToFloat64(metrics.lazyReader.loadCount))
   114  	testutil.Equals(t, float64(1), promtestutil.ToFloat64(metrics.lazyReader.unloadCount))
   115  
   116  	// Ensure it can still read data (will be re-opened).
   117  	labelNames, err = r.LabelNames()
   118  	testutil.Ok(t, err)
   119  	testutil.Equals(t, []string{"a"}, labelNames)
   120  	testutil.Assert(t, pool.isTracking(r.(*LazyBinaryReader)))
   121  	testutil.Equals(t, float64(2), promtestutil.ToFloat64(metrics.lazyReader.loadCount))
   122  	testutil.Equals(t, float64(1), promtestutil.ToFloat64(metrics.lazyReader.unloadCount))
   123  
   124  	// We expect an explicit call to Close() to close the reader and release it from the pool too.
   125  	testutil.Ok(t, r.Close())
   126  	testutil.Assert(t, !pool.isTracking(r.(*LazyBinaryReader)))
   127  	testutil.Equals(t, float64(2), promtestutil.ToFloat64(metrics.lazyReader.loadCount))
   128  	testutil.Equals(t, float64(2), promtestutil.ToFloat64(metrics.lazyReader.unloadCount))
   129  }