github.com/m3db/m3@v1.5.0/src/dbnode/encoding/series_iterator_accumulator.go (about)

     1  // Copyright (c) 2020 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 encoding
    22  
    23  import (
    24  	"errors"
    25  	"fmt"
    26  
    27  	"github.com/m3db/m3/src/dbnode/ts"
    28  	"github.com/m3db/m3/src/x/ident"
    29  	xtime "github.com/m3db/m3/src/x/time"
    30  )
    31  
    32  var _ SeriesIteratorAccumulator = (*seriesIteratorAccumulator)(nil)
    33  
    34  type seriesIteratorAccumulator struct {
    35  	id    ident.ID
    36  	nsID  ident.ID
    37  	start xtime.UnixNano
    38  	end   xtime.UnixNano
    39  
    40  	iters                 iterators
    41  	seriesIterators       []SeriesIterator
    42  	firstAnnotationHolder annotationHolder
    43  
    44  	err       error
    45  	firstNext bool
    46  	closed    bool
    47  }
    48  
    49  // NewSeriesIteratorAccumulator creates a new series iterator.
    50  func NewSeriesIteratorAccumulator(iter SeriesIterator) (SeriesIteratorAccumulator, error) {
    51  	nsID := ""
    52  	if iter.Namespace() != nil {
    53  		nsID = iter.Namespace().String()
    54  	}
    55  	it := &seriesIteratorAccumulator{
    56  		// NB: clone id and nsID so that they will be accessible after underlying
    57  		// iterators are closed.
    58  		id:              ident.StringID(iter.ID().String()),
    59  		nsID:            ident.StringID(nsID),
    60  		seriesIterators: make([]SeriesIterator, 0, 2),
    61  		firstNext:       true,
    62  	}
    63  
    64  	it.iters.reset()
    65  
    66  	err := it.Add(iter)
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  
    71  	return it, nil
    72  }
    73  
    74  func (it *seriesIteratorAccumulator) Add(iter SeriesIterator) error {
    75  	if it.err != nil {
    76  		return it.err
    77  	}
    78  
    79  	if !iter.Next() {
    80  		err := iter.Err()
    81  		return err
    82  	}
    83  
    84  	firstAnnotation := iter.FirstAnnotation()
    85  	if !it.iters.push(iter) {
    86  		err := iter.Err()
    87  		return err
    88  	}
    89  
    90  	iterStart := iter.Start()
    91  	if start := it.start; start.IsZero() || iterStart.Before(start) {
    92  		it.start = iterStart
    93  		if len(firstAnnotation) > 0 {
    94  			it.firstAnnotationHolder.set(firstAnnotation)
    95  		}
    96  	}
    97  
    98  	iterEnd := iter.End()
    99  	if end := it.end; end.IsZero() || iterEnd.After(end) {
   100  		it.end = iterEnd
   101  	}
   102  
   103  	it.seriesIterators = append(it.seriesIterators, iter)
   104  	return nil
   105  }
   106  
   107  func (it *seriesIteratorAccumulator) ID() ident.ID {
   108  	return it.id
   109  }
   110  
   111  func (it *seriesIteratorAccumulator) Namespace() ident.ID {
   112  	return it.nsID
   113  }
   114  
   115  func (it *seriesIteratorAccumulator) Tags() ident.TagIterator {
   116  	// NB: the tags for each iterator must be the same, so it's valid to return
   117  	// from whichever iterator is available.
   118  	for _, iter := range it.seriesIterators {
   119  		if tags := iter.Tags(); tags != nil {
   120  			return tags
   121  		}
   122  	}
   123  
   124  	return ident.EmptyTagIterator
   125  }
   126  
   127  func (it *seriesIteratorAccumulator) Start() xtime.UnixNano {
   128  	return it.start
   129  }
   130  
   131  func (it *seriesIteratorAccumulator) End() xtime.UnixNano {
   132  	return it.end
   133  }
   134  
   135  func (it *seriesIteratorAccumulator) Next() bool {
   136  	if !it.firstNext {
   137  		if !it.hasNext() {
   138  			return false
   139  		}
   140  
   141  		it.moveToNext()
   142  	}
   143  
   144  	it.firstNext = false
   145  	return it.hasNext()
   146  }
   147  
   148  func (it *seriesIteratorAccumulator) Current() (ts.Datapoint, xtime.Unit, ts.Annotation) {
   149  	return it.iters.current()
   150  }
   151  
   152  func (it *seriesIteratorAccumulator) Err() error {
   153  	if it.err != nil {
   154  		return it.err
   155  	}
   156  
   157  	for _, iter := range it.seriesIterators {
   158  		if err := iter.Err(); err != nil {
   159  			it.err = err
   160  			return err
   161  		}
   162  	}
   163  
   164  	return nil
   165  }
   166  
   167  func (it *seriesIteratorAccumulator) FirstAnnotation() ts.Annotation {
   168  	return it.firstAnnotationHolder.get()
   169  }
   170  
   171  func (it *seriesIteratorAccumulator) Close() {
   172  	if it.isClosed() {
   173  		return
   174  	}
   175  	it.closed = true
   176  	if it.id != nil {
   177  		it.id.Finalize()
   178  		it.id = nil
   179  	}
   180  	if it.nsID != nil {
   181  		it.nsID.Finalize()
   182  		it.nsID = nil
   183  	}
   184  	it.iters.reset()
   185  	it.firstAnnotationHolder.reset()
   186  	it.firstNext = true
   187  }
   188  
   189  func (it *seriesIteratorAccumulator) Replicas() ([]MultiReaderIterator, error) {
   190  	if l := len(it.seriesIterators); l != 1 {
   191  		return nil, fmt.Errorf("cannot get replicas for accumulated series "+
   192  			"iterators: need 1 iterator, have %d", l)
   193  	}
   194  	return it.seriesIterators[0].Replicas()
   195  }
   196  
   197  func (it *seriesIteratorAccumulator) Reset(SeriesIteratorOptions) {
   198  	if it.err == nil {
   199  		it.err = errors.New("cannot reset a series accumulator")
   200  	}
   201  }
   202  
   203  func (it *seriesIteratorAccumulator) IterateEqualTimestampStrategy() IterateEqualTimestampStrategy {
   204  	return it.iters.equalTimesStrategy
   205  }
   206  
   207  func (it *seriesIteratorAccumulator) SetIterateEqualTimestampStrategy(
   208  	strategy IterateEqualTimestampStrategy,
   209  ) {
   210  	it.iters.equalTimesStrategy = strategy
   211  	for _, iter := range it.seriesIterators {
   212  		iter.SetIterateEqualTimestampStrategy(strategy)
   213  	}
   214  }
   215  
   216  func (it *seriesIteratorAccumulator) hasError() bool {
   217  	return it.err != nil
   218  }
   219  
   220  func (it *seriesIteratorAccumulator) isClosed() bool {
   221  	return it.closed
   222  }
   223  
   224  func (it *seriesIteratorAccumulator) hasMore() bool {
   225  	return it.iters.len() > 0
   226  }
   227  
   228  func (it *seriesIteratorAccumulator) hasNext() bool {
   229  	return !it.hasError() && !it.isClosed() && it.hasMore()
   230  }
   231  
   232  func (it *seriesIteratorAccumulator) moveToNext() {
   233  	for {
   234  		prev := it.iters.at()
   235  		next, err := it.iters.moveToValidNext()
   236  		if err != nil {
   237  			it.err = err
   238  			return
   239  		}
   240  		if !next {
   241  			return
   242  		}
   243  
   244  		curr := it.iters.at()
   245  		if curr != prev {
   246  			return
   247  		}
   248  
   249  		// Dedupe by continuing
   250  	}
   251  }
   252  
   253  func (it *seriesIteratorAccumulator) Stats() (SeriesIteratorStats, error) {
   254  	approx := 0
   255  	for _, iter := range it.seriesIterators {
   256  		stats, err := iter.Stats()
   257  		if err != nil {
   258  			return SeriesIteratorStats{}, err
   259  		}
   260  		approx += stats.ApproximateSizeInBytes
   261  	}
   262  	return SeriesIteratorStats{ApproximateSizeInBytes: approx}, nil
   263  }