innodb_ruby 0.9.0 → 0.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|