Class: Innodb::Page::FspHdrXdes

Inherits:
Innodb::Page show all
Defined in:
lib/innodb/page/fsp_hdr_xdes.rb

Overview

A specialized class for FSP_HDR (filespace header) and XDES (extent descriptor) page types. Each tablespace always has an FSP_HDR page as its first page (page 0), and has repeating XDES pages every 16,384 pages after that (page 16384, 32768, ...). The FSP_HDR and XDES page structure is completely identical, with the exception that the FSP header structure is zero-filled on XDES pages, but populated on FSP_HDR pages.

The basic structure of FSP_HDR and XDES pages is: FIL header, FSP header, an array of 256 XDES entries, empty (unused) space, and FIL trailer.

Constant Summary collapse

FLAGS_PAGE_SIZE_ADJUST =

A value added to the adjusted exponent stored in the page size field of the flags in the FSP header.

9

Constants inherited from Innodb::Page

PAGE_TYPE, PAGE_TYPE_BY_VALUE, SPECIALIZED_CLASSES

Instance Attribute Summary

Attributes inherited from Innodb::Page

#space

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Innodb::Page

#calculate_checksum, #checksum, #corrupt?, #cursor, #data, #fil_header, handle, #initialize, #inspect, #lsn, maybe_undefined, #next, #offset, parse, #pos_fil_header, #pos_fil_trailer, #pos_page_body, #prev, #size, #size_fil_header, #size_fil_trailer, #type

Constructor Details

This class inherits a constructor from Innodb::Page

Class Method Details

.decode_flags(flags) ⇒ Object

Decode the "flags" field in the FSP header, returning a hash of useful decoded flags. Unfortunately, InnoDB has a fairly weird and broken implementation of these flags. The flags are:

Offset Size Description 0 1 Page Format (redundant, compact). This is unfortunately coerced to 0 if it is "compact" and no other flags are set, making it useless to innodb_ruby. 1 4 Compressed Page Size (zip_size). This is stored as a power of 2, minus 9. Since 0 is reserved to mean "not compressed", the minimum value is 1, thus making the smallest page size 1024 (2 ** (9 + 1)). 5 1 Table Format (Antelope, Barracuda). This was supposed to reserve 6 bits, but due to a bug in InnoDB only actually reserved 1 bit.



42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/innodb/page/fsp_hdr_xdes.rb', line 42

def self.decode_flags(flags)
  # The page size for compressed pages is stored at bit offset 1 and consumes
  # 4 bits. Value 0 means the page is not compressed.
  page_size = read_bits_at_offset(flags, 4, 1)
  {
    :compressed => page_size == 0 ? false : true,
    :page_size => page_size == 0 ?
      Innodb::Space::DEFAULT_PAGE_SIZE :
      (1 << (FLAGS_PAGE_SIZE_ADJUST + page_size)),
    :value => flags,
  }
end

.read_bits_at_offset(data, bits, offset) ⇒ Object

Read a given number of bits from an integer at a specific bit offset. The value returned is 0-based so does not need further shifting or adjustment.



22
23
24
# File 'lib/innodb/page/fsp_hdr_xdes.rb', line 22

def self.read_bits_at_offset(data, bits, offset)
  ((data & (((1 << bits) - 1) << offset)) >> offset)
end

Instance Method Details

#dumpObject

Dump the contents of a page for debugging purposes.



138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/innodb/page/fsp_hdr_xdes.rb', line 138

def dump
  super

  puts "fsp header:"
  pp fsp_header
  puts

  puts "xdes entries:"
  each_xdes do |xdes|
    pp xdes
  end
  puts
end

#each_listObject

Iterate through all lists in the file space.



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

def each_list
  unless block_given?
    return enum_for(:each_list)
  end

  fsp_header.each do |key, value|
    yield key, value if value.is_a?(Innodb::List)
  end
end

#each_xdesObject

Iterate through all XDES entries in order. This is useful for debugging, but each of these entries is actually a node in some other list. The state field in the XDES entry indicates which type of list it is present in, although not necessarily which list (e.g. :fseg).



125
126
127
128
129
130
131
132
133
134
135
# File 'lib/innodb/page/fsp_hdr_xdes.rb', line 125

def each_xdes
  unless block_given?
    return enum_for(:each_xdes)
  end

  cursor(pos_xdes_array).name("xdes_array") do |c|
    entries_in_xdes_array.times do |n|
      yield Innodb::Xdes.new(self, c)
    end
  end
end

#entries_in_xdes_arrayObject

The number of entries in the XDES array. Defined as page size divided by extent size.



73
74
75
# File 'lib/innodb/page/fsp_hdr_xdes.rb', line 73

def entries_in_xdes_array
  size / space.pages_per_extent
end

#fsp_headerObject

Read the FSP (filespace) header, which contains a few counters and flags, as well as list base nodes for each list maintained in the filespace.



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/innodb/page/fsp_hdr_xdes.rb', line 79

def fsp_header
  @fsp_header ||= cursor(pos_fsp_header).name("fsp") do |c|
    {
      :space_id           => c.name("space_id") { c.get_uint32 },
      :unused             => c.name("unused") { c.get_uint32 },
      :size               => c.name("size") { c.get_uint32 },
      :free_limit         => c.name("free_limit") { c.get_uint32 },
      :flags              => c.name("flags") { 
        self.class.decode_flags(c.get_uint32)
      },
      :frag_n_used        => c.name("frag_n_used") { c.get_uint32 },
      :free               => c.name("list[free]") {
        Innodb::List::Xdes.new(@space, Innodb::List.get_base_node(c))
      },
      :free_frag          => c.name("list[free_frag]") {
        Innodb::List::Xdes.new(@space, Innodb::List.get_base_node(c))
      },
      :full_frag          => c.name("list[full_frag]") {
        Innodb::List::Xdes.new(@space, Innodb::List.get_base_node(c))
      },
      :first_unused_seg   => c.name("first_unused_seg") { c.get_uint64 },
      :full_inodes        => c.name("list[full_inodes]") {
        Innodb::List::Inode.new(@space, Innodb::List.get_base_node(c))
      },
      :free_inodes        => c.name("list[free_inodes]") {
        Innodb::List::Inode.new(@space, Innodb::List.get_base_node(c))
      },
    }
  end
end

#pos_fsp_headerObject

The FSP header immediately follows the FIL header.



56
57
58
# File 'lib/innodb/page/fsp_hdr_xdes.rb', line 56

def pos_fsp_header
  pos_fil_header + size_fil_header
end

#pos_xdes_arrayObject

The XDES entry array immediately follows the FSP header.



67
68
69
# File 'lib/innodb/page/fsp_hdr_xdes.rb', line 67

def pos_xdes_array
  pos_fsp_header + size_fsp_header
end

#size_fsp_headerObject

The FSP header contains six 32-bit integers, one 64-bit integer, and 5 list base nodes.



62
63
64
# File 'lib/innodb/page/fsp_hdr_xdes.rb', line 62

def size_fsp_header
  ((4 * 6) + (1 * 8) + (5 * Innodb::List::BASE_NODE_SIZE))
end