gitlab-exporter 7.1.2 → 10.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 350884c8d1f03a58cad2630e0076aa641d22d60aed65a5d2342cb7f4508ec655
4
- data.tar.gz: d1857b8e6a8f842b438d12810c110ff4b8bbdf5226b5a6c5859dd949c12d1dd6
3
+ metadata.gz: 0f7115d7a7e8604d15ad7734afd3280c22edf9f6911af159f9386f2a9d495701
4
+ data.tar.gz: 7b050b23851b8073da229a5347b0c22afd641a1420859f37f0a0b8a7a4113244
5
5
  SHA512:
6
- metadata.gz: 9b62aaf4f95b4da82b1e5bc86058b97c363a1b43ae7026589e30da6af47ccf69261ec279094574927180b270be358afbba8304d10bff3fe8fb047fb54b6be538
7
- data.tar.gz: 34d27b77c5b04c4a079d184ff30db9b75f37471f9ac0e5199790ce550ee360e52d6f81d2b22b6f159a780ff7525b866b79f8ab0c06265d6251f697177b86fc83
6
+ metadata.gz: 848007d860313f8d62239b3f97a9024944aec9ddbfe6ea97472eaae64ddfc6e03cc056fe9466ce719209a6fad2b5a88947ff085f25ed6cf4ecf6421c1db576d7
7
+ data.tar.gz: f751e8af1eea6d30eb00dae65ec41681b50e9481a392b6521fde15c07934d8550dd2c3e3b65ea13ae6cbc0adadfe30986bad418c88172699b3172d20f9f62a75
@@ -7,7 +7,7 @@ include:
7
7
  - template: Security/Secret-Detection.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-foss/-/blob/master/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml
8
8
 
9
9
  default:
10
- image: "ruby:2.3"
10
+ image: ruby:2.7
11
11
  cache:
12
12
  paths:
13
13
  - vendor
@@ -1,5 +1,7 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
1
3
  AllCops:
2
- TargetRubyVersion: 2.3
4
+ TargetRubyVersion: 2.7
3
5
  DisplayCopNames: true
4
6
 
5
7
  # Just use double quotes please
@@ -20,15 +22,15 @@ Style/RaiseArgs:
20
22
  Style/FrozenStringLiteralComment:
21
23
  Enabled: false
22
24
 
25
+ # Commonly used screens these days easily fit more than 80 characters.
26
+ Layout/LineLength:
27
+ Max: 120
28
+
23
29
  Metrics/MethodLength:
24
30
  Max: 15
25
31
 
26
32
  Metrics/AbcSize:
27
33
  Enabled: false
28
34
 
29
- # Commonly used screens these days easily fit more than 80 characters.
30
- Metrics/LineLength:
31
- Max: 120
32
-
33
35
  Metrics/ClassLength:
34
36
  Max: 150
@@ -0,0 +1,64 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2021-01-11 12:24:03 UTC using RuboCop version 0.93.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Configuration parameters: Include.
11
+ # Include: **/*.gemspec
12
+ Gemspec/RequiredRubyVersion:
13
+ Exclude:
14
+ - 'gitlab-exporter.gemspec'
15
+
16
+ # Offense count: 3
17
+ Lint/AmbiguousBlockAssociation:
18
+ Exclude:
19
+ - 'spec/git_spec.rb'
20
+ - 'spec/util_spec.rb'
21
+
22
+ # Offense count: 2
23
+ # Configuration parameters: MaximumRangeSize.
24
+ Lint/MissingCopEnableDirective:
25
+ Exclude:
26
+ - 'spec/database/ci_builds_spec.rb'
27
+ - 'spec/git_process_proper_spec.rb'
28
+
29
+ # Offense count: 1
30
+ # Cop supports --auto-correct.
31
+ Lint/NonDeterministicRequireOrder:
32
+ Exclude:
33
+ - 'spec/spec_helper.rb'
34
+
35
+ # Offense count: 16
36
+ # Configuration parameters: CountComments, CountAsOne, ExcludedMethods.
37
+ # ExcludedMethods: refine
38
+ Metrics/BlockLength:
39
+ Max: 349
40
+
41
+ # Offense count: 1
42
+ # Configuration parameters: IgnoredMethods.
43
+ Metrics/CyclomaticComplexity:
44
+ Max: 8
45
+
46
+ # Offense count: 1
47
+ # Configuration parameters: IgnoredMethods.
48
+ Metrics/PerceivedComplexity:
49
+ Max: 9
50
+
51
+ # Offense count: 1
52
+ # Configuration parameters: EnforcedStyle, AllowModifiersOnSymbols.
53
+ # SupportedStyles: inline, group
54
+ Style/AccessModifierDeclarations:
55
+ Exclude:
56
+ - 'lib/gitlab_exporter/util.rb'
57
+
58
+ # Offense count: 2
59
+ # Cop supports --auto-correct.
60
+ # Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods.
61
+ # AllowedMethods: present?, blank?, presence, try, try!
62
+ Style/SafeNavigation:
63
+ Exclude:
64
+ - 'lib/gitlab_exporter/database/base.rb'
@@ -0,0 +1 @@
1
+ 2.7.2
@@ -1,9 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab-exporter (7.1.2)
4
+ gitlab-exporter (10.0.0)
5
5
  connection_pool (~> 2.2.1)
6
6
  pg (~> 1.1)
7
+ puma (~> 5.1.1)
7
8
  quantile (~> 0.2.0)
8
9
  redis (~> 4.1.2)
9
10
  redis-namespace (~> 1.6.0)
@@ -13,23 +14,28 @@ PATH
13
14
  GEM
14
15
  remote: https://rubygems.org/
15
16
  specs:
16
- ast (2.4.0)
17
+ ast (2.4.1)
17
18
  connection_pool (2.2.3)
18
19
  diff-lcs (1.3)
19
20
  mustermann (1.1.1)
20
21
  ruby2_keywords (~> 0.0.1)
21
- parser (2.5.1.0)
22
- ast (~> 2.4.0)
22
+ nio4r (2.5.4)
23
+ parallel (1.20.1)
24
+ parser (3.0.0.0)
25
+ ast (~> 2.4.1)
23
26
  pg (1.2.3)
24
- powerpack (0.1.1)
27
+ puma (5.1.1)
28
+ nio4r (~> 2.0)
25
29
  quantile (0.2.1)
26
30
  rack (2.2.3)
27
31
  rack-protection (2.0.8.1)
28
32
  rack
29
- rainbow (2.1.0)
33
+ rainbow (3.0.0)
30
34
  redis (4.1.4)
31
35
  redis-namespace (1.6.0)
32
36
  redis (>= 3.0.4)
37
+ regexp_parser (2.0.3)
38
+ rexml (3.2.4)
33
39
  rspec (3.7.0)
34
40
  rspec-core (~> 3.7.0)
35
41
  rspec-expectations (~> 3.7.0)
@@ -43,14 +49,19 @@ GEM
43
49
  diff-lcs (>= 1.2.0, < 2.0)
44
50
  rspec-support (~> 3.7.0)
45
51
  rspec-support (3.7.1)
46
- rubocop (0.42.0)
47
- parser (>= 2.3.1.1, < 3.0)
48
- powerpack (~> 0.1)
49
- rainbow (>= 1.99.1, < 3.0)
52
+ rubocop (0.93.1)
53
+ parallel (~> 1.10)
54
+ parser (>= 2.7.1.5)
55
+ rainbow (>= 2.2.2, < 4.0)
56
+ regexp_parser (>= 1.8)
57
+ rexml
58
+ rubocop-ast (>= 0.6.0)
50
59
  ruby-progressbar (~> 1.7)
51
- unicode-display_width (~> 1.0, >= 1.0.1)
52
- ruby-progressbar (1.8.1)
53
- ruby2_keywords (0.0.2)
60
+ unicode-display_width (>= 1.4.0, < 2.0)
61
+ rubocop-ast (1.4.0)
62
+ parser (>= 2.7.1.5)
63
+ ruby-progressbar (1.11.0)
64
+ ruby2_keywords (0.0.4)
54
65
  sidekiq (5.2.9)
55
66
  connection_pool (~> 2.2, >= 2.2.2)
56
67
  rack (~> 2.0)
@@ -62,7 +73,7 @@ GEM
62
73
  rack-protection (= 2.0.8.1)
63
74
  tilt (~> 2.0)
64
75
  tilt (2.0.10)
65
- unicode-display_width (1.6.0)
76
+ unicode-display_width (1.7.0)
66
77
 
67
78
  PLATFORMS
68
79
  ruby
@@ -74,4 +85,4 @@ DEPENDENCIES
74
85
  rubocop (~> 0.42)
75
86
 
76
87
  BUNDLED WITH
77
- 1.17.3
88
+ 2.1.4
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
3
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
4
4
 
5
+ require "rubygems"
6
+ require "bundler/setup"
5
7
  require "optparse"
6
8
  require "gitlab_exporter"
7
9
 
@@ -6,6 +6,7 @@ db_common: &db_common
6
6
 
7
7
  # Web server config
8
8
  server:
9
+ name: puma # cf. https://github.com/sinatra/sinatra#available-settings
9
10
  listen_address: 0.0.0.0
10
11
  listen_port: 9168
11
12
  # Maximum amount of memory to use in megabytes, after which the process is killed
@@ -94,12 +95,21 @@ probes:
94
95
  redis_url: "redis://localhost:6379"
95
96
  redis_enable_client: true
96
97
 
98
+ ruby: &ruby
99
+ class_name: RubyProber
100
+ methods:
101
+ - probe_gc
102
+ opts:
103
+ quantiles: false
104
+
97
105
  metrics:
98
106
  multiple: true
99
107
  git_process:
100
108
  <<: *git_process
101
109
  process:
102
110
  <<: *process
111
+ ruby:
112
+ <<: *ruby
103
113
  sidekiq:
104
114
  <<: *sidekiq
105
115
  ci_builds:
@@ -1,4 +1,4 @@
1
- lib = File.expand_path("../lib", __FILE__)
1
+ lib = File.expand_path("lib", __dir__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
  require "gitlab_exporter/version"
4
4
 
@@ -20,13 +20,14 @@ Gem::Specification.new do |s|
20
20
  s.homepage = "http://gitlab.com"
21
21
  s.license = "MIT"
22
22
 
23
+ s.add_runtime_dependency "connection_pool", "~> 2.2.1"
23
24
  s.add_runtime_dependency "pg", "~> 1.1"
24
- s.add_runtime_dependency "sinatra", "~> 2.0.4"
25
+ s.add_runtime_dependency "puma", "~> 5.1.1"
25
26
  s.add_runtime_dependency "quantile", "~> 0.2.0"
26
- s.add_runtime_dependency "sidekiq", "~> 5.2.1"
27
27
  s.add_runtime_dependency "redis", "~> 4.1.2"
28
28
  s.add_runtime_dependency "redis-namespace", "~> 1.6.0"
29
- s.add_runtime_dependency "connection_pool", "~> 2.2.1"
29
+ s.add_runtime_dependency "sidekiq", "~> 5.2.1"
30
+ s.add_runtime_dependency "sinatra", "~> 2.0.4"
30
31
 
31
32
  s.add_development_dependency "rspec", "~> 3.7.0"
32
33
  s.add_development_dependency "rspec-expectations", "~> 3.7.0"
@@ -14,5 +14,6 @@ module GitLab
14
14
  autoload :WebExporter, "gitlab_exporter/web_exporter"
15
15
  autoload :Prober, "gitlab_exporter/prober"
16
16
  autoload :SidekiqProber, "gitlab_exporter/sidekiq"
17
+ autoload :RubyProber, "gitlab_exporter/ruby"
17
18
  end
18
19
  end
@@ -19,8 +19,7 @@ module GitLab
19
19
  # Empty runner that will raise an InvalidCLICommand when executed to provide the usage
20
20
  # in the exception message
21
21
  class NullRunner
22
- def initialize(args)
23
- end
22
+ def initialize(args); end
24
23
 
25
24
  def run
26
25
  fail InvalidCLICommand.new("Usage: #{EXECUTABLE_NAME} <command> [options] [arguments...]\n\n"\
@@ -8,14 +8,39 @@ module GitLab
8
8
  #
9
9
  # It takes a connection string (e.g. "dbname=test port=5432")
10
10
  class Base
11
+ POOL_SIZE = 3
12
+
13
+ # This timeout is configured to higher interval than scrapping
14
+ # of Prometheus to ensure that connection is kept instead of
15
+ # needed to be re-initialized
16
+ POOL_TIMEOUT = 90
17
+
11
18
  def self.connection_pool
12
- @connection_pool ||= Hash.new do |h, connection_string|
13
- h[connection_string] = ConnectionPool.new(size: 3, timeout: 5) do
14
- PG.connect(connection_string)
19
+ @@connection_pool ||= Hash.new do |h, connection_string| # rubocop:disable Style/ClassVars
20
+ h[connection_string] = ConnectionPool.new(size: POOL_SIZE, timeout: POOL_TIMEOUT) do
21
+ PG.connect(connection_string).tap do |conn|
22
+ configure_type_map_for_results(conn)
23
+ end
15
24
  end
16
25
  end
17
26
  end
18
27
 
28
+ def self.configure_type_map_for_results(conn)
29
+ tm = PG::BasicTypeMapForResults.new(conn)
30
+
31
+ # Remove warning message:
32
+ # Warning: no type cast defined for type "name" with oid 19.
33
+ # Please cast this type explicitly to TEXT to be safe for future changes.
34
+ # Warning: no type cast defined for type "regproc" with oid 24.
35
+ # Please cast this type explicitly to TEXT to be safe for future changes.
36
+ [{ "type": "text", "oid": 19 }, { "type": "int4", "oid": 24 }].each do |value|
37
+ old_coder = tm.coders.find { |c| c.name == value[:type] }
38
+ tm.add_coder(old_coder.dup.tap { |c| c.oid = value[:oid] })
39
+ end
40
+
41
+ conn.type_map_for_results = tm
42
+ end
43
+
19
44
  def initialize(args, logger: nil)
20
45
  @connection_string = args[:connection_string]
21
46
  @logger = logger
@@ -31,13 +56,11 @@ module GitLab
31
56
 
32
57
  def with_connection_pool
33
58
  connection_pool.with do |conn|
34
- begin
35
- yield conn
36
- rescue PG::UnableToSend => e
37
- @logger.warn "Error sending to the database: #{e}" if @logger
38
- conn.reset
39
- raise e
40
- end
59
+ yield conn
60
+ rescue PG::UnableToSend => e
61
+ @logger.warn "Error sending to the database: #{e}" if @logger
62
+ conn.reset
63
+ raise e
41
64
  end
42
65
  rescue PG::Error => e
43
66
  @logger.error "Error connecting to the database: #{e}" if @logger
@@ -35,7 +35,7 @@ module GitLab
35
35
 
36
36
  # Prober class to gather bloat metrics
37
37
  class BloatProber
38
- METRIC_KEYS = %w(bloat_ratio bloat_size extra_size real_size).freeze
38
+ METRIC_KEYS = %w[bloat_ratio bloat_size extra_size real_size].freeze
39
39
 
40
40
  attr_reader :metrics, :collector, :bloat_types
41
41
 
@@ -46,7 +46,7 @@ module GitLab
46
46
  @metrics = metrics
47
47
  @collector = collector
48
48
  @collector.logger = logger
49
- @bloat_types = opts[:bloat_types] || %i(btree table)
49
+ @bloat_types = opts[:bloat_types] || %i[btree table]
50
50
  end
51
51
 
52
52
  def probe_db
@@ -12,73 +12,90 @@ SELECT current_database(), nspname AS schemaname, tblname, idxname AS object_nam
12
12
  END AS bloat_size,
13
13
  100 * (relpages-est_pages_ff)::float / relpages AS bloat_ratio,
14
14
  is_na
15
- -- , 100-(sub.pst).avg_leaf_density, est_pages, index_tuple_hdr_bm, maxalign, pagehdr, nulldatawidth, nulldatahdrwidth, sub.reltuples, sub.relpages -- (DEBUG INFO)
15
+ -- , 100-(pst).avg_leaf_density AS pst_avg_bloat, est_pages, index_tuple_hdr_bm, maxalign, pagehdr, nulldatawidth, nulldatahdrwidth, reltuples, relpages -- (DEBUG INFO)
16
16
  FROM (
17
17
  SELECT coalesce(1 +
18
- ceil(reltuples/floor((bs-pageopqdata-pagehdr)/(4+nulldatahdrwidth)::float)), 0 -- ItemIdData size + computed avg size of a tuple (nulldatahdrwidth)
19
- ) AS est_pages,
20
- coalesce(1 +
21
- ceil(reltuples/floor((bs-pageopqdata-pagehdr)*fillfactor/(100*(4+nulldatahdrwidth)::float))), 0
22
- ) AS est_pages_ff,
23
- bs, nspname, table_oid, tblname, idxname, relpages, fillfactor, is_na
24
- -- , stattuple.pgstatindex(quote_ident(nspname)||'.'||quote_ident(idxname)) AS pst, index_tuple_hdr_bm, maxalign, pagehdr, nulldatawidth, nulldatahdrwidth, reltuples -- (DEBUG INFO)
18
+ ceil(reltuples/floor((bs-pageopqdata-pagehdr)/(4+nulldatahdrwidth)::float)), 0 -- ItemIdData size + computed avg size of a tuple (nulldatahdrwidth)
19
+ ) AS est_pages,
20
+ coalesce(1 +
21
+ ceil(reltuples/floor((bs-pageopqdata-pagehdr)*fillfactor/(100*(4+nulldatahdrwidth)::float))), 0
22
+ ) AS est_pages_ff,
23
+ bs, nspname, tblname, idxname, relpages, fillfactor, is_na
24
+ -- , pgstatindex(idxoid) AS pst, index_tuple_hdr_bm, maxalign, pagehdr, nulldatawidth, nulldatahdrwidth, reltuples -- (DEBUG INFO)
25
25
  FROM (
26
- SELECT maxalign, bs, nspname, tblname, idxname, reltuples, relpages, relam, table_oid, fillfactor,
27
- ( index_tuple_hdr_bm +
28
- maxalign - CASE -- Add padding to the index tuple header to align on MAXALIGN
29
- WHEN index_tuple_hdr_bm%maxalign = 0 THEN maxalign
30
- ELSE index_tuple_hdr_bm%maxalign
31
- END
32
- + nulldatawidth + maxalign - CASE -- Add padding to the data to align on MAXALIGN
33
- WHEN nulldatawidth = 0 THEN 0
34
- WHEN nulldatawidth::integer%maxalign = 0 THEN maxalign
35
- ELSE nulldatawidth::integer%maxalign
36
- END
37
- )::numeric AS nulldatahdrwidth, pagehdr, pageopqdata, is_na
38
- -- , index_tuple_hdr_bm, nulldatawidth -- (DEBUG INFO)
39
- FROM (
40
- SELECT
41
- i.nspname, i.tblname, i.idxname, i.reltuples, i.relpages, i.relam, a.attrelid AS table_oid,
42
- current_setting('block_size')::numeric AS bs, fillfactor,
43
- CASE -- MAXALIGN: 4 on 32bits, 8 on 64bits (and mingw32 ?)
44
- WHEN version() ~ 'mingw32' OR version() ~ '64-bit|x86_64|ppc64|ia64|amd64' THEN 8
45
- ELSE 4
46
- END AS maxalign,
47
- /* per page header, fixed size: 20 for 7.X, 24 for others */
48
- 24 AS pagehdr,
49
- /* per page btree opaque data */
50
- 16 AS pageopqdata,
51
- /* per tuple header: add IndexAttributeBitMapData if some cols are null-able */
52
- CASE WHEN max(coalesce(s.null_frac,0)) = 0
53
- THEN 2 -- IndexTupleData size
54
- ELSE 2 + (( 32 + 8 - 1 ) / 8) -- IndexTupleData size + IndexAttributeBitMapData size ( max num filed per index + 8 - 1 /8)
55
- END AS index_tuple_hdr_bm,
56
- /* data len: we remove null values save space using it fractionnal part from stats */
57
- sum( (1-coalesce(s.null_frac, 0)) * coalesce(s.avg_width, 1024)) AS nulldatawidth,
58
- max( CASE WHEN a.atttypid = 'pg_catalog.name'::regtype THEN 1 ELSE 0 END ) > 0 AS is_na
59
- FROM pg_attribute AS a
60
- JOIN (
61
- SELECT nspname, tbl.relname AS tblname, idx.relname AS idxname, idx.reltuples, idx.relpages, idx.relam,
62
- indrelid, indexrelid, indkey::smallint[] AS attnum,
63
- coalesce(substring(
64
- array_to_string(idx.reloptions, ' ')
65
- from 'fillfactor=([0-9]+)')::smallint, 90) AS fillfactor
66
- FROM pg_index
67
- JOIN pg_class idx ON idx.oid=pg_index.indexrelid
68
- JOIN pg_class tbl ON tbl.oid=pg_index.indrelid
69
- JOIN pg_namespace ON pg_namespace.oid = idx.relnamespace
70
- WHERE pg_index.indisvalid AND tbl.relkind = 'r' AND idx.relpages > 0
71
- ) AS i ON a.attrelid = i.indexrelid
72
- JOIN pg_stats AS s ON s.schemaname = i.nspname
73
- AND ((s.tablename = i.tblname AND s.attname = pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE)) -- stats from tbl
74
- OR (s.tablename = i.idxname AND s.attname = a.attname))-- stats from functionnal cols
75
- JOIN pg_type AS t ON a.atttypid = t.oid
76
- WHERE a.attnum > 0
77
- GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9
78
- ) AS s1
79
- ) AS s2
80
- JOIN pg_am am ON s2.relam = am.oid WHERE am.amname = 'btree'
81
- ) AS sub
82
- WHERE NOT is_na
83
- AND nspname = 'public'
84
- ORDER BY 2,3,4;
26
+ SELECT maxalign, bs, nspname, tblname, idxname, reltuples, relpages, idxoid, fillfactor,
27
+ ( index_tuple_hdr_bm +
28
+ maxalign - CASE -- Add padding to the index tuple header to align on MAXALIGN
29
+ WHEN index_tuple_hdr_bm%maxalign = 0 THEN maxalign
30
+ ELSE index_tuple_hdr_bm%maxalign
31
+ END
32
+ + nulldatawidth + maxalign - CASE -- Add padding to the data to align on MAXALIGN
33
+ WHEN nulldatawidth = 0 THEN 0
34
+ WHEN nulldatawidth::integer%maxalign = 0 THEN maxalign
35
+ ELSE nulldatawidth::integer%maxalign
36
+ END
37
+ )::numeric AS nulldatahdrwidth, pagehdr, pageopqdata, is_na
38
+ -- , index_tuple_hdr_bm, nulldatawidth -- (DEBUG INFO)
39
+ FROM (
40
+ SELECT n.nspname, i.tblname, i.idxname, i.reltuples, i.relpages,
41
+ i.idxoid, i.fillfactor, current_setting('block_size')::numeric AS bs,
42
+ CASE -- MAXALIGN: 4 on 32bits, 8 on 64bits (and mingw32 ?)
43
+ WHEN version() ~ 'mingw32' OR version() ~ '64-bit|x86_64|ppc64|ia64|amd64' THEN 8
44
+ ELSE 4
45
+ END AS maxalign,
46
+ /* per page header, fixed size: 20 for 7.X, 24 for others */
47
+ 24 AS pagehdr,
48
+ /* per page btree opaque data */
49
+ 16 AS pageopqdata,
50
+ /* per tuple header: add IndexAttributeBitMapData if some cols are null-able */
51
+ CASE WHEN max(coalesce(s.null_frac,0)) = 0
52
+ THEN 2 -- IndexTupleData size
53
+ ELSE 2 + (( 32 + 8 - 1 ) / 8) -- IndexTupleData size + IndexAttributeBitMapData size ( max num filed per index + 8 - 1 /8)
54
+ END AS index_tuple_hdr_bm,
55
+ /* data len: we remove null values save space using it fractionnal part from stats */
56
+ sum( (1-coalesce(s.null_frac, 0)) * coalesce(s.avg_width, 1024)) AS nulldatawidth,
57
+ max( CASE WHEN i.atttypid = 'pg_catalog.name'::regtype THEN 1 ELSE 0 END ) > 0 AS is_na
58
+ FROM (
59
+ 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,
60
+ coalesce(a1.attnum, a2.attnum) AS attnum, coalesce(a1.attname, a2.attname) AS attname, coalesce(a1.atttypid, a2.atttypid) AS atttypid,
61
+ CASE WHEN a1.attnum IS NULL
62
+ THEN ic.idxname
63
+ ELSE ct.relname
64
+ END AS attrelname
65
+ FROM (
66
+ SELECT idxname, reltuples, relpages, tbloid, idxoid, fillfactor, indkey,
67
+ pg_catalog.generate_series(1,indnatts) AS attpos
68
+ FROM (
69
+ SELECT ci.relname AS idxname, ci.reltuples, ci.relpages, i.indrelid AS tbloid,
70
+ i.indexrelid AS idxoid,
71
+ coalesce(substring(
72
+ array_to_string(ci.reloptions, ' ')
73
+ from 'fillfactor=([0-9]+)')::smallint, 90) AS fillfactor,
74
+ i.indnatts,
75
+ pg_catalog.string_to_array(pg_catalog.textin(
76
+ pg_catalog.int2vectorout(i.indkey)),' ')::int[] AS indkey
77
+ FROM pg_catalog.pg_index i
78
+ JOIN pg_catalog.pg_class ci ON ci.oid = i.indexrelid
79
+ WHERE ci.relam=(SELECT oid FROM pg_am WHERE amname = 'btree')
80
+ AND ci.relpages > 0
81
+ ) AS idx_data
82
+ ) AS ic
83
+ JOIN pg_catalog.pg_class ct ON ct.oid = ic.tbloid
84
+ LEFT JOIN pg_catalog.pg_attribute a1 ON
85
+ ic.indkey[ic.attpos] <> 0
86
+ AND a1.attrelid = ic.tbloid
87
+ AND a1.attnum = ic.indkey[ic.attpos]
88
+ LEFT JOIN pg_catalog.pg_attribute a2 ON
89
+ ic.indkey[ic.attpos] = 0
90
+ AND a2.attrelid = ic.idxoid
91
+ AND a2.attnum = ic.attpos
92
+ ) i
93
+ JOIN pg_catalog.pg_namespace n ON n.oid = i.relnamespace
94
+ JOIN pg_catalog.pg_stats s ON s.schemaname = n.nspname
95
+ AND s.tablename = i.attrelname
96
+ AND s.attname = i.attname
97
+ GROUP BY 1,2,3,4,5,6,7,8,9,10,11
98
+ ) AS rows_data_stats
99
+ ) AS rows_hdr_pdg_stats
100
+ ) AS relation_stats
101
+ ORDER BY nspname, tblname, idxname;