innodb_ruby 0.9.14 → 0.12.0
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.
- checksums.yaml +7 -0
- data/README.md +5 -6
- data/bin/innodb_log +13 -18
- data/bin/innodb_space +654 -778
- data/lib/innodb/checksum.rb +26 -24
- data/lib/innodb/data_dictionary.rb +490 -550
- data/lib/innodb/data_type.rb +362 -325
- data/lib/innodb/field.rb +102 -89
- data/lib/innodb/fseg_entry.rb +22 -26
- data/lib/innodb/history.rb +21 -21
- data/lib/innodb/history_list.rb +72 -76
- data/lib/innodb/ibuf_bitmap.rb +36 -36
- data/lib/innodb/ibuf_index.rb +6 -2
- data/lib/innodb/index.rb +245 -276
- data/lib/innodb/inode.rb +166 -124
- data/lib/innodb/list.rb +196 -183
- data/lib/innodb/log.rb +139 -110
- data/lib/innodb/log_block.rb +100 -91
- data/lib/innodb/log_group.rb +53 -64
- data/lib/innodb/log_reader.rb +97 -96
- data/lib/innodb/log_record.rb +328 -279
- data/lib/innodb/lsn.rb +86 -81
- data/lib/innodb/page/blob.rb +82 -83
- data/lib/innodb/page/fsp_hdr_xdes.rb +174 -165
- data/lib/innodb/page/ibuf_bitmap.rb +34 -34
- data/lib/innodb/page/index.rb +965 -924
- data/lib/innodb/page/index_compressed.rb +34 -34
- data/lib/innodb/page/inode.rb +103 -112
- data/lib/innodb/page/sys.rb +13 -15
- data/lib/innodb/page/sys_data_dictionary_header.rb +81 -59
- data/lib/innodb/page/sys_ibuf_header.rb +45 -42
- data/lib/innodb/page/sys_rseg_header.rb +88 -82
- data/lib/innodb/page/trx_sys.rb +204 -182
- data/lib/innodb/page/undo_log.rb +106 -92
- data/lib/innodb/page.rb +417 -414
- data/lib/innodb/record.rb +121 -164
- data/lib/innodb/record_describer.rb +66 -68
- data/lib/innodb/space.rb +381 -413
- data/lib/innodb/stats.rb +33 -35
- data/lib/innodb/system.rb +149 -171
- data/lib/innodb/undo_log.rb +129 -107
- data/lib/innodb/undo_record.rb +255 -247
- data/lib/innodb/util/buffer_cursor.rb +81 -79
- data/lib/innodb/util/read_bits_at_offset.rb +2 -1
- data/lib/innodb/version.rb +2 -2
- data/lib/innodb/xdes.rb +144 -142
- data/lib/innodb.rb +4 -5
- metadata +100 -25
data/lib/innodb/inode.rb
CHANGED
@@ -1,144 +1,186 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
|
5
|
+
module Innodb
|
6
|
+
class Inode
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
Header = Struct.new(
|
10
|
+
:offset,
|
11
|
+
:fseg_id,
|
12
|
+
:not_full_n_used,
|
13
|
+
:free,
|
14
|
+
:not_full,
|
15
|
+
:full,
|
16
|
+
:magic_n,
|
17
|
+
:frag_array,
|
18
|
+
keyword_init: true
|
19
|
+
)
|
20
|
+
|
21
|
+
# The number of "slots" (each representing one page) in the fragment array
|
22
|
+
# within each Inode entry.
|
23
|
+
FRAG_ARRAY_N_SLOTS = 32 # FSP_EXTENT_SIZE / 2
|
24
|
+
|
25
|
+
# The size (in bytes) of each slot in the fragment array.
|
26
|
+
FRAG_SLOT_SIZE = 4
|
27
|
+
|
28
|
+
# A magic number which helps determine if an Inode structure is in use
|
29
|
+
# and populated with valid data.
|
30
|
+
MAGIC_N_VALUE = 97_937_874
|
31
|
+
|
32
|
+
# The size (in bytes) of an Inode entry.
|
33
|
+
SIZE = (16 + (3 * Innodb::List::BASE_NODE_SIZE) +
|
34
|
+
(FRAG_ARRAY_N_SLOTS * FRAG_SLOT_SIZE))
|
35
|
+
|
36
|
+
LISTS = %i[
|
37
|
+
free
|
38
|
+
not_full
|
39
|
+
full
|
40
|
+
].freeze
|
41
|
+
|
42
|
+
# Read an array of page numbers (32-bit integers, which may be nil) from
|
43
|
+
# the provided cursor.
|
44
|
+
def self.page_number_array(size, cursor)
|
45
|
+
size.times.map do |n|
|
46
|
+
cursor.name("page[#{n}]") do |c|
|
47
|
+
Innodb::Page.maybe_undefined(c.read_uint32)
|
48
|
+
end
|
25
49
|
end
|
26
50
|
end
|
27
|
-
end
|
28
51
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
:full => cursor.name("list[full]") {
|
46
|
-
Innodb::List::Xdes.new(space, Innodb::List.get_base_node(cursor))
|
47
|
-
},
|
48
|
-
:magic_n => cursor.name("magic_n") {
|
49
|
-
cursor.get_uint32
|
50
|
-
},
|
51
|
-
:frag_array => cursor.name("frag_array") {
|
52
|
-
page_number_array(FRAG_ARRAY_N_SLOTS, cursor)
|
53
|
-
},
|
54
|
-
}
|
55
|
-
|
56
|
-
Innodb::Inode.new(space, data)
|
57
|
-
end
|
52
|
+
# Construct a new Inode by reading an FSEG header from a cursor.
|
53
|
+
def self.new_from_cursor(space, cursor)
|
54
|
+
Innodb::Inode.new(
|
55
|
+
space,
|
56
|
+
Header.new(
|
57
|
+
offset: cursor.position,
|
58
|
+
fseg_id: cursor.name("fseg_id") { cursor.read_uint64 },
|
59
|
+
not_full_n_used: cursor.name("not_full_n_used") { cursor.read_uint32 },
|
60
|
+
free: cursor.name("list[free]") { Innodb::List::Xdes.new(space, Innodb::List.get_base_node(cursor)) },
|
61
|
+
not_full: cursor.name("list[not_full]") { Innodb::List::Xdes.new(space, Innodb::List.get_base_node(cursor)) },
|
62
|
+
full: cursor.name("list[full]") { Innodb::List::Xdes.new(space, Innodb::List.get_base_node(cursor)) },
|
63
|
+
magic_n: cursor.name("magic_n") { cursor.read_uint32 },
|
64
|
+
frag_array: cursor.name("frag_array") { page_number_array(FRAG_ARRAY_N_SLOTS, cursor) }
|
65
|
+
)
|
66
|
+
)
|
67
|
+
end
|
58
68
|
|
59
|
-
|
69
|
+
attr_accessor :space
|
70
|
+
attr_accessor :header
|
60
71
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
72
|
+
def initialize(space, header)
|
73
|
+
@space = space
|
74
|
+
@header = header
|
75
|
+
end
|
65
76
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
77
|
+
def_delegator :header, :offset
|
78
|
+
def_delegator :header, :fseg_id
|
79
|
+
def_delegator :header, :not_full_n_used
|
80
|
+
def_delegator :header, :free
|
81
|
+
def_delegator :header, :not_full
|
82
|
+
def_delegator :header, :full
|
83
|
+
def_delegator :header, :magic_n
|
84
|
+
def_delegator :header, :frag_array
|
85
|
+
|
86
|
+
def inspect
|
87
|
+
"<%s space=%s, fseg=%i>" % [
|
88
|
+
self.class.name,
|
89
|
+
space.inspect,
|
90
|
+
fseg_id,
|
91
|
+
]
|
92
|
+
end
|
82
93
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
94
|
+
# Helper method to determine if an Inode is in use. Inodes that are not in
|
95
|
+
# use have an fseg_id of 0.
|
96
|
+
def allocated?
|
97
|
+
fseg_id != 0
|
98
|
+
end
|
88
99
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
100
|
+
# Helper method to return an array of only non-nil fragment pages.
|
101
|
+
def frag_array_pages
|
102
|
+
frag_array.reject(&:nil?)
|
103
|
+
end
|
93
104
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
105
|
+
# Helper method to count non-nil fragment pages.
|
106
|
+
def frag_array_n_used
|
107
|
+
frag_array_pages.count
|
108
|
+
end
|
98
109
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
110
|
+
# Calculate the total number of pages in use (not free) within this fseg.
|
111
|
+
def used_pages
|
112
|
+
frag_array_n_used + not_full_n_used +
|
113
|
+
(full.length * @space.pages_per_extent)
|
114
|
+
end
|
104
115
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
116
|
+
# Calculate the total number of pages within this fseg.
|
117
|
+
def total_pages
|
118
|
+
frag_array_n_used +
|
119
|
+
(free.length * @space.pages_per_extent) +
|
120
|
+
(not_full.length * @space.pages_per_extent) +
|
121
|
+
(full.length * @space.pages_per_extent)
|
122
|
+
end
|
112
123
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
124
|
+
# Calculate the fill factor of this fseg, in percent.
|
125
|
+
def fill_factor
|
126
|
+
total_pages.positive? ? 100.0 * (used_pages.to_f / total_pages) : 0.0
|
127
|
+
end
|
117
128
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
end
|
129
|
+
# Return a list from the fseg, given its name as a symbol.
|
130
|
+
def list(name)
|
131
|
+
return unless LISTS.include?(name)
|
122
132
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
133
|
+
header[name]
|
134
|
+
end
|
135
|
+
|
136
|
+
# Iterate through all lists, yielding the list name and the list itself.
|
137
|
+
def each_list
|
138
|
+
return enum_for(:each_list) unless block_given?
|
139
|
+
|
140
|
+
LISTS.each do |name|
|
141
|
+
yield name, list(name)
|
142
|
+
end
|
127
143
|
|
128
|
-
|
129
|
-
def each_list
|
130
|
-
lists.each do |name|
|
131
|
-
yield name, list(name)
|
144
|
+
nil
|
132
145
|
end
|
133
|
-
end
|
134
146
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
147
|
+
# Iterate through the fragment array followed by all lists, yielding the
|
148
|
+
# page number. This allows a convenient way to identify all pages that are
|
149
|
+
# part of this inode.
|
150
|
+
def each_page_number(&block)
|
151
|
+
return enum_for(:each_page_number) unless block_given?
|
152
|
+
|
153
|
+
frag_array_pages.each(&block)
|
154
|
+
|
155
|
+
each_list do |_fseg_name, fseg_list|
|
156
|
+
fseg_list.each do |xdes|
|
157
|
+
xdes.each_page_status(&block)
|
158
|
+
end
|
159
|
+
end
|
139
160
|
|
140
|
-
|
141
|
-
|
142
|
-
|
161
|
+
nil
|
162
|
+
end
|
163
|
+
|
164
|
+
# Iterate through the page as associated with this inode using the
|
165
|
+
# each_page_number method, and yield the page number and page.
|
166
|
+
def each_page
|
167
|
+
return enum_for(:each_page) unless block_given?
|
168
|
+
|
169
|
+
each_page_number do |page_number|
|
170
|
+
yield page_number, space.page(page_number)
|
171
|
+
end
|
172
|
+
|
173
|
+
nil
|
174
|
+
end
|
175
|
+
|
176
|
+
# Compare one Innodb::Inode to another.
|
177
|
+
def ==(other)
|
178
|
+
fseg_id == other.fseg_id if other
|
179
|
+
end
|
180
|
+
|
181
|
+
# Dump a summary of this object for debugging purposes.
|
182
|
+
def dump
|
183
|
+
pp header
|
184
|
+
end
|
143
185
|
end
|
144
186
|
end
|
data/lib/innodb/list.rb
CHANGED
@@ -1,233 +1,246 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# An abstract InnoDB "free list" or FLST (renamed to just "list" here as it
|
4
4
|
# frequently is used for structures that aren't free lists). This class must
|
5
5
|
# be sub-classed to provide an appropriate #object_from_address method.
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
7
|
+
module Innodb
|
8
|
+
class List
|
9
|
+
BaseNode = Struct.new(
|
10
|
+
:length, # rubocop:disable Lint/StructNewOverride
|
11
|
+
:first, # rubocop:disable Lint/StructNewOverride
|
12
|
+
:last,
|
13
|
+
keyword_init: true
|
14
|
+
)
|
15
|
+
|
16
|
+
Node = Struct.new(
|
17
|
+
:prev,
|
18
|
+
:next,
|
19
|
+
keyword_init: true
|
20
|
+
)
|
21
|
+
|
22
|
+
# An "address", which consists of a page number and byte offset within the
|
23
|
+
# page. This points to the list "node" pointers (prev and next) of the
|
24
|
+
# node, not necessarily the node object.
|
25
|
+
ADDRESS_SIZE = 4 + 2
|
26
|
+
|
27
|
+
# Read a node address from a cursor. Return nil if the address is an end
|
28
|
+
# or "NULL" pointer (the page number is UINT32_MAX), or the address if
|
29
|
+
# valid.
|
30
|
+
def self.get_address(cursor)
|
31
|
+
page = cursor.name("page") { Innodb::Page.maybe_undefined(cursor.read_uint32) }
|
32
|
+
offset = cursor.name("offset") { cursor.read_uint16 }
|
33
|
+
|
34
|
+
Innodb::Page::Address.new(page: page, offset: offset) if page
|
26
35
|
end
|
27
|
-
end
|
28
|
-
|
29
|
-
# A list node consists of two addresses: the "previous" node address, and
|
30
|
-
# the "next" node address.
|
31
|
-
NODE_SIZE = 2 * ADDRESS_SIZE
|
32
|
-
|
33
|
-
# Read a node, consisting of two consecutive addresses (:prev and :next)
|
34
|
-
# from a cursor. Either address may be nil, indicating the end of the
|
35
|
-
# linked list.
|
36
|
-
def self.get_node(cursor)
|
37
|
-
{
|
38
|
-
:prev => cursor.name("prev") { get_address(cursor) },
|
39
|
-
:next => cursor.name("next") { get_address(cursor) },
|
40
|
-
}
|
41
|
-
end
|
42
36
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
:last => cursor.name("last") { get_address(cursor) },
|
57
|
-
}
|
58
|
-
end
|
37
|
+
# A list node consists of two addresses: the "previous" node address, and
|
38
|
+
# the "next" node address.
|
39
|
+
NODE_SIZE = 2 * ADDRESS_SIZE
|
40
|
+
|
41
|
+
# Read a node, consisting of two consecutive addresses (:prev and :next)
|
42
|
+
# from a cursor. Either address may be nil, indicating the end of the
|
43
|
+
# linked list.
|
44
|
+
def self.get_node(cursor)
|
45
|
+
Node.new(
|
46
|
+
prev: cursor.name("prev") { get_address(cursor) },
|
47
|
+
next: cursor.name("next") { get_address(cursor) }
|
48
|
+
)
|
49
|
+
end
|
59
50
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
51
|
+
# A list base node consists of a list length followed by two addresses:
|
52
|
+
# the "first" node address, and the "last" node address.
|
53
|
+
BASE_NODE_SIZE = 4 + (2 * ADDRESS_SIZE)
|
54
|
+
|
55
|
+
# Read a base node, consisting of a list length followed by two addresses
|
56
|
+
# (:first and :last) from a cursor. Either address may be nil. An empty list
|
57
|
+
# has a :length of 0 and :first and :last are nil. A list with only a single
|
58
|
+
# item will have a :length of 1 and :first and :last will point to the same
|
59
|
+
# address.
|
60
|
+
def self.get_base_node(cursor)
|
61
|
+
BaseNode.new(
|
62
|
+
length: cursor.name("length") { cursor.read_uint32 },
|
63
|
+
first: cursor.name("first") { get_address(cursor) },
|
64
|
+
last: cursor.name("last") { get_address(cursor) }
|
65
|
+
)
|
66
|
+
end
|
64
67
|
|
65
|
-
|
66
|
-
|
68
|
+
attr_reader :space
|
69
|
+
attr_reader :base
|
67
70
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
71
|
+
def initialize(space, base)
|
72
|
+
@space = space
|
73
|
+
@base = base
|
74
|
+
end
|
73
75
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
raise "Class #{object.class} does not respond to prev_address"
|
76
|
+
# Abstract #object_from_address method which must be implemented by
|
77
|
+
# sub-classes in order to return a useful object given an object address.
|
78
|
+
def object_from_address(_address)
|
79
|
+
raise "#{self.class} must implement object_from_address"
|
79
80
|
end
|
80
81
|
|
81
|
-
|
82
|
-
|
82
|
+
# Return the object pointed to by the "previous" address pointer of the
|
83
|
+
# provided object.
|
84
|
+
def prev(object)
|
85
|
+
raise "Class #{object.class} does not respond to prev_address" unless object.respond_to?(:prev_address)
|
83
86
|
|
84
|
-
|
85
|
-
# provided object.
|
86
|
-
def next(object)
|
87
|
-
unless object.respond_to? :next_address
|
88
|
-
raise "Class #{object.class} does not respond to next_address"
|
87
|
+
object_from_address(object.prev_address)
|
89
88
|
end
|
90
89
|
|
91
|
-
|
92
|
-
|
90
|
+
# Return the object pointed to by the "next" address pointer of the
|
91
|
+
# provided object.
|
92
|
+
def next(object)
|
93
|
+
raise "Class #{object.class} does not respond to next_address" unless object.respond_to?(:next_address)
|
93
94
|
|
94
|
-
|
95
|
-
|
96
|
-
@base[:length]
|
97
|
-
end
|
95
|
+
object_from_address(object.next_address)
|
96
|
+
end
|
98
97
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
end
|
98
|
+
# Return the number of items in the list.
|
99
|
+
def length
|
100
|
+
@base.length
|
101
|
+
end
|
104
102
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
103
|
+
# Is the list currently empty?
|
104
|
+
def empty?
|
105
|
+
length.zero?
|
106
|
+
end
|
110
107
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
108
|
+
# Return the first object in the list using the list base node "first"
|
109
|
+
# address pointer.
|
110
|
+
def first
|
111
|
+
object_from_address(@base.first)
|
112
|
+
end
|
115
113
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
each.to_a.include? item
|
122
|
-
end
|
114
|
+
# Return the first object in the list using the list base node "last"
|
115
|
+
# address pointer.
|
116
|
+
def last
|
117
|
+
object_from_address(@base.last)
|
118
|
+
end
|
123
119
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
return enum_for(:each)
|
120
|
+
# Return a list cursor for the list.
|
121
|
+
def list_cursor(node = :min, direction = :forward)
|
122
|
+
ListCursor.new(self, node, direction)
|
128
123
|
end
|
129
124
|
|
130
|
-
|
131
|
-
|
125
|
+
# Return whether the given item is present in the list. This depends on the
|
126
|
+
# item and the items in the list implementing some sufficient == method.
|
127
|
+
# This is implemented rather inefficiently by constructing an array and
|
128
|
+
# leaning on Array#include? to do the real work.
|
129
|
+
def include?(item)
|
130
|
+
each.to_a.include?(item)
|
132
131
|
end
|
133
|
-
end
|
134
132
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
@list = list
|
141
|
-
@direction = direction
|
142
|
-
|
143
|
-
case node
|
144
|
-
when :min
|
145
|
-
@node = @list.first
|
146
|
-
when :max
|
147
|
-
@node = @list.last
|
148
|
-
else
|
149
|
-
@node = node
|
150
|
-
end
|
133
|
+
# Iterate through all nodes in the list.
|
134
|
+
def each(&block)
|
135
|
+
return enum_for(:each) unless block_given?
|
136
|
+
|
137
|
+
list_cursor.each_node(&block)
|
151
138
|
end
|
152
139
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
140
|
+
# A list iteration cursor used primarily by the Innodb::List #cursor method
|
141
|
+
# implicitly. Keeps its own state for iterating through lists efficiently.
|
142
|
+
class ListCursor
|
143
|
+
def initialize(list, node = :min, direction = :forward)
|
144
|
+
@initial = true
|
145
|
+
@list = list
|
146
|
+
@direction = direction
|
147
|
+
@node = initial_node(node)
|
157
148
|
end
|
158
149
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
150
|
+
def initial_node(node)
|
151
|
+
case node
|
152
|
+
when :min
|
153
|
+
@list.first
|
154
|
+
when :max
|
155
|
+
@list.last
|
156
|
+
else
|
157
|
+
node
|
158
|
+
end
|
164
159
|
end
|
165
|
-
end
|
166
160
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
@
|
161
|
+
def node
|
162
|
+
if @initial
|
163
|
+
@initial = false
|
164
|
+
return @node
|
165
|
+
end
|
166
|
+
|
167
|
+
case @direction
|
168
|
+
when :forward
|
169
|
+
next_node
|
170
|
+
when :backward
|
171
|
+
prev_node
|
172
|
+
end
|
174
173
|
end
|
175
|
-
end
|
176
174
|
|
177
|
-
|
178
|
-
|
179
|
-
# return the first entry in the list and adjust the cursor position to
|
180
|
-
# that entry.
|
181
|
-
def next_node
|
182
|
-
if node = @list.next(@node)
|
183
|
-
@node = node
|
175
|
+
def goto_node(node)
|
176
|
+
@node = node if node
|
184
177
|
end
|
185
|
-
end
|
186
178
|
|
187
|
-
|
188
|
-
|
189
|
-
|
179
|
+
# Return the previous entry from the current position, and advance the
|
180
|
+
# cursor position to the returned entry. If the cursor is currently nil,
|
181
|
+
# return the last entry in the list and adjust the cursor position to
|
182
|
+
# that entry.
|
183
|
+
def prev_node
|
184
|
+
goto_node(@list.prev(@node))
|
190
185
|
end
|
191
186
|
|
192
|
-
|
193
|
-
|
187
|
+
# Return the next entry from the current position, and advance the
|
188
|
+
# cursor position to the returned entry. If the cursor is currently nil,
|
189
|
+
# return the first entry in the list and adjust the cursor position to
|
190
|
+
# that entry.
|
191
|
+
def next_node
|
192
|
+
goto_node(@list.next(@node))
|
193
|
+
end
|
194
|
+
|
195
|
+
def each_node
|
196
|
+
return enum_for(:each_node) unless block_given?
|
197
|
+
|
198
|
+
while (n = node)
|
199
|
+
yield n
|
200
|
+
end
|
194
201
|
end
|
195
202
|
end
|
196
|
-
end
|
197
|
-
end
|
198
203
|
|
199
|
-
# A list of extent descriptor entries. Objects returned by list methods
|
200
|
-
# will be Innodb::Xdes objects.
|
201
|
-
class
|
202
|
-
|
203
|
-
|
204
|
-
|
204
|
+
# A list of extent descriptor entries. Objects returned by list methods
|
205
|
+
# will be Innodb::Xdes objects.
|
206
|
+
class Xdes < Innodb::List
|
207
|
+
def object_from_address(address)
|
208
|
+
return unless address
|
209
|
+
|
210
|
+
page = @space.page(address.page)
|
211
|
+
return unless page
|
212
|
+
|
213
|
+
Innodb::Xdes.new(page, page.cursor(address.offset - 8))
|
214
|
+
end
|
205
215
|
end
|
206
|
-
end
|
207
|
-
end
|
208
216
|
|
209
|
-
# A list of Inode pages. Objects returned by list methods will be
|
210
|
-
# Innodb::Page::Inode objects.
|
211
|
-
class
|
212
|
-
|
213
|
-
|
214
|
-
|
217
|
+
# A list of Inode pages. Objects returned by list methods will be
|
218
|
+
# Innodb::Page::Inode objects.
|
219
|
+
class Inode < Innodb::List
|
220
|
+
def object_from_address(address)
|
221
|
+
return unless address
|
222
|
+
|
223
|
+
@space.page(address.page)
|
224
|
+
end
|
215
225
|
end
|
216
|
-
end
|
217
|
-
end
|
218
226
|
|
219
|
-
class
|
220
|
-
|
221
|
-
|
222
|
-
|
227
|
+
class UndoPage < Innodb::List
|
228
|
+
def object_from_address(address)
|
229
|
+
return unless address
|
230
|
+
|
231
|
+
@space.page(address.page)
|
232
|
+
end
|
223
233
|
end
|
224
|
-
end
|
225
|
-
end
|
226
234
|
|
227
|
-
class
|
228
|
-
|
229
|
-
|
230
|
-
|
235
|
+
class History < Innodb::List
|
236
|
+
def object_from_address(address)
|
237
|
+
return unless address
|
238
|
+
|
239
|
+
page = @space.page(address.page)
|
240
|
+
return unless page
|
241
|
+
|
242
|
+
Innodb::UndoLog.new(page, address.offset - 34)
|
243
|
+
end
|
231
244
|
end
|
232
245
|
end
|
233
246
|
end
|