mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
lib/protoparser/native: follow-up after fe01f4803d
This commit is contained in:
parent
fe01f4803d
commit
deaa8c1ffa
2 changed files with 35 additions and 35 deletions
|
@ -17,6 +17,7 @@ The following tip changes can be tested by building VictoriaMetrics components f
|
||||||
|
|
||||||
FEATURE: [vmalert](https://docs.victoriametrics.com/vmalert.html): add support for `alert_relabel_configs` option at `-notifier.config`. This option allows configuring relabeling rules for alerts before sending them to configured notifiers. See [these docs](https://docs.victoriametrics.com/vmalert.html#notifier-configuration-file) for details.
|
FEATURE: [vmalert](https://docs.victoriametrics.com/vmalert.html): add support for `alert_relabel_configs` option at `-notifier.config`. This option allows configuring relabeling rules for alerts before sending them to configured notifiers. See [these docs](https://docs.victoriametrics.com/vmalert.html#notifier-configuration-file) for details.
|
||||||
|
|
||||||
|
BUGFIX: fix goroutine leak and possible deadlock when importing invalid data via [native binary format](https://docs.victoriametrics.com/#how-to-import-data-in-native-format). See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/2423).
|
||||||
BUGFIX: [Graphite Render API](https://docs.victoriametrics.com/#graphite-render-api-usage): properly calculate [hitCount](https://graphite.readthedocs.io/en/latest/functions.html#graphite.render.functions.hitcount) function. Previously it could return empty results if there were no original samples in some parts of the selected time range.
|
BUGFIX: [Graphite Render API](https://docs.victoriametrics.com/#graphite-render-api-usage): properly calculate [hitCount](https://graphite.readthedocs.io/en/latest/functions.html#graphite.render.functions.hitcount) function. Previously it could return empty results if there were no original samples in some parts of the selected time range.
|
||||||
BUGFIX: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): allow overriding built-in function names inside [WITH templates](https://play.victoriametrics.com/promql/expand-with-exprs). For example, `WITH (sum(a,b) = a + b + 1) sum(x,y)` now expands into `x + y + 1`. Previously such a query would fail with `cannot use reserved name` error. See [this bugreport](https://github.com/VictoriaMetrics/metricsql/issues/5).
|
BUGFIX: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): allow overriding built-in function names inside [WITH templates](https://play.victoriametrics.com/promql/expand-with-exprs). For example, `WITH (sum(a,b) = a + b + 1) sum(x,y)` now expands into `x + y + 1`. Previously such a query would fail with `cannot use reserved name` error. See [this bugreport](https://github.com/VictoriaMetrics/metricsql/issues/5).
|
||||||
|
|
||||||
|
|
|
@ -42,57 +42,37 @@ func ParseStream(r io.Reader, isGzip bool, callback func(block *Block) error) er
|
||||||
|
|
||||||
// Read native blocks and feed workers with work.
|
// Read native blocks and feed workers with work.
|
||||||
sizeBuf := make([]byte, 4)
|
sizeBuf := make([]byte, 4)
|
||||||
var wg sync.WaitGroup
|
|
||||||
var (
|
ctx := &streamContext{}
|
||||||
callbackErrLock sync.Mutex
|
|
||||||
callbackErr error
|
|
||||||
)
|
|
||||||
addFirstErr := func(err error) {
|
|
||||||
processErrors.Inc()
|
|
||||||
callbackErrLock.Lock()
|
|
||||||
if callbackErr == nil {
|
|
||||||
callbackErr = fmt.Errorf("error when processing native block: %w", err)
|
|
||||||
}
|
|
||||||
callbackErrLock.Unlock()
|
|
||||||
}
|
|
||||||
for {
|
for {
|
||||||
uw := getUnmarshalWork()
|
uw := getUnmarshalWork()
|
||||||
uw.tr = tr
|
uw.tr = tr
|
||||||
uw.callback = func(block *Block, parseErr error) {
|
uw.ctx = ctx
|
||||||
defer wg.Done()
|
uw.callback = callback
|
||||||
// fast path
|
|
||||||
if parseErr != nil {
|
|
||||||
addFirstErr(parseErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := callback(block); err != nil {
|
|
||||||
addFirstErr(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read uw.metricNameBuf
|
// Read uw.metricNameBuf
|
||||||
if _, err := io.ReadFull(br, sizeBuf); err != nil {
|
if _, err := io.ReadFull(br, sizeBuf); err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
// End of stream
|
// End of stream
|
||||||
putUnmarshalWork(uw)
|
putUnmarshalWork(uw)
|
||||||
wg.Wait()
|
ctx.wg.Wait()
|
||||||
return callbackErr
|
return ctx.err
|
||||||
}
|
}
|
||||||
readErrors.Inc()
|
readErrors.Inc()
|
||||||
wg.Wait()
|
ctx.wg.Wait()
|
||||||
return fmt.Errorf("cannot read metricName size: %w", err)
|
return fmt.Errorf("cannot read metricName size: %w", err)
|
||||||
}
|
}
|
||||||
readCalls.Inc()
|
readCalls.Inc()
|
||||||
bufSize := encoding.UnmarshalUint32(sizeBuf)
|
bufSize := encoding.UnmarshalUint32(sizeBuf)
|
||||||
if bufSize > 1024*1024 {
|
if bufSize > 1024*1024 {
|
||||||
parseErrors.Inc()
|
parseErrors.Inc()
|
||||||
wg.Wait()
|
ctx.wg.Wait()
|
||||||
return fmt.Errorf("too big metricName size; got %d; shouldn't exceed %d", bufSize, 1024*1024)
|
return fmt.Errorf("too big metricName size; got %d; shouldn't exceed %d", bufSize, 1024*1024)
|
||||||
}
|
}
|
||||||
uw.metricNameBuf = bytesutil.ResizeNoCopyMayOverallocate(uw.metricNameBuf, int(bufSize))
|
uw.metricNameBuf = bytesutil.ResizeNoCopyMayOverallocate(uw.metricNameBuf, int(bufSize))
|
||||||
if _, err := io.ReadFull(br, uw.metricNameBuf); err != nil {
|
if _, err := io.ReadFull(br, uw.metricNameBuf); err != nil {
|
||||||
readErrors.Inc()
|
readErrors.Inc()
|
||||||
wg.Wait()
|
ctx.wg.Wait()
|
||||||
return fmt.Errorf("cannot read metricName with size %d bytes: %w", bufSize, err)
|
return fmt.Errorf("cannot read metricName with size %d bytes: %w", bufSize, err)
|
||||||
}
|
}
|
||||||
readCalls.Inc()
|
readCalls.Inc()
|
||||||
|
@ -100,30 +80,36 @@ func ParseStream(r io.Reader, isGzip bool, callback func(block *Block) error) er
|
||||||
// Read uw.blockBuf
|
// Read uw.blockBuf
|
||||||
if _, err := io.ReadFull(br, sizeBuf); err != nil {
|
if _, err := io.ReadFull(br, sizeBuf); err != nil {
|
||||||
readErrors.Inc()
|
readErrors.Inc()
|
||||||
wg.Wait()
|
ctx.wg.Wait()
|
||||||
return fmt.Errorf("cannot read native block size: %w", err)
|
return fmt.Errorf("cannot read native block size: %w", err)
|
||||||
}
|
}
|
||||||
readCalls.Inc()
|
readCalls.Inc()
|
||||||
bufSize = encoding.UnmarshalUint32(sizeBuf)
|
bufSize = encoding.UnmarshalUint32(sizeBuf)
|
||||||
if bufSize > 1024*1024 {
|
if bufSize > 1024*1024 {
|
||||||
parseErrors.Inc()
|
parseErrors.Inc()
|
||||||
wg.Wait()
|
ctx.wg.Wait()
|
||||||
return fmt.Errorf("too big native block size; got %d; shouldn't exceed %d", bufSize, 1024*1024)
|
return fmt.Errorf("too big native block size; got %d; shouldn't exceed %d", bufSize, 1024*1024)
|
||||||
}
|
}
|
||||||
uw.blockBuf = bytesutil.ResizeNoCopyMayOverallocate(uw.blockBuf, int(bufSize))
|
uw.blockBuf = bytesutil.ResizeNoCopyMayOverallocate(uw.blockBuf, int(bufSize))
|
||||||
if _, err := io.ReadFull(br, uw.blockBuf); err != nil {
|
if _, err := io.ReadFull(br, uw.blockBuf); err != nil {
|
||||||
readErrors.Inc()
|
readErrors.Inc()
|
||||||
wg.Wait()
|
ctx.wg.Wait()
|
||||||
return fmt.Errorf("cannot read native block with size %d bytes: %w", bufSize, err)
|
return fmt.Errorf("cannot read native block with size %d bytes: %w", bufSize, err)
|
||||||
}
|
}
|
||||||
readCalls.Inc()
|
readCalls.Inc()
|
||||||
blocksRead.Inc()
|
blocksRead.Inc()
|
||||||
|
|
||||||
wg.Add(1)
|
ctx.wg.Add(1)
|
||||||
common.ScheduleUnmarshalWork(uw)
|
common.ScheduleUnmarshalWork(uw)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type streamContext struct {
|
||||||
|
wg sync.WaitGroup
|
||||||
|
errLock sync.Mutex
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
// Block is a single block from `/api/v1/import/native` request.
|
// Block is a single block from `/api/v1/import/native` request.
|
||||||
type Block struct {
|
type Block struct {
|
||||||
MetricName storage.MetricName
|
MetricName storage.MetricName
|
||||||
|
@ -149,13 +135,15 @@ var (
|
||||||
|
|
||||||
type unmarshalWork struct {
|
type unmarshalWork struct {
|
||||||
tr storage.TimeRange
|
tr storage.TimeRange
|
||||||
callback func(block *Block, parseErr error)
|
ctx *streamContext
|
||||||
|
callback func(block *Block) error
|
||||||
metricNameBuf []byte
|
metricNameBuf []byte
|
||||||
blockBuf []byte
|
blockBuf []byte
|
||||||
block Block
|
block Block
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uw *unmarshalWork) reset() {
|
func (uw *unmarshalWork) reset() {
|
||||||
|
uw.ctx = nil
|
||||||
uw.callback = nil
|
uw.callback = nil
|
||||||
uw.metricNameBuf = uw.metricNameBuf[:0]
|
uw.metricNameBuf = uw.metricNameBuf[:0]
|
||||||
uw.blockBuf = uw.blockBuf[:0]
|
uw.blockBuf = uw.blockBuf[:0]
|
||||||
|
@ -167,8 +155,19 @@ func (uw *unmarshalWork) Unmarshal() {
|
||||||
err := uw.unmarshal()
|
err := uw.unmarshal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
parseErrors.Inc()
|
parseErrors.Inc()
|
||||||
|
} else {
|
||||||
|
err = uw.callback(&uw.block)
|
||||||
}
|
}
|
||||||
uw.callback(&uw.block, err)
|
ctx := uw.ctx
|
||||||
|
if err != nil {
|
||||||
|
processErrors.Inc()
|
||||||
|
ctx.errLock.Lock()
|
||||||
|
if ctx.err == nil {
|
||||||
|
ctx.err = fmt.Errorf("error when processing native block: %w", err)
|
||||||
|
}
|
||||||
|
ctx.errLock.Unlock()
|
||||||
|
}
|
||||||
|
ctx.wg.Done()
|
||||||
putUnmarshalWork(uw)
|
putUnmarshalWork(uw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue