innodb_ruby 0.7.11 → 0.7.12
Sign up to get free protection for your applications and to get access to all the features.
- 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
|