innodb_ruby 0.9.16 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +5 -6
  3. data/bin/innodb_log +13 -18
  4. data/bin/innodb_space +377 -757
  5. data/lib/innodb.rb +4 -5
  6. data/lib/innodb/checksum.rb +26 -24
  7. data/lib/innodb/data_dictionary.rb +490 -550
  8. data/lib/innodb/data_type.rb +362 -326
  9. data/lib/innodb/field.rb +102 -89
  10. data/lib/innodb/fseg_entry.rb +22 -26
  11. data/lib/innodb/history.rb +21 -21
  12. data/lib/innodb/history_list.rb +72 -76
  13. data/lib/innodb/ibuf_bitmap.rb +36 -36
  14. data/lib/innodb/ibuf_index.rb +6 -2
  15. data/lib/innodb/index.rb +245 -276
  16. data/lib/innodb/inode.rb +154 -155
  17. data/lib/innodb/list.rb +191 -183
  18. data/lib/innodb/log.rb +139 -110
  19. data/lib/innodb/log_block.rb +100 -91
  20. data/lib/innodb/log_group.rb +53 -64
  21. data/lib/innodb/log_reader.rb +97 -96
  22. data/lib/innodb/log_record.rb +328 -279
  23. data/lib/innodb/lsn.rb +86 -81
  24. data/lib/innodb/page.rb +417 -414
  25. data/lib/innodb/page/blob.rb +82 -83
  26. data/lib/innodb/page/fsp_hdr_xdes.rb +174 -165
  27. data/lib/innodb/page/ibuf_bitmap.rb +34 -34
  28. data/lib/innodb/page/index.rb +964 -943
  29. data/lib/innodb/page/index_compressed.rb +34 -34
  30. data/lib/innodb/page/inode.rb +103 -112
  31. data/lib/innodb/page/sys.rb +13 -15
  32. data/lib/innodb/page/sys_data_dictionary_header.rb +81 -59
  33. data/lib/innodb/page/sys_ibuf_header.rb +45 -42
  34. data/lib/innodb/page/sys_rseg_header.rb +88 -82
  35. data/lib/innodb/page/trx_sys.rb +204 -182
  36. data/lib/innodb/page/undo_log.rb +106 -92
  37. data/lib/innodb/record.rb +121 -160
  38. data/lib/innodb/record_describer.rb +66 -68
  39. data/lib/innodb/space.rb +380 -418
  40. data/lib/innodb/stats.rb +33 -35
  41. data/lib/innodb/system.rb +149 -171
  42. data/lib/innodb/undo_log.rb +129 -107
  43. data/lib/innodb/undo_record.rb +255 -247
  44. data/lib/innodb/util/buffer_cursor.rb +81 -79
  45. data/lib/innodb/util/read_bits_at_offset.rb +2 -1
  46. data/lib/innodb/version.rb +2 -2
  47. data/lib/innodb/xdes.rb +144 -142
  48. metadata +80 -11
@@ -1,86 +1,85 @@
1
- # -*- encoding : utf-8 -*-
2
-
3
- class Innodb::Page::Blob < Innodb::Page
4
- def pos_blob_header
5
- pos_page_body
6
- end
7
-
8
- def size_blob_header
9
- 4 + 4
10
- end
11
-
12
- def pos_blob_data
13
- pos_blob_header + size_blob_header
14
- end
15
-
16
- def blob_header
17
- cursor(pos_blob_header).name("blob_header") do |c|
18
- {
19
- :length => c.name("length") { c.get_uint32 },
20
- :next => c.name("next") { Innodb::Page.maybe_undefined(c.get_uint32) },
21
- }
22
- end
23
- end
24
-
25
- def blob_data
26
- cursor(pos_blob_data).name("blob_data") do |c|
27
- c.get_bytes(blob_header[:length])
28
- end
29
- end
30
-
31
- def dump_hex(string)
32
- slice_size = 16
33
- bytes = string.split("").map { |s| s.ord }
34
- string.split("").each_slice(slice_size).each_with_index do |slice_bytes, slice_count|
35
- puts "%08i %-23s %-23s |%-16s|" % [
36
- (slice_count * slice_size),
37
- slice_bytes[0..8].map { |n| "%02x" % n.ord }.join(" "),
38
- slice_bytes[8..16].map { |n| "%02x" % n.ord }.join(" "),
39
- slice_bytes.join(""),
40
- ]
1
+ # frozen_string_literal: true
2
+
3
+ module Innodb
4
+ class Page
5
+ class Blob < Page
6
+ specialization_for :BLOB
7
+
8
+ def pos_blob_header
9
+ pos_page_body
10
+ end
11
+
12
+ def size_blob_header
13
+ 4 + 4
14
+ end
15
+
16
+ def pos_blob_data
17
+ pos_blob_header + size_blob_header
18
+ end
19
+
20
+ def blob_header
21
+ cursor(pos_blob_header).name("blob_header") do |c|
22
+ {
23
+ length: c.name("length") { c.read_uint32 },
24
+ next: c.name("next") { Innodb::Page.maybe_undefined(c.read_uint32) },
25
+ }
26
+ end
27
+ end
28
+
29
+ def blob_data
30
+ cursor(pos_blob_data).name("blob_data") do |c|
31
+ c.read_bytes(blob_header[:length])
32
+ end
33
+ end
34
+
35
+ def dump_hex(string)
36
+ slice_size = 16
37
+ string.chars.each_slice(slice_size).each_with_index do |slice_bytes, slice_count|
38
+ puts "%08i %-23s %-23s |%-16s|" % [
39
+ (slice_count * slice_size),
40
+ slice_bytes[0..8].map { |n| "%02x" % n.ord }.join(" "),
41
+ slice_bytes[8..16].map { |n| "%02x" % n.ord }.join(" "),
42
+ slice_bytes.join,
43
+ ]
44
+ end
45
+ end
46
+
47
+ def each_region(&block)
48
+ return enum_for(:each_region) unless block_given?
49
+
50
+ super(&block)
51
+
52
+ yield Region.new(
53
+ offset: pos_blob_header,
54
+ length: size_blob_header,
55
+ name: :blob_header,
56
+ info: "Blob Header"
57
+ )
58
+
59
+ yield Region.new(
60
+ offset: pos_blob_data,
61
+ length: blob_header[:length],
62
+ name: :blob_data,
63
+ info: "Blob Data"
64
+ )
65
+
66
+ nil
67
+ end
68
+
69
+ # Dump the contents of a page for debugging purposes.
70
+ def dump
71
+ super
72
+
73
+ puts "blob header:"
74
+ pp blob_header
75
+ puts
76
+
77
+ puts "blob data:"
78
+ dump_hex(blob_data)
79
+ puts
80
+
81
+ puts
82
+ end
41
83
  end
42
84
  end
43
-
44
- def each_region
45
- unless block_given?
46
- return enum_for(:each_region)
47
- end
48
-
49
- super do |region|
50
- yield region
51
- end
52
-
53
- yield({
54
- :offset => pos_blob_header,
55
- :length => size_blob_header,
56
- :name => :blob_header,
57
- :info => "Blob Header",
58
- })
59
-
60
- yield({
61
- :offset => pos_blob_data,
62
- :length => blob_header[:length],
63
- :name => :blob_data,
64
- :info => "Blob Data",
65
- })
66
-
67
- nil
68
- end
69
-
70
- # Dump the contents of a page for debugging purposes.
71
- def dump
72
- super
73
-
74
- puts "blob header:"
75
- pp blob_header
76
- puts
77
-
78
- puts "blob data:"
79
- dump_hex(blob_data)
80
- puts
81
-
82
- puts
83
- end
84
85
  end
85
-
86
- Innodb::Page::SPECIALIZED_CLASSES[:BLOB] = Innodb::Page::Blob
@@ -1,4 +1,4 @@
1
- # -*- encoding : utf-8 -*-
1
+ # frozen_string_literal: true
2
2
 
3
3
  require "innodb/list"
4
4
  require "innodb/xdes"
@@ -12,186 +12,195 @@ require "innodb/xdes"
12
12
  #
13
13
  # The basic structure of FSP_HDR and XDES pages is: FIL header, FSP header,
14
14
  # an array of 256 XDES entries, empty (unused) space, and FIL trailer.
15
- class Innodb::Page::FspHdrXdes < Innodb::Page
16
- extend ReadBitsAtOffset
17
-
18
- # A value added to the adjusted exponent stored in the page size field of
19
- # the flags in the FSP header.
20
- FLAGS_PAGE_SIZE_SHIFT = 9
21
-
22
- def self.shift_page_size(page_size_shifted)
23
- if page_size_shifted != 0
24
- (1 << (FLAGS_PAGE_SIZE_SHIFT + page_size_shifted))
25
- end
26
- end
27
-
28
- # Decode the "flags" field in the FSP header, returning a hash of useful
29
- # decodings of the flags (based on MySQl 5.6 definitions). The flags are:
30
- #
31
- # Offset Size Description
32
- # 0 1 Post-Antelope Flag.
33
- # 1 4 Compressed Page Size (zip_size). This is stored as a
34
- # power of 2, minus 9. Since 0 is reserved to mean "not
35
- # compressed", the minimum value is 1, thus making the
36
- # smallest page size 1024 (2 ** (9 + 1)).
37
- # 5 1 Atomic Blobs Flag.
38
- # 6 4 System Page Size (innodb_page_size, UNIV_PAGE_SIZE).
39
- # The setting of the system page size when the tablespace
40
- # was created, stored in the same format as the compressed
41
- # page size above.
42
- # 10 1 Data Directory Flag.
43
- #
44
- def self.decode_flags(flags)
45
- system_page_size =
46
- shift_page_size(read_bits_at_offset(flags, 4, 6)) ||
47
- Innodb::Space::DEFAULT_PAGE_SIZE
48
- compressed_page_size = shift_page_size(read_bits_at_offset(flags, 4, 1))
49
-
50
- {
51
- :system_page_size => system_page_size,
52
- :compressed => compressed_page_size ? false : true,
53
- :page_size => compressed_page_size || system_page_size,
54
- :post_antelope => read_bits_at_offset(flags, 1, 0) == 1,
55
- :atomic_blobs => read_bits_at_offset(flags, 1, 5) == 1,
56
- :data_directory => read_bits_at_offset(flags, 1, 10) == 1,
57
- :value => flags,
58
- }
59
- end
60
-
61
- # The FSP header immediately follows the FIL header.
62
- def pos_fsp_header
63
- pos_page_body
64
- end
65
-
66
- # The FSP header contains six 32-bit integers, one 64-bit integer, and 5
67
- # list base nodes.
68
- def size_fsp_header
69
- ((4 * 6) + (1 * 8) + (5 * Innodb::List::BASE_NODE_SIZE))
70
- end
71
-
72
- # The XDES entry array immediately follows the FSP header.
73
- def pos_xdes_array
74
- pos_fsp_header + size_fsp_header
75
- end
15
+ module Innodb
16
+ class Page
17
+ class FspHdrXdes < Page
18
+ extend ReadBitsAtOffset
19
+
20
+ specialization_for :FSP_HDR
21
+ specialization_for :XDES
22
+
23
+ Flags = Struct.new(
24
+ :system_page_size,
25
+ :compressed,
26
+ :page_size,
27
+ :post_antelope,
28
+ :atomic_blobs,
29
+ :data_directory,
30
+ :value,
31
+ keyword_init: true
32
+ )
33
+
34
+ Header = Struct.new(
35
+ :space_id,
36
+ :unused,
37
+ :size, # rubocop:disable Lint/StructNewOverride
38
+ :free_limit,
39
+ :flags,
40
+ :frag_n_used,
41
+ :free,
42
+ :free_frag,
43
+ :full_frag,
44
+ :first_unused_seg,
45
+ :full_inodes,
46
+ :free_inodes,
47
+ keyword_init: true
48
+ )
49
+
50
+ # A value added to the adjusted exponent stored in the page size field of
51
+ # the flags in the FSP header.
52
+ FLAGS_PAGE_SIZE_SHIFT = 9
53
+
54
+ def self.shift_page_size(page_size_shifted)
55
+ (1 << (FLAGS_PAGE_SIZE_SHIFT + page_size_shifted)) if page_size_shifted != 0
56
+ end
76
57
 
77
- # The number of entries in the XDES array. Defined as page size divided by
78
- # extent size.
79
- def entries_in_xdes_array
80
- size / space.pages_per_extent
81
- end
58
+ # Decode the "flags" field in the FSP header, returning a hash of useful
59
+ # decodings of the flags (based on MySQl 5.6 definitions). The flags are:
60
+ #
61
+ # Offset Size Description
62
+ # 0 1 Post-Antelope Flag.
63
+ # 1 4 Compressed Page Size (zip_size). This is stored as a
64
+ # power of 2, minus 9. Since 0 is reserved to mean "not
65
+ # compressed", the minimum value is 1, thus making the
66
+ # smallest page size 1024 (2 ** (9 + 1)).
67
+ # 5 1 Atomic Blobs Flag.
68
+ # 6 4 System Page Size (innodb_page_size, UNIV_PAGE_SIZE).
69
+ # The setting of the system page size when the tablespace
70
+ # was created, stored in the same format as the compressed
71
+ # page size above.
72
+ # 10 1 Data Directory Flag.
73
+ #
74
+ def self.decode_flags(flags)
75
+ system_page_size =
76
+ shift_page_size(read_bits_at_offset(flags, 4, 6)) ||
77
+ Innodb::Space::DEFAULT_PAGE_SIZE
78
+ compressed_page_size = shift_page_size(read_bits_at_offset(flags, 4, 1))
79
+
80
+ Flags.new(
81
+ system_page_size: system_page_size,
82
+ compressed: compressed_page_size ? false : true,
83
+ page_size: compressed_page_size || system_page_size,
84
+ post_antelope: read_bits_at_offset(flags, 1, 0) == 1,
85
+ atomic_blobs: read_bits_at_offset(flags, 1, 5) == 1,
86
+ data_directory: read_bits_at_offset(flags, 1, 10) == 1,
87
+ value: flags
88
+ )
89
+ end
82
90
 
83
- def size_xdes_entry
84
- @size_xdes_entry ||= Innodb::Xdes.new(self, cursor(pos_xdes_array)).size_entry
85
- end
91
+ # The FSP header immediately follows the FIL header.
92
+ def pos_fsp_header
93
+ pos_page_body
94
+ end
86
95
 
87
- def size_xdes_array
88
- entries_in_xdes_array * size_xdes_entry
89
- end
96
+ # The FSP header contains six 32-bit integers, one 64-bit integer, and 5
97
+ # list base nodes.
98
+ def size_fsp_header
99
+ ((4 * 6) + (1 * 8) + (5 * Innodb::List::BASE_NODE_SIZE))
100
+ end
90
101
 
91
- # Read the FSP (filespace) header, which contains a few counters and flags,
92
- # as well as list base nodes for each list maintained in the filespace.
93
- def fsp_header
94
- @fsp_header ||= cursor(pos_fsp_header).name("fsp") do |c|
95
- {
96
- :space_id => c.name("space_id") { c.get_uint32 },
97
- :unused => c.name("unused") { c.get_uint32 },
98
- :size => c.name("size") { c.get_uint32 },
99
- :free_limit => c.name("free_limit") { c.get_uint32 },
100
- :flags => c.name("flags") {
101
- self.class.decode_flags(c.get_uint32)
102
- },
103
- :frag_n_used => c.name("frag_n_used") { c.get_uint32 },
104
- :free => c.name("list[free]") {
105
- Innodb::List::Xdes.new(@space, Innodb::List.get_base_node(c))
106
- },
107
- :free_frag => c.name("list[free_frag]") {
108
- Innodb::List::Xdes.new(@space, Innodb::List.get_base_node(c))
109
- },
110
- :full_frag => c.name("list[full_frag]") {
111
- Innodb::List::Xdes.new(@space, Innodb::List.get_base_node(c))
112
- },
113
- :first_unused_seg => c.name("first_unused_seg") { c.get_uint64 },
114
- :full_inodes => c.name("list[full_inodes]") {
115
- Innodb::List::Inode.new(@space, Innodb::List.get_base_node(c))
116
- },
117
- :free_inodes => c.name("list[free_inodes]") {
118
- Innodb::List::Inode.new(@space, Innodb::List.get_base_node(c))
119
- },
120
- }
121
- end
122
- end
102
+ # The XDES entry array immediately follows the FSP header.
103
+ def pos_xdes_array
104
+ pos_fsp_header + size_fsp_header
105
+ end
123
106
 
124
- # Iterate through all lists in the file space.
125
- def each_list
126
- unless block_given?
127
- return enum_for(:each_list)
128
- end
107
+ # The number of entries in the XDES array. Defined as page size divided by
108
+ # extent size.
109
+ def entries_in_xdes_array
110
+ size / space.pages_per_extent
111
+ end
129
112
 
130
- fsp_header.each do |key, value|
131
- yield key, value if value.is_a?(Innodb::List)
132
- end
133
- end
113
+ def size_xdes_entry
114
+ @size_xdes_entry ||= Innodb::Xdes.new(self, cursor(pos_xdes_array)).size_entry
115
+ end
134
116
 
135
- # Iterate through all XDES entries in order. This is useful for debugging,
136
- # but each of these entries is actually a node in some other list. The state
137
- # field in the XDES entry indicates which type of list it is present in,
138
- # although not necessarily which list (e.g. :fseg).
139
- def each_xdes
140
- unless block_given?
141
- return enum_for(:each_xdes)
142
- end
117
+ def size_xdes_array
118
+ entries_in_xdes_array * size_xdes_entry
119
+ end
143
120
 
144
- cursor(pos_xdes_array).name("xdes_array") do |c|
145
- entries_in_xdes_array.times do |n|
146
- yield Innodb::Xdes.new(self, c)
121
+ # Read the FSP (filespace) header, which contains a few counters and flags,
122
+ # as well as list base nodes for each list maintained in the filespace.
123
+ def fsp_header
124
+ @fsp_header ||= cursor(pos_fsp_header).name("fsp") do |c|
125
+ Header.new(
126
+ space_id: c.name("space_id") { c.read_uint32 },
127
+ unused: c.name("unused") { c.read_uint32 },
128
+ size: c.name("size") { c.read_uint32 },
129
+ free_limit: c.name("free_limit") { c.read_uint32 },
130
+ flags: c.name("flags") { self.class.decode_flags(c.read_uint32) },
131
+ frag_n_used: c.name("frag_n_used") { c.read_uint32 },
132
+ free: c.name("list[free]") { Innodb::List::Xdes.new(@space, Innodb::List.get_base_node(c)) },
133
+ free_frag: c.name("list[free_frag]") { Innodb::List::Xdes.new(@space, Innodb::List.get_base_node(c)) },
134
+ full_frag: c.name("list[full_frag]") { Innodb::List::Xdes.new(@space, Innodb::List.get_base_node(c)) },
135
+ first_unused_seg: c.name("first_unused_seg") { c.read_uint64 },
136
+ full_inodes: c.name("list[full_inodes]") { Innodb::List::Inode.new(@space, Innodb::List.get_base_node(c)) },
137
+ free_inodes: c.name("list[free_inodes]") { Innodb::List::Inode.new(@space, Innodb::List.get_base_node(c)) }
138
+ )
139
+ end
147
140
  end
148
- end
149
- end
150
141
 
151
- def each_region
152
- unless block_given?
153
- return enum_for(:each_region)
154
- end
142
+ # Iterate through all lists in the file space.
143
+ def each_list
144
+ return enum_for(:each_list) unless block_given?
155
145
 
156
- super do |region|
157
- yield region
158
- end
146
+ fsp_header.to_h.each do |key, value|
147
+ yield key, value if value.is_a?(Innodb::List)
148
+ end
149
+ end
159
150
 
160
- yield({
161
- :offset => pos_fsp_header,
162
- :length => size_fsp_header,
163
- :name => :fsp_header,
164
- :info => "FSP Header",
165
- })
166
-
167
- each_xdes do |xdes|
168
- state = xdes.state || "unused"
169
- yield({
170
- :offset => xdes.offset,
171
- :length => size_xdes_entry,
172
- :name => "xdes_#{state}".to_sym,
173
- :info => "Extent Descriptor (#{state})",
174
- })
175
- end
151
+ # Iterate through all XDES entries in order. This is useful for debugging,
152
+ # but each of these entries is actually a node in some other list. The state
153
+ # field in the XDES entry indicates which type of list it is present in,
154
+ # although not necessarily which list (e.g. :fseg).
155
+ def each_xdes
156
+ return enum_for(:each_xdes) unless block_given?
157
+
158
+ cursor(pos_xdes_array).name("xdes_array") do |c|
159
+ entries_in_xdes_array.times do
160
+ yield Innodb::Xdes.new(self, c)
161
+ end
162
+ end
163
+ end
176
164
 
177
- nil
178
- end
165
+ def each_region(&block)
166
+ return enum_for(:each_region) unless block_given?
167
+
168
+ super(&block)
169
+
170
+ yield Region.new(
171
+ offset: pos_fsp_header,
172
+ length: size_fsp_header,
173
+ name: :fsp_header,
174
+ info: "FSP Header"
175
+ )
176
+
177
+ each_xdes do |xdes|
178
+ state = xdes.state || "unused"
179
+ yield Region.new(
180
+ offset: xdes.offset,
181
+ length: size_xdes_entry,
182
+ name: "xdes_#{state}".to_sym,
183
+ info: "Extent Descriptor (#{state})"
184
+ )
185
+ end
186
+
187
+ nil
188
+ end
179
189
 
180
- # Dump the contents of a page for debugging purposes.
181
- def dump
182
- super
190
+ # Dump the contents of a page for debugging purposes.
191
+ def dump
192
+ super
183
193
 
184
- puts "fsp header:"
185
- pp fsp_header
186
- puts
194
+ puts "fsp header:"
195
+ pp fsp_header
196
+ puts
187
197
 
188
- puts "xdes entries:"
189
- each_xdes do |xdes|
190
- pp xdes
198
+ puts "xdes entries:"
199
+ each_xdes do |xdes|
200
+ pp xdes
201
+ end
202
+ puts
203
+ end
191
204
  end
192
- puts
193
205
  end
194
206
  end
195
-
196
- Innodb::Page::SPECIALIZED_CLASSES[:FSP_HDR] = Innodb::Page::FspHdrXdes
197
- Innodb::Page::SPECIALIZED_CLASSES[:XDES] = Innodb::Page::FspHdrXdes