Class: Innodb::Cursor
- Inherits:
-
Object
- Object
- Innodb::Cursor
- Defined in:
- lib/innodb/cursor.rb
Overview
A cursor to walk through InnoDB data structures to read fields.
Defined Under Namespace
Classes: StackEntry
Constant Summary collapse
- @@tracing =
false
Class Method Summary collapse
-
.trace!(arg = true) ⇒ Object
Enable tracing for all Innodb::Cursor objects.
Instance Method Summary collapse
-
#adjust(relative_position) ⇒ Object
Adjust the current cursor to a new relative position.
-
#backward ⇒ Object
Set the direction of the cursor to "backward".
-
#current ⇒ Object
The current cursor object; the top of the stack.
-
#direction(direction_arg = nil) ⇒ Object
Return the direction of the current cursor.
- #each_byte_as_uint8(length) ⇒ Object
-
#forward ⇒ Object
Set the direction of the cursor to "forward".
-
#get_bit_array(num_bits) ⇒ Object
Read an array of 1-bit integers.
-
#get_bytes(length) ⇒ Object
Return raw bytes.
-
#get_hex(length) ⇒ Object
Return raw bytes as hex.
-
#get_i_sint16 ⇒ Object
Read an InnoDB-munged signed 16-bit integer.
-
#get_i_sint24 ⇒ Object
Read an InnoDB-munged signed 24-bit integer.
-
#get_i_sint32 ⇒ Object
Read an InnoDB-munged signed 32-bit integer.
-
#get_i_sint48 ⇒ Object
Read an InnoDB-munged signed 48-bit integer.
-
#get_i_sint64 ⇒ Object
Read an InnoDB-munged signed 64-bit integer.
-
#get_i_sint8 ⇒ Object
Read an InnoDB-munged signed 8-bit integer.
-
#get_i_sint_by_size(size) ⇒ Object
Read an InnoDB-munged signed integer given its size in bytes.
-
#get_ic_uint32 ⇒ Object
Read an InnoDB-compressed unsigned 32-bit integer.
-
#get_sint16(position = nil) ⇒ Object
Read a big-endian signed 16-bit integer.
-
#get_uint16(position = nil) ⇒ Object
Read a big-endian unsigned 16-bit integer.
-
#get_uint24(position = nil) ⇒ Object
Read a big-endian unsigned 24-bit integer.
-
#get_uint32(position = nil) ⇒ Object
Read a big-endian unsigned 32-bit integer.
-
#get_uint48(position = nil) ⇒ Object
Read a big-endian unsigned 48-bit integer.
-
#get_uint64(position = nil) ⇒ Object
Read a big-endian unsigned 64-bit integer.
-
#get_uint8(position = nil) ⇒ Object
Read an unsigned 8-bit integer.
- #get_uint_array_by_size(size, count) ⇒ Object
-
#get_uint_by_size(size) ⇒ Object
Read a big-endian unsigned integer given its size in bytes.
-
#initialize(buffer, position) ⇒ Cursor
constructor
Initialize a cursor within a buffer at the given position.
-
#name(name_arg = nil) ⇒ Object
Set the field name.
-
#peek(position = nil) ⇒ Object
Execute a block and restore the cursor to the previous position after the block returns.
-
#pop ⇒ Object
Restore the last cursor position.
-
#position ⇒ Object
Return the position of the current cursor.
-
#print_trace(cursor, position, bytes, name) ⇒ Object
Print a trace output for this cursor.
-
#push(position = nil) ⇒ Object
Save the current cursor position and start a new (nested, stacked) cursor.
-
#read_and_advance(length) ⇒ Object
Read a number of bytes forwards or backwards from the current cursor position and adjust the cursor position by that amount.
-
#seek(position) ⇒ Object
Move the current cursor to a new absolute position.
-
#trace(position, bytes, name) ⇒ Object
Generate a trace record from the current cursor.
-
#trace_with(arg = nil) ⇒ Object
Set a Proc or method on self to trace with.
Constructor Details
#initialize(buffer, position) ⇒ Cursor
Initialize a cursor within a buffer at the given position.
36 37 38 39 40 41 |
# File 'lib/innodb/cursor.rb', line 36 def initialize(buffer, position) @buffer = buffer @stack = [ StackEntry.new(self, position) ] trace_with :print_trace end |
Class Method Details
.trace!(arg = true) ⇒ Object
Enable tracing for all Innodb::Cursor objects.
31 32 33 |
# File 'lib/innodb/cursor.rb', line 31 def self.trace!(arg=true) @@tracing = arg end |
Instance Method Details
#adjust(relative_position) ⇒ Object
Adjust the current cursor to a new relative position.
128 129 130 131 |
# File 'lib/innodb/cursor.rb', line 128 def adjust(relative_position) current.position += relative_position self end |
#backward ⇒ Object
Set the direction of the cursor to "backward".
112 113 114 |
# File 'lib/innodb/cursor.rb', line 112 def backward direction(:backward) end |
#current ⇒ Object
The current cursor object; the top of the stack.
76 77 78 |
# File 'lib/innodb/cursor.rb', line 76 def current @stack.last end |
#direction(direction_arg = nil) ⇒ Object
Return the direction of the current cursor.
97 98 99 100 101 102 103 104 |
# File 'lib/innodb/cursor.rb', line 97 def direction(direction_arg=nil) if direction_arg.nil? return current.direction end current.direction = direction_arg self end |
#each_byte_as_uint8(length) ⇒ Object
181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/innodb/cursor.rb', line 181 def each_byte_as_uint8(length) unless block_given? return enum_for(:each_byte_as_uint8, length) end read_and_advance(length).bytes.each do |byte| yield byte end nil end |
#forward ⇒ Object
Set the direction of the cursor to "forward".
107 108 109 |
# File 'lib/innodb/cursor.rb', line 107 def forward direction(:forward) end |
#get_bit_array(num_bits) ⇒ Object
Read an array of 1-bit integers.
349 350 351 352 353 354 |
# File 'lib/innodb/cursor.rb', line 349 def get_bit_array(num_bits) size = (num_bits + 7) / 8 data = read_and_advance(size) bit_array = BinData::Array.new(:type => :bit1, :initial_length => size * 8) bit_array.read(data).to_ary end |
#get_bytes(length) ⇒ Object
Return raw bytes.
177 178 179 |
# File 'lib/innodb/cursor.rb', line 177 def get_bytes(length) read_and_advance(length) end |
#get_hex(length) ⇒ Object
Return raw bytes as hex.
194 195 196 |
# File 'lib/innodb/cursor.rb', line 194 def get_hex(length) read_and_advance(length).bytes.map { |c| "%02x" % c }.join end |
#get_i_sint16 ⇒ Object
Read an InnoDB-munged signed 16-bit integer.
299 300 301 302 |
# File 'lib/innodb/cursor.rb', line 299 def get_i_sint16 data = read_and_advance(2) BinData::Int16be.read(data) ^ (-1 << 15) end |
#get_i_sint24 ⇒ Object
Read an InnoDB-munged signed 24-bit integer.
305 306 307 308 |
# File 'lib/innodb/cursor.rb', line 305 def get_i_sint24 data = read_and_advance(3) BinData::Int24be.read(data) ^ (-1 << 23) end |
#get_i_sint32 ⇒ Object
Read an InnoDB-munged signed 32-bit integer.
311 312 313 314 |
# File 'lib/innodb/cursor.rb', line 311 def get_i_sint32 data = read_and_advance(4) BinData::Int32be.read(data) ^ (-1 << 31) end |
#get_i_sint48 ⇒ Object
Read an InnoDB-munged signed 48-bit integer.
317 318 319 320 |
# File 'lib/innodb/cursor.rb', line 317 def get_i_sint48 data = read_and_advance(6) BinData::Int48be.read(data) ^ (-1 << 47) end |
#get_i_sint64 ⇒ Object
Read an InnoDB-munged signed 64-bit integer.
323 324 325 326 |
# File 'lib/innodb/cursor.rb', line 323 def get_i_sint64 data = read_and_advance(8) BinData::Int64be.read(data) ^ (-1 << 63) end |
#get_i_sint8 ⇒ Object
Read an InnoDB-munged signed 8-bit integer.
293 294 295 296 |
# File 'lib/innodb/cursor.rb', line 293 def get_i_sint8 data = read_and_advance(1) BinData::Int8.read(data) ^ (-1 << 7) end |
#get_i_sint_by_size(size) ⇒ Object
Read an InnoDB-munged signed integer given its size in bytes.
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 |
# File 'lib/innodb/cursor.rb', line 329 def get_i_sint_by_size(size) case size when 1 get_i_sint8 when 2 get_i_sint16 when 3 get_i_sint24 when 4 get_i_sint32 when 6 get_i_sint48 when 8 get_i_sint64 else raise "Not implemented" end end |
#get_ic_uint32 ⇒ Object
Read an InnoDB-compressed unsigned 32-bit integer.
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/innodb/cursor.rb', line 272 def get_ic_uint32 flag = peek { get_uint8 } case when flag < 0x80 get_uint8 when flag < 0xc0 get_uint16 & 0x7fff when flag < 0xe0 get_uint24 & 0x3fffff when flag < 0xf0 get_uint32 & 0x1fffffff when flag == 0xf0 adjust(+1) # Skip the flag. get_uint32 else raise "Invalid flag #{flag.to_s(16)} seen" end end |
#get_sint16(position = nil) ⇒ Object
Read a big-endian signed 16-bit integer.
213 214 215 216 217 |
# File 'lib/innodb/cursor.rb', line 213 def get_sint16(position=nil) seek(position) data = read_and_advance(2) BinData::Int16be.read(data) end |
#get_uint16(position = nil) ⇒ Object
Read a big-endian unsigned 16-bit integer.
206 207 208 209 210 |
# File 'lib/innodb/cursor.rb', line 206 def get_uint16(position=nil) seek(position) data = read_and_advance(2) BinData::Uint16be.read(data) end |
#get_uint24(position = nil) ⇒ Object
Read a big-endian unsigned 24-bit integer.
220 221 222 223 224 |
# File 'lib/innodb/cursor.rb', line 220 def get_uint24(position=nil) seek(position) data = read_and_advance(3) BinData::Uint24be.read(data) end |
#get_uint32(position = nil) ⇒ Object
Read a big-endian unsigned 32-bit integer.
227 228 229 230 231 |
# File 'lib/innodb/cursor.rb', line 227 def get_uint32(position=nil) seek(position) data = read_and_advance(4) BinData::Uint32be.read(data) end |
#get_uint48(position = nil) ⇒ Object
Read a big-endian unsigned 48-bit integer.
234 235 236 237 238 |
# File 'lib/innodb/cursor.rb', line 234 def get_uint48(position=nil) seek(position) data = read_and_advance(6) BinData::Uint48be.read(data) end |
#get_uint64(position = nil) ⇒ Object
Read a big-endian unsigned 64-bit integer.
241 242 243 244 245 |
# File 'lib/innodb/cursor.rb', line 241 def get_uint64(position=nil) seek(position) data = read_and_advance(8) BinData::Uint64be.read(data) end |
#get_uint8(position = nil) ⇒ Object
Read an unsigned 8-bit integer.
199 200 201 202 203 |
# File 'lib/innodb/cursor.rb', line 199 def get_uint8(position=nil) seek(position) data = read_and_advance(1) BinData::Uint8.read(data) end |
#get_uint_array_by_size(size, count) ⇒ Object
267 268 269 |
# File 'lib/innodb/cursor.rb', line 267 def get_uint_array_by_size(size, count) (0...count).to_a.inject([]) { |a, n| a << get_uint_by_size(size); a } end |
#get_uint_by_size(size) ⇒ Object
Read a big-endian unsigned integer given its size in bytes.
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
# File 'lib/innodb/cursor.rb', line 248 def get_uint_by_size(size) case size when 1 get_uint8 when 2 get_uint16 when 3 get_uint24 when 4 get_uint32 when 6 get_uint48 when 8 get_uint64 else raise "Not implemented" end end |
#name(name_arg = nil) ⇒ Object
Set the field name.
81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/innodb/cursor.rb', line 81 def name(name_arg=nil) if name_arg.nil? return current.name end unless block_given? raise "No block given" end current.name.push name_arg ret = yield(self) current.name.pop ret end |
#peek(position = nil) ⇒ Object
Execute a block and restore the cursor to the previous position after the block returns. Return the block's return value after restoring the cursor. Optionally seek to provided position before executing block.
150 151 152 153 154 155 156 |
# File 'lib/innodb/cursor.rb', line 150 def peek(position=nil) raise "No block given" unless block_given? push(position) result = yield(self) pop result end |
#pop ⇒ Object
Restore the last cursor position.
141 142 143 144 145 |
# File 'lib/innodb/cursor.rb', line 141 def pop raise "No cursors to pop" unless @stack.size > 1 @stack.pop self end |
#position ⇒ Object
Return the position of the current cursor.
117 118 119 |
# File 'lib/innodb/cursor.rb', line 117 def position current.position end |
#print_trace(cursor, position, bytes, name) ⇒ Object
Print a trace output for this cursor. The method is passed a cursor object, position, raw byte buffer, and array of names.
45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/innodb/cursor.rb', line 45 def print_trace(cursor, position, bytes, name) slice_size = 16 bytes.each_slice(slice_size).each_with_index do |slice_bytes, slice_count| puts "%06i %s %-32s %s" % [ position + (slice_count * slice_size), direction == :backward ? "←" : "→", slice_bytes.map { |n| "%02x" % n }.join, slice_count == 0 ? name.join(".") : "↵", ] end end |
#push(position = nil) ⇒ Object
Save the current cursor position and start a new (nested, stacked) cursor.
134 135 136 137 138 |
# File 'lib/innodb/cursor.rb', line 134 def push(position=nil) @stack.push current.dup seek(position) self end |
#read_and_advance(length) ⇒ Object
Read a number of bytes forwards or backwards from the current cursor position and adjust the cursor position by that amount.
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/innodb/cursor.rb', line 160 def read_and_advance(length) data = nil cursor_start = current.position case current.direction when :forward data = @buffer.data(current.position, length) adjust(length) when :backward adjust(-length) data = @buffer.data(current.position, length) end trace(cursor_start, data.bytes, current.name) data end |
#seek(position) ⇒ Object
Move the current cursor to a new absolute position.
122 123 124 125 |
# File 'lib/innodb/cursor.rb', line 122 def seek(position) current.position = position if position self end |
#trace(position, bytes, name) ⇒ Object
Generate a trace record from the current cursor.
71 72 73 |
# File 'lib/innodb/cursor.rb', line 71 def trace(position, bytes, name) @trace_proc.call(self, position, bytes, name) if @@tracing && @trace_proc end |
#trace_with(arg = nil) ⇒ Object
Set a Proc or method on self to trace with.
58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/innodb/cursor.rb', line 58 def trace_with(arg=nil) if arg.nil? @trace_proc = nil elsif arg.class == Proc @trace_proc = arg elsif arg.class == Symbol @trace_proc = lambda { |cursor, position, bytes, name| self.send(arg, cursor, position, bytes, name) } else raise "Don't know how to trace with #{arg}" end end |