diff --git a/bin/innodb_space b/bin/innodb_space index 493d390..a59f433 100644 --- a/bin/innodb_space +++ b/bin/innodb_space @@ -1309,9 +1309,9 @@ getopt.each do |opt, arg| when "--trace" @options.trace += 1 when "--system-space-file" - @options.system_space_file = arg + @options.system_space_file = arg.split(",") when "--space-file" - @options.space_file = arg + @options.space_file = arg.split(",") when "--table-name" @options.table_name = arg when "--index-name" diff --git a/lib/innodb/space.rb b/lib/innodb/space.rb index f94cf99..c9a8063 100644 --- a/lib/innodb/space.rb +++ b/lib/innodb/space.rb @@ -20,11 +20,39 @@ class Innodb::Space 7 => :SYS, } + class DataFile + attr_reader :file + attr_reader :size + attr_reader :offset + + def initialize(filename, offset) + @file = File.open(filename) + @size = @file.stat.size + @offset = offset + end + + def name + prefix = "" + if File.extname(file.path) == ".ibd" + prefix = File.basename(File.dirname(file.path)) + "/" + end + + prefix + File.basename(file.path) + end + end + # Open a space file, optionally providing the page size to use. Pages # that aren't 16 KiB may not be supported well. - def initialize(file) - @file = File.open(file) - @size = @file.stat.size + def initialize(filenames) + filenames = [filenames] unless filenames.is_a?(Array) + + @data_files = [] + @size = 0 + filenames.each do |filename| + file = DataFile.new(filename, @size) + @size += file.size + @data_files << file + end @system_page_size = fsp_flags[:system_page_size] @page_size = fsp_flags[:page_size] @@ -58,14 +86,7 @@ def initialize(file) # to do anything which could instantiate a BufferCursor so that we can use # this method in cursor initialization. def name - return @name if @name - - prefix = "" - if File.extname(@file.path) == ".ibd" - prefix = File.basename(File.dirname(@file.path)) + "/" - end - - @name = prefix + File.basename(@file.path) + @name ||= @data_files.map { |f| f.name }.join(",") end def inspect @@ -184,18 +205,25 @@ def xdes_for_page(page_number) xdes_array[xdes_entry_for_page(page_number)] end + def data_file_for_offset(offset) + @data_files.each do |file| + return file if offset < file.size + offset -= file.size + end + nil + end + # Get the raw byte buffer of size bytes at offset in the file. def read_at_offset(offset, size) - @file.seek(offset) - @file.read(size) + return nil unless offset < @size && (offset + size) <= @size + data_file = data_file_for_offset(offset) + data_file.file.seek(offset - data_file.offset) + data_file.file.read(size) end # Get the raw byte buffer for a specific page by page number. def page_data(page_number) - offset = page_number.to_i * page_size - return nil unless offset < @size - return nil unless (offset + page_size) <= @size - read_at_offset(offset, page_size) + read_at_offset(page_number * page_size, page_size) end # Get an Innodb::Page object for a specific page by page number. diff --git a/lib/innodb/system.rb b/lib/innodb/system.rb index d36ea0e..2413745 100644 --- a/lib/innodb/system.rb +++ b/lib/innodb/system.rb @@ -18,14 +18,28 @@ class Innodb::System # The space ID of the system space, always 0. SYSTEM_SPACE_ID = 0 - def initialize(system_space_file) + def initialize(arg) + if arg.is_a?(Array) && arg.size > 1 + data_filenames = arg + else + arg = arg.first if arg.is_a?(Array) + if File.directory?(arg) + data_filenames = Dir.glob(arg + "/ibdata?").sort + if data_filenames.empty? + raise "Couldn't find any ibdata files in #{arg}" + end + else + data_filenames = [arg] + end + end + @spaces = {} @orphans = [] @config = { - :datadir => File.dirname(system_space_file), + :datadir => File.dirname(data_filenames.first), } - add_space_file(system_space_file) + add_space_file(data_filenames) @data_dictionary = Innodb::DataDictionary.new(system_space) end @@ -45,8 +59,8 @@ def add_space(space) end # Add a space by filename. - def add_space_file(space_file) - space = Innodb::Space.new(space_file) + def add_space_file(space_filenames) + space = Innodb::Space.new(space_filenames) space.innodb_system = self add_space(space) end