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_HEADER_SIZE =

The size in bytes of the log file header.

LOG_HEADER_BLOCKS * Innodb::LogBlock::BLOCK_SIZE
LOG_CHECKPOINT_GROUPS =

Maximum number of log group checkpoints.

32

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(filename) ⇒ Log

Open a log file.



23
24
25
26
27
28
# File 'lib/innodb/log.rb', line 23

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

Instance Attribute Details

#blocksObject (readonly)

The number of blocks in the log.



37
38
39
# File 'lib/innodb/log.rb', line 37

def blocks
  @blocks
end

#capacityObject (readonly)

The log capacity (in bytes).



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

def capacity
  @capacity
end

#sizeObject (readonly)

The size (in bytes) of the log.



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

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.



112
113
114
115
116
# File 'lib/innodb/log.rb', line 112

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.



47
48
49
# File 'lib/innodb/log.rb', line 47

def block_cursor(offset)
  BufferCursor.new(block_data(offset), 0)
end

#block_data(offset) ⇒ Object

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



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

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

#checkpointObject

Return the log checkpoints.



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/innodb/log.rb', line 92

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|
        cp = read_checkpoint(cursor)
        cp.delete(:group_array)
        cp
      end,
      :checkpoint_2 => block_cursor(offset2).name("checkpoint_2") do |cursor|
        cp = read_checkpoint(cursor)
        cp.delete(:group_array)
        cp
      end
    }
end

#each_blockObject

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



120
121
122
123
124
125
# File 'lib/innodb/log.rb', line 120

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

#headerObject

Return the log header.



52
53
54
55
56
57
58
59
60
61
62
# File 'lib/innodb/log.rb', line 52

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 },
      :file_no    => c.name("file_no")    { c.get_uint32 },
      :created_by => c.name("created_by") { c.get_string(32) }
    }
  end
end

#read_checkpoint(c) ⇒ Object

Read a log checkpoint from the given cursor.



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/innodb/log.rb', line 65

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 },
    :lsn_offset     => c.name("lsn_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