| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | package clickhouse |
| 4 | |
| 5 | import ( |
| 6 | "fmt" |
| 7 | "strconv" |
| 8 | |
| 9 | "github.com/netdata/netdata/go/plugins/pkg/web" |
| 10 | ) |
| 11 | |
| 12 | const querySystemParts = ` |
| 13 | SELECT |
| 14 | database, |
| 15 | table, |
| 16 | sum(bytes) as bytes, |
| 17 | count() as parts, |
| 18 | sum(rows) as rows |
| 19 | FROM |
| 20 | system.parts |
| 21 | WHERE |
| 22 | active = 1 |
| 23 | GROUP BY |
| 24 | database, |
| 25 | table FORMAT CSVWithNames |
| 26 | ` |
| 27 | |
| 28 | type tableStats struct { |
| 29 | database string |
| 30 | table string |
| 31 | bytes int64 |
| 32 | parts int64 |
| 33 | rows int64 |
| 34 | } |
| 35 | |
| 36 | func (c *Collector) collectSystemParts(mx map[string]int64) error { |
| 37 | req, err := web.NewHTTPRequest(c.RequestConfig) |
| 38 | if err != nil { |
| 39 | return err |
| 40 | } |
| 41 | req.URL.RawQuery = makeURLQuery(querySystemParts) |
| 42 | |
| 43 | seen := make(map[string]*tableStats) |
| 44 | |
| 45 | getTable := func(db, table string) *tableStats { |
| 46 | k := table + db |
| 47 | s, ok := seen[k] |
| 48 | if !ok { |
| 49 | s = &tableStats{database: db, table: table} |
| 50 | seen[k] = s |
| 51 | } |
| 52 | return s |
| 53 | } |
| 54 | |
| 55 | var database, table string |
| 56 | |
| 57 | err = c.doHTTP(req, func(column, value string, lineEnd bool) { |
| 58 | switch column { |
| 59 | case "database": |
| 60 | database = value |
| 61 | case "table": |
| 62 | table = value |
| 63 | case "bytes": |
| 64 | v, _ := strconv.ParseInt(value, 10, 64) |
| 65 | getTable(database, table).bytes = v |
| 66 | case "parts": |
| 67 | v, _ := strconv.ParseInt(value, 10, 64) |
| 68 | getTable(database, table).parts = v |
| 69 | case "rows": |
| 70 | v, _ := strconv.ParseInt(value, 10, 64) |
| 71 | getTable(database, table).rows = v |
| 72 | } |
| 73 | }) |
| 74 | if err != nil { |
| 75 | return err |
| 76 | } |
| 77 | |
| 78 | for _, table := range seen { |
| 79 | k := table.table + table.database |
| 80 | if _, ok := c.seenDbTables[k]; !ok { |
| 81 | v := &seenTable{db: table.database, table: table.table} |
| 82 | c.seenDbTables[k] = v |
| 83 | c.addTableCharts(v) |
| 84 | } |
| 85 | |
| 86 | px := fmt.Sprintf("table_%s_database_%s_", table.table, table.database) |
| 87 | |
| 88 | mx[px+"size_bytes"] = table.bytes |
| 89 | mx[px+"parts"] = table.parts |
| 90 | mx[px+"rows"] = table.rows |
| 91 | } |
| 92 | |
| 93 | for k, v := range c.seenDbTables { |
| 94 | if _, ok := seen[k]; !ok { |
| 95 | delete(c.seenDbTables, k) |
| 96 | c.removeTableCharts(v) |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | return nil |
| 101 | } |