innodb_ruby 0.5.0 → 0.5.1
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/lib/innodb/free_list.rb +27 -0
- data/lib/innodb/index.rb +85 -0
- data/lib/innodb/page/fsp_hdr_xdes.rb +78 -0
- data/lib/innodb/page/index.rb +351 -0
- data/lib/innodb/page/inode.rb +44 -0
- data/lib/innodb/version.rb +1 -1
- metadata +8 -3
@@ -0,0 +1,27 @@
|
|
1
|
+
class Innodb::FreeList
|
2
|
+
FIL_ADDR_SIZE = 4 + 2
|
3
|
+
NODE_SIZE = 2 * FIL_ADDR_SIZE
|
4
|
+
BASE_NODE_SIZE = 4 + (2 * FIL_ADDR_SIZE)
|
5
|
+
|
6
|
+
def self.get_address(cursor)
|
7
|
+
{
|
8
|
+
:page => Innodb::Page.maybe_undefined(cursor.get_uint32),
|
9
|
+
:offset => cursor.get_uint16,
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.get_node(cursor)
|
14
|
+
{
|
15
|
+
:prev => Innodb::FreeList::get_address(cursor),
|
16
|
+
:next => Innodb::FreeList::get_address(cursor),
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.get_base_node(cursor)
|
21
|
+
{
|
22
|
+
:length => cursor.get_uint32,
|
23
|
+
:first => Innodb::FreeList::get_address(cursor),
|
24
|
+
:last => Innodb::FreeList::get_address(cursor),
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
data/lib/innodb/index.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# An InnoDB index B-tree, given an Innodb::Space and a root page number.
|
2
|
+
class Innodb::Index
|
3
|
+
def initialize(space, root_page_number)
|
4
|
+
@space = space
|
5
|
+
@root = @space.page(root_page_number)
|
6
|
+
|
7
|
+
unless @root
|
8
|
+
raise "Page #{root_page_number} couldn't be read"
|
9
|
+
end
|
10
|
+
|
11
|
+
# The root page should be an index page.
|
12
|
+
unless @root.type == :INDEX
|
13
|
+
raise "Page #{root_page_number} is a #{@root.type} page, not an INDEX page"
|
14
|
+
end
|
15
|
+
|
16
|
+
# The root page should not be a leaf page.
|
17
|
+
unless @root.level > 0
|
18
|
+
raise "Page #{root_page_number} is a leaf page"
|
19
|
+
end
|
20
|
+
|
21
|
+
# The root page should be the only page at its level.
|
22
|
+
unless @root.prev.nil? && @root.next.nil?
|
23
|
+
raise "Page #{root_page_number} is a node page, but not appear to be the root; it has previous page and next page pointers"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Internal method used by recurse.
|
28
|
+
def _recurse(parent_page, page_proc, link_proc, depth=0)
|
29
|
+
if page_proc && parent_page.type == :INDEX
|
30
|
+
page_proc.call(parent_page, depth)
|
31
|
+
end
|
32
|
+
|
33
|
+
parent_page.each_child_page do |child_page_number, child_min_key|
|
34
|
+
child_page = @space.page(child_page_number)
|
35
|
+
child_page.record_formatter = @space.record_formatter
|
36
|
+
if child_page.type == :INDEX
|
37
|
+
if link_proc
|
38
|
+
link_proc.call(parent_page, child_page, child_min_key, depth+1)
|
39
|
+
end
|
40
|
+
_recurse(child_page, page_proc, link_proc, depth+1)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Walk an index tree depth-first, calling procs for each page and link
|
46
|
+
# in the tree.
|
47
|
+
def recurse(page_proc, link_proc)
|
48
|
+
_recurse(@root, page_proc, link_proc)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Return the first leaf page in the index by walking down the left side
|
52
|
+
# of the B-tree until a page at the given level is encountered.
|
53
|
+
def first_page_at_level(level)
|
54
|
+
page = @root
|
55
|
+
record = @root.first_record
|
56
|
+
while record && page.level > level
|
57
|
+
page = @space.page(record[:child_page_number])
|
58
|
+
record = page.first_record
|
59
|
+
end
|
60
|
+
page if page.level == level
|
61
|
+
end
|
62
|
+
|
63
|
+
# Iterate through all pages at this level starting with the provided page.
|
64
|
+
def each_page_from(page)
|
65
|
+
while page && page.type == :INDEX
|
66
|
+
yield page
|
67
|
+
page = @space.page(page.next)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Iterate through all pages at the given level by finding the first page
|
72
|
+
# and following the next pointers in each page.
|
73
|
+
def each_page_at_level(level)
|
74
|
+
each_page_from(first_page_at_level(level)) { |page| yield page }
|
75
|
+
end
|
76
|
+
|
77
|
+
# Iterate through all records on all leaf pages in ascending order.
|
78
|
+
def each_record
|
79
|
+
each_leaf_page do |page|
|
80
|
+
page.each_record do |record|
|
81
|
+
yield record
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require "innodb/free_list"
|
2
|
+
|
3
|
+
class Innodb::Page::FspHdrXdes < Innodb::Page
|
4
|
+
XDES_BITS_PER_PAGE = 2
|
5
|
+
XDES_BITMAP_SIZE = (64 * XDES_BITS_PER_PAGE) / 8
|
6
|
+
XDES_SIZE = 8 + Innodb::FreeList::NODE_SIZE + 4 + XDES_BITMAP_SIZE
|
7
|
+
|
8
|
+
XDES_N_ARRAY_ENTRIES = 10
|
9
|
+
|
10
|
+
def pos_fsp_header
|
11
|
+
pos_fil_header + size_fil_header
|
12
|
+
end
|
13
|
+
|
14
|
+
def size_fsp_header
|
15
|
+
(32 + 5 * Innodb::FreeList::BASE_NODE_SIZE)
|
16
|
+
end
|
17
|
+
|
18
|
+
def pos_xdes_array
|
19
|
+
pos_fsp_header + size_fsp_header
|
20
|
+
end
|
21
|
+
|
22
|
+
def fsp_header
|
23
|
+
c = cursor(pos_fsp_header)
|
24
|
+
@fsp_header ||= {
|
25
|
+
:space_id => c.get_uint32,
|
26
|
+
:unused => c.get_uint32,
|
27
|
+
:size => c.get_uint32,
|
28
|
+
:free_limit => c.get_uint32,
|
29
|
+
:flags => c.get_uint32,
|
30
|
+
:frag_n_used => c.get_uint32,
|
31
|
+
:free_frag => Innodb::FreeList::get_base_node(c),
|
32
|
+
:full_frag => Innodb::FreeList::get_base_node(c),
|
33
|
+
:first_unused_seg => c.get_uint64,
|
34
|
+
:full_inodes => Innodb::FreeList::get_base_node(c),
|
35
|
+
:free_inodes => Innodb::FreeList::get_base_node(c),
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
XDES_STATES = {
|
40
|
+
1 => :free,
|
41
|
+
2 => :free_frag,
|
42
|
+
3 => :full_frag,
|
43
|
+
4 => :fseg,
|
44
|
+
}
|
45
|
+
|
46
|
+
def read_xdes(cursor)
|
47
|
+
{
|
48
|
+
:xdes_id => cursor.get_uint64,
|
49
|
+
:free_list => Innodb::FreeList::get_node(cursor),
|
50
|
+
:state => XDES_STATES[cursor.get_uint32],
|
51
|
+
:bitmap => cursor.get_bytes(XDES_BITMAP_SIZE),
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def each_xdes
|
56
|
+
c = cursor(pos_xdes_array)
|
57
|
+
XDES_N_ARRAY_ENTRIES.times do
|
58
|
+
yield read_xdes(c)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def dump
|
63
|
+
super
|
64
|
+
|
65
|
+
puts
|
66
|
+
puts "fsp header:"
|
67
|
+
pp fsp_header
|
68
|
+
|
69
|
+
puts
|
70
|
+
puts "xdes entries:"
|
71
|
+
each_xdes do |xdes|
|
72
|
+
pp xdes
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
Innodb::Page::SPECIALIZED_CLASSES[:FSP_HDR] = Innodb::Page::FspHdrXdes
|
78
|
+
Innodb::Page::SPECIALIZED_CLASSES[:XDES] = Innodb::Page::FspHdrXdes
|
@@ -0,0 +1,351 @@
|
|
1
|
+
class Innodb::Page::Index < Innodb::Page
|
2
|
+
attr_accessor :record_formatter
|
3
|
+
|
4
|
+
# Return the byte offset of the start of the "index" page header, which
|
5
|
+
# immediately follows the "fil" header.
|
6
|
+
def pos_index_header
|
7
|
+
pos_fil_header + size_fil_header
|
8
|
+
end
|
9
|
+
|
10
|
+
# The size of the "index" header.
|
11
|
+
def size_index_header
|
12
|
+
36
|
13
|
+
end
|
14
|
+
|
15
|
+
# Return the byte offset of the start of the "fseg" header, which immediately
|
16
|
+
# follows the "index" header.
|
17
|
+
def pos_fseg_header
|
18
|
+
pos_index_header + size_index_header
|
19
|
+
end
|
20
|
+
|
21
|
+
# The size of the "fseg" header.
|
22
|
+
def size_fseg_header
|
23
|
+
2 * 10
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return the byte offset of the start of records within the page (the
|
27
|
+
# position immediately after the page header).
|
28
|
+
def pos_records
|
29
|
+
size_fil_header + size_index_header + size_fseg_header
|
30
|
+
end
|
31
|
+
|
32
|
+
# The size of the data from the supremum or infimum records.
|
33
|
+
def size_mum_record
|
34
|
+
8
|
35
|
+
end
|
36
|
+
|
37
|
+
# Return the byte offset of the start of the "origin" of the infimum record,
|
38
|
+
# which is always the first record in the singly-linked record chain on any
|
39
|
+
# page, and represents a record with a "lower value than any possible user
|
40
|
+
# record". The infimum record immediately follows the page header.
|
41
|
+
def pos_infimum
|
42
|
+
pos_records + size_record_header + size_record_undefined
|
43
|
+
end
|
44
|
+
|
45
|
+
# Return the byte offset of the start of the "origin" of the supremum record,
|
46
|
+
# which is always the last record in the singly-linked record chain on any
|
47
|
+
# page, and represents a record with a "higher value than any possible user
|
48
|
+
# record". The supremum record immediately follows the infimum record.
|
49
|
+
def pos_supremum
|
50
|
+
pos_infimum + size_record_header + size_record_undefined + size_mum_record
|
51
|
+
end
|
52
|
+
|
53
|
+
# Return the byte offset of the start of the user records in a page, which
|
54
|
+
# immediately follows the supremum record.
|
55
|
+
def pos_user_records
|
56
|
+
pos_supremum + size_mum_record
|
57
|
+
end
|
58
|
+
|
59
|
+
# The position of the page directory, which starts at the "fil" trailer and
|
60
|
+
# grows backwards from there.
|
61
|
+
def pos_directory
|
62
|
+
pos_fil_trailer
|
63
|
+
end
|
64
|
+
|
65
|
+
# The amount of space consumed by the page header.
|
66
|
+
def header_space
|
67
|
+
# The end of the supremum system record is the beginning of the space
|
68
|
+
# available for user records.
|
69
|
+
pos_user_records
|
70
|
+
end
|
71
|
+
|
72
|
+
# The amount of space consumed by the page directory.
|
73
|
+
def directory_space
|
74
|
+
page_header[:n_dir_slots] * PAGE_DIR_SLOT_SIZE
|
75
|
+
end
|
76
|
+
|
77
|
+
# The amount of space consumed by the trailers in the page.
|
78
|
+
def trailer_space
|
79
|
+
size_fil_trailer
|
80
|
+
end
|
81
|
+
|
82
|
+
# Return the amount of free space in the page.
|
83
|
+
def free_space
|
84
|
+
page_header[:garbage] +
|
85
|
+
(size - size_fil_trailer - directory_space - page_header[:heap_top])
|
86
|
+
end
|
87
|
+
|
88
|
+
# Return the amount of used space in the page.
|
89
|
+
def used_space
|
90
|
+
size - free_space
|
91
|
+
end
|
92
|
+
|
93
|
+
# Return the amount of space occupied by records in the page.
|
94
|
+
def record_space
|
95
|
+
used_space - header_space - directory_space - trailer_space
|
96
|
+
end
|
97
|
+
|
98
|
+
# Return the actual bytes of the portion of the page which is used to
|
99
|
+
# store user records (eliminate the headers and trailer from the page).
|
100
|
+
def record_bytes
|
101
|
+
data(pos_user_records, page_header[:heap_top] - pos_user_records)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Page direction values possible in the page_header[:direction] field.
|
105
|
+
PAGE_DIRECTION = {
|
106
|
+
1 => :left,
|
107
|
+
2 => :right,
|
108
|
+
3 => :same_rec,
|
109
|
+
4 => :same_page,
|
110
|
+
5 => :no_direction,
|
111
|
+
}
|
112
|
+
|
113
|
+
# Return the "index" header.
|
114
|
+
def page_header
|
115
|
+
return nil unless type == :INDEX
|
116
|
+
|
117
|
+
c = cursor(pos_index_header)
|
118
|
+
@page_header ||= {
|
119
|
+
:n_dir_slots => c.get_uint16,
|
120
|
+
:heap_top => c.get_uint16,
|
121
|
+
:n_heap => ((n_heap = c.get_uint16) & (2**15-1)),
|
122
|
+
:free => c.get_uint16,
|
123
|
+
:garbage => c.get_uint16,
|
124
|
+
:last_insert => c.get_uint16,
|
125
|
+
:direction => PAGE_DIRECTION[c.get_uint16],
|
126
|
+
:n_direction => c.get_uint16,
|
127
|
+
:n_recs => c.get_uint16,
|
128
|
+
:max_trx_id => c.get_uint64,
|
129
|
+
:level => c.get_uint16,
|
130
|
+
:index_id => c.get_uint64,
|
131
|
+
:format => (n_heap & 1<<15) == 0 ? :redundant : :compact,
|
132
|
+
}
|
133
|
+
end
|
134
|
+
alias :ph :page_header
|
135
|
+
|
136
|
+
# A helper function to return the page level from the "page" header, for
|
137
|
+
# easier access.
|
138
|
+
def level
|
139
|
+
page_header && page_header[:level]
|
140
|
+
end
|
141
|
+
|
142
|
+
RECORD_BITS_SIZE = 3
|
143
|
+
RECORD_NEXT_SIZE = 2
|
144
|
+
|
145
|
+
PAGE_DIR_SLOT_SIZE = 2
|
146
|
+
PAGE_DIR_SLOT_MIN_N_OWNED = 4
|
147
|
+
PAGE_DIR_SLOT_MAX_N_OWNED = 8
|
148
|
+
|
149
|
+
# Return the size of the header for each record.
|
150
|
+
def size_record_header
|
151
|
+
case page_header[:format]
|
152
|
+
when :compact
|
153
|
+
RECORD_BITS_SIZE + RECORD_NEXT_SIZE
|
154
|
+
when :redundant
|
155
|
+
RECORD_BITS_SIZE + RECORD_NEXT_SIZE + 1
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Return the size of a field in the record header for which no description
|
160
|
+
# could be found (but must be skipped anyway).
|
161
|
+
def size_record_undefined
|
162
|
+
case page_header[:format]
|
163
|
+
when :compact
|
164
|
+
0
|
165
|
+
when :redundant
|
166
|
+
1
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Record types used in the :type field of the record header.
|
171
|
+
RECORD_TYPES = {
|
172
|
+
0 => :conventional,
|
173
|
+
1 => :node_pointer,
|
174
|
+
2 => :infimum,
|
175
|
+
3 => :supremum,
|
176
|
+
}
|
177
|
+
|
178
|
+
# This record is the minimum record at this level of the B-tree.
|
179
|
+
RECORD_INFO_MIN_REC_FLAG = 1
|
180
|
+
|
181
|
+
# This record has been marked as deleted.
|
182
|
+
RECORD_INFO_DELETED_FLAG = 2
|
183
|
+
|
184
|
+
# Return the header from a record. (This is mostly unimplemented.)
|
185
|
+
def record_header(offset)
|
186
|
+
return nil unless type == :INDEX
|
187
|
+
|
188
|
+
c = cursor(offset).backward
|
189
|
+
case page_header[:format]
|
190
|
+
when :compact
|
191
|
+
header = {}
|
192
|
+
header[:next] = c.get_sint16
|
193
|
+
bits1 = c.get_uint16
|
194
|
+
header[:type] = RECORD_TYPES[bits1 & 0x07]
|
195
|
+
header[:order] = (bits1 & 0xf8) >> 3
|
196
|
+
bits2 = c.get_uint8
|
197
|
+
header[:n_owned] = bits2 & 0x0f
|
198
|
+
info = (bits2 & 0xf0) >> 4
|
199
|
+
header[:min_rec] = (info & RECORD_INFO_MIN_REC_FLAG) != 0
|
200
|
+
header[:deleted] = (info & RECORD_INFO_DELETED_FLAG) != 0
|
201
|
+
header
|
202
|
+
when :redundant
|
203
|
+
raise "Not implemented"
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Parse and return simple fixed-format system records, such as InnoDB's
|
208
|
+
# internal infimum and supremum records.
|
209
|
+
def system_record(offset)
|
210
|
+
return nil unless type == :INDEX
|
211
|
+
|
212
|
+
header = record_header(offset)
|
213
|
+
{
|
214
|
+
:header => header,
|
215
|
+
:next => offset + header[:next],
|
216
|
+
:data => cursor(offset).get_bytes(size_mum_record),
|
217
|
+
}
|
218
|
+
end
|
219
|
+
|
220
|
+
# Return the infimum record on a page.
|
221
|
+
def infimum
|
222
|
+
@infimum ||= system_record(pos_infimum)
|
223
|
+
end
|
224
|
+
|
225
|
+
# Return the supremum record on a page.
|
226
|
+
def supremum
|
227
|
+
@supremum ||= system_record(pos_supremum)
|
228
|
+
end
|
229
|
+
|
230
|
+
# Return (and cache) the record format provided by an external class.
|
231
|
+
def record_format
|
232
|
+
if record_formatter
|
233
|
+
@record_format ||= record_formatter.format(self)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# Parse and return a record at a given offset.
|
238
|
+
def record(offset)
|
239
|
+
return nil unless offset
|
240
|
+
return nil unless type == :INDEX
|
241
|
+
return nil if offset == pos_infimum
|
242
|
+
return nil if offset == pos_supremum
|
243
|
+
|
244
|
+
c = cursor(offset).forward
|
245
|
+
|
246
|
+
# There is a header preceding the row itself, so back up and read it.
|
247
|
+
header = record_header(offset)
|
248
|
+
|
249
|
+
this_record = {
|
250
|
+
:header => header,
|
251
|
+
:next => header[:next] == 0 ? nil : (offset + header[:next]),
|
252
|
+
}
|
253
|
+
|
254
|
+
if record_format
|
255
|
+
this_record[:type] = record_format[:type]
|
256
|
+
|
257
|
+
# Read the key fields present in all types of pages.
|
258
|
+
this_record[:key] = []
|
259
|
+
record_format[:key].each do |f|
|
260
|
+
this_record[:key].push c.send(*f)
|
261
|
+
end
|
262
|
+
|
263
|
+
# If this is a leaf page of the clustered index, read InnoDB's internal
|
264
|
+
# fields, a transaction ID and roll pointer.
|
265
|
+
if level == 0 && record_format[:type] == :clustered
|
266
|
+
this_record[:transaction_id] = c.get_hex(6)
|
267
|
+
this_record[:roll_pointer] = c.get_hex(7)
|
268
|
+
end
|
269
|
+
|
270
|
+
# If this is a leaf page of the clustered index, or any page of a
|
271
|
+
# secondary index, read the non-key fields.
|
272
|
+
if (level == 0 && record_format[:type] == :clustered) ||
|
273
|
+
(record_format[:type] == :secondary)
|
274
|
+
# Read the non-key fields.
|
275
|
+
this_record[:row] = []
|
276
|
+
record_format[:row].each do |f|
|
277
|
+
this_record[:row].push c.send(*f)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
# If this is a node (non-leaf) page, it will have a child page number
|
282
|
+
# (or "node pointer") stored as the last field.
|
283
|
+
if level > 0
|
284
|
+
# Read the node pointer in a node (non-leaf) page.
|
285
|
+
this_record[:child_page_number] = c.get_uint32
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
this_record
|
290
|
+
end
|
291
|
+
|
292
|
+
# Return the first record on this page.
|
293
|
+
def first_record
|
294
|
+
record(infimum[:next])
|
295
|
+
end
|
296
|
+
|
297
|
+
# Iterate through all records. (This is mostly unimplemented.)
|
298
|
+
def each_record
|
299
|
+
rec = infimum
|
300
|
+
while rec = record(rec[:next])
|
301
|
+
yield rec
|
302
|
+
end
|
303
|
+
nil
|
304
|
+
end
|
305
|
+
|
306
|
+
# Iterate through all child pages of a node (non-leaf) page, which are
|
307
|
+
# stored as records with the child page number as the last field in the
|
308
|
+
# record.
|
309
|
+
def each_child_page
|
310
|
+
return nil if level == 0
|
311
|
+
each_record do |rec|
|
312
|
+
yield rec[:child_page_number], rec[:key]
|
313
|
+
end
|
314
|
+
nil
|
315
|
+
end
|
316
|
+
|
317
|
+
# Dump the contents of a page for debugging purposes.
|
318
|
+
def dump
|
319
|
+
super
|
320
|
+
|
321
|
+
puts
|
322
|
+
puts "page header:"
|
323
|
+
pp page_header
|
324
|
+
|
325
|
+
puts
|
326
|
+
puts "sizes:"
|
327
|
+
puts " %-15s%5i" % [ "header", header_space ]
|
328
|
+
puts " %-15s%5i" % [ "trailer", trailer_space ]
|
329
|
+
puts " %-15s%5i" % [ "directory", directory_space ]
|
330
|
+
puts " %-15s%5i" % [ "free", free_space ]
|
331
|
+
puts " %-15s%5i" % [ "used", used_space ]
|
332
|
+
puts " %-15s%5i" % [ "record", record_space ]
|
333
|
+
puts " %-15s%5.2f" % [
|
334
|
+
"per record",
|
335
|
+
(page_header[:n_recs] > 0) ? (record_space / page_header[:n_recs]) : 0
|
336
|
+
]
|
337
|
+
|
338
|
+
puts
|
339
|
+
puts "system records:"
|
340
|
+
pp infimum
|
341
|
+
pp supremum
|
342
|
+
|
343
|
+
puts
|
344
|
+
puts "records:"
|
345
|
+
each_record do |rec|
|
346
|
+
pp rec
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
Innodb::Page::SPECIALIZED_CLASSES[:INDEX] = Innodb::Page::Index
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "innodb/free_list"
|
2
|
+
|
3
|
+
class Innodb::Page::Inode < Innodb::Page
|
4
|
+
FRAG_ARRAY_N_SLOTS = 32 # FSP_EXTENT_SIZE / 2
|
5
|
+
FRAG_SLOT_SIZE = 4
|
6
|
+
|
7
|
+
MAGIC_N_VALUE = 97937874
|
8
|
+
|
9
|
+
def pos_inode_header
|
10
|
+
pos_fil_header + size_fil_header + Innodb::FreeList::NODE_SIZE
|
11
|
+
end
|
12
|
+
|
13
|
+
def size_inode_header
|
14
|
+
(16 + (3 * Innodb::FreeList::BASE_NODE_SIZE) +
|
15
|
+
(FRAG_ARRAY_N_SLOTS * FRAG_SLOT_SIZE))
|
16
|
+
end
|
17
|
+
|
18
|
+
def uint32_array(size, cursor)
|
19
|
+
size.times.map { |n| cursor.get_uint32 }
|
20
|
+
end
|
21
|
+
|
22
|
+
def inode_header
|
23
|
+
c = cursor(pos_inode_header)
|
24
|
+
{
|
25
|
+
:fseg_id => c.get_uint64,
|
26
|
+
:not_full_n_used => c.get_uint32,
|
27
|
+
:free => Innodb::FreeList.get_base_node(c),
|
28
|
+
:not_full => Innodb::FreeList.get_base_node(c),
|
29
|
+
:full => Innodb::FreeList.get_base_node(c),
|
30
|
+
:magic_n => c.get_uint32,
|
31
|
+
:frag_array => uint32_array(FRAG_ARRAY_N_SLOTS, c),
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def dump
|
36
|
+
super
|
37
|
+
|
38
|
+
puts
|
39
|
+
puts "inode header:"
|
40
|
+
pp inode_header
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
Innodb::Page::SPECIALIZED_CLASSES[:INODE] = Innodb::Page::Inode
|
data/lib/innodb/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: innodb_ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 9
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 5
|
9
|
-
-
|
10
|
-
version: 0.5.
|
9
|
+
- 1
|
10
|
+
version: 0.5.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jeremy Cole
|
@@ -30,9 +30,14 @@ extra_rdoc_files: []
|
|
30
30
|
files:
|
31
31
|
- lib/innodb.rb
|
32
32
|
- lib/innodb/cursor.rb
|
33
|
+
- lib/innodb/free_list.rb
|
34
|
+
- lib/innodb/index.rb
|
33
35
|
- lib/innodb/log.rb
|
34
36
|
- lib/innodb/log_block.rb
|
35
37
|
- lib/innodb/page.rb
|
38
|
+
- lib/innodb/page/fsp_hdr_xdes.rb
|
39
|
+
- lib/innodb/page/index.rb
|
40
|
+
- lib/innodb/page/inode.rb
|
36
41
|
- lib/innodb/space.rb
|
37
42
|
- lib/innodb/version.rb
|
38
43
|
- bin/innodb_dump_log
|