github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/iter/cache.go (about)

     1  package iter
     2  
     3  import (
     4  	"github.com/grafana/loki/pkg/logproto"
     5  )
     6  
     7  type CacheEntryIterator interface {
     8  	EntryIterator
     9  	Wrapped() EntryIterator
    10  	Reset()
    11  }
    12  
    13  // cachedIterator is an iterator that caches iteration to be replayed later on.
    14  type cachedIterator struct {
    15  	cache   []entryWithLabels
    16  	wrapped EntryIterator // once set to nil it means we have to use the cache.
    17  
    18  	curr int
    19  
    20  	closeErr error
    21  	iterErr  error
    22  }
    23  
    24  // NewCachedIterator creates an iterator that cache iteration result and can be iterated again
    25  // after closing it without re-using the underlaying iterator `it`.
    26  func NewCachedIterator(it EntryIterator, cap int) CacheEntryIterator {
    27  	c := &cachedIterator{
    28  		wrapped: it,
    29  		cache:   make([]entryWithLabels, 0, cap),
    30  		curr:    -1,
    31  	}
    32  	return c
    33  }
    34  
    35  func (it *cachedIterator) Reset() {
    36  	it.curr = -1
    37  }
    38  
    39  func (it *cachedIterator) Wrapped() EntryIterator {
    40  	return it.wrapped
    41  }
    42  
    43  func (it *cachedIterator) consumeWrapped() bool {
    44  	if it.Wrapped() == nil {
    45  		return false
    46  	}
    47  	ok := it.Wrapped().Next()
    48  	// we're done with the base iterator.
    49  	if !ok {
    50  		it.closeErr = it.Wrapped().Close()
    51  		it.iterErr = it.Wrapped().Error()
    52  		it.wrapped = nil
    53  		return false
    54  	}
    55  	// we're caching entries
    56  	it.cache = append(it.cache, entryWithLabels{Entry: it.Wrapped().Entry(), labels: it.Wrapped().Labels(), streamHash: it.Wrapped().StreamHash()})
    57  	it.curr++
    58  	return true
    59  }
    60  
    61  func (it *cachedIterator) Next() bool {
    62  	if len(it.cache) == 0 && it.Wrapped() == nil {
    63  		return false
    64  	}
    65  	if it.curr+1 >= len(it.cache) {
    66  		if it.Wrapped() != nil {
    67  			return it.consumeWrapped()
    68  		}
    69  		return false
    70  	}
    71  	it.curr++
    72  	return true
    73  }
    74  
    75  func (it *cachedIterator) Entry() logproto.Entry {
    76  	if len(it.cache) == 0 || it.curr < 0 || it.curr >= len(it.cache) {
    77  		return logproto.Entry{}
    78  	}
    79  
    80  	return it.cache[it.curr].Entry
    81  }
    82  
    83  func (it *cachedIterator) Labels() string {
    84  	if len(it.cache) == 0 || it.curr < 0 || it.curr >= len(it.cache) {
    85  		return ""
    86  	}
    87  	return it.cache[it.curr].labels
    88  }
    89  
    90  func (it *cachedIterator) StreamHash() uint64 {
    91  	if len(it.cache) == 0 || it.curr < 0 || it.curr >= len(it.cache) {
    92  		return 0
    93  	}
    94  	return it.cache[it.curr].streamHash
    95  }
    96  
    97  func (it *cachedIterator) Error() error { return it.iterErr }
    98  
    99  func (it *cachedIterator) Close() error {
   100  	it.Reset()
   101  	return it.closeErr
   102  }
   103  
   104  type CacheSampleIterator interface {
   105  	SampleIterator
   106  	Wrapped() SampleIterator
   107  	Reset()
   108  }
   109  
   110  // cachedIterator is an iterator that caches iteration to be replayed later on.
   111  type cachedSampleIterator struct {
   112  	cache   []sampleWithLabels
   113  	wrapped SampleIterator
   114  
   115  	curr int
   116  
   117  	closeErr error
   118  	iterErr  error
   119  }
   120  
   121  // newSampleCachedIterator creates an iterator that cache iteration result and can be iterated again
   122  // after closing it without re-using the underlaying iterator `it`.
   123  func NewCachedSampleIterator(it SampleIterator, cap int) CacheSampleIterator {
   124  	c := &cachedSampleIterator{
   125  		wrapped: it,
   126  		cache:   make([]sampleWithLabels, 0, cap),
   127  		curr:    -1,
   128  	}
   129  	return c
   130  }
   131  
   132  func (it *cachedSampleIterator) Wrapped() SampleIterator {
   133  	return it.wrapped
   134  }
   135  
   136  func (it *cachedSampleIterator) Reset() {
   137  	it.curr = -1
   138  }
   139  
   140  func (it *cachedSampleIterator) consumeWrapped() bool {
   141  	if it.Wrapped() == nil {
   142  		return false
   143  	}
   144  	ok := it.Wrapped().Next()
   145  	// we're done with the base iterator.
   146  	if !ok {
   147  		it.closeErr = it.Wrapped().Close()
   148  		it.iterErr = it.Wrapped().Error()
   149  		it.wrapped = nil
   150  		return false
   151  	}
   152  	// we're caching entries
   153  	it.cache = append(it.cache, sampleWithLabels{Sample: it.Wrapped().Sample(), labels: it.Wrapped().Labels(), streamHash: it.Wrapped().StreamHash()})
   154  	it.curr++
   155  	return true
   156  }
   157  
   158  func (it *cachedSampleIterator) Next() bool {
   159  	if len(it.cache) == 0 && it.Wrapped() == nil {
   160  		return false
   161  	}
   162  	if it.curr+1 >= len(it.cache) {
   163  		if it.Wrapped() != nil {
   164  			return it.consumeWrapped()
   165  		}
   166  		return false
   167  	}
   168  	it.curr++
   169  	return true
   170  }
   171  
   172  func (it *cachedSampleIterator) Sample() logproto.Sample {
   173  	if len(it.cache) == 0 || it.curr < 0 || it.curr >= len(it.cache) {
   174  		return logproto.Sample{}
   175  	}
   176  	return it.cache[it.curr].Sample
   177  }
   178  
   179  func (it *cachedSampleIterator) Labels() string {
   180  	if len(it.cache) == 0 || it.curr < 0 || it.curr >= len(it.cache) {
   181  		return ""
   182  	}
   183  	return it.cache[it.curr].labels
   184  }
   185  
   186  func (it *cachedSampleIterator) StreamHash() uint64 {
   187  	if len(it.cache) == 0 || it.curr < 0 || it.curr >= len(it.cache) {
   188  		return 0
   189  	}
   190  	return it.cache[it.curr].streamHash
   191  }
   192  
   193  func (it *cachedSampleIterator) Error() error { return it.iterErr }
   194  
   195  func (it *cachedSampleIterator) Close() error {
   196  	it.Reset()
   197  	return it.closeErr
   198  }