innodb_ruby 0.9.16 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +5 -6
  3. data/bin/innodb_log +13 -18
  4. data/bin/innodb_space +377 -757
  5. data/lib/innodb.rb +4 -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 -326
  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 -276
  16. data/lib/innodb/inode.rb +154 -155
  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 +417 -414
  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 +964 -943
  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 -160
  38. data/lib/innodb/record_describer.rb +66 -68
  39. data/lib/innodb/space.rb +380 -418
  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 +80 -11
@@ -1,134 +1,156 @@
1
- # -*- encoding : utf-8 -*-
2
-
3
- class Innodb::UndoLog
4
- attr_reader :page
5
- attr_reader :position
6
- def initialize(page, position)
7
- @page = page
8
- @position = position
9
- end
10
-
11
- def size_xa_header
12
- 4 + 4 + 4 + 128
13
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Innodb
4
+ class UndoLog
5
+ Header = Struct.new(
6
+ :trx_id,
7
+ :trx_no,
8
+ :delete_mark_flag,
9
+ :log_start_offset,
10
+ :xid_flag,
11
+ :ddl_flag,
12
+ :ddl_table_id,
13
+ :next_log_offset,
14
+ :prev_log_offset,
15
+ :history_list_node,
16
+ :xid,
17
+ keyword_init: true
18
+ )
19
+
20
+ HeaderXid = Struct.new(
21
+ :format,
22
+ :trid_len,
23
+ :bqual_len,
24
+ :data,
25
+ keyword_init: true
26
+ )
27
+
28
+ attr_reader :page
29
+ attr_reader :position
30
+
31
+ def initialize(page, position)
32
+ @page = page
33
+ @position = position
34
+ end
14
35
 
15
- def size_header
16
- 8 + 8 + 2 + 2 + 1 + 1 + 8 + 2 + 2 + Innodb::List::NODE_SIZE + size_xa_header
17
- end
36
+ def size_xa_header
37
+ 4 + 4 + 4 + 128
38
+ end
18
39
 
19
- def header
20
- @header ||= page.cursor(@position).name("header") do |c|
21
- xid_flag = nil
22
- {
23
- :trx_id => c.name("trx_id") { c.get_uint64 },
24
- :trx_no => c.name("trx_no") { c.get_uint64 },
25
- :delete_mark_flag => c.name("delete_mark_flag") { (c.get_uint16 != 0) },
26
- :log_start_offset => c.name("log_start_offset") { c.get_uint16 },
27
- :xid_flag => c.name("xid_flag") { xid_flag = (c.get_uint8 != 0) },
28
- :ddl_flag => c.name("ddl_flag") { (c.get_uint8 != 0) },
29
- :ddl_table_id => c.name("ddl_table_id") { c.get_uint64 },
30
- :next_log_offset => c.name("next_log_offset") { c.get_uint16 },
31
- :prev_log_offset => c.name("prev_log_offset") { c.get_uint16 },
32
- :history_list_node => c.name("history_list_node") {
33
- Innodb::List.get_node(c)
34
- },
35
- :xid => c.name("xid") {
36
- if xid_flag
37
- {
38
- :format => c.name("format") { c.get_uint32 },
39
- :trid_len => c.name("trid_len") { c.get_uint32 },
40
- :bqual_len => c.name("bqual_len") { c.get_uint32 },
41
- :data => c.name("data") { c.get_bytes(128) },
42
- }
43
- end
44
- },
45
- }
40
+ def size_header
41
+ 8 + 8 + 2 + 2 + 1 + 1 + 8 + 2 + 2 + Innodb::List::NODE_SIZE + size_xa_header
46
42
  end
47
- end
48
43
 
49
- def prev_address
50
- header[:history_list_node][:prev]
51
- end
44
+ def header
45
+ @header ||= page.cursor(@position).name("header") do |c|
46
+ header = Header.new(
47
+ trx_id: c.name("trx_id") { c.read_uint64 },
48
+ trx_no: c.name("trx_no") { c.read_uint64 },
49
+ delete_mark_flag: c.name("delete_mark_flag") { (c.read_uint16 != 0) },
50
+ log_start_offset: c.name("log_start_offset") { c.read_uint16 },
51
+ xid_flag: c.name("xid_flag") { (c.read_uint8 != 0) },
52
+ ddl_flag: c.name("ddl_flag") { (c.read_uint8 != 0) },
53
+ ddl_table_id: c.name("ddl_table_id") { c.read_uint64 },
54
+ next_log_offset: c.name("next_log_offset") { c.read_uint16 },
55
+ prev_log_offset: c.name("prev_log_offset") { c.read_uint16 },
56
+ history_list_node: c.name("history_list_node") { Innodb::List.get_node(c) }
57
+ )
58
+
59
+ if header.xid_flag
60
+ header.xid = c.name("xid") do
61
+ HeaderXid.new(
62
+ format: c.name("format") { c.read_uint32 },
63
+ trid_len: c.name("trid_len") { c.read_uint32 },
64
+ bqual_len: c.name("bqual_len") { c.read_uint32 },
65
+ data: c.name("data") { c.read_bytes(128) }
66
+ )
67
+ end
68
+ end
52
69
 
53
- def next_address
54
- header[:history_list_node][:next]
55
- end
70
+ header
71
+ end
72
+ end
56
73
 
57
- def undo_record(offset)
58
- new_undo_record = Innodb::UndoRecord.new(page, offset)
59
- new_undo_record.undo_log = self
60
- new_undo_record
61
- end
74
+ def prev_address
75
+ header.history_list_node.prev
76
+ end
62
77
 
63
- def min_undo_record
64
- undo_record(header[:log_start_offset])
65
- end
78
+ def next_address
79
+ header.history_list_node.next
80
+ end
66
81
 
67
- class UndoRecordCursor
68
- def initialize(undo_log, offset, direction=:forward)
69
- @initial = true
70
- @undo_log = undo_log
71
- @offset = offset
72
- @direction = direction
73
-
74
- case offset
75
- when :min
76
- @undo_record = @undo_log.min_undo_record
77
- when :max
78
- raise "Not implemented"
79
- else
80
- @undo_record = @undo_log.undo_record(offset)
81
- end
82
+ def undo_record(offset)
83
+ new_undo_record = Innodb::UndoRecord.new(page, offset)
84
+ new_undo_record.undo_log = self
85
+ new_undo_record
82
86
  end
83
87
 
84
- def next_undo_record
85
- if rec = @undo_record.next
86
- @undo_record = rec
87
- end
88
+ def min_undo_record
89
+ undo_record(header.log_start_offset)
88
90
  end
89
91
 
90
- def prev_undo_record
91
- if rec = @undo_record.prev
92
- @undo_record = rec
92
+ class UndoRecordCursor
93
+ def initialize(undo_log, offset, direction = :forward)
94
+ @initial = true
95
+ @undo_log = undo_log
96
+ @offset = offset
97
+ @direction = direction
98
+
99
+ case offset
100
+ when :min
101
+ @undo_record = @undo_log.min_undo_record
102
+ when :max
103
+ raise "Not implemented"
104
+ else
105
+ @undo_record = @undo_log.undo_record(offset)
106
+ end
93
107
  end
94
- end
95
108
 
96
- def undo_record
97
- if @initial
98
- @initial = false
99
- return @undo_record
109
+ def next_undo_record
110
+ rec = @undo_record.next
111
+ @undo_record = rec if rec
100
112
  end
101
113
 
102
- case @direction
103
- when :forward
104
- next_undo_record
105
- when :backward
106
- prev_undo_record
114
+ def prev_undo_record
115
+ rec = @undo_record.prev
116
+ @undo_record = rec if rec
107
117
  end
108
- end
109
118
 
110
- def each_undo_record
111
- unless block_given?
112
- return enum_for(:each_undo_record)
119
+ def undo_record
120
+ if @initial
121
+ @initial = false
122
+ return @undo_record
123
+ end
124
+
125
+ case @direction
126
+ when :forward
127
+ next_undo_record
128
+ when :backward
129
+ prev_undo_record
130
+ end
113
131
  end
114
132
 
115
- while rec = undo_record
116
- yield rec
133
+ def each_undo_record
134
+ return enum_for(:each_undo_record) unless block_given?
135
+
136
+ while (rec = undo_record)
137
+ yield rec
138
+ end
117
139
  end
118
140
  end
119
- end
120
141
 
121
- def undo_record_cursor(offset, direction=:forward)
122
- UndoRecordCursor.new(self, offset, direction)
123
- end
142
+ def undo_record_cursor(offset, direction = :forward)
143
+ UndoRecordCursor.new(self, offset, direction)
144
+ end
124
145
 
125
- def first_undo_record_cursor
126
- undo_record_cursor(header[:log_start_offset])
127
- end
146
+ def first_undo_record_cursor
147
+ undo_record_cursor(header.log_start_offset)
148
+ end
128
149
 
129
- def dump
130
- puts "header:"
131
- pp header
132
- puts
150
+ def dump
151
+ puts "header:"
152
+ pp header
153
+ puts
154
+ end
133
155
  end
134
156
  end
@@ -1,165 +1,204 @@
1
- # -*- encoding : utf-8 -*-
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
2
4
 
3
5
  # A single undo log record.
4
- class Innodb::UndoRecord
5
- attr_reader :undo_page
6
- attr_reader :position
6
+ module Innodb
7
+ class UndoRecord
8
+ extend Forwardable
9
+
10
+ Header = Struct.new(
11
+ :prev,
12
+ :next,
13
+ :type,
14
+ :extern_flag,
15
+ :info,
16
+ keyword_init: true
17
+ )
18
+
19
+ HeaderInfo = Struct.new(
20
+ :order_may_change,
21
+ :size_may_change,
22
+ keyword_init: true
23
+ )
24
+
25
+ Record = Struct.new(
26
+ :page,
27
+ :offset,
28
+ :header,
29
+ :undo_no,
30
+ :table_id,
31
+ :info_bits,
32
+ :trx_id,
33
+ :roll_ptr,
34
+ :data,
35
+ :key,
36
+ :row,
37
+ keyword_init: true
38
+ )
39
+
40
+ Field = Struct.new(
41
+ :name,
42
+ :type,
43
+ :value,
44
+ keyword_init: true
45
+ )
46
+
47
+ attr_reader :undo_page
48
+ attr_reader :position
49
+
50
+ attr_accessor :undo_log
51
+ attr_accessor :index_page
52
+
53
+ def initialize(undo_page, position)
54
+ @undo_page = undo_page
55
+ @position = position
56
+
57
+ @undo_log = nil
58
+ @index_page = nil
59
+ end
7
60
 
8
- attr_accessor :undo_log
9
- attr_accessor :index_page
61
+ def new_subordinate(undo_page, position)
62
+ new_undo_record = self.class.new(undo_page, position)
63
+ new_undo_record.undo_log = undo_log
64
+ new_undo_record.index_page = index_page
10
65
 
11
- def initialize(undo_page, position)
12
- @undo_page = undo_page
13
- @position = position
66
+ new_undo_record
67
+ end
14
68
 
15
- @undo_log = nil
16
- @index_page = nil
17
- end
69
+ # The header really starts 2 bytes before the undo record position, as the
70
+ # pointer to the previous record is written there.
71
+ def pos_header
72
+ @position - 2
73
+ end
18
74
 
19
- def new_subordinate(undo_page, position)
20
- new_undo_record = self.class.new(undo_page, position)
21
- new_undo_record.undo_log = undo_log
22
- new_undo_record.index_page = index_page
75
+ # The size of the header.
76
+ def size_header
77
+ 2 + 2 + 1
78
+ end
23
79
 
24
- new_undo_record
25
- end
80
+ def pos_record
81
+ pos_header + size_header
82
+ end
26
83
 
27
- # The header really starts 2 bytes before the undo record position, as the
28
- # pointer to the previous record is written there.
29
- def pos_header
30
- @position - 2
31
- end
84
+ # Return a BufferCursor starting before the header.
85
+ def cursor(position)
86
+ new_cursor = @undo_page.cursor(position)
87
+ new_cursor.push_name("undo_log[#{@undo_log.position}]") if @undo_log
88
+ new_cursor.push_name("undo_record[#{@position}]")
89
+ new_cursor
90
+ end
32
91
 
33
- # The size of the header.
34
- def size_header
35
- 2 + 2 + 1
36
- end
92
+ # Possible undo record types.
93
+ TYPE = {
94
+ 11 => :insert,
95
+ 12 => :update_existing,
96
+ 13 => :update_deleted,
97
+ 14 => :delete,
98
+ }.freeze
99
+
100
+ TYPES_WITH_PREVIOUS_VERSIONS = %i[
101
+ update_existing
102
+ update_deleted
103
+ delete
104
+ ].freeze
105
+
106
+ TYPE_MASK = 0x0f
107
+ COMPILATION_INFO_MASK = 0x70
108
+ COMPILATION_INFO_SHIFT = 4
109
+ COMPILATION_INFO_NO_ORDER_CHANGE_BV = 1
110
+ COMPILATION_INFO_NO_SIZE_CHANGE_BV = 2
111
+ EXTERN_FLAG = 0x80
112
+
113
+ def header
114
+ @header ||= cursor(pos_header).name("header") do |c|
115
+ header = Header.new(
116
+ prev: c.name("prev") { c.read_uint16 },
117
+ next: c.name("next") { c.read_uint16 }
118
+ )
119
+
120
+ info = c.name("info") { c.read_uint8 }
121
+ cmpl = (info & COMPILATION_INFO_MASK) >> COMPILATION_INFO_SHIFT
122
+ header.type = TYPE[info & TYPE_MASK]
123
+ header.extern_flag = (info & EXTERN_FLAG) != 0
124
+ header.info = HeaderInfo.new(
125
+ order_may_change: (cmpl & COMPILATION_INFO_NO_ORDER_CHANGE_BV).zero?,
126
+ size_may_change: (cmpl & COMPILATION_INFO_NO_SIZE_CHANGE_BV).zero?
127
+ )
128
+
129
+ header
130
+ end
131
+ end
37
132
 
38
- def pos_record
39
- pos_header + size_header
40
- end
133
+ def_delegator :header, :type
41
134
 
42
- # Return a BufferCursor starting before the header.
43
- def cursor(position)
44
- new_cursor = @undo_page.cursor(position)
45
- if @undo_log
46
- new_cursor.push_name("undo_log[#{@undo_log.position}]")
135
+ def previous_version?
136
+ TYPES_WITH_PREVIOUS_VERSIONS.include?(type)
47
137
  end
48
- new_cursor.push_name("undo_record[#{@position}]")
49
- new_cursor
50
- end
51
138
 
52
- # Possible undo record types.
53
- TYPE = {
54
- 11 => :insert,
55
- 12 => :update_existing,
56
- 13 => :update_deleted,
57
- 14 => :delete,
58
- }
59
-
60
- TYPE_MASK = 0x0f
61
- COMPILATION_INFO_MASK = 0x70
62
- COMPILATION_INFO_SHIFT = 4
63
- COMPILATION_INFO_NO_ORDER_CHANGE_BV = 1
64
- COMPILATION_INFO_NO_SIZE_CHANGE_BV = 2
65
- EXTERN_FLAG = 0x80
66
-
67
- def header
68
- @header ||= cursor(pos_header).name("header") do |c|
69
- header = {
70
- :prev => c.name("prev") { c.get_uint16 },
71
- :next => c.name("next") { c.get_uint16 },
72
- }
73
-
74
- info = c.name("info") { c.get_uint8 }
75
- cmpl = (info & COMPILATION_INFO_MASK) >> COMPILATION_INFO_SHIFT
76
- header[:type] = TYPE[info & TYPE_MASK]
77
- header[:extern_flag] = (info & EXTERN_FLAG) != 0
78
- header[:info] = {
79
- :order_may_change => (cmpl & COMPILATION_INFO_NO_ORDER_CHANGE_BV) == 0,
80
- :size_may_change => (cmpl & COMPILATION_INFO_NO_SIZE_CHANGE_BV) == 0,
81
- }
82
-
83
- header
84
- end
85
- end
139
+ def get(prev_or_next)
140
+ return if header[prev_or_next].zero?
86
141
 
87
- def type
88
- header[:type]
89
- end
142
+ new_undo_record = new_subordinate(@undo_page, header[prev_or_next])
143
+ new_undo_record if new_undo_record.type
144
+ end
90
145
 
91
- def has_previous_version?
92
- [:update_existing, :update_deleted, :delete].include?(type)
93
- end
146
+ def prev
147
+ get(:prev)
148
+ end
94
149
 
95
- def get(prev_or_next)
96
- if header[prev_or_next] != 0
97
- new_undo_record = new_subordinate(@undo_page, header[prev_or_next])
98
- if new_undo_record.type
99
- new_undo_record
100
- end
150
+ def next
151
+ get(:next)
101
152
  end
102
- end
103
153
 
104
- def prev
105
- get(:prev)
106
- end
154
+ def record_size
155
+ header[:next] - @position - size_header
156
+ end
107
157
 
108
- def next
109
- get(:next)
110
- end
158
+ def read_record
159
+ cursor(pos_record).name("record") do |c|
160
+ this_record = Record.new(
161
+ page: undo_page.offset,
162
+ offset: position,
163
+ header: header,
164
+ undo_no: c.name("undo_no") { c.read_imc_uint64 },
165
+ table_id: c.name("table_id") { c.read_imc_uint64 }
166
+ )
167
+
168
+ if previous_version?
169
+ this_record.info_bits = c.name("info_bits") { c.read_uint8 }
170
+ this_record.trx_id = c.name("trx_id") { c.read_ic_uint64 }
171
+ this_record.roll_ptr = c.name("roll_ptr") do
172
+ Innodb::DataType::RollPointerType.parse_roll_pointer(c.read_ic_uint64)
173
+ end
174
+ end
111
175
 
112
- def record_size
113
- header[:next] - @position - size_header
114
- end
176
+ if index_page
177
+ read_record_fields(this_record, c)
178
+ else
179
+ # Slurp up the remaining data as a string.
180
+ this_record.data = c.read_bytes(header[:next] - c.position - 2)
181
+ end
115
182
 
116
- def read_record
117
- cursor(pos_record).name("record") do |c|
118
- this_record = {
119
- :page => undo_page.offset,
120
- :offset => position,
121
- :header => header,
122
- :undo_no => c.name("undo_no") { c.get_imc_uint64 },
123
- :table_id => c.name("table_id") { c.get_imc_uint64 },
124
- }
125
-
126
- if has_previous_version?
127
- this_record[:info_bits] = c.name("info_bits") { c.get_uint8 }
128
- this_record[:trx_id] = c.name("trx_id") { c.get_ic_uint64 }
129
- this_record[:roll_ptr] = c.name("roll_ptr") {
130
- Innodb::DataType::RollPointerType.parse_roll_pointer(c.get_ic_uint64)
131
- }
183
+ this_record
132
184
  end
185
+ end
133
186
 
134
- if index_page
135
- read_record_fields(this_record, c)
136
- else
137
- # Slurp up the remaining data as a string.
138
- this_record[:data] = c.get_bytes(header[:next] - c.position - 2)
139
- end
187
+ def read_record_fields(this_record, cursor)
188
+ this_record.key = []
189
+ index_page.record_format[:key].each do |field|
190
+ length = cursor.name("field_length") { cursor.read_ic_uint32 }
191
+ value = cursor.name(field.name) { field.value_by_length(cursor, length) }
140
192
 
141
- this_record
142
- end
143
- end
193
+ this_record.key[field.position] = Field.new(name: field.name, type: field.data_type.name, value: value)
194
+ end
144
195
 
145
- def read_record_fields(this_record, c)
146
- this_record[:key] = []
147
- index_page.record_format[:key].each do |field|
148
- this_record[:key][field.position] = {
149
- :name => field.name,
150
- :type => field.data_type.name,
151
- :value => c.name(field.name) {
152
- field_length = c.name("field_length") { c.get_ic_uint32 }
153
- field.value_by_length(c, field_length)
154
- }
155
- }
156
- end
196
+ return unless previous_version?
157
197
 
158
- if has_previous_version?
159
- field_count = c.name("field_count") { c.get_ic_uint32 }
160
- this_record[:row] = Array.new(index_page.record_format[:row].size)
198
+ field_count = cursor.name("field_count") { cursor.read_ic_uint32 }
199
+ this_record.row = Array.new(index_page.record_format[:row].size)
161
200
  field_count.times do
162
- field_number = c.name("field_number[#{field_count}]") { c.get_ic_uint32 }
201
+ field_number = cursor.name("field_number[#{field_count}]") { cursor.read_ic_uint32 }
163
202
  field = nil
164
203
  field_index = nil
165
204
  index_page.record_format[:row].each_with_index do |candidate_field, index|
@@ -168,140 +207,109 @@ class Innodb::UndoRecord
168
207
  field_index = index
169
208
  end
170
209
  end
171
- raise "Unknown field #{field_number}" unless field
172
- this_record[:row][field_index] = {
173
- :name => field.name,
174
- :type => field.data_type.name,
175
- :value => c.name(field.name) {
176
- field_length = c.name("field_length") { c.get_ic_uint32 }
177
- field.value_by_length(c, field_length)
178
- }
179
- }
180
- end
181
- end
182
- end
183
-
184
- def undo_record
185
- @undo_record ||= read_record
186
- end
187
210
 
188
- def undo_no
189
- undo_record[:undo_no]
190
- end
191
-
192
- def table_id
193
- undo_record[:table_id]
194
- end
195
-
196
- def trx_id
197
- undo_record[:trx_id]
198
- end
211
+ raise "Unknown field #{field_number}" unless field
199
212
 
200
- def roll_ptr
201
- undo_record[:roll_ptr]
202
- end
213
+ length = cursor.name("field_length") { cursor.read_ic_uint32 }
214
+ value = cursor.name(field.name) { field.value_by_length(cursor, length) }
203
215
 
204
- def key
205
- undo_record[:key]
206
- end
216
+ this_record.row[field_index] = Field.new(name: field.name, type: field.data_type.name, value: value)
217
+ end
218
+ end
207
219
 
208
- def page
209
- undo_record[:page]
210
- end
220
+ def undo_record
221
+ @undo_record ||= read_record
222
+ end
211
223
 
212
- def offset
213
- undo_record[:offset]
214
- end
224
+ def_delegator :undo_record, :undo_no
225
+ def_delegator :undo_record, :table_id
226
+ def_delegator :undo_record, :trx_id
227
+ def_delegator :undo_record, :roll_ptr
228
+ def_delegator :undo_record, :key
229
+ def_delegator :undo_record, :page
230
+ def_delegator :undo_record, :offset
215
231
 
216
- def key_string
217
- key && key.map { |r| "%s=%s" % [r[:name], r[:value].inspect] }.join(", ")
218
- end
232
+ def key_string
233
+ key&.map { |r| "%s=%s" % [r[:name], r[:value].inspect] }&.join(", ")
234
+ end
219
235
 
220
- def row
221
- undo_record[:row]
222
- end
236
+ def row
237
+ undo_record[:row]
238
+ end
223
239
 
224
- def row_string
225
- row && row.select { |r| !r.nil? }.map { |r| r && "%s=%s" % [r[:name], r[:value].inspect] }.join(", ")
226
- end
240
+ def row_string
241
+ row&.reject(&:nil?)&.map { |r| r && "%s=%s" % [r[:name], r[:value].inspect] }&.join(", ")
242
+ end
227
243
 
228
- def string
229
- "(%s) → (%s)" % [key_string, row_string]
230
- end
244
+ def string
245
+ "(%s) → (%s)" % [key_string, row_string]
246
+ end
231
247
 
232
- # Find the previous row version by following the roll_ptr from one undo
233
- # record to the next (backwards through the record version history). Since
234
- # we are operating without the benefit of knowing about active transactions
235
- # and without protection from purge, check that everything looks sane before
236
- # returning it.
237
- def prev_by_history
238
- unless has_previous_version?
248
+ # Find the previous row version by following the roll_ptr from one undo
249
+ # record to the next (backwards through the record version history). Since
250
+ # we are operating without the benefit of knowing about active transactions
251
+ # and without protection from purge, check that everything looks sane before
252
+ # returning it.
253
+ def prev_by_history
239
254
  # This undo record type has no previous version information.
240
- return nil
241
- end
255
+ return unless previous_version?
242
256
 
243
- undo_log = roll_ptr[:undo_log]
244
- older_undo_page = @undo_page.space.page(undo_log[:page])
257
+ undo_log = roll_ptr[:undo_log]
258
+ older_undo_page = @undo_page.space.page(undo_log[:page])
245
259
 
246
- unless older_undo_page and older_undo_page.is_a?(Innodb::Page::UndoLog)
247
260
  # The page was probably re-used for something else.
248
- return nil
249
- end
261
+ return unless older_undo_page.is_a?(Innodb::Page::UndoLog)
250
262
 
251
- older_undo_record = new_subordinate(older_undo_page,
252
- undo_log[:offset])
263
+ older_undo_record = new_subordinate(older_undo_page, undo_log[:offset])
253
264
 
254
- unless older_undo_record and table_id == older_undo_record.table_id
255
265
  # The record space was probably re-used for something else.
256
- return nil
257
- end
266
+ return unless older_undo_record && table_id == older_undo_record.table_id
258
267
 
259
- unless older_undo_record.trx_id.nil? or trx_id >= older_undo_record.trx_id
260
268
  # The trx_id should not be newer; but may be absent (for insert).
261
- return nil
262
- end
269
+ return unless older_undo_record.trx_id.nil? || trx_id >= older_undo_record.trx_id
263
270
 
264
- older_undo_record
265
- end
266
-
267
- def dump
268
- puts "Undo record at offset %i" % offset
269
- puts
270
-
271
- puts "Header:"
272
- puts " %-25s: %i" % ["Previous record offset", header[:prev]]
273
- puts " %-25s: %i" % ["Next record offset", header[:next]]
274
- puts " %-25s: %s" % ["Type", header[:type]]
275
- puts
276
-
277
- puts "System fields:"
278
- puts " Transaction ID: %s" % trx_id
279
- puts " Roll Pointer:"
280
- puts " Undo Log: page %i, offset %i" % [
281
- roll_ptr[:undo_log][:page],
282
- roll_ptr[:undo_log][:offset],
283
- ]
284
- puts " Rollback Segment ID: %i" % roll_ptr[:rseg_id]
285
- puts
286
-
287
- puts "Key fields:"
288
- key.each do |field|
289
- puts " %s: %s" % [
290
- field[:name],
291
- field[:value].inspect,
292
- ]
271
+ older_undo_record
293
272
  end
294
- puts
295
-
296
- puts "Non-key fields:"
297
- row.each do |field|
298
- next if !field
299
- puts " %s: %s" % [
300
- field[:name],
301
- field[:value].inspect,
273
+
274
+ def dump
275
+ puts "Undo record at offset %i" % offset
276
+ puts
277
+
278
+ puts "Header:"
279
+ puts " %-25s: %i" % ["Previous record offset", header[:prev]]
280
+ puts " %-25s: %i" % ["Next record offset", header[:next]]
281
+ puts " %-25s: %s" % ["Type", header[:type]]
282
+ puts
283
+
284
+ puts "System fields:"
285
+ puts " Transaction ID: %s" % trx_id
286
+ puts " Roll Pointer:"
287
+ puts " Undo Log: page %i, offset %i" % [
288
+ roll_ptr[:undo_log][:page],
289
+ roll_ptr[:undo_log][:offset],
302
290
  ]
291
+ puts " Rollback Segment ID: %i" % roll_ptr[:rseg_id]
292
+ puts
293
+
294
+ puts "Key fields:"
295
+ key.each do |field|
296
+ puts " %s: %s" % [
297
+ field[:name],
298
+ field[:value].inspect,
299
+ ]
300
+ end
301
+ puts
302
+
303
+ puts "Non-key fields:"
304
+ row.each do |field|
305
+ next unless field
306
+
307
+ puts " %s: %s" % [
308
+ field[:name],
309
+ field[:value].inspect,
310
+ ]
311
+ end
312
+ puts
303
313
  end
304
- puts
305
314
  end
306
-
307
315
  end