innodb_ruby 0.9.0 → 0.9.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|