red-arrow-format 23.0.1 → 24.0.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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +7 -2
  3. data/Rakefile +23 -1
  4. data/lib/arrow-format/array.rb +486 -117
  5. data/lib/arrow-format/bitmap.rb +25 -6
  6. data/lib/arrow-format/buffer-alignable.rb +35 -0
  7. data/lib/arrow-format/dictionary.rb +29 -0
  8. data/lib/arrow-format/error.rb +1 -1
  9. data/lib/arrow-format/field.rb +24 -3
  10. data/lib/arrow-format/file-reader.rb +47 -25
  11. data/lib/arrow-format/file-writer.rb +56 -0
  12. data/lib/arrow-format/flatbuffers.rb +67 -0
  13. data/lib/arrow-format/org/apache/arrow/flatbuf/binary.rb +5 -1
  14. data/lib/arrow-format/org/apache/arrow/flatbuf/binary_view.rb +5 -1
  15. data/lib/arrow-format/org/apache/arrow/flatbuf/block.rb +10 -2
  16. data/lib/arrow-format/org/apache/arrow/flatbuf/body_compression.rb +8 -1
  17. data/lib/arrow-format/org/apache/arrow/flatbuf/body_compression_method.rb +3 -1
  18. data/lib/arrow-format/org/apache/arrow/flatbuf/bool.rb +5 -1
  19. data/lib/arrow-format/org/apache/arrow/flatbuf/buffer.rb +8 -1
  20. data/lib/arrow-format/org/apache/arrow/flatbuf/compression_type.rb +1 -1
  21. data/lib/arrow-format/org/apache/arrow/flatbuf/date.rb +7 -1
  22. data/lib/arrow-format/org/apache/arrow/flatbuf/date_unit.rb +1 -1
  23. data/lib/arrow-format/org/apache/arrow/flatbuf/decimal.rb +9 -1
  24. data/lib/arrow-format/org/apache/arrow/flatbuf/dictionary_batch.rb +9 -1
  25. data/lib/arrow-format/org/apache/arrow/flatbuf/dictionary_encoding.rb +11 -2
  26. data/lib/arrow-format/org/apache/arrow/flatbuf/dictionary_kind.rb +1 -1
  27. data/lib/arrow-format/org/apache/arrow/flatbuf/duration.rb +7 -1
  28. data/lib/arrow-format/org/apache/arrow/flatbuf/endianness.rb +1 -1
  29. data/lib/arrow-format/org/apache/arrow/flatbuf/feature.rb +1 -1
  30. data/lib/arrow-format/org/apache/arrow/flatbuf/field.rb +13 -1
  31. data/lib/arrow-format/org/apache/arrow/flatbuf/field_node.rb +8 -1
  32. data/lib/arrow-format/org/apache/arrow/flatbuf/fixed_size_binary.rb +7 -1
  33. data/lib/arrow-format/org/apache/arrow/flatbuf/fixed_size_list.rb +7 -1
  34. data/lib/arrow-format/org/apache/arrow/flatbuf/floating_point.rb +7 -1
  35. data/lib/arrow-format/org/apache/arrow/flatbuf/footer.rb +22 -2
  36. data/lib/arrow-format/org/apache/arrow/flatbuf/int.rb +8 -1
  37. data/lib/arrow-format/org/apache/arrow/flatbuf/interval.rb +7 -1
  38. data/lib/arrow-format/org/apache/arrow/flatbuf/interval_unit.rb +1 -1
  39. data/lib/arrow-format/org/apache/arrow/flatbuf/key_value.rb +8 -1
  40. data/lib/arrow-format/org/apache/arrow/flatbuf/large_binary.rb +5 -1
  41. data/lib/arrow-format/org/apache/arrow/flatbuf/large_list.rb +5 -1
  42. data/lib/arrow-format/org/apache/arrow/flatbuf/large_list_view.rb +5 -1
  43. data/lib/arrow-format/org/apache/arrow/flatbuf/large_utf8.rb +5 -1
  44. data/lib/arrow-format/org/apache/arrow/flatbuf/list.rb +5 -1
  45. data/lib/arrow-format/org/apache/arrow/flatbuf/list_view.rb +5 -1
  46. data/lib/arrow-format/org/apache/arrow/flatbuf/map.rb +8 -2
  47. data/lib/arrow-format/org/apache/arrow/flatbuf/message.rb +22 -2
  48. data/lib/arrow-format/org/apache/arrow/flatbuf/message_header.rb +1 -1
  49. data/lib/arrow-format/org/apache/arrow/flatbuf/metadata_version.rb +1 -1
  50. data/lib/arrow-format/org/apache/arrow/flatbuf/null.rb +5 -1
  51. data/lib/arrow-format/org/apache/arrow/flatbuf/precision.rb +1 -1
  52. data/lib/arrow-format/org/apache/arrow/flatbuf/record_batch.rb +12 -2
  53. data/lib/arrow-format/org/apache/arrow/flatbuf/run_end_encoded.rb +5 -1
  54. data/lib/arrow-format/org/apache/arrow/flatbuf/schema.rb +10 -1
  55. data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_matrix_compressed_axis.rb +1 -1
  56. data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_matrix_index_csx.rb +12 -2
  57. data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_tensor.rb +13 -1
  58. data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_tensor_index.rb +1 -1
  59. data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_tensor_index_coo.rb +13 -4
  60. data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_tensor_index_csf.rb +14 -4
  61. data/lib/arrow-format/org/apache/arrow/flatbuf/struct_.rb +5 -1
  62. data/lib/arrow-format/org/apache/arrow/flatbuf/tensor.rb +11 -1
  63. data/lib/arrow-format/org/apache/arrow/flatbuf/tensor_dim.rb +8 -1
  64. data/lib/arrow-format/org/apache/arrow/flatbuf/time.rb +8 -1
  65. data/lib/arrow-format/org/apache/arrow/flatbuf/time_unit.rb +1 -1
  66. data/lib/arrow-format/org/apache/arrow/flatbuf/timestamp.rb +8 -1
  67. data/lib/arrow-format/org/apache/arrow/flatbuf/type.rb +1 -1
  68. data/lib/arrow-format/org/apache/arrow/flatbuf/union.rb +8 -1
  69. data/lib/arrow-format/org/apache/arrow/flatbuf/union_mode.rb +1 -1
  70. data/lib/arrow-format/org/apache/arrow/flatbuf/utf8.rb +5 -1
  71. data/lib/arrow-format/org/apache/arrow/flatbuf/utf8view.rb +5 -1
  72. data/lib/arrow-format/readable.rb +151 -96
  73. data/lib/arrow-format/record-batch.rb +70 -1
  74. data/lib/arrow-format/schema.rb +14 -1
  75. data/lib/arrow-format/streaming-pull-reader.rb +49 -23
  76. data/lib/arrow-format/streaming-reader.rb +51 -14
  77. data/lib/arrow-format/streaming-writer.rb +156 -0
  78. data/lib/arrow-format/type.rb +397 -34
  79. data/lib/arrow-format/version.rb +1 -1
  80. data/lib/arrow-format.rb +2 -0
  81. data/red-arrow-format.gemspec +2 -1
  82. metadata +9 -4
@@ -21,29 +21,66 @@ module ArrowFormat
21
21
  class StreamingReader
22
22
  include Enumerable
23
23
 
24
- attr_reader :schema
25
24
  def initialize(input)
26
- @input = input
27
- @schema = nil
25
+ case input
26
+ when File
27
+ @input = IO::Buffer.map(input, nil, 0, IO::Buffer::READONLY)
28
+ @offset = 0
29
+ when String
30
+ @input = IO::Buffer.for(input)
31
+ @offset = 0
32
+ else
33
+ @input = input
34
+ end
35
+
36
+ @on_read = nil
37
+ @pull_reader = StreamingPullReader.new do |record_batch|
38
+ @on_read.call(record_batch) if @on_read
39
+ end
40
+ @buffer = "".b
41
+ ensure_schema
28
42
  end
29
43
 
30
- def each
44
+ def schema
45
+ @pull_reader.schema
46
+ end
47
+
48
+ def each(&block)
31
49
  return to_enum(__method__) unless block_given?
32
50
 
33
- reader = StreamingPullReader.new do |record_batch|
34
- @schema ||= reader.schema
35
- yield(record_batch)
51
+ @on_read = block
52
+ begin
53
+ loop do
54
+ break unless consume
55
+ end
56
+ ensure
57
+ @on_read = nil
36
58
  end
59
+ end
37
60
 
38
- buffer = "".b
39
- loop do
40
- next_size = reader.next_required_size
41
- break if next_size.zero?
61
+ private
62
+ def consume
63
+ next_size = @pull_reader.next_required_size
64
+ return false if next_size.zero?
42
65
 
43
- next_chunk = @input.read(next_size, buffer)
44
- break if next_chunk.nil?
66
+ if @input.is_a?(IO::Buffer)
67
+ next_chunk = @input.slice(@offset, next_size)
68
+ @offset += next_size
69
+ @pull_reader.consume(next_chunk)
70
+ true
71
+ else
72
+ next_chunk = @input.read(next_size, @buffer)
73
+ return false if next_chunk.nil?
45
74
 
46
- reader.consume(IO::Buffer.for(next_chunk))
75
+ @pull_reader.consume(IO::Buffer.for(next_chunk))
76
+ true
77
+ end
78
+ end
79
+
80
+ def ensure_schema
81
+ loop do
82
+ break unless consume
83
+ break if @pull_reader.schema
47
84
  end
48
85
  end
49
86
  end
@@ -0,0 +1,156 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ require_relative "buffer-alignable"
19
+
20
+ module ArrowFormat
21
+ class StreamingWriter
22
+ include BufferAlignable
23
+
24
+ ALIGNMENT_SIZE = IO::Buffer.size_of(:u64)
25
+ CONTINUATION = "\xFF\xFF\xFF\xFF".b.freeze
26
+ EOS = "\xFF\xFF\xFF\xFF\x00\x00\x00\x00".b.freeze
27
+ METADATA_LARGEST_PADDING = "\x00" * 7
28
+
29
+ def initialize(output)
30
+ @output = output
31
+ @offset = 0
32
+ @fb_dictionary_blocks = []
33
+ @fb_record_batch_blocks = []
34
+ @written_dictionary_offsets = {}
35
+ end
36
+
37
+ def start(schema)
38
+ write_message(build_metadata(schema.to_flatbuffers,
39
+ custom_metadata: schema.message_metadata))
40
+ end
41
+
42
+ def write_record_batch(record_batch)
43
+ record_batch.schema.fields.each_with_index do |field, i|
44
+ next unless field.type.is_a?(DictionaryType)
45
+ dictionary_array = record_batch.columns[i]
46
+ write_dictionary(field.type.id, dictionary_array)
47
+ end
48
+
49
+ write_record_batch_based_message(record_batch,
50
+ record_batch.to_flatbuffers,
51
+ @fb_record_batch_blocks)
52
+ end
53
+
54
+ def finish
55
+ write_data(EOS)
56
+ @output
57
+ end
58
+
59
+ private
60
+ def write_data(data)
61
+ case data
62
+ when IO::Buffer
63
+ # TODO: We should use IO::Buffer#write to avoid needless copy.
64
+ # data.write(@output)
65
+ @output << data.get_string
66
+ @offset += data.size
67
+ else
68
+ @output << data
69
+ @offset += data.bytesize
70
+ end
71
+ end
72
+
73
+ def write_buffer(buffer)
74
+ write_data(buffer)
75
+ padding_size = buffer_padding_size(buffer)
76
+ write_data(padding(padding_size)) if padding_size > 0
77
+ end
78
+
79
+ def build_metadata(header, body_length=0, custom_metadata: nil)
80
+ fb_message = FB::Message::Data.new
81
+ fb_message.version = FB::MetadataVersion::V5
82
+ fb_message.header = header
83
+ fb_message.body_length = body_length
84
+ fb_message.custom_metadata = FB.build_custom_metadata(custom_metadata)
85
+ metadata = FB::Message.serialize(fb_message)
86
+ metadata_size = metadata.bytesize
87
+ padding_size = compute_padding_size(metadata_size, ALIGNMENT_SIZE)
88
+ metadata_size += padding_size
89
+ align!(metadata, ALIGNMENT_SIZE)
90
+ metadata
91
+ end
92
+
93
+ def write_record_batch_based_message(record_batch, fb_header, fb_blocks)
94
+ body_length = 0
95
+ record_batch.all_buffers_enumerator.each do |buffer|
96
+ body_length += aligned_buffer_size(buffer) if buffer
97
+ end
98
+ metadata = build_metadata(fb_header, body_length,
99
+ custom_metadata: record_batch.message_metadata)
100
+ fb_block = FB::Block::Data.new
101
+ fb_block.offset = @offset
102
+ fb_block.meta_data_length =
103
+ CONTINUATION.bytesize +
104
+ MessagePullReader::METADATA_LENGTH_SIZE +
105
+ metadata.bytesize
106
+ fb_block.body_length = body_length
107
+ fb_blocks << fb_block
108
+ write_message(metadata) do
109
+ record_batch.all_buffers_enumerator.each do |buffer|
110
+ write_buffer(buffer) if buffer
111
+ end
112
+ end
113
+ end
114
+
115
+ def write_dictionary(id, dictionary_array)
116
+ value_type = dictionary_array.type.value_type
117
+ base_offset = 0
118
+ dictionary_array.dictionaries.each do |dictionary|
119
+ data = dictionary.array
120
+ written_offset = @written_dictionary_offsets[id] || 0
121
+ current_base_offset = base_offset
122
+ next_base_offset = base_offset + data.size
123
+ base_offset = next_base_offset
124
+
125
+ next if next_base_offset <= written_offset
126
+
127
+ is_delta = (not written_offset.zero?)
128
+ if current_base_offset < written_offset
129
+ data = data.slice(written_offset - current_base_offset)
130
+ end
131
+
132
+ schema = Schema.new([Field.new("dummy", value_type)])
133
+ size = data.size
134
+ record_batch =
135
+ RecordBatch.new(schema, size, [data],
136
+ message_metadata: dictionary.message_metadata)
137
+ fb_dictionary_batch = FB::DictionaryBatch::Data.new
138
+ fb_dictionary_batch.id = id
139
+ fb_dictionary_batch.data = record_batch.to_flatbuffers
140
+ fb_dictionary_batch.delta = is_delta
141
+ write_record_batch_based_message(record_batch,
142
+ fb_dictionary_batch,
143
+ @fb_dictionary_blocks)
144
+ @written_dictionary_offsets[id] = written_offset + data.size
145
+ end
146
+ end
147
+
148
+ def write_message(metadata)
149
+ write_data(CONTINUATION)
150
+ metadata_size = metadata.bytesize
151
+ write_data([metadata_size].pack("l<"))
152
+ write_data(metadata)
153
+ yield if block_given?
154
+ end
155
+ end
156
+ end