herringbone 0.1.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.
@@ -0,0 +1,309 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Herringbone
4
+ # Parquet file metadata structures, mirroring parquet.thrift.
5
+ # Enums are plain i32 on the wire; constants below give them names.
6
+ module Format
7
+ module Type
8
+ BOOLEAN = 0
9
+ INT32 = 1
10
+ INT64 = 2
11
+ INT96 = 3
12
+ FLOAT = 4
13
+ DOUBLE = 5
14
+ BYTE_ARRAY = 6
15
+ FIXED_LEN_BYTE_ARRAY = 7
16
+ NAMES = constants.to_h { |c| [const_get(c), c] }.freeze
17
+ end
18
+
19
+ module ConvertedType
20
+ UTF8 = 0
21
+ MAP = 1
22
+ MAP_KEY_VALUE = 2
23
+ LIST = 3
24
+ ENUM = 4
25
+ DECIMAL = 5
26
+ DATE = 6
27
+ TIME_MILLIS = 7
28
+ TIME_MICROS = 8
29
+ TIMESTAMP_MILLIS = 9
30
+ TIMESTAMP_MICROS = 10
31
+ UINT_8 = 11
32
+ UINT_16 = 12
33
+ UINT_32 = 13
34
+ UINT_64 = 14
35
+ INT_8 = 15
36
+ INT_16 = 16
37
+ INT_32 = 17
38
+ INT_64 = 18
39
+ JSON = 19
40
+ BSON = 20
41
+ INTERVAL = 21
42
+ NAMES = constants.to_h { |c| [const_get(c), c] }.freeze
43
+ end
44
+
45
+ module Repetition
46
+ REQUIRED = 0
47
+ OPTIONAL = 1
48
+ REPEATED = 2
49
+ NAMES = constants.to_h { |c| [const_get(c), c] }.freeze
50
+ end
51
+
52
+ module Encoding
53
+ PLAIN = 0
54
+ PLAIN_DICTIONARY = 2
55
+ RLE = 3
56
+ BIT_PACKED = 4
57
+ DELTA_BINARY_PACKED = 5
58
+ DELTA_LENGTH_BYTE_ARRAY = 6
59
+ DELTA_BYTE_ARRAY = 7
60
+ RLE_DICTIONARY = 8
61
+ BYTE_STREAM_SPLIT = 9
62
+ NAMES = constants.to_h { |c| [const_get(c), c] }.freeze
63
+ end
64
+
65
+ module Codec
66
+ UNCOMPRESSED = 0
67
+ SNAPPY = 1
68
+ GZIP = 2
69
+ LZO = 3
70
+ BROTLI = 4
71
+ LZ4 = 5
72
+ ZSTD = 6
73
+ LZ4_RAW = 7
74
+ NAMES = constants.to_h { |c| [const_get(c), c] }.freeze
75
+ end
76
+
77
+ module PageType
78
+ DATA_PAGE = 0
79
+ INDEX_PAGE = 1
80
+ DICTIONARY_PAGE = 2
81
+ DATA_PAGE_V2 = 3
82
+ NAMES = constants.to_h { |c| [const_get(c), c] }.freeze
83
+ end
84
+
85
+ S = Thrift::Struct
86
+
87
+ class SizeStatistics < S
88
+ field 1, :unencoded_byte_array_data_bytes, :i64
89
+ field 2, :repetition_level_histogram, [:list, :i64]
90
+ field 3, :definition_level_histogram, [:list, :i64]
91
+ end
92
+
93
+ class Statistics < S
94
+ field 1, :max, :binary
95
+ field 2, :min, :binary
96
+ field 3, :null_count, :i64
97
+ field 4, :distinct_count, :i64
98
+ field 5, :max_value, :binary
99
+ field 6, :min_value, :binary
100
+ field 7, :is_max_value_exact, :bool
101
+ field 8, :is_min_value_exact, :bool
102
+ end
103
+
104
+ # Empty marker structs used inside unions
105
+ class StringType < S; end
106
+ class UUIDType < S; end
107
+ class MapType < S; end
108
+ class ListType < S; end
109
+ class EnumType < S; end
110
+ class DateType < S; end
111
+ class Float16Type < S; end
112
+ class NullType < S; end
113
+ class JsonType < S; end
114
+ class BsonType < S; end
115
+ class MilliSeconds < S; end
116
+ class MicroSeconds < S; end
117
+ class NanoSeconds < S; end
118
+ class TypeDefinedOrder < S; end
119
+ class IndexPageHeader < S; end
120
+
121
+ class VariantType < S
122
+ field 1, :specification_version, :byte
123
+ end
124
+
125
+ class DecimalType < S
126
+ field 1, :scale, :i32
127
+ field 2, :precision, :i32
128
+ end
129
+
130
+ class TimeUnit < S
131
+ field 1, :millis, MilliSeconds
132
+ field 2, :micros, MicroSeconds
133
+ field 3, :nanos, NanoSeconds
134
+
135
+ def self.millis = new(millis: MilliSeconds.new)
136
+ def self.micros = new(micros: MicroSeconds.new)
137
+ def self.nanos = new(nanos: NanoSeconds.new)
138
+
139
+ def to_sym
140
+ if millis then :millis
141
+ elsif micros then :micros
142
+ elsif nanos then :nanos
143
+ end
144
+ end
145
+ end
146
+
147
+ class TimestampType < S
148
+ field 1, :is_adjusted_to_utc, :bool
149
+ field 2, :unit, TimeUnit
150
+ end
151
+
152
+ class TimeType < S
153
+ field 1, :is_adjusted_to_utc, :bool
154
+ field 2, :unit, TimeUnit
155
+ end
156
+
157
+ class IntType < S
158
+ field 1, :bit_width, :byte
159
+ field 2, :is_signed, :bool
160
+ end
161
+
162
+ class LogicalType < S
163
+ field 1, :string, StringType
164
+ field 2, :map, MapType
165
+ field 3, :list, ListType
166
+ field 4, :enum, EnumType
167
+ field 5, :decimal, DecimalType
168
+ field 6, :date, DateType
169
+ field 7, :time, TimeType
170
+ field 8, :timestamp, TimestampType
171
+ field 10, :integer, IntType
172
+ field 11, :unknown, NullType
173
+ field 12, :json, JsonType
174
+ field 13, :bson, BsonType
175
+ field 14, :uuid, UUIDType
176
+ field 15, :float16, Float16Type
177
+ field 16, :variant, VariantType
178
+
179
+ # Returns [kind_symbol, payload] for whichever union member is set
180
+ def kind
181
+ self.class.fields.each do |f|
182
+ v = instance_variable_get(f.ivar)
183
+ return [f.name, v] if v
184
+ end
185
+ nil
186
+ end
187
+ end
188
+
189
+ class SchemaElement < S
190
+ field 1, :type, :i32
191
+ field 2, :type_length, :i32
192
+ field 3, :repetition_type, :i32
193
+ field 4, :name, :string
194
+ field 5, :num_children, :i32
195
+ field 6, :converted_type, :i32
196
+ field 7, :scale, :i32
197
+ field 8, :precision, :i32
198
+ field 9, :field_id, :i32
199
+ field 10, :logical_type, LogicalType
200
+ end
201
+
202
+ class DataPageHeader < S
203
+ field 1, :num_values, :i32
204
+ field 2, :encoding, :i32
205
+ field 3, :definition_level_encoding, :i32
206
+ field 4, :repetition_level_encoding, :i32
207
+ field 5, :statistics, Statistics
208
+ end
209
+
210
+ class DictionaryPageHeader < S
211
+ field 1, :num_values, :i32
212
+ field 2, :encoding, :i32
213
+ field 3, :is_sorted, :bool
214
+ end
215
+
216
+ class DataPageHeaderV2 < S
217
+ field 1, :num_values, :i32
218
+ field 2, :num_nulls, :i32
219
+ field 3, :num_rows, :i32
220
+ field 4, :encoding, :i32
221
+ field 5, :definition_levels_byte_length, :i32
222
+ field 6, :repetition_levels_byte_length, :i32
223
+ field 7, :is_compressed, :bool
224
+ field 8, :statistics, Statistics
225
+ end
226
+
227
+ class PageHeader < S
228
+ field 1, :type, :i32
229
+ field 2, :uncompressed_page_size, :i32
230
+ field 3, :compressed_page_size, :i32
231
+ field 4, :crc, :i32
232
+ field 5, :data_page_header, DataPageHeader
233
+ field 6, :index_page_header, IndexPageHeader
234
+ field 7, :dictionary_page_header, DictionaryPageHeader
235
+ field 8, :data_page_header_v2, DataPageHeaderV2
236
+ end
237
+
238
+ class KeyValue < S
239
+ field 1, :key, :string
240
+ field 2, :value, :string
241
+ end
242
+
243
+ class SortingColumn < S
244
+ field 1, :column_idx, :i32
245
+ field 2, :descending, :bool
246
+ field 3, :nulls_first, :bool
247
+ end
248
+
249
+ class PageEncodingStats < S
250
+ field 1, :page_type, :i32
251
+ field 2, :encoding, :i32
252
+ field 3, :count, :i32
253
+ end
254
+
255
+ class ColumnMetaData < S
256
+ field 1, :type, :i32
257
+ field 2, :encodings, [:list, :i32]
258
+ field 3, :path_in_schema, [:list, :string]
259
+ field 4, :codec, :i32
260
+ field 5, :num_values, :i64
261
+ field 6, :total_uncompressed_size, :i64
262
+ field 7, :total_compressed_size, :i64
263
+ field 8, :key_value_metadata, [:list, KeyValue]
264
+ field 9, :data_page_offset, :i64
265
+ field 10, :index_page_offset, :i64
266
+ field 11, :dictionary_page_offset, :i64
267
+ field 12, :statistics, Statistics
268
+ field 13, :encoding_stats, [:list, PageEncodingStats]
269
+ field 14, :bloom_filter_offset, :i64
270
+ field 15, :bloom_filter_length, :i32
271
+ field 16, :size_statistics, SizeStatistics
272
+ end
273
+
274
+ class ColumnChunk < S
275
+ field 1, :file_path, :string
276
+ field 2, :file_offset, :i64
277
+ field 3, :meta_data, ColumnMetaData
278
+ field 4, :offset_index_offset, :i64
279
+ field 5, :offset_index_length, :i32
280
+ field 6, :column_index_offset, :i64
281
+ field 7, :column_index_length, :i32
282
+ field 9, :encrypted_column_metadata, :binary
283
+ end
284
+
285
+ class RowGroup < S
286
+ field 1, :columns, [:list, ColumnChunk]
287
+ field 2, :total_byte_size, :i64
288
+ field 3, :num_rows, :i64
289
+ field 4, :sorting_columns, [:list, SortingColumn]
290
+ field 5, :file_offset, :i64
291
+ field 6, :total_compressed_size, :i64
292
+ field 7, :ordinal, :i16
293
+ end
294
+
295
+ class ColumnOrder < S
296
+ field 1, :type_order, TypeDefinedOrder
297
+ end
298
+
299
+ class FileMetaData < S
300
+ field 1, :version, :i32
301
+ field 2, :schema, [:list, SchemaElement]
302
+ field 3, :num_rows, :i64
303
+ field 4, :row_groups, [:list, RowGroup]
304
+ field 5, :key_value_metadata, [:list, KeyValue]
305
+ field 6, :created_by, :string
306
+ field 7, :column_orders, [:list, ColumnOrder]
307
+ end
308
+ end
309
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Herringbone
4
+ # IO::Buffer lets the decompressors copy bytes around without allocating a String per copy.
5
+ # It still carries an "experimental" warning, which is silenced once here: the gem only uses
6
+ # new/for/copy/get_string/free, and falls back to String operations where it is missing.
7
+ module IOBufferSupport
8
+ AVAILABLE = begin
9
+ if defined?(IO::Buffer) && IO::Buffer.method_defined?(:copy) && IO::Buffer.method_defined?(:get_string)
10
+ previous = Warning[:experimental]
11
+ begin
12
+ Warning[:experimental] = false
13
+ IO::Buffer.new(1).free
14
+ ensure
15
+ Warning[:experimental] = previous
16
+ end
17
+ ENV["HERRINGBONE_NO_IO_BUFFER"].nil?
18
+ else
19
+ false
20
+ end
21
+ rescue StandardError
22
+ false
23
+ end
24
+ end
25
+ end