class Innodb::LogRecord

Constants

INFO_AND_STATUS_MASK

Flag of whether an insert log record contains info and status.

Index
IndexFieldInfo
LENGTH_NULL
Preamble
RECORD_TYPES

InnoDB log record types.

RECORD_TYPE_MASK
SINGLE_RECORD_MASK

Single record flag is masked in the record type.

UNDO_TYPES

Types of undo log segments.

Attributes

lsn[RW]

Start and end LSNs for this record.

payload[R]
preamble[R]
size[R]

The size (in bytes) of the record.

Public Instance Methods

dump() click to toggle source

Dump the contents of the record.

# File lib/innodb/log_record.rb, line 102
def dump
  pp({ lsn: lsn, size: size, preamble: @preamble, payload: @payload })
end
read(cursor) click to toggle source
# File lib/innodb/log_record.rb, line 94
def read(cursor)
  origin = cursor.position
  @preamble = read_preamble(cursor)
  @payload = read_payload(@preamble.type, cursor)
  @size = cursor.position - origin
end
read_clust_delete_mark(cursor) click to toggle source

Read the log record for delete marking or unmarking of a clustered index record. Ref. btr_cur_parse_del_mark_set_clust_rec

# File lib/innodb/log_record.rb, line 217
def read_clust_delete_mark(cursor)
  {
    flags: cursor.name("flags") { cursor.read_uint8 },
    value: cursor.name("value") { cursor.read_uint8 },
    sys_fields: cursor.name("sys_fields") { read_sys_fields(cursor) },
    offset: cursor.name("offset") { cursor.read_uint16 },
  }
end
read_index(cursor) click to toggle source

Read the index part of a log record for a compact record insert. Ref. mlog_parse_index

# File lib/innodb/log_record.rb, line 132
def read_index(cursor)
  n_cols = cursor.name("n_cols") { cursor.read_uint16 }
  n_uniq = cursor.name("n_uniq") { cursor.read_uint16 }
  cols = n_cols.times.collect do
    info = cursor.name("field_info") { cursor.read_uint16 }
    IndexFieldInfo.new(
      mtype: ((info + 1) & 0x7fff) <= 1 ? :BINARY : :FIXBINARY,
      prtype: (info & 0x8000).zero? ? nil : :NOT_NULL,
      length: info & 0x7fff
    )
  end

  Index.new(n_cols: n_cols, n_uniq: n_uniq, cols: cols)
end
read_insert_record(cursor) click to toggle source

Read the insert record into page part of a insert log. Ref. page_cur_parse_insert_rec

# File lib/innodb/log_record.rb, line 152
def read_insert_record(cursor)
  page_offset = cursor.name("page_offset") { cursor.read_uint16 }
  end_seg_len = cursor.name("end_seg_len") { cursor.read_ic_uint32 }

  if (end_seg_len & INFO_AND_STATUS_MASK) != 0
    info_and_status_bits = cursor.read_uint8
    origin_offset = cursor.read_ic_uint32
    mismatch_index = cursor.read_ic_uint32
  end

  {
    page_offset: page_offset,
    end_seg_len: end_seg_len >> 1,
    info_and_status_bits: info_and_status_bits,
    origin_offset: origin_offset,
    mismatch_index: mismatch_index,
    record: cursor.name("record") { cursor.read_bytes(end_seg_len >> 1) },
  }
end
read_payload(type, cursor) click to toggle source

The bodies of the branches here are sometimes duplicates, but logically distinct. rubocop:disable Lint/DuplicateBranch

# File lib/innodb/log_record.rb, line 228
def read_payload(type, cursor)
  case type
  when :MLOG_1BYTE, :MLOG_2BYTE, :MLOG_4BYTE
    {
      page_offset: cursor.name("page_offset") { cursor.read_uint16 },
      value: cursor.name("value") { cursor.read_ic_uint32 },
    }
  when :MLOG_8BYTE
    {
      offset: cursor.name("offset") { cursor.read_uint16 },
      value: cursor.name("value") { cursor.read_ic_uint64 },
    }
  when :UNDO_HDR_CREATE, :UNDO_HDR_REUSE
    {
      trx_id: cursor.name("trx_id") { cursor.read_ic_uint64 },
    }
  when :UNDO_INSERT
    {
      length: length = cursor.name("length") { cursor.read_uint16 },
      value: cursor.name("value") { cursor.read_bytes(length) },
    }
  when :REC_INSERT
    {
      record: cursor.name("record") { read_insert_record(cursor) },
    }
  when :COMP_REC_INSERT
    {
      index: cursor.name("index") { read_index(cursor) },
      record: cursor.name("record") { read_insert_record(cursor) },
    }
  when :COMP_REC_UPDATE_IN_PLACE
    {
      index: cursor.name("index") { read_index(cursor) },
      record: cursor.name("record") { read_update_in_place_record(cursor) },
    }
  when :REC_UPDATE_IN_PLACE
    {
      record: cursor.name("record") { read_update_in_place_record(cursor) },
    }
  when :WRITE_STRING
    {
      offset: cursor.name("offset") { cursor.read_uint16 },
      length: length = cursor.name("length") { cursor.read_uint16 },
      value: cursor.name("value") { cursor.read_bytes(length) },
    }
  when :UNDO_INIT
    {
      type: cursor.name("type") { UNDO_TYPES[cursor.read_ic_uint32] },
    }
  when :FILE_CREATE, :FILE_DELETE
    {
      name_len: name_len = cursor.name("name_len") { cursor.read_uint16 },
      name: cursor.name("name") { cursor.read_bytes(name_len) },
    }
  when :FILE_CREATE2
    {
      flags: cursor.name("flags") { cursor.read_uint32 },
      name_len: name_len = cursor.name("name_len") { cursor.read_uint16 },
      name: cursor.name("name") { cursor.read_bytes(name_len) },
    }
  when :FILE_RENAME
    {
      old: {
        name_len: name_len = cursor.name("name_len") { cursor.read_uint16 },
        name: cursor.name("name") { cursor.read_bytes(name_len) },
      },
      new: {
        name_len: name_len = cursor.name("name_len") { cursor.read_uint16 },
        name: cursor.name("name") { cursor.read_bytes(name_len) },
      },
    }
  when :COMP_REC_CLUST_DELETE_MARK
    {
      index: cursor.name("index") { read_index(cursor) },
      record: cursor.name("record") { read_clust_delete_mark(cursor) },
    }
  when :REC_CLUST_DELETE_MARK
    {
      record: cursor.name("record") { read_clust_delete_mark(cursor) },
    }
  when :COMP_REC_SEC_DELETE_MARK
    {
      index: cursor.name("index") { read_index(cursor) },
      value: cursor.name("value") { cursor.read_uint8 },
      offset: cursor.name("offset") { cursor.read_uint16 },
    }
  when :REC_SEC_DELETE_MARK
    {
      value: cursor.name("value") { cursor.read_uint8 },
      offset: cursor.name("offset") { cursor.read_uint16 },
    }
  when :REC_DELETE
    {
      offset: cursor.name("offset") { cursor.read_uint16 },
    }
  when :COMP_REC_DELETE
    {
      index: cursor.name("index") { read_index(cursor) },
      offset: cursor.name("offset") { cursor.read_uint16 },
    }
  when :REC_MIN_MARK, :COMP_REC_MIN_MARK
    {
      offset: cursor.name("offset") { cursor.read_uint16 },
    }
  when :LIST_START_DELETE, :LIST_END_DELETE
    {
      offset: cursor.name("offset") { cursor.read_uint16 },
    }
  when :COMP_LIST_START_DELETE, :COMP_LIST_END_DELETE
    {
      index: cursor.name("index") { read_index(cursor) },
      offset: cursor.name("offset") { cursor.read_uint16 },
    }
  when :LIST_END_COPY_CREATED
    {
      length: length = cursor.name("length") { cursor.read_uint32 },
      data: cursor.name("data") { cursor.read_bytes(length) },
    }
  when :COMP_LIST_END_COPY_CREATE
    {
      index: cursor.name("index") { read_index(cursor) },
      length: length = cursor.name("length") { cursor.read_uint32 },
      data: cursor.name("data") { cursor.read_bytes(length) },
    }
  when :COMP_PAGE_REORGANIZE
    {
      index: cursor.name("index") { read_index(cursor) },
    }
  when :DUMMY_RECORD, :MULTI_REC_END, :INIT_FILE_PAGE,
       :IBUF_BITMAP_INIT, :PAGE_CREATE, :COMP_PAGE_CREATE,
       :PAGE_REORGANIZE, :UNDO_ERASE_END, :UNDO_HDR_DISCARD
    {}
  else
    raise "Unsupported log record type: #{type}"
  end
end
read_preamble(cursor) click to toggle source

Return a preamble of the first record in this block.

# File lib/innodb/log_record.rb, line 111
def read_preamble(cursor)
  type_and_flag = cursor.name("type") { cursor.read_uint8 }
  type = type_and_flag & RECORD_TYPE_MASK
  type = RECORD_TYPES[type] || type
  # Whether this is a single record for a single page.
  single_record = (type_and_flag & SINGLE_RECORD_MASK).positive?
  case type
  when :MULTI_REC_END, :DUMMY_RECORD
    Preamble.new(type: type)
  else
    Preamble.new(
      type: type,
      single_record: single_record,
      space: cursor.name("space") { cursor.read_ic_uint32 },
      page_number: cursor.name("page_number") { cursor.read_ic_uint32 }
    )
  end
end
read_sys_fields(cursor) click to toggle source

Read system fields values in a log record. Ref. row_upd_parse_sys_vals

# File lib/innodb/log_record.rb, line 206
def read_sys_fields(cursor)
  {
    trx_id_pos: cursor.name("trx_id_pos") { cursor.read_ic_uint32 },
    roll_ptr: cursor.name("roll_ptr") { cursor.read_bytes(7) },
    trx_id: cursor.name("trx_id") { cursor.read_ic_uint64 },
  }
end
read_update_in_place_record(cursor) click to toggle source

Read the log record for an in-place update. Ref. btr_cur_parse_update_in_place

# File lib/innodb/log_record.rb, line 174
def read_update_in_place_record(cursor)
  {
    flags: cursor.name("flags") { cursor.read_uint8 },
    sys_fields: read_sys_fields(cursor),
    rec_offset: cursor.name("rec_offset") { cursor.read_uint16 },
    update_index: read_update_index(cursor),
  }
end
read_update_index(cursor) click to toggle source

Read the update vector for an update log record. Ref. row_upd_index_parse

# File lib/innodb/log_record.rb, line 187
def read_update_index(cursor)
  info_bits = cursor.name("info_bits") { cursor.read_uint8 }
  n_fields  = cursor.name("n_fields") { cursor.read_ic_uint32 }
  fields = n_fields.times.collect do
    {
      field_no: cursor.name("field_no") { cursor.read_ic_uint32 },
      len: len = cursor.name("len") { cursor.read_ic_uint32 },
      data: cursor.name("data") { len == LENGTH_NULL ? :NULL : cursor.read_bytes(len) },
    }
  end
  {
    info_bits: info_bits,
    n_fields: n_fields,
    fields: fields,
  }
end