innodb_ruby 0.9.16 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +5 -6
- data/bin/innodb_log +13 -18
- data/bin/innodb_space +377 -757
- data/lib/innodb.rb +4 -5
- data/lib/innodb/checksum.rb +26 -24
- data/lib/innodb/data_dictionary.rb +490 -550
- data/lib/innodb/data_type.rb +362 -326
- data/lib/innodb/field.rb +102 -89
- data/lib/innodb/fseg_entry.rb +22 -26
- data/lib/innodb/history.rb +21 -21
- data/lib/innodb/history_list.rb +72 -76
- data/lib/innodb/ibuf_bitmap.rb +36 -36
- data/lib/innodb/ibuf_index.rb +6 -2
- data/lib/innodb/index.rb +245 -276
- data/lib/innodb/inode.rb +154 -155
- data/lib/innodb/list.rb +191 -183
- data/lib/innodb/log.rb +139 -110
- data/lib/innodb/log_block.rb +100 -91
- data/lib/innodb/log_group.rb +53 -64
- data/lib/innodb/log_reader.rb +97 -96
- data/lib/innodb/log_record.rb +328 -279
- data/lib/innodb/lsn.rb +86 -81
- data/lib/innodb/page.rb +417 -414
- data/lib/innodb/page/blob.rb +82 -83
- data/lib/innodb/page/fsp_hdr_xdes.rb +174 -165
- data/lib/innodb/page/ibuf_bitmap.rb +34 -34
- data/lib/innodb/page/index.rb +964 -943
- data/lib/innodb/page/index_compressed.rb +34 -34
- data/lib/innodb/page/inode.rb +103 -112
- data/lib/innodb/page/sys.rb +13 -15
- data/lib/innodb/page/sys_data_dictionary_header.rb +81 -59
- data/lib/innodb/page/sys_ibuf_header.rb +45 -42
- data/lib/innodb/page/sys_rseg_header.rb +88 -82
- data/lib/innodb/page/trx_sys.rb +204 -182
- data/lib/innodb/page/undo_log.rb +106 -92
- data/lib/innodb/record.rb +121 -160
- data/lib/innodb/record_describer.rb +66 -68
- data/lib/innodb/space.rb +380 -418
- data/lib/innodb/stats.rb +33 -35
- data/lib/innodb/system.rb +149 -171
- data/lib/innodb/undo_log.rb +129 -107
- data/lib/innodb/undo_record.rb +255 -247
- data/lib/innodb/util/buffer_cursor.rb +81 -79
- data/lib/innodb/util/read_bits_at_offset.rb +2 -1
- data/lib/innodb/version.rb +2 -2
- data/lib/innodb/xdes.rb +144 -142
- metadata +80 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 21b726dd85c361262f577f663a70b008acb56f45fc2a1632147bc94eb622141e
|
4
|
+
data.tar.gz: 720eda759132e67b03c8bcd9c0e50a90625f3de214048e870875cb964bdd8bbe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1814840cf61fd850140e282ea2706c196563881e4de69e6612e890b8dcd6e9b93cd4dbc73c61d8c02fbc071c3e339223eea4d0af636ef00a4505ab1f143e207e
|
7
|
+
data.tar.gz: 85b0326cc2b029ab24a493e1b781e4f9239533bff9b1849e67a4672493ce9775006a08004ce1a4d9aa724b0324354c67465cfcdfa3a722032c7c34f90822c6c1
|
data/README.md
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
# A parser for InnoDB file formats, in Ruby
|
1
|
+
# A parser for InnoDB file formats, in Ruby
|
2
|
+
|
3
|
+
[![rspec test status](https://github.com/jeremycole/innodb_ruby/actions/workflows/rspec.yml/badge.svg)](https://github.com/jeremycole/innodb_ruby/actions/workflows/rspec.yml)
|
4
|
+
[![rubocop style check status](https://github.com/jeremycole/innodb_ruby/actions/workflows/rubocop.yml/badge.svg)](https://github.com/jeremycole/innodb_ruby/actions/workflows/rubocop.yml)
|
2
5
|
|
3
6
|
The purpose for this library and tools is to expose some otherwise hidden internals of InnoDB. This code is not intended for critical production usage. It is definitely buggy, and it may be dangerous. Neither its internal APIs or its output are considered stable and are subject to change at any time.
|
4
7
|
|
@@ -11,11 +14,7 @@ It is intended as for a few purposes:
|
|
11
14
|
|
12
15
|
Various parts of this library and the tools included may have wildly differing maturity levels, as it is worked on primarily based on immediate needs of the authors.
|
13
16
|
|
14
|
-
# Resources
|
17
|
+
# Resources
|
15
18
|
|
16
19
|
* The [innodb_ruby wiki](https://github.com/jeremycole/innodb_ruby/wiki) contains some additional references and documentation to help you get started.
|
17
|
-
* Visit the [innodb_ruby mailing list on Google Groups](https://groups.google.com/d/forum/innodb_ruby) or email [innodb_ruby@googlegroups.com](mailto:innodb_ruby@googlegroups.com) — If you have questions about `innodb_ruby` or its usage.
|
18
20
|
* See the [RubyGems page for innodb_ruby](http://rubygems.org/gems/innodb_ruby) — Gem packaged releases are published regularly to RubyGems.org, which also provides online documentation.
|
19
|
-
|
20
|
-
|
21
|
-
[![Build Status](https://travis-ci.org/jeremycole/innodb_ruby.svg?branch=master)](https://travis-ci.org/jeremycole/innodb_ruby)
|
data/bin/innodb_log
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
#
|
2
|
+
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "getoptlong"
|
5
5
|
require "ostruct"
|
@@ -7,15 +7,9 @@ require "set"
|
|
7
7
|
require "innodb"
|
8
8
|
|
9
9
|
def log_summary(log_group)
|
10
|
-
puts "%-20s%-15s%-10s%-12s%-10s" % [
|
11
|
-
"lsn",
|
12
|
-
"block",
|
13
|
-
"length",
|
14
|
-
"first_rec",
|
15
|
-
"checkpoint",
|
16
|
-
]
|
10
|
+
puts "%-20s%-15s%-10s%-12s%-10s" % %w[lsn block length first_rec checkpoint]
|
17
11
|
lsn = log_group.start_lsn.first
|
18
|
-
log_group.each_block do |
|
12
|
+
log_group.each_block do |_block_index, block|
|
19
13
|
header = block.header
|
20
14
|
puts "%-20i%-15i%-10i%-12i%-10i" % [
|
21
15
|
lsn,
|
@@ -30,14 +24,7 @@ def log_summary(log_group)
|
|
30
24
|
end
|
31
25
|
|
32
26
|
def log_reader_record_summary(reader, follow)
|
33
|
-
puts "%-10s%-10s%-20s%-10s%-10s%-10s" % [
|
34
|
-
"time",
|
35
|
-
"lsn",
|
36
|
-
"type",
|
37
|
-
"size",
|
38
|
-
"space",
|
39
|
-
"page"
|
40
|
-
]
|
27
|
+
puts "%-10s%-10s%-20s%-10s%-10s%-10s" % %w[time lsn type size space page]
|
41
28
|
|
42
29
|
reader.each_record(follow) do |rec|
|
43
30
|
preamble = rec.preamble.dup
|
@@ -72,6 +59,7 @@ end
|
|
72
59
|
def usage(exit_code, message = nil)
|
73
60
|
print "Error: #{message}\n" unless message.nil?
|
74
61
|
|
62
|
+
# rubocop:disable Layout/HeredocIndentation
|
75
63
|
print <<'END_OF_USAGE'
|
76
64
|
|
77
65
|
Usage: innodb_log [-d] [-l <lsn>] -f <log file> <mode>
|
@@ -103,6 +91,7 @@ The following modes are supported:
|
|
103
91
|
Dump the contents of a log record, using the Ruby pp ("pretty-print") module.
|
104
92
|
|
105
93
|
END_OF_USAGE
|
94
|
+
# rubocop:enable Layout/HeredocIndentation
|
106
95
|
|
107
96
|
exit exit_code
|
108
97
|
end
|
@@ -112,12 +101,14 @@ end
|
|
112
101
|
@options.dump = false
|
113
102
|
@options.lsn = nil
|
114
103
|
|
104
|
+
# rubocop:disable Layout/SpaceInsideArrayLiteralBrackets
|
115
105
|
getopt_options = [
|
116
106
|
[ "--help", "-?", GetoptLong::NO_ARGUMENT ],
|
117
107
|
[ "--log-file", "-f", GetoptLong::REQUIRED_ARGUMENT ],
|
118
108
|
[ "--dump-blocks", "-d", GetoptLong::NO_ARGUMENT ],
|
119
109
|
[ "--lsn", "-l", GetoptLong::REQUIRED_ARGUMENT ],
|
120
110
|
]
|
111
|
+
# rubocop:enable Layout/SpaceInsideArrayLiteralBrackets
|
121
112
|
|
122
113
|
getopt = GetoptLong.new(*getopt_options)
|
123
114
|
|
@@ -136,6 +127,8 @@ end
|
|
136
127
|
|
137
128
|
mode = ARGV.shift
|
138
129
|
|
130
|
+
# rubocop:disable Style/IfUnlessModifier
|
131
|
+
|
139
132
|
unless mode
|
140
133
|
usage 1, "At least one mode must be provided"
|
141
134
|
end
|
@@ -144,10 +137,12 @@ if @options.log_files.empty?
|
|
144
137
|
usage 1, "At least one log file (-f) must be specified"
|
145
138
|
end
|
146
139
|
|
147
|
-
if /^(log-)?record-/.match(mode)
|
140
|
+
if /^(log-)?record-/.match(mode) && !@options.lsn
|
148
141
|
usage 1, "LSN must be specified using -l/--lsn"
|
149
142
|
end
|
150
143
|
|
144
|
+
# rubocop:enable Style/IfUnlessModifier
|
145
|
+
|
151
146
|
log_group = Innodb::LogGroup.new(@options.log_files.sort)
|
152
147
|
|
153
148
|
case mode
|
data/bin/innodb_space
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
#
|
2
|
+
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "getoptlong"
|
5
5
|
require "ostruct"
|
6
|
+
require "histogram/array"
|
6
7
|
require "innodb"
|
7
8
|
|
8
9
|
# Convert a floating point RGB array into an ANSI color number approximating it.
|
@@ -11,17 +12,13 @@ def rgb_to_ansi(rgb)
|
|
11
12
|
16 + (rgb_n[0] * 36) + (rgb_n[1] * 6) + rgb_n[2]
|
12
13
|
end
|
13
14
|
|
14
|
-
def rgb_to_rgbhex(rgb)
|
15
|
-
rgb.map { |c| "%02x" % [(c * 255.0).round] }.join
|
16
|
-
end
|
17
|
-
|
18
15
|
# Interpolate intermediate float-arrays between two float-arrays. Do not
|
19
16
|
# include the points a and b in the result.
|
20
|
-
def interpolate(
|
21
|
-
deltas =
|
22
|
-
steps =
|
17
|
+
def interpolate(ary_a, ary_b, count)
|
18
|
+
deltas = ary_a.each_index.map { |i| ary_b[i] - ary_a[i] }
|
19
|
+
steps = ary_a.each_index.map { |i| deltas[i].to_f / (count.to_f + 1) }
|
23
20
|
|
24
|
-
count.times.to_a.map { |i|
|
21
|
+
count.times.to_a.map { |i| ary_a.each_index.map { |j| ary_a[j] + ((i + 1).to_f * steps[j]) } }
|
25
22
|
end
|
26
23
|
|
27
24
|
# Interpolate intermediate float-arrays between each step in a sequence of
|
@@ -29,7 +26,7 @@ end
|
|
29
26
|
def interpolate_sequence(sequence, count)
|
30
27
|
result = []
|
31
28
|
result << sequence.first
|
32
|
-
(sequence.size-1).times.map { |n| [sequence[n], sequence[n+1]] }.each do |from, to|
|
29
|
+
(sequence.size - 1).times.map { |n| [sequence[n], sequence[n + 1]] }.each do |from, to|
|
33
30
|
interpolate(from, to, count).each do |step|
|
34
31
|
result << step
|
35
32
|
end
|
@@ -48,15 +45,11 @@ HEATMAP_PROGRESSION = [
|
|
48
45
|
[1.0, 1.0, 0.0], # Yellow
|
49
46
|
[1.0, 0.0, 0.0], # Red
|
50
47
|
[1.0, 0.0, 1.0], # Purple
|
51
|
-
]
|
48
|
+
].freeze
|
52
49
|
|
53
50
|
# Typical heatmap color progression.
|
54
51
|
ANSI_COLORS_HEATMAP = interpolate_sequence(HEATMAP_PROGRESSION, 6).map { |rgb| rgb_to_ansi(rgb) }
|
55
52
|
|
56
|
-
RGBHEX_COLORS_HEATMAP = interpolate_sequence(HEATMAP_PROGRESSION, 41).map { |rgb| rgb_to_rgbhex(rgb) }
|
57
|
-
|
58
|
-
RGBHEX_COLORS_RANDOM = 100.times.inject([]) { |a, x| a << rgb_to_rgbhex([rand * 0.7 + 0.25, rand * 0.7 + 0.25, rand * 0.7 + 0.25]) }
|
59
|
-
|
60
53
|
# The 24-step grayscale progression.
|
61
54
|
ANSI_COLORS_GRAYSCALE = (0xe8..0xff).to_a
|
62
55
|
|
@@ -66,69 +59,47 @@ def ansi_color(color, text)
|
|
66
59
|
end
|
67
60
|
|
68
61
|
# Zero and 1/8 through 8/8 illustrations.
|
69
|
-
BLOCK_CHARS_V =
|
70
|
-
BLOCK_CHARS_H =
|
62
|
+
BLOCK_CHARS_V = "░▁▂▃▄▅▆▇█".chars.freeze
|
63
|
+
BLOCK_CHARS_H = "░▏▎▍▌▋▊▉█".chars.freeze
|
71
64
|
|
72
65
|
# A reasonably large prime number to multiply identifiers by in order to
|
73
66
|
# space out the colors used for similar identifiers.
|
74
|
-
COLOR_SPACING_PRIME =
|
67
|
+
COLOR_SPACING_PRIME = 999_983
|
75
68
|
|
76
69
|
# Return a string with a possibly colored filled block for use in printing
|
77
70
|
# to an ANSI-capable Unicode-enabled terminal.
|
78
|
-
def filled_block(fraction, identifier=nil, block_chars=BLOCK_CHARS_V)
|
79
|
-
if fraction
|
71
|
+
def filled_block(fraction, identifier = nil, block_chars = BLOCK_CHARS_V)
|
72
|
+
if fraction.zero?
|
80
73
|
block = block_chars[0]
|
81
74
|
else
|
82
|
-
parts = (fraction.to_f * (block_chars.size.to_f-1)).floor
|
83
|
-
block = block_chars[[block_chars.size-1, parts+1].min]
|
75
|
+
parts = (fraction.to_f * (block_chars.size.to_f - 1)).floor
|
76
|
+
block = block_chars[[block_chars.size - 1, parts + 1].min]
|
84
77
|
end
|
85
78
|
if identifier
|
86
79
|
# ANSI 256-color mode, color palette starts at 10 and contains 216 colors.
|
87
|
-
color = 16 + ((identifier * COLOR_SPACING_PRIME)
|
80
|
+
color = 16 + ((identifier * COLOR_SPACING_PRIME) % 216)
|
88
81
|
ansi_color(color, block)
|
89
82
|
else
|
90
83
|
block
|
91
84
|
end
|
92
85
|
end
|
93
86
|
|
94
|
-
def
|
95
|
-
|
96
|
-
end
|
87
|
+
def center(text, width)
|
88
|
+
return text if text.size >= width
|
97
89
|
|
98
|
-
|
99
|
-
|
100
|
-
"<" + elem.to_s + " " + svg_join_args(args) + ">" +
|
101
|
-
content.to_s +
|
102
|
-
"</" + elem.to_s + ">"
|
103
|
-
else
|
104
|
-
"<" + elem.to_s + " " + svg_join_args(args) + " />"
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def svg_path_rounded_rect(x, y, w, h, r)
|
109
|
-
[
|
110
|
-
"M%i,%i" % [ x + r, y - r ],
|
111
|
-
"L%i,%i" % [ x + w - r, y - r ],
|
112
|
-
"S%i,%i %i,%i" % [ x + w + r, y - r, x + w + r, y + r ],
|
113
|
-
"L%i,%i" % [ x + w + r, y + h - r ],
|
114
|
-
"S%i,%i %i,%i" % [ x + w + r, y + h + r, x + w - r, y + h + r ],
|
115
|
-
"L%i,%i" % [ x + r, y + h + r ],
|
116
|
-
"S%i,%i %i,%i" % [ x - r, y + h + r, x - r, y + h - r ],
|
117
|
-
"L%i,%i" % [ x - r, y + r ],
|
118
|
-
"S%i,%i %i,%i" % [ x - r, y - r, x + r, y - r ],
|
119
|
-
"Z",
|
120
|
-
].join(" ")
|
90
|
+
spaces = (width - text.size) / 2
|
91
|
+
(" " * spaces) + text + (" " * spaces)
|
121
92
|
end
|
122
93
|
|
123
94
|
# Print metadata about each list in an array of InnoDB::List objects.
|
124
95
|
def print_lists(lists)
|
125
|
-
puts "%-20s%-12s%-12s%-12s%-12s%-12s" % [
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
96
|
+
puts "%-20s%-12s%-12s%-12s%-12s%-12s" % %w[
|
97
|
+
name
|
98
|
+
length
|
99
|
+
f_page
|
100
|
+
f_offset
|
101
|
+
l_page
|
102
|
+
l_offset
|
132
103
|
]
|
133
104
|
|
134
105
|
lists.each do |name, list|
|
@@ -146,33 +117,31 @@ end
|
|
146
117
|
# Print a page usage bitmap for each extent descriptor in an array of
|
147
118
|
# Innodb::XdesEntry objects.
|
148
119
|
def print_xdes_list(space, list)
|
149
|
-
puts "%-12s%-64s" % [
|
150
|
-
|
151
|
-
|
120
|
+
puts "%-12s%-64s" % %w[
|
121
|
+
start_page
|
122
|
+
page_used_bitmap
|
152
123
|
]
|
153
124
|
|
154
125
|
list.each do |entry|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
},
|
163
|
-
]
|
126
|
+
display = entry.each_page_status.inject("") do |bitmap, (page_number, page_status)|
|
127
|
+
if page_number < space.pages
|
128
|
+
bitmap += page_status[:free] ? "." : "#"
|
129
|
+
end
|
130
|
+
bitmap
|
131
|
+
end
|
132
|
+
puts "%-12i%-64s" % [entry.xdes[:start_page], display]
|
164
133
|
end
|
165
134
|
end
|
166
135
|
|
167
136
|
# Print a summary of page usage for all pages in an index.
|
168
137
|
def print_index_page_summary(pages)
|
169
|
-
puts "%-12s%-8s%-8s%-8s%-8s%-8s" % [
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
138
|
+
puts "%-12s%-8s%-8s%-8s%-8s%-8s" % %w[
|
139
|
+
page
|
140
|
+
index
|
141
|
+
level
|
142
|
+
data
|
143
|
+
free
|
144
|
+
records
|
176
145
|
]
|
177
146
|
|
178
147
|
pages.each do |page_number, page|
|
@@ -187,17 +156,17 @@ def print_index_page_summary(pages)
|
|
187
156
|
page.records,
|
188
157
|
]
|
189
158
|
when :ALLOCATED
|
190
|
-
puts "%-12i%-8i%-8i%-8i%-8i%-8i" % [
|
159
|
+
puts "%-12i%-8i%-8i%-8i%-8i%-8i" % [page_number, 0, 0, 0, page.size, 0]
|
191
160
|
end
|
192
161
|
end
|
193
162
|
end
|
194
163
|
|
195
164
|
# Print a summary of all spaces in the InnoDB system.
|
196
165
|
def system_spaces(innodb_system)
|
197
|
-
puts "%-32s%-12s%-12s" % [
|
198
|
-
|
199
|
-
|
200
|
-
|
166
|
+
puts "%-32s%-12s%-12s" % %w[
|
167
|
+
name
|
168
|
+
pages
|
169
|
+
indexes
|
201
170
|
]
|
202
171
|
|
203
172
|
print_space_information = lambda do |name, space|
|
@@ -213,6 +182,7 @@ def system_spaces(innodb_system)
|
|
213
182
|
innodb_system.each_table_name do |table_name|
|
214
183
|
space = innodb_system.space_by_table_name(table_name)
|
215
184
|
next unless space
|
185
|
+
|
216
186
|
print_space_information.call(table_name, space)
|
217
187
|
end
|
218
188
|
|
@@ -223,15 +193,15 @@ end
|
|
223
193
|
|
224
194
|
# Print the contents of the SYS_TABLES data dictionary table.
|
225
195
|
def data_dictionary_tables(innodb_system)
|
226
|
-
puts "%-32s%-12s%-12s%-12s%-12s%-12s%-15s%-12s" % [
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
196
|
+
puts "%-32s%-12s%-12s%-12s%-12s%-12s%-15s%-12s" % %w[
|
197
|
+
name
|
198
|
+
id
|
199
|
+
n_cols
|
200
|
+
type
|
201
|
+
mix_id
|
202
|
+
mix_len
|
203
|
+
cluster_name
|
204
|
+
space
|
235
205
|
]
|
236
206
|
|
237
207
|
innodb_system.data_dictionary.each_table do |record|
|
@@ -250,14 +220,14 @@ end
|
|
250
220
|
|
251
221
|
# Print the contents of the SYS_COLUMNS data dictionary table.
|
252
222
|
def data_dictionary_columns(innodb_system)
|
253
|
-
puts "%-12s%-6s%-32s%-12s%-12s%-6s%-6s" % [
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
223
|
+
puts "%-12s%-6s%-32s%-12s%-12s%-6s%-6s" % %w[
|
224
|
+
table_id
|
225
|
+
pos
|
226
|
+
name
|
227
|
+
mtype
|
228
|
+
prtype
|
229
|
+
len
|
230
|
+
prec
|
261
231
|
]
|
262
232
|
|
263
233
|
innodb_system.data_dictionary.each_column do |record|
|
@@ -275,14 +245,14 @@ end
|
|
275
245
|
|
276
246
|
# Print the contents of the SYS_INDEXES data dictionary table.
|
277
247
|
def data_dictionary_indexes(innodb_system)
|
278
|
-
puts "%-12s%-12s%-32s%-10s%-6s%-12s%-12s" % [
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
248
|
+
puts "%-12s%-12s%-32s%-10s%-6s%-12s%-12s" % %w[
|
249
|
+
table_id
|
250
|
+
id
|
251
|
+
name
|
252
|
+
n_fields
|
253
|
+
type
|
254
|
+
space
|
255
|
+
page_no
|
286
256
|
]
|
287
257
|
|
288
258
|
innodb_system.data_dictionary.each_index do |record|
|
@@ -300,10 +270,10 @@ end
|
|
300
270
|
|
301
271
|
# Print the contents of the SYS_FIELDS data dictionary table.
|
302
272
|
def data_dictionary_fields(innodb_system)
|
303
|
-
puts "%-12s%-12s%-32s" % [
|
304
|
-
|
305
|
-
|
306
|
-
|
273
|
+
puts "%-12s%-12s%-32s" % %w[
|
274
|
+
index_id
|
275
|
+
pos
|
276
|
+
col_name
|
307
277
|
]
|
308
278
|
|
309
279
|
innodb_system.data_dictionary.each_field do |record|
|
@@ -316,12 +286,12 @@ def data_dictionary_fields(innodb_system)
|
|
316
286
|
end
|
317
287
|
|
318
288
|
def space_summary(space, start_page)
|
319
|
-
puts "%-12s%-20s%-12s%-12s%-20s" % [
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
289
|
+
puts "%-12s%-20s%-12s%-12s%-20s" % %w[
|
290
|
+
page
|
291
|
+
type
|
292
|
+
prev
|
293
|
+
next
|
294
|
+
lsn
|
325
295
|
]
|
326
296
|
|
327
297
|
space.each_page(start_page) do |page_number, page|
|
@@ -344,11 +314,11 @@ def space_index_fseg_pages_summary(space, fseg_id)
|
|
344
314
|
end
|
345
315
|
|
346
316
|
def space_page_type_regions(space, start_page)
|
347
|
-
puts "%-12s%-12s%-12s%-20s" % [
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
317
|
+
puts "%-12s%-12s%-12s%-20s" % %w[
|
318
|
+
start
|
319
|
+
end
|
320
|
+
count
|
321
|
+
type
|
352
322
|
]
|
353
323
|
|
354
324
|
space.each_page_type_region(start_page) do |region|
|
@@ -367,16 +337,16 @@ def space_page_type_summary(space, start_page)
|
|
367
337
|
page_count = 0
|
368
338
|
# A Hash of page type => count.
|
369
339
|
page_type = Hash.new(0)
|
370
|
-
space.each_page(start_page) do |
|
340
|
+
space.each_page(start_page) do |_page_number, page|
|
371
341
|
page_count += 1
|
372
342
|
page_type[page.type] += 1
|
373
343
|
end
|
374
344
|
|
375
|
-
puts "%-20s%-12s%-12s%-20s" % [
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
345
|
+
puts "%-20s%-12s%-12s%-20s" % %w[
|
346
|
+
type
|
347
|
+
count
|
348
|
+
percent
|
349
|
+
description
|
380
350
|
]
|
381
351
|
|
382
352
|
# Sort the page type Hash by count, descending.
|
@@ -384,7 +354,7 @@ def space_page_type_summary(space, start_page)
|
|
384
354
|
puts "%-20s%-12i%-12.2f%-20s" % [
|
385
355
|
type,
|
386
356
|
type_count,
|
387
|
-
100.0 * (type_count.to_f / page_count
|
357
|
+
100.0 * (type_count.to_f / page_count),
|
388
358
|
Innodb::Page::PAGE_TYPE[type][:description],
|
389
359
|
]
|
390
360
|
end
|
@@ -397,16 +367,14 @@ end
|
|
397
367
|
def space_list_iterate(space, list_name)
|
398
368
|
fsp = space.page(0).fsp_header
|
399
369
|
|
400
|
-
|
401
|
-
raise "List '#{list_name}' doesn't exist"
|
402
|
-
end
|
370
|
+
raise "List '#{list_name}' doesn't exist" unless fsp[list_name].is_a?(Innodb::List)
|
403
371
|
|
404
372
|
case fsp[list_name]
|
405
373
|
when Innodb::List::Xdes
|
406
374
|
print_xdes_list(space, fsp[list_name])
|
407
375
|
when Innodb::List::Inode
|
408
|
-
puts "%-12s" % [
|
409
|
-
|
376
|
+
puts "%-12s" % %w[
|
377
|
+
page
|
410
378
|
]
|
411
379
|
fsp[list_name].each do |page|
|
412
380
|
puts "%-12i" % [
|
@@ -417,15 +385,15 @@ def space_list_iterate(space, list_name)
|
|
417
385
|
end
|
418
386
|
|
419
387
|
def space_indexes(innodb_system, space)
|
420
|
-
puts "%-12s%-32s%-12s%-12s%-12s%-12s%-12s%-12s" % [
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
388
|
+
puts "%-12s%-32s%-12s%-12s%-12s%-12s%-12s%-12s" % %w[
|
389
|
+
id
|
390
|
+
name
|
391
|
+
root
|
392
|
+
fseg
|
393
|
+
fseg_id
|
394
|
+
used
|
395
|
+
allocated
|
396
|
+
fill_factor
|
429
397
|
]
|
430
398
|
|
431
399
|
space.each_index do |index|
|
@@ -444,17 +412,15 @@ def space_indexes(innodb_system, space)
|
|
444
412
|
end
|
445
413
|
end
|
446
414
|
|
447
|
-
def space_index_pages_free_plot(space,
|
448
|
-
unless require "gnuplot"
|
449
|
-
raise "Couldn't load gnuplot. Is it installed?"
|
450
|
-
end
|
415
|
+
def space_index_pages_free_plot(space, start_page)
|
416
|
+
raise "Could not load gnuplot. Is it installed?" unless require "gnuplot"
|
451
417
|
|
452
|
-
index_data = {0 => {:
|
418
|
+
index_data = { 0 => { x: [], y: [] } }
|
453
419
|
|
454
420
|
space.each_page(start_page) do |page_number, page|
|
455
421
|
case page.type
|
456
422
|
when :INDEX
|
457
|
-
data = (index_data[page.page_header[:index_id]] ||= {:
|
423
|
+
data = (index_data[page.page_header[:index_id]] ||= { x: [], y: [] })
|
458
424
|
data[:x] << page_number
|
459
425
|
data[:y] << page.free_space
|
460
426
|
when :ALLOCATED
|
@@ -463,15 +429,17 @@ def space_index_pages_free_plot(space, image, start_page)
|
|
463
429
|
end
|
464
430
|
end
|
465
431
|
|
466
|
-
|
432
|
+
image_name = space.name.sub(".ibd", "").gsub(/[^a-zA-Z0-9_]/, "_").sub(/\A_+/, "")
|
433
|
+
image_file = "#{image_name}_free.png"
|
434
|
+
|
467
435
|
# Aim for one horizontal pixel per extent, but min 1k and max 10k width.
|
468
|
-
image_width = [
|
436
|
+
image_width = [10_000, [1_000, space.pages / space.pages_per_extent].max].min
|
469
437
|
|
470
438
|
Gnuplot.open do |gp|
|
471
439
|
Gnuplot::Plot.new(gp) do |plot|
|
472
440
|
plot.terminal "png size #{image_width}, 800"
|
473
441
|
plot.output image_file
|
474
|
-
plot.title
|
442
|
+
plot.title image_name.gsub("_", " ")
|
475
443
|
plot.key "reverse left top box horizontal Left textcolor variable"
|
476
444
|
plot.ylabel "free space per page"
|
477
445
|
plot.xlabel "page number"
|
@@ -481,7 +449,7 @@ def space_index_pages_free_plot(space, image, start_page)
|
|
481
449
|
index_data.sort.each do |id, data|
|
482
450
|
plot.data << Gnuplot::DataSet.new([data[:x], data[:y]]) do |ds|
|
483
451
|
ds.with = "dots"
|
484
|
-
ds.title = id
|
452
|
+
ds.title = id.zero? ? "Unallocated" : "Index #{id}"
|
485
453
|
end
|
486
454
|
end
|
487
455
|
|
@@ -494,279 +462,99 @@ def space_extents(space)
|
|
494
462
|
print_xdes_list(space, space.each_xdes)
|
495
463
|
end
|
496
464
|
|
465
|
+
# rubocop:disable Metrics/BlockNesting
|
466
|
+
def space_extents_illustrate_page_status(space, entry, count_by_identifier, identifiers)
|
467
|
+
entry.each_page_status.each_with_object("".dup) do |(page_number, page_status), bitmap|
|
468
|
+
if page_number >= space.pages
|
469
|
+
bitmap << " "
|
470
|
+
next
|
471
|
+
end
|
472
|
+
|
473
|
+
used_fraction = 1.0
|
474
|
+
identifier = nil
|
475
|
+
if page_status[:free]
|
476
|
+
used_fraction = 0.0
|
477
|
+
else
|
478
|
+
page = space.page(page_number)
|
479
|
+
used_fraction = page.used_space.to_f / page.size if page.respond_to?(:used_space)
|
480
|
+
if page.respond_to?(:index_id)
|
481
|
+
identifier = page.index_id
|
482
|
+
unless identifiers[identifier]
|
483
|
+
identifiers[identifier] = page.ibuf_index? ? "Insert Buffer Index" : "Index #{page.index_id}"
|
484
|
+
if space.innodb_system
|
485
|
+
table, index = space.innodb_system.table_and_index_name_by_id(page.index_id)
|
486
|
+
identifiers[identifier] += " (%s.%s)" % [table, index] if table && index
|
487
|
+
end
|
488
|
+
end
|
489
|
+
end
|
490
|
+
end
|
491
|
+
|
492
|
+
bitmap << filled_block(used_fraction, identifier)
|
493
|
+
|
494
|
+
if used_fraction.zero?
|
495
|
+
count_by_identifier[:free] += 1
|
496
|
+
else
|
497
|
+
count_by_identifier[identifier] += 1
|
498
|
+
end
|
499
|
+
end
|
500
|
+
end
|
501
|
+
# rubocop:enable Metrics/BlockNesting
|
502
|
+
|
497
503
|
# Illustrate the space by printing each extent and for each page, printing a
|
498
504
|
# filled block colored based on the index the page is part of. Print a legend
|
499
505
|
# for the colors used afterwards.
|
500
506
|
def space_extents_illustrate(space)
|
501
|
-
|
507
|
+
width = space.pages_per_extent
|
502
508
|
puts
|
503
|
-
puts "%12s
|
509
|
+
puts "%12s %-#{width}s " % ["", center(space.name, width)]
|
510
|
+
puts "%12s ╭%-#{width}s╮" % ["Start Page", "─" * width]
|
504
511
|
|
505
512
|
identifiers = {}
|
506
513
|
count_by_identifier = Hash.new(0)
|
507
514
|
|
508
515
|
space.each_xdes do |entry|
|
509
|
-
puts "%12i │%-#{
|
516
|
+
puts "%12i │%-#{width}s│" % [
|
510
517
|
entry.xdes[:start_page],
|
511
|
-
|
512
|
-
if page_number < space.pages
|
513
|
-
used_fraction = 1.0
|
514
|
-
identifier = nil
|
515
|
-
if page_status[:free]
|
516
|
-
used_fraction = 0.0
|
517
|
-
else
|
518
|
-
page = space.page(page_number)
|
519
|
-
if page.respond_to?(:used_space)
|
520
|
-
used_fraction = page.used_space.to_f / page.size.to_f
|
521
|
-
end
|
522
|
-
if page.respond_to?(:index_id)
|
523
|
-
identifier = page.index_id
|
524
|
-
unless identifiers[identifier]
|
525
|
-
identifiers[identifier] = (page.index_id == Innodb::IbufIndex::INDEX_ID) ?
|
526
|
-
"Insert Buffer Index" :
|
527
|
-
"Index #{page.index_id}"
|
528
|
-
if space.innodb_system
|
529
|
-
table, index = space.innodb_system.table_and_index_name_by_id(page.index_id)
|
530
|
-
if table && index
|
531
|
-
identifiers[identifier] += " (%s.%s)" % [table, index]
|
532
|
-
end
|
533
|
-
end
|
534
|
-
end
|
535
|
-
end
|
536
|
-
end
|
537
|
-
bitmap += filled_block(used_fraction, identifier)
|
538
|
-
if used_fraction != 0.0
|
539
|
-
count_by_identifier[identifier] += 1
|
540
|
-
else
|
541
|
-
count_by_identifier[:free] += 1
|
542
|
-
end
|
543
|
-
else
|
544
|
-
bitmap += " "
|
545
|
-
end
|
546
|
-
bitmap
|
547
|
-
},
|
518
|
+
space_extents_illustrate_page_status(space, entry, count_by_identifier, identifiers),
|
548
519
|
]
|
549
520
|
end
|
550
521
|
total_pages = count_by_identifier.values.reduce(:+)
|
551
522
|
|
552
|
-
puts "%12s ╰%-#{
|
523
|
+
puts "%12s ╰%-#{width}s╯" % ["", "─" * width]
|
553
524
|
|
554
525
|
puts
|
555
526
|
puts "Legend (%s = 1 page):" % [filled_block(1.0, nil)]
|
556
527
|
puts " %-62s %8s %8s" % [
|
557
|
-
"Page Type",
|
528
|
+
"Page Type",
|
529
|
+
"Pages",
|
530
|
+
"Ratio",
|
558
531
|
]
|
559
532
|
puts " %s %-60s %8i %7.2f%%" % [
|
560
533
|
filled_block(1.0, nil),
|
561
534
|
"System",
|
562
535
|
count_by_identifier[nil],
|
563
|
-
100.0 * (count_by_identifier[nil].to_f / total_pages
|
536
|
+
100.0 * (count_by_identifier[nil].to_f / total_pages),
|
564
537
|
]
|
565
538
|
identifiers.sort.each do |identifier, description|
|
566
539
|
puts " %s %-60s %8i %7.2f%%" % [
|
567
540
|
filled_block(1.0, identifier),
|
568
541
|
description,
|
569
542
|
count_by_identifier[identifier],
|
570
|
-
100.0 * (count_by_identifier[identifier].to_f / total_pages
|
543
|
+
100.0 * (count_by_identifier[identifier].to_f / total_pages),
|
571
544
|
]
|
572
545
|
end
|
573
546
|
puts " %s %-60s %8i %7.2f%%" % [
|
574
547
|
filled_block(0.0, nil),
|
575
548
|
"Free space",
|
576
549
|
count_by_identifier[:free],
|
577
|
-
100.0 * (count_by_identifier[:free].to_f / total_pages
|
550
|
+
100.0 * (count_by_identifier[:free].to_f / total_pages),
|
578
551
|
]
|
579
552
|
puts
|
580
553
|
end
|
581
554
|
|
582
|
-
def svg_extent_legend(x, y, block_size, color=nil, description=nil, pages=nil, ratio=nil)
|
583
|
-
[
|
584
|
-
svg("rect", {
|
585
|
-
"y" => y,
|
586
|
-
"x" => x,
|
587
|
-
"width" => block_size,
|
588
|
-
"height" => block_size,
|
589
|
-
"fill" => color ? color : "white",
|
590
|
-
"stroke" => description ? "black" : "none",
|
591
|
-
}),
|
592
|
-
svg("text", {
|
593
|
-
"y" => y + block_size - 4,
|
594
|
-
"x" => x + (description ? block_size + 5 : 0),
|
595
|
-
"font-family" => "monospace",
|
596
|
-
"font-size" => block_size,
|
597
|
-
"font-weight" => description ? "normal" : "bold",
|
598
|
-
"text-anchor" => "start",
|
599
|
-
}, description ? description : "Page Type"),
|
600
|
-
svg("text", {
|
601
|
-
"y" => y + block_size - 4,
|
602
|
-
"x" => x + block_size + 5 + (40 * block_size),
|
603
|
-
"font-family" => "monospace",
|
604
|
-
"font-size" => block_size,
|
605
|
-
"font-weight" => description ? "normal" : "bold",
|
606
|
-
"text-anchor" => "end",
|
607
|
-
}, pages ? pages : "Pages"),
|
608
|
-
svg("text", {
|
609
|
-
"y" => y + block_size - 4,
|
610
|
-
"x" => x + block_size + 5 + (40 * block_size) + (10 * block_size),
|
611
|
-
"font-family" => "monospace",
|
612
|
-
"font-size" => block_size,
|
613
|
-
"font-weight" => description ? "normal" : "bold",
|
614
|
-
"text-anchor" => "end",
|
615
|
-
}, ratio ? ("%7.2f%%" % [ratio]) : "Ratio"),
|
616
|
-
].join("\n")
|
617
|
-
end
|
618
|
-
|
619
|
-
# Illustrate the space by printing each extent and for each page, printing a
|
620
|
-
# filled block colored based on the index the page is part of. Print a legend
|
621
|
-
# for the colors used afterwards.
|
622
|
-
def space_extents_illustrate_svg(space)
|
623
|
-
line_width = space.pages_per_extent
|
624
|
-
block_size = @options.illustration_block_size
|
625
|
-
|
626
|
-
puts "<?xml version=\"1.0\"?>"
|
627
|
-
puts "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
|
628
|
-
|
629
|
-
identifiers = {}
|
630
|
-
count_by_identifier = Hash.new(0)
|
631
|
-
|
632
|
-
graphic_x = 48
|
633
|
-
graphic_y = 16
|
634
|
-
|
635
|
-
puts svg("text", {
|
636
|
-
"y" => graphic_y - 3,
|
637
|
-
"x" => graphic_x - 7,
|
638
|
-
"font-family" => "monospace",
|
639
|
-
"font-size" => block_size,
|
640
|
-
"font-weight" => "bold",
|
641
|
-
"text-anchor" => "end",
|
642
|
-
}, "Page")
|
643
|
-
|
644
|
-
block_x = 0
|
645
|
-
block_y = 0
|
646
|
-
space.each_xdes do |entry|
|
647
|
-
block_x = 0
|
648
|
-
|
649
|
-
puts svg("text", {
|
650
|
-
"y" => graphic_y + block_y + block_size,
|
651
|
-
"x" => graphic_x - 7,
|
652
|
-
"font-family" => "monospace",
|
653
|
-
"font-size" => block_size,
|
654
|
-
"text-anchor" => "end",
|
655
|
-
}, entry.xdes[:start_page])
|
656
|
-
|
657
|
-
entry.each_page_status do |page_number, page_status|
|
658
|
-
if page_number < space.pages
|
659
|
-
used_fraction = 1.0
|
660
|
-
identifier = nil
|
661
|
-
if page_status[:free]
|
662
|
-
used_fraction = 0.0
|
663
|
-
else
|
664
|
-
page = space.page(page_number)
|
665
|
-
if page.respond_to?(:used_space)
|
666
|
-
used_fraction = page.used_space.to_f / page.size.to_f
|
667
|
-
end
|
668
|
-
if page.respond_to?(:index_id)
|
669
|
-
identifier = page.index_id
|
670
|
-
unless identifiers[identifier]
|
671
|
-
identifiers[identifier] = (page.index_id == Innodb::IbufIndex::INDEX_ID) ?
|
672
|
-
"Insert Buffer Index" :
|
673
|
-
"Index #{page.index_id}"
|
674
|
-
if space.innodb_system
|
675
|
-
table, index = space.innodb_system.table_and_index_name_by_id(page.index_id)
|
676
|
-
if table && index
|
677
|
-
identifiers[identifier] += " (%s.%s)" % [table, index]
|
678
|
-
end
|
679
|
-
end
|
680
|
-
end
|
681
|
-
end
|
682
|
-
end
|
683
|
-
if used_fraction != 0.0
|
684
|
-
count_by_identifier[identifier] += 1
|
685
|
-
else
|
686
|
-
count_by_identifier[:free] += 1
|
687
|
-
end
|
688
|
-
|
689
|
-
block_height = block_size * used_fraction
|
690
|
-
color = "black"
|
691
|
-
if identifier
|
692
|
-
color = "#" + RGBHEX_COLORS_RANDOM[(identifier * COLOR_SPACING_PRIME) % RGBHEX_COLORS_RANDOM.size]
|
693
|
-
end
|
694
|
-
puts svg("rect", {
|
695
|
-
"x" => graphic_x + block_x,
|
696
|
-
"y" => graphic_y + block_y + (block_size - block_height),
|
697
|
-
"width" => block_size,
|
698
|
-
"height" => block_height,
|
699
|
-
"fill" => color,
|
700
|
-
})
|
701
|
-
end
|
702
|
-
block_x += block_size
|
703
|
-
end
|
704
|
-
block_y += block_size
|
705
|
-
end
|
706
|
-
|
707
|
-
puts svg("path", {
|
708
|
-
"stroke" => "black",
|
709
|
-
"stroke-width" => 1,
|
710
|
-
"fill" => "none",
|
711
|
-
"d" => svg_path_rounded_rect(
|
712
|
-
graphic_x,
|
713
|
-
graphic_y,
|
714
|
-
block_x,
|
715
|
-
block_y,
|
716
|
-
4
|
717
|
-
),
|
718
|
-
})
|
719
|
-
|
720
|
-
block_x = 0
|
721
|
-
block_y += 10
|
722
|
-
puts svg_extent_legend(
|
723
|
-
graphic_x + block_x,
|
724
|
-
graphic_y + block_y,
|
725
|
-
block_size
|
726
|
-
)
|
727
|
-
block_y += block_size + 2
|
728
|
-
|
729
|
-
puts svg_extent_legend(
|
730
|
-
graphic_x + block_x,
|
731
|
-
graphic_y + block_y,
|
732
|
-
block_size,
|
733
|
-
"black",
|
734
|
-
"System",
|
735
|
-
count_by_identifier[nil],
|
736
|
-
100.0 * (count_by_identifier[nil].to_f / space.pages.to_f)
|
737
|
-
)
|
738
|
-
block_y += block_size + 2
|
739
|
-
|
740
|
-
identifiers.sort.each do |identifier, description|
|
741
|
-
puts svg_extent_legend(
|
742
|
-
graphic_x + block_x,
|
743
|
-
graphic_y + block_y,
|
744
|
-
block_size,
|
745
|
-
"#" + RGBHEX_COLORS_RANDOM[(identifier * COLOR_SPACING_PRIME) % RGBHEX_COLORS_RANDOM.size],
|
746
|
-
description,
|
747
|
-
count_by_identifier[identifier],
|
748
|
-
100.0 * (count_by_identifier[identifier].to_f / space.pages.to_f)
|
749
|
-
)
|
750
|
-
block_y += block_size + 2
|
751
|
-
end
|
752
|
-
|
753
|
-
puts svg_extent_legend(
|
754
|
-
graphic_x + block_x,
|
755
|
-
graphic_y + block_y,
|
756
|
-
block_size,
|
757
|
-
"white",
|
758
|
-
"Free space",
|
759
|
-
count_by_identifier[:free],
|
760
|
-
100.0 * (count_by_identifier[:free].to_f / space.pages.to_f)
|
761
|
-
)
|
762
|
-
|
763
|
-
puts "</svg>"
|
764
|
-
end
|
765
|
-
|
766
|
-
|
767
555
|
def space_lsn_age_illustrate(space)
|
768
556
|
colors = ANSI_COLORS_HEATMAP
|
769
|
-
|
557
|
+
width = @options.illustration_line_width
|
770
558
|
|
771
559
|
# Calculate the minimum and maximum LSN in the space. This is pretty
|
772
560
|
# inefficient as we end up scanning all pages twice.
|
@@ -774,70 +562,57 @@ def space_lsn_age_illustrate(space)
|
|
774
562
|
|
775
563
|
lsn_min = lsn_max = space.page(0).lsn
|
776
564
|
space.each_page do |page_number, page|
|
777
|
-
if page.lsn
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
565
|
+
next if page.lsn.zero?
|
566
|
+
|
567
|
+
page_lsn[page_number] = page.lsn
|
568
|
+
lsn_min = page.lsn < lsn_min ? page.lsn : lsn_min
|
569
|
+
lsn_max = page.lsn > lsn_max ? page.lsn : lsn_max
|
782
570
|
end
|
783
571
|
lsn_delta = lsn_max - lsn_min
|
784
572
|
|
785
573
|
puts
|
786
|
-
puts "%12s
|
574
|
+
puts "%12s %-#{width}s " % ["", center(space.name, width)]
|
575
|
+
puts "%12s ╭%-#{width}s╮" % ["Start Page", "─" * width]
|
787
576
|
|
788
577
|
start_page = 0
|
789
|
-
page_lsn.each_slice(
|
790
|
-
puts "%12i │%-#{
|
578
|
+
page_lsn.each_slice(width) do |slice|
|
579
|
+
puts "%12i │%-#{width}s│" % [
|
791
580
|
start_page,
|
792
|
-
slice.inject("")
|
581
|
+
slice.inject("") do |line, lsn|
|
793
582
|
if lsn
|
794
|
-
age_ratio = (lsn - lsn_min).to_f / lsn_delta
|
583
|
+
age_ratio = (lsn - lsn_min).to_f / lsn_delta
|
795
584
|
color = colors[(age_ratio * colors.size.to_f).floor]
|
796
585
|
line += ansi_color(color, filled_block(1.0, nil))
|
797
586
|
else
|
798
587
|
line += " "
|
799
588
|
end
|
800
589
|
line
|
801
|
-
|
590
|
+
end,
|
802
591
|
]
|
803
|
-
start_page +=
|
592
|
+
start_page += width
|
804
593
|
end
|
805
594
|
|
806
|
-
puts "%12s ╰%-#{
|
807
|
-
|
808
|
-
lsn_legend = "<" + ("─" * (colors.size - 2)) + ">"
|
809
|
-
|
810
|
-
begin
|
811
|
-
# Try to optionally replace the boring lsn_legend with a histogram of
|
812
|
-
# page age distribution. If histogram/array is not available, move on.
|
813
|
-
|
814
|
-
require 'histogram/array'
|
815
|
-
|
816
|
-
lsn_bins, lsn_freq = page_lsn.select { |lsn| !lsn.nil? }.
|
817
|
-
histogram(colors.size, :min => lsn_min, :max => lsn_max)
|
595
|
+
puts "%12s ╰%-#{width}s╯" % ["", "─" * width]
|
818
596
|
|
819
|
-
|
597
|
+
_, lsn_freq = page_lsn.reject(&:nil?).histogram(colors.size, min: lsn_min, max: lsn_max)
|
598
|
+
lsn_freq_delta = lsn_freq.max - lsn_freq.min
|
820
599
|
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
lsn_legend << filled_block(freq_norm)
|
826
|
-
else
|
827
|
-
# Avoid the "empty" block used for 0.0.
|
828
|
-
lsn_legend << " "
|
829
|
-
end
|
830
|
-
end
|
831
|
-
rescue LoadError
|
832
|
-
# That's okay! Leave the legend boring.
|
600
|
+
lsn_age_histogram = "".dup
|
601
|
+
lsn_freq.each do |freq|
|
602
|
+
freq_norm = freq / lsn_freq_delta
|
603
|
+
lsn_age_histogram << (freq_norm > 0.0 ? filled_block(freq_norm) : " ")
|
833
604
|
end
|
834
605
|
|
835
606
|
puts
|
836
|
-
puts "
|
607
|
+
puts "LSN Age Histogram (%s = ~%d pages):" % [
|
608
|
+
filled_block(1.0, nil),
|
609
|
+
(space.pages.to_f / colors.size).round,
|
610
|
+
]
|
837
611
|
puts " %12s %s %-12s" % [
|
838
612
|
"Min LSN",
|
839
|
-
|
840
|
-
"Max LSN"
|
613
|
+
lsn_age_histogram,
|
614
|
+
"Max LSN",
|
615
|
+
]
|
841
616
|
puts " %12i %s %-12i" % [
|
842
617
|
lsn_min,
|
843
618
|
colors.map { |c| ansi_color(c, filled_block(1.0, nil)) }.join,
|
@@ -845,126 +620,6 @@ def space_lsn_age_illustrate(space)
|
|
845
620
|
]
|
846
621
|
end
|
847
622
|
|
848
|
-
def space_lsn_age_illustrate_svg(space)
|
849
|
-
colors = RGBHEX_COLORS_HEATMAP
|
850
|
-
line_width = @options.illustration_line_width
|
851
|
-
block_size = @options.illustration_block_size
|
852
|
-
|
853
|
-
puts "<?xml version=\"1.0\"?>"
|
854
|
-
puts "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
|
855
|
-
|
856
|
-
# Calculate the minimum and maximum LSN in the space. This is pretty
|
857
|
-
# inefficient as we end up scanning all pages twice.
|
858
|
-
page_lsn = Array.new(space.pages)
|
859
|
-
|
860
|
-
lsn_min = lsn_max = space.page(0).lsn
|
861
|
-
space.each_page do |page_number, page|
|
862
|
-
if page.lsn != 0
|
863
|
-
page_lsn[page_number] = page.lsn
|
864
|
-
lsn_min = page.lsn < lsn_min ? page.lsn : lsn_min
|
865
|
-
lsn_max = page.lsn > lsn_max ? page.lsn : lsn_max
|
866
|
-
end
|
867
|
-
end
|
868
|
-
lsn_delta = lsn_max - lsn_min
|
869
|
-
|
870
|
-
graphic_x = 48
|
871
|
-
graphic_y = 16
|
872
|
-
|
873
|
-
block_x = 0
|
874
|
-
block_y = 0
|
875
|
-
|
876
|
-
puts svg("text", {
|
877
|
-
"y" => graphic_y - 3,
|
878
|
-
"x" => graphic_x - 7,
|
879
|
-
"font-family" => "monospace",
|
880
|
-
"font-size" => block_size,
|
881
|
-
"font-weight" => "bold",
|
882
|
-
"text-anchor" => "end",
|
883
|
-
}, "Page")
|
884
|
-
|
885
|
-
start_page = 0
|
886
|
-
page_lsn.each_slice(line_width) do |slice|
|
887
|
-
block_x = 0
|
888
|
-
slice.each do |lsn|
|
889
|
-
rgbhex = ""
|
890
|
-
if lsn
|
891
|
-
age_ratio = (lsn - lsn_min).to_f / lsn_delta.to_f
|
892
|
-
color = colors[(age_ratio * colors.size.to_f).floor]
|
893
|
-
end
|
894
|
-
puts svg("rect", {
|
895
|
-
"y" => graphic_y + block_y,
|
896
|
-
"x" => graphic_x + block_x,
|
897
|
-
"width" => block_size,
|
898
|
-
"height" => block_size,
|
899
|
-
"fill" => color ? "#" + color : "black",
|
900
|
-
})
|
901
|
-
block_x += block_size
|
902
|
-
end
|
903
|
-
puts svg("text", {
|
904
|
-
"y" => graphic_y + block_y + block_size,
|
905
|
-
"x" => graphic_x - 7,
|
906
|
-
"font-family" => "monospace",
|
907
|
-
"font-size" => block_size,
|
908
|
-
"text-anchor" => "end",
|
909
|
-
}, start_page)
|
910
|
-
block_y += block_size
|
911
|
-
start_page += line_width
|
912
|
-
end
|
913
|
-
|
914
|
-
puts svg("path", {
|
915
|
-
"stroke" => "black",
|
916
|
-
"stroke-width" => 1,
|
917
|
-
"fill" => "none",
|
918
|
-
"d" => svg_path_rounded_rect(
|
919
|
-
graphic_x,
|
920
|
-
graphic_y,
|
921
|
-
line_width * block_size,
|
922
|
-
block_y,
|
923
|
-
4
|
924
|
-
),
|
925
|
-
})
|
926
|
-
|
927
|
-
block_x = 0
|
928
|
-
block_y += 16
|
929
|
-
puts svg("text", {
|
930
|
-
"y" => graphic_y + block_y + block_size - 4,
|
931
|
-
"x" => graphic_x + block_x,
|
932
|
-
"font-family" => "monospace",
|
933
|
-
"font-size" => block_size,
|
934
|
-
"text-anchor" => "start",
|
935
|
-
}, lsn_min)
|
936
|
-
color_width = ((64.0 * block_size.to_f) / colors.size.to_f).round
|
937
|
-
colors.each do |color|
|
938
|
-
puts svg("rect", {
|
939
|
-
"y" => graphic_y + block_y + block_size,
|
940
|
-
"x" => graphic_x + block_x,
|
941
|
-
"width" => color_width,
|
942
|
-
"height" => block_size,
|
943
|
-
"fill" => "#" + color,
|
944
|
-
})
|
945
|
-
block_x += color_width
|
946
|
-
end
|
947
|
-
puts svg("text", {
|
948
|
-
"y" => graphic_y + block_y + block_size - 4,
|
949
|
-
"x" => graphic_x + block_x,
|
950
|
-
"font-family" => "monospace",
|
951
|
-
"font-size" => block_size,
|
952
|
-
"text-anchor" => "end",
|
953
|
-
}, lsn_max)
|
954
|
-
|
955
|
-
puts svg("text", {
|
956
|
-
"y" => graphic_y + block_y + block_size - 4,
|
957
|
-
"x" => graphic_x + (block_x / 2),
|
958
|
-
"font-family" => "monospace",
|
959
|
-
"font-weight" => "bold",
|
960
|
-
"font-size" => block_size,
|
961
|
-
"text-anchor" => "middle",
|
962
|
-
}, "LSN Age")
|
963
|
-
|
964
|
-
|
965
|
-
puts "</svg>\n"
|
966
|
-
end
|
967
|
-
|
968
623
|
def print_inode_summary(inode)
|
969
624
|
puts "INODE fseg_id=%d, pages=%d, frag=%d, full=%d, not_full=%d, free=%d" % [
|
970
625
|
inode.fseg_id,
|
@@ -977,6 +632,7 @@ def print_inode_summary(inode)
|
|
977
632
|
end
|
978
633
|
|
979
634
|
def print_inode_detail(inode)
|
635
|
+
# rubocop:disable Layout/LineLength
|
980
636
|
puts "INODE fseg_id=%d, pages=%d, frag=%d pages (%s), full=%d extents (%s), not_full=%d extents (%s) (%d/%d pages used), free=%d extents (%s)" % [
|
981
637
|
inode.fseg_id,
|
982
638
|
inode.total_pages,
|
@@ -991,6 +647,7 @@ def print_inode_detail(inode)
|
|
991
647
|
inode.free.length,
|
992
648
|
inode.free.each.to_a.map { |x| "#{x.start_page}-#{x.end_page}" }.join(", "),
|
993
649
|
]
|
650
|
+
# rubocop:enable Layout/LineLength
|
994
651
|
end
|
995
652
|
|
996
653
|
def space_inodes_fseg_id(space)
|
@@ -1027,7 +684,6 @@ def page_account(innodb_system, space, page_number)
|
|
1027
684
|
page_type[:usage],
|
1028
685
|
]
|
1029
686
|
|
1030
|
-
|
1031
687
|
xdes = space.xdes_for_page(page_number)
|
1032
688
|
puts " Extent descriptor for pages %d-%d is at page %d, offset %d." % [
|
1033
689
|
xdes.start_page,
|
@@ -1044,25 +700,23 @@ def page_account(innodb_system, space, page_number)
|
|
1044
700
|
|
1045
701
|
xdes_status = xdes.page_status(page_number)
|
1046
702
|
puts " Page is marked as %s in extent descriptor." % [
|
1047
|
-
xdes_status[:free] ?
|
703
|
+
xdes_status[:free] ? "free" : "used",
|
1048
704
|
]
|
1049
705
|
|
1050
706
|
space.each_xdes_list do |name, list|
|
1051
|
-
if list.include?
|
1052
|
-
puts " Extent is in #{name} list of space."
|
1053
|
-
end
|
707
|
+
puts " Extent is in #{name} list of space." if list.include?(xdes)
|
1054
708
|
end
|
1055
709
|
|
1056
710
|
page_inode = nil
|
1057
711
|
space.each_inode do |inode|
|
1058
712
|
inode.each_list do |name, list|
|
1059
|
-
if list.include?
|
713
|
+
if list.include?(xdes)
|
1060
714
|
page_inode = inode
|
1061
715
|
puts " Extent is in #{name} list of fseg #{inode.fseg_id}."
|
1062
716
|
end
|
1063
717
|
end
|
1064
718
|
|
1065
|
-
if inode.frag_array.include?
|
719
|
+
if inode.frag_array.include?(page_number) # rubocop:disable Style/Next
|
1066
720
|
page_inode = inode
|
1067
721
|
puts " Page is in fragment array of fseg %d." % [
|
1068
722
|
inode.fseg_id,
|
@@ -1072,42 +726,30 @@ def page_account(innodb_system, space, page_number)
|
|
1072
726
|
|
1073
727
|
space.each_index do |index|
|
1074
728
|
index.each_fseg do |fseg_name, fseg|
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
end
|
1083
|
-
end
|
729
|
+
next unless page_inode == fseg
|
730
|
+
|
731
|
+
puts " Fseg is in #{fseg_name} fseg of index #{index.id}."
|
732
|
+
puts " Index root is page #{index.root.offset}."
|
733
|
+
if innodb_system
|
734
|
+
table_name, index_name = innodb_system.table_and_index_name_by_id(index.id)
|
735
|
+
puts " Index is #{table_name}.#{index_name}." if table_name && index_name
|
1084
736
|
end
|
1085
737
|
end
|
1086
738
|
end
|
1087
739
|
|
1088
|
-
if space.system_space?
|
1089
|
-
if page_inode == space.trx_sys.fseg
|
1090
|
-
|
1091
|
-
end
|
740
|
+
if space.system_space? # rubocop:disable Style/GuardClause
|
741
|
+
puts " Fseg is trx_sys." if page_inode == space.trx_sys.fseg
|
742
|
+
puts " Fseg is doublewrite buffer." if page_inode == space.trx_sys.doublewrite[:fseg]
|
1092
743
|
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
if innodb_system
|
1098
|
-
innodb_system.data_dictionary.each_data_dictionary_index do |table_name, index_name, index|
|
1099
|
-
index.each_fseg do |fseg_name, fseg|
|
1100
|
-
if page_inode == fseg
|
1101
|
-
puts " Index is #{table_name}.#{index_name} of data dictionary."
|
1102
|
-
end
|
1103
|
-
end
|
744
|
+
innodb_system.data_dictionary&.each_data_dictionary_index do |table_name, index_name, index|
|
745
|
+
index.each_fseg do |_fseg_name, fseg|
|
746
|
+
puts " Index is #{table_name}.#{index_name} of data dictionary." if page_inode == fseg
|
1104
747
|
end
|
1105
748
|
end
|
1106
749
|
|
1107
750
|
space.trx_sys.rsegs.each_with_index do |rseg_slot, index|
|
1108
|
-
if page.fil_header
|
1109
|
-
|
1110
|
-
puts " Page is a rollback segment in slot #{index}."
|
751
|
+
if page.fil_header.space_id == rseg_slot.space_id && page.fil_header.offset == rseg_slot.page_number
|
752
|
+
puts " Page is a rollback segment in slot #{index}."
|
1111
753
|
end
|
1112
754
|
end
|
1113
755
|
end
|
@@ -1121,10 +763,9 @@ def page_validate_index(page)
|
|
1121
763
|
puts "done."
|
1122
764
|
|
1123
765
|
directory_offsets = page.each_directory_offset.to_a
|
1124
|
-
record_offsets = records.map
|
766
|
+
record_offsets = records.map(&:offset)
|
1125
767
|
|
1126
|
-
invalid_directory_entries =
|
1127
|
-
directory_offsets.select { |n| ! record_offsets.include?(n) }
|
768
|
+
invalid_directory_entries = directory_offsets.reject { |n| record_offsets.include?(n) }
|
1128
769
|
|
1129
770
|
unless invalid_directory_entries.empty?
|
1130
771
|
page_is_valid = false
|
@@ -1138,9 +779,7 @@ def page_validate_index(page)
|
|
1138
779
|
end
|
1139
780
|
|
1140
781
|
# Read all records corresponding to valid directory entries.
|
1141
|
-
directory_records = directory_offsets.
|
1142
|
-
select { |o| !invalid_directory_entries.include?(o) }.
|
1143
|
-
map { |o| page.record(o) }
|
782
|
+
directory_records = directory_offsets.reject { |o| invalid_directory_entries.include?(o) }.map { |o| page.record(o) }
|
1144
783
|
|
1145
784
|
misordered_directory_entries = []
|
1146
785
|
prev = nil
|
@@ -1149,13 +788,13 @@ def page_validate_index(page)
|
|
1149
788
|
prev = rec
|
1150
789
|
next
|
1151
790
|
end
|
1152
|
-
if rec.compare_key(prev.key.map { |v| v[:value]}) == 1
|
791
|
+
if rec.compare_key(prev.key.map { |v| v[:value] }) == 1
|
1153
792
|
page_is_valid = false
|
1154
793
|
misordered_directory_entries << {
|
1155
|
-
:
|
1156
|
-
:
|
1157
|
-
:
|
1158
|
-
:
|
794
|
+
slot: page.offset_is_directory_slot?(rec.offset),
|
795
|
+
offset: rec.offset,
|
796
|
+
key: rec.key_string,
|
797
|
+
prev_key: prev.key_string,
|
1159
798
|
}
|
1160
799
|
end
|
1161
800
|
prev = rec
|
@@ -1179,12 +818,12 @@ def page_validate_index(page)
|
|
1179
818
|
prev = rec
|
1180
819
|
next
|
1181
820
|
end
|
1182
|
-
if rec.compare_key(prev.key.map { |v| v[:value]}) == 1
|
821
|
+
if rec.compare_key(prev.key.map { |v| v[:value] }) == 1
|
1183
822
|
page_is_valid = false
|
1184
823
|
misordered_records << {
|
1185
|
-
:
|
1186
|
-
:
|
1187
|
-
:
|
824
|
+
offset: rec.offset,
|
825
|
+
key: rec.key_string,
|
826
|
+
prev_key: prev.key_string,
|
1188
827
|
}
|
1189
828
|
end
|
1190
829
|
prev = rec
|
@@ -1203,8 +842,7 @@ def page_validate_index(page)
|
|
1203
842
|
page_is_valid
|
1204
843
|
end
|
1205
844
|
|
1206
|
-
|
1207
|
-
def page_validate(innodb_system, space, page_number)
|
845
|
+
def page_validate(_innodb_system, space, page_number)
|
1208
846
|
page_is_valid = true
|
1209
847
|
puts "Validating page %d..." % [page_number]
|
1210
848
|
|
@@ -1219,11 +857,11 @@ def page_validate(innodb_system, space, page_number)
|
|
1219
857
|
puts " header %10d (0x%08x), type %s" % [
|
1220
858
|
page.checksum,
|
1221
859
|
page.checksum,
|
1222
|
-
page.checksum_type
|
860
|
+
page.checksum_type || "unknown",
|
1223
861
|
]
|
1224
862
|
puts " trailer %10d (0x%08x)" % [
|
1225
|
-
page.
|
1226
|
-
page.
|
863
|
+
page.fil_trailer.checksum,
|
864
|
+
page.fil_trailer.checksum,
|
1227
865
|
]
|
1228
866
|
puts " Calculated checksums:"
|
1229
867
|
puts " crc32 %10d (0x%08x)" % [
|
@@ -1246,12 +884,12 @@ def page_validate(innodb_system, space, page_number)
|
|
1246
884
|
]
|
1247
885
|
puts " Low 32 bits of LSN:"
|
1248
886
|
puts " header %10d (0x%08x)" % [
|
1249
|
-
page.
|
1250
|
-
page.
|
887
|
+
page.fil_header.lsn_low32,
|
888
|
+
page.fil_header.lsn_low32,
|
1251
889
|
]
|
1252
890
|
puts " trailer %10d (0x%08x)" % [
|
1253
|
-
page.
|
1254
|
-
page.
|
891
|
+
page.fil_trailer.lsn_low32,
|
892
|
+
page.fil_trailer.lsn_low32,
|
1255
893
|
]
|
1256
894
|
end
|
1257
895
|
|
@@ -1265,16 +903,14 @@ def page_validate(innodb_system, space, page_number)
|
|
1265
903
|
]
|
1266
904
|
end
|
1267
905
|
if page.misplaced_space?
|
1268
|
-
puts " Space
|
906
|
+
puts " Space ID %d does not match page stored space ID %d." % [
|
1269
907
|
page.space.space_id,
|
1270
908
|
page.space_id,
|
1271
909
|
]
|
1272
910
|
end
|
1273
911
|
end
|
1274
912
|
|
1275
|
-
if page.type == :INDEX && !page_validate_index(page)
|
1276
|
-
page_is_valid = false
|
1277
|
-
end
|
913
|
+
page_is_valid = false if page.type == :INDEX && !page_validate_index(page)
|
1278
914
|
|
1279
915
|
puts "Page %d appears to be %s!" % [
|
1280
916
|
page_number,
|
@@ -1282,24 +918,21 @@ def page_validate(innodb_system, space, page_number)
|
|
1282
918
|
]
|
1283
919
|
end
|
1284
920
|
|
1285
|
-
def page_directory_summary(
|
1286
|
-
if page.type != :INDEX
|
1287
|
-
usage 1, "Page must be an index page"
|
1288
|
-
end
|
921
|
+
def page_directory_summary(_space, page)
|
922
|
+
usage(1, "Page must be an index page") if page.type != :INDEX
|
1289
923
|
|
1290
|
-
puts "%-8s%-8s%-14s%-8s%s" % [
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
924
|
+
puts "%-8s%-8s%-14s%-8s%s" % %w[
|
925
|
+
slot
|
926
|
+
offset
|
927
|
+
type
|
928
|
+
owned
|
929
|
+
key
|
1296
930
|
]
|
1297
931
|
|
1298
932
|
page.directory.each_with_index do |offset, slot|
|
1299
933
|
record = page.record(offset)
|
1300
|
-
key =
|
1301
|
-
|
1302
|
-
end
|
934
|
+
key = %i[conventional node_pointer].include?(record.header[:type]) ? "(%s)" % record.key_string : ""
|
935
|
+
|
1303
936
|
puts "%-8i%-8i%-14s%-8i%s" % [
|
1304
937
|
slot,
|
1305
938
|
offset,
|
@@ -1310,13 +943,12 @@ def page_directory_summary(space, page)
|
|
1310
943
|
end
|
1311
944
|
end
|
1312
945
|
|
1313
|
-
def page_records(
|
946
|
+
def page_records(_space, page)
|
1314
947
|
page.each_record do |record|
|
1315
948
|
puts "Record %i: %s" % [
|
1316
949
|
record.offset,
|
1317
950
|
record.string,
|
1318
951
|
]
|
1319
|
-
puts if record.header[:type] == :conventional
|
1320
952
|
end
|
1321
953
|
end
|
1322
954
|
|
@@ -1328,40 +960,46 @@ def page_illustrate(page)
|
|
1328
960
|
identifier_sort = 0
|
1329
961
|
count_by_identifier = Hash.new(0)
|
1330
962
|
|
1331
|
-
page.each_region.
|
1332
|
-
region
|
963
|
+
page.each_region.sort_by(&:offset).each do |region|
|
964
|
+
region.length.times do |n|
|
1333
965
|
identifier = nil
|
1334
966
|
fraction = 0.0
|
1335
|
-
if region
|
1336
|
-
|
1337
|
-
|
1338
|
-
else
|
1339
|
-
fraction = 1.0
|
1340
|
-
end
|
1341
|
-
identifier = region[:name].hash.abs
|
967
|
+
if region.name != :garbage
|
968
|
+
fraction = n == region.length - 1 ? 0.5 : 1.0
|
969
|
+
identifier = region.name.hash.abs
|
1342
970
|
unless identifiers[identifier]
|
1343
971
|
# Prefix an integer <0123> on each name so that the legend can be
|
1344
972
|
# sorted by the appearance of each region in the page.
|
1345
973
|
identifiers[identifier] = "<%04i>%s" % [
|
1346
974
|
identifier_sort,
|
1347
|
-
region
|
975
|
+
region.info,
|
1348
976
|
]
|
1349
977
|
identifier_sort += 1
|
1350
978
|
end
|
1351
979
|
end
|
1352
|
-
blocks[region
|
980
|
+
blocks[region.offset + n] = filled_block(fraction, identifier, BLOCK_CHARS_H)
|
1353
981
|
count_by_identifier[identifier] += 1
|
1354
982
|
end
|
1355
983
|
end
|
1356
984
|
|
1357
985
|
puts
|
1358
|
-
puts "%12s
|
986
|
+
puts "%12s %-#{width}s " % ["", center("Page #{page.offset} (#{page.type})", width)]
|
987
|
+
puts "%12s ╭%-#{width}s╮" % ["Offset", "─" * width]
|
1359
988
|
offset = 0
|
989
|
+
skipped_lines = 0
|
1360
990
|
blocks.each_slice(width) do |slice|
|
1361
|
-
|
991
|
+
if slice.any? { |s| s != " " }
|
992
|
+
if skipped_lines.positive?
|
993
|
+
puts "%12s │%-#{width}s│" % ["...", ""]
|
994
|
+
skipped_lines = 0
|
995
|
+
end
|
996
|
+
puts "%12i │%-s│" % [offset, slice.join]
|
997
|
+
else
|
998
|
+
skipped_lines += 1
|
999
|
+
end
|
1362
1000
|
offset += width
|
1363
1001
|
end
|
1364
|
-
puts "%12s ╰%-#{width}s╯" % [
|
1002
|
+
puts "%12s ╰%-#{width}s╯" % ["", "─" * width]
|
1365
1003
|
|
1366
1004
|
puts
|
1367
1005
|
puts "Legend (%s = 1 byte):" % [filled_block(1.0, nil)]
|
@@ -1370,26 +1008,26 @@ def page_illustrate(page)
|
|
1370
1008
|
"Bytes",
|
1371
1009
|
"Ratio",
|
1372
1010
|
]
|
1373
|
-
identifiers.sort { |a,b| a[1] <=> b[1] }.each do |identifier, description|
|
1011
|
+
identifiers.sort { |a, b| a[1] <=> b[1] }.each do |identifier, description|
|
1374
1012
|
puts " %s %-30s %8i %7.2f%%" % [
|
1375
1013
|
filled_block(1.0, identifier),
|
1376
1014
|
description.gsub(/^<\d+>/, ""),
|
1377
1015
|
count_by_identifier[identifier],
|
1378
|
-
100.0 * (count_by_identifier[identifier].to_f / page.size
|
1016
|
+
100.0 * (count_by_identifier[identifier].to_f / page.size),
|
1379
1017
|
]
|
1380
1018
|
end
|
1381
1019
|
puts " %s %-30s %8i %7.2f%%" % [
|
1382
1020
|
filled_block(0.0, nil),
|
1383
1021
|
"Garbage",
|
1384
1022
|
count_by_identifier[nil],
|
1385
|
-
100.0 * (count_by_identifier[nil].to_f / page.size
|
1023
|
+
100.0 * (count_by_identifier[nil].to_f / page.size),
|
1386
1024
|
]
|
1387
|
-
free_space = page.size - count_by_identifier.inject(0) { |sum,(
|
1025
|
+
free_space = page.size - count_by_identifier.inject(0) { |sum, (_k, v)| sum + v }
|
1388
1026
|
puts " %s %-30s %8i %7.2f%%" % [
|
1389
1027
|
unknown_page_content ? "▞" : " ",
|
1390
1028
|
unknown_page_content ? "Unknown (no data dictionary)" : "Free",
|
1391
1029
|
free_space,
|
1392
|
-
100.0 * (free_space.to_f / page.size
|
1030
|
+
100.0 * (free_space.to_f / page.size),
|
1393
1031
|
]
|
1394
1032
|
|
1395
1033
|
if unknown_page_content
|
@@ -1403,21 +1041,17 @@ def page_illustrate(page)
|
|
1403
1041
|
end
|
1404
1042
|
|
1405
1043
|
def record_dump(page, record_offset)
|
1406
|
-
|
1407
|
-
|
1408
|
-
end
|
1044
|
+
record = page.record(record_offset)
|
1045
|
+
raise "Record at offset #{record_offset} not found" unless record
|
1409
1046
|
|
1410
1047
|
record.dump
|
1411
1048
|
end
|
1412
1049
|
|
1413
1050
|
def record_history(page, record_offset)
|
1414
|
-
unless page.leaf?
|
1415
|
-
raise "Record is not located on a leaf page; no history available"
|
1416
|
-
end
|
1051
|
+
raise "Record is not located on a leaf page; no history available" unless page.leaf?
|
1417
1052
|
|
1418
|
-
|
1419
|
-
|
1420
|
-
end
|
1053
|
+
record = page.record(record_offset)
|
1054
|
+
raise "Record at offset #{record_offset} not found" unless record
|
1421
1055
|
|
1422
1056
|
puts "%-14s%-20s%s" % [
|
1423
1057
|
"Transaction",
|
@@ -1435,29 +1069,23 @@ def record_history(page, record_offset)
|
|
1435
1069
|
end
|
1436
1070
|
|
1437
1071
|
def index_fseg_lists(index, fseg_name)
|
1438
|
-
unless index.fseg(fseg_name)
|
1439
|
-
raise "File segment '#{fseg_name}' doesn't exist"
|
1440
|
-
end
|
1072
|
+
raise "File segment '#{fseg_name}' doesn't exist" unless index.fseg(fseg_name)
|
1441
1073
|
|
1442
1074
|
print_lists(index.each_fseg_list(index.fseg(fseg_name)))
|
1443
1075
|
end
|
1444
1076
|
|
1445
1077
|
def index_fseg_list_iterate(index, fseg_name, list_name)
|
1446
|
-
|
1447
|
-
|
1448
|
-
end
|
1078
|
+
fseg = index.fseg(fseg_name)
|
1079
|
+
raise "File segment '#{fseg_name}' doesn't exist" unless fseg
|
1449
1080
|
|
1450
|
-
|
1451
|
-
|
1452
|
-
end
|
1081
|
+
list = fseg.list(list_name)
|
1082
|
+
raise "List '#{list_name}' doesn't exist" unless list
|
1453
1083
|
|
1454
1084
|
print_xdes_list(index.space, list)
|
1455
1085
|
end
|
1456
1086
|
|
1457
1087
|
def index_fseg_frag_pages(index, fseg_name)
|
1458
|
-
unless index.fseg(fseg_name)
|
1459
|
-
raise "File segment '#{fseg_name}' doesn't exist"
|
1460
|
-
end
|
1088
|
+
raise "File segment '#{fseg_name}' doesn't exist" unless index.fseg(fseg_name)
|
1461
1089
|
|
1462
1090
|
print_index_page_summary(index.each_fseg_frag_page(index.fseg(fseg_name)))
|
1463
1091
|
end
|
@@ -1472,17 +1100,17 @@ def index_recurse(index)
|
|
1472
1100
|
page.records,
|
1473
1101
|
page.record_space,
|
1474
1102
|
]
|
1475
|
-
if page.level
|
1103
|
+
if page.level.zero?
|
1476
1104
|
page.each_record do |record|
|
1477
1105
|
puts "%sRECORD: (%s) → (%s)" % [
|
1478
|
-
" " * (depth+1),
|
1106
|
+
" " * (depth + 1),
|
1479
1107
|
record.key_string,
|
1480
1108
|
record.row_string,
|
1481
1109
|
]
|
1482
1110
|
end
|
1483
1111
|
end
|
1484
1112
|
end,
|
1485
|
-
lambda do |
|
1113
|
+
lambda do |_parent_page, child_page, child_min_key, depth|
|
1486
1114
|
puts "%sNODE POINTER RECORD ≥ (%s) → #%i" % [
|
1487
1115
|
" " * depth,
|
1488
1116
|
child_min_key.map { |r| "%s=%s" % [r[:name], r[:value].inspect] }.join(", "),
|
@@ -1493,13 +1121,13 @@ def index_recurse(index)
|
|
1493
1121
|
end
|
1494
1122
|
|
1495
1123
|
def index_record_offsets(index)
|
1496
|
-
puts "%-20s%-20s" % [
|
1497
|
-
|
1498
|
-
|
1124
|
+
puts "%-20s%-20s" % %w[
|
1125
|
+
page_offset
|
1126
|
+
record_offset
|
1499
1127
|
]
|
1500
1128
|
index.recurse(
|
1501
|
-
lambda do |page,
|
1502
|
-
if page.level
|
1129
|
+
lambda do |page, _depth|
|
1130
|
+
if page.level.zero?
|
1503
1131
|
page.each_record do |record|
|
1504
1132
|
puts "%-20i%-20i" % [
|
1505
1133
|
page.offset,
|
@@ -1508,7 +1136,7 @@ def index_record_offsets(index)
|
|
1508
1136
|
end
|
1509
1137
|
end
|
1510
1138
|
end,
|
1511
|
-
|
1139
|
+
->(*_) {}
|
1512
1140
|
)
|
1513
1141
|
end
|
1514
1142
|
|
@@ -1528,13 +1156,13 @@ def index_digraph(index)
|
|
1528
1156
|
child_key.join(", "),
|
1529
1157
|
]
|
1530
1158
|
end
|
1531
|
-
puts " %spage_%i [ shape =
|
1159
|
+
puts " %spage_%i [ shape = 'record'; label = '%s'; ];" % [
|
1532
1160
|
" " * depth,
|
1533
1161
|
page.offset,
|
1534
1162
|
label,
|
1535
1163
|
]
|
1536
1164
|
end,
|
1537
|
-
lambda do |parent_page, child_page,
|
1165
|
+
lambda do |parent_page, child_page, _child_key, depth|
|
1538
1166
|
puts " %spage_%i:dir_%i → page_%i:page:nw;" % [
|
1539
1167
|
" " * depth,
|
1540
1168
|
parent_page.offset,
|
@@ -1547,14 +1175,14 @@ def index_digraph(index)
|
|
1547
1175
|
end
|
1548
1176
|
|
1549
1177
|
def index_level_summary(index, level)
|
1550
|
-
puts "%-8s%-8s%-8s%-8s%-8s%-8s%-8s" % [
|
1551
|
-
|
1552
|
-
|
1553
|
-
|
1554
|
-
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1178
|
+
puts "%-8s%-8s%-8s%-8s%-8s%-8s%-8s" % %w[
|
1179
|
+
page
|
1180
|
+
index
|
1181
|
+
level
|
1182
|
+
data
|
1183
|
+
free
|
1184
|
+
records
|
1185
|
+
min_key
|
1558
1186
|
]
|
1559
1187
|
|
1560
1188
|
index.each_page_at_level(level) do |page|
|
@@ -1571,15 +1199,14 @@ def index_level_summary(index, level)
|
|
1571
1199
|
end
|
1572
1200
|
|
1573
1201
|
def undo_history_summary(innodb_system)
|
1574
|
-
|
1575
|
-
|
1576
|
-
|
1577
|
-
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
"Table",
|
1202
|
+
history_list = innodb_system.history.each_history_list.reject { |h| h.list.empty? }
|
1203
|
+
|
1204
|
+
puts "%-8s%-8s%-14s%-20s%s" % %w[
|
1205
|
+
Page
|
1206
|
+
Offset
|
1207
|
+
Transaction
|
1208
|
+
Type
|
1209
|
+
Table
|
1583
1210
|
]
|
1584
1211
|
|
1585
1212
|
history_list.each do |history|
|
@@ -1609,6 +1236,7 @@ def usage(exit_code, message = nil)
|
|
1609
1236
|
exit exit_code
|
1610
1237
|
end
|
1611
1238
|
|
1239
|
+
# rubocop:disable Layout/HeredocIndentation
|
1612
1240
|
print <<'END_OF_USAGE'
|
1613
1241
|
|
1614
1242
|
Usage: innodb_space <options> <mode>
|
@@ -1636,9 +1264,9 @@ The following options are supported:
|
|
1636
1264
|
|
1637
1265
|
--system-space-file, -s <arg>
|
1638
1266
|
Load the system tablespace file or files <arg>: Either a single file e.g.
|
1639
|
-
|
1267
|
+
'ibdata1', a comma-delimited list of files e.g. 'ibdata1,ibdata1', or a
|
1640
1268
|
directory name. If a directory name is provided, it will be scanned for all
|
1641
|
-
files named
|
1269
|
+
files named 'ibdata?' which will then be sorted alphabetically and used to
|
1642
1270
|
load the system tablespace.
|
1643
1271
|
|
1644
1272
|
--table-name, -T <name>
|
@@ -1663,7 +1291,7 @@ The following options are supported:
|
|
1663
1291
|
Operate on the file segment (fseg) <fseg_id>.
|
1664
1292
|
|
1665
1293
|
--require, -r <file>
|
1666
|
-
Use Ruby's
|
1294
|
+
Use Ruby's 'require' to load the file <file>. This is useful for loading
|
1667
1295
|
classes with record describers.
|
1668
1296
|
|
1669
1297
|
--describer, -d <describer>
|
@@ -1691,9 +1319,9 @@ The following modes are supported:
|
|
1691
1319
|
provided with the --page/-p argument.
|
1692
1320
|
|
1693
1321
|
space-index-pages-summary
|
1694
|
-
Summarize all
|
1695
|
-
page fill rates and record counts per page. In addition to
|
1696
|
-
|
1322
|
+
Summarize all 'INDEX' pages within a tablespace. This is useful to analyze
|
1323
|
+
page fill rates and record counts per page. In addition to 'INDEX' pages,
|
1324
|
+
'ALLOCATED' pages are also printed and assumed to be completely empty.
|
1697
1325
|
A starting page number can be provided with the --page/-p argument.
|
1698
1326
|
|
1699
1327
|
space-index-fseg-pages-summary
|
@@ -1702,7 +1330,7 @@ The following modes are supported:
|
|
1702
1330
|
|
1703
1331
|
space-index-pages-free-plot
|
1704
1332
|
Use Ruby's gnuplot module to produce a scatterplot of page free space for
|
1705
|
-
all
|
1333
|
+
all 'INDEX' and 'ALLOCATED' pages in a tablespace. More aesthetically
|
1706
1334
|
pleasing plots can be produced with space-index-pages-summary output,
|
1707
1335
|
but this is a quick and easy way to produce a passable plot. A starting
|
1708
1336
|
page number can be provided with the --page/-p argument.
|
@@ -1734,20 +1362,11 @@ The following modes are supported:
|
|
1734
1362
|
color and Unicode box drawing characters to show page usage throughout
|
1735
1363
|
the space.
|
1736
1364
|
|
1737
|
-
space-extents-illustrate-svg
|
1738
|
-
Iterate through all extents, illustrating the extent usage in SVG format
|
1739
|
-
printed to stdout to show page usage throughout the space.
|
1740
|
-
|
1741
1365
|
space-lsn-age-illustrate
|
1742
1366
|
Iterate through all pages, producing a heat map colored by the page LSN
|
1743
1367
|
using ANSI color and Unicode box drawing characters, allowing the user to
|
1744
1368
|
get an overview of page modification recency.
|
1745
1369
|
|
1746
|
-
space-lsn-age-illustrate-svg
|
1747
|
-
Iterate through all pages, producing a heat map colored by the page LSN
|
1748
|
-
producing SVG format output, allowing the user to get an overview of page
|
1749
|
-
modification recency.
|
1750
|
-
|
1751
1370
|
space-inodes-fseg-id
|
1752
1371
|
Iterate through all inodes, printing only the FSEG ID.
|
1753
1372
|
|
@@ -1785,7 +1404,7 @@ The following modes are supported:
|
|
1785
1404
|
Iterate the file segment list (whose name is provided in the first --list/-L
|
1786
1405
|
argument) for internal or leaf pages for a given index (whose root page
|
1787
1406
|
is provided in the first --page/-p argument). The lists used for each
|
1788
|
-
index are
|
1407
|
+
index are 'full', 'not_full', and 'free'.
|
1789
1408
|
|
1790
1409
|
index-fseg-internal-frag-pages
|
1791
1410
|
index-fseg-leaf-frag-pages
|
@@ -1793,7 +1412,7 @@ The following modes are supported:
|
|
1793
1412
|
page must be provided with --page/-p.
|
1794
1413
|
|
1795
1414
|
page-dump
|
1796
|
-
Dump the contents of a page, using the Ruby pp (
|
1415
|
+
Dump the contents of a page, using the Ruby pp ('pretty-print') module.
|
1797
1416
|
|
1798
1417
|
page-account
|
1799
1418
|
Account for a page's usage in FSEGs.
|
@@ -1827,6 +1446,7 @@ The following modes are supported:
|
|
1827
1446
|
A record offset must be provided with -R/--record.
|
1828
1447
|
|
1829
1448
|
END_OF_USAGE
|
1449
|
+
# rubocop:enable Layout/HeredocIndentation
|
1830
1450
|
|
1831
1451
|
exit exit_code
|
1832
1452
|
end
|
@@ -1849,6 +1469,7 @@ Signal.trap("PIPE") { exit }
|
|
1849
1469
|
@options.illustration_line_width = 64
|
1850
1470
|
@options.illustration_block_size = 8
|
1851
1471
|
|
1472
|
+
# rubocop:disable Layout/SpaceInsideArrayLiteralBrackets
|
1852
1473
|
getopt_options = [
|
1853
1474
|
[ "--help", "-?", GetoptLong::NO_ARGUMENT ],
|
1854
1475
|
[ "--trace", "-t", GetoptLong::NO_ARGUMENT ],
|
@@ -1866,6 +1487,7 @@ getopt_options = [
|
|
1866
1487
|
[ "--illustration-line-width", GetoptLong::REQUIRED_ARGUMENT ],
|
1867
1488
|
[ "--illustration-block-size", GetoptLong::REQUIRED_ARGUMENT ],
|
1868
1489
|
]
|
1490
|
+
# rubocop:enable Layout/SpaceInsideArrayLiteralBrackets
|
1869
1491
|
|
1870
1492
|
getopt = GetoptLong.new(*getopt_options)
|
1871
1493
|
|
@@ -1904,17 +1526,17 @@ getopt.each do |opt, arg|
|
|
1904
1526
|
end
|
1905
1527
|
end
|
1906
1528
|
|
1907
|
-
|
1529
|
+
# rubocop:disable Style/IfUnlessModifier
|
1530
|
+
|
1531
|
+
unless @options.system_space_file || @options.space_file
|
1908
1532
|
usage 1, "System space file (-s) or space file (-f) must be specified"
|
1909
1533
|
end
|
1910
1534
|
|
1911
|
-
if @options.system_space_file
|
1535
|
+
if @options.system_space_file && @options.space_file
|
1912
1536
|
usage 1, "Only one of system space or space file may be specified"
|
1913
1537
|
end
|
1914
1538
|
|
1915
|
-
if @options.trace > 1
|
1916
|
-
BufferCursor.trace!
|
1917
|
-
end
|
1539
|
+
BufferCursor.trace! if @options.trace > 1
|
1918
1540
|
|
1919
1541
|
# A few globals that we'll try to populate from the command-line arguments.
|
1920
1542
|
innodb_system = nil
|
@@ -1926,7 +1548,7 @@ if @options.system_space_file
|
|
1926
1548
|
innodb_system = Innodb::System.new(@options.system_space_file)
|
1927
1549
|
end
|
1928
1550
|
|
1929
|
-
if innodb_system
|
1551
|
+
if innodb_system && @options.table_name
|
1930
1552
|
table_tablespace = innodb_system.space_by_table_name(@options.table_name)
|
1931
1553
|
space = table_tablespace || innodb_system.system_space
|
1932
1554
|
elsif @options.space_file
|
@@ -1936,24 +1558,17 @@ else
|
|
1936
1558
|
end
|
1937
1559
|
|
1938
1560
|
if @options.describer
|
1939
|
-
describer = eval(@options.describer)
|
1940
|
-
|
1941
|
-
describer = Innodb::RecordDescriber.const_get(@options.describer)
|
1942
|
-
end
|
1561
|
+
describer = eval(@options.describer) # rubocop:disable Security/Eval
|
1562
|
+
describer ||= Innodb::RecordDescriber.const_get(@options.describer)
|
1943
1563
|
space.record_describer = describer.new
|
1944
1564
|
end
|
1945
1565
|
|
1946
|
-
if innodb_system
|
1566
|
+
if innodb_system && @options.table_name && @options.index_name
|
1947
1567
|
index = innodb_system.index_by_name(@options.table_name, @options.index_name)
|
1948
|
-
|
1949
|
-
page = space.page(@options.page)
|
1950
|
-
else
|
1951
|
-
page = index.root
|
1952
|
-
end
|
1568
|
+
page = @options.page ? space.page(@options.page) : index.root
|
1953
1569
|
elsif @options.page
|
1954
|
-
|
1955
|
-
|
1956
|
-
end
|
1570
|
+
page = space.page(@options.page)
|
1571
|
+
index = space.index(@options.page) if page&.type == :INDEX && page&.root?
|
1957
1572
|
end
|
1958
1573
|
|
1959
1574
|
# The non-option argument on the command line is the mode (usually the last,
|
@@ -1961,53 +1576,63 @@ end
|
|
1961
1576
|
mode = ARGV.shift
|
1962
1577
|
|
1963
1578
|
unless mode
|
1964
|
-
usage
|
1579
|
+
usage(1, "At least one mode must be provided")
|
1965
1580
|
end
|
1966
1581
|
|
1967
|
-
if /^(system-|data-dictionary-)/.match(mode)
|
1968
|
-
usage
|
1582
|
+
if /^(system-|data-dictionary-)/.match(mode) && !innodb_system
|
1583
|
+
usage(1, "System tablespace must be specified using -s/--system-space-file")
|
1969
1584
|
end
|
1970
1585
|
|
1971
|
-
if /^space-/.match(mode)
|
1972
|
-
usage
|
1586
|
+
if /^space-/.match(mode) && !space
|
1587
|
+
usage(
|
1588
|
+
1,
|
1589
|
+
"Tablespace must be specified using either -f/--space-file " \
|
1590
|
+
"or a combination of -s/--system-space-file and -T/--table"
|
1591
|
+
)
|
1973
1592
|
end
|
1974
1593
|
|
1975
|
-
if /^index-/.match(mode)
|
1976
|
-
usage
|
1594
|
+
if /^index-/.match(mode) && !index
|
1595
|
+
usage(
|
1596
|
+
1,
|
1597
|
+
"Index must be specified using a combination of either -f/--space-file and -p/--page " \
|
1598
|
+
"or -s/--system-space-file, -T/--table-name, and -I/--index-name"
|
1599
|
+
)
|
1977
1600
|
end
|
1978
1601
|
|
1979
|
-
if /^page-/.match(mode)
|
1980
|
-
usage
|
1602
|
+
if /^page-/.match(mode) && !page
|
1603
|
+
usage(1, "Page number must be specified using -p/--page")
|
1981
1604
|
end
|
1982
1605
|
|
1983
|
-
if /^record-/.match(mode)
|
1984
|
-
usage
|
1606
|
+
if /^record-/.match(mode) && !@options.record
|
1607
|
+
usage(1, "Record offset must be specified using -R/--record")
|
1985
1608
|
end
|
1986
1609
|
|
1987
|
-
if /-list-iterate$/.match(mode)
|
1988
|
-
usage
|
1610
|
+
if /-list-iterate$/.match(mode) && !@options.list
|
1611
|
+
usage(1, "List name must be specified using -L/--list")
|
1989
1612
|
end
|
1990
1613
|
|
1991
|
-
if /-level-/.match(mode)
|
1992
|
-
usage
|
1614
|
+
if /-level-/.match(mode) && !@options.level
|
1615
|
+
usage(1, "Level must be specified using -l/--level")
|
1993
1616
|
end
|
1994
1617
|
|
1995
|
-
if [
|
1996
|
-
|
1997
|
-
|
1998
|
-
|
1999
|
-
|
2000
|
-
].include?(mode)
|
2001
|
-
usage
|
1618
|
+
if %w[
|
1619
|
+
index-recurse
|
1620
|
+
index-record-offsets
|
1621
|
+
index-digraph
|
1622
|
+
index-level-summary
|
1623
|
+
].include?(mode) && !index.record_describer
|
1624
|
+
usage(1, "Record describer must be specified using -d/--describer")
|
2002
1625
|
end
|
2003
1626
|
|
2004
|
-
if [
|
2005
|
-
|
1627
|
+
if %w[
|
1628
|
+
space-index-fseg-pages-summary
|
1629
|
+
].include?(mode) && !@options.fseg_id
|
1630
|
+
usage(1, "File segment id must be specified using -F/--fseg-id")
|
2006
1631
|
end
|
2007
1632
|
|
2008
|
-
|
2009
|
-
|
2010
|
-
|
1633
|
+
# rubocop:enable Style/IfUnlessModifier
|
1634
|
+
|
1635
|
+
BufferCursor.trace! if @options.trace.positive?
|
2011
1636
|
|
2012
1637
|
case mode
|
2013
1638
|
when "system-spaces"
|
@@ -2027,8 +1652,7 @@ when "space-index-pages-summary"
|
|
2027
1652
|
when "space-index-fseg-pages-summary"
|
2028
1653
|
space_index_fseg_pages_summary(space, @options.fseg_id)
|
2029
1654
|
when "space-index-pages-free-plot"
|
2030
|
-
|
2031
|
-
space_index_pages_free_plot(space, file_name, @options.page || 0)
|
1655
|
+
space_index_pages_free_plot(space, @options.page || 0)
|
2032
1656
|
when "space-page-type-regions"
|
2033
1657
|
space_page_type_regions(space, @options.page || 0)
|
2034
1658
|
when "space-page-type-summary"
|
@@ -2043,12 +1667,8 @@ when "space-extents"
|
|
2043
1667
|
space_extents(space)
|
2044
1668
|
when "space-extents-illustrate"
|
2045
1669
|
space_extents_illustrate(space)
|
2046
|
-
when "space-extents-illustrate-svg"
|
2047
|
-
space_extents_illustrate_svg(space)
|
2048
1670
|
when "space-lsn-age-illustrate"
|
2049
1671
|
space_lsn_age_illustrate(space)
|
2050
|
-
when "space-lsn-age-illustrate-svg"
|
2051
|
-
space_lsn_age_illustrate_svg(space)
|
2052
1672
|
when "space-inodes-fseg-id"
|
2053
1673
|
space_inodes_fseg_id(space)
|
2054
1674
|
when "space-inodes-summary"
|