innodb_ruby 0.9.13 → 0.9.14
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/innodb_log +1 -1
- data/bin/innodb_space +86 -40
- data/lib/innodb.rb +1 -0
- data/lib/innodb/index.rb +2 -1
- data/lib/innodb/page.rb +192 -40
- data/lib/innodb/page/sys.rb +4 -4
- data/lib/innodb/space.rb +28 -1
- data/lib/innodb/version.rb +1 -1
- metadata +18 -2
data/bin/innodb_log
CHANGED
data/bin/innodb_space
CHANGED
@@ -492,15 +492,15 @@ end
|
|
492
492
|
# filled block colored based on the index the page is part of. Print a legend
|
493
493
|
# for the colors used afterwards.
|
494
494
|
def space_extents_illustrate(space)
|
495
|
-
|
495
|
+
line_width = space.pages_per_extent
|
496
496
|
puts
|
497
|
-
puts "%12s ╭%-#{
|
497
|
+
puts "%12s ╭%-#{line_width}s╮" % [ "Start Page", "─" * line_width ]
|
498
498
|
|
499
499
|
identifiers = {}
|
500
500
|
count_by_identifier = Hash.new(0)
|
501
501
|
|
502
502
|
space.each_xdes do |entry|
|
503
|
-
puts "%12i │%-#{
|
503
|
+
puts "%12i │%-#{line_width}s│" % [
|
504
504
|
entry.xdes[:start_page],
|
505
505
|
entry.each_page_status.inject("") { |bitmap, (page_number, page_status)|
|
506
506
|
if page_number < space.pages
|
@@ -543,7 +543,7 @@ def space_extents_illustrate(space)
|
|
543
543
|
end
|
544
544
|
total_pages = count_by_identifier.values.reduce(:+)
|
545
545
|
|
546
|
-
puts "%12s ╰%-#{
|
546
|
+
puts "%12s ╰%-#{line_width}s╯" % [ "", "─" * line_width ]
|
547
547
|
|
548
548
|
puts
|
549
549
|
puts "Legend (%s = 1 page):" % [filled_block(1.0, nil)]
|
@@ -614,7 +614,8 @@ end
|
|
614
614
|
# filled block colored based on the index the page is part of. Print a legend
|
615
615
|
# for the colors used afterwards.
|
616
616
|
def space_extents_illustrate_svg(space)
|
617
|
-
|
617
|
+
line_width = space.pages_per_extent
|
618
|
+
block_size = @options.illustration_block_size
|
618
619
|
|
619
620
|
puts "<?xml version=\"1.0\"?>"
|
620
621
|
puts "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
|
@@ -622,7 +623,6 @@ def space_extents_illustrate_svg(space)
|
|
622
623
|
identifiers = {}
|
623
624
|
count_by_identifier = Hash.new(0)
|
624
625
|
|
625
|
-
block_size = 16
|
626
626
|
graphic_x = 48
|
627
627
|
graphic_y = 16
|
628
628
|
|
@@ -716,7 +716,7 @@ def space_extents_illustrate_svg(space)
|
|
716
716
|
puts svg_extent_legend(
|
717
717
|
graphic_x + block_x,
|
718
718
|
graphic_y + block_y,
|
719
|
-
block_size
|
719
|
+
block_size
|
720
720
|
)
|
721
721
|
block_y += block_size + 2
|
722
722
|
|
@@ -760,6 +760,7 @@ end
|
|
760
760
|
|
761
761
|
def space_lsn_age_illustrate(space)
|
762
762
|
colors = ANSI_COLORS_HEATMAP
|
763
|
+
line_width = @options.illustration_line_width
|
763
764
|
|
764
765
|
# Calculate the minimum and maximum LSN in the space. This is pretty
|
765
766
|
# inefficient as we end up scanning all pages twice.
|
@@ -776,11 +777,11 @@ def space_lsn_age_illustrate(space)
|
|
776
777
|
lsn_delta = lsn_max - lsn_min
|
777
778
|
|
778
779
|
puts
|
779
|
-
puts "%12s
|
780
|
+
puts "%12s ╭%-#{line_width}s╮" % [ "Start Page", "─" * line_width ]
|
780
781
|
|
781
782
|
start_page = 0
|
782
|
-
page_lsn.each_slice(
|
783
|
-
puts "%12i
|
783
|
+
page_lsn.each_slice(line_width) do |slice|
|
784
|
+
puts "%12i │%-#{line_width}s│" % [
|
784
785
|
start_page,
|
785
786
|
slice.inject("") { |line, lsn|
|
786
787
|
if lsn
|
@@ -793,10 +794,10 @@ def space_lsn_age_illustrate(space)
|
|
793
794
|
line
|
794
795
|
},
|
795
796
|
]
|
796
|
-
start_page +=
|
797
|
+
start_page += line_width
|
797
798
|
end
|
798
799
|
|
799
|
-
puts "%12s
|
800
|
+
puts "%12s ╰%-#{line_width}s╯" % [ "", "─" * line_width ]
|
800
801
|
|
801
802
|
lsn_legend = "<" + ("─" * (colors.size - 2)) + ">"
|
802
803
|
|
@@ -840,6 +841,8 @@ end
|
|
840
841
|
|
841
842
|
def space_lsn_age_illustrate_svg(space)
|
842
843
|
colors = RGBHEX_COLORS_HEATMAP
|
844
|
+
line_width = @options.illustration_line_width
|
845
|
+
block_size = @options.illustration_block_size
|
843
846
|
|
844
847
|
puts "<?xml version=\"1.0\"?>"
|
845
848
|
puts "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
|
@@ -858,7 +861,6 @@ def space_lsn_age_illustrate_svg(space)
|
|
858
861
|
end
|
859
862
|
lsn_delta = lsn_max - lsn_min
|
860
863
|
|
861
|
-
block_size = 16
|
862
864
|
graphic_x = 48
|
863
865
|
graphic_y = 16
|
864
866
|
|
@@ -875,7 +877,7 @@ def space_lsn_age_illustrate_svg(space)
|
|
875
877
|
}, "Page")
|
876
878
|
|
877
879
|
start_page = 0
|
878
|
-
page_lsn.each_slice(
|
880
|
+
page_lsn.each_slice(line_width) do |slice|
|
879
881
|
block_x = 0
|
880
882
|
slice.each do |lsn|
|
881
883
|
rgbhex = ""
|
@@ -900,7 +902,7 @@ def space_lsn_age_illustrate_svg(space)
|
|
900
902
|
"text-anchor" => "end",
|
901
903
|
}, start_page)
|
902
904
|
block_y += block_size
|
903
|
-
start_page +=
|
905
|
+
start_page += line_width
|
904
906
|
end
|
905
907
|
|
906
908
|
puts svg("path", {
|
@@ -910,7 +912,7 @@ def space_lsn_age_illustrate_svg(space)
|
|
910
912
|
"d" => svg_path_rounded_rect(
|
911
913
|
graphic_x,
|
912
914
|
graphic_y,
|
913
|
-
|
915
|
+
line_width * block_size,
|
914
916
|
block_y,
|
915
917
|
4
|
916
918
|
),
|
@@ -1013,6 +1015,42 @@ def page_account(innodb_system, space, page_number)
|
|
1013
1015
|
page_type[:usage],
|
1014
1016
|
]
|
1015
1017
|
|
1018
|
+
if page.corrupt?
|
1019
|
+
puts " Page appears to be corrupt."
|
1020
|
+
puts " Stored checksum is %d, type %s." % [
|
1021
|
+
page.checksum,
|
1022
|
+
page.checksum_type ? page.checksum_type : "unknown",
|
1023
|
+
]
|
1024
|
+
puts " Calculated checksums:"
|
1025
|
+
puts " crc32 %d" % [page.checksum_crc32]
|
1026
|
+
puts " innodb %d" % [page.checksum_innodb]
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
if page.torn?
|
1030
|
+
puts " Page appears to be torn."
|
1031
|
+
puts " Full LSN from header is %d." % [page.lsn]
|
1032
|
+
puts " Low 32 bits of LSN from header is %d, trailer is %d." % [
|
1033
|
+
page.lsn_low32_header,
|
1034
|
+
page.lsn_low32_trailer,
|
1035
|
+
]
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
if page.misplaced?
|
1039
|
+
puts " Page appears to be misplaced."
|
1040
|
+
if page.misplaced_offset?
|
1041
|
+
puts " Requested page %d but offset stored in page is %d." % [
|
1042
|
+
page_number,
|
1043
|
+
page.offset,
|
1044
|
+
]
|
1045
|
+
end
|
1046
|
+
if page.misplaced_space?
|
1047
|
+
puts " Space's ID %d does not match page's stored space ID %d." % [
|
1048
|
+
page.space.space_id,
|
1049
|
+
page.space_id,
|
1050
|
+
]
|
1051
|
+
end
|
1052
|
+
end
|
1053
|
+
|
1016
1054
|
xdes = space.xdes_for_page(page_number)
|
1017
1055
|
puts " Extent descriptor for pages %d-%d is at page %d, offset %d." % [
|
1018
1056
|
xdes.start_page,
|
@@ -1630,30 +1668,34 @@ Signal.trap("INT") { exit }
|
|
1630
1668
|
Signal.trap("PIPE") { exit }
|
1631
1669
|
|
1632
1670
|
@options = OpenStruct.new
|
1633
|
-
@options.trace
|
1634
|
-
@options.system_space_file
|
1635
|
-
@options.space_file
|
1636
|
-
@options.table_name
|
1637
|
-
@options.index_name
|
1638
|
-
@options.page
|
1639
|
-
@options.record
|
1640
|
-
@options.level
|
1641
|
-
@options.list
|
1642
|
-
@options.describer
|
1671
|
+
@options.trace = 0
|
1672
|
+
@options.system_space_file = nil
|
1673
|
+
@options.space_file = nil
|
1674
|
+
@options.table_name = nil
|
1675
|
+
@options.index_name = nil
|
1676
|
+
@options.page = nil
|
1677
|
+
@options.record = nil
|
1678
|
+
@options.level = nil
|
1679
|
+
@options.list = nil
|
1680
|
+
@options.describer = nil
|
1681
|
+
@options.illustration_line_width = 64
|
1682
|
+
@options.illustration_block_size = 8
|
1643
1683
|
|
1644
1684
|
getopt_options = [
|
1645
|
-
[ "--help",
|
1646
|
-
[ "--trace",
|
1647
|
-
[ "--system-space-file",
|
1648
|
-
[ "--space-file",
|
1649
|
-
[ "--table-name",
|
1650
|
-
[ "--index-name",
|
1651
|
-
[ "--page",
|
1652
|
-
[ "--record",
|
1653
|
-
[ "--level",
|
1654
|
-
[ "--list",
|
1655
|
-
[ "--require",
|
1656
|
-
[ "--describer",
|
1685
|
+
[ "--help", "-?", GetoptLong::NO_ARGUMENT ],
|
1686
|
+
[ "--trace", "-t", GetoptLong::NO_ARGUMENT ],
|
1687
|
+
[ "--system-space-file", "-s", GetoptLong::REQUIRED_ARGUMENT ],
|
1688
|
+
[ "--space-file", "-f", GetoptLong::REQUIRED_ARGUMENT ],
|
1689
|
+
[ "--table-name", "-T", GetoptLong::REQUIRED_ARGUMENT ],
|
1690
|
+
[ "--index-name", "-I", GetoptLong::REQUIRED_ARGUMENT ],
|
1691
|
+
[ "--page", "-p", GetoptLong::REQUIRED_ARGUMENT ],
|
1692
|
+
[ "--record", "-R", GetoptLong::REQUIRED_ARGUMENT ],
|
1693
|
+
[ "--level", "-l", GetoptLong::REQUIRED_ARGUMENT ],
|
1694
|
+
[ "--list", "-L", GetoptLong::REQUIRED_ARGUMENT ],
|
1695
|
+
[ "--require", "-r", GetoptLong::REQUIRED_ARGUMENT ],
|
1696
|
+
[ "--describer", "-d", GetoptLong::REQUIRED_ARGUMENT ],
|
1697
|
+
[ "--illustration-line-width", GetoptLong::REQUIRED_ARGUMENT ],
|
1698
|
+
[ "--illustration-block-size", GetoptLong::REQUIRED_ARGUMENT ],
|
1657
1699
|
]
|
1658
1700
|
|
1659
1701
|
getopt = GetoptLong.new(*getopt_options)
|
@@ -1684,6 +1726,10 @@ getopt.each do |opt, arg|
|
|
1684
1726
|
require File.expand_path(arg)
|
1685
1727
|
when "--describer"
|
1686
1728
|
@options.describer = arg
|
1729
|
+
when "--illustration-line-width"
|
1730
|
+
@options.illustration_line_width = arg.to_i
|
1731
|
+
when "--illustration-block-size"
|
1732
|
+
@options.illustration_block_size = arg.to_i
|
1687
1733
|
end
|
1688
1734
|
end
|
1689
1735
|
|
@@ -1804,8 +1850,8 @@ when "space-summary"
|
|
1804
1850
|
when "space-index-pages-summary"
|
1805
1851
|
space_index_pages_summary(space, @options.page || 0)
|
1806
1852
|
when "space-index-pages-free-plot"
|
1807
|
-
|
1808
|
-
space_index_pages_free_plot(space,
|
1853
|
+
file_name = space.name.sub(".ibd", "").sub(/[^a-zA-Z0-9_]/, "_")
|
1854
|
+
space_index_pages_free_plot(space, file_name, @options.page || 0)
|
1809
1855
|
when "space-page-type-regions"
|
1810
1856
|
space_page_type_regions(space, @options.page || 0)
|
1811
1857
|
when "space-page-type-summary"
|
data/lib/innodb.rb
CHANGED
data/lib/innodb/index.rb
CHANGED
data/lib/innodb/page.rb
CHANGED
@@ -19,27 +19,27 @@ class Innodb::Page
|
|
19
19
|
# extract the page type in order to avoid throwing away a generic
|
20
20
|
# Innodb::Page object when parsing every specialized page, but this is
|
21
21
|
# a bit cleaner, and we're not particularly performance sensitive.
|
22
|
-
def self.parse(space, buffer)
|
22
|
+
def self.parse(space, buffer, page_number=nil)
|
23
23
|
# Create a page object as a generic page.
|
24
|
-
page = Innodb::Page.new(space, buffer)
|
24
|
+
page = Innodb::Page.new(space, buffer, page_number)
|
25
25
|
|
26
26
|
# If there is a specialized class available for this page type, re-create
|
27
27
|
# the page object using that specialized class.
|
28
28
|
if specialized_class = SPECIALIZED_CLASSES[page.type]
|
29
|
-
page = specialized_class.handle(page, space, buffer)
|
29
|
+
page = specialized_class.handle(page, space, buffer, page_number)
|
30
30
|
end
|
31
31
|
|
32
32
|
page
|
33
33
|
end
|
34
34
|
|
35
35
|
# Allow the specialized class to do something that isn't 'new' with this page.
|
36
|
-
def self.handle(page, space, buffer)
|
37
|
-
self.new(space, buffer)
|
36
|
+
def self.handle(page, space, buffer, page_number=nil)
|
37
|
+
self.new(space, buffer, page_number)
|
38
38
|
end
|
39
39
|
|
40
40
|
# Initialize a page by passing in a buffer containing the raw page contents.
|
41
41
|
# The buffer size should match the space's page size.
|
42
|
-
def initialize(space, buffer)
|
42
|
+
def initialize(space, buffer, page_number=nil)
|
43
43
|
unless space && buffer
|
44
44
|
raise "Page can't be initialized from nil space or buffer (space: #{space}, buffer: #{buffer})"
|
45
45
|
end
|
@@ -50,6 +50,7 @@ class Innodb::Page
|
|
50
50
|
|
51
51
|
@space = space
|
52
52
|
@buffer = buffer
|
53
|
+
@page_number = page_number
|
53
54
|
end
|
54
55
|
|
55
56
|
attr_reader :space
|
@@ -100,6 +101,20 @@ class Innodb::Page
|
|
100
101
|
4 + 4 + 4 + 4 + 8 + 2 + 8 + 4
|
101
102
|
end
|
102
103
|
|
104
|
+
# The start of the checksummed portion of the file header.
|
105
|
+
def pos_partial_page_header
|
106
|
+
pos_fil_header + 4
|
107
|
+
end
|
108
|
+
|
109
|
+
# The size of the portion of the fil header that is included in the
|
110
|
+
# checksum. Exclude the following:
|
111
|
+
# :checksum (offset 4, size 4)
|
112
|
+
# :flush_lsn (offset 26, size 8)
|
113
|
+
# :space_id (offset 34, size 4)
|
114
|
+
def size_partial_page_header
|
115
|
+
size_fil_header - 4 - 8 - 4
|
116
|
+
end
|
117
|
+
|
103
118
|
# Return the byte offset of the start of the "fil" trailer, which is at
|
104
119
|
# the end of the page.
|
105
120
|
def pos_fil_trailer
|
@@ -117,6 +132,11 @@ class Innodb::Page
|
|
117
132
|
pos_fil_header + size_fil_header
|
118
133
|
end
|
119
134
|
|
135
|
+
# Return the size of the page body, excluding the header and trailer.
|
136
|
+
def size_page_body
|
137
|
+
size - size_fil_trailer - size_fil_header
|
138
|
+
end
|
139
|
+
|
120
140
|
# InnoDB Page Type constants from include/fil0fil.h.
|
121
141
|
PAGE_TYPE = {
|
122
142
|
:ALLOCATED => {
|
@@ -196,7 +216,7 @@ class Innodb::Page
|
|
196
216
|
|
197
217
|
# Return the "fil" header from the page, which is common for all page types.
|
198
218
|
def fil_header
|
199
|
-
@fil_header ||= cursor(pos_fil_header).name("
|
219
|
+
@fil_header ||= cursor(pos_fil_header).name("fil_header") do |c|
|
200
220
|
{
|
201
221
|
:checksum => c.name("checksum") { c.get_uint32 },
|
202
222
|
:offset => c.name("offset") { c.get_uint32 },
|
@@ -214,12 +234,28 @@ class Innodb::Page
|
|
214
234
|
end
|
215
235
|
end
|
216
236
|
|
237
|
+
# Return the "fil" trailer from the page, which is common for all page types.
|
238
|
+
def fil_trailer
|
239
|
+
@fil_trailer ||= cursor(pos_fil_trailer).name("fil_trailer") do |c|
|
240
|
+
{
|
241
|
+
:checksum => c.name("checksum") { c.get_uint32 },
|
242
|
+
:lsn_low32 => c.name("lsn_low32") { c.get_uint32 },
|
243
|
+
}
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
217
247
|
# A helper function to return the checksum from the "fil" header, for easier
|
218
248
|
# access.
|
219
249
|
def checksum
|
220
250
|
fil_header[:checksum]
|
221
251
|
end
|
222
252
|
|
253
|
+
# A helper function to return the checksum from the "fil" trailer, for easier
|
254
|
+
# access.
|
255
|
+
def checksum_trailer
|
256
|
+
fil_trailer[:checksum]
|
257
|
+
end
|
258
|
+
|
223
259
|
# A helper function to return the page offset from the "fil" header, for
|
224
260
|
# easier access.
|
225
261
|
def offset
|
@@ -240,53 +276,161 @@ class Innodb::Page
|
|
240
276
|
fil_header[:next]
|
241
277
|
end
|
242
278
|
|
243
|
-
# A helper function to return the LSN, for easier access.
|
279
|
+
# A helper function to return the LSN from the page header, for easier access.
|
244
280
|
def lsn
|
245
281
|
fil_header[:lsn]
|
246
282
|
end
|
247
283
|
|
284
|
+
# A helper function to return the low 32 bits of the LSN from the page header
|
285
|
+
# for use in comparing to the low 32 bits stored in the trailer.
|
286
|
+
def lsn_low32_header
|
287
|
+
fil_header[:lsn] & 0xffffffff
|
288
|
+
end
|
289
|
+
|
290
|
+
# A helper function to return the low 32 bits of the LSN as stored in the page
|
291
|
+
# trailer.
|
292
|
+
def lsn_low32_trailer
|
293
|
+
fil_trailer[:lsn_low32]
|
294
|
+
end
|
295
|
+
|
248
296
|
# A helper function to return the page type from the "fil" header, for easier
|
249
297
|
# access.
|
250
298
|
def type
|
251
299
|
fil_header[:type]
|
252
300
|
end
|
253
301
|
|
254
|
-
#
|
255
|
-
#
|
256
|
-
|
257
|
-
|
302
|
+
# A helper function to return the space ID from the "fil" header, for easier
|
303
|
+
# access.
|
304
|
+
def space_id
|
305
|
+
fil_header[:space_id]
|
306
|
+
end
|
307
|
+
|
308
|
+
# Iterate each byte of the FIL header.
|
309
|
+
def each_page_header_byte_as_uint8
|
310
|
+
unless block_given?
|
311
|
+
return enum_for(:each_page_header_byte_as_uint8)
|
312
|
+
end
|
313
|
+
|
314
|
+
cursor(pos_partial_page_header).
|
315
|
+
each_byte_as_uint8(size_partial_page_header) do |byte|
|
316
|
+
yield byte
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
# Iterate each byte of the page body, except for the FIL header and
|
321
|
+
# the FIL trailer.
|
322
|
+
def each_page_body_byte_as_uint8
|
323
|
+
unless block_given?
|
324
|
+
return enum_for(:each_page_body_byte_as_uint8)
|
325
|
+
end
|
326
|
+
|
327
|
+
cursor(pos_page_body).
|
328
|
+
each_byte_as_uint8(size_page_body) do |byte|
|
329
|
+
yield byte
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
# Calculate the checksum of the page using InnoDB's algorithm.
|
334
|
+
def checksum_innodb
|
335
|
+
unless size == 16384
|
336
|
+
raise "Checksum calculation is only supported for 16 KiB pages"
|
337
|
+
end
|
338
|
+
|
339
|
+
@checksum_innodb ||= begin
|
340
|
+
# Calculate the InnoDB checksum of the page header.
|
341
|
+
c_partial_header = Innodb::Checksum.fold_enumerator(each_page_header_byte_as_uint8)
|
342
|
+
|
343
|
+
# Calculate the InnoDB checksum of the page body.
|
344
|
+
c_page_body = Innodb::Checksum.fold_enumerator(each_page_body_byte_as_uint8)
|
345
|
+
|
346
|
+
# Add the two checksums together, and mask the result back to 32 bits.
|
347
|
+
(c_partial_header + c_page_body) & Innodb::Checksum::MAX
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def checksum_innodb?
|
352
|
+
checksum == checksum_innodb
|
353
|
+
end
|
354
|
+
|
355
|
+
# Calculate the checksum of the page using the CRC32c algorithm.
|
356
|
+
def checksum_crc32
|
258
357
|
unless size == 16384
|
259
358
|
raise "Checksum calculation is only supported for 16 KiB pages"
|
260
359
|
end
|
261
360
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
361
|
+
@checksum_crc32 ||= begin
|
362
|
+
# Calculate the CRC32c of the page header.
|
363
|
+
crc_partial_header = Digest::CRC32c.new
|
364
|
+
each_page_header_byte_as_uint8 do |byte|
|
365
|
+
crc_partial_header << byte.chr
|
366
|
+
end
|
367
|
+
|
368
|
+
# Calculate the CRC32c of the page body.
|
369
|
+
crc_page_body = Digest::CRC32c.new
|
370
|
+
each_page_body_byte_as_uint8 do |byte|
|
371
|
+
crc_page_body << byte.chr
|
372
|
+
end
|
373
|
+
|
374
|
+
# Bitwise XOR the two checksums together.
|
375
|
+
crc_partial_header.checksum ^ crc_page_body.checksum
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
def checksum_crc32?
|
380
|
+
checksum == checksum_crc32
|
381
|
+
end
|
382
|
+
|
383
|
+
# Is the page checksum correct?
|
384
|
+
def checksum_valid?
|
385
|
+
checksum_crc32? || checksum_innodb?
|
386
|
+
end
|
387
|
+
|
388
|
+
# Is the page checksum incorrect?
|
389
|
+
def checksum_invalid?
|
390
|
+
!checksum_valid?
|
391
|
+
end
|
392
|
+
|
393
|
+
def checksum_type
|
394
|
+
case
|
395
|
+
when checksum_crc32?
|
396
|
+
:crc32
|
397
|
+
when checksum_innodb?
|
398
|
+
:innodb
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
# Is the LSN stored in the header different from the one stored in the
|
403
|
+
# trailer?
|
404
|
+
def torn?
|
405
|
+
lsn_low32_header != lsn_low32_trailer
|
406
|
+
end
|
407
|
+
|
408
|
+
# Is the page in the doublewrite buffer?
|
409
|
+
def in_doublewrite_buffer?
|
410
|
+
space && space.system_space? && space.doublewrite_page?(offset)
|
411
|
+
end
|
412
|
+
|
413
|
+
# Is the space ID stored in the header different from that of the space
|
414
|
+
# provided when initializing this page?
|
415
|
+
def misplaced_space?
|
416
|
+
space && (space_id != space.space_id)
|
417
|
+
end
|
418
|
+
|
419
|
+
# Is the page number stored in the header different from the page number
|
420
|
+
# which was supposed to be read?
|
421
|
+
def misplaced_offset?
|
422
|
+
offset != @page_number
|
423
|
+
end
|
424
|
+
|
425
|
+
# Is the page misplaced in the wrong file or by offset in the file?
|
426
|
+
def misplaced?
|
427
|
+
!in_doublewrite_buffer? && (misplaced_space? || misplaced_offset?)
|
428
|
+
end
|
429
|
+
|
430
|
+
# Is the page corrupt, either due to data corruption, tearing, or in the
|
431
|
+
# wrong place?
|
288
432
|
def corrupt?
|
289
|
-
|
433
|
+
checksum_invalid? || torn? || misplaced?
|
290
434
|
end
|
291
435
|
|
292
436
|
def each_region
|
@@ -315,7 +459,7 @@ class Innodb::Page
|
|
315
459
|
# the page buffer, since it's very large and mostly not interesting.
|
316
460
|
def inspect
|
317
461
|
if fil_header
|
318
|
-
"#<%s: size=%i, space_id=%i, offset=%i, type=%s, prev=%s, next=%s>" % [
|
462
|
+
"#<%s: size=%i, space_id=%i, offset=%i, type=%s, prev=%s, next=%s, checksum_valid?=%s (%s), torn?=%s, misplaced?=%s>" % [
|
319
463
|
self.class,
|
320
464
|
size,
|
321
465
|
fil_header[:space_id],
|
@@ -323,6 +467,10 @@ class Innodb::Page
|
|
323
467
|
fil_header[:type],
|
324
468
|
fil_header[:prev] || "nil",
|
325
469
|
fil_header[:next] || "nil",
|
470
|
+
checksum_valid?,
|
471
|
+
checksum_type ? checksum_type : "unknown",
|
472
|
+
torn?,
|
473
|
+
misplaced?,
|
326
474
|
]
|
327
475
|
else
|
328
476
|
"#<#{self.class}>"
|
@@ -337,5 +485,9 @@ class Innodb::Page
|
|
337
485
|
puts "fil header:"
|
338
486
|
pp fil_header
|
339
487
|
puts
|
488
|
+
|
489
|
+
puts "fil trailer:"
|
490
|
+
pp fil_trailer
|
491
|
+
puts
|
340
492
|
end
|
341
493
|
end
|
data/lib/innodb/page/sys.rb
CHANGED
@@ -8,14 +8,14 @@ require "innodb/page/sys_ibuf_header"
|
|
8
8
|
# uses within InnoDB. We'll override the self.handle method and check the
|
9
9
|
# page offset to decide which type of SYS page this is.
|
10
10
|
class Innodb::Page::Sys < Innodb::Page
|
11
|
-
def self.handle(page, space, buffer)
|
11
|
+
def self.handle(page, space, buffer, page_number=nil)
|
12
12
|
case
|
13
13
|
when page.offset == 3
|
14
|
-
Innodb::Page::SysIbufHeader.new(space, buffer)
|
14
|
+
Innodb::Page::SysIbufHeader.new(space, buffer, page_number)
|
15
15
|
when page.offset == 7
|
16
|
-
Innodb::Page::SysDataDictionaryHeader.new(space, buffer)
|
16
|
+
Innodb::Page::SysDataDictionaryHeader.new(space, buffer, page_number)
|
17
17
|
when space.rseg_page?(page.offset)
|
18
|
-
Innodb::Page::SysRsegHeader.new(space, buffer)
|
18
|
+
Innodb::Page::SysRsegHeader.new(space, buffer, page_number)
|
19
19
|
else
|
20
20
|
# We can't do anything better, so pass on the generic InnoDB::Page.
|
21
21
|
page
|
data/lib/innodb/space.rb
CHANGED
@@ -228,7 +228,12 @@ class Innodb::Space
|
|
228
228
|
|
229
229
|
# Get an Innodb::Page object for a specific page by page number.
|
230
230
|
def page(page_number)
|
231
|
-
|
231
|
+
data = page_data(page_number)
|
232
|
+
if data
|
233
|
+
Innodb::Page.parse(self, data, page_number)
|
234
|
+
else
|
235
|
+
nil
|
236
|
+
end
|
232
237
|
end
|
233
238
|
|
234
239
|
# Determine whether this space looks like a system space. If the initial
|
@@ -374,6 +379,28 @@ class Innodb::Space
|
|
374
379
|
end
|
375
380
|
end
|
376
381
|
|
382
|
+
# Iterate through the page numbers in the doublewrite buffer.
|
383
|
+
def each_doublewrite_page_number
|
384
|
+
return nil unless system_space?
|
385
|
+
|
386
|
+
unless block_given?
|
387
|
+
return enum_for(:each_doublewrite_page_number)
|
388
|
+
end
|
389
|
+
|
390
|
+
trx_sys.doublewrite[:page_info][0][:page_number].each do |start_page|
|
391
|
+
(start_page...(start_page+pages_per_extent)).each do |page_number|
|
392
|
+
yield page_number
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
# Return true if a page is in the doublewrite buffer.
|
398
|
+
def doublewrite_page?(page_number)
|
399
|
+
return false unless system_space?
|
400
|
+
@doublewrite_pages ||= each_doublewrite_page_number.to_a
|
401
|
+
@doublewrite_pages.include?(page_number)
|
402
|
+
end
|
403
|
+
|
377
404
|
# Iterate through all pages in a space, returning the page number and an
|
378
405
|
# Innodb::Page object for each one.
|
379
406
|
def each_page(start_page=0)
|
data/lib/innodb/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: innodb_ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.14
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2016-09-21 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bindata
|
@@ -28,6 +28,22 @@ dependencies:
|
|
28
28
|
- - ! '>='
|
29
29
|
- !ruby/object:Gem::Version
|
30
30
|
version: 1.4.5
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: digest-crc
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: 0.4.1
|
39
|
+
type: :runtime
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.4.1
|
31
47
|
description: Library for parsing InnoDB data files in Ruby
|
32
48
|
email: jeremy@jcole.us
|
33
49
|
executables:
|