| 1 | //go:build cgo |
| 2 | |
| 3 | package db2 |
| 4 | |
| 5 | import ( |
| 6 | "fmt" |
| 7 | "sort" |
| 8 | "strings" |
| 9 | |
| 10 | "github.com/netdata/netdata/go/plugins/plugin/ibm.d/modules/db2/contexts" |
| 11 | ) |
| 12 | |
| 13 | type indexEntry struct { |
| 14 | name string |
| 15 | metrics indexInstanceMetrics |
| 16 | } |
| 17 | |
| 18 | type indexGroupAggregate struct { |
| 19 | LeafNodes int64 |
| 20 | IndexScans int64 |
| 21 | FullScans int64 |
| 22 | } |
| 23 | |
| 24 | func indexGroupKey(name string) string { |
| 25 | if idx := strings.Index(name, "."); idx > 0 { |
| 26 | return name[:idx] |
| 27 | } |
| 28 | return name |
| 29 | } |
| 30 | |
| 31 | func (a *indexGroupAggregate) add(m indexInstanceMetrics) { |
| 32 | a.LeafNodes += m.LeafNodes |
| 33 | a.IndexScans += m.IndexScans |
| 34 | a.FullScans += m.FullScans |
| 35 | } |
| 36 | |
| 37 | func (c *Collector) exportIndexMetrics() { |
| 38 | entries := make([]indexEntry, 0, len(c.mx.indexes)) |
| 39 | for name, metrics := range c.mx.indexes { |
| 40 | entries = append(entries, indexEntry{name: name, metrics: metrics}) |
| 41 | } |
| 42 | |
| 43 | if len(entries) == 0 { |
| 44 | c.clearWarnOnce("db2_index_overflow") |
| 45 | return |
| 46 | } |
| 47 | |
| 48 | sort.Slice(entries, func(i, j int) bool { |
| 49 | return entries[i].name < entries[j].name |
| 50 | }) |
| 51 | |
| 52 | limit := c.MaxIndexes |
| 53 | if limit <= 0 || limit > len(entries) { |
| 54 | limit = len(entries) |
| 55 | } |
| 56 | |
| 57 | groupAgg := make(map[string]*indexGroupAggregate) |
| 58 | overflowAgg := &indexGroupAggregate{} |
| 59 | overflowCount := 0 |
| 60 | overflowGroups := make(map[string]int) |
| 61 | overflowExample := make(map[string]string) |
| 62 | |
| 63 | for idx, entry := range entries { |
| 64 | key := indexGroupKey(entry.name) |
| 65 | agg := groupAgg[key] |
| 66 | if agg == nil { |
| 67 | agg = &indexGroupAggregate{} |
| 68 | groupAgg[key] = agg |
| 69 | } |
| 70 | agg.add(entry.metrics) |
| 71 | |
| 72 | if idx < limit { |
| 73 | labels := contexts.IndexLabels{Index: entry.name} |
| 74 | contexts.Index.Usage.Set(c.State, labels, contexts.IndexUsageValues{ |
| 75 | Index: entry.metrics.IndexScans, |
| 76 | Full: entry.metrics.FullScans, |
| 77 | }) |
| 78 | continue |
| 79 | } |
| 80 | |
| 81 | overflowAgg.add(entry.metrics) |
| 82 | overflowCount++ |
| 83 | overflowGroups[key]++ |
| 84 | if _, ok := overflowExample[key]; !ok { |
| 85 | overflowExample[key] = entry.name |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | c.emitIndexGroupMetrics(groupAgg, overflowAgg, overflowCount) |
| 90 | |
| 91 | if overflowCount > 0 { |
| 92 | parts := make([]string, 0, len(overflowGroups)) |
| 93 | for group, count := range overflowGroups { |
| 94 | parts = append(parts, fmt.Sprintf("%s:%d (e.g. %s)", group, count, overflowExample[group])) |
| 95 | } |
| 96 | sort.Strings(parts) |
| 97 | c.warnOnce("db2_index_overflow", "too many indexes for per-instance charts (MaxIndexes=%d). Aggregated %d additional indexes: %s", c.MaxIndexes, overflowCount, strings.Join(parts, ", ")) |
| 98 | } else { |
| 99 | c.clearWarnOnce("db2_index_overflow") |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | func (c *Collector) emitIndexGroupMetrics(groups map[string]*indexGroupAggregate, overflow *indexGroupAggregate, overflowCount int) { |
| 104 | keys := make([]string, 0, len(groups)) |
| 105 | for k := range groups { |
| 106 | keys = append(keys, k) |
| 107 | } |
| 108 | sort.Strings(keys) |
| 109 | |
| 110 | for _, key := range keys { |
| 111 | agg := groups[key] |
| 112 | labels := contexts.IndexGroupLabels{Group: key} |
| 113 | |
| 114 | contexts.IndexGroup.Usage.Set(c.State, labels, contexts.IndexGroupUsageValues{ |
| 115 | Index: agg.IndexScans, |
| 116 | Full: agg.FullScans, |
| 117 | }) |
| 118 | } |
| 119 | |
| 120 | if overflowCount > 0 && overflow != nil { |
| 121 | labels := contexts.IndexGroupLabels{Group: "__other__"} |
| 122 | contexts.IndexGroup.Usage.Set(c.State, labels, contexts.IndexGroupUsageValues{ |
| 123 | Index: overflow.IndexScans, |
| 124 | Full: overflow.FullScans, |
| 125 | }) |
| 126 | } |
| 127 | } |