-
Notifications
You must be signed in to change notification settings - Fork 12
[ES-1292925] Fix metrics with reusable counter resets #107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,30 +12,37 @@ import ( | |
| "github.com/prometheus/prometheus/tsdb/chunkenc" | ||
| ) | ||
|
|
||
| const UseMergedSeries = "use_merged_series" | ||
|
|
||
| // mergedSeries is a storage.Series that implements a simple merge sort algorithm. | ||
| // when replicas has conflict values at the same timestamp, the first replica will be selected. | ||
| type mergedSeries struct { | ||
| lset labels.Labels | ||
| replicas []storage.Series | ||
|
|
||
| isCounter bool | ||
| } | ||
|
|
||
| func NewMergedSeries(lset labels.Labels, replicas []storage.Series) storage.Series { | ||
| func NewMergedSeries(lset labels.Labels, replicas []storage.Series, f string) storage.Series { | ||
| return &mergedSeries{ | ||
| lset: lset, | ||
| replicas: replicas, | ||
|
|
||
| isCounter: isCounter(f), | ||
| } | ||
| } | ||
|
|
||
| func (m *mergedSeries) Labels() labels.Labels { | ||
| return m.lset | ||
| } | ||
| func (m *mergedSeries) Iterator(_ chunkenc.Iterator) chunkenc.Iterator { | ||
| iters := make([]chunkenc.Iterator, 0, len(m.replicas)) | ||
| iters := make([]adjustableSeriesIterator, 0, len(m.replicas)) | ||
| oks := make([]bool, 0, len(m.replicas)) | ||
| for _, r := range m.replicas { | ||
| it := r.Iterator(nil) | ||
| var it adjustableSeriesIterator | ||
| if m.isCounter { | ||
| it = &counterErrAdjustSeriesIterator{Iterator: r.Iterator(nil)} | ||
| } else { | ||
| it = &noopAdjustableSeriesIterator{Iterator: r.Iterator(nil)} | ||
| } | ||
|
Comment on lines
+40
to
+45
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are applying counter adjustments to the raw data samples before deduplication. This is more complicated than applying the adjustments to the single time series after deduplication. The adjustments will intervene with quorum-based deduplication logic. I'm concerned it may introduce other edge cases.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add another test case such that one raw time series has a large gap with a reset, but the other two have complete data?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added new test cases, the reason i've done it this way is to reuse |
||
| ok := it.Next() != chunkenc.ValNone // iterate to the first value. | ||
| iters = append(iters, it) | ||
| oks = append(oks, ok) | ||
|
|
@@ -49,26 +56,25 @@ func (m *mergedSeries) Iterator(_ chunkenc.Iterator) chunkenc.Iterator { | |
| } | ||
|
|
||
| type quorumValuePicker struct { | ||
| currentValue int64 | ||
| currentValue float64 | ||
| cnt int | ||
| } | ||
|
|
||
| func NewQuorumValuePicker(v float64) *quorumValuePicker { | ||
| return &quorumValuePicker{ | ||
| currentValue: int64(v), | ||
| currentValue: v, | ||
| cnt: 1, | ||
| } | ||
| } | ||
|
|
||
| // Return true if this is the new majority value. | ||
| func (q *quorumValuePicker) addValue(v float64) bool { | ||
| iv := int64(v) | ||
| if q.currentValue == iv { | ||
| if q.currentValue == v { | ||
jnyi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| q.cnt++ | ||
| } else { | ||
| q.cnt-- | ||
| if q.cnt == 0 { | ||
| q.currentValue = iv | ||
| q.currentValue = v | ||
| q.cnt = 1 | ||
| return true | ||
| } | ||
|
|
@@ -77,11 +83,12 @@ func (q *quorumValuePicker) addValue(v float64) bool { | |
| } | ||
|
|
||
| type mergedSeriesIterator struct { | ||
| iters []chunkenc.Iterator | ||
| iters []adjustableSeriesIterator | ||
| oks []bool | ||
|
|
||
| lastT int64 | ||
| lastIter chunkenc.Iterator | ||
| lastV float64 | ||
| lastIter adjustableSeriesIterator | ||
| } | ||
|
|
||
| func (m *mergedSeriesIterator) Next() chunkenc.ValueType { | ||
|
|
@@ -91,8 +98,8 @@ func (m *mergedSeriesIterator) Next() chunkenc.ValueType { | |
| // 1. Next()/Seek() is never called. m.lastT is math.MinInt64 in this case. | ||
| // 2. The iterator runs out of values. m.lastT is the last timestamp in this case. | ||
| minT := int64(math.MaxInt64) | ||
| var lastIter chunkenc.Iterator | ||
| quoramValue := NewQuorumValuePicker(0) | ||
| var lastIter adjustableSeriesIterator | ||
| quoramValue := NewQuorumValuePicker(0.0) | ||
| for i, it := range m.iters { | ||
| if !m.oks[i] { | ||
| continue | ||
|
|
@@ -117,6 +124,8 @@ func (m *mergedSeriesIterator) Next() chunkenc.ValueType { | |
| if m.lastIter == nil { | ||
| return chunkenc.ValNone | ||
| } | ||
| m.lastIter.adjustAtValue(m.lastV) | ||
| _, m.lastV = m.lastIter.At() | ||
| m.lastT = minT | ||
| return chunkenc.ValFloat | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.