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:
Jan-Otto Kröpke
2026-10-10 16:40:12 +02:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 40d7514078
commit 5e397bb34d
10 changed files with 288 additions and 25 deletions
+28 -3
View File
@@ -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.