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_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.
37 38 39 40 41 42 |
# File 'lib/innodb/cursor.rb', line 37 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.
32 33 34 |
# File 'lib/innodb/cursor.rb', line 32 def self.trace!(arg=true) @@tracing = arg end |
Instance Method Details
#adjust(relative_position) ⇒ Object
Adjust the current cursor to a new relative position.
129 130 131 132 |
# File 'lib/innodb/cursor.rb', line 129 def adjust(relative_position) current.position += relative_position self end |
#backward ⇒ Object
Set the direction of the cursor to “backward”.
113 114 115 |
# File 'lib/innodb/cursor.rb', line 113 def backward direction(:backward) end |
#current ⇒ Object
The current cursor object; the top of the stack.
77 78 79 |
# File 'lib/innodb/cursor.rb', line 77 def current @stack.last end |
#direction(direction_arg = nil) ⇒ Object
Return the direction of the current cursor.
98 99 100 101 102 103 104 105 |
# File 'lib/innodb/cursor.rb', line 98 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
182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/innodb/cursor.rb', line 182 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”.
108 109 110 |
# File 'lib/innodb/cursor.rb', line 108 def forward direction(:forward) end |
#get_bit_array(num_bits) ⇒ Object
Read an array of 1-bit integers.
294 295 296 297 298 299 |
# File 'lib/innodb/cursor.rb', line 294 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.
178 179 180 |
# File 'lib/innodb/cursor.rb', line 178 def get_bytes(length) read_and_advance(length) end |
#get_hex(length) ⇒ Object
Return raw bytes as hex.
195 196 197 |
# File 'lib/innodb/cursor.rb', line 195 def get_hex(length) read_and_advance(length).bytes.map { |c| "%02x" % c }.join end |
#get_ic_uint32 ⇒ Object
Read an InnoDB-compressed unsigned 32-bit integer.
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
# File 'lib/innodb/cursor.rb', line 273 def get_ic_uint32 flag = peek { name("ic_uint32") { get_uint8 } } case when flag < 0x80 name("uint8") { get_uint8 } when flag < 0xc0 name("uint16") { get_uint16 } & 0x7fff when flag < 0xe0 name("uint24") { get_uint24 } & 0x3fffff when flag < 0xf0 name("uint32") { get_uint32 } & 0x1fffffff when flag == 0xf0 adjust(+1) # Skip the flag. name("uint32+1") { get_uint32 } else raise "Invalid flag #{flag.to_s} seen" end end |
#get_sint16(position = nil) ⇒ Object
Read a big-endian signed 16-bit integer.
214 215 216 217 218 |
# File 'lib/innodb/cursor.rb', line 214 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.
207 208 209 210 211 |
# File 'lib/innodb/cursor.rb', line 207 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.
221 222 223 224 225 |
# File 'lib/innodb/cursor.rb', line 221 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.
228 229 230 231 232 |
# File 'lib/innodb/cursor.rb', line 228 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.
235 236 237 238 239 |
# File 'lib/innodb/cursor.rb', line 235 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.
242 243 244 245 246 |
# File 'lib/innodb/cursor.rb', line 242 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.
200 201 202 203 204 |
# File 'lib/innodb/cursor.rb', line 200 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
268 269 270 |
# File 'lib/innodb/cursor.rb', line 268 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.
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'lib/innodb/cursor.rb', line 249 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.
82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/innodb/cursor.rb', line 82 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.
151 152 153 154 155 156 157 |
# File 'lib/innodb/cursor.rb', line 151 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.
142 143 144 145 146 |
# File 'lib/innodb/cursor.rb', line 142 def pop raise "No cursors to pop" unless @stack.size > 1 @stack.pop self end |
#position ⇒ Object
Return the position of the current cursor.
118 119 120 |
# File 'lib/innodb/cursor.rb', line 118 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.
46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/innodb/cursor.rb', line 46 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.
135 136 137 138 139 |
# File 'lib/innodb/cursor.rb', line 135 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.
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/innodb/cursor.rb', line 161 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.
123 124 125 126 |
# File 'lib/innodb/cursor.rb', line 123 def seek(position) current.position = position if position self end |
#trace(position, bytes, name) ⇒ Object
Generate a trace record from the current cursor.
72 73 74 |
# File 'lib/innodb/cursor.rb', line 72 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.
59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/innodb/cursor.rb', line 59 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 |