@cryptotaxi247 / netdata-1 / commits / 2706778fe

fix(go.d/oracledb): correct tablespace usage calculation for all types (#20373)

Ilya Mashchenko committed May 29, 2025 at 13:12 UTC 2706778fecb920e5767711f631b144296a12c4da
3 files changed +146 -46
src/go/plugin/go.d/collector/oracledb/charts.go
+6 -5
@@ -319,21 +319,22 @@ var (
319 }
320 )
321
322 -func (c *Collector) addTablespaceCharts(tablespace string) {
322 +func (c *Collector) addTablespaceCharts(ts tablespaceInfo) {
323 charts := tablespaceChartsTmpl.Copy()
324
325 for _, chart := range *charts {
326 - chart.ID = cleanChartId(fmt.Sprintf(chart.ID, tablespace))
326 + chart.ID = cleanChartId(fmt.Sprintf(chart.ID, ts.name))
327 chart.Labels = []module.Label{
328 - {Key: "tablespace", Value: tablespace},
328 + {Key: "tablespace", Value: ts.name},
329 + {Key: "autoextend_status", Value: ts.autoExtent},
330 }
331 for _, dim := range chart.Dims {
331 - dim.ID = fmt.Sprintf(dim.ID, tablespace)
332 + dim.ID = fmt.Sprintf(dim.ID, ts.name)
333 }
334 }
335
336 if err := c.Charts().Add(*charts...); err != nil {
336 - c.Warningf("failed to add tablespace '%s' charts: %v", tablespace, err)
337 + c.Warningf("failed to add tablespace '%s' charts: %v", ts.name, err)
338 }
339 }
340
src/go/plugin/go.d/collector/oracledb/collect_tablespace.go
+134 -41
@@ -5,45 +5,111 @@ package oracledb
5 import (
6 "fmt"
7 "strconv"
8 + "strings"
9 )
10
11 const queryTablespace = `
11 -SELECT
12 - f.tablespace_name,
13 - f.autoextensible,
14 - SUM(f.bytes) AS allocated_bytes,
15 - SUM(f.maxbytes) AS max_bytes,
16 - (SUM(f.bytes) - COALESCE(SUM(fs.free_bytes), 0)) AS used_bytes
17 -FROM
18 - dba_data_files f
19 -LEFT JOIN
20 - (
21 - SELECT
12 +SELECT
13 + ts.tablespace_name,
14 + ts.contents AS tablespace_type,
15 + CASE
16 + WHEN df_all.files_with_autoextend = 0 THEN 'NO'
17 + WHEN df_all.files_with_autoextend = df_all.total_files THEN 'YES'
18 + ELSE 'MIXED (' || df_all.files_with_autoextend || '/' || df_all.total_files || ')'
19 + END AS autoextend_status,
20 + CASE
21 + -- For PERMANENT tablespaces: allocated - free
22 + WHEN ts.contents = 'PERMANENT' THEN
23 + COALESCE(df_all.allocated_bytes, 0) - COALESCE(fs.free_bytes, 0)
24 + -- For UNDO tablespaces: sum of UNDO segments
25 + WHEN ts.contents = 'UNDO' THEN
26 + COALESCE(us.used_bytes, 0)
27 + -- For TEMPORARY tablespaces: use v$temp_space_header
28 + WHEN ts.contents = 'TEMPORARY' THEN
29 + COALESCE(tu.used_bytes, 0)
30 + ELSE 0
31 + END AS used_bytes,
32 + COALESCE(df_all.allocated_bytes, 0) AS allocated_bytes,
33 + -- For max_bytes, only count maxbytes from files with autoextend=YES
34 + COALESCE(df_all.max_bytes, 0) AS max_bytes
35 +FROM
36 + dba_tablespaces ts
37 + -- Combined datafiles and tempfiles info with autoextend counts
38 + LEFT JOIN (
39 + SELECT
40 + tablespace_name,
41 + COUNT(*) AS total_files,
42 + SUM(CASE WHEN autoextensible = 'YES' THEN 1 ELSE 0 END) AS files_with_autoextend,
43 + SUM(bytes) AS allocated_bytes,
44 + -- Only count maxbytes for files with autoextend enabled
45 + SUM(CASE
46 + WHEN autoextensible = 'YES' AND maxbytes > 0 THEN maxbytes
47 + WHEN autoextensible = 'YES' AND maxbytes = 0 THEN bytes
48 + ELSE bytes -- For non-autoextend files, current size is the max
49 + END) AS max_bytes
50 + FROM dba_data_files
51 + GROUP BY tablespace_name
52 + UNION ALL
53 + SELECT
54 + tablespace_name,
55 + COUNT(*) AS total_files,
56 + SUM(CASE WHEN autoextensible = 'YES' THEN 1 ELSE 0 END) AS files_with_autoextend,
57 + SUM(bytes) AS allocated_bytes,
58 + SUM(CASE
59 + WHEN autoextensible = 'YES' AND maxbytes > 0 THEN maxbytes
60 + WHEN autoextensible = 'YES' AND maxbytes = 0 THEN bytes
61 + ELSE bytes
62 + END) AS max_bytes
63 + FROM dba_temp_files
64 + GROUP BY tablespace_name
65 + ) df_all ON ts.tablespace_name = df_all.tablespace_name
66 + -- Free space for permanent tablespaces
67 + LEFT JOIN (
68 + SELECT
69 tablespace_name,
70 SUM(bytes) AS free_bytes
24 - FROM
25 - dba_free_space
26 - GROUP BY
27 - tablespace_name
28 - ) fs
29 - ON f.tablespace_name = fs.tablespace_name
30 -GROUP BY
31 - f.tablespace_name, f.autoextensible
71 + FROM dba_free_space
72 + GROUP BY tablespace_name
73 + ) fs ON ts.tablespace_name = fs.tablespace_name
74 + -- Used space for UNDO tablespaces
75 + LEFT JOIN (
76 + SELECT
77 + tablespace_name,
78 + SUM(bytes) AS used_bytes
79 + FROM dba_segments
80 + WHERE segment_type LIKE 'UNDO%'
81 + GROUP BY tablespace_name
82 + ) us ON ts.tablespace_name = us.tablespace_name
83 + -- Used space for TEMPORARY tablespaces
84 + LEFT JOIN (
85 + SELECT
86 + tablespace_name,
87 + SUM(bytes_used) AS used_bytes
88 + FROM v$temp_space_header
89 + GROUP BY tablespace_name
90 + ) tu ON ts.tablespace_name = tu.tablespace_name
91 +WHERE
92 + df_all.tablespace_name IS NOT NULL -- Only show tablespaces with datafiles/tempfiles
93 +ORDER BY
94 + ts.tablespace_name
95 `
96
97 +type tablespaceInfo struct {
98 + name string
99 + typ string
100 + autoExtent string
101 + allocBytes float64
102 + maxBytes float64
103 + usedBytes float64
104 +}
105 +
106 func (c *Collector) collectTablespace(mx map[string]int64) error {
107 q := queryTablespace
108 c.Debugf("executing query: %s", q)
109
38 - var ts struct {
39 - name string
40 - autoExtent bool
41 - allocBytes float64
42 - maxBytes float64
43 - usedBytes float64
44 - }
110 + var ts tablespaceInfo
111
46 - seen := make(map[string]bool)
112 + seen := make(map[string]tablespaceInfo)
113
114 err := c.doQuery(q, func(column, value string, lineEnd bool) error {
115 var err error
@@ -51,8 +117,18 @@ func (c *Collector) collectTablespace(mx map[string]int64) error {
117 switch column {
118 case "TABLESPACE_NAME":
119 ts.name = value
54 - case "AUTOEXTENSIBLE":
55 - ts.autoExtent = value == "YES"
120 + case "TABLESPACE_TYPE":
121 + ts.typ = value
122 + case "AUTOEXTEND_STATUS":
123 + switch {
124 + case value == "YES":
125 + value = "enabled"
126 + case value == "NO":
127 + value = "disabled"
128 + case strings.HasPrefix(value, "MIXED"):
129 + value = "mixed"
130 + }
131 + ts.autoExtent = value
132 case "ALLOCATED_BYTES":
133 ts.allocBytes, err = strconv.ParseFloat(value, 64)
134 case "MAX_BYTES":
@@ -65,21 +141,38 @@ func (c *Collector) collectTablespace(mx map[string]int64) error {
141 }
142
143 if lineEnd {
68 - seen[ts.name] = true
144 + if ts.typ == "TEMPORARY" {
145 + return nil
146 + }
147 + seen[ts.name] = ts
148 +
149 + limit := ts.maxBytes
150 + if ts.autoExtent == "disabled" {
151 + limit = ts.allocBytes
152 + }
153
70 - limit := ts.allocBytes
71 - if ts.autoExtent {
72 - limit = ts.maxBytes
154 + used := ts.usedBytes
155 + if used > limit {
156 + used = limit
157 + }
158 +
159 + avail := limit - used
160 +
161 + var util float64
162 + if limit > 0 {
163 + if util = used / limit * 100; util > 100 {
164 + util = 100
165 + }
166 }
167
168 px := fmt.Sprintf("tablespace_%s_", ts.name)
169
170 mx[px+"max_size_bytes"] = int64(limit)
78 - mx[px+"used_bytes"] = int64(ts.usedBytes)
79 - mx[px+"avail_bytes"] = int64(limit - ts.usedBytes)
171 + mx[px+"used_bytes"] = int64(used)
172 + mx[px+"avail_bytes"] = int64(avail)
173 mx[px+"utilization"] = 0
174 if limit > 0 {
82 - mx[px+"utilization"] = int64(ts.usedBytes / limit * 100 * precision)
175 + mx[px+"utilization"] = int64(util * precision)
176 }
177 }
178
@@ -89,14 +182,14 @@ func (c *Collector) collectTablespace(mx map[string]int64) error {
182 return err
183 }
184
92 - for name := range seen {
93 - if !c.seenTablespaces[name] {
94 - c.seenTablespaces[name] = true
95 - c.addTablespaceCharts(name)
185 + for _, ts := range seen {
186 + if !c.seenTablespaces[ts.name] {
187 + c.seenTablespaces[ts.name] = true
188 + c.addTablespaceCharts(ts)
189 }
190 }
191 for name := range c.seenTablespaces {
99 - if !seen[name] {
192 + if _, ok := seen[name]; !ok {
193 delete(c.seenTablespaces, name)
194 c.removeTablespaceChart(name)
195 }
src/go/plugin/go.d/collector/oracledb/metadata.yaml
+6
@@ -34,6 +34,10 @@ modules:
34 - `v$system_wait_class`
35 - `dba_data_files`
36 - `dba_free_space`
37 + - `dba_segments`
38 + - `dba_temp_files`
39 + - `dba_tablespaces`
40 + - `v$temp_space_header`
41 default_behavior:
42 auto_detection:
43 description: |
@@ -243,6 +247,8 @@ modules:
247 labels:
248 - name: tablespace
249 description: Tablespace name.
250 + - name: autoextend_status
251 + description: Autoextend status (enabled, disabled, mixed).
252 metrics:
253 - name: oracledb.tablespace_utilization
254 description: Tablespace Utilization