innodb_ruby 0.4 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,31 +3,187 @@
3
3
  require "pp"
4
4
  require "innodb"
5
5
 
6
- file, page_number = ARGV.shift(2)
6
+ class EdgesRecordFormatter
7
+ def format(page)
8
+ bytes_per_record = (page.record_space / page.page_header[:n_recs])
9
+ case
10
+ when [48, 26].include?(bytes_per_record) # Clustered Key
11
+ {
12
+ # PRIMARY KEY (source_id, state, position)
13
+ :type => :clustered,
14
+ :key => [
15
+ [:get_uint64], # source_id
16
+ [:get_i_sint8], # state
17
+ [:get_i_sint64], # position
18
+ ],
19
+ :row => [
20
+ [:get_uint32], # updated_at
21
+ [:get_uint64], # destination_id
22
+ [:get_uint8], # count
23
+ ],
24
+ }
25
+ when [30, 34].include?(bytes_per_record) # Secondary Key
26
+ {
27
+ # INDEX (source_id, destination_id)
28
+ :type => :secondary,
29
+ :key => [
30
+ [:get_uint64], # source_id
31
+ [:get_uint64], # destination_id
32
+ ],
33
+ # PKV ([source_id], state, position)
34
+ :row => [
35
+ [:get_i_sint8], # state
36
+ [:get_i_sint64], # position
37
+ ],
38
+ }
39
+ end
40
+ end
41
+ end
7
42
 
8
- space = Innodb::Space.new(file)
9
- #space.page(page_number).dump
10
- #exit
11
-
12
- page_types = Hash.new(0)
13
- page_levels = Hash.new(0)
14
- records_per_level = {}
15
- puts "%-8s%-8s%-8s%-8s" % ["page", "index", "level", "data"]
16
- space.each_page do |page_number, page|
17
- page_types[page.type] += 1
18
- if page.type == :INDEX
19
- puts "%-8i%-8i%-8i%-8i" % [
20
- page_number,
43
+ class PageSplitTestFormatter
44
+ def format(page)
45
+ {
46
+ # PRIMARY KEY (id)
47
+ :type => :clustered,
48
+ :key => [
49
+ [:get_uint64], # id
50
+ ],
51
+ :row => [],
52
+ }
53
+ end
54
+ end
55
+
56
+ def digraph_index(index)
57
+ puts "digraph btree {"
58
+ puts " rankdir = LR;"
59
+ puts " ranksep = 2.0;"
60
+ index.recurse(
61
+ lambda do |page, depth|
62
+ if true #page.level != 0
63
+ label = "<page>Page %i|(%i records)" % [
64
+ page.offset,
65
+ page.page_header[:n_recs],
66
+ ]
67
+ page.each_child_page do |child_page_number, child_key|
68
+ label += "|<dir_%i>(%s)" % [
69
+ child_page_number,
70
+ child_key.join(", "),
71
+ ]
72
+ end
73
+ puts " %spage_%i [ shape = \"record\"; label = \"%s\"; ];" % [
74
+ " " * depth,
75
+ page.offset,
76
+ label,
77
+ ]
78
+ end
79
+ end,
80
+ lambda do |parent_page, child_page, child_key, depth|
81
+ if true #child_page.level > 0
82
+ puts " %spage_%i:dir_%i -> page_%i:page:nw;" % [
83
+ " " * depth,
84
+ parent_page.offset,
85
+ child_page.offset,
86
+ child_page.offset,
87
+ ]
88
+ end
89
+ end
90
+ )
91
+ puts "}"
92
+ end
93
+
94
+ def recurse_index(index)
95
+ index.recurse(
96
+ lambda do |page, depth|
97
+ puts "%s%s %i: %i records, %i bytes" % [
98
+ " " * depth,
99
+ page.level == 0 ? "LEAF" : "NODE",
100
+ page.offset,
101
+ page.page_header[:n_recs],
102
+ page.record_space,
103
+ ]
104
+ if page.level == 0
105
+ page.each_record do |record|
106
+ puts "%sRECORD: (%s) -> (%s)" % [
107
+ " " * (depth+1),
108
+ record[:key].join(", "),
109
+ record[:row].join(", "),
110
+ ]
111
+ end
112
+ end
113
+ end,
114
+ lambda do |parent_page, child_page, child_min_key, depth|
115
+ puts "%sLINK %i -> %i: %s records >= (%s)" % [
116
+ " " * depth,
117
+ parent_page.offset,
118
+ child_page.offset,
119
+ child_page.page_header[:n_recs],
120
+ child_min_key.join(", "),
121
+ ]
122
+ end
123
+ )
124
+ end
125
+
126
+ def dump_space(space)
127
+ puts "%-8s%-8s%-8s%-8s%-8s%-8s" % [
128
+ "page",
129
+ "index",
130
+ "level",
131
+ "data",
132
+ "free",
133
+ "records",
134
+ ]
135
+
136
+ space.each_page do |page_number, page|
137
+ case page.type
138
+ when :INDEX
139
+ puts "%-8i%-8i%-8i%-8i%-8i%-8i" % [
140
+ page_number,
141
+ page.ph[:index_id],
142
+ page.ph[:level],
143
+ page.record_space,
144
+ page.free_space,
145
+ page.ph[:n_recs],
146
+ ]
147
+ when :ALLOCATED
148
+ puts "%-8i%-8i%-8i%-8i%-8i%-8i" % [ page_number, 0, 0, 0, Innodb::Space::PAGE_SIZE, 0 ]
149
+ end
150
+ end
151
+ end
152
+
153
+ def dump_index_level(index, level)
154
+ puts "%-8s%-8s%-8s%-8s%-8s%-8s%-8s" % [
155
+ "page",
156
+ "index",
157
+ "level",
158
+ "data",
159
+ "free",
160
+ "records",
161
+ "min_key",
162
+ ]
163
+
164
+ index.each_page_at_level(level) do |page|
165
+ puts "%-8i%-8i%-8i%-8i%-8i%-8i%s" % [
166
+ page.offset,
21
167
  page.ph[:index_id],
22
168
  page.ph[:level],
23
169
  page.record_space,
170
+ page.free_space,
171
+ page.ph[:n_recs],
172
+ page.first_record[:key].join("|"),
24
173
  ]
25
- #page_levels[page.ph[:index_id]] ||= Hash.new(0)
26
- #page_levels[page.ph[:index_id]][page.ph[:level]] += 1
27
- #records_per_level[page.ph[:level]] ||= Hash.new(0)
28
- #records_per_level[page.ph[:level]][page.ph[:n_recs]] += 1
29
- end
30
- if page.type == :ALLOCATED
31
- puts "%-8i%-8i%-8i%-8i" % [ page_number, 0, 0, 0 ]
32
174
  end
33
175
  end
176
+
177
+ file, page_number = ARGV.shift(2)
178
+
179
+ formatter = EdgesRecordFormatter.new
180
+ #formatter = PageSplitTestFormatter.new
181
+ space = Innodb::Space.new(file)
182
+ space.record_formatter = formatter
183
+ space.page(page_number).dump
184
+ #space.each_page { |page_number, page| puts "%6i%20s" % [page_number, page.type] }
185
+ #dump_space(space)
186
+ #dump_index_level(Innodb::Index.new(space, page_number), 1)
187
+ #recurse_index(Innodb::Index.new(space, page_number))
188
+ #digraph_index(Innodb::Index.new(space, page_number))
189
+ #Innodb::Index.new(space, page_number).each_record { |record| puts "(#{record[:key].join(", ")}) -> (#{record[:row].join(", ")})" }
data/lib/innodb.rb CHANGED
@@ -3,6 +3,10 @@ module Innodb; end
3
3
 
4
4
  require "innodb/version"
5
5
  require "innodb/page"
6
+ require "innodb/page/fsp_hdr_xdes"
7
+ require "innodb/page/inode"
8
+ require "innodb/page/index"
6
9
  require "innodb/space"
10
+ require "innodb/index"
7
11
  require "innodb/log_block"
8
12
  require "innodb/log"
data/lib/innodb/cursor.rb CHANGED
@@ -82,6 +82,11 @@ class Innodb::Cursor
82
82
  read_and_advance(length)
83
83
  end
84
84
 
85
+ # Return raw bytes as hex.
86
+ def get_hex(length)
87
+ read_and_advance(length).bytes.map { |c| "%02x" % c }.join
88
+ end
89
+
85
90
  # Return a big-endian unsigned 8-bit integer.
86
91
  def get_uint8(offset=nil)
87
92
  seek(offset)
@@ -145,4 +150,16 @@ class Innodb::Cursor
145
150
  raise "Invalid flag #{flag.to_s(16)} seen"
146
151
  end
147
152
  end
153
+
154
+ # Return an InnoDB-munged signed 8-bit integer. (This is only implemented
155
+ # for positive integers at the moment.)
156
+ def get_i_sint8
157
+ get_uint8 ^ (1 << 7)
158
+ end
159
+
160
+ # Return an InnoDB-munged signed 64-bit integer. (This is only implemented
161
+ # for positive integers at the moment.)
162
+ def get_i_sint64
163
+ get_uint64 ^ (1 << 63)
164
+ end
148
165
  end
data/lib/innodb/page.rb CHANGED
@@ -1,36 +1,33 @@
1
1
  require "innodb/cursor"
2
2
 
3
3
  class Innodb::Page
4
- # Currently only 16kB InnoDB pages are supported.
5
- PAGE_SIZE = 16384
4
+ SPECIALIZED_CLASSES = {}
6
5
 
7
- # InnoDB Page Type constants from include/fil0fil.h.
8
- PAGE_TYPE = {
9
- 0 => :ALLOCATED, # Freshly allocated page
10
- 2 => :UNDO_LOG, # Undo log page
11
- 3 => :INODE, # Index node
12
- 4 => :IBUF_FREE_LIST, # Insert buffer free list
13
- 5 => :IBUF_BITMAP, # Insert buffer bitmap
14
- 6 => :SYS, # System page
15
- 7 => :TRX_SYS, # Transaction system data
16
- 8 => :FSP_HDR, # File space header
17
- 9 => :XDES, # Extent descriptor page
18
- 10 => :BLOB, # Uncompressed BLOB page
19
- 11 => :ZBLOB, # First compressed BLOB page
20
- 12 => :ZBLOB2, # Subsequent compressed BLOB page
21
- 17855 => :INDEX, # B-tree node
22
- }
6
+ # Load a page as a generic page in order to make the "fil" header accessible,
7
+ # and then attempt to hand off the page to a specialized class to be
8
+ # re-parsed if possible. If there is no specialized class for this type
9
+ # of page, return the generic object.
10
+ def self.parse(buffer)
11
+ page = Innodb::Page.new(buffer)
12
+
13
+ if specialized_class = SPECIALIZED_CLASSES[page.type]
14
+ page = specialized_class.new(buffer)
15
+ end
16
+
17
+ page
18
+ end
23
19
 
24
20
  # Initialize a page by passing in a 16kB buffer containing the raw page
25
21
  # contents. Currently only 16kB pages are supported.
26
22
  def initialize(buffer)
27
- unless buffer.size == PAGE_SIZE
28
- raise "Page buffer provided was not #{PAGE_SIZE} bytes"
29
- end
30
-
31
23
  @buffer = buffer
32
24
  end
33
25
 
26
+ # Return the page size, to eventually be able to deal with non-16kB pages.
27
+ def size
28
+ @size ||= @buffer.size
29
+ end
30
+
34
31
  # A helper function to return bytes from the page buffer based on offset
35
32
  # and length, both in bytes.
36
33
  def data(offset, length)
@@ -42,23 +39,59 @@ class Innodb::Page
42
39
  Innodb::Cursor.new(self, offset)
43
40
  end
44
41
 
45
- FIL_HEADER_SIZE = 38
46
- FIL_HEADER_START = 0
42
+ # Return the byte offset of the start of the "fil" header, which is at the
43
+ # beginning of the page. Included here primarily for completeness.
44
+ def pos_fil_header
45
+ 0
46
+ end
47
+
48
+ # Return the size of the "fil" header, in bytes.
49
+ def size_fil_header
50
+ 38
51
+ end
52
+
53
+ # Return the byte offset of the start of the "fil" trailer, which is at
54
+ # the end of the page.
55
+ def pos_fil_trailer
56
+ size - size_fil_trailer
57
+ end
58
+
59
+ # Return the size of the "fil" trailer, in bytes.
60
+ def size_fil_trailer
61
+ 8
62
+ end
63
+
64
+ # InnoDB Page Type constants from include/fil0fil.h.
65
+ PAGE_TYPE = {
66
+ 0 => :ALLOCATED, # Freshly allocated page
67
+ 2 => :UNDO_LOG, # Undo log page
68
+ 3 => :INODE, # Index node
69
+ 4 => :IBUF_FREE_LIST, # Insert buffer free list
70
+ 5 => :IBUF_BITMAP, # Insert buffer bitmap
71
+ 6 => :SYS, # System page
72
+ 7 => :TRX_SYS, # Transaction system data
73
+ 8 => :FSP_HDR, # File space header
74
+ 9 => :XDES, # Extent descriptor page
75
+ 10 => :BLOB, # Uncompressed BLOB page
76
+ 11 => :ZBLOB, # First compressed BLOB page
77
+ 12 => :ZBLOB2, # Subsequent compressed BLOB page
78
+ 17855 => :INDEX, # B-tree node
79
+ }
47
80
 
48
81
  # A helper to convert "undefined" values stored in previous and next pointers
49
82
  # in the page header to nil.
50
- def maybe_undefined(value)
83
+ def self.maybe_undefined(value)
51
84
  value == 4294967295 ? nil : value
52
85
  end
53
86
 
54
87
  # Return the "fil" header from the page, which is common for all page types.
55
88
  def fil_header
56
- c = cursor(FIL_HEADER_START)
89
+ c = cursor(pos_fil_header)
57
90
  @fil_header ||= {
58
91
  :checksum => c.get_uint32,
59
92
  :offset => c.get_uint32,
60
- :prev => maybe_undefined(c.get_uint32),
61
- :next => maybe_undefined(c.get_uint32),
93
+ :prev => Innodb::Page.maybe_undefined(c.get_uint32),
94
+ :next => Innodb::Page.maybe_undefined(c.get_uint32),
62
95
  :lsn => c.get_uint64,
63
96
  :type => PAGE_TYPE[c.get_uint16],
64
97
  :flush_lsn => c.get_uint64,
@@ -73,6 +106,12 @@ class Innodb::Page
73
106
  fil_header[:type]
74
107
  end
75
108
 
109
+ # A helper function to return the page offset from the "fil" header, for
110
+ # easier access.
111
+ def offset
112
+ fil_header[:offset]
113
+ end
114
+
76
115
  # A helper function to return the page number of the logical previous page
77
116
  # (from the doubly-linked list from page to page) from the "fil" header,
78
117
  # for easier access.
@@ -87,227 +126,13 @@ class Innodb::Page
87
126
  fil_header[:next]
88
127
  end
89
128
 
90
- PAGE_HEADER_SIZE = 36
91
- PAGE_HEADER_START = FIL_HEADER_START + FIL_HEADER_SIZE
92
-
93
- PAGE_TRAILER_SIZE = 16
94
- PAGE_TRAILER_START = PAGE_SIZE - PAGE_TRAILER_SIZE
95
-
96
- FSEG_HEADER_SIZE = 10
97
- FSEG_HEADER_START = PAGE_HEADER_START + PAGE_HEADER_SIZE
98
- FSEG_HEADER_COUNT = 2
99
-
100
- MUM_RECORD_SIZE = 8
101
-
102
- RECORD_BITS_SIZE = 3
103
- RECORD_NEXT_SIZE = 2
104
-
105
- # Page direction values possible in the page_header[:direction] field.
106
- PAGE_DIRECTION = {
107
- 1 => :left,
108
- 2 => :right,
109
- 3 => :same_rec,
110
- 4 => :same_page,
111
- 5 => :no_direction,
112
- }
113
-
114
- # Return the size of the header for each record.
115
- def size_record_header
116
- case page_header[:format]
117
- when :compact
118
- RECORD_BITS_SIZE + RECORD_NEXT_SIZE
119
- when :redundant
120
- RECORD_BITS_SIZE + RECORD_NEXT_SIZE + 1
121
- end
122
- end
123
-
124
- # Return the size of a field in the record header for which no description
125
- # could be found (but must be skipped anyway).
126
- def size_record_undefined
127
- case page_header[:format]
128
- when :compact
129
- 0
130
- when :redundant
131
- 1
132
- end
133
- end
134
-
135
- # Return the "page" header; currently only "INDEX" pages are supported.
136
- def page_header
137
- return nil unless type == :INDEX
138
-
139
- c = cursor(PAGE_HEADER_START)
140
- @page_header ||= {
141
- :n_dir_slots => c.get_uint16,
142
- :heap_top => c.get_uint16,
143
- :n_heap => ((n_heap = c.get_uint16) & (2**15-1)),
144
- :free => c.get_uint16,
145
- :garbage => c.get_uint16,
146
- :last_insert => c.get_uint16,
147
- :direction => PAGE_DIRECTION[c.get_uint16],
148
- :n_direction => c.get_uint16,
149
- :n_recs => c.get_uint16,
150
- :max_trx_id => c.get_uint64,
151
- :level => c.get_uint16,
152
- :index_id => c.get_uint64,
153
- :format => (n_heap & 1<<15) == 0 ? :redundant : :compact,
154
- }
155
- end
156
- alias :ph :page_header
157
-
158
- # Parse and return simple fixed-format system records, such as InnoDB's
159
- # internal infimum and supremum records.
160
- def system_record(offset)
161
- return nil unless type == :INDEX
162
-
163
- c = cursor(offset)
164
- c.adjust(-2)
165
- {
166
- :next => offset + c.get_sint16,
167
- :data => c.get_bytes(8),
168
- }
169
- end
170
-
171
- # Return the byte offset of the start of the "origin" of the infimum record,
172
- # which is always the first record in the singly-linked record chain on any
173
- # page, and represents a record with a "lower value than any possible user
174
- # record". The infimum record immediately follows the page header.
175
- def pos_infimum
176
- pos_records + size_record_header + size_record_undefined
177
- end
178
-
179
- # Return the infimum record on a page.
180
- def infimum
181
- @infimum ||= system_record(pos_infimum)
182
- end
183
-
184
- # Return the byte offset of the start of the "origin" of the supremum record,
185
- # which is always the last record in the singly-linked record chain on any
186
- # page, and represents a record with a "higher value than any possible user
187
- # record". The supremum record immediately follows the infimum record.
188
- def pos_supremum
189
- pos_infimum + size_record_header + size_record_undefined + MUM_RECORD_SIZE
190
- end
191
-
192
- # Return the supremum record on a page.
193
- def supremum
194
- @supremum ||= system_record(pos_supremum)
195
- end
196
-
197
- # Return the byte offset of the start of records within the page (the
198
- # position immediately after the page header).
199
- def pos_records
200
- FIL_HEADER_SIZE +
201
- PAGE_HEADER_SIZE +
202
- (FSEG_HEADER_COUNT * FSEG_HEADER_SIZE)
203
- end
204
-
205
- # Return the byte offset of the start of the user records in a page, which
206
- # immediately follows the supremum record.
207
- def pos_user_records
208
- pos_supremum + size_record_header + size_record_undefined + MUM_RECORD_SIZE
209
- end
210
-
211
- # Return the amount of free space in the page.
212
- def free_space
213
- unused_space = (PAGE_TRAILER_START - page_header[:heap_top])
214
- unused_space + page_header[:garbage]
215
- end
216
-
217
- # Return the amount of used space in the page.
218
- def used_space
219
- PAGE_SIZE - free_space
220
- end
221
-
222
- # Return the amount of space occupied by records in the page.
223
- def record_space
224
- used_space - pos_user_records
225
- end
226
-
227
- # Return the actual bytes of the portion of the page which is used to
228
- # store user records (eliminate the headers and trailer from the page).
229
- def record_bytes
230
- data(pos_user_records, page_header[:heap_top] - pos_user_records)
231
- end
232
-
233
- # Return the header from a record. (This is mostly unimplemented.)
234
- def record_header(offset)
235
- return nil unless type == :INDEX
236
-
237
- c = cursor(offset).backward
238
- case page_header[:format]
239
- when :compact
240
- header = {}
241
- header[:next] = c.get_sint16
242
- bits1 = c.get_uint16
243
- header[:type] = bits1 & 0x07
244
- header[:order] = (bits1 & 0xf8) >> 3
245
- bits2 = c.get_uint8
246
- header[:n_owned] = bits2 & 0x0f
247
- header[:deleted] = (bits2 & 0xf0) >> 4
248
- header
249
- when :redundant
250
- raise "Not implemented"
251
- end
252
- end
253
-
254
- # Return a record. (This is mostly unimplemented.)
255
- def record(offset)
256
- return nil unless offset
257
- return nil unless type == :INDEX
258
- return nil if offset == pos_infimum
259
- return nil if offset == pos_supremum
260
-
261
- c = cursor(offset).forward
262
- # There is a header preceding the row itself, so back up and read it.
263
- header = record_header(offset)
264
- {
265
- :header => header,
266
- :next => header[:next] == 0 ? nil : (offset + header[:next]),
267
- # These system records may not be present depending on schema.
268
- :rec1 => c.get_bytes(6),
269
- :rec2 => c.get_bytes(6),
270
- :rec3 => c.get_bytes(7),
271
- # Read a few bytes just so it can be visually verified.
272
- :data => c.get_bytes(8),
273
- }
274
- end
275
-
276
- # Iterate through all records. (This is mostly unimplemented.)
277
- def each_record
278
- rec = infimum
279
- while rec = record(rec[:next])
280
- yield rec
281
- end
282
- nil
283
- end
284
-
285
129
  # Dump the contents of a page for debugging purposes.
286
130
  def dump
287
131
  puts
288
- puts "fil header:"
289
- pp fil_header
132
+ puts "#{self}:"
290
133
 
291
134
  puts
292
- puts "page header:"
293
- pp page_header
294
-
295
- puts
296
- puts "free space: #{free_space}"
297
- puts "used space: #{used_space}"
298
- puts "record space: #{record_space}"
299
-
300
- if type == :INDEX
301
- puts
302
- puts "system records:"
303
- pp infimum
304
- pp supremum
305
-
306
- puts
307
- puts "records:"
308
- each_record do |rec|
309
- pp rec
310
- end
311
- end
135
+ puts "fil header:"
136
+ pp fil_header
312
137
  end
313
138
  end
data/lib/innodb/space.rb CHANGED
@@ -1,21 +1,33 @@
1
1
  # An InnoDB tablespace file, which can be either a multi-table ibdataN file
2
2
  # or a single-table "innodb_file_per_table" .ibd file.
3
3
  class Innodb::Space
4
+ attr_accessor :record_formatter
5
+
6
+ # Currently only 16kB InnoDB pages are supported.
7
+ PAGE_SIZE = 16384
8
+
4
9
  # Open a tablespace file.
5
10
  def initialize(file)
6
11
  @file = File.open(file)
7
12
  @size = @file.stat.size
8
- @pages = (@size / Innodb::Page::PAGE_SIZE)
13
+ @pages = (@size / PAGE_SIZE)
14
+ @record_formatter = nil
9
15
  end
10
16
 
11
17
  # Get an Innodb::Page object for a specific page by page number.
12
18
  def page(page_number)
13
- offset = page_number.to_i * Innodb::Page::PAGE_SIZE
19
+ offset = page_number.to_i * PAGE_SIZE
14
20
  return nil unless offset < @size
15
- return nil unless (offset + Innodb::Page::PAGE_SIZE) <= @size
21
+ return nil unless (offset + PAGE_SIZE) <= @size
16
22
  @file.seek(offset)
17
- page_data = @file.read(Innodb::Page::PAGE_SIZE)
18
- Innodb::Page.new(page_data)
23
+ page_data = @file.read(PAGE_SIZE)
24
+ this_page = Innodb::Page.parse(page_data)
25
+
26
+ if this_page.type == :INDEX
27
+ this_page.record_formatter = @record_formatter
28
+ end
29
+
30
+ this_page
19
31
  end
20
32
 
21
33
  # Iterate through all pages in a tablespace, returning the page number
@@ -1,3 +1,3 @@
1
1
  module Innodb
2
- VERSION = "0.4"
2
+ VERSION = "0.5.0"
3
3
  end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: innodb_ruby
3
3
  version: !ruby/object:Gem::Version
4
- hash: 3
4
+ hash: 11
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 4
9
- version: "0.4"
8
+ - 5
9
+ - 0
10
+ version: 0.5.0
10
11
  platform: ruby
11
12
  authors:
12
13
  - Jeremy Cole
@@ -14,7 +15,7 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2012-11-20 00:00:00 Z
18
+ date: 2012-11-29 00:00:00 Z
18
19
  dependencies: []
19
20
 
20
21
  description: Library for parsing InnoDB data files in Ruby