innodb_ruby 0.7.11 → 0.7.12
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.
- data/bin/innodb_space +162 -25
- data/lib/innodb.rb +8 -1
- data/lib/innodb/checksum.rb +30 -0
- data/lib/innodb/cursor.rb +165 -37
- data/lib/innodb/field.rb +31 -57
- data/lib/innodb/field_type.rb +124 -0
- data/lib/innodb/fseg_entry.rb +9 -6
- data/lib/innodb/index.rb +23 -12
- data/lib/innodb/inode.rb +133 -0
- data/lib/innodb/list.rb +44 -12
- data/lib/innodb/log.rb +1 -0
- data/lib/innodb/log_block.rb +2 -1
- data/lib/innodb/page.rb +93 -17
- data/lib/innodb/page/blob.rb +60 -0
- data/lib/innodb/page/fsp_hdr_xdes.rb +34 -24
- data/lib/innodb/page/index.rb +364 -190
- data/lib/innodb/page/inode.rb +20 -51
- data/lib/innodb/page/sys.rb +22 -0
- data/lib/innodb/page/sys_data_dictionary_header.rb +92 -0
- data/lib/innodb/page/sys_rseg_header.rb +59 -0
- data/lib/innodb/page/trx_sys.rb +72 -29
- data/lib/innodb/page/undo_log.rb +95 -0
- data/lib/innodb/record_describer.rb +2 -1
- data/lib/innodb/space.rb +162 -17
- data/lib/innodb/undo_log.rb +73 -0
- data/lib/innodb/version.rb +2 -1
- data/lib/innodb/xdes.rb +44 -11
- metadata +19 -6
data/bin/innodb_space
CHANGED
@@ -36,7 +36,7 @@ def print_xdes_list(list)
|
|
36
36
|
list.each do |entry|
|
37
37
|
puts "%-12i%-64s" % [
|
38
38
|
entry.xdes[:start_page],
|
39
|
-
entry.each_page_status.inject("") { |bitmap, page_status|
|
39
|
+
entry.each_page_status.inject("") { |bitmap, (page_number, page_status)|
|
40
40
|
bitmap += page_status[:free] ? "." : "#"
|
41
41
|
bitmap
|
42
42
|
},
|
@@ -151,29 +151,13 @@ def space_indexes(space)
|
|
151
151
|
|
152
152
|
space.each_index do |index|
|
153
153
|
index.each_fseg do |fseg_name, fseg|
|
154
|
-
fragments =
|
155
|
-
fseg[:frag_array].inject(0) { |c, i| c += 1 if i; c }
|
156
|
-
|
157
|
-
used =
|
158
|
-
fragments +
|
159
|
-
fseg[:not_full_n_used] +
|
160
|
-
space.pages_per_extent * fseg[:full].base[:length]
|
161
|
-
|
162
|
-
allocated =
|
163
|
-
fragments +
|
164
|
-
space.pages_per_extent * fseg[:full].base[:length] +
|
165
|
-
space.pages_per_extent * fseg[:not_full].base[:length] +
|
166
|
-
space.pages_per_extent * fseg[:free].base[:length]
|
167
|
-
|
168
|
-
fill_factor = allocated > 0 ? 100.0 * (used.to_f / allocated.to_f) : 0.0
|
169
|
-
|
170
154
|
puts "%-12i%-12i%-12s%-12i%-12i%-12s" % [
|
171
155
|
index.id,
|
172
156
|
index.root.offset,
|
173
157
|
fseg_name,
|
174
|
-
|
175
|
-
|
176
|
-
"%.2f%%" % fill_factor,
|
158
|
+
fseg.used_pages,
|
159
|
+
fseg.total_pages,
|
160
|
+
"%.2f%%" % fseg.fill_factor,
|
177
161
|
]
|
178
162
|
end
|
179
163
|
end
|
@@ -229,6 +213,134 @@ def space_extents(space)
|
|
229
213
|
print_xdes_list(space.each_xdes)
|
230
214
|
end
|
231
215
|
|
216
|
+
def print_inode_summary(inode)
|
217
|
+
puts "INODE fseg_id=%d, pages=%d, frag=%d, full=%d, not_full=%d, free=%d" % [
|
218
|
+
inode.fseg_id,
|
219
|
+
inode.total_pages,
|
220
|
+
inode.frag_array_n_used,
|
221
|
+
inode.full.length,
|
222
|
+
inode.not_full.length,
|
223
|
+
inode.free.length,
|
224
|
+
]
|
225
|
+
end
|
226
|
+
|
227
|
+
def print_inode_detail(inode)
|
228
|
+
puts "INODE fseg_id=%d, pages=%d, frag=%d pages (%s), full=%d extents (%s), not_full=%d extents (%s) (%d/%d pages used), free=%d extents (%s)" % [
|
229
|
+
inode.fseg_id,
|
230
|
+
inode.total_pages,
|
231
|
+
inode.frag_array_n_used,
|
232
|
+
inode.frag_array_pages.join(", "),
|
233
|
+
inode.full.length,
|
234
|
+
inode.full.each.to_a.map { |x| "#{x.start_page}-#{x.end_page}" }.join(", "),
|
235
|
+
inode.not_full.length,
|
236
|
+
inode.not_full.each.to_a.map { |x| "#{x.start_page}-#{x.end_page}" }.join(", "),
|
237
|
+
inode.not_full_n_used,
|
238
|
+
inode.not_full.length * inode.space.pages_per_extent,
|
239
|
+
inode.free.length,
|
240
|
+
inode.free.each.to_a.map { |x| "#{x.start_page}-#{x.end_page}" }.join(", "),
|
241
|
+
]
|
242
|
+
end
|
243
|
+
|
244
|
+
def space_inodes_summary(space)
|
245
|
+
space.each_inode do |inode|
|
246
|
+
print_inode_summary(inode)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def space_inodes_detail(space)
|
251
|
+
space.each_inode do |inode|
|
252
|
+
print_inode_detail(inode)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def page_account(space, page_number)
|
257
|
+
puts "Accounting for page #{page_number}:"
|
258
|
+
|
259
|
+
if page_number > space.pages
|
260
|
+
puts " Page does not exist."
|
261
|
+
return
|
262
|
+
end
|
263
|
+
|
264
|
+
page = space.page(page_number)
|
265
|
+
puts " Page type is #{page.type}."
|
266
|
+
|
267
|
+
xdes = space.xdes_for_page(page_number)
|
268
|
+
puts " Extent descriptor for pages %d-%d is at page %d, offset %d." % [
|
269
|
+
xdes.start_page,
|
270
|
+
xdes.end_page,
|
271
|
+
xdes.this[:page],
|
272
|
+
xdes.this[:offset],
|
273
|
+
]
|
274
|
+
|
275
|
+
if xdes.allocated_to_fseg?
|
276
|
+
puts " Extent is fully allocated to fseg #{xdes.fseg_id}."
|
277
|
+
else
|
278
|
+
puts " Extent is not fully allocated to an fseg; may be a fragment extent."
|
279
|
+
end
|
280
|
+
|
281
|
+
xdes_status = xdes.page_status(page_number)
|
282
|
+
puts " Page is marked as %s in extent descriptor." % [
|
283
|
+
xdes_status[:free] ? 'free' : 'used'
|
284
|
+
]
|
285
|
+
|
286
|
+
space.each_xdes_list do |name, list|
|
287
|
+
if list.include? xdes
|
288
|
+
puts " Extent is in #{name} list of space."
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
page_inode = nil
|
293
|
+
space.each_inode do |inode|
|
294
|
+
inode.each_list do |name, list|
|
295
|
+
if list.include? xdes
|
296
|
+
page_inode = inode
|
297
|
+
puts " Extent is in #{name} list of fseg #{inode.fseg_id}."
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
if inode.frag_array.include? page_number
|
302
|
+
page_inode = inode
|
303
|
+
puts " Page is in fragment array of fseg %d." % [
|
304
|
+
inode.fseg_id,
|
305
|
+
]
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
space.each_index do |index|
|
310
|
+
index.each_fseg do |fseg_name, fseg|
|
311
|
+
if page_inode == fseg
|
312
|
+
puts " Fseg is in #{fseg_name} fseg of index #{index.id}."
|
313
|
+
puts " Index root is page #{index.root.offset}."
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
if space.system_space?
|
319
|
+
if page_inode == space.trx_sys.fseg
|
320
|
+
puts " Fseg is trx_sys."
|
321
|
+
end
|
322
|
+
|
323
|
+
if page_inode == space.trx_sys.doublewrite[:fseg]
|
324
|
+
puts " Fseg is doublewrite buffer."
|
325
|
+
end
|
326
|
+
|
327
|
+
space.data_dictionary.each_index do |table_name, index_name, index|
|
328
|
+
index.each_fseg do |fseg_name, fseg|
|
329
|
+
if page_inode == fseg
|
330
|
+
puts " Index is #{table_name}.#{index_name} of data dictionary."
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
space.trx_sys.rsegs.each_with_index do |rseg_slot, index|
|
336
|
+
if page.fil_header[:space_id] == rseg_slot[:space_id] &&
|
337
|
+
page.fil_header[:offset] == rseg_slot[:page_number]
|
338
|
+
puts " Page is a rollback segment in slot #{index}."
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
232
344
|
def page_directory_summary(page)
|
233
345
|
puts "%-8s%-8s%-14s%-8s%s" % [
|
234
346
|
"slot",
|
@@ -264,16 +376,15 @@ def index_fseg_lists(index, fseg_name)
|
|
264
376
|
end
|
265
377
|
|
266
378
|
def index_fseg_list_iterate(index, fseg_name, list_name)
|
267
|
-
unless index.fseg(fseg_name)
|
379
|
+
unless fseg = index.fseg(fseg_name)
|
268
380
|
raise "File segment '#{fseg_name}' doesn't exist"
|
269
381
|
end
|
270
382
|
|
271
|
-
|
272
|
-
unless fseg[list_name] && fseg[list_name].is_a?(Innodb::List)
|
383
|
+
unless list = fseg.list(list_name)
|
273
384
|
raise "List '#{list_name}' doesn't exist"
|
274
385
|
end
|
275
386
|
|
276
|
-
print_xdes_list(
|
387
|
+
print_xdes_list(list)
|
277
388
|
end
|
278
389
|
|
279
390
|
def index_fseg_frag_pages(index, fseg_name)
|
@@ -444,9 +555,18 @@ The following modes are supported:
|
|
444
555
|
space-extents
|
445
556
|
Iterate through all extents, printing the extent descriptor bitmap.
|
446
557
|
|
558
|
+
space-inodes-summary
|
559
|
+
Iterate through all inodes, printing a short summary of each FSEG.
|
560
|
+
|
561
|
+
space-inodes-detail
|
562
|
+
Iterate through all inodes, printing a detailed report of each FSEG.
|
563
|
+
|
447
564
|
page-dump
|
448
565
|
Dump the contents of a page, using the Ruby pp ("pretty-print") module.
|
449
566
|
|
567
|
+
page-account
|
568
|
+
Account for a page's usage in FSEGs.
|
569
|
+
|
450
570
|
page-directory-summary
|
451
571
|
Summarize the record contents of the page directory in a page. If a record
|
452
572
|
describer is available, the key of each record will be printed.
|
@@ -500,6 +620,7 @@ Signal.trap("PIPE") { exit }
|
|
500
620
|
|
501
621
|
getopt_options = [
|
502
622
|
[ "--help", "-?", GetoptLong::NO_ARGUMENT ],
|
623
|
+
[ "--trace", "-t", GetoptLong::NO_ARGUMENT ],
|
503
624
|
[ "--file", "-f", GetoptLong::REQUIRED_ARGUMENT ],
|
504
625
|
[ "--page-size", "-P", GetoptLong::REQUIRED_ARGUMENT ],
|
505
626
|
[ "--page", "-p", GetoptLong::REQUIRED_ARGUMENT ],
|
@@ -515,6 +636,8 @@ getopt.each do |opt, arg|
|
|
515
636
|
case opt
|
516
637
|
when "--help"
|
517
638
|
usage 0
|
639
|
+
when "--trace"
|
640
|
+
Innodb::Cursor.trace!
|
518
641
|
when "--mode"
|
519
642
|
@options.mode = arg
|
520
643
|
when "--file"
|
@@ -544,7 +667,9 @@ end
|
|
544
667
|
space = Innodb::Space.new(@options.file, @options.page_size)
|
545
668
|
|
546
669
|
if @options.describer
|
547
|
-
space.record_describer =
|
670
|
+
unless space.record_describer = eval(@options.describer)
|
671
|
+
space.record_describer = Innodb::RecordDescriber.const_get(@options.describer)
|
672
|
+
end
|
548
673
|
end
|
549
674
|
|
550
675
|
if ARGV.empty?
|
@@ -561,6 +686,14 @@ ARGV.each do |mode|
|
|
561
686
|
@options.pages.each do |page_number|
|
562
687
|
space.page(page_number).dump
|
563
688
|
end
|
689
|
+
when "page-account"
|
690
|
+
if @options.pages.empty?
|
691
|
+
usage 1, "Page numbers to dump must be provided with --page/-p"
|
692
|
+
end
|
693
|
+
|
694
|
+
@options.pages.each do |page_number|
|
695
|
+
page_account(space, page_number)
|
696
|
+
end
|
564
697
|
when "page-directory-summary"
|
565
698
|
if @options.pages.empty?
|
566
699
|
usage 1, "Page numbers to dump must be provided with --page/-p"
|
@@ -595,6 +728,10 @@ ARGV.each do |mode|
|
|
595
728
|
space_indexes(space)
|
596
729
|
when "space-extents"
|
597
730
|
space_extents(space)
|
731
|
+
when "space-inodes-summary"
|
732
|
+
space_inodes_summary(space)
|
733
|
+
when "space-inodes-detail"
|
734
|
+
space_inodes_detail(space)
|
598
735
|
when "index-recurse"
|
599
736
|
unless space.record_describer
|
600
737
|
usage 1, "Record describer necessary for index recursion"
|
data/lib/innodb.rb
CHANGED
@@ -1,18 +1,25 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
1
2
|
# A set of classes for parsing and working with InnoDB data files.
|
2
3
|
module Innodb; end
|
3
4
|
|
4
5
|
require "enumerator"
|
5
6
|
|
6
7
|
require "innodb/version"
|
8
|
+
require "innodb/checksum"
|
7
9
|
require "innodb/page"
|
10
|
+
require "innodb/page/blob"
|
8
11
|
require "innodb/page/fsp_hdr_xdes"
|
9
12
|
require "innodb/page/inode"
|
10
13
|
require "innodb/page/index"
|
11
14
|
require "innodb/page/trx_sys"
|
15
|
+
require "innodb/page/sys"
|
16
|
+
require "innodb/page/undo_log"
|
12
17
|
require "innodb/record_describer"
|
13
18
|
require "innodb/field"
|
14
19
|
require "innodb/space"
|
20
|
+
require "innodb/inode"
|
15
21
|
require "innodb/index"
|
16
22
|
require "innodb/log_block"
|
17
23
|
require "innodb/log"
|
18
|
-
require "innodb/
|
24
|
+
require "innodb/undo_log"
|
25
|
+
require "innodb/xdes"
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
class Innodb::Checksum
|
3
|
+
MAX = 0xFFFFFFFF.freeze
|
4
|
+
MASK1 = 1463735687.freeze
|
5
|
+
MASK2 = 1653893711.freeze
|
6
|
+
|
7
|
+
# This is derived from ut_fold_ulint_pair in include/ut0rnd.ic in the
|
8
|
+
# InnoDB source code. Since Ruby's Bignum class is *much* slower than its
|
9
|
+
# Fixnum class, we mask back to 32 bits to keep things from overflowing
|
10
|
+
# and being promoted to Bignum.
|
11
|
+
def self.fold_pair(n1, n2)
|
12
|
+
(((((((n1 ^ n2 ^ MASK2) << 8) & MAX) + n1) & MAX) ^ MASK1) + n2) & MAX
|
13
|
+
end
|
14
|
+
|
15
|
+
# Iterate through the provided enumerator, which is expected to return a
|
16
|
+
# Fixnum (or something coercible to it), and "fold" them together to produce
|
17
|
+
# a single value.
|
18
|
+
def self.fold_enumerator(enumerator)
|
19
|
+
fold = 0
|
20
|
+
enumerator.each do |byte|
|
21
|
+
fold = fold_pair(fold, byte)
|
22
|
+
end
|
23
|
+
fold
|
24
|
+
end
|
25
|
+
|
26
|
+
# A simple helper (and example) to fold a provided string.
|
27
|
+
def self.fold_string(string)
|
28
|
+
fold_enumerator(string.bytes)
|
29
|
+
end
|
30
|
+
end
|
data/lib/innodb/cursor.rb
CHANGED
@@ -1,62 +1,156 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
1
2
|
require "bindata"
|
2
3
|
|
3
4
|
# A cursor to walk through InnoDB data structures to read fields.
|
4
5
|
class Innodb::Cursor
|
5
|
-
|
6
|
+
|
7
|
+
# An entry in a stack of cursors. The cursor position, direction, and
|
8
|
+
# name array are each attributes of the current cursor stack and are
|
9
|
+
# manipulated together.
|
10
|
+
class StackEntry
|
11
|
+
attr_accessor :cursor
|
12
|
+
attr_accessor :position
|
13
|
+
attr_accessor :direction
|
14
|
+
attr_accessor :name
|
15
|
+
|
16
|
+
def initialize(cursor, position=0, direction=:forward, name=nil)
|
17
|
+
@cursor = cursor
|
18
|
+
@position = position
|
19
|
+
@direction = direction
|
20
|
+
@name = name || []
|
21
|
+
end
|
22
|
+
|
23
|
+
def dup
|
24
|
+
StackEntry.new(cursor, position, direction, name.dup)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
@@tracing = false
|
29
|
+
|
30
|
+
# Enable tracing for all Innodb::Cursor objects.
|
31
|
+
def self.trace!(arg=true)
|
32
|
+
@@tracing = arg
|
33
|
+
end
|
34
|
+
|
35
|
+
# Initialize a cursor within a buffer at the given position.
|
36
|
+
def initialize(buffer, position)
|
6
37
|
@buffer = buffer
|
7
|
-
@
|
8
|
-
|
38
|
+
@stack = [ StackEntry.new(self, position) ]
|
39
|
+
|
40
|
+
trace_with :print_trace
|
41
|
+
end
|
42
|
+
|
43
|
+
# Print a trace output for this cursor. The method is passed a cursor object,
|
44
|
+
# position, raw byte buffer, and array of names.
|
45
|
+
def print_trace(cursor, position, bytes, name)
|
46
|
+
slice_size = 16
|
47
|
+
bytes.each_slice(slice_size).each_with_index do |slice_bytes, slice_count|
|
48
|
+
puts "%06i %s %-32s %s" % [
|
49
|
+
position + (slice_count * slice_size),
|
50
|
+
direction == :backward ? "←" : "→",
|
51
|
+
slice_bytes.map { |n| "%02x" % n }.join,
|
52
|
+
slice_count == 0 ? name.join(".") : "↵",
|
53
|
+
]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Set a Proc or method on self to trace with.
|
58
|
+
def trace_with(arg=nil)
|
59
|
+
if arg.nil?
|
60
|
+
@trace_proc = nil
|
61
|
+
elsif arg.class == Proc
|
62
|
+
@trace_proc = arg
|
63
|
+
elsif arg.class == Symbol
|
64
|
+
@trace_proc = lambda { |cursor, position, bytes, name| self.send(arg, cursor, position, bytes, name) }
|
65
|
+
else
|
66
|
+
raise "Don't know how to trace with #{arg}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Generate a trace record from the current cursor.
|
71
|
+
def trace(position, bytes, name)
|
72
|
+
@trace_proc.call(self, position, bytes, name) if @@tracing && @trace_proc
|
73
|
+
end
|
74
|
+
|
75
|
+
# The current cursor object; the top of the stack.
|
76
|
+
def current
|
77
|
+
@stack.last
|
78
|
+
end
|
79
|
+
|
80
|
+
# Set the field name.
|
81
|
+
def name(name_arg=nil)
|
82
|
+
if name_arg.nil?
|
83
|
+
return current.name
|
84
|
+
end
|
85
|
+
|
86
|
+
unless block_given?
|
87
|
+
raise "No block given"
|
88
|
+
end
|
89
|
+
|
90
|
+
current.name.push name_arg
|
91
|
+
ret = yield(self)
|
92
|
+
current.name.pop
|
93
|
+
ret
|
94
|
+
end
|
95
|
+
|
96
|
+
# Return the direction of the current cursor.
|
97
|
+
def direction(direction_arg=nil)
|
98
|
+
if direction_arg.nil?
|
99
|
+
return current.direction
|
100
|
+
end
|
101
|
+
|
102
|
+
current.direction = direction_arg
|
103
|
+
self
|
9
104
|
end
|
10
105
|
|
11
106
|
# Set the direction of the cursor to "forward".
|
12
107
|
def forward
|
13
|
-
|
14
|
-
self
|
108
|
+
direction(:forward)
|
15
109
|
end
|
16
110
|
|
17
111
|
# Set the direction of the cursor to "backward".
|
18
112
|
def backward
|
19
|
-
|
20
|
-
self
|
113
|
+
direction(:backward)
|
21
114
|
end
|
22
115
|
|
23
116
|
# Return the position of the current cursor.
|
24
117
|
def position
|
25
|
-
|
118
|
+
current.position
|
26
119
|
end
|
27
120
|
|
28
121
|
# Move the current cursor to a new absolute position.
|
29
|
-
def seek(
|
30
|
-
|
122
|
+
def seek(position)
|
123
|
+
current.position = position if position
|
31
124
|
self
|
32
125
|
end
|
33
126
|
|
34
127
|
# Adjust the current cursor to a new relative position.
|
35
|
-
def adjust(
|
36
|
-
|
128
|
+
def adjust(relative_position)
|
129
|
+
current.position += relative_position
|
37
130
|
self
|
38
131
|
end
|
39
132
|
|
40
133
|
# Save the current cursor position and start a new (nested, stacked) cursor.
|
41
|
-
def push(
|
42
|
-
@
|
134
|
+
def push(position=nil)
|
135
|
+
@stack.push current.dup
|
136
|
+
seek(position)
|
43
137
|
self
|
44
138
|
end
|
45
139
|
|
46
140
|
# Restore the last cursor position.
|
47
141
|
def pop
|
48
|
-
raise "No cursors to pop" unless @
|
49
|
-
@
|
142
|
+
raise "No cursors to pop" unless @stack.size > 1
|
143
|
+
@stack.pop
|
50
144
|
self
|
51
145
|
end
|
52
146
|
|
53
147
|
# Execute a block and restore the cursor to the previous position after
|
54
148
|
# the block returns. Return the block's return value after restoring the
|
55
|
-
# cursor.
|
56
|
-
def peek
|
149
|
+
# cursor. Optionally seek to provided position before executing block.
|
150
|
+
def peek(position=nil)
|
57
151
|
raise "No block given" unless block_given?
|
58
|
-
push
|
59
|
-
result = yield
|
152
|
+
push(position)
|
153
|
+
result = yield(self)
|
60
154
|
pop
|
61
155
|
result
|
62
156
|
end
|
@@ -65,16 +159,17 @@ class Innodb::Cursor
|
|
65
159
|
# position and adjust the cursor position by that amount.
|
66
160
|
def read_and_advance(length)
|
67
161
|
data = nil
|
68
|
-
|
69
|
-
case
|
162
|
+
cursor_start = current.position
|
163
|
+
case current.direction
|
70
164
|
when :forward
|
71
|
-
data = @buffer.data(
|
165
|
+
data = @buffer.data(current.position, length)
|
72
166
|
adjust(length)
|
73
167
|
when :backward
|
74
168
|
adjust(-length)
|
75
|
-
data = @buffer.data(
|
169
|
+
data = @buffer.data(current.position, length)
|
76
170
|
end
|
77
|
-
|
171
|
+
|
172
|
+
trace(cursor_start, data.bytes, current.name)
|
78
173
|
data
|
79
174
|
end
|
80
175
|
|
@@ -83,49 +178,68 @@ class Innodb::Cursor
|
|
83
178
|
read_and_advance(length)
|
84
179
|
end
|
85
180
|
|
181
|
+
def each_byte_as_uint8(length)
|
182
|
+
unless block_given?
|
183
|
+
return enum_for(:each_byte_as_uint8, length)
|
184
|
+
end
|
185
|
+
|
186
|
+
read_and_advance(length).bytes.each do |byte|
|
187
|
+
yield byte
|
188
|
+
end
|
189
|
+
|
190
|
+
nil
|
191
|
+
end
|
192
|
+
|
86
193
|
# Return raw bytes as hex.
|
87
194
|
def get_hex(length)
|
88
195
|
read_and_advance(length).bytes.map { |c| "%02x" % c }.join
|
89
196
|
end
|
90
197
|
|
91
198
|
# Read an unsigned 8-bit integer.
|
92
|
-
def get_uint8(
|
93
|
-
seek(
|
199
|
+
def get_uint8(position=nil)
|
200
|
+
seek(position)
|
94
201
|
data = read_and_advance(1)
|
95
202
|
BinData::Uint8.read(data)
|
96
203
|
end
|
97
204
|
|
98
205
|
# Read a big-endian unsigned 16-bit integer.
|
99
|
-
def get_uint16(
|
100
|
-
seek(
|
206
|
+
def get_uint16(position=nil)
|
207
|
+
seek(position)
|
101
208
|
data = read_and_advance(2)
|
102
209
|
BinData::Uint16be.read(data)
|
103
210
|
end
|
104
211
|
|
105
212
|
# Read a big-endian signed 16-bit integer.
|
106
|
-
def get_sint16(
|
107
|
-
seek(
|
213
|
+
def get_sint16(position=nil)
|
214
|
+
seek(position)
|
108
215
|
data = read_and_advance(2)
|
109
216
|
BinData::Int16be.read(data)
|
110
217
|
end
|
111
218
|
|
112
219
|
# Read a big-endian unsigned 24-bit integer.
|
113
|
-
def get_uint24(
|
114
|
-
seek(
|
220
|
+
def get_uint24(position=nil)
|
221
|
+
seek(position)
|
115
222
|
data = read_and_advance(3)
|
116
223
|
BinData::Uint24be.read(data)
|
117
224
|
end
|
118
225
|
|
119
226
|
# Read a big-endian unsigned 32-bit integer.
|
120
|
-
def get_uint32(
|
121
|
-
seek(
|
227
|
+
def get_uint32(position=nil)
|
228
|
+
seek(position)
|
122
229
|
data = read_and_advance(4)
|
123
230
|
BinData::Uint32be.read(data)
|
124
231
|
end
|
125
232
|
|
233
|
+
# Read a big-endian unsigned 48-bit integer.
|
234
|
+
def get_uint48(position=nil)
|
235
|
+
seek(position)
|
236
|
+
data = read_and_advance(6)
|
237
|
+
BinData::Uint48be.read(data)
|
238
|
+
end
|
239
|
+
|
126
240
|
# Read a big-endian unsigned 64-bit integer.
|
127
|
-
def get_uint64(
|
128
|
-
seek(
|
241
|
+
def get_uint64(position=nil)
|
242
|
+
seek(position)
|
129
243
|
data = read_and_advance(8)
|
130
244
|
BinData::Uint64be.read(data)
|
131
245
|
end
|
@@ -141,6 +255,8 @@ class Innodb::Cursor
|
|
141
255
|
get_uint24
|
142
256
|
when 4
|
143
257
|
get_uint32
|
258
|
+
when 6
|
259
|
+
get_uint48
|
144
260
|
when 8
|
145
261
|
get_uint64
|
146
262
|
else
|
@@ -148,6 +264,10 @@ class Innodb::Cursor
|
|
148
264
|
end
|
149
265
|
end
|
150
266
|
|
267
|
+
def get_uint_array_by_size(size, count)
|
268
|
+
(0...count).to_a.inject([]) { |a, n| a << get_uint_by_size(size); a }
|
269
|
+
end
|
270
|
+
|
151
271
|
# Read an InnoDB-compressed unsigned 32-bit integer.
|
152
272
|
def get_ic_uint32
|
153
273
|
flag = peek { get_uint8 }
|
@@ -193,6 +313,12 @@ class Innodb::Cursor
|
|
193
313
|
BinData::Int32be.read(data) ^ (-1 << 31)
|
194
314
|
end
|
195
315
|
|
316
|
+
# Read an InnoDB-munged signed 48-bit integer.
|
317
|
+
def get_i_sint48
|
318
|
+
data = read_and_advance(6)
|
319
|
+
BinData::Int48be.read(data) ^ (-1 << 47)
|
320
|
+
end
|
321
|
+
|
196
322
|
# Read an InnoDB-munged signed 64-bit integer.
|
197
323
|
def get_i_sint64
|
198
324
|
data = read_and_advance(8)
|
@@ -210,6 +336,8 @@ class Innodb::Cursor
|
|
210
336
|
get_i_sint24
|
211
337
|
when 4
|
212
338
|
get_i_sint32
|
339
|
+
when 6
|
340
|
+
get_i_sint48
|
213
341
|
when 8
|
214
342
|
get_i_sint64
|
215
343
|
else
|