github.com/m3db/m3@v1.5.0/src/dbnode/storage/block/result.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 block
    22  
    23  import (
    24  	"sort"
    25  
    26  	"github.com/m3db/m3/src/dbnode/x/xio"
    27  	"github.com/m3db/m3/src/x/ident"
    28  	xtime "github.com/m3db/m3/src/x/time"
    29  )
    30  
    31  // NewFetchBlockResult creates a new fetch block result
    32  func NewFetchBlockResult(
    33  	start xtime.UnixNano,
    34  	blocks []xio.BlockReader,
    35  	err error,
    36  ) FetchBlockResult {
    37  	return FetchBlockResult{
    38  		Start:  start,
    39  		Blocks: blocks,
    40  		Err:    err,
    41  	}
    42  }
    43  
    44  type fetchBlockResultByTimeAscending []FetchBlockResult
    45  
    46  func (e fetchBlockResultByTimeAscending) Len() int           { return len(e) }
    47  func (e fetchBlockResultByTimeAscending) Swap(i, j int)      { e[i], e[j] = e[j], e[i] }
    48  func (e fetchBlockResultByTimeAscending) Less(i, j int) bool { return e[i].Start.Before(e[j].Start) }
    49  
    50  // SortFetchBlockResultByTimeAscending sorts fetch block results in time ascending order
    51  func SortFetchBlockResultByTimeAscending(results []FetchBlockResult) {
    52  	sort.Sort(fetchBlockResultByTimeAscending(results))
    53  }
    54  
    55  // NewFetchBlockMetadataResult creates a new fetch block metadata result.
    56  func NewFetchBlockMetadataResult(
    57  	start xtime.UnixNano,
    58  	size int64,
    59  	checksum *uint32,
    60  	lastRead xtime.UnixNano,
    61  	err error,
    62  ) FetchBlockMetadataResult {
    63  	return FetchBlockMetadataResult{
    64  		Start:    start,
    65  		Size:     size,
    66  		Checksum: checksum,
    67  		LastRead: lastRead,
    68  		Err:      err,
    69  	}
    70  }
    71  
    72  type fetchBlockMetadataResultByTimeAscending []FetchBlockMetadataResult
    73  
    74  func (a fetchBlockMetadataResultByTimeAscending) Len() int      { return len(a) }
    75  func (a fetchBlockMetadataResultByTimeAscending) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
    76  func (a fetchBlockMetadataResultByTimeAscending) Less(i, j int) bool {
    77  	return a[i].Start.Before(a[j].Start)
    78  }
    79  
    80  type fetchBlockMetadataResults struct {
    81  	results []FetchBlockMetadataResult
    82  	pool    FetchBlockMetadataResultsPool
    83  }
    84  
    85  // NewFetchBlockMetadataResults creates a non-pooled fetchBlockMetadataResults
    86  func NewFetchBlockMetadataResults() FetchBlockMetadataResults {
    87  	return &fetchBlockMetadataResults{}
    88  }
    89  
    90  func newPooledFetchBlockMetadataResults(
    91  	results []FetchBlockMetadataResult,
    92  	pool FetchBlockMetadataResultsPool,
    93  ) FetchBlockMetadataResults {
    94  	return &fetchBlockMetadataResults{results: results, pool: pool}
    95  }
    96  
    97  func (s *fetchBlockMetadataResults) Add(res FetchBlockMetadataResult) {
    98  	s.results = append(s.results, res)
    99  }
   100  
   101  func (s *fetchBlockMetadataResults) Results() []FetchBlockMetadataResult {
   102  	return s.results
   103  }
   104  
   105  func (s *fetchBlockMetadataResults) Sort() {
   106  	sort.Sort(fetchBlockMetadataResultByTimeAscending(s.results))
   107  }
   108  
   109  func (s *fetchBlockMetadataResults) Reset() {
   110  	var zeroed FetchBlockMetadataResult
   111  	for i := range s.results {
   112  		s.results[i] = zeroed
   113  	}
   114  	s.results = s.results[:0]
   115  }
   116  
   117  func (s *fetchBlockMetadataResults) Close() {
   118  	if s.pool != nil {
   119  		s.pool.Put(s)
   120  	}
   121  }
   122  
   123  // NewFetchBlocksMetadataResult creates new database blocks metadata
   124  func NewFetchBlocksMetadataResult(
   125  	id ident.ID,
   126  	tags ident.TagIterator,
   127  	blocks FetchBlockMetadataResults,
   128  ) FetchBlocksMetadataResult {
   129  	return FetchBlocksMetadataResult{ID: id, Tags: tags, Blocks: blocks}
   130  }
   131  
   132  type fetchBlocksMetadataResults struct {
   133  	results []FetchBlocksMetadataResult
   134  	pool    FetchBlocksMetadataResultsPool
   135  }
   136  
   137  // NewFetchBlocksMetadataResults creates a non-pooled FetchBlocksMetadataResults
   138  func NewFetchBlocksMetadataResults() FetchBlocksMetadataResults {
   139  	return &fetchBlocksMetadataResults{}
   140  }
   141  
   142  func newPooledFetchBlocksMetadataResults(
   143  	results []FetchBlocksMetadataResult,
   144  	pool FetchBlocksMetadataResultsPool,
   145  ) FetchBlocksMetadataResults {
   146  	return &fetchBlocksMetadataResults{results: results, pool: pool}
   147  }
   148  
   149  func (s *fetchBlocksMetadataResults) Add(res FetchBlocksMetadataResult) {
   150  	s.results = append(s.results, res)
   151  }
   152  
   153  func (s *fetchBlocksMetadataResults) Results() []FetchBlocksMetadataResult {
   154  	return s.results
   155  }
   156  
   157  func (s *fetchBlocksMetadataResults) Reset() {
   158  	var zeroed FetchBlocksMetadataResult
   159  	for i := range s.results {
   160  		s.results[i] = zeroed
   161  	}
   162  	s.results = s.results[:0]
   163  }
   164  
   165  func (s *fetchBlocksMetadataResults) Close() {
   166  	for i := range s.results {
   167  		if s.results[i].ID != nil {
   168  			s.results[i].ID.Finalize()
   169  			s.results[i].ID = nil
   170  		}
   171  		if s.results[i].Tags != nil {
   172  			s.results[i].Tags.Close()
   173  			s.results[i].Tags = nil
   174  		}
   175  		if s.results[i].Blocks != nil {
   176  			s.results[i].Blocks.Close()
   177  			s.results[i].Blocks = nil
   178  		}
   179  	}
   180  	if s.pool != nil {
   181  		s.pool.Put(s)
   182  	}
   183  }
   184  
   185  type filteredBlocksMetadataIter struct {
   186  	res      []FetchBlocksMetadataResult
   187  	id       ident.ID
   188  	metadata Metadata
   189  	resIdx   int
   190  	blockIdx int
   191  	err      error
   192  }
   193  
   194  // NewFilteredBlocksMetadataIter creates a new filtered blocks metadata
   195  // iterator, there's no pooling of the tags returned currently.
   196  // Only the repair process uses this currently which is unoptimized.
   197  func NewFilteredBlocksMetadataIter(
   198  	res FetchBlocksMetadataResults,
   199  ) FilteredBlocksMetadataIter {
   200  	return &filteredBlocksMetadataIter{res: res.Results()}
   201  }
   202  
   203  func (it *filteredBlocksMetadataIter) Next() bool {
   204  	if it.err != nil {
   205  		return false
   206  	}
   207  	if it.resIdx >= len(it.res) {
   208  		return false
   209  	}
   210  	blocks := it.res[it.resIdx].Blocks.Results()
   211  	for it.blockIdx < len(blocks) {
   212  		block := blocks[it.blockIdx]
   213  		if block.Err != nil {
   214  			it.blockIdx++
   215  			continue
   216  		}
   217  		break
   218  	}
   219  	if it.blockIdx >= len(blocks) {
   220  		it.resIdx++
   221  		it.blockIdx = 0
   222  		return it.Next()
   223  	}
   224  	it.id = it.res[it.resIdx].ID
   225  	block := blocks[it.blockIdx]
   226  	var tags ident.Tags
   227  	if tagsIter := it.res[it.resIdx].Tags; tagsIter != nil {
   228  		for tagsIter.Next() {
   229  			curr := tagsIter.Current()
   230  			tags.Append(ident.StringTag(curr.Name.String(), curr.Value.String()))
   231  		}
   232  		if err := tagsIter.Err(); err != nil {
   233  			it.err = err
   234  			return false
   235  		}
   236  		tagsIter.Close()
   237  		// Set to nil so it doesn't get closed again later and trigger a double-put pooling bug.
   238  		it.res[it.resIdx].Tags = nil
   239  	}
   240  	it.metadata = NewMetadata(it.id, tags, block.Start,
   241  		block.Size, block.Checksum, block.LastRead)
   242  	it.blockIdx++
   243  	return true
   244  }
   245  
   246  func (it *filteredBlocksMetadataIter) Current() (ident.ID, Metadata) {
   247  	return it.id, it.metadata
   248  }
   249  
   250  func (it *filteredBlocksMetadataIter) Err() error {
   251  	return it.err
   252  }