innodb_ruby 0.9.13 → 0.9.14
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 +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:
|