github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/query/storage/m3/encoded_series_iterator.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 m3
    22  
    23  import (
    24  	"fmt"
    25  	"time"
    26  
    27  	"github.com/m3db/m3/src/dbnode/encoding"
    28  	"github.com/m3db/m3/src/query/block"
    29  	"github.com/m3db/m3/src/query/ts"
    30  	"github.com/m3db/m3/src/query/util"
    31  )
    32  
    33  // NewEncodedSeriesIter creates a new encoded series iterator.
    34  func NewEncodedSeriesIter(
    35  	meta block.Metadata,
    36  	seriesMetas []block.SeriesMeta,
    37  	seriesIters []encoding.SeriesIterator,
    38  	instrumented bool,
    39  ) block.SeriesIter {
    40  	return &encodedSeriesIter{
    41  		idx:          -1,
    42  		meta:         meta,
    43  		seriesMeta:   seriesMetas,
    44  		seriesIters:  seriesIters,
    45  		instrumented: instrumented,
    46  	}
    47  }
    48  
    49  type encodedSeriesIter struct {
    50  	idx          int
    51  	err          error
    52  	meta         block.Metadata
    53  	datapoints   ts.Datapoints
    54  	series       block.UnconsolidatedSeries
    55  	seriesMeta   []block.SeriesMeta
    56  	seriesIters  []encoding.SeriesIterator
    57  	instrumented bool
    58  }
    59  
    60  func (it *encodedSeriesIter) Current() block.UnconsolidatedSeries {
    61  	return it.series
    62  }
    63  
    64  func (it *encodedSeriesIter) Err() error {
    65  	return it.err
    66  }
    67  
    68  func (it *encodedSeriesIter) Next() bool {
    69  	if it.err != nil {
    70  		return false
    71  	}
    72  
    73  	it.idx++
    74  	next := it.idx < len(it.seriesIters)
    75  	if !next {
    76  		return false
    77  	}
    78  
    79  	iter := it.seriesIters[it.idx]
    80  	if it.datapoints == nil {
    81  		it.datapoints = make(ts.Datapoints, 0, initBlockReplicaLength)
    82  	} else {
    83  		it.datapoints = it.datapoints[:0]
    84  	}
    85  
    86  	var (
    87  		decodeDuration time.Duration
    88  		decodeStart    time.Time
    89  	)
    90  	if it.instrumented {
    91  		decodeStart = time.Now()
    92  	}
    93  
    94  	for iter.Next() {
    95  		dp, _, _ := iter.Current()
    96  		it.datapoints = append(it.datapoints,
    97  			ts.Datapoint{
    98  				Timestamp: dp.TimestampNanos,
    99  				Value:     dp.Value,
   100  			})
   101  	}
   102  
   103  	if it.instrumented {
   104  		decodeDuration = time.Since(decodeStart)
   105  	}
   106  
   107  	if it.err = iter.Err(); it.err != nil {
   108  		return false
   109  	}
   110  
   111  	it.series = block.NewUnconsolidatedSeries(
   112  		it.datapoints,
   113  		it.seriesMeta[it.idx],
   114  		block.UnconsolidatedSeriesStats{
   115  			Enabled:        it.instrumented,
   116  			DecodeDuration: decodeDuration,
   117  		})
   118  
   119  	return next
   120  }
   121  
   122  func (it *encodedSeriesIter) SeriesCount() int {
   123  	return len(it.seriesIters)
   124  }
   125  
   126  func (it *encodedSeriesIter) SeriesMeta() []block.SeriesMeta {
   127  	return it.seriesMeta
   128  }
   129  
   130  func (it *encodedSeriesIter) Close() {
   131  	// noop, as the resources at the step may still be in use;
   132  	// instead call Close() on the encodedBlock that generated this
   133  }
   134  
   135  // MultiSeriesIter returns batched series iterators for the block based on
   136  // given concurrency.
   137  func (b *encodedBlock) MultiSeriesIter(
   138  	concurrency int,
   139  ) ([]block.SeriesIterBatch, error) {
   140  	fn := iteratorBatchingFn
   141  	if b.options != nil && b.options.IteratorBatchingFn() != nil {
   142  		fn = b.options.IteratorBatchingFn()
   143  	}
   144  
   145  	return fn(
   146  		concurrency,
   147  		b.seriesBlockIterators,
   148  		b.seriesMetas,
   149  		b.meta,
   150  		b.options,
   151  	)
   152  }
   153  
   154  func iteratorBatchingFn(
   155  	concurrency int,
   156  	seriesBlockIterators []encoding.SeriesIterator,
   157  	seriesMetas []block.SeriesMeta,
   158  	meta block.Metadata,
   159  	opts Options,
   160  ) ([]block.SeriesIterBatch, error) {
   161  	if concurrency < 1 {
   162  		return nil, fmt.Errorf("batch size %d must be greater than 0", concurrency)
   163  	}
   164  
   165  	var (
   166  		iterCount  = len(seriesBlockIterators)
   167  		iters      = make([]block.SeriesIterBatch, 0, concurrency)
   168  		chunkSize  = iterCount / concurrency
   169  		remainder  = iterCount % concurrency
   170  		chunkSizes = make([]int, concurrency)
   171  	)
   172  
   173  	util.MemsetInt(chunkSizes, chunkSize)
   174  	for i := 0; i < remainder; i++ {
   175  		chunkSizes[i] = chunkSizes[i] + 1
   176  	}
   177  
   178  	start := 0
   179  	for _, chunkSize := range chunkSizes {
   180  		end := start + chunkSize
   181  
   182  		if end > iterCount {
   183  			end = iterCount
   184  		}
   185  
   186  		iter := NewEncodedSeriesIter(
   187  			meta, seriesMetas[start:end], seriesBlockIterators[start:end],
   188  			opts.Instrumented(),
   189  		)
   190  
   191  		iters = append(iters, block.SeriesIterBatch{
   192  			Iter: iter,
   193  			Size: end - start,
   194  		})
   195  
   196  		start = end
   197  	}
   198  
   199  	return iters, nil
   200  }
   201  
   202  // BlockSeriesProcessor processes blocks.
   203  type BlockSeriesProcessor interface {
   204  	Process(bl block.Block, opts Options, fn BlockSeriesProcessorFn) error
   205  }
   206  
   207  // BlockSeriesProcessorFn processes an individual series iterator.
   208  type BlockSeriesProcessorFn func(
   209  	iter block.SeriesIter,
   210  ) error
   211  
   212  // NewBlockSeriesProcessor creates a standard block processor.
   213  func NewBlockSeriesProcessor() BlockSeriesProcessor {
   214  	return seriesBlockProcessor{}
   215  }
   216  
   217  type seriesBlockProcessor struct {
   218  }
   219  
   220  func (p seriesBlockProcessor) Process(
   221  	bl block.Block,
   222  	opts Options,
   223  	fn BlockSeriesProcessorFn,
   224  ) error {
   225  	iter, err := bl.SeriesIter()
   226  	if err != nil {
   227  		return err
   228  	}
   229  	return fn(iter)
   230  }