gitlab-exporter 16.9.0 → 16.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 77bae663d5dff12133db411a27154cb55c100caf0bec1ecdd4dd4e8102c88994
4
- data.tar.gz: d98c9128dc327d8757d4bb8d021cf863274f59588767ff877ce5ebe4c3274636
3
+ metadata.gz: 3a3b7fa869eab272c352626dfd0f8acc2cbcc3fb2df46da92ea0387471282d2b
4
+ data.tar.gz: fc2f8a0a213b2a97a92ed5f417a5856f181c9f422cbbc4640c9cce45d86e4fcf
5
5
  SHA512:
6
- metadata.gz: ff4b8dc86a0765ab98cf1e7ac97ee7016e09e1ec1e0a08db4366bdd9a66ae75dc34cb9d41ad5ed28668a6d279f641db780526ac3619b04b114f4c68aa29d8a74
7
- data.tar.gz: a76a114f309436e969865d25cb3a0e7aa4b94d8239cb4d7f775958ef971d3a6747380d002adf8999d3a8be545ad3692980ae980dd5ed6e1a8533cc3f7bc87173
6
+ metadata.gz: 2f6603c161ae6c9346d5b3ecd919f4df54bceb8232e588db181d1142eedc2e90231039b15a357ceed1ae62ae735b7540567e2717bbacadcea5e83ddd5b366fb2
7
+ data.tar.gz: 760580b43d2290a933842a4ffbd4182fe60660b401d03e9df6a7c8d85f6c3363054124b9aba2fd5a4983fb1989a11f2df28cf2f3cbdf7ca67e653bde4be95bf7
data/Gemfile.lock CHANGED
@@ -1,12 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab-exporter (16.9.0)
4
+ gitlab-exporter (16.10.0)
5
5
  connection_pool (= 2.5.5)
6
6
  deep_merge (~> 1.2.2)
7
7
  faraday (= 2.14.3)
8
8
  pg (= 1.6.3)
9
- puma (= 8.0.1)
9
+ puma (= 8.0.2)
10
10
  quantile (= 0.2.1)
11
11
  redis (= 4.8.1)
12
12
  redis-namespace (= 1.11.0)
@@ -40,7 +40,7 @@ GEM
40
40
  racc
41
41
  pg (1.6.3)
42
42
  prism (1.9.0)
43
- puma (8.0.1)
43
+ puma (8.0.2)
44
44
  nio4r (~> 2.0)
45
45
  quantile (0.2.1)
46
46
  racc (1.8.1)
@@ -26,7 +26,7 @@ Gem::Specification.new do |s|
26
26
  s.add_runtime_dependency "deep_merge", "~> 1.2.2"
27
27
  s.add_runtime_dependency "faraday", "2.14.3"
28
28
  s.add_runtime_dependency "pg", "1.6.3"
29
- s.add_runtime_dependency "puma", "8.0.1"
29
+ s.add_runtime_dependency "puma", "8.0.2"
30
30
  s.add_runtime_dependency "quantile", "0.2.1"
31
31
  s.add_runtime_dependency "redis", "4.8.1"
32
32
  s.add_runtime_dependency "redis-namespace", "1.11.0"
@@ -1,107 +1,147 @@
1
1
  -- Originally from: https://github.com/ioguix/pgsql-bloat-estimation/blob/master/btree/btree_bloat.sql
2
- -- WARNING: executed with a non-superuser role, the query inspect only index on tables you are granted to read.
2
+ --
3
+ -- Rewritten to use CROSS JOIN LATERAL stages so this query stays in sync with the
4
+ -- `postgres_index_bloat_estimate(p_schema, p_idxname)` function used by the main GitLab
5
+ -- application's reindexing pipeline:
6
+ -- https://gitlab.com/gitlab-org/gitlab/-/blob/master/db/migrate/20260526120000_add_postgres_index_bloat_estimate_function.rb
7
+ --
8
+ -- Expanding the index columns inside a LATERAL join (instead of putting a set-returning
9
+ -- function such as generate_series in the SELECT list) avoids the ProjectSet barrier that
10
+ -- prevents the planner from pushing predicates down. See:
11
+ -- https://gitlab.com/gitlab-org/gitlab/-/work_items/569363
12
+ -- https://gitlab.com/gitlab-org/gitlab/-/work_items/599210
13
+ --
14
+ -- WARNING: executed with a non-superuser role, the query inspects only indexes on tables you are granted to read.
3
15
  -- WARNING: rows with is_na = 't' are known to have bad statistics ("name" type is not supported).
4
- -- This query is compatible with PostgreSQL 12 and after
5
- -- pg_stats is materialized so the planner sees the true row count before planning the join,
6
- -- avoiding a catastrophic cardinality underestimate on PostgreSQL 17.
7
- WITH pg_stats_cached AS MATERIALIZED (
8
- SELECT schemaname, tablename, attname, null_frac, avg_width
9
- FROM pg_catalog.pg_stats
10
- )
11
- SELECT current_database(), nspname AS schemaname, tblname, idxname AS object_name, bs*(relpages)::bigint AS real_size,
12
- bs*(relpages-est_pages)::bigint AS extra_size,
13
- 100 * (relpages-est_pages)::float / relpages AS extra_ratio,
14
- fillfactor,
15
- CASE WHEN relpages > est_pages_ff
16
- THEN bs*(relpages-est_pages_ff)
16
+ -- This query is compatible with PostgreSQL 9.3 and after (LATERAL joins).
17
+ --
18
+ -- Note: unlike the previous ioguix-style query, this form does NOT need to materialize
19
+ -- pg_stats to stay fast on PostgreSQL 17. The old query joined pg_stats once as a single
20
+ -- large join that the PG17 planner badly underestimated (see f18ac4b); here pg_stats is
21
+ -- looked up per index inside the LATERAL, resolving through the pg_statistic indexes, so
22
+ -- there is no single join for the planner to misestimate.
23
+ SELECT
24
+ current_database(),
25
+ n.nspname AS schemaname,
26
+ ct.relname AS tblname,
27
+ ci.relname AS object_name,
28
+ c.bs * ci.relpages::bigint AS real_size,
29
+ c.bs * (ci.relpages - bloat.est_pages)::bigint AS extra_size,
30
+ 100 * (ci.relpages - bloat.est_pages)::float / ci.relpages AS extra_ratio,
31
+ c.fillfactor,
32
+ CASE WHEN ci.relpages > bloat.est_pages_ff
33
+ THEN c.bs * (ci.relpages - bloat.est_pages_ff)
17
34
  ELSE 0
18
35
  END AS bloat_size,
19
- 100 * (relpages-est_pages_ff)::float / relpages AS bloat_ratio,
20
- is_na
21
- -- , 100-(pst).avg_leaf_density AS pst_avg_bloat, est_pages, index_tuple_hdr_bm, maxalign, pagehdr, nulldatawidth, nulldatahdrwidth, reltuples, relpages -- (DEBUG INFO)
22
- FROM (
23
- SELECT coalesce(1 +
24
- ceil(reltuples/floor((bs-pageopqdata-pagehdr)/(4+nulldatahdrwidth)::float)), 0 -- ItemIdData size + computed avg size of a tuple (nulldatahdrwidth)
25
- ) AS est_pages,
26
- coalesce(1 +
27
- ceil(reltuples/floor((bs-pageopqdata-pagehdr)*fillfactor/(100*(4+nulldatahdrwidth)::float))), 0
28
- ) AS est_pages_ff,
29
- bs, nspname, tblname, idxname, relpages, fillfactor, is_na
30
- -- , pgstatindex(idxoid) AS pst, index_tuple_hdr_bm, maxalign, pagehdr, nulldatawidth, nulldatahdrwidth, reltuples -- (DEBUG INFO)
31
- FROM (
32
- SELECT maxalign, bs, nspname, tblname, idxname, reltuples, relpages, idxoid, fillfactor,
33
- ( index_tuple_hdr_bm +
34
- maxalign - CASE -- Add padding to the index tuple header to align on MAXALIGN
35
- WHEN index_tuple_hdr_bm%maxalign = 0 THEN maxalign
36
- ELSE index_tuple_hdr_bm%maxalign
37
- END
38
- + nulldatawidth + maxalign - CASE -- Add padding to the data to align on MAXALIGN
39
- WHEN nulldatawidth = 0 THEN 0
40
- WHEN nulldatawidth::integer%maxalign = 0 THEN maxalign
41
- ELSE nulldatawidth::integer%maxalign
42
- END
43
- )::numeric AS nulldatahdrwidth, pagehdr, pageopqdata, is_na
44
- -- , index_tuple_hdr_bm, nulldatawidth -- (DEBUG INFO)
45
- FROM (
46
- SELECT n.nspname, i.tblname, i.idxname, i.reltuples, i.relpages,
47
- i.idxoid, i.fillfactor, current_setting('block_size')::numeric AS bs,
48
- CASE -- MAXALIGN: 4 on 32bits, 8 on 64bits (and mingw32 ?)
49
- WHEN version() ~ 'mingw32' OR version() ~ '64-bit|x86_64|ppc64|ia64|amd64' THEN 8
50
- ELSE 4
51
- END AS maxalign,
52
- /* per page header, fixed size: 20 for 7.X, 24 for others */
53
- 24 AS pagehdr,
54
- /* per page btree opaque data */
55
- 16 AS pageopqdata,
56
- /* per tuple header: add IndexAttributeBitMapData if some cols are null-able */
57
- CASE WHEN max(coalesce(s.null_frac,0)) = 0
58
- THEN 2 -- IndexTupleData size
59
- ELSE 2 + (( 32 + 8 - 1 ) / 8) -- IndexTupleData size + IndexAttributeBitMapData size ( max num filed per index + 8 - 1 /8)
60
- END AS index_tuple_hdr_bm,
61
- /* data len: we remove null values save space using it fractionnal part from stats */
62
- sum( (1-coalesce(s.null_frac, 0)) * coalesce(s.avg_width, 1024)) AS nulldatawidth,
63
- max( CASE WHEN i.atttypid = 'pg_catalog.name'::regtype THEN 1 ELSE 0 END ) > 0 AS is_na
64
- FROM (
65
- SELECT ct.relname AS tblname, ct.relnamespace, ic.idxname, ic.attpos, ic.indkey, ic.indkey[ic.attpos], ic.reltuples, ic.relpages, ic.tbloid, ic.idxoid, ic.fillfactor,
66
- coalesce(a1.attnum, a2.attnum) AS attnum, coalesce(a1.attname, a2.attname) AS attname, coalesce(a1.atttypid, a2.atttypid) AS atttypid,
67
- CASE WHEN a1.attnum IS NULL
68
- THEN ic.idxname
69
- ELSE ct.relname
70
- END AS attrelname
71
- FROM (
72
- SELECT idxname, reltuples, relpages, tbloid, idxoid, fillfactor, indkey,
73
- pg_catalog.generate_series(1,indnatts) AS attpos
74
- FROM (
75
- SELECT ci.relname AS idxname, ci.reltuples, ci.relpages, i.indrelid AS tbloid,
76
- i.indexrelid AS idxoid,
77
- coalesce(substring(
78
- array_to_string(ci.reloptions, ' ')
79
- from 'fillfactor=([0-9]+)')::smallint, 90) AS fillfactor,
80
- i.indnatts,
81
- pg_catalog.string_to_array(pg_catalog.textin(
82
- pg_catalog.int2vectorout(i.indkey)),' ')::int[] AS indkey
83
- FROM pg_catalog.pg_index i
84
- JOIN pg_catalog.pg_class ci ON ci.oid = i.indexrelid
85
- WHERE ci.relam=(SELECT oid FROM pg_am WHERE amname = 'btree')
86
- AND ci.relpages > 0
87
- ) AS idx_data
88
- ) AS ic
89
- JOIN pg_catalog.pg_class ct ON ct.oid = ic.tbloid
90
- LEFT JOIN pg_catalog.pg_attribute a1 ON
91
- ic.indkey[ic.attpos] <> 0
92
- AND a1.attrelid = ic.tbloid
93
- AND a1.attnum = ic.indkey[ic.attpos]
94
- LEFT JOIN pg_catalog.pg_attribute a2 ON
95
- ic.indkey[ic.attpos] = 0
96
- AND a2.attrelid = ic.idxoid
97
- AND a2.attnum = ic.attpos
98
- ) i
99
- JOIN pg_catalog.pg_namespace n ON n.oid = i.relnamespace
100
- JOIN pg_stats_cached s ON s.schemaname = n.nspname
101
- AND s.tablename = i.attrelname
102
- AND s.attname = i.attname
103
- GROUP BY 1,2,3,4,5,6,7,8,9,10,11
104
- ) AS rows_data_stats
105
- ) AS rows_hdr_pdg_stats
106
- ) AS relation_stats
107
- ORDER BY nspname, tblname, idxname;
36
+ 100 * (ci.relpages - bloat.est_pages_ff)::float / ci.relpages AS bloat_ratio,
37
+ bloat.is_na
38
+ FROM pg_catalog.pg_class ci
39
+ JOIN pg_catalog.pg_index i ON i.indexrelid = ci.oid
40
+ JOIN pg_catalog.pg_class ct ON ct.oid = i.indrelid
41
+ JOIN pg_catalog.pg_namespace n ON n.oid = ct.relnamespace
42
+
43
+ -- Per-index system constants and fillfactor.
44
+ CROSS JOIN LATERAL (
45
+ SELECT
46
+ current_setting('block_size')::numeric AS bs,
47
+ CASE -- MAXALIGN: 4 on 32bits, 8 on 64bits (and mingw32 ?)
48
+ WHEN version() ~ 'mingw32'::text
49
+ OR version() ~ '64-bit|x86_64|ppc64|ia64|amd64'::text THEN 8
50
+ ELSE 4
51
+ END AS maxalign,
52
+ 24 AS pagehdr, -- per page header, fixed size: 24 for 8.3 and after
53
+ 16 AS pageopqdata, -- per page btree opaque data
54
+ COALESCE(
55
+ substring(array_to_string(ci.reloptions, ' '::text) FROM 'fillfactor=([0-9]+)')::smallint::integer,
56
+ 90
57
+ ) AS fillfactor
58
+ ) c
59
+
60
+ -- Aggregate the per-column statistics for this index, expanding the index columns
61
+ -- through a LATERAL generate_series rather than a SELECT-list set-returning function.
62
+ CROSS JOIN LATERAL (
63
+ SELECT
64
+ max(CASE WHEN COALESCE(a1.atttypid, a2.atttypid) = 'pg_catalog.name'::regtype THEN 1 ELSE 0 END) > 0 AS is_na,
65
+ /* per tuple header: add IndexAttributeBitMapData if some cols are null-able */
66
+ CASE WHEN max(COALESCE(s_t.null_frac, s_x.null_frac, 0::real)) = 0::double precision
67
+ THEN 2 -- IndexTupleData size
68
+ ELSE 2 + (32 + 8 - 1) / 8 -- IndexTupleData size + IndexAttributeBitMapData size
69
+ END AS index_tuple_hdr_bm,
70
+ /* data len: we remove null values, saving space, using their fractional part from stats */
71
+ sum((1::double precision - COALESCE(s_t.null_frac, s_x.null_frac, 0::real))
72
+ * COALESCE(s_t.avg_width, s_x.avg_width, 1024)::double precision) AS nulldatawidth
73
+ FROM generate_series(1, i.indnatts::integer) AS gs(attpos)
74
+ -- Decode the indkey int2vector into an int[] once per index (not once per column).
75
+ CROSS JOIN LATERAL (
76
+ SELECT string_to_array(textin(int2vectorout(i.indkey)), ' '::text)::integer[] AS indkey_arr
77
+ ) ik
78
+ LEFT JOIN pg_catalog.pg_attribute a1
79
+ ON ik.indkey_arr[gs.attpos] <> 0
80
+ AND a1.attrelid = i.indrelid
81
+ AND a1.attnum = ik.indkey_arr[gs.attpos]
82
+ LEFT JOIN pg_catalog.pg_attribute a2
83
+ ON ik.indkey_arr[gs.attpos] = 0
84
+ AND a2.attrelid = ci.oid
85
+ AND a2.attnum = gs.attpos
86
+ LEFT JOIN pg_catalog.pg_stats s_t
87
+ ON s_t.schemaname = n.nspname
88
+ AND s_t.tablename = ct.relname
89
+ AND s_t.attname = a1.attname
90
+ LEFT JOIN pg_catalog.pg_stats s_x
91
+ ON s_x.schemaname = n.nspname
92
+ AND s_x.tablename = ci.relname
93
+ AND s_x.attname = a2.attname
94
+ ) agg
95
+
96
+ -- Index tuple header width, aligned on MAXALIGN.
97
+ CROSS JOIN LATERAL (
98
+ SELECT
99
+ (
100
+ (agg.index_tuple_hdr_bm + c.maxalign
101
+ - CASE -- Add padding to the index tuple header to align on MAXALIGN
102
+ WHEN (agg.index_tuple_hdr_bm % c.maxalign) = 0 THEN c.maxalign
103
+ ELSE agg.index_tuple_hdr_bm % c.maxalign
104
+ END)::double precision
105
+ + agg.nulldatawidth
106
+ + c.maxalign::double precision
107
+ - CASE -- Add padding to the data to align on MAXALIGN
108
+ WHEN agg.nulldatawidth = 0::double precision THEN 0
109
+ WHEN (agg.nulldatawidth::integer % c.maxalign) = 0 THEN c.maxalign
110
+ ELSE agg.nulldatawidth::integer % c.maxalign
111
+ END::double precision
112
+ )::numeric AS nulldatahdrwidth
113
+ ) hdr
114
+
115
+ -- Estimated number of pages, with and without the fillfactor applied.
116
+ CROSS JOIN LATERAL (
117
+ SELECT
118
+ agg.is_na,
119
+ -- NULLIF guards against division by zero: floor(...) reaches 0 once
120
+ -- nulldatahdrwidth exceeds the usable page size (an index whose columns are
121
+ -- entirely unanalyzed and fall back to the 1024-byte default width). Without
122
+ -- it, PostgreSQL raises a hard error that would fail the whole probe; instead
123
+ -- the NULL flows through the outer COALESCE to est_pages = 0.
124
+ COALESCE(
125
+ 1::double precision + ceil(
126
+ ci.reltuples / NULLIF(floor(
127
+ (c.bs - c.pageopqdata::numeric - c.pagehdr::numeric)::double precision
128
+ / (4::numeric + hdr.nulldatahdrwidth)::double precision
129
+ ), 0)
130
+ ),
131
+ 0::double precision
132
+ ) AS est_pages,
133
+ COALESCE(
134
+ 1::double precision + ceil(
135
+ ci.reltuples / NULLIF(floor(
136
+ ((c.bs - c.pageopqdata::numeric - c.pagehdr::numeric) * c.fillfactor::numeric)::double precision
137
+ / (100::double precision * (4::numeric + hdr.nulldatahdrwidth)::double precision)
138
+ ), 0)
139
+ ),
140
+ 0::double precision
141
+ ) AS est_pages_ff
142
+ ) bloat
143
+
144
+ WHERE ci.relkind = 'i'
145
+ AND ci.relam = (SELECT oid FROM pg_am WHERE amname = 'btree'::name)
146
+ AND ci.relpages > 0
147
+ ORDER BY n.nspname, ct.relname, ci.relname;
@@ -1,5 +1,5 @@
1
1
  module GitLab
2
2
  module Exporter
3
- VERSION = "16.9.0".freeze
3
+ VERSION = "16.10.0".freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-exporter
3
3
  version: !ruby/object:Gem::Version
4
- version: 16.9.0
4
+ version: 16.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pablo Carranza
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: 8.0.1
75
+ version: 8.0.2
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - '='
81
81
  - !ruby/object:Gem::Version
82
- version: 8.0.1
82
+ version: 8.0.2
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: quantile
85
85
  requirement: !ruby/object:Gem::Requirement