mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-10-20 11:39:04 +02:00
mi: read elements without per-call allocations (#2652)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
40d7514078
commit
5e397bb34d
@@ -22,6 +22,7 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
@@ -232,8 +233,15 @@ func (o *Operation) Unmarshal[T any](dst *[]T) error {
|
||||
type miField struct {
|
||||
index int
|
||||
tag string
|
||||
name ElementName
|
||||
}
|
||||
|
||||
// miFieldsCache maps a struct type to its []miField. Collectors query the same
|
||||
// types on every scrape, so the tags are parsed and converted to UTF-16 once.
|
||||
//
|
||||
//nolint:gochecknoglobals
|
||||
var miFieldsCache sync.Map
|
||||
|
||||
// prepareUnmarshal checks that dst is non-nil and T is a struct, resets *dst to empty
|
||||
// and returns the `mi`-tagged fields of T. Callers run it before starting a query,
|
||||
// so invalid input is rejected without a WMI round trip.
|
||||
@@ -254,8 +262,14 @@ func prepareUnmarshal[T any](dst *[]T) ([]miField, error) {
|
||||
|
||||
// miFieldsOf returns the fields of T that carry an `mi` tag.
|
||||
// It returns ErrInvalidEntityType if T is not a struct.
|
||||
// The returned slice is shared and must not be modified.
|
||||
func miFieldsOf[T any]() ([]miField, error) {
|
||||
structType := reflect.TypeFor[T]()
|
||||
|
||||
if fields, ok := miFieldsCache.Load(structType); ok {
|
||||
return fields.([]miField), nil //nolint:forcetypeassert
|
||||
}
|
||||
|
||||
if structType.Kind() != reflect.Struct {
|
||||
return nil, ErrInvalidEntityType
|
||||
}
|
||||
@@ -263,12 +277,23 @@ func miFieldsOf[T any]() ([]miField, error) {
|
||||
fields := make([]miField, 0, structType.NumField())
|
||||
|
||||
for i := range structType.NumField() {
|
||||
if miTag := structType.Field(i).Tag.Get("mi"); miTag != "" {
|
||||
fields = append(fields, miField{index: i, tag: miTag})
|
||||
miTag := structType.Field(i).Tag.Get("mi")
|
||||
if miTag == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
name, err := NewElementName(miTag)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid mi tag %q: %w", miTag, err)
|
||||
}
|
||||
|
||||
fields = append(fields, miField{index: i, tag: miTag, name: name})
|
||||
}
|
||||
|
||||
return fields, nil
|
||||
// Concurrent first queries of a type agree on one shared slice.
|
||||
cached, _ := miFieldsCache.LoadOrStore(structType, fields)
|
||||
|
||||
return cached.([]miField), nil //nolint:forcetypeassert
|
||||
}
|
||||
|
||||
// unmarshal iterates over the operation's instances and appends them to dst.
|
||||
|
||||
Reference in New Issue
Block a user