github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/query/pools/query_pools.go (about)

     1  // Copyright (c) 2018 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 pools
    22  
    23  import (
    24  	"github.com/m3db/m3/src/dbnode/encoding"
    25  	"github.com/m3db/m3/src/dbnode/encoding/m3tsz"
    26  	"github.com/m3db/m3/src/dbnode/namespace"
    27  	"github.com/m3db/m3/src/dbnode/x/xio"
    28  	"github.com/m3db/m3/src/dbnode/x/xpool"
    29  	xconfig "github.com/m3db/m3/src/x/config"
    30  	"github.com/m3db/m3/src/x/ident"
    31  	"github.com/m3db/m3/src/x/instrument"
    32  	"github.com/m3db/m3/src/x/pool"
    33  	"github.com/m3db/m3/src/x/serialize"
    34  	xsync "github.com/m3db/m3/src/x/sync"
    35  
    36  	"github.com/uber-go/tally"
    37  )
    38  
    39  const (
    40  	// TODO: add capabilities to get this from configs
    41  	defaultReplicas                    = 3
    42  	defaultSeriesIteratorPoolSize      = 2 << 12 // ~8k
    43  	defaultCheckedBytesWrapperPoolSize = 2 << 12 // ~8k
    44  	defaultPoolableConcurrentQueries   = 64
    45  	defaultPoolableSeriesPerQuery      = 4096
    46  )
    47  
    48  var (
    49  	defaultSeriesIteratorsPoolBuckets = []pool.Bucket{
    50  		{
    51  			Capacity: defaultPoolableSeriesPerQuery,
    52  			Count:    defaultPoolableConcurrentQueries,
    53  		},
    54  	}
    55  	defaultSeriesIDBytesPoolBuckets = []pool.Bucket{
    56  		{
    57  			Capacity: 256, // Can pool IDs up to 256 in size with this bucket.
    58  			Count:    defaultPoolableSeriesPerQuery,
    59  		},
    60  		{
    61  			Capacity: 1024, // Can pool IDs up to 1024 in size with this bucket.
    62  			Count:    defaultPoolableSeriesPerQuery,
    63  		},
    64  	}
    65  )
    66  
    67  // BuildWorkerPools builds a worker pool
    68  func BuildWorkerPools(
    69  	instrumentOptions instrument.Options,
    70  	readPoolPolicy, writePoolPolicy xconfig.WorkerPoolPolicy,
    71  	scope tally.Scope,
    72  ) (xsync.PooledWorkerPool, xsync.PooledWorkerPool, error) {
    73  	opts, readPoolSize := readPoolPolicy.Options()
    74  	opts = opts.SetInstrumentOptions(instrumentOptions.
    75  		SetMetricsScope(scope.SubScope("read-worker-pool")))
    76  	readWorkerPool, err := xsync.NewPooledWorkerPool(readPoolSize, opts)
    77  	if err != nil {
    78  		return nil, nil, err
    79  	}
    80  
    81  	readWorkerPool.Init()
    82  	opts, writePoolSize := writePoolPolicy.Options()
    83  	opts = opts.SetInstrumentOptions(instrumentOptions.
    84  		SetMetricsScope(scope.SubScope("write-worker-pool")))
    85  	writeWorkerPool, err := xsync.NewPooledWorkerPool(writePoolSize, opts)
    86  	if err != nil {
    87  		return nil, nil, err
    88  	}
    89  
    90  	writeWorkerPool.Init()
    91  	return readWorkerPool, writeWorkerPool, nil
    92  }
    93  
    94  type sessionPools struct {
    95  	multiReaderIteratorArray encoding.MultiReaderIteratorArrayPool
    96  	multiReaderIterator      encoding.MultiReaderIteratorPool
    97  	seriesIterator           encoding.SeriesIteratorPool
    98  	checkedBytesWrapper      xpool.CheckedBytesWrapperPool
    99  	id                       ident.Pool
   100  	tagEncoder               serialize.TagEncoderPool
   101  	tagDecoder               serialize.TagDecoderPool
   102  }
   103  
   104  func (s sessionPools) MultiReaderIteratorArray() encoding.MultiReaderIteratorArrayPool {
   105  	return s.multiReaderIteratorArray
   106  }
   107  
   108  func (s sessionPools) MultiReaderIterator() encoding.MultiReaderIteratorPool {
   109  	return s.multiReaderIterator
   110  }
   111  
   112  func (s sessionPools) SeriesIterator() encoding.SeriesIteratorPool {
   113  	return s.seriesIterator
   114  }
   115  
   116  func (s sessionPools) CheckedBytesWrapper() xpool.CheckedBytesWrapperPool {
   117  	return s.checkedBytesWrapper
   118  }
   119  
   120  func (s sessionPools) ID() ident.Pool {
   121  	return s.id
   122  }
   123  
   124  func (s sessionPools) TagEncoder() serialize.TagEncoderPool {
   125  	return s.tagEncoder
   126  }
   127  
   128  func (s sessionPools) TagDecoder() serialize.TagDecoderPool {
   129  	return s.tagDecoder
   130  }
   131  
   132  // BuildIteratorPoolsOptions is a set of build iterator pools.
   133  type BuildIteratorPoolsOptions struct {
   134  	Replicas                    int
   135  	SeriesIteratorPoolSize      int
   136  	SeriesIteratorsPoolBuckets  []pool.Bucket
   137  	SeriesIDBytesPoolBuckets    []pool.Bucket
   138  	CheckedBytesWrapperPoolSize int
   139  }
   140  
   141  // ReplicasOrDefault returns the replicas or default.
   142  func (o BuildIteratorPoolsOptions) ReplicasOrDefault() int {
   143  	if o.Replicas <= 0 {
   144  		return defaultReplicas
   145  	}
   146  	return o.Replicas
   147  }
   148  
   149  // SeriesIteratorPoolSizeOrDefault returns the replicas or default.
   150  func (o BuildIteratorPoolsOptions) SeriesIteratorPoolSizeOrDefault() int {
   151  	if o.SeriesIteratorPoolSize <= 0 {
   152  		return defaultSeriesIteratorPoolSize
   153  	}
   154  	return o.SeriesIteratorPoolSize
   155  }
   156  
   157  // CheckedBytesWrapperPoolSizeOrDefault returns the checked bytes
   158  // wrapper pool size or default.
   159  func (o BuildIteratorPoolsOptions) CheckedBytesWrapperPoolSizeOrDefault() int {
   160  	if o.CheckedBytesWrapperPoolSize <= 0 {
   161  		return defaultCheckedBytesWrapperPoolSize
   162  	}
   163  	return o.CheckedBytesWrapperPoolSize
   164  }
   165  
   166  // SeriesIteratorsPoolBucketsOrDefault returns the series iterator pool
   167  // buckets or defaults.
   168  func (o BuildIteratorPoolsOptions) SeriesIteratorsPoolBucketsOrDefault() []pool.Bucket {
   169  	if len(o.SeriesIteratorsPoolBuckets) == 0 {
   170  		return defaultSeriesIteratorsPoolBuckets
   171  	}
   172  	return o.SeriesIteratorsPoolBuckets
   173  }
   174  
   175  // SeriesIDBytesPoolBucketsOrDefault returns the bytes pool buckets or defaults.
   176  func (o BuildIteratorPoolsOptions) SeriesIDBytesPoolBucketsOrDefault() []pool.Bucket {
   177  	if len(o.SeriesIDBytesPoolBuckets) == 0 {
   178  		return defaultSeriesIDBytesPoolBuckets
   179  	}
   180  	return o.SeriesIDBytesPoolBuckets
   181  }
   182  
   183  // BuildIteratorPools build iterator pools if they are unavailable from
   184  // m3db (e.g. if running standalone query)
   185  func BuildIteratorPools(
   186  	encodingOpts encoding.Options,
   187  	opts BuildIteratorPoolsOptions,
   188  ) encoding.IteratorPools {
   189  	// TODO: add instrumentation options to these pools
   190  	pools := sessionPools{}
   191  
   192  	defaultPerSeriesIteratorsBuckets := opts.SeriesIteratorsPoolBucketsOrDefault()
   193  
   194  	pools.multiReaderIteratorArray = encoding.NewMultiReaderIteratorArrayPool(defaultPerSeriesIteratorsBuckets)
   195  	pools.multiReaderIteratorArray.Init()
   196  
   197  	defaultPerSeriesPoolOpts := pool.NewObjectPoolOptions().
   198  		SetSize(opts.SeriesIteratorPoolSizeOrDefault())
   199  
   200  	readerIteratorPoolPoolOpts := pool.NewObjectPoolOptions().
   201  		SetSize(opts.SeriesIteratorPoolSizeOrDefault() * opts.ReplicasOrDefault())
   202  
   203  	readerIteratorPool := encoding.NewReaderIteratorPool(readerIteratorPoolPoolOpts)
   204  
   205  	encodingOpts = encodingOpts.
   206  		SetReaderIteratorPool(readerIteratorPool)
   207  
   208  	readerIteratorPool.Init(m3tsz.DefaultReaderIteratorAllocFn(encodingOpts))
   209  
   210  	pools.multiReaderIterator = encoding.NewMultiReaderIteratorPool(defaultPerSeriesPoolOpts)
   211  	pools.multiReaderIterator.Init(
   212  		func(r xio.Reader64, s namespace.SchemaDescr) encoding.ReaderIterator {
   213  			iter := readerIteratorPool.Get()
   214  			iter.Reset(r, s)
   215  			return iter
   216  		})
   217  
   218  	pools.seriesIterator = encoding.NewSeriesIteratorPool(defaultPerSeriesPoolOpts)
   219  	pools.seriesIterator.Init()
   220  
   221  	wrapperPoolOpts := pool.NewObjectPoolOptions().
   222  		SetSize(opts.CheckedBytesWrapperPoolSizeOrDefault())
   223  	pools.checkedBytesWrapper = xpool.NewCheckedBytesWrapperPool(wrapperPoolOpts)
   224  	pools.checkedBytesWrapper.Init()
   225  
   226  	pools.tagEncoder = serialize.NewTagEncoderPool(
   227  		serialize.NewTagEncoderOptions(),
   228  		defaultPerSeriesPoolOpts)
   229  	pools.tagEncoder.Init()
   230  
   231  	tagDecoderCheckBytesWrapperPoolSize := 0
   232  	tagDecoderOpts := serialize.NewTagDecoderOptions(serialize.TagDecoderOptionsConfig{
   233  		// We pass in a preallocated pool so use a zero sized pool in options init.
   234  		CheckBytesWrapperPoolSize: &tagDecoderCheckBytesWrapperPoolSize,
   235  	})
   236  	tagDecoderOpts = tagDecoderOpts.SetCheckedBytesWrapperPool(pools.checkedBytesWrapper)
   237  
   238  	pools.tagDecoder = serialize.NewTagDecoderPool(tagDecoderOpts, defaultPerSeriesPoolOpts)
   239  	pools.tagDecoder.Init()
   240  
   241  	bytesPool := pool.NewCheckedBytesPool(opts.SeriesIDBytesPoolBucketsOrDefault(),
   242  		nil, func(sizes []pool.Bucket) pool.BytesPool {
   243  			return pool.NewBytesPool(sizes, nil)
   244  		})
   245  	bytesPool.Init()
   246  
   247  	pools.id = ident.NewPool(bytesPool, ident.PoolOptions{
   248  		IDPoolOptions:           defaultPerSeriesPoolOpts,
   249  		TagsPoolOptions:         defaultPerSeriesPoolOpts,
   250  		TagsIteratorPoolOptions: defaultPerSeriesPoolOpts,
   251  	})
   252  
   253  	return pools
   254  }