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/lib/innodb/page.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
2
|
|
3
|
-
require "innodb/cursor"
|
4
|
-
|
5
3
|
# A generic class for any type of page, which handles reading the common
|
6
4
|
# FIL header and trailer, and can handle (via #parse) dispatching to a more
|
7
5
|
# specialized class depending on page type (which comes from the FIL header).
|
@@ -61,12 +59,26 @@ class Innodb::Page
|
|
61
59
|
@size ||= @buffer.size
|
62
60
|
end
|
63
61
|
|
64
|
-
#
|
62
|
+
# Return a simple string to uniquely identify this page within the space.
|
63
|
+
# Be careful not to call anything which would instantiate a BufferCursor
|
64
|
+
# so that we can use this method in cursor initialization.
|
65
|
+
def name
|
66
|
+
page_offset = BinData::Uint32be.read(@buffer.slice(4, 4))
|
67
|
+
page_type = BinData::Uint16be.read(@buffer.slice(24, 2))
|
68
|
+
"%i,%s" % [
|
69
|
+
page_offset,
|
70
|
+
PAGE_TYPE_BY_VALUE[page_type],
|
71
|
+
]
|
72
|
+
end
|
73
|
+
|
74
|
+
# If no block is passed, return an BufferCursor object positioned at a
|
65
75
|
# specific offset. If a block is passed, create a cursor at the provided
|
66
76
|
# offset and yield it to the provided block one time, and then return the
|
67
77
|
# return value of the block.
|
68
|
-
def cursor(
|
69
|
-
new_cursor =
|
78
|
+
def cursor(buffer_offset)
|
79
|
+
new_cursor = BufferCursor.new(@buffer, buffer_offset)
|
80
|
+
new_cursor.push_name("space[#{space.name}]")
|
81
|
+
new_cursor.push_name("page[#{name}]")
|
70
82
|
|
71
83
|
if block_given?
|
72
84
|
# Call the block once and return its return value.
|
@@ -277,6 +289,28 @@ class Innodb::Page
|
|
277
289
|
checksum != calculate_checksum
|
278
290
|
end
|
279
291
|
|
292
|
+
def each_region
|
293
|
+
unless block_given?
|
294
|
+
return enum_for(:each_region)
|
295
|
+
end
|
296
|
+
|
297
|
+
yield({
|
298
|
+
:offset => pos_fil_header,
|
299
|
+
:length => size_fil_header,
|
300
|
+
:name => :fil_header,
|
301
|
+
:info => "FIL Header",
|
302
|
+
})
|
303
|
+
|
304
|
+
yield({
|
305
|
+
:offset => pos_fil_trailer,
|
306
|
+
:length => size_fil_trailer,
|
307
|
+
:name => :fil_trailer,
|
308
|
+
:info => "FIL Trailer",
|
309
|
+
})
|
310
|
+
|
311
|
+
nil
|
312
|
+
end
|
313
|
+
|
280
314
|
# Implement a custom inspect method to avoid irb printing the contents of
|
281
315
|
# the page buffer, since it's very large and mostly not interesting.
|
282
316
|
def inspect
|
data/lib/innodb/page/blob.rb
CHANGED
@@ -41,6 +41,32 @@ class Innodb::Page::Blob < Innodb::Page
|
|
41
41
|
end
|
42
42
|
end
|
43
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
|
+
|
44
70
|
# Dump the contents of a page for debugging purposes.
|
45
71
|
def dump
|
46
72
|
super
|
@@ -13,16 +13,12 @@ require "innodb/xdes"
|
|
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
15
|
class Innodb::Page::FspHdrXdes < Innodb::Page
|
16
|
+
extend ReadBitsAtOffset
|
17
|
+
|
16
18
|
# A value added to the adjusted exponent stored in the page size field of
|
17
19
|
# the flags in the FSP header.
|
18
20
|
FLAGS_PAGE_SIZE_ADJUST = 9
|
19
21
|
|
20
|
-
# Read a given number of bits from an integer at a specific bit offset. The
|
21
|
-
# value returned is 0-based so does not need further shifting or adjustment.
|
22
|
-
def self.read_bits_at_offset(data, bits, offset)
|
23
|
-
((data & (((1 << bits) - 1) << offset)) >> offset)
|
24
|
-
end
|
25
|
-
|
26
22
|
# Decode the "flags" field in the FSP header, returning a hash of useful
|
27
23
|
# decoded flags. Unfortunately, InnoDB has a fairly weird and broken
|
28
24
|
# implementation of these flags. The flags are:
|
@@ -74,6 +70,14 @@ class Innodb::Page::FspHdrXdes < Innodb::Page
|
|
74
70
|
size / space.pages_per_extent
|
75
71
|
end
|
76
72
|
|
73
|
+
def size_xdes_entry
|
74
|
+
@size_xdes_entry ||= Innodb::Xdes.new(self, cursor(pos_xdes_array)).size_entry
|
75
|
+
end
|
76
|
+
|
77
|
+
def size_xdes_array
|
78
|
+
entries_in_xdes_array * size_xdes_entry
|
79
|
+
end
|
80
|
+
|
77
81
|
# Read the FSP (filespace) header, which contains a few counters and flags,
|
78
82
|
# as well as list base nodes for each list maintained in the filespace.
|
79
83
|
def fsp_header
|
@@ -134,6 +138,34 @@ class Innodb::Page::FspHdrXdes < Innodb::Page
|
|
134
138
|
end
|
135
139
|
end
|
136
140
|
|
141
|
+
def each_region
|
142
|
+
unless block_given?
|
143
|
+
return enum_for(:each_region)
|
144
|
+
end
|
145
|
+
|
146
|
+
super do |region|
|
147
|
+
yield region
|
148
|
+
end
|
149
|
+
|
150
|
+
yield({
|
151
|
+
:offset => pos_fsp_header,
|
152
|
+
:length => size_fsp_header,
|
153
|
+
:name => :fsp_header,
|
154
|
+
:info => "FSP Header",
|
155
|
+
})
|
156
|
+
|
157
|
+
each_xdes do |xdes|
|
158
|
+
yield({
|
159
|
+
:offset => xdes.offset,
|
160
|
+
:length => size_xdes_entry,
|
161
|
+
:name => :xdes,
|
162
|
+
:info => "Extent Descriptor",
|
163
|
+
})
|
164
|
+
end
|
165
|
+
|
166
|
+
nil
|
167
|
+
end
|
168
|
+
|
137
169
|
# Dump the contents of a page for debugging purposes.
|
138
170
|
def dump
|
139
171
|
super
|
data/lib/innodb/page/index.rb
CHANGED
@@ -31,6 +31,11 @@ class Innodb::Page::Index < Innodb::Page
|
|
31
31
|
# "compact" record format.
|
32
32
|
RECORD_COMPACT_BITS_SIZE = 3
|
33
33
|
|
34
|
+
# Maximum number of fields.
|
35
|
+
RECORD_MAX_N_SYSTEM_FIELDS = 3
|
36
|
+
RECORD_MAX_N_FIELDS = 1024 - 1
|
37
|
+
RECORD_MAX_N_USER_FIELDS = RECORD_MAX_N_FIELDS - RECORD_MAX_N_SYSTEM_FIELDS * 2
|
38
|
+
|
34
39
|
# Page direction values possible in the page_header's :direction field.
|
35
40
|
PAGE_DIRECTION = {
|
36
41
|
1 => :left, # Inserts have been in descending order.
|
@@ -312,6 +317,8 @@ class Innodb::Page::Index < Innodb::Page
|
|
312
317
|
when :redundant
|
313
318
|
record_header_redundant_additional(header, cursor)
|
314
319
|
end
|
320
|
+
|
321
|
+
header[:length] = origin - cursor.position
|
315
322
|
end
|
316
323
|
|
317
324
|
header
|
@@ -325,13 +332,13 @@ class Innodb::Page::Index < Innodb::Page
|
|
325
332
|
# bit vector indicating NULL fields and the length of each
|
326
333
|
# non-NULL variable-length field.
|
327
334
|
if record_format
|
328
|
-
header[:
|
335
|
+
header[:nulls] = cursor.name("nulls") {
|
329
336
|
record_header_compact_null_bitmap(cursor)
|
330
337
|
}
|
331
|
-
header[:
|
332
|
-
cursor.name("
|
338
|
+
header[:lengths], header[:externs] =
|
339
|
+
cursor.name("lengths_and_externs") {
|
333
340
|
record_header_compact_variable_lengths_and_externs(cursor,
|
334
|
-
header[:
|
341
|
+
header[:nulls])
|
335
342
|
}
|
336
343
|
end
|
337
344
|
end
|
@@ -339,39 +346,35 @@ class Innodb::Page::Index < Innodb::Page
|
|
339
346
|
|
340
347
|
# Return an array indicating which fields are null.
|
341
348
|
def record_header_compact_null_bitmap(cursor)
|
342
|
-
fields =
|
349
|
+
fields = record_fields
|
343
350
|
|
344
351
|
# The number of bits in the bitmap is the number of nullable fields.
|
345
352
|
size = fields.count { |f| f.nullable? }
|
346
353
|
|
347
354
|
# There is no bitmap if there are no nullable fields.
|
348
|
-
return
|
349
|
-
|
350
|
-
# To simplify later checks, expand bitmap to one for each field.
|
351
|
-
bitmap = Array.new(fields.last.position + 1, false)
|
355
|
+
return [] unless size > 0
|
352
356
|
|
353
357
|
null_bit_array = cursor.get_bit_array(size).reverse!
|
354
358
|
|
355
|
-
# For every nullable field,
|
356
|
-
fields.
|
357
|
-
|
359
|
+
# For every nullable field, select the ones which are actually null.
|
360
|
+
fields.inject([]) do |nulls, f|
|
361
|
+
nulls << f.name if f.nullable? && (null_bit_array.shift == 1)
|
362
|
+
nulls
|
358
363
|
end
|
359
|
-
|
360
|
-
return bitmap
|
361
364
|
end
|
362
365
|
|
363
366
|
# Return an array containing an array of the length of each variable-length
|
364
367
|
# field and an array indicating which fields are stored externally.
|
365
|
-
def record_header_compact_variable_lengths_and_externs(cursor,
|
368
|
+
def record_header_compact_variable_lengths_and_externs(cursor, nulls)
|
366
369
|
fields = (record_format[:key] + record_format[:row])
|
367
370
|
|
368
|
-
|
369
|
-
|
371
|
+
lengths = {}
|
372
|
+
externs = []
|
370
373
|
|
371
374
|
# For each non-NULL variable-length field, the record header contains
|
372
375
|
# the length in one or two bytes.
|
373
376
|
fields.each do |f|
|
374
|
-
next if !f.variable?
|
377
|
+
next if !f.variable? || nulls.include?(f.name)
|
375
378
|
|
376
379
|
len = cursor.get_uint8
|
377
380
|
ext = false
|
@@ -383,18 +386,16 @@ class Innodb::Page::Index < Innodb::Page
|
|
383
386
|
len = ((len & 0x3f) << 8) + cursor.get_uint8
|
384
387
|
end
|
385
388
|
|
386
|
-
|
387
|
-
|
389
|
+
lengths[f.name] = len
|
390
|
+
externs << f.name if ext
|
388
391
|
end
|
389
392
|
|
390
|
-
return
|
393
|
+
return lengths, externs
|
391
394
|
end
|
392
395
|
|
393
396
|
# Read additional header information from a redundant format record header.
|
394
397
|
def record_header_redundant_additional(header, cursor)
|
395
|
-
|
396
|
-
header[:field_nulls] = []
|
397
|
-
header[:field_externs] = []
|
398
|
+
lengths, nulls, externs = [], [], []
|
398
399
|
|
399
400
|
field_offsets = record_header_redundant_field_end_offsets(header, cursor)
|
400
401
|
|
@@ -403,17 +404,31 @@ class Innodb::Page::Index < Innodb::Page
|
|
403
404
|
case header[:offset_size]
|
404
405
|
when 1
|
405
406
|
next_field_offset = (n & RECORD_REDUNDANT_OFF1_OFFSET_MASK)
|
406
|
-
|
407
|
-
|
408
|
-
|
407
|
+
lengths << (next_field_offset - this_field_offset)
|
408
|
+
nulls << ((n & RECORD_REDUNDANT_OFF1_NULL_MASK) != 0)
|
409
|
+
externs << false
|
409
410
|
when 2
|
410
411
|
next_field_offset = (n & RECORD_REDUNDANT_OFF2_OFFSET_MASK)
|
411
|
-
|
412
|
-
|
413
|
-
|
412
|
+
lengths << (next_field_offset - this_field_offset)
|
413
|
+
nulls << ((n & RECORD_REDUNDANT_OFF2_NULL_MASK) != 0)
|
414
|
+
externs << ((n & RECORD_REDUNDANT_OFF2_EXTERN_MASK) != 0)
|
414
415
|
end
|
415
416
|
this_field_offset = next_field_offset
|
416
417
|
end
|
418
|
+
|
419
|
+
# If possible, refer to fields by name rather than position for
|
420
|
+
# better formatting (i.e. pp).
|
421
|
+
if record_format
|
422
|
+
header[:lengths], header[:nulls], header[:externs] = {}, [], []
|
423
|
+
|
424
|
+
record_fields.each do |f|
|
425
|
+
header[:lengths][f.name] = lengths[f.position]
|
426
|
+
header[:nulls] << f.name if nulls[f.position]
|
427
|
+
header[:externs] << f.name if externs[f.position]
|
428
|
+
end
|
429
|
+
else
|
430
|
+
header[:lengths], header[:nulls], header[:externs] = lengths, nulls, externs
|
431
|
+
end
|
417
432
|
end
|
418
433
|
|
419
434
|
# Read field end offsets from the provided cursor for each field as counted
|
@@ -437,6 +452,7 @@ class Innodb::Page::Index < Innodb::Page
|
|
437
452
|
:header => header,
|
438
453
|
:next => header[:next],
|
439
454
|
:data => c.name("data") { c.get_bytes(size_mum_record) },
|
455
|
+
:length => c.position - offset,
|
440
456
|
})
|
441
457
|
end
|
442
458
|
end
|
@@ -470,24 +486,28 @@ class Innodb::Page::Index < Innodb::Page
|
|
470
486
|
|
471
487
|
# Return a set of field objects that describe the record.
|
472
488
|
def make_record_description
|
489
|
+
position = (0..RECORD_MAX_N_FIELDS).each
|
473
490
|
description = record_describer.description
|
474
|
-
|
475
|
-
position = 0
|
476
|
-
fields = {:type => description[:type], :key => [], :row => []}
|
491
|
+
fields = {:type => description[:type], :key => [], :sys => [], :row => []}
|
477
492
|
|
478
493
|
description[:key].each do |field|
|
479
|
-
fields[:key] << Innodb::Field.new(position, field[:name], *field[:type])
|
480
|
-
position += 1
|
494
|
+
fields[:key] << Innodb::Field.new(position.next, field[:name], *field[:type])
|
481
495
|
end
|
482
496
|
|
483
|
-
|
484
|
-
|
485
|
-
|
497
|
+
# If this is a leaf page of the clustered index, read InnoDB's internal
|
498
|
+
# fields, a transaction ID and roll pointer.
|
499
|
+
if level == 0 && fields[:type] == :clustered
|
500
|
+
[["DB_TRX_ID", :TRX_ID,],["DB_ROLL_PTR", :ROLL_PTR]].each do |name, type|
|
501
|
+
fields[:sys] << Innodb::Field.new(position.next, name, type, :NOT_NULL)
|
502
|
+
end
|
486
503
|
end
|
487
504
|
|
488
|
-
|
489
|
-
|
490
|
-
|
505
|
+
# If this is a leaf page of the clustered index, or any page of a
|
506
|
+
# secondary index, read the non-key fields.
|
507
|
+
if (level == 0 && fields[:type] == :clustered) || (fields[:type] == :secondary)
|
508
|
+
description[:row].each do |field|
|
509
|
+
fields[:row] << Innodb::Field.new(position.next, field[:name], *field[:type])
|
510
|
+
end
|
491
511
|
end
|
492
512
|
|
493
513
|
fields
|
@@ -500,6 +520,13 @@ class Innodb::Page::Index < Innodb::Page
|
|
500
520
|
end
|
501
521
|
end
|
502
522
|
|
523
|
+
# Returns the (ordered) set of fields that describe records in this page.
|
524
|
+
def record_fields
|
525
|
+
if record_format
|
526
|
+
record_format.values_at(:key, :sys, :row).flatten.sort_by {|f| f.position}
|
527
|
+
end
|
528
|
+
end
|
529
|
+
|
503
530
|
# Parse and return a record at a given offset.
|
504
531
|
def record(offset)
|
505
532
|
return nil unless offset
|
@@ -520,53 +547,23 @@ class Innodb::Page::Index < Innodb::Page
|
|
520
547
|
if record_format
|
521
548
|
this_record[:type] = record_format[:type]
|
522
549
|
|
523
|
-
#
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
:name => f.name,
|
529
|
-
:type => f.data_type.name,
|
530
|
-
:value => f.value(this_record, c),
|
531
|
-
:extern => f.extern(this_record, c),
|
532
|
-
}
|
533
|
-
end
|
534
|
-
end
|
535
|
-
|
536
|
-
# If this is a leaf page of the clustered index, read InnoDB's internal
|
537
|
-
# fields, a transaction ID and roll pointer.
|
538
|
-
if level == 0 && record_format[:type] == :clustered
|
539
|
-
this_record[:transaction_id] = c.name("transaction_id") { c.get_hex(6) }
|
540
|
-
c.name("roll_pointer") do
|
541
|
-
rseg_id_insert_flag = c.name("rseg_id_insert_flag") { c.get_uint8 }
|
542
|
-
this_record[:roll_pointer] = {
|
543
|
-
:is_insert => (rseg_id_insert_flag & 0x80) == 0x80,
|
544
|
-
:rseg_id => rseg_id_insert_flag & 0x7f,
|
545
|
-
:undo_log => c.name("undo_log") {
|
546
|
-
{
|
547
|
-
:page => c.name("page") { c.get_uint32 },
|
548
|
-
:offset => c.name("offset") { c.get_uint16 },
|
549
|
-
}
|
550
|
-
}
|
551
|
-
}
|
552
|
-
end
|
550
|
+
# Used to indicate whether a field is part of key/row/sys.
|
551
|
+
fmap = [:key, :row, :sys].inject({}) do |h, k|
|
552
|
+
this_record[k] = []
|
553
|
+
record_format[k].each { |f| h[f.position] = k }
|
554
|
+
h
|
553
555
|
end
|
554
556
|
|
555
|
-
#
|
556
|
-
|
557
|
-
|
558
|
-
(
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
:type => f.data_type.name,
|
566
|
-
:value => f.value(this_record, c),
|
567
|
-
:extern => f.extern(this_record, c),
|
568
|
-
}
|
569
|
-
end
|
557
|
+
# Read the fields present in this record.
|
558
|
+
record_fields.each do |f|
|
559
|
+
p = fmap[f.position]
|
560
|
+
c.name("#{p.to_s}[#{f.name}]") do
|
561
|
+
this_record[p] << {
|
562
|
+
:name => f.name,
|
563
|
+
:type => f.data_type.name,
|
564
|
+
:value => f.value(c, this_record),
|
565
|
+
:extern => f.extern(c, this_record),
|
566
|
+
}.reject { |k, v| v.nil? }
|
570
567
|
end
|
571
568
|
end
|
572
569
|
|
@@ -577,6 +574,18 @@ class Innodb::Page::Index < Innodb::Page
|
|
577
574
|
this_record[:child_page_number] =
|
578
575
|
c.name("child_page_number") { c.get_uint32 }
|
579
576
|
end
|
577
|
+
|
578
|
+
this_record[:length] = c.position - offset
|
579
|
+
|
580
|
+
# Add system field accessors for convenience.
|
581
|
+
this_record[:sys].each do |f|
|
582
|
+
case f[:name]
|
583
|
+
when "DB_TRX_ID"
|
584
|
+
this_record[:transaction_id] = f[:value]
|
585
|
+
when "DB_ROLL_PTR"
|
586
|
+
this_record[:roll_pointer] = f[:value]
|
587
|
+
end
|
588
|
+
end
|
580
589
|
end
|
581
590
|
|
582
591
|
Innodb::Record.new(self, this_record)
|
@@ -649,23 +658,20 @@ class Innodb::Page::Index < Innodb::Page
|
|
649
658
|
end
|
650
659
|
end
|
651
660
|
|
652
|
-
# Return the current record, mostly as a helper.
|
653
|
-
def current_record
|
654
|
-
@record
|
655
|
-
end
|
656
|
-
|
657
661
|
# Return the next record, and advance the cursor. Return nil when the
|
658
662
|
# end of records (supremum) is reached.
|
659
663
|
def next_record
|
660
664
|
Innodb::Stats.increment :page_record_cursor_next_record
|
661
665
|
|
662
|
-
|
666
|
+
rec = @page.record(@record.next)
|
663
667
|
|
664
|
-
|
668
|
+
# The garbage record list's end is self-linked, so we must check for
|
669
|
+
# both supremum and the current record's offset.
|
670
|
+
if rec == @page.supremum || rec.offset == @record.offset
|
665
671
|
# We've reached the end of the linked list at supremum.
|
666
672
|
nil
|
667
673
|
else
|
668
|
-
@record
|
674
|
+
@record = rec
|
669
675
|
end
|
670
676
|
end
|
671
677
|
|
@@ -696,7 +702,7 @@ class Innodb::Page::Index < Innodb::Page
|
|
696
702
|
def record
|
697
703
|
if @initial
|
698
704
|
@initial = false
|
699
|
-
return
|
705
|
+
return @record
|
700
706
|
end
|
701
707
|
|
702
708
|
case @direction
|
@@ -885,7 +891,7 @@ class Innodb::Page::Index < Innodb::Page
|
|
885
891
|
return enum_for(:each_record)
|
886
892
|
end
|
887
893
|
|
888
|
-
c = record_cursor(
|
894
|
+
c = record_cursor(:min)
|
889
895
|
|
890
896
|
while rec = c.record
|
891
897
|
yield rec
|
@@ -930,6 +936,80 @@ class Innodb::Page::Index < Innodb::Page
|
|
930
936
|
nil
|
931
937
|
end
|
932
938
|
|
939
|
+
def each_region
|
940
|
+
unless block_given?
|
941
|
+
return enum_for(:each_region)
|
942
|
+
end
|
943
|
+
|
944
|
+
super do |region|
|
945
|
+
yield region
|
946
|
+
end
|
947
|
+
|
948
|
+
yield({
|
949
|
+
:offset => pos_index_header,
|
950
|
+
:length => size_index_header,
|
951
|
+
:name => :index_header,
|
952
|
+
:info => "Index Header",
|
953
|
+
})
|
954
|
+
|
955
|
+
yield({
|
956
|
+
:offset => pos_fseg_header,
|
957
|
+
:length => size_fseg_header,
|
958
|
+
:name => :fseg_header,
|
959
|
+
:info => "File Segment Header",
|
960
|
+
})
|
961
|
+
|
962
|
+
yield({
|
963
|
+
:offset => pos_infimum - 5,
|
964
|
+
:length => size_mum_record + 5,
|
965
|
+
:name => :infimum,
|
966
|
+
:info => "Infimum",
|
967
|
+
})
|
968
|
+
|
969
|
+
yield({
|
970
|
+
:offset => pos_supremum - 5,
|
971
|
+
:length => size_mum_record + 5,
|
972
|
+
:name => :supremum,
|
973
|
+
:info => "Supremum",
|
974
|
+
})
|
975
|
+
|
976
|
+
|
977
|
+
directory_slots.times do |n|
|
978
|
+
yield({
|
979
|
+
:offset => pos_directory - (n * 2),
|
980
|
+
:length => 2,
|
981
|
+
:name => :directory,
|
982
|
+
:info => "Page Directory",
|
983
|
+
})
|
984
|
+
end
|
985
|
+
|
986
|
+
each_garbage_record do |record|
|
987
|
+
yield({
|
988
|
+
:offset => record.offset - record.header[:length],
|
989
|
+
:length => record.length + record.header[:length],
|
990
|
+
:name => :garbage,
|
991
|
+
:info => "Garbage",
|
992
|
+
})
|
993
|
+
end
|
994
|
+
|
995
|
+
each_record do |record|
|
996
|
+
yield({
|
997
|
+
:offset => record.offset - record.header[:length],
|
998
|
+
:length => record.header[:length],
|
999
|
+
:name => :record_header,
|
1000
|
+
:info => "Record Header",
|
1001
|
+
})
|
1002
|
+
|
1003
|
+
yield({
|
1004
|
+
:offset => record.offset,
|
1005
|
+
:length => record.length,
|
1006
|
+
:name => :record_data,
|
1007
|
+
:info => "Record Data",
|
1008
|
+
})
|
1009
|
+
end
|
1010
|
+
|
1011
|
+
nil
|
1012
|
+
end
|
933
1013
|
|
934
1014
|
# Dump the contents of a page for debugging purposes.
|
935
1015
|
def dump
|