Class: Innodb::Log

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

Overview

An InnoDB transaction log file.

Constant Summary collapse

LOG_HEADER_BLOCK_MAP =

A map of the name and position of the blocks that form the log header.

{
  :LOG_FILE_HEADER  => 0,
  :LOG_CHECKPOINT_1 => 1,
  :EMPTY            => 2,
  :LOG_CHECKPOINT_2 => 3,
}
LOG_HEADER_BLOCKS =

Number of blocks in the log file header.

LOG_HEADER_BLOCK_MAP.size
LOG_CHECKPOINT_GROUPS =

Maximum number of log group checkpoints.

32

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file) ⇒ Log

Open a log file.



21
22
23
24
25
# File 'lib/innodb/log.rb', line 21

def initialize(file)
  @file = File.open(file)
  @size = @file.stat.size
  @blocks = (@size / Innodb::LogBlock::BLOCK_SIZE) - LOG_HEADER_BLOCKS
end

Instance Attribute Details

#blocks ⇒ Object (readonly)

The number of blocks in the the log.



31
32
33
# File 'lib/innodb/log.rb', line 31

def blocks
  @blocks
end

#size ⇒ Object (readonly)

The size (in bytes) of the log.



28
29
30
# File 'lib/innodb/log.rb', line 28

def size
  @size
end

Instance Method Details

#block(block_index) ⇒ Object

Return a log block with a given block index as an InnoDB::LogBlock object. Blocks are indexed after the log file header, starting from 0.



101
102
103
104
105
# File 'lib/innodb/log.rb', line 101

def block(block_index)
  return nil unless block_index.between?(0, @blocks - 1)
  offset = (LOG_HEADER_BLOCKS + block_index.to_i) * Innodb::LogBlock::BLOCK_SIZE
  Innodb::LogBlock.new(block_data(offset))
end

#block_cursor(offset) ⇒ Object

Get a cursor to a block in a given offset of the log.



41
42
43
# File 'lib/innodb/log.rb', line 41

def block_cursor(offset)
  Innodb::Cursor.new(block_data(offset), 0)
end

#block_data(offset) ⇒ Object

Get the raw byte buffer for a specific block by block offset.



34
35
36
37
38
# File 'lib/innodb/log.rb', line 34

def block_data(offset)
  raise "Invalid block offset" unless (offset % Innodb::LogBlock::BLOCK_SIZE).zero?
  @file.seek(offset)
  @file.read(Innodb::LogBlock::BLOCK_SIZE)
end

#checkpoint ⇒ Object

Return the log checkpoints.



85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/innodb/log.rb', line 85

def checkpoint
  offset1 = LOG_HEADER_BLOCK_MAP[:LOG_CHECKPOINT_1] * Innodb::LogBlock::BLOCK_SIZE
  offset2 = LOG_HEADER_BLOCK_MAP[:LOG_CHECKPOINT_2] * Innodb::LogBlock::BLOCK_SIZE
  @checkpoint ||=
    {
      :checkpoint_1 => block_cursor(offset1).name("checkpoint_1") do |cursor|
        read_checkpoint(cursor)
      end,
      :checkpoint_2 => block_cursor(offset2).name("checkpoint_2") do |cursor|
        read_checkpoint(cursor)
      end
    }
end

#each_block ⇒ Object

Iterate through all log blocks, returning the block index and an InnoDB::LogBlock object for each block.



109
110
111
112
113
114
# File 'lib/innodb/log.rb', line 109

def each_block
  (0...@blocks).each do |block_index|
    current_block = block(block_index)
    yield block_index, current_block if current_block
  end
end

#header ⇒ Object

Return the log header.



46
47
48
49
50
51
52
53
54
55
# File 'lib/innodb/log.rb', line 46

def header
  offset = LOG_HEADER_BLOCK_MAP[:LOG_FILE_HEADER] * Innodb::LogBlock::BLOCK_SIZE
  @header ||= block_cursor(offset).name("header") do |c|
    {
      :group_id   => c.name("group_id")   { c.get_uint32 },
      :start_lsn  => c.name("start_lsn")  { c.get_uint64 },
      :created_by => c.name("created_by") { c.seek(16).get_bytes(4) }
    }
  end
end

#read_checkpoint(c) ⇒ Object

Read a log checkpoint from the given cursor.



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/innodb/log.rb', line 58

def read_checkpoint(c)
  # Log archive related fields (e.g. group_array) are not currently in
  # use or even read by InnoDB. However, for the sake of completeness,
  # they are included.
  {
    :number         => c.name("number")       { c.get_uint64 },
    :lsn            => c.name("lsn")          { c.get_uint64 },
    :offset         => c.name("offset")       { c.get_uint32 },
    :buffer_size    => c.name("buffer_size")  { c.get_uint32 },
    :archived_lsn   => c.name("archived_lsn") { c.get_uint64 },
    :group_array    =>
      (0 .. LOG_CHECKPOINT_GROUPS - 1).map do |n|
        c.name("group_array[#{n}]") do
          {
            :archived_file_no => c.name("archived_file_no") { c.get_uint32 },
            :archived_offset  => c.name("archived_offset")  { c.get_uint32 },
          }
        end
      end,
    :checksum_1     => c.name("checksum_1")     { c.get_uint32 },
    :checksum_2     => c.name("checksum_2")     { c.get_uint32 },
    :fsp_free_limit => c.name("fsp_free_limit") { c.get_uint32 },
    :fsp_magic      => c.name("fsp_magic")      { c.get_uint32 },
  }
end