innodb_ruby 0.9.0 → 0.9.5
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/innodb_log +100 -34
- data/bin/innodb_space +288 -9
- data/lib/innodb.rb +10 -0
- data/lib/innodb/data_dictionary.rb +8 -8
- data/lib/innodb/data_type.rb +49 -0
- data/lib/innodb/field.rb +21 -11
- data/lib/innodb/history.rb +30 -0
- data/lib/innodb/history_list.rb +106 -0
- data/lib/innodb/index.rb +49 -57
- data/lib/innodb/inode.rb +11 -1
- data/lib/innodb/list.rb +45 -23
- data/lib/innodb/log.rb +22 -11
- data/lib/innodb/log_block.rb +52 -82
- data/lib/innodb/log_group.rb +59 -54
- data/lib/innodb/log_reader.rb +116 -0
- data/lib/innodb/log_record.rb +317 -0
- data/lib/innodb/lsn.rb +103 -0
- data/lib/innodb/page.rb +39 -5
- data/lib/innodb/page/blob.rb +26 -0
- data/lib/innodb/page/fsp_hdr_xdes.rb +38 -6
- data/lib/innodb/page/index.rb +176 -96
- data/lib/innodb/page/inode.rb +33 -1
- data/lib/innodb/page/sys_data_dictionary_header.rb +19 -0
- data/lib/innodb/page/sys_rseg_header.rb +41 -2
- data/lib/innodb/page/trx_sys.rb +69 -1
- data/lib/innodb/record.rb +37 -0
- data/lib/innodb/space.rb +28 -4
- data/lib/innodb/system.rb +4 -0
- data/lib/innodb/undo_log.rb +84 -24
- data/lib/innodb/undo_record.rb +259 -0
- data/lib/innodb/{cursor.rb → util/buffer_cursor.rb} +135 -29
- data/lib/innodb/util/read_bits_at_offset.rb +8 -0
- data/lib/innodb/version.rb +1 -1
- data/lib/innodb/xdes.rb +2 -0
- metadata +10 -3
data/bin/innodb_log
CHANGED
@@ -6,52 +6,101 @@ require "ostruct"
|
|
6
6
|
require "set"
|
7
7
|
require "innodb"
|
8
8
|
|
9
|
-
def log_summary(
|
10
|
-
puts "%-
|
9
|
+
def log_summary(log_group)
|
10
|
+
puts "%-20s%-15s%-10s%-12s%-10s" % [
|
11
|
+
"lsn",
|
11
12
|
"block",
|
13
|
+
"length",
|
14
|
+
"first_rec",
|
15
|
+
"checkpoint",
|
16
|
+
]
|
17
|
+
lsn = log_group.start_lsn.first
|
18
|
+
log_group.each_block do |block_index, block|
|
19
|
+
header = block.header
|
20
|
+
puts "%-20i%-15i%-10i%-12i%-10i" % [
|
21
|
+
lsn,
|
22
|
+
header[:block_number],
|
23
|
+
header[:data_length],
|
24
|
+
header[:first_rec_group],
|
25
|
+
header[:checkpoint_no],
|
26
|
+
]
|
27
|
+
block.dump if @options.dump
|
28
|
+
lsn += Innodb::LogBlock::BLOCK_SIZE
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def log_reader_record_summary(reader, follow)
|
33
|
+
puts "%-10s%-10s%-20s%-10s%-10s%-10s" % [
|
34
|
+
"time",
|
35
|
+
"lsn",
|
12
36
|
"type",
|
37
|
+
"size",
|
13
38
|
"space",
|
14
|
-
"page"
|
39
|
+
"page"
|
15
40
|
]
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
block.dump
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
41
|
+
|
42
|
+
reader.each_record(follow) do |rec|
|
43
|
+
preamble = rec.preamble.dup
|
44
|
+
preamble.default = ""
|
45
|
+
puts "%-10s%-10i%-20s%-10i%-10s%-10s" % [
|
46
|
+
(Time.now.strftime "%H:%M:%S"),
|
47
|
+
rec.lsn.first,
|
48
|
+
preamble[:type].to_s,
|
49
|
+
rec.size,
|
50
|
+
rec.preamble[:space].to_s,
|
51
|
+
rec.preamble[:page_number].to_s,
|
52
|
+
]
|
32
53
|
end
|
33
54
|
end
|
34
55
|
|
56
|
+
def log_follow_tail_summary(log_group)
|
57
|
+
reader = log_group.reader(log_group.max_checkpoint_lsn)
|
58
|
+
reader.checksum = true
|
59
|
+
log_reader_record_summary(reader, true)
|
60
|
+
end
|
61
|
+
|
62
|
+
def log_record_summary(log_group, lsn_no)
|
63
|
+
reader = log_group.reader(log_group.start_lsn)
|
64
|
+
reader.seek(lsn_no)
|
65
|
+
log_reader_record_summary(reader, false)
|
66
|
+
end
|
67
|
+
|
68
|
+
def record_dump(log_group, lsn)
|
69
|
+
log_group.record(lsn).dump
|
70
|
+
end
|
71
|
+
|
35
72
|
def usage(exit_code, message = nil)
|
36
73
|
print "Error: #{message}\n" unless message.nil?
|
37
74
|
|
38
75
|
print <<'END_OF_USAGE'
|
39
76
|
|
40
|
-
Usage: innodb_log [-d] [-s] <file>
|
77
|
+
Usage: innodb_log [-d] [-s] -f <log file> <mode>
|
41
78
|
|
42
79
|
--help, -?
|
43
80
|
Print this usage text.
|
44
81
|
|
82
|
+
--log-file, -f
|
83
|
+
Load a InnoDB redo log file. Repeat for each log file in the log group.
|
84
|
+
|
45
85
|
--dump-blocks, -d
|
46
86
|
Dump block header, trailer, and record.
|
47
87
|
|
48
|
-
--
|
49
|
-
|
88
|
+
--lsn <number>, -l
|
89
|
+
Use the log sequence number <number>.
|
50
90
|
|
51
91
|
The following modes are supported:
|
52
92
|
|
53
|
-
log-summary
|
54
|
-
A summary of
|
93
|
+
log-summary
|
94
|
+
A summary of each block within the logs.
|
95
|
+
|
96
|
+
log-follow-tail-summary
|
97
|
+
Follow the tail of the log and print a summary of each newly logged record.
|
98
|
+
|
99
|
+
log-record-summary
|
100
|
+
Print a summary of each log record following a given LSN.
|
101
|
+
|
102
|
+
record-dump
|
103
|
+
Dump the contents of a log record, using the Ruby pp ("pretty-print") module.
|
55
104
|
|
56
105
|
END_OF_USAGE
|
57
106
|
|
@@ -59,13 +108,15 @@ END_OF_USAGE
|
|
59
108
|
end
|
60
109
|
|
61
110
|
@options = OpenStruct.new
|
111
|
+
@options.log_files = []
|
62
112
|
@options.dump = false
|
63
|
-
@options.
|
113
|
+
@options.lsn = nil
|
64
114
|
|
65
115
|
getopt_options = [
|
66
116
|
[ "--help", "-?", GetoptLong::NO_ARGUMENT ],
|
117
|
+
[ "--log-file", "-f", GetoptLong::REQUIRED_ARGUMENT ],
|
67
118
|
[ "--dump-blocks", "-d", GetoptLong::NO_ARGUMENT ],
|
68
|
-
[ "--
|
119
|
+
[ "--lsn", "-l", GetoptLong::REQUIRED_ARGUMENT ],
|
69
120
|
]
|
70
121
|
|
71
122
|
getopt = GetoptLong.new(*getopt_options)
|
@@ -74,25 +125,40 @@ getopt.each do |opt, arg|
|
|
74
125
|
case opt
|
75
126
|
when "--help"
|
76
127
|
usage 0
|
128
|
+
when "--log-file"
|
129
|
+
@options.log_files << arg
|
77
130
|
when "--dump-blocks"
|
78
131
|
@options.dump = true
|
79
|
-
when "--
|
80
|
-
@options.
|
132
|
+
when "--lsn"
|
133
|
+
@options.lsn = arg.to_i
|
81
134
|
end
|
82
135
|
end
|
83
136
|
|
84
|
-
|
85
|
-
|
86
|
-
|
137
|
+
mode = ARGV.shift
|
138
|
+
|
139
|
+
unless mode
|
140
|
+
usage 1, "At least one mode must be provided"
|
141
|
+
end
|
142
|
+
|
143
|
+
if @options.log_files.empty?
|
144
|
+
usage 1, "At least one log file (-f) must be specified"
|
87
145
|
end
|
88
146
|
|
89
|
-
log
|
147
|
+
if /^(log-)?record-/.match(mode) and !@options.lsn
|
148
|
+
usage 1, "LSN must be specified using -l/--lsn"
|
149
|
+
end
|
90
150
|
|
91
|
-
|
151
|
+
log_group = Innodb::LogGroup.new(@options.log_files.sort)
|
92
152
|
|
93
153
|
case mode
|
94
154
|
when "log-summary"
|
95
|
-
log_summary(
|
155
|
+
log_summary(log_group)
|
156
|
+
when "log-follow-tail-summary"
|
157
|
+
log_follow_tail_summary(log_group)
|
158
|
+
when "log-record-summary"
|
159
|
+
log_record_summary(log_group, @options.lsn)
|
160
|
+
when "record-dump"
|
161
|
+
record_dump(log_group, @options.lsn)
|
96
162
|
else
|
97
163
|
usage 1, "Unknown mode: #{mode}"
|
98
164
|
end
|
data/bin/innodb_space
CHANGED
@@ -5,6 +5,84 @@ require "getoptlong"
|
|
5
5
|
require "ostruct"
|
6
6
|
require "innodb"
|
7
7
|
|
8
|
+
# Convert a floating point RGB array into an ANSI color number approximating it.
|
9
|
+
def rgb_to_ansi(rgb)
|
10
|
+
rgb_n = rgb.map { |c| (c * 5.0).round }
|
11
|
+
16 + (rgb_n[0] * 36) + (rgb_n[1] * 6) + rgb_n[2]
|
12
|
+
end
|
13
|
+
|
14
|
+
# Interpolate intermediate float-arrays between two float-arrays. Do not
|
15
|
+
# include the points a and b in the result.
|
16
|
+
def interpolate(a, b, count)
|
17
|
+
deltas = a.each_index.map { |i| b[i] - a[i] }
|
18
|
+
steps = a.each_index.map { |i| deltas[i].to_f / (count.to_f + 1) }
|
19
|
+
|
20
|
+
count.times.to_a.map { |i| a.each_index.map { |j| a[j] + ((i+1).to_f * steps[j]) } }
|
21
|
+
end
|
22
|
+
|
23
|
+
# Interpolate intermediate float-arrays between each step in a sequence of
|
24
|
+
# float-arrays. Include each step in the sequence.
|
25
|
+
def interpolate_sequence(sequence, count)
|
26
|
+
result = []
|
27
|
+
result << sequence.first
|
28
|
+
(sequence.size-1).times.map { |n| [sequence[n], sequence[n+1]] }.each do |from, to|
|
29
|
+
interpolate(from, to, count).each do |step|
|
30
|
+
result << step
|
31
|
+
end
|
32
|
+
result << to
|
33
|
+
end
|
34
|
+
|
35
|
+
result
|
36
|
+
end
|
37
|
+
|
38
|
+
# The RGB values of the typical heatmap progression.
|
39
|
+
HEATMAP_PROGRESSION = [
|
40
|
+
[0.0, 0.0, 0.0], # Black
|
41
|
+
[0.0, 0.0, 1.0], # Blue
|
42
|
+
[0.0, 1.0, 1.0], # Cyan
|
43
|
+
[0.0, 1.0, 0.0], # Green
|
44
|
+
[1.0, 1.0, 0.0], # Yellow
|
45
|
+
[1.0, 0.0, 0.0], # Red
|
46
|
+
[1.0, 0.0, 1.0], # Purple
|
47
|
+
]
|
48
|
+
|
49
|
+
# Typical heatmap color progression.
|
50
|
+
ANSI_COLORS_HEATMAP = interpolate_sequence(HEATMAP_PROGRESSION, 6).map { |rgb| rgb_to_ansi(rgb) }
|
51
|
+
|
52
|
+
# The 24-step grayscale progression.
|
53
|
+
ANSI_COLORS_GRAYSCALE = (0xe8..0xff).to_a
|
54
|
+
|
55
|
+
# Return the text supplied with ANSI 256-color coloring applied.
|
56
|
+
def ansi_color(color, text)
|
57
|
+
"\x1b[38;5;#{color}m#{text}\x1b[0m"
|
58
|
+
end
|
59
|
+
|
60
|
+
# Zero and 1/8 through 8/8 illustrations.
|
61
|
+
BLOCK_CHARS_V = ["░", "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"]
|
62
|
+
BLOCK_CHARS_H = ["░", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█"]
|
63
|
+
|
64
|
+
# A reasonably large prime number to multiply identifiers by in order to
|
65
|
+
# space out the colors used for similar identifiers.
|
66
|
+
COLOR_SPACING_PRIME = 999983
|
67
|
+
|
68
|
+
# Return a string with a possibly colored filled block for use in printing
|
69
|
+
# to an ANSI-capable Unicode-enabled terminal.
|
70
|
+
def filled_block(fraction, identifier=nil, block_chars=BLOCK_CHARS_V)
|
71
|
+
if fraction == 0.0
|
72
|
+
block = block_chars[0]
|
73
|
+
else
|
74
|
+
parts = (fraction.to_f * (block_chars.size.to_f-1)).floor
|
75
|
+
block = block_chars[[block_chars.size-1, parts+1].min]
|
76
|
+
end
|
77
|
+
if identifier
|
78
|
+
# ANSI 256-color mode, color palette starts at 10 and contains 216 colors.
|
79
|
+
color = 16 + ((identifier * COLOR_SPACING_PRIME) % 216)
|
80
|
+
ansi_color(color, block)
|
81
|
+
else
|
82
|
+
block
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
8
86
|
# Print metadata about each list in an array of InnoDB::List objects.
|
9
87
|
def print_lists(lists)
|
10
88
|
puts "%-20s%-12s%-12s%-12s%-12s%-12s" % [
|
@@ -30,7 +108,7 @@ end
|
|
30
108
|
|
31
109
|
# Print a page usage bitmap for each extent descriptor in an array of
|
32
110
|
# Innodb::XdesEntry objects.
|
33
|
-
def print_xdes_list(list)
|
111
|
+
def print_xdes_list(space, list)
|
34
112
|
puts "%-12s%-64s" % [
|
35
113
|
"start_page",
|
36
114
|
"page_used_bitmap"
|
@@ -40,7 +118,9 @@ def print_xdes_list(list)
|
|
40
118
|
puts "%-12i%-64s" % [
|
41
119
|
entry.xdes[:start_page],
|
42
120
|
entry.each_page_status.inject("") { |bitmap, (page_number, page_status)|
|
43
|
-
|
121
|
+
if page_number < space.pages
|
122
|
+
bitmap += page_status[:free] ? "." : "#"
|
123
|
+
end
|
44
124
|
bitmap
|
45
125
|
},
|
46
126
|
]
|
@@ -278,7 +358,7 @@ def space_list_iterate(space, list_name)
|
|
278
358
|
|
279
359
|
case fsp[list_name]
|
280
360
|
when Innodb::List::Xdes
|
281
|
-
print_xdes_list(fsp[list_name])
|
361
|
+
print_xdes_list(space, fsp[list_name])
|
282
362
|
when Innodb::List::Inode
|
283
363
|
puts "%-12s" % [
|
284
364
|
"page",
|
@@ -364,7 +444,144 @@ def space_index_pages_free_plot(space, image, start_page)
|
|
364
444
|
end
|
365
445
|
|
366
446
|
def space_extents(space)
|
367
|
-
print_xdes_list(space.each_xdes)
|
447
|
+
print_xdes_list(space, space.each_xdes)
|
448
|
+
end
|
449
|
+
|
450
|
+
# Illustrate the space by printing each extent and for each page, printing a
|
451
|
+
# filled block colored based on the index the page is part of. Print a legend
|
452
|
+
# for the colors used afterwards.
|
453
|
+
def space_extents_illustrate(space)
|
454
|
+
puts
|
455
|
+
puts "%12s ╭%-64s╮" % [ "Start Page", "─" * 64 ]
|
456
|
+
|
457
|
+
identifiers = {}
|
458
|
+
|
459
|
+
space.each_xdes do |entry|
|
460
|
+
puts "%12i │%-64s│" % [
|
461
|
+
entry.xdes[:start_page],
|
462
|
+
entry.each_page_status.inject("") { |bitmap, (page_number, page_status)|
|
463
|
+
if page_number < space.pages
|
464
|
+
used_fraction = 1.0
|
465
|
+
identifier = nil
|
466
|
+
if page_status[:free]
|
467
|
+
used_fraction = 0.0
|
468
|
+
else
|
469
|
+
page = space.page(page_number)
|
470
|
+
if page.respond_to?(:used_space)
|
471
|
+
used_fraction = page.used_space.to_f / page.size.to_f
|
472
|
+
end
|
473
|
+
if page.respond_to?(:index_id)
|
474
|
+
identifier = page.index_id
|
475
|
+
unless identifiers[identifier]
|
476
|
+
identifiers[identifier] = "Index #{page.index_id}"
|
477
|
+
if space.innodb_system
|
478
|
+
table, index = space.innodb_system.table_and_index_name_by_id(page.index_id)
|
479
|
+
if table && index
|
480
|
+
identifiers[identifier] += " (%s.%s)" % [table, index]
|
481
|
+
end
|
482
|
+
end
|
483
|
+
end
|
484
|
+
end
|
485
|
+
end
|
486
|
+
bitmap += filled_block(used_fraction, identifier)
|
487
|
+
else
|
488
|
+
bitmap += " "
|
489
|
+
end
|
490
|
+
bitmap
|
491
|
+
},
|
492
|
+
]
|
493
|
+
end
|
494
|
+
|
495
|
+
puts "%12s ╰%-64s╯" % [ "", "─" * 64 ]
|
496
|
+
|
497
|
+
puts
|
498
|
+
puts "Legend:"
|
499
|
+
puts " %s %s" % [filled_block(1.0, nil), "System"]
|
500
|
+
identifiers.sort.each do |identifier, description|
|
501
|
+
puts " %s %s" % [filled_block(1.0, identifier), description]
|
502
|
+
end
|
503
|
+
puts " %s %s" % [filled_block(0.0, nil), "Free space"]
|
504
|
+
puts
|
505
|
+
end
|
506
|
+
|
507
|
+
def space_lsn_age_illustrate(space)
|
508
|
+
colors = ANSI_COLORS_HEATMAP
|
509
|
+
|
510
|
+
# Calculate the minimum and maximum LSN in the space. This is pretty
|
511
|
+
# inefficient as we end up scanning all pages twice.
|
512
|
+
page_lsn = Array.new(space.pages)
|
513
|
+
|
514
|
+
lsn_min = lsn_max = space.page(0).lsn
|
515
|
+
space.each_page do |page_number, page|
|
516
|
+
if page.lsn != 0
|
517
|
+
page_lsn[page_number] = page.lsn
|
518
|
+
lsn_min = page.lsn < lsn_min ? page.lsn : lsn_min
|
519
|
+
lsn_max = page.lsn > lsn_max ? page.lsn : lsn_max
|
520
|
+
end
|
521
|
+
end
|
522
|
+
lsn_delta = lsn_max - lsn_min
|
523
|
+
|
524
|
+
puts
|
525
|
+
puts "%12s ╭%-64s╮" % [ "Start Page", "─" * 64 ]
|
526
|
+
|
527
|
+
start_page = 0
|
528
|
+
page_lsn.each_slice(64) do |slice|
|
529
|
+
puts "%12i │%-64s│" % [
|
530
|
+
start_page,
|
531
|
+
slice.inject("") { |line, lsn|
|
532
|
+
if lsn
|
533
|
+
age_ratio = (lsn - lsn_min).to_f / lsn_delta.to_f
|
534
|
+
color = colors[(age_ratio * colors.size.to_f).floor]
|
535
|
+
line += ansi_color(color, filled_block(1.0, nil))
|
536
|
+
else
|
537
|
+
line += " "
|
538
|
+
end
|
539
|
+
line
|
540
|
+
},
|
541
|
+
]
|
542
|
+
start_page += 64
|
543
|
+
end
|
544
|
+
|
545
|
+
puts "%12s ╰%-64s╯" % [ "", "─" * 64 ]
|
546
|
+
|
547
|
+
lsn_legend = "<" + ("─" * (colors.size - 2)) + ">"
|
548
|
+
|
549
|
+
begin
|
550
|
+
# Try to optionally replace the boring lsn_legend with a histogram of
|
551
|
+
# page age distribution. If histogram/array is not available, move on.
|
552
|
+
|
553
|
+
require 'histogram/array'
|
554
|
+
|
555
|
+
lsn_bins, lsn_freq = page_lsn.select { |lsn| !lsn.nil? }.
|
556
|
+
histogram(colors.size, :min => lsn_min, :max => lsn_max)
|
557
|
+
|
558
|
+
lsn_freq_delta = lsn_freq.max - lsn_freq.min
|
559
|
+
|
560
|
+
lsn_legend = ""
|
561
|
+
lsn_freq.each do |freq|
|
562
|
+
freq_norm = freq / lsn_freq_delta
|
563
|
+
if freq_norm > 0.0
|
564
|
+
lsn_legend << filled_block(freq_norm)
|
565
|
+
else
|
566
|
+
# Avoid the "empty" block used for 0.0.
|
567
|
+
lsn_legend << " "
|
568
|
+
end
|
569
|
+
end
|
570
|
+
rescue LoadError
|
571
|
+
# That's okay! Leave the legend boring.
|
572
|
+
end
|
573
|
+
|
574
|
+
puts
|
575
|
+
puts "Legend:"
|
576
|
+
puts " %12s %s %-12s" % [
|
577
|
+
"Min LSN",
|
578
|
+
lsn_legend,
|
579
|
+
"Max LSN" ]
|
580
|
+
puts " %12i %s %-12i" % [
|
581
|
+
lsn_min,
|
582
|
+
colors.map { |c| ansi_color(c, filled_block(1.0, nil)) }.join,
|
583
|
+
lsn_max,
|
584
|
+
]
|
368
585
|
end
|
369
586
|
|
370
587
|
def print_inode_summary(inode)
|
@@ -537,6 +754,59 @@ def page_directory_summary(page_number)
|
|
537
754
|
end
|
538
755
|
end
|
539
756
|
|
757
|
+
def page_illustrate(page)
|
758
|
+
width = 256
|
759
|
+
blocks = Array.new(page.size, " ")
|
760
|
+
identifiers = {}
|
761
|
+
identifier_sort = 0
|
762
|
+
|
763
|
+
page.each_region.sort { |a,b| a[:offset] <=> b[:offset]}.each do |region|
|
764
|
+
region[:length].times do |n|
|
765
|
+
identifier = nil
|
766
|
+
fraction = 0.0
|
767
|
+
if region[:name] != :garbage
|
768
|
+
if n == region[:length] - 1
|
769
|
+
fraction = 0.5
|
770
|
+
else
|
771
|
+
fraction = 1.0
|
772
|
+
end
|
773
|
+
identifier = region[:name].hash.abs
|
774
|
+
unless identifiers[identifier]
|
775
|
+
# Prefix an integer <0123> on each name so that the legend can be
|
776
|
+
# sorted by the appearance of each region in the page.
|
777
|
+
identifiers[identifier] = "<%04i>%s" % [
|
778
|
+
identifier_sort,
|
779
|
+
region[:info]
|
780
|
+
]
|
781
|
+
identifier_sort += 1
|
782
|
+
end
|
783
|
+
end
|
784
|
+
blocks[region[:offset] + n] = filled_block(fraction, identifier, BLOCK_CHARS_H)
|
785
|
+
end
|
786
|
+
end
|
787
|
+
|
788
|
+
puts
|
789
|
+
puts "%12s ╭%-#{width}s╮" % [ "Offset", "─" * width ]
|
790
|
+
offset = 0
|
791
|
+
blocks.each_slice(width) do |slice|
|
792
|
+
puts "%12i │%-s│" % [offset, slice.join]
|
793
|
+
offset += width
|
794
|
+
end
|
795
|
+
puts "%12s ╰%-#{width}s╯" % [ "", "─" * width ]
|
796
|
+
|
797
|
+
puts
|
798
|
+
puts "Legend:"
|
799
|
+
identifiers.sort { |a,b| a[1] <=> b[1] }.each do |identifier, description|
|
800
|
+
puts " %s %s" % [
|
801
|
+
filled_block(1.0, identifier),
|
802
|
+
description.gsub(/^<\d+>/, "")
|
803
|
+
]
|
804
|
+
end
|
805
|
+
puts " %s %s" % [filled_block(0.0, nil), "Garbage"]
|
806
|
+
|
807
|
+
puts
|
808
|
+
end
|
809
|
+
|
540
810
|
def index_fseg_lists(index, fseg_name)
|
541
811
|
unless index.fseg(fseg_name)
|
542
812
|
raise "File segment '#{fseg_name}' doesn't exist"
|
@@ -554,7 +824,7 @@ def index_fseg_list_iterate(index, fseg_name, list_name)
|
|
554
824
|
raise "List '#{list_name}' doesn't exist"
|
555
825
|
end
|
556
826
|
|
557
|
-
print_xdes_list(list)
|
827
|
+
print_xdes_list(index.space, list)
|
558
828
|
end
|
559
829
|
|
560
830
|
def index_fseg_frag_pages(index, fseg_name)
|
@@ -787,6 +1057,11 @@ The following modes are supported:
|
|
787
1057
|
space-extents
|
788
1058
|
Iterate through all extents, printing the extent descriptor bitmap.
|
789
1059
|
|
1060
|
+
space-extents-illustrate
|
1061
|
+
Iterate through all extents, illustrating the extent usage using ANSI
|
1062
|
+
color and Unicode box drawing characters to show page usage throughout
|
1063
|
+
the space.
|
1064
|
+
|
790
1065
|
space-inodes-summary
|
791
1066
|
Iterate through all inodes, printing a short summary of each FSEG.
|
792
1067
|
|
@@ -861,9 +1136,9 @@ getopt_options = [
|
|
861
1136
|
[ "--help", "-?", GetoptLong::NO_ARGUMENT ],
|
862
1137
|
[ "--trace", "-t", GetoptLong::NO_ARGUMENT ],
|
863
1138
|
[ "--system-space-file", "-s", GetoptLong::REQUIRED_ARGUMENT ],
|
1139
|
+
[ "--space-file", "-f", GetoptLong::REQUIRED_ARGUMENT ],
|
864
1140
|
[ "--table-name", "-T", GetoptLong::REQUIRED_ARGUMENT ],
|
865
1141
|
[ "--index-name", "-I", GetoptLong::REQUIRED_ARGUMENT ],
|
866
|
-
[ "--space-file", "-f", GetoptLong::REQUIRED_ARGUMENT ],
|
867
1142
|
[ "--page", "-p", GetoptLong::REQUIRED_ARGUMENT ],
|
868
1143
|
[ "--level", "-l", GetoptLong::REQUIRED_ARGUMENT ],
|
869
1144
|
[ "--list", "-L", GetoptLong::REQUIRED_ARGUMENT ],
|
@@ -879,9 +1154,7 @@ getopt.each do |opt, arg|
|
|
879
1154
|
when "--help"
|
880
1155
|
usage 0
|
881
1156
|
when "--trace"
|
882
|
-
|
883
|
-
when "--mode"
|
884
|
-
@options.mode = arg
|
1157
|
+
BufferCursor.trace!
|
885
1158
|
when "--system-space-file"
|
886
1159
|
@options.system_space_file = arg
|
887
1160
|
when "--space-file"
|
@@ -1012,6 +1285,10 @@ when "space-indexes"
|
|
1012
1285
|
space_indexes(innodb_system, space)
|
1013
1286
|
when "space-extents"
|
1014
1287
|
space_extents(space)
|
1288
|
+
when "space-extents-illustrate"
|
1289
|
+
space_extents_illustrate(space)
|
1290
|
+
when "space-lsn-age-illustrate"
|
1291
|
+
space_lsn_age_illustrate(space)
|
1015
1292
|
when "space-inodes-summary"
|
1016
1293
|
space_inodes_summary(space)
|
1017
1294
|
when "space-inodes-detail"
|
@@ -1042,6 +1319,8 @@ when "page-account"
|
|
1042
1319
|
page_account(innodb_system, space, @options.page)
|
1043
1320
|
when "page-directory-summary"
|
1044
1321
|
page_directory_summary(@options.page)
|
1322
|
+
when "page-illustrate"
|
1323
|
+
page_illustrate(space.page(@options.page))
|
1045
1324
|
else
|
1046
1325
|
usage 1, "Unknown mode: #{mode}"
|
1047
1326
|
end
|