Class: Innodb::Log

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

Defined Under Namespace

Classes: Checkpoint, CheckpointGroup, CheckpointSet, Header

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,
}.freeze
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.



58
59
60
61
62
63
# File 'lib/innodb/log.rb', line 58

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.



72
73
74
# File 'lib/innodb/log.rb', line 72

def blocks
  @blocks
end

#capacityObject (readonly)

The log capacity (in bytes).



69
70
71
# File 'lib/innodb/log.rb', line 69

def capacity
  @capacity
end

#sizeObject (readonly)

The size (in bytes) of the log.



66
67
68
# File 'lib/innodb/log.rb', line 66

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.



139
140
141
142
143
144
# File 'lib/innodb/log.rb', line 139

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.



83
84
85
# File 'lib/innodb/log.rb', line 83

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.



75
76
77
78
79
80
# File 'lib/innodb/log.rb', line 75

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.



128
129
130
131
132
133
134
135
# File 'lib/innodb/log.rb', line 128

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 ||= CheckpointSet.new(
    checkpoint_1: block_cursor(offset1).name("checkpoint_1") { |c| read_checkpoint(c) },
    checkpoint_2: block_cursor(offset2).name("checkpoint_2") { |c| read_checkpoint(c) }
  )
end

#each_blockObject

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



148
149
150
151
152
153
# File 'lib/innodb/log.rb', line 148

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.



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

def header
  offset = LOG_HEADER_BLOCK_MAP[:LOG_FILE_HEADER] * Innodb::LogBlock::BLOCK_SIZE
  @header ||= block_cursor(offset).name("header") do |c|
    Header.new(
      group_id: c.name("group_id") { c.read_uint32 },
      start_lsn: c.name("start_lsn") { c.read_uint64 },
      file_no: c.name("file_no") { c.read_uint32 },
      created_by: c.name("created_by") { c.read_string(32) }
    )
  end
end

#read_checkpoint(cursor) ⇒ Object

Read a log checkpoint from the given cursor.



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/innodb/log.rb', line 101

def read_checkpoint(cursor)
  # 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.
  Checkpoint.new(
    number: cursor.name("number") { cursor.read_uint64 },
    lsn: cursor.name("lsn") { cursor.read_uint64 },
    lsn_offset: cursor.name("lsn_offset") { cursor.read_uint32 },
    buffer_size: cursor.name("buffer_size") { cursor.read_uint32 },
    archived_lsn: cursor.name("archived_lsn") { cursor.read_uint64 },
    group_array:
      (0..(LOG_CHECKPOINT_GROUPS - 1)).map do |n|
        cursor.name("group_array[#{n}]") do
          CheckpointGroup.new(
            archived_file_no: cursor.name("archived_file_no") { cursor.read_uint32 },
            archived_offset: cursor.name("archived_offset") { cursor.read_uint32 }
          )
        end
      end,
    checksum_1: cursor.name("checksum_1") { cursor.read_uint32 },
    checksum_2: cursor.name("checksum_2") { cursor.read_uint32 },
    fsp_free_limit: cursor.name("fsp_free_limit") { cursor.read_uint32 },
    fsp_magic: cursor.name("fsp_magic") { cursor.read_uint32 }
  )
end