github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/persist/fs/options.go (about)

     1  // Copyright (c) 2016 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 fs
    22  
    23  import (
    24  	"errors"
    25  	"fmt"
    26  	"os"
    27  
    28  	"github.com/m3db/m3/src/dbnode/persist/fs/msgpack"
    29  	"github.com/m3db/m3/src/dbnode/runtime"
    30  	"github.com/m3db/m3/src/m3ninx/index/segment/fst"
    31  	"github.com/m3db/m3/src/x/clock"
    32  	"github.com/m3db/m3/src/x/instrument"
    33  	"github.com/m3db/m3/src/x/mmap"
    34  	"github.com/m3db/m3/src/x/pool"
    35  	"github.com/m3db/m3/src/x/serialize"
    36  )
    37  
    38  const (
    39  	// defaultIndexSummariesPercent is the default percent of series for which an entry will be written into the metadata summary
    40  	defaultIndexSummariesPercent = 0.03
    41  
    42  	// defaultIndexBloomFilterFalsePositivePercent is the false positive percent to use to calculate size for when writing bloom filters
    43  	defaultIndexBloomFilterFalsePositivePercent = 0.02
    44  
    45  	// defaultWriterBufferSize is the default buffer size for writing TSDB files
    46  	defaultWriterBufferSize = 65536
    47  
    48  	// defaultDataReaderBufferSize is the default buffer size for reading TSDB data and index files
    49  	defaultDataReaderBufferSize = 65536
    50  
    51  	// defaultInfoReaderBufferSize is the default buffer size for reading TSDB info, checkpoint and digest files
    52  	defaultInfoReaderBufferSize = 64
    53  
    54  	// defaultSeekReaderBufferSize is the default buffer size for fs seeker's data buffer
    55  	defaultSeekReaderBufferSize = 4096
    56  
    57  	// defaultMmapEnableHugePages is the default setting whether to enable huge pages or not
    58  	defaultMmapEnableHugePages = false
    59  
    60  	// defaultMmapHugePagesThreshold is the default threshold for when to enable huge pages if enabled
    61  	defaultMmapHugePagesThreshold = 2 << 14 // 32kb (or when eclipsing 8 pages of default 4096 page size)
    62  
    63  	// defaultForceIndexSummariesMmapMemory is the default configuration for whether the bytes for the index
    64  	// summaries file should be mmap'd as an anonymous region (forced completely into memory) or mmap'd as a file.
    65  	defaultForceIndexSummariesMmapMemory = false
    66  
    67  	// defaultForceIndexBloomFilterMmapMemory is the default configuration for whether the bytes for the bloom filter
    68  	// should be mmap'd as an anonymous region (forced completely into memory) or mmap'd as a file.
    69  	defaultForceIndexBloomFilterMmapMemory = false
    70  
    71  	// defaultIndexReaderAutovalidateIndexSegments is the default configuration for
    72  	// whether or not the index reader should autovalidate the index segments when
    73  	// opening segments. This is an expensive operation and should be done post-open.
    74  	defaultIndexReaderAutovalidateIndexSegments = false
    75  )
    76  
    77  var (
    78  	defaultFilePathPrefix   = os.TempDir()
    79  	defaultNewFileMode      = os.FileMode(0o666)
    80  	defaultNewDirectoryMode = os.ModeDir | os.FileMode(0o755)
    81  	defaultFSTWriterOptions = fst.WriterOptions{}
    82  
    83  	errTagEncoderPoolNotSet = errors.New("tag encoder pool is not set")
    84  	errTagDecoderPoolNotSet = errors.New("tag decoder pool is not set")
    85  )
    86  
    87  type options struct {
    88  	clockOpts                            clock.Options
    89  	instrumentOpts                       instrument.Options
    90  	runtimeOptsMgr                       runtime.OptionsManager
    91  	decodingOpts                         msgpack.DecodingOptions
    92  	filePathPrefix                       string
    93  	newFileMode                          os.FileMode
    94  	newDirectoryMode                     os.FileMode
    95  	indexSummariesPercent                float64
    96  	indexBloomFilterFalsePositivePercent float64
    97  	writerBufferSize                     int
    98  	dataReaderBufferSize                 int
    99  	infoReaderBufferSize                 int
   100  	seekReaderBufferSize                 int
   101  	mmapHugePagesThreshold               int64
   102  	tagEncoderPool                       serialize.TagEncoderPool
   103  	tagDecoderPool                       serialize.TagDecoderPool
   104  	fstOptions                           fst.Options
   105  	fstWriterOptions                     fst.WriterOptions
   106  	forceIndexSummariesMmapMemory        bool
   107  	forceBloomFilterMmapMemory           bool
   108  	mmapEnableHugePages                  bool
   109  	mmapReporter                         mmap.Reporter
   110  	indexReaderAutovalidateIndexSegments bool
   111  	encodingOptions                      msgpack.LegacyEncodingOptions
   112  }
   113  
   114  type optionsInput struct {
   115  	tagEncoderPool serialize.TagEncoderPool
   116  	tagDecoderPool serialize.TagDecoderPool
   117  	fstOptions     fst.Options
   118  
   119  	// the bools allow explicitly setting the field to nil
   120  	tagEncoderPoolSet bool
   121  	tagDecoderPoolSet bool
   122  	fstOptionsSet     bool
   123  }
   124  
   125  // OptionSetter is a function that modifies the behavior of NewOptions
   126  type OptionSetter func(o *optionsInput)
   127  
   128  // WithTagEncoderPool is an OptionSetter that provides custom serialize.TagEncoderPool
   129  // Passing nil will be equivalent to calling Options.SetTagEncoderPool(nil)
   130  // on the result of NewOptions
   131  func WithTagEncoderPool(o serialize.TagEncoderPool) OptionSetter {
   132  	return func(input *optionsInput) {
   133  		input.tagEncoderPool = o
   134  		input.tagEncoderPoolSet = true
   135  	}
   136  }
   137  
   138  // WithTagDecodePool is an OptionSetter that provides custom serialize.TagDecoder
   139  // Passing nil will be equivalent to calling Options.SetTagDecoderPool(nil)
   140  // on the result of NewOptions
   141  func WithTagDecodePool(o serialize.TagDecoderPool) OptionSetter {
   142  	return func(input *optionsInput) {
   143  		input.tagDecoderPool = o
   144  		input.tagDecoderPoolSet = true
   145  	}
   146  }
   147  
   148  // WithFstOptions is an OptionSetter that provides custom fst.Options
   149  // Passing nil will be equivalent to calling Options.SetFSTOptions(nil)
   150  // on the result of NewOptions
   151  func WithFstOptions(o fst.Options) OptionSetter {
   152  	return func(input *optionsInput) {
   153  		input.fstOptions = o
   154  		input.fstOptionsSet = true
   155  	}
   156  }
   157  
   158  // NewOptions creates a new set of fs options
   159  func NewOptions(setters ...OptionSetter) Options {
   160  	input := optionsInput{}
   161  	for _, setter := range setters {
   162  		setter(&input)
   163  	}
   164  	if !input.tagEncoderPoolSet && input.tagEncoderPool == nil {
   165  		input.tagEncoderPool = serialize.NewTagEncoderPool(
   166  			serialize.NewTagEncoderOptions(), pool.NewObjectPoolOptions())
   167  	}
   168  
   169  	if !input.tagDecoderPoolSet && input.tagDecoderPool == nil {
   170  		input.tagDecoderPool = serialize.NewTagDecoderPool(
   171  			serialize.NewTagDecoderOptions(serialize.TagDecoderOptionsConfig{}),
   172  			pool.NewObjectPoolOptions())
   173  	}
   174  
   175  	if !input.fstOptionsSet && input.fstOptions == nil {
   176  		input.fstOptions = fst.NewOptions()
   177  	}
   178  
   179  	if input.tagEncoderPool != nil {
   180  		input.tagEncoderPool.Init()
   181  	}
   182  	if input.tagDecoderPool != nil {
   183  		input.tagDecoderPool.Init()
   184  	}
   185  
   186  	return &options{
   187  		clockOpts:                            clock.NewOptions(),
   188  		instrumentOpts:                       instrument.NewOptions(),
   189  		runtimeOptsMgr:                       runtime.NewOptionsManager(),
   190  		decodingOpts:                         msgpack.NewDecodingOptions(),
   191  		filePathPrefix:                       defaultFilePathPrefix,
   192  		newFileMode:                          defaultNewFileMode,
   193  		newDirectoryMode:                     defaultNewDirectoryMode,
   194  		indexSummariesPercent:                defaultIndexSummariesPercent,
   195  		indexBloomFilterFalsePositivePercent: defaultIndexBloomFilterFalsePositivePercent,
   196  		forceIndexSummariesMmapMemory:        defaultForceIndexSummariesMmapMemory,
   197  		forceBloomFilterMmapMemory:           defaultForceIndexBloomFilterMmapMemory,
   198  		writerBufferSize:                     defaultWriterBufferSize,
   199  		dataReaderBufferSize:                 defaultDataReaderBufferSize,
   200  		infoReaderBufferSize:                 defaultInfoReaderBufferSize,
   201  		seekReaderBufferSize:                 defaultSeekReaderBufferSize,
   202  		mmapEnableHugePages:                  defaultMmapEnableHugePages,
   203  		mmapHugePagesThreshold:               defaultMmapHugePagesThreshold,
   204  		tagEncoderPool:                       input.tagEncoderPool,
   205  		tagDecoderPool:                       input.tagDecoderPool,
   206  		fstOptions:                           input.fstOptions,
   207  		fstWriterOptions:                     defaultFSTWriterOptions,
   208  		indexReaderAutovalidateIndexSegments: defaultIndexReaderAutovalidateIndexSegments,
   209  		encodingOptions:                      msgpack.DefaultLegacyEncodingOptions,
   210  	}
   211  }
   212  
   213  func (o *options) Validate() error {
   214  	if o.indexSummariesPercent < 0 || o.indexSummariesPercent > 1.0 {
   215  		return fmt.Errorf(
   216  			"invalid index summaries percent, must be >= 0 and <= 1: instead %f",
   217  			o.indexSummariesPercent)
   218  	}
   219  	if o.indexBloomFilterFalsePositivePercent < 0 || o.indexBloomFilterFalsePositivePercent > 1.0 {
   220  		return fmt.Errorf(
   221  			"invalid index bloom filter false positive percent, must be >= 0 and <= 1: instead %f",
   222  			o.indexBloomFilterFalsePositivePercent)
   223  	}
   224  	if o.tagEncoderPool == nil {
   225  		return errTagEncoderPoolNotSet
   226  	}
   227  	if o.tagDecoderPool == nil {
   228  		return errTagDecoderPoolNotSet
   229  	}
   230  	return nil
   231  }
   232  
   233  func (o *options) SetClockOptions(value clock.Options) Options {
   234  	opts := *o
   235  	opts.clockOpts = value
   236  	return &opts
   237  }
   238  
   239  func (o *options) ClockOptions() clock.Options {
   240  	return o.clockOpts
   241  }
   242  
   243  func (o *options) SetInstrumentOptions(value instrument.Options) Options {
   244  	opts := *o
   245  	opts.instrumentOpts = value
   246  	return &opts
   247  }
   248  
   249  func (o *options) InstrumentOptions() instrument.Options {
   250  	return o.instrumentOpts
   251  }
   252  
   253  func (o *options) SetRuntimeOptionsManager(value runtime.OptionsManager) Options {
   254  	opts := *o
   255  	opts.runtimeOptsMgr = value
   256  	return &opts
   257  }
   258  
   259  func (o *options) RuntimeOptionsManager() runtime.OptionsManager {
   260  	return o.runtimeOptsMgr
   261  }
   262  
   263  func (o *options) SetDecodingOptions(value msgpack.DecodingOptions) Options {
   264  	opts := *o
   265  	opts.decodingOpts = value
   266  	return &opts
   267  }
   268  
   269  func (o *options) DecodingOptions() msgpack.DecodingOptions {
   270  	return o.decodingOpts
   271  }
   272  
   273  func (o *options) SetFilePathPrefix(value string) Options {
   274  	opts := *o
   275  	opts.filePathPrefix = value
   276  	return &opts
   277  }
   278  
   279  func (o *options) FilePathPrefix() string {
   280  	return o.filePathPrefix
   281  }
   282  
   283  func (o *options) SetNewFileMode(value os.FileMode) Options {
   284  	opts := *o
   285  	opts.newFileMode = value
   286  	return &opts
   287  }
   288  
   289  func (o *options) NewFileMode() os.FileMode {
   290  	return o.newFileMode
   291  }
   292  
   293  func (o *options) SetNewDirectoryMode(value os.FileMode) Options {
   294  	opts := *o
   295  	opts.newDirectoryMode = value
   296  	return &opts
   297  }
   298  
   299  func (o *options) NewDirectoryMode() os.FileMode {
   300  	return o.newDirectoryMode
   301  }
   302  
   303  func (o *options) SetIndexSummariesPercent(value float64) Options {
   304  	opts := *o
   305  	opts.indexSummariesPercent = value
   306  	return &opts
   307  }
   308  
   309  func (o *options) IndexSummariesPercent() float64 {
   310  	return o.indexSummariesPercent
   311  }
   312  
   313  func (o *options) SetIndexBloomFilterFalsePositivePercent(value float64) Options {
   314  	opts := *o
   315  	opts.indexBloomFilterFalsePositivePercent = value
   316  	return &opts
   317  }
   318  
   319  func (o *options) IndexBloomFilterFalsePositivePercent() float64 {
   320  	return o.indexBloomFilterFalsePositivePercent
   321  }
   322  
   323  func (o *options) SetForceIndexSummariesMmapMemory(value bool) Options {
   324  	opts := *o
   325  	opts.forceIndexSummariesMmapMemory = value
   326  	return &opts
   327  }
   328  
   329  func (o *options) ForceIndexSummariesMmapMemory() bool {
   330  	return o.forceIndexSummariesMmapMemory
   331  }
   332  
   333  func (o *options) SetForceBloomFilterMmapMemory(value bool) Options {
   334  	opts := *o
   335  	opts.forceBloomFilterMmapMemory = value
   336  	return &opts
   337  }
   338  
   339  func (o *options) ForceBloomFilterMmapMemory() bool {
   340  	return o.forceBloomFilterMmapMemory
   341  }
   342  
   343  func (o *options) SetWriterBufferSize(value int) Options {
   344  	opts := *o
   345  	opts.writerBufferSize = value
   346  	return &opts
   347  }
   348  
   349  func (o *options) WriterBufferSize() int {
   350  	return o.writerBufferSize
   351  }
   352  
   353  func (o *options) SetDataReaderBufferSize(value int) Options {
   354  	opts := *o
   355  	opts.dataReaderBufferSize = value
   356  	return &opts
   357  }
   358  
   359  func (o *options) DataReaderBufferSize() int {
   360  	return o.dataReaderBufferSize
   361  }
   362  
   363  func (o *options) SetInfoReaderBufferSize(value int) Options {
   364  	opts := *o
   365  	opts.infoReaderBufferSize = value
   366  	return &opts
   367  }
   368  
   369  func (o *options) InfoReaderBufferSize() int {
   370  	return o.infoReaderBufferSize
   371  }
   372  
   373  func (o *options) SetSeekReaderBufferSize(value int) Options {
   374  	opts := *o
   375  	opts.seekReaderBufferSize = value
   376  	return &opts
   377  }
   378  
   379  func (o *options) SeekReaderBufferSize() int {
   380  	return o.seekReaderBufferSize
   381  }
   382  
   383  func (o *options) SetMmapEnableHugeTLB(value bool) Options {
   384  	opts := *o
   385  	opts.mmapEnableHugePages = value
   386  	return &opts
   387  }
   388  
   389  func (o *options) MmapEnableHugeTLB() bool {
   390  	return o.mmapEnableHugePages
   391  }
   392  
   393  func (o *options) SetMmapHugeTLBThreshold(value int64) Options {
   394  	opts := *o
   395  	opts.mmapHugePagesThreshold = value
   396  	return &opts
   397  }
   398  
   399  func (o *options) MmapHugeTLBThreshold() int64 {
   400  	return o.mmapHugePagesThreshold
   401  }
   402  
   403  func (o *options) SetTagEncoderPool(value serialize.TagEncoderPool) Options {
   404  	opts := *o
   405  	opts.tagEncoderPool = value
   406  	return &opts
   407  }
   408  
   409  func (o *options) TagEncoderPool() serialize.TagEncoderPool {
   410  	return o.tagEncoderPool
   411  }
   412  
   413  func (o *options) SetTagDecoderPool(value serialize.TagDecoderPool) Options {
   414  	opts := *o
   415  	opts.tagDecoderPool = value
   416  	return &opts
   417  }
   418  
   419  func (o *options) TagDecoderPool() serialize.TagDecoderPool {
   420  	return o.tagDecoderPool
   421  }
   422  
   423  func (o *options) SetFSTOptions(value fst.Options) Options {
   424  	opts := *o
   425  	opts.fstOptions = value
   426  	return &opts
   427  }
   428  
   429  func (o *options) FSTOptions() fst.Options {
   430  	return o.fstOptions
   431  }
   432  
   433  func (o *options) SetFSTWriterOptions(value fst.WriterOptions) Options {
   434  	opts := *o
   435  	opts.fstWriterOptions = value
   436  	return &opts
   437  }
   438  
   439  func (o *options) FSTWriterOptions() fst.WriterOptions {
   440  	return o.fstWriterOptions
   441  }
   442  
   443  func (o *options) SetMmapReporter(mmapReporter mmap.Reporter) Options {
   444  	opts := *o
   445  	opts.mmapReporter = mmapReporter
   446  	return &opts
   447  }
   448  
   449  func (o *options) MmapReporter() mmap.Reporter {
   450  	return o.mmapReporter
   451  }
   452  
   453  func (o *options) SetIndexReaderAutovalidateIndexSegments(value bool) Options {
   454  	opts := *o
   455  	opts.indexReaderAutovalidateIndexSegments = value
   456  	return &opts
   457  }
   458  
   459  func (o *options) IndexReaderAutovalidateIndexSegments() bool {
   460  	return o.indexReaderAutovalidateIndexSegments
   461  }
   462  
   463  func (o *options) SetEncodingOptions(value msgpack.LegacyEncodingOptions) Options {
   464  	opts := *o
   465  	opts.encodingOptions = value
   466  	return &opts
   467  }
   468  
   469  func (o *options) EncodingOptions() msgpack.LegacyEncodingOptions {
   470  	return o.encodingOptions
   471  }