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