Class: Innodb::Page

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

Overview

A generic class for any type of page, which handles reading the common FIL header and trailer, and can handle (via #parse) dispatching to a more specialized class depending on page type (which comes from the FIL header). A page being handled by Innodb::Page indicates that its type is not currently handled by any more specialized class.

Direct Known Subclasses

FspHdrXdes, Index, Inode, TrxSys

Defined Under Namespace

Classes: FspHdrXdes, Index, Inode, TrxSys

Constant Summary collapse

SPECIALIZED_CLASSES =

A hash of page types to specialized classes to handle them. Normally subclasses will register themselves in this list.

{}
PAGE_TYPE =

InnoDB Page Type constants from include/fil0fil.h.

{
  0     => :ALLOCATED,      # Freshly allocated page
  2     => :UNDO_LOG,       # Undo log page
  3     => :INODE,          # Index node
  4     => :IBUF_FREE_LIST, # Insert buffer free list
  5     => :IBUF_BITMAP,    # Insert buffer bitmap
  6     => :SYS,            # System page
  7     => :TRX_SYS,        # Transaction system data
  8     => :FSP_HDR,        # File space header
  9     => :XDES,           # Extent descriptor page
  10    => :BLOB,           # Uncompressed BLOB page
  11    => :ZBLOB,          # First compressed BLOB page
  12    => :ZBLOB2,         # Subsequent compressed BLOB page
  17855 => :INDEX,          # B-tree node
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(space, buffer) ⇒ Page

Initialize a page by passing in a buffer containing the raw page contents. The buffer size should match the space’s page size.



37
38
39
40
41
42
43
44
# File 'lib/innodb/page.rb', line 37

def initialize(space, buffer)
  unless space.page_size == buffer.size
    raise "Buffer size #{buffer.size} is different than space page size"
  end

  @space  = space
  @buffer = buffer
end

Instance Attribute Details

#spaceObject (readonly)

Returns the value of attribute space.



46
47
48
# File 'lib/innodb/page.rb', line 46

def space
  @space
end

Class Method Details

.maybe_undefined(value) ⇒ Object

A helper to convert “undefined” values stored in previous and next pointers in the page header to nil.



105
106
107
# File 'lib/innodb/page.rb', line 105

def self.maybe_undefined(value)
  value == 4294967295 ? nil : value
end

.parse(space, buffer) ⇒ Object

Load a page as a generic page in order to make the “fil” header accessible, and then attempt to hand off the page to a specialized class to be re-parsed if possible. If there is no specialized class for this type of page, return the generic object.

This could be optimized to reach into the page buffer and efficiently extract the page type in order to avoid throwing away a generic Innodb::Page object when parsing every specialized page, but this is a bit cleaner, and we’re not particularly performance sensitive.



22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/innodb/page.rb', line 22

def self.parse(space, buffer)
  # Create a page object as a generic page.
  page = Innodb::Page.new(space, buffer)

  # If there is a specialized class available for this page type, re-create
  # the page object using that specialized class.
  if specialized_class = SPECIALIZED_CLASSES[page.type]
    page = specialized_class.new(space, buffer)
  end

  page
end

Instance Method Details

#cursor(offset) ⇒ Object

Return an Innodb::Cursor object positioned at a specific offset.



60
61
62
# File 'lib/innodb/page.rb', line 60

def cursor(offset)
  Innodb::Cursor.new(self, offset)
end

#data(offset, length) ⇒ Object

A helper function to return bytes from the page buffer based on offset and length, both in bytes.



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

def data(offset, length)
  @buffer[offset...(offset + length)]
end

#dumpObject

Dump the contents of a page for debugging purposes.



174
175
176
177
178
179
180
181
# File 'lib/innodb/page.rb', line 174

def dump
  puts "#{self}:"
  puts

  puts "fil header:"
  pp fil_header
  puts
end

#fil_headerObject

Return the “fil” header from the page, which is common for all page types.



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

def fil_header
  c = cursor(pos_fil_header)
  @fil_header ||= {
    :checksum   => c.get_uint32,
    :offset     => c.get_uint32,
    :prev       => Innodb::Page.maybe_undefined(c.get_uint32),
    :next       => Innodb::Page.maybe_undefined(c.get_uint32),
    :lsn        => c.get_uint64,
    :type       => PAGE_TYPE[c.get_uint16],
    :flush_lsn  => c.get_uint64,
    :space_id   => c.get_uint32,
  }
end

#inspectObject

Implement a custom inspect method to avoid irb printing the contents of the page buffer, since it’s very large and mostly not interesting.



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/innodb/page.rb', line 157

def inspect
  if fil_header
    "#<%s: size=%i, space_id=%i, offset=%i, type=%s, prev=%s, next=%s>" % [
      self.class,
      size,
      fil_header[:space_id],
      fil_header[:offset],
      fil_header[:type],
      fil_header[:prev] || "nil",
      fil_header[:next] || "nil",
    ]
  else
    "#<#{self.class}>"
  end
end

#lsnObject

A helper function to return the LSN, for easier access.



151
152
153
# File 'lib/innodb/page.rb', line 151

def lsn
  fil_header[:lsn]
end

#nextObject

A helper function to return the page number of the logical next page (from the doubly-linked list from page to page) from the “fil” header, for easier access.



146
147
148
# File 'lib/innodb/page.rb', line 146

def next
  fil_header[:next]
end

#offsetObject

A helper function to return the page offset from the “fil” header, for easier access.



132
133
134
# File 'lib/innodb/page.rb', line 132

def offset
  fil_header[:offset]
end

#pos_fil_headerObject

Return the byte offset of the start of the “fil” header, which is at the beginning of the page. Included here primarily for completeness.



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

def pos_fil_header
  0
end

#pos_fil_trailerObject

Return the byte offset of the start of the “fil” trailer, which is at the end of the page.



77
78
79
# File 'lib/innodb/page.rb', line 77

def pos_fil_trailer
  size - size_fil_trailer
end

#prevObject

A helper function to return the page number of the logical previous page (from the doubly-linked list from page to page) from the “fil” header, for easier access.



139
140
141
# File 'lib/innodb/page.rb', line 139

def prev
  fil_header[:prev]
end

#sizeObject

Return the page size, to eventually be able to deal with non-16kB pages.



49
50
51
# File 'lib/innodb/page.rb', line 49

def size
  @size ||= @buffer.size
end

#size_fil_headerObject

Return the size of the “fil” header, in bytes.



71
72
73
# File 'lib/innodb/page.rb', line 71

def size_fil_header
  4 + 4 + 4 + 4 + 8 + 2 + 8 + 4
end

#size_fil_trailerObject

Return the size of the “fil” trailer, in bytes.



82
83
84
# File 'lib/innodb/page.rb', line 82

def size_fil_trailer
  4 + 4
end

#typeObject

A helper function to return the page type from the “fil” header, for easier access.



126
127
128
# File 'lib/innodb/page.rb', line 126

def type
  fil_header[:type]
end