Class: Innodb::LogBlock

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

Overview

An InnoDB transaction log block.

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.



31
32
33
34
35
36
37
# File 'lib/innodb/log_block.rb', line 31

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

  @buffer = buffer
end

Instance Method Details

#calculate_checksumObject

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



94
95
96
97
98
99
100
101
102
# File 'lib/innodb/log_block.rb', line 94

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

#checksumObject

A helper function to return the checksum from the trailer, for easier access.



88
89
90
# File 'lib/innodb/log_block.rb', line 88

def checksum
  trailer[:checksum]
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)


106
107
108
# File 'lib/innodb/log_block.rb', line 106

def corrupt?
  checksum != calculate_checksum
end

#cursor(offset) ⇒ Object

Return an BufferCursor object positioned at a specific offset.



40
41
42
# File 'lib/innodb/log_block.rb', line 40

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.



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

def data(offset = DATA_OFFSET)
  length = header[:data_length]

  if length == BLOCK_SIZE
    length -= TRAILER_SIZE
  end

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

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

#dumpObject

Dump the contents of a log block for debugging purposes.



111
112
113
114
115
116
117
118
119
# File 'lib/innodb/log_block.rb', line 111

def dump
  puts
  puts "header:"
  pp header

  puts
  puts "trailer:"
  pp trailer
end

#headerObject

Return the log block header.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/innodb/log_block.rb', line 45

def header
  @header ||= cursor(HEADER_OFFSET).name("header") do |c|
    {
      :flush => c.name("flush") {
        c.peek { (c.get_uint32 & HEADER_FLUSH_BIT_MASK) > 0 }
      },
      :block_number => c.name("block_number") {
        c.get_uint32 & ~HEADER_FLUSH_BIT_MASK
      },
      :data_length      => c.name("data_length")     { c.get_uint16 },
      :first_rec_group  => c.name("first_rec_group") { c.get_uint16 },
      :checkpoint_no    => c.name("checkpoint_no")   { c.get_uint32 },
    }
  end
end

#trailerObject

Return the log block trailer.



78
79
80
81
82
83
84
# File 'lib/innodb/log_block.rb', line 78

def trailer
  @trailer ||= cursor(TRAILER_OFFSET).name("trailer") do |c|
    {
      :checksum => c.name("checksum") { c.get_uint32 },
    }
  end
end