Class: Innodb::LogBlock

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/innodb/log_block.rb

Defined Under Namespace

Classes: Header, Trailer

Constant Summary collapse

BLOCK_SIZE =

Log blocks are fixed-length at 512 bytes in InnoDB.

512
HEADER_OFFSET =

Offset of the header within the log block.

0
HEADER_SIZE =

The size of the block header.

4 + 2 + 2 + 4
TRAILER_OFFSET =

Offset of the trailer within ths log block.

BLOCK_SIZE - 4
TRAILER_SIZE =

The size of the block trailer.

4
DATA_OFFSET =

Offset of the start of data in the block.

HEADER_SIZE
DATA_SIZE =

Size of the space available for log records.

BLOCK_SIZE - HEADER_SIZE - TRAILER_SIZE
HEADER_FLUSH_BIT_MASK =

Mask used to get the flush bit in the header.

0x80000000

Instance Method Summary collapse

Constructor Details

#initialize(buffer) ⇒ LogBlock

Initialize a log block by passing in a 512-byte buffer containing the raw log block contents.



50
51
52
53
54
# File 'lib/innodb/log_block.rb', line 50

def initialize(buffer)
  raise "Log block buffer provided was not #{BLOCK_SIZE} bytes" unless buffer.size == BLOCK_SIZE

  @buffer = buffer
end

Instance Method Details

#calculate_checksumObject

Calculate the checksum of the block using InnoDB’s log block checksum algorithm.



102
103
104
105
106
107
108
109
110
# File 'lib/innodb/log_block.rb', line 102

def calculate_checksum
  csum = 1
  shift = (0..24).cycle
  cursor(0).each_byte_as_uint8(TRAILER_OFFSET) do |b|
    csum &= 0x7fffffff
    csum += b + (b << shift.next)
  end
  csum
end

#corrupt?Boolean

Is the block corrupt? Calculate the checksum of the block and compare to the stored checksum; return true or false.

Returns:

  • (Boolean)


114
115
116
# File 'lib/innodb/log_block.rb', line 114

def corrupt?
  checksum != calculate_checksum
end

#cursor(offset) ⇒ Object

Return an BufferCursor object positioned at a specific offset.



57
58
59
# File 'lib/innodb/log_block.rb', line 57

def cursor(offset)
  BufferCursor.new(@buffer, offset)
end

#data(offset = DATA_OFFSET) ⇒ Object

Return a slice of actual block data (that is, excluding header and trailer) starting at the given offset.



82
83
84
85
86
87
88
89
# File 'lib/innodb/log_block.rb', line 82

def data(offset = DATA_OFFSET)
  length = data_length
  length -= TRAILER_SIZE if length == BLOCK_SIZE

  raise "Invalid block data offset" if offset < DATA_OFFSET || offset > length

  @buffer.slice(offset, length - offset)
end

#dumpObject

Dump the contents of a log block for debugging purposes.



119
120
121
122
123
124
125
126
127
# File 'lib/innodb/log_block.rb', line 119

def dump
  puts
  puts "header:"
  pp header

  puts
  puts "trailer:"
  pp trailer
end

#headerObject

Return the log block header.



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/innodb/log_block.rb', line 62

def header
  @header ||= cursor(HEADER_OFFSET).name("header") do |c|
    Header.new(
      flush: c.name("flush") { c.peek { (c.read_uint32 & HEADER_FLUSH_BIT_MASK).positive? } },
      block_number: c.name("block_number") { c.read_uint32 & ~HEADER_FLUSH_BIT_MASK },
      data_length: c.name("data_length") { c.read_uint16 },
      first_rec_group: c.name("first_rec_group") { c.read_uint16 },
      checkpoint_no: c.name("checkpoint_no") { c.read_uint32 }
    )
  end
end

#trailerObject

Return the log block trailer.



92
93
94
95
96
# File 'lib/innodb/log_block.rb', line 92

def trailer
  @trailer ||= cursor(TRAILER_OFFSET).name("trailer") do |c|
    Trailer.new(checksum: c.name("checksum") { c.read_uint32 })
  end
end