innodb_ruby 0.8.8 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +6 -1
- data/bin/innodb_log +8 -6
- data/bin/innodb_space +344 -212
- data/lib/innodb.rb +12 -1
- data/lib/innodb/cursor.rb +2 -2
- data/lib/innodb/data_dictionary.rb +591 -0
- data/lib/innodb/index.rb +149 -178
- data/lib/innodb/log.rb +96 -33
- data/lib/innodb/log_block.rb +34 -68
- data/lib/innodb/page.rb +1 -7
- data/lib/innodb/page/index.rb +303 -39
- data/lib/innodb/page/index_compressed.rb +4 -0
- data/lib/innodb/page/sys_data_dictionary_header.rb +1 -43
- data/lib/innodb/record.rb +34 -3
- data/lib/innodb/record_describer.rb +2 -0
- data/lib/innodb/space.rb +37 -22
- data/lib/innodb/stats.rb +46 -0
- data/lib/innodb/system.rb +122 -42
- data/lib/innodb/version.rb +1 -1
- metadata +3 -2
data/lib/innodb/log_block.rb
CHANGED
@@ -8,30 +8,14 @@ class Innodb::LogBlock
|
|
8
8
|
# Log blocks are fixed-length at 512 bytes in InnoDB.
|
9
9
|
BLOCK_SIZE = 512
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
# Offset of the header within the log block.
|
12
|
+
HEADER_OFFSET = 0
|
13
13
|
|
14
|
-
|
15
|
-
|
14
|
+
# Offset of the trailer within ths log block.
|
15
|
+
TRAILER_OFFSET = BLOCK_SIZE - 4
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
# Header:
|
20
|
-
#define LOG_BLOCK_HDR_NO 0 /* block number which must be > 0 and
|
21
|
-
#define LOG_BLOCK_HDR_DATA_LEN 4 /* number of bytes of log written to
|
22
|
-
#define LOG_BLOCK_FIRST_REC_GROUP 6 /* offset of the first start of an
|
23
|
-
#define LOG_BLOCK_CHECKPOINT_NO 8 /* 4 lower bytes of the value of
|
24
|
-
|
25
|
-
# Trailer:
|
26
|
-
#define LOG_BLOCK_CHECKSUM 0 /* 4 byte checksum of the log block
|
27
|
-
|
28
|
-
#/* Offsets for a checkpoint field */
|
29
|
-
#define LOG_CHECKPOINT_NO 0
|
30
|
-
#define LOG_CHECKPOINT_LSN 8
|
31
|
-
#define LOG_CHECKPOINT_OFFSET 16
|
32
|
-
#define LOG_CHECKPOINT_LOG_BUF_SIZE 20
|
33
|
-
#define LOG_CHECKPOINT_ARCHIVED_LSN 24
|
34
|
-
#define LOG_CHECKPOINT_GROUP_ARRAY 32
|
17
|
+
# Mask used to get the flush bit in the header.
|
18
|
+
HEADER_FLUSH_BIT_MASK = 0x80000000
|
35
19
|
|
36
20
|
# Initialize a log block by passing in a 512-byte buffer containing the raw
|
37
21
|
# log block contents.
|
@@ -43,36 +27,33 @@ class Innodb::LogBlock
|
|
43
27
|
@buffer = buffer
|
44
28
|
end
|
45
29
|
|
46
|
-
# A helper function to return bytes from the log block buffer based on offset
|
47
|
-
# and length, both in bytes.
|
48
|
-
def data(offset, length)
|
49
|
-
@buffer[offset...(offset + length)]
|
50
|
-
end
|
51
|
-
|
52
30
|
# Return an Innodb::Cursor object positioned at a specific offset.
|
53
31
|
def cursor(offset)
|
54
|
-
Innodb::Cursor.new(
|
32
|
+
Innodb::Cursor.new(@buffer, offset)
|
55
33
|
end
|
56
34
|
|
57
35
|
# Return the log block header.
|
58
36
|
def header
|
59
|
-
@header ||=
|
60
|
-
c = cursor(HEADER_START)
|
37
|
+
@header ||= cursor(HEADER_OFFSET).name("header") do |c|
|
61
38
|
{
|
62
|
-
:
|
63
|
-
|
64
|
-
|
65
|
-
:
|
39
|
+
:flush => c.name("flush") {
|
40
|
+
c.peek { (c.get_uint32 & HEADER_FLUSH_BIT_MASK) > 0 }
|
41
|
+
},
|
42
|
+
:block_number => c.name("block_number") {
|
43
|
+
c.get_uint32 & ~HEADER_FLUSH_BIT_MASK
|
44
|
+
},
|
45
|
+
:data_length => c.name("data_length") { c.get_uint16 },
|
46
|
+
:first_rec_group => c.name("first_rec_group") { c.get_uint16 },
|
47
|
+
:checkpoint_no => c.name("checkpoint_no") { c.get_uint32 },
|
66
48
|
}
|
67
49
|
end
|
68
50
|
end
|
69
51
|
|
70
52
|
# Return the log block trailer.
|
71
53
|
def trailer
|
72
|
-
@trailer ||=
|
73
|
-
c = cursor(TRAILER_START)
|
54
|
+
@trailer ||= cursor(TRAILER_OFFSET).name("trailer") do |c|
|
74
55
|
{
|
75
|
-
:checksum => c.get_uint32,
|
56
|
+
:checksum => c.name("checksum") { c.get_uint32 },
|
76
57
|
}
|
77
58
|
end
|
78
59
|
end
|
@@ -127,41 +108,26 @@ class Innodb::LogBlock
|
|
127
108
|
51 => :ZIP_PAGE_COMPRESS,
|
128
109
|
}
|
129
110
|
|
130
|
-
# Return the log record contents. (This is mostly unimplemented.)
|
131
|
-
def record_content(record_type, offset)
|
132
|
-
c = cursor(offset)
|
133
|
-
case record_type
|
134
|
-
when :MLOG_1BYTE
|
135
|
-
c.get_uint8
|
136
|
-
when :MLOG_2BYTE
|
137
|
-
c.get_uint16
|
138
|
-
when :MLOG_4BYTE
|
139
|
-
c.get_uint32
|
140
|
-
when :MLOG_8BYTE
|
141
|
-
c.get_uint64
|
142
|
-
when :UNDO_INSERT
|
143
|
-
when :COMP_REC_INSERT
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
111
|
SINGLE_RECORD_MASK = 0x80
|
148
112
|
RECORD_TYPE_MASK = 0x7f
|
149
113
|
|
150
|
-
# Return the
|
151
|
-
def
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
114
|
+
# Return a preamble of the first record in this block.
|
115
|
+
def first_record_preamble
|
116
|
+
return nil unless header[:first_rec_group] > 0
|
117
|
+
cursor(header[:first_rec_group]).name("header") do |c|
|
118
|
+
type_and_flag = c.name("type") { c.get_uint8 }
|
119
|
+
type = type_and_flag & RECORD_TYPE_MASK
|
120
|
+
type = RECORD_TYPES[type] || type
|
121
|
+
single_record = (type_and_flag & SINGLE_RECORD_MASK) > 0
|
122
|
+
case type
|
123
|
+
when :MULTI_REC_END, :DUMMY_RECORD
|
124
|
+
{ :type => type }
|
125
|
+
else
|
159
126
|
{
|
160
127
|
:type => type,
|
161
128
|
:single_record => single_record,
|
162
|
-
:
|
163
|
-
:
|
164
|
-
:page_number => c.get_ic_uint32,
|
129
|
+
:space => c.name("space") { c.get_ic_uint32 },
|
130
|
+
:page_number => c.name("page_number") { c.get_ic_uint32 },
|
165
131
|
}
|
166
132
|
end
|
167
133
|
end
|
@@ -179,6 +145,6 @@ class Innodb::LogBlock
|
|
179
145
|
|
180
146
|
puts
|
181
147
|
puts "record:"
|
182
|
-
pp
|
148
|
+
pp first_record_preamble
|
183
149
|
end
|
184
150
|
end
|
data/lib/innodb/page.rb
CHANGED
@@ -61,18 +61,12 @@ class Innodb::Page
|
|
61
61
|
@size ||= @buffer.size
|
62
62
|
end
|
63
63
|
|
64
|
-
# A helper function to return bytes from the page buffer based on offset
|
65
|
-
# and length, both in bytes.
|
66
|
-
def data(offset, length)
|
67
|
-
@buffer[offset...(offset + length)]
|
68
|
-
end
|
69
|
-
|
70
64
|
# If no block is passed, return an Innodb::Cursor object positioned at a
|
71
65
|
# specific offset. If a block is passed, create a cursor at the provided
|
72
66
|
# offset and yield it to the provided block one time, and then return the
|
73
67
|
# return value of the block.
|
74
68
|
def cursor(offset)
|
75
|
-
new_cursor = Innodb::Cursor.new(
|
69
|
+
new_cursor = Innodb::Cursor.new(@buffer, offset)
|
76
70
|
|
77
71
|
if block_given?
|
78
72
|
# Call the block once and return its return value.
|
data/lib/innodb/page/index.rb
CHANGED
@@ -11,8 +11,6 @@ require "innodb/fseg_entry"
|
|
11
11
|
# (the actual data) which grow ascending by offset, free space, the page
|
12
12
|
# directory which grows descending by offset, and the FIL trailer.
|
13
13
|
class Innodb::Page::Index < Innodb::Page
|
14
|
-
attr_accessor :record_describer
|
15
|
-
|
16
14
|
# The size (in bytes) of the "next" pointer in each record header.
|
17
15
|
RECORD_NEXT_SIZE = 2
|
18
16
|
|
@@ -228,6 +226,11 @@ class Innodb::Page::Index < Innodb::Page
|
|
228
226
|
end
|
229
227
|
end
|
230
228
|
|
229
|
+
# A helper function to return the index id.
|
230
|
+
def index_id
|
231
|
+
page_header && page_header[:index_id]
|
232
|
+
end
|
233
|
+
|
231
234
|
# A helper function to return the page level from the "page" header, for
|
232
235
|
# easier access.
|
233
236
|
def level
|
@@ -429,7 +432,7 @@ class Innodb::Page::Index < Innodb::Page
|
|
429
432
|
def system_record(offset)
|
430
433
|
cursor(offset).name("record[#{offset}]") do |c|
|
431
434
|
header = c.peek { record_header(c) }
|
432
|
-
Innodb::Record.new({
|
435
|
+
Innodb::Record.new(self, {
|
433
436
|
:offset => offset,
|
434
437
|
:header => header,
|
435
438
|
:next => header[:next],
|
@@ -448,6 +451,23 @@ class Innodb::Page::Index < Innodb::Page
|
|
448
451
|
@supremum ||= system_record(pos_supremum)
|
449
452
|
end
|
450
453
|
|
454
|
+
def record_describer=(o)
|
455
|
+
@record_describer = o
|
456
|
+
end
|
457
|
+
|
458
|
+
def record_describer
|
459
|
+
return @record_describer if @record_describer
|
460
|
+
|
461
|
+
if space and space.innodb_system and index_id
|
462
|
+
@record_describer =
|
463
|
+
space.innodb_system.data_dictionary.record_describer_by_index_id(index_id)
|
464
|
+
elsif space
|
465
|
+
@record_describer = space.record_describer
|
466
|
+
end
|
467
|
+
|
468
|
+
@record_describer
|
469
|
+
end
|
470
|
+
|
451
471
|
# Return a set of field objects that describe the record.
|
452
472
|
def make_record_description
|
453
473
|
description = record_describer.description
|
@@ -559,48 +579,304 @@ class Innodb::Page::Index < Innodb::Page
|
|
559
579
|
end
|
560
580
|
end
|
561
581
|
|
562
|
-
Innodb::Record.new(this_record)
|
582
|
+
Innodb::Record.new(self, this_record)
|
583
|
+
end
|
584
|
+
end
|
585
|
+
|
586
|
+
# Return an array of row offsets for all entries in the page directory.
|
587
|
+
def directory
|
588
|
+
return @directory if @directory
|
589
|
+
|
590
|
+
@directory = []
|
591
|
+
cursor(pos_directory).backward.name("page_directory") do |c|
|
592
|
+
directory_slots.times do |n|
|
593
|
+
@directory.push c.name("slot[#{n}]") { c.get_uint16 }
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
@directory
|
598
|
+
end
|
599
|
+
|
600
|
+
# Return the slot number of the provided offset in the page directory, or nil
|
601
|
+
# if the offset is not present in the page directory.
|
602
|
+
def offset_is_directory_slot?(offset)
|
603
|
+
directory.index(offset)
|
604
|
+
end
|
605
|
+
|
606
|
+
# Return the slot number of the provided record in the page directory, or nil
|
607
|
+
# if the record is not present in the page directory.
|
608
|
+
def record_is_directory_slot?(this_record)
|
609
|
+
offset_is_directory_slot?(this_record.offset)
|
610
|
+
end
|
611
|
+
|
612
|
+
# Return the slot number for the page directory entry which "owns" the
|
613
|
+
# provided record. This will be either the record itself, or the nearest
|
614
|
+
# record with an entry in the directory and a value greater than the record.
|
615
|
+
def directory_slot_for_record(this_record)
|
616
|
+
if slot = record_is_directory_slot?(this_record)
|
617
|
+
return slot
|
563
618
|
end
|
619
|
+
|
620
|
+
unless search_cursor = record_cursor(this_record.next)
|
621
|
+
raise "Couldn't position cursor"
|
622
|
+
end
|
623
|
+
|
624
|
+
while rec = search_cursor.record
|
625
|
+
if slot = record_is_directory_slot?(rec)
|
626
|
+
return slot
|
627
|
+
end
|
628
|
+
end
|
629
|
+
|
630
|
+
return record_is_directory_slot?(supremum)
|
564
631
|
end
|
565
632
|
|
566
633
|
# A class for cursoring through records starting from an arbitrary point.
|
567
634
|
class RecordCursor
|
568
|
-
def initialize(page, offset)
|
569
|
-
|
570
|
-
|
635
|
+
def initialize(page, offset, direction)
|
636
|
+
Innodb::Stats.increment :page_record_cursor_create
|
637
|
+
|
638
|
+
@initial = true
|
639
|
+
@page = page
|
640
|
+
@direction = direction
|
641
|
+
case offset
|
642
|
+
when :min
|
643
|
+
@record = @page.min_record
|
644
|
+
when :max
|
645
|
+
@record = @page.max_record
|
646
|
+
else
|
647
|
+
# Offset is a byte offset of a record (hopefully).
|
648
|
+
@record = @page.record(offset)
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
# Return the current record, mostly as a helper.
|
653
|
+
def current_record
|
654
|
+
@record
|
571
655
|
end
|
572
656
|
|
573
657
|
# Return the next record, and advance the cursor. Return nil when the
|
574
|
-
# end of records is reached.
|
575
|
-
def
|
576
|
-
|
658
|
+
# end of records (supremum) is reached.
|
659
|
+
def next_record
|
660
|
+
Innodb::Stats.increment :page_record_cursor_next_record
|
577
661
|
|
578
|
-
record = @page.record(@
|
662
|
+
@record = @page.record(@record.next)
|
579
663
|
|
580
|
-
if record == @page.supremum
|
664
|
+
if @record == @page.supremum
|
581
665
|
# We've reached the end of the linked list at supremum.
|
582
|
-
|
583
|
-
elsif record.next == @offset
|
584
|
-
# The record links to itself; go ahead and return it (once), but set
|
585
|
-
# the next offset to nil to end the loop.
|
586
|
-
@offset = nil
|
587
|
-
record
|
666
|
+
nil
|
588
667
|
else
|
589
|
-
@
|
590
|
-
|
668
|
+
@record
|
669
|
+
end
|
670
|
+
end
|
671
|
+
|
672
|
+
# Return the previous record, and advance the cursor. Return nil when the
|
673
|
+
# end of records (infimum) is reached.
|
674
|
+
def prev_record
|
675
|
+
Innodb::Stats.increment :page_record_cursor_prev_record
|
676
|
+
|
677
|
+
unless slot = @page.directory_slot_for_record(@record)
|
678
|
+
raise "Couldn't find slot for record"
|
679
|
+
end
|
680
|
+
|
681
|
+
unless search_cursor = @page.record_cursor(@page.directory[slot-1])
|
682
|
+
raise "Couldn't position search cursor"
|
683
|
+
end
|
684
|
+
|
685
|
+
while rec = search_cursor.record and rec.offset != @record.offset
|
686
|
+
if rec.next == @record.offset
|
687
|
+
if rec == @page.infimum
|
688
|
+
return nil
|
689
|
+
end
|
690
|
+
return @record = rec
|
691
|
+
end
|
692
|
+
end
|
693
|
+
end
|
694
|
+
|
695
|
+
# Return the next record in the order defined when the cursor was created.
|
696
|
+
def record
|
697
|
+
if @initial
|
698
|
+
@initial = false
|
699
|
+
return current_record
|
700
|
+
end
|
701
|
+
|
702
|
+
case @direction
|
703
|
+
when :forward
|
704
|
+
next_record
|
705
|
+
when :backward
|
706
|
+
prev_record
|
707
|
+
end
|
708
|
+
end
|
709
|
+
|
710
|
+
# Iterate through all records in the cursor.
|
711
|
+
def each_record
|
712
|
+
unless block_given?
|
713
|
+
return enum_for(:each_record)
|
714
|
+
end
|
715
|
+
|
716
|
+
while rec = record
|
717
|
+
yield rec
|
591
718
|
end
|
592
719
|
end
|
593
720
|
end
|
594
721
|
|
595
722
|
# Return a RecordCursor starting at offset.
|
596
|
-
def record_cursor(offset)
|
597
|
-
RecordCursor.new(self, offset)
|
723
|
+
def record_cursor(offset=:min, direction=:forward)
|
724
|
+
RecordCursor.new(self, offset, direction)
|
598
725
|
end
|
599
726
|
|
600
|
-
# Return the
|
601
|
-
def
|
602
|
-
|
603
|
-
|
727
|
+
# Return the minimum record on this page.
|
728
|
+
def min_record
|
729
|
+
min = record(infimum.next)
|
730
|
+
min if min != supremum
|
731
|
+
end
|
732
|
+
|
733
|
+
# Return the maximum record on this page.
|
734
|
+
def max_record
|
735
|
+
# Since the records are only singly-linked in the forward direction, in
|
736
|
+
# order to do find the last record, we must create a cursor and walk
|
737
|
+
# backwards one step.
|
738
|
+
unless max_cursor = record_cursor(supremum.offset, :backward)
|
739
|
+
raise "Couldn't position cursor"
|
740
|
+
end
|
741
|
+
# Note the deliberate use of prev_record rather than record; we want
|
742
|
+
# to skip over supremum itself.
|
743
|
+
max = max_cursor.prev_record
|
744
|
+
max if max != infimum
|
745
|
+
end
|
746
|
+
|
747
|
+
# Search for a record within a single page, and return either a perfect
|
748
|
+
# match for the key, or the last record closest to they key but not greater
|
749
|
+
# than the key. (If an exact match is desired, compare_key must be used to
|
750
|
+
# check if the returned record matches. This makes the function useful for
|
751
|
+
# search in both leaf and non-leaf pages.)
|
752
|
+
def linear_search_from_cursor(search_cursor, key)
|
753
|
+
Innodb::Stats.increment :linear_search_from_cursor
|
754
|
+
|
755
|
+
this_rec = search_cursor.record
|
756
|
+
|
757
|
+
if Innodb.debug?
|
758
|
+
puts "linear_search_from_cursor: page=%i, level=%i, start=(%s)" % [
|
759
|
+
offset,
|
760
|
+
level,
|
761
|
+
this_rec && this_rec.key_string,
|
762
|
+
]
|
763
|
+
end
|
764
|
+
|
765
|
+
# Iterate through all records until finding either a matching record or
|
766
|
+
# one whose key is greater than the desired key.
|
767
|
+
while this_rec && next_rec = search_cursor.record
|
768
|
+
Innodb::Stats.increment :linear_search_from_cursor_record_scans
|
769
|
+
|
770
|
+
if Innodb.debug?
|
771
|
+
puts "linear_search_from_cursor: page=%i, level=%i, current=(%s)" % [
|
772
|
+
offset,
|
773
|
+
level,
|
774
|
+
this_rec && this_rec.key_string,
|
775
|
+
]
|
776
|
+
end
|
777
|
+
|
778
|
+
# If we reach supremum, return the last non-system record we got.
|
779
|
+
return this_rec if next_rec.header[:type] == :supremum
|
780
|
+
|
781
|
+
if this_rec.compare_key(key) < 0
|
782
|
+
return this_rec
|
783
|
+
end
|
784
|
+
|
785
|
+
if (this_rec.compare_key(key) >= 0) &&
|
786
|
+
(next_rec.compare_key(key) < 0)
|
787
|
+
# The desired key is either an exact match for this_rec or is greater
|
788
|
+
# than it but less than next_rec. If this is a non-leaf page, that
|
789
|
+
# will mean that the record will fall on the leaf page this node
|
790
|
+
# pointer record points to, if it exists at all.
|
791
|
+
return this_rec
|
792
|
+
end
|
793
|
+
|
794
|
+
this_rec = next_rec
|
795
|
+
end
|
796
|
+
|
797
|
+
this_rec
|
798
|
+
end
|
799
|
+
|
800
|
+
# Search or a record within a single page using the page directory to limit
|
801
|
+
# the number of record comparisons required. Once the last page directory
|
802
|
+
# entry closest to but not greater than the key is found, fall back to
|
803
|
+
# linear search using linear_search_from_cursor to find the closest record
|
804
|
+
# whose key is not greater than the desired key. (If an exact match is
|
805
|
+
# desired, the returned record must be checked in the same way as the above
|
806
|
+
# linear_search_from_cursor function.)
|
807
|
+
def binary_search_by_directory(dir, key)
|
808
|
+
Innodb::Stats.increment :binary_search_by_directory
|
809
|
+
|
810
|
+
return nil if dir.empty?
|
811
|
+
|
812
|
+
# Split the directory at the mid-point (using integer math, so the division
|
813
|
+
# is rounding down). Retrieve the record that sits at the mid-point.
|
814
|
+
mid = ((dir.size-1) / 2)
|
815
|
+
rec = record(dir[mid])
|
816
|
+
|
817
|
+
if Innodb.debug?
|
818
|
+
puts "binary_search_by_directory: page=%i, level=%i, dir.size=%i, dir[%i]=(%s)" % [
|
819
|
+
offset,
|
820
|
+
level,
|
821
|
+
dir.size,
|
822
|
+
mid,
|
823
|
+
rec.key_string,
|
824
|
+
]
|
825
|
+
end
|
826
|
+
|
827
|
+
# The mid-point record was the infimum record, which is not comparable with
|
828
|
+
# compare_key, so we need to just linear scan from here. If the mid-point
|
829
|
+
# is the beginning of the page there can't be many records left to check
|
830
|
+
# anyway.
|
831
|
+
if rec.header[:type] == :infimum
|
832
|
+
return linear_search_from_cursor(record_cursor(rec.next), key)
|
833
|
+
end
|
834
|
+
|
835
|
+
# Compare the desired key to the mid-point record's key.
|
836
|
+
case rec.compare_key(key)
|
837
|
+
when 0
|
838
|
+
# An exact match for the key was found. Return the record.
|
839
|
+
Innodb::Stats.increment :binary_search_by_directory_exact_match
|
840
|
+
rec
|
841
|
+
when +1
|
842
|
+
# The mid-point record's key is less than the desired key.
|
843
|
+
if dir.size > 2
|
844
|
+
# There are more entries remaining from the directory, recurse again
|
845
|
+
# using binary search on the right half of the directory, which
|
846
|
+
# represents values greater than or equal to the mid-point record's
|
847
|
+
# key.
|
848
|
+
Innodb::Stats.increment :binary_search_by_directory_recurse_right
|
849
|
+
binary_search_by_directory(dir[mid...dir.size], key)
|
850
|
+
else
|
851
|
+
next_rec = record(dir[mid+1])
|
852
|
+
next_key = next_rec && next_rec.compare_key(key)
|
853
|
+
if dir.size == 1 || next_key == -1 || next_key == 0
|
854
|
+
# This is the last entry remaining from the directory, or our key is
|
855
|
+
# greater than rec and less than rec+1's key. Use linear search to
|
856
|
+
# find the record starting at rec.
|
857
|
+
Innodb::Stats.increment :binary_search_by_directory_linear_search
|
858
|
+
linear_search_from_cursor(record_cursor(rec.offset), key)
|
859
|
+
elsif next_key == +1
|
860
|
+
Innodb::Stats.increment :binary_search_by_directory_linear_search
|
861
|
+
linear_search_from_cursor(record_cursor(next_rec.offset), key)
|
862
|
+
else
|
863
|
+
nil
|
864
|
+
end
|
865
|
+
end
|
866
|
+
when -1
|
867
|
+
# The mid-point record's key is greater than the desired key.
|
868
|
+
if dir.size == 1
|
869
|
+
# If this is the last entry remaining from the directory, we didn't
|
870
|
+
# find anything workable.
|
871
|
+
Innodb::Stats.increment :binary_search_by_directory_empty_result
|
872
|
+
nil
|
873
|
+
else
|
874
|
+
# Recurse on the left half of the directory, which represents values
|
875
|
+
# less than the mid-point record's key.
|
876
|
+
Innodb::Stats.increment :binary_search_by_directory_recurse_left
|
877
|
+
binary_search_by_directory(dir[0...mid], key)
|
878
|
+
end
|
879
|
+
end
|
604
880
|
end
|
605
881
|
|
606
882
|
# Iterate through all records.
|
@@ -618,6 +894,7 @@ class Innodb::Page::Index < Innodb::Page
|
|
618
894
|
nil
|
619
895
|
end
|
620
896
|
|
897
|
+
# Iterate through all records in the garbage list.
|
621
898
|
def each_garbage_record
|
622
899
|
unless block_given?
|
623
900
|
return enum_for(:each_garbage_record)
|
@@ -653,19 +930,6 @@ class Innodb::Page::Index < Innodb::Page
|
|
653
930
|
nil
|
654
931
|
end
|
655
932
|
|
656
|
-
# Return an array of row offsets for all entries in the page directory.
|
657
|
-
def directory
|
658
|
-
return @directory if @directory
|
659
|
-
|
660
|
-
@directory = []
|
661
|
-
cursor(pos_directory).backward.name("page_directory") do |c|
|
662
|
-
directory_slots.times do |n|
|
663
|
-
@directory.push c.name("slot[#{n}]") { c.get_uint16 }
|
664
|
-
end
|
665
|
-
end
|
666
|
-
|
667
|
-
@directory
|
668
|
-
end
|
669
933
|
|
670
934
|
# Dump the contents of a page for debugging purposes.
|
671
935
|
def dump
|