github.com/m3db/m3@v1.5.0/src/cmd/services/m3dbnode/config/pooling.go (about)

     1  // Copyright (c) 2017 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 config
    22  
    23  import (
    24  	"fmt"
    25  
    26  	"github.com/m3db/m3/src/x/pool"
    27  )
    28  
    29  // PoolingType is a type of pooling, using runtime or mmap'd bytes pooling.
    30  type PoolingType string
    31  
    32  const (
    33  	// SimplePooling uses the basic Go runtime to allocate bytes for bytes pools.
    34  	SimplePooling PoolingType = "simple"
    35  
    36  	defaultPoolingType = SimplePooling
    37  
    38  	defaultBlockAllocSize = 16
    39  )
    40  
    41  var defaultThriftBytesPoolAllocSizes = []int{16, 64, 256, 512, 1024, 2048}
    42  
    43  type poolPolicyDefault struct {
    44  	size                pool.Size
    45  	refillLowWaterMark  float64
    46  	refillHighWaterMark float64
    47  
    48  	// Only used for capacity and max capacity pools.
    49  	capacity int
    50  	// Only used for max capacity pools.
    51  	maxCapacity int
    52  }
    53  
    54  type bucketPoolPolicyDefault struct {
    55  	buckets []CapacityPoolPolicy
    56  }
    57  
    58  var (
    59  	defaultRefillLowWaterMark  = 0.3
    60  	defaultRefillHighWaterMark = 0.6
    61  
    62  	defaultPoolPolicy = poolPolicyDefault{
    63  		size:                4096,
    64  		refillLowWaterMark:  0,
    65  		refillHighWaterMark: 0,
    66  	}
    67  
    68  	defaultPoolPolicies = map[string]poolPolicyDefault{
    69  		"checkedBytesWrapper": poolPolicyDefault{
    70  			size:                65536,
    71  			refillLowWaterMark:  0,
    72  			refillHighWaterMark: 0,
    73  		},
    74  		"tagsIterator": defaultPoolPolicy,
    75  		"indexResults": poolPolicyDefault{
    76  			// NB(r): There only needs to be one index results map per
    77  			// concurrent query, so as long as there is no more than
    78  			// the number of concurrent index queries than the size
    79  			// specified here the maps should be recycled.
    80  			size:                256,
    81  			refillLowWaterMark:  0,
    82  			refillHighWaterMark: 0,
    83  		},
    84  		"tagEncoder": poolPolicyDefault{
    85  			// NB(r): Tag encoder is used for every individual time series
    86  			// returned from an index query since it needs to encode the tags
    87  			// back for RPC and has a bytes buffer internally for each time
    88  			// series being returned.
    89  			size:                8192,
    90  			refillLowWaterMark:  0,
    91  			refillHighWaterMark: 0,
    92  		},
    93  		"tagDecoder": defaultPoolPolicy,
    94  		"context": poolPolicyDefault{
    95  			size:                32768,
    96  			refillLowWaterMark:  0,
    97  			refillHighWaterMark: 0,
    98  		},
    99  		"series": poolPolicyDefault{
   100  			size:                65536,
   101  			refillLowWaterMark:  defaultRefillLowWaterMark,
   102  			refillHighWaterMark: defaultRefillHighWaterMark,
   103  		},
   104  		"block": poolPolicyDefault{
   105  			size:                65536,
   106  			refillLowWaterMark:  defaultRefillLowWaterMark,
   107  			refillHighWaterMark: defaultRefillHighWaterMark,
   108  		},
   109  		"encoder": poolPolicyDefault{
   110  			size:                65536,
   111  			refillLowWaterMark:  defaultRefillLowWaterMark,
   112  			refillHighWaterMark: defaultRefillHighWaterMark,
   113  		},
   114  		"closers": poolPolicyDefault{
   115  			// NB(r): Note this has to be bigger than context pool by
   116  			// big fraction (by factor of say 4) since each context
   117  			// usually uses a fair few closers.
   118  			size:                262144,
   119  			refillLowWaterMark:  0,
   120  			refillHighWaterMark: 0,
   121  		},
   122  		"segmentReader": poolPolicyDefault{
   123  			size:                65536,
   124  			refillLowWaterMark:  defaultRefillLowWaterMark,
   125  			refillHighWaterMark: defaultRefillHighWaterMark,
   126  		},
   127  		"iterator": poolPolicyDefault{
   128  			size:                2048,
   129  			refillLowWaterMark:  defaultRefillLowWaterMark,
   130  			refillHighWaterMark: defaultRefillHighWaterMark,
   131  		},
   132  		"blockMetadata": poolPolicyDefault{
   133  			size:                65536,
   134  			refillLowWaterMark:  defaultRefillLowWaterMark,
   135  			refillHighWaterMark: defaultRefillHighWaterMark,
   136  		},
   137  		"blocksMetadata": poolPolicyDefault{
   138  			size:                65536,
   139  			refillLowWaterMark:  defaultRefillLowWaterMark,
   140  			refillHighWaterMark: defaultRefillHighWaterMark,
   141  		},
   142  		"identifier": poolPolicyDefault{
   143  			size:                65536,
   144  			refillLowWaterMark:  defaultRefillLowWaterMark,
   145  			refillHighWaterMark: defaultRefillHighWaterMark,
   146  		},
   147  		"postingsList": poolPolicyDefault{
   148  			// defaultPostingsListPoolSize has a small default pool size since postings
   149  			// lists can frequently reach the size of 4mb each in practice even when
   150  			// reset.
   151  			size:                16,
   152  			refillLowWaterMark:  defaultRefillLowWaterMark,
   153  			refillHighWaterMark: defaultRefillHighWaterMark,
   154  		},
   155  		"bufferBucket": poolPolicyDefault{
   156  			size:                65536,
   157  			refillLowWaterMark:  defaultRefillLowWaterMark,
   158  			refillHighWaterMark: defaultRefillHighWaterMark,
   159  		},
   160  		"bufferBucketVersions": poolPolicyDefault{
   161  			size:                65536,
   162  			refillLowWaterMark:  defaultRefillLowWaterMark,
   163  			refillHighWaterMark: defaultRefillHighWaterMark,
   164  		},
   165  		"retrieveRequestPool": poolPolicyDefault{
   166  			size:                65536,
   167  			refillLowWaterMark:  0,
   168  			refillHighWaterMark: 0,
   169  		},
   170  
   171  		// Capacity pools.
   172  		"fetchBlockMetadataResults": poolPolicyDefault{
   173  			size:                65536,
   174  			refillLowWaterMark:  defaultRefillLowWaterMark,
   175  			refillHighWaterMark: defaultRefillHighWaterMark,
   176  			capacity:            32,
   177  		},
   178  		"fetchBlocksMetadataResults": poolPolicyDefault{
   179  			size:                32,
   180  			refillLowWaterMark:  defaultRefillLowWaterMark,
   181  			refillHighWaterMark: defaultRefillHighWaterMark,
   182  			capacity:            4096,
   183  		},
   184  		"replicaMetadataSlice": poolPolicyDefault{
   185  			size:                131072,
   186  			refillLowWaterMark:  defaultRefillLowWaterMark,
   187  			refillHighWaterMark: defaultRefillHighWaterMark,
   188  			capacity:            3,
   189  		},
   190  		"blockMetadataSlice": poolPolicyDefault{
   191  			size:                65536,
   192  			refillLowWaterMark:  defaultRefillLowWaterMark,
   193  			refillHighWaterMark: defaultRefillHighWaterMark,
   194  			capacity:            32,
   195  		},
   196  		"blocksMetadataSlice": poolPolicyDefault{
   197  			size:                32,
   198  			refillLowWaterMark:  defaultRefillLowWaterMark,
   199  			refillHighWaterMark: defaultRefillHighWaterMark,
   200  			capacity:            4096,
   201  		},
   202  
   203  		// Max capacity pools.
   204  		"tags": poolPolicyDefault{
   205  			size:                4096,
   206  			refillLowWaterMark:  defaultRefillLowWaterMark,
   207  			refillHighWaterMark: defaultRefillHighWaterMark,
   208  			capacity:            0,
   209  			maxCapacity:         16,
   210  		},
   211  	}
   212  
   213  	defaultBucketPoolPolicies = map[string]bucketPoolPolicyDefault{
   214  		"bytes": bucketPoolPolicyDefault{
   215  			buckets: []CapacityPoolPolicy{
   216  				{
   217  					Capacity: intPtr(16),
   218  					PoolPolicy: PoolPolicy{
   219  						Size:                poolSizePtr(524288),
   220  						RefillLowWaterMark:  &defaultRefillLowWaterMark,
   221  						RefillHighWaterMark: &defaultRefillHighWaterMark,
   222  					},
   223  				},
   224  				{
   225  					Capacity: intPtr(32),
   226  					PoolPolicy: PoolPolicy{
   227  						Size:                poolSizePtr(262144),
   228  						RefillLowWaterMark:  &defaultRefillLowWaterMark,
   229  						RefillHighWaterMark: &defaultRefillHighWaterMark,
   230  					},
   231  				},
   232  				{
   233  					Capacity: intPtr(64),
   234  					PoolPolicy: PoolPolicy{
   235  						Size:                poolSizePtr(131072),
   236  						RefillLowWaterMark:  &defaultRefillLowWaterMark,
   237  						RefillHighWaterMark: &defaultRefillHighWaterMark,
   238  					},
   239  				},
   240  				{
   241  					Capacity: intPtr(128),
   242  					PoolPolicy: PoolPolicy{
   243  						Size:                poolSizePtr(65536),
   244  						RefillLowWaterMark:  &defaultRefillLowWaterMark,
   245  						RefillHighWaterMark: &defaultRefillHighWaterMark,
   246  					},
   247  				},
   248  				{
   249  					Capacity: intPtr(256),
   250  					PoolPolicy: PoolPolicy{
   251  						Size:                poolSizePtr(65536),
   252  						RefillLowWaterMark:  &defaultRefillLowWaterMark,
   253  						RefillHighWaterMark: &defaultRefillHighWaterMark,
   254  					},
   255  				},
   256  				{
   257  					Capacity: intPtr(1440),
   258  					PoolPolicy: PoolPolicy{
   259  						Size:                poolSizePtr(16384),
   260  						RefillLowWaterMark:  &defaultRefillLowWaterMark,
   261  						RefillHighWaterMark: &defaultRefillHighWaterMark,
   262  					},
   263  				},
   264  				{
   265  					Capacity: intPtr(4096),
   266  					PoolPolicy: PoolPolicy{
   267  						Size:                poolSizePtr(8192),
   268  						RefillLowWaterMark:  &defaultRefillLowWaterMark,
   269  						RefillHighWaterMark: &defaultRefillHighWaterMark,
   270  					},
   271  				},
   272  			},
   273  		},
   274  	}
   275  )
   276  
   277  // PoolingPolicy specifies the pooling policy. To add a new pool, follow these steps:
   278  //
   279  //    1. Add the pool to the struct below.
   280  //    2. Add the default values to the defaultPoolPolicies or defaultBucketPoolPolicies map.
   281  //    3. Add a call to initDefaultsAndValidate() for the new pool in the
   282  //       PoolingPolicy.InitDefaultsAndValidate() method.
   283  type PoolingPolicy struct {
   284  	// The initial alloc size for a block.
   285  	BlockAllocSize *int `yaml:"blockAllocSize"`
   286  
   287  	// The thrift bytes pool max bytes slice allocation for a single binary field.
   288  	ThriftBytesPoolAllocSize *int `yaml:"thriftBytesPoolAllocSize"`
   289  
   290  	// The general pool type (currently only supported: simple).
   291  	Type *PoolingType `yaml:"type"`
   292  
   293  	// The Bytes pool buckets to use.
   294  	BytesPool BucketPoolPolicy `yaml:"bytesPool"`
   295  
   296  	// The policy for the checked bytes wrapper pool.
   297  	CheckedBytesWrapperPool PoolPolicy `yaml:"checkedBytesWrapperPool"`
   298  
   299  	// The policy for the Closers pool.
   300  	ClosersPool PoolPolicy `yaml:"closersPool"`
   301  
   302  	// The policy for the Context pool.
   303  	ContextPool PoolPolicy `yaml:"contextPool"`
   304  
   305  	// The policy for the DatabaseSeries pool.
   306  	SeriesPool PoolPolicy `yaml:"seriesPool"`
   307  
   308  	// The policy for the DatabaseBlock pool.
   309  	BlockPool PoolPolicy `yaml:"blockPool"`
   310  
   311  	// The policy for the Encoder pool.
   312  	EncoderPool PoolPolicy `yaml:"encoderPool"`
   313  
   314  	// The policy for the Iterator pool.
   315  	IteratorPool PoolPolicy `yaml:"iteratorPool"`
   316  
   317  	// The policy for the Segment Reader pool.
   318  	SegmentReaderPool PoolPolicy `yaml:"segmentReaderPool"`
   319  
   320  	// The policy for the Identifier pool.
   321  	IdentifierPool PoolPolicy `yaml:"identifierPool"`
   322  
   323  	// The policy for the FetchBlockMetadataResult pool.
   324  	FetchBlockMetadataResultsPool CapacityPoolPolicy `yaml:"fetchBlockMetadataResultsPool"`
   325  
   326  	// The policy for the FetchBlocksMetadataResults pool.
   327  	FetchBlocksMetadataResultsPool CapacityPoolPolicy `yaml:"fetchBlocksMetadataResultsPool"`
   328  
   329  	// The policy for the ReplicaMetadataSlicePool pool.
   330  	ReplicaMetadataSlicePool CapacityPoolPolicy `yaml:"replicaMetadataSlicePool"`
   331  
   332  	// The policy for the BlockMetadat pool.
   333  	BlockMetadataPool PoolPolicy `yaml:"blockMetadataPool"`
   334  
   335  	// The policy for the BlockMetadataSlice pool.
   336  	BlockMetadataSlicePool CapacityPoolPolicy `yaml:"blockMetadataSlicePool"`
   337  
   338  	// The policy for the BlocksMetadata pool.
   339  	BlocksMetadataPool PoolPolicy `yaml:"blocksMetadataPool"`
   340  
   341  	// The policy for the BlocksMetadataSlice pool.
   342  	BlocksMetadataSlicePool CapacityPoolPolicy `yaml:"blocksMetadataSlicePool"`
   343  
   344  	// The policy for the tags pool.
   345  	TagsPool MaxCapacityPoolPolicy `yaml:"tagsPool"`
   346  
   347  	// The policy for the tags iterator pool.
   348  	TagsIteratorPool PoolPolicy `yaml:"tagIteratorPool"`
   349  
   350  	// The policy for the index.ResultsPool.
   351  	IndexResultsPool PoolPolicy `yaml:"indexResultsPool"`
   352  
   353  	// The policy for the TagEncoderPool.
   354  	TagEncoderPool PoolPolicy `yaml:"tagEncoderPool"`
   355  
   356  	// The policy for the TagDecoderPool.
   357  	TagDecoderPool PoolPolicy `yaml:"tagDecoderPool"`
   358  
   359  	// The policy for the WriteBatchPool.
   360  	WriteBatchPool WriteBatchPoolPolicy `yaml:"writeBatchPool"`
   361  
   362  	// The policy for the BufferBucket pool.
   363  	BufferBucketPool PoolPolicy `yaml:"bufferBucketPool"`
   364  
   365  	// The policy for the BufferBucketVersions pool.
   366  	BufferBucketVersionsPool PoolPolicy `yaml:"bufferBucketVersionsPool"`
   367  
   368  	// The policy for the RetrieveRequestPool pool.
   369  	RetrieveRequestPool PoolPolicy `yaml:"retrieveRequestPool"`
   370  
   371  	// The policy for the PostingsListPool.
   372  	PostingsListPool PoolPolicy `yaml:"postingsListPool"`
   373  }
   374  
   375  // InitDefaultsAndValidate initializes all default values and validates the configuration
   376  func (p *PoolingPolicy) InitDefaultsAndValidate() error {
   377  	if err := p.CheckedBytesWrapperPool.initDefaultsAndValidate("checkedBytesWrapper"); err != nil {
   378  		return err
   379  	}
   380  	if err := p.ClosersPool.initDefaultsAndValidate("closers"); err != nil {
   381  		return err
   382  	}
   383  	if err := p.ContextPool.initDefaultsAndValidate("context"); err != nil {
   384  		return err
   385  	}
   386  	if err := p.SeriesPool.initDefaultsAndValidate("series"); err != nil {
   387  		return err
   388  	}
   389  	if err := p.BlockPool.initDefaultsAndValidate("block"); err != nil {
   390  		return err
   391  	}
   392  	if err := p.EncoderPool.initDefaultsAndValidate("encoder"); err != nil {
   393  		return err
   394  	}
   395  	if err := p.IteratorPool.initDefaultsAndValidate("iterator"); err != nil {
   396  		return err
   397  	}
   398  	if err := p.SegmentReaderPool.initDefaultsAndValidate("segmentReader"); err != nil {
   399  		return err
   400  	}
   401  	if err := p.IdentifierPool.initDefaultsAndValidate("identifier"); err != nil {
   402  		return err
   403  	}
   404  	if err := p.FetchBlockMetadataResultsPool.initDefaultsAndValidate("fetchBlockMetadataResults"); err != nil {
   405  		return err
   406  	}
   407  	if err := p.FetchBlocksMetadataResultsPool.initDefaultsAndValidate("fetchBlocksMetadataResults"); err != nil {
   408  		return err
   409  	}
   410  	if err := p.ReplicaMetadataSlicePool.initDefaultsAndValidate("replicaMetadataSlice"); err != nil {
   411  		return err
   412  	}
   413  	if err := p.BlockMetadataPool.initDefaultsAndValidate("blockMetadata"); err != nil {
   414  		return err
   415  	}
   416  	if err := p.BlockMetadataSlicePool.initDefaultsAndValidate("blockMetadataSlice"); err != nil {
   417  		return err
   418  	}
   419  	if err := p.BlocksMetadataPool.initDefaultsAndValidate("blocksMetadata"); err != nil {
   420  		return err
   421  	}
   422  	if err := p.BlocksMetadataSlicePool.initDefaultsAndValidate("blocksMetadataSlice"); err != nil {
   423  		return err
   424  	}
   425  	if err := p.TagsPool.initDefaultsAndValidate("tags"); err != nil {
   426  		return err
   427  	}
   428  	if err := p.TagsIteratorPool.initDefaultsAndValidate("tagsIterator"); err != nil {
   429  		return err
   430  	}
   431  	if err := p.IndexResultsPool.initDefaultsAndValidate("indexResults"); err != nil {
   432  		return err
   433  	}
   434  	if err := p.TagEncoderPool.initDefaultsAndValidate("tagEncoder"); err != nil {
   435  		return err
   436  	}
   437  	if err := p.TagDecoderPool.initDefaultsAndValidate("tagDecoder"); err != nil {
   438  		return err
   439  	}
   440  	if err := p.PostingsListPool.initDefaultsAndValidate("postingsList"); err != nil {
   441  		return err
   442  	}
   443  	if err := p.BytesPool.initDefaultsAndValidate("bytes"); err != nil {
   444  		return err
   445  	}
   446  	if err := p.BufferBucketPool.initDefaultsAndValidate("bufferBucket"); err != nil {
   447  		return err
   448  	}
   449  	if err := p.BufferBucketVersionsPool.initDefaultsAndValidate("bufferBucketVersions"); err != nil {
   450  		return err
   451  	}
   452  	if err := p.RetrieveRequestPool.initDefaultsAndValidate("retrieveRequestPool"); err != nil {
   453  		return err
   454  	}
   455  	return nil
   456  }
   457  
   458  // BlockAllocSizeOrDefault returns the configured block alloc size if provided,
   459  // or a default value otherwise.
   460  func (p *PoolingPolicy) BlockAllocSizeOrDefault() int {
   461  	if p.BlockAllocSize != nil {
   462  		return *p.BlockAllocSize
   463  	}
   464  
   465  	return defaultBlockAllocSize
   466  }
   467  
   468  // ThriftBytesPoolAllocSizesOrDefault returns the configured thrift bytes pool
   469  // max alloc size if provided, or a default value otherwise.
   470  func (p *PoolingPolicy) ThriftBytesPoolAllocSizesOrDefault() []int {
   471  	if p.ThriftBytesPoolAllocSize != nil {
   472  		return []int{*p.ThriftBytesPoolAllocSize}
   473  	}
   474  
   475  	return defaultThriftBytesPoolAllocSizes
   476  }
   477  
   478  // TypeOrDefault returns the configured pooling type if provided, or a default
   479  // value otherwise.
   480  func (p *PoolingPolicy) TypeOrDefault() PoolingType {
   481  	if p.Type != nil {
   482  		return *p.Type
   483  	}
   484  
   485  	return defaultPoolingType
   486  }
   487  
   488  // PoolPolicy specifies a single pool policy.
   489  type PoolPolicy struct {
   490  	// The size of the pool.
   491  	Size *pool.Size `yaml:"size"`
   492  
   493  	// The low watermark to start refilling the pool, if zero none.
   494  	RefillLowWaterMark *float64 `yaml:"lowWatermark"`
   495  
   496  	// The high watermark to stop refilling the pool, if zero none.
   497  	RefillHighWaterMark *float64 `yaml:"highWatermark"`
   498  }
   499  
   500  func (p *PoolPolicy) initDefaultsAndValidate(poolName string) error {
   501  	defaults, ok := defaultPoolPolicies[poolName]
   502  	if !ok {
   503  		return fmt.Errorf("no default values for pool: %s", poolName)
   504  	}
   505  
   506  	if p.Size == nil {
   507  		p.Size = &defaults.size
   508  	}
   509  	if p.RefillLowWaterMark == nil {
   510  		p.RefillLowWaterMark = &defaults.refillLowWaterMark
   511  	}
   512  	if p.RefillHighWaterMark == nil {
   513  		p.RefillHighWaterMark = &defaults.refillHighWaterMark
   514  	}
   515  
   516  	if *p.RefillLowWaterMark < 0 || *p.RefillLowWaterMark > 1 {
   517  		return fmt.Errorf(
   518  			"invalid lowWatermark value for %s pool, should be >= 0 and <= 1", poolName)
   519  	}
   520  
   521  	if *p.RefillHighWaterMark < 0 || *p.RefillHighWaterMark > 1 {
   522  		return fmt.Errorf(
   523  			"invalid lowWatermark value for %s pool, should be >= 0 and <= 1", poolName)
   524  	}
   525  
   526  	return nil
   527  }
   528  
   529  // SizeOrDefault returns the configured size if present, or a default value otherwise.
   530  func (p *PoolPolicy) SizeOrDefault() pool.Size {
   531  	return *p.Size
   532  }
   533  
   534  // RefillLowWaterMarkOrDefault returns the configured refill low water mark if present,
   535  // or a default value otherwise.
   536  func (p *PoolPolicy) RefillLowWaterMarkOrDefault() float64 {
   537  	return *p.RefillLowWaterMark
   538  }
   539  
   540  // RefillHighWaterMarkOrDefault returns the configured refill high water mark if present,
   541  // or a default value otherwise.
   542  func (p *PoolPolicy) RefillHighWaterMarkOrDefault() float64 {
   543  	return *p.RefillHighWaterMark
   544  }
   545  
   546  // CapacityPoolPolicy specifies a single pool policy that has a
   547  // per element capacity.
   548  type CapacityPoolPolicy struct {
   549  	PoolPolicy `yaml:",inline"`
   550  
   551  	// The capacity of items in the pool.
   552  	Capacity *int `yaml:"capacity"`
   553  }
   554  
   555  // Validate validates the capacity pool policy config.
   556  func (p *CapacityPoolPolicy) initDefaultsAndValidate(poolName string) error {
   557  	if err := p.PoolPolicy.initDefaultsAndValidate(poolName); err != nil {
   558  		return err
   559  	}
   560  
   561  	defaults, ok := defaultPoolPolicies[poolName]
   562  	if !ok {
   563  		return fmt.Errorf("no default values for pool: %s", poolName)
   564  	}
   565  
   566  	if p.Capacity == nil {
   567  		p.Capacity = &defaults.capacity
   568  	}
   569  
   570  	if *p.Capacity < 0 {
   571  		return fmt.Errorf("capacity of %s pool must be >= 0", poolName)
   572  	}
   573  
   574  	return nil
   575  }
   576  
   577  // CapacityOrDefault returns the configured capacity if present, or a default value otherwise.
   578  func (p *CapacityPoolPolicy) CapacityOrDefault() int {
   579  	return *p.Capacity
   580  }
   581  
   582  // MaxCapacityPoolPolicy specifies a single pool policy that has a
   583  // per element capacity, and a maximum allowed capacity as well.
   584  type MaxCapacityPoolPolicy struct {
   585  	CapacityPoolPolicy `yaml:",inline"`
   586  
   587  	// The max capacity of items in the pool.
   588  	MaxCapacity *int `yaml:"maxCapacity"`
   589  }
   590  
   591  func (p *MaxCapacityPoolPolicy) initDefaultsAndValidate(poolName string) error {
   592  	if err := p.CapacityPoolPolicy.initDefaultsAndValidate(poolName); err != nil {
   593  		return err
   594  	}
   595  
   596  	defaults, ok := defaultPoolPolicies[poolName]
   597  	if !ok {
   598  		return fmt.Errorf("no default values for pool: %s", poolName)
   599  	}
   600  
   601  	if p.MaxCapacity == nil {
   602  		p.MaxCapacity = &defaults.maxCapacity
   603  	}
   604  
   605  	if *p.MaxCapacity < 0 {
   606  		return fmt.Errorf("maxCapacity of %s pool must be >= 0", poolName)
   607  	}
   608  
   609  	return nil
   610  }
   611  
   612  // MaxCapacityOrDefault returns the configured maximum capacity if present, or a
   613  // default value otherwise.
   614  func (p *MaxCapacityPoolPolicy) MaxCapacityOrDefault() int {
   615  	return *p.MaxCapacity
   616  }
   617  
   618  // BucketPoolPolicy specifies a bucket pool policy.
   619  type BucketPoolPolicy struct {
   620  	// The pool buckets sizes to use
   621  	Buckets []CapacityPoolPolicy `yaml:"buckets"`
   622  }
   623  
   624  func (p *BucketPoolPolicy) initDefaultsAndValidate(poolName string) error {
   625  	defaults, ok := defaultBucketPoolPolicies[poolName]
   626  	if !ok {
   627  		return fmt.Errorf("no default values for pool: %s", poolName)
   628  	}
   629  
   630  	if p.Buckets == nil {
   631  		p.Buckets = defaults.buckets
   632  	}
   633  
   634  	for i, bucket := range p.Buckets {
   635  		// If the user provided buckets, but no values for refill low/high watermarks
   636  		// then set them to default values.
   637  		if bucket.RefillLowWaterMark == nil {
   638  			p.Buckets[i].RefillLowWaterMark = &defaultRefillLowWaterMark
   639  		}
   640  		if bucket.RefillHighWaterMark == nil {
   641  			p.Buckets[i].RefillHighWaterMark = &defaultRefillHighWaterMark
   642  		}
   643  	}
   644  
   645  	for _, bucket := range p.Buckets {
   646  		if bucket.Size == nil {
   647  			return fmt.Errorf("bucket size for pool %s cannot be nil", poolName)
   648  		}
   649  		if bucket.Capacity == nil {
   650  			return fmt.Errorf("bucket capacity for pool %s cannot be nil", poolName)
   651  		}
   652  	}
   653  	return nil
   654  }
   655  
   656  // WriteBatchPoolPolicy specifies the pooling policy for the WriteBatch pool.
   657  type WriteBatchPoolPolicy struct {
   658  	// The size of the pool.
   659  	Size *int `yaml:"size"`
   660  
   661  	// InitialBatchSize controls the initial batch size for each WriteBatch when
   662  	// the pool is being constructed / refilled.
   663  	InitialBatchSize *int `yaml:"initialBatchSize"`
   664  
   665  	// MaxBatchSize controls the maximum size that a pooled WriteBatch can grow to
   666  	// and still remain in the pool.
   667  	MaxBatchSize *int `yaml:"maxBatchSize"`
   668  }
   669  
   670  func intPtr(x int) *int {
   671  	return &x
   672  }
   673  
   674  func poolSizePtr(x int) *pool.Size {
   675  	sz := pool.Size(x)
   676  	return &sz
   677  }