Skip to content

Commit c662861

Browse files
authored
feat(common): introduce arrow utilities (#110)
1 parent 29c9f20 commit c662861

12 files changed

Lines changed: 1436 additions & 0 deletions
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#include "paimon/common/utils/arrow/arrow_input_stream_adapter.h"
21+
22+
#include <cstdint>
23+
#include <utility>
24+
25+
#include "arrow/api.h"
26+
#include "fmt/format.h"
27+
#include "paimon/common/utils/arrow/status_utils.h"
28+
#include "paimon/common/utils/math.h"
29+
#include "paimon/common/utils/options_utils.h"
30+
#include "paimon/fs/file_system.h"
31+
#include "paimon/macros.h"
32+
#include "paimon/result.h"
33+
#include "paimon/status.h"
34+
35+
namespace paimon {
36+
37+
namespace {
38+
39+
template <typename To, typename From>
40+
arrow::Status ValidateArrowIoRange(From value, const char* name) {
41+
if (!InRange<To>(value)) {
42+
return arrow::Status::Invalid(fmt::format("{} value {} is out of bound of type {}", name,
43+
value, OptionsUtils::GetTypeName<To>()));
44+
}
45+
return arrow::Status::OK();
46+
}
47+
48+
} // namespace
49+
50+
ArrowInputStreamAdapter::ArrowInputStreamAdapter(
51+
const std::shared_ptr<paimon::InputStream>& input_stream,
52+
const std::shared_ptr<arrow::MemoryPool>& pool, uint64_t file_size)
53+
: input_stream_(input_stream), pool_(pool), file_size_(file_size) {}
54+
55+
ArrowInputStreamAdapter::~ArrowInputStreamAdapter() {
56+
[[maybe_unused]] auto status = DoClose();
57+
}
58+
59+
arrow::Status ArrowInputStreamAdapter::Seek(int64_t position) {
60+
return ToArrowStatus(input_stream_->Seek(position, SeekOrigin::FS_SEEK_SET));
61+
}
62+
63+
arrow::Result<int64_t> ArrowInputStreamAdapter::Read(int64_t nbytes, void* out) {
64+
ARROW_RETURN_NOT_OK(ValidateArrowIoRange<uint32_t>(nbytes, "nbytes"));
65+
Result<int32_t> read_bytes =
66+
input_stream_->Read(static_cast<char*>(out), static_cast<uint32_t>(nbytes));
67+
if (!read_bytes.ok()) {
68+
return ToArrowStatus(read_bytes.status());
69+
}
70+
return read_bytes.value();
71+
}
72+
73+
arrow::Result<std::shared_ptr<arrow::Buffer>> ArrowInputStreamAdapter::Read(int64_t nbytes) {
74+
ARROW_ASSIGN_OR_RAISE(std::shared_ptr<arrow::ResizableBuffer> buffer,
75+
arrow::AllocateResizableBuffer(nbytes, pool_.get()));
76+
ARROW_ASSIGN_OR_RAISE(int64_t read_bytes, Read(nbytes, buffer->mutable_data()));
77+
if (read_bytes < nbytes) {
78+
ARROW_RETURN_NOT_OK(buffer->Resize(read_bytes));
79+
}
80+
return std::shared_ptr<arrow::Buffer>(std::move(buffer));
81+
}
82+
83+
arrow::Result<int64_t> ArrowInputStreamAdapter::ReadAt(int64_t position, int64_t nbytes,
84+
void* out) {
85+
ARROW_RETURN_NOT_OK(ValidateArrowIoRange<uint64_t>(position, "position"));
86+
ARROW_RETURN_NOT_OK(ValidateArrowIoRange<uint32_t>(nbytes, "nbytes"));
87+
Result<int32_t> read_bytes = input_stream_->Read(
88+
static_cast<char*>(out), static_cast<uint32_t>(nbytes), static_cast<uint64_t>(position));
89+
if (!read_bytes.ok()) {
90+
return ToArrowStatus(read_bytes.status());
91+
}
92+
return read_bytes.value();
93+
}
94+
95+
arrow::Result<std::shared_ptr<arrow::Buffer>> ArrowInputStreamAdapter::ReadAt(int64_t position,
96+
int64_t nbytes) {
97+
ARROW_ASSIGN_OR_RAISE(std::shared_ptr<arrow::ResizableBuffer> buffer,
98+
arrow::AllocateResizableBuffer(nbytes, pool_.get()));
99+
ARROW_ASSIGN_OR_RAISE(int64_t read_bytes, ReadAt(position, nbytes, buffer->mutable_data()));
100+
if (read_bytes < nbytes) {
101+
ARROW_RETURN_NOT_OK(buffer->Resize(read_bytes));
102+
}
103+
return std::shared_ptr<arrow::Buffer>(std::move(buffer));
104+
}
105+
106+
arrow::Future<std::shared_ptr<arrow::Buffer>> ArrowInputStreamAdapter::ReadAsync(
107+
const arrow::io::IOContext& io_context, int64_t position, int64_t nbytes) {
108+
auto fut = arrow::Future<std::shared_ptr<arrow::Buffer>>::Make();
109+
auto range_status = ValidateArrowIoRange<uint64_t>(position, "position");
110+
if (!range_status.ok()) {
111+
fut.MarkFinished(range_status);
112+
return fut;
113+
}
114+
range_status = ValidateArrowIoRange<uint32_t>(nbytes, "nbytes");
115+
if (!range_status.ok()) {
116+
fut.MarkFinished(range_status);
117+
return fut;
118+
}
119+
120+
arrow::Result<std::shared_ptr<arrow::Buffer>> buffer_result =
121+
arrow::AllocateResizableBuffer(nbytes, pool_.get());
122+
if (PAIMON_UNLIKELY(!buffer_result.ok())) {
123+
fut.MarkFinished(buffer_result.status());
124+
return fut;
125+
}
126+
std::shared_ptr<arrow::Buffer> buffer = std::move(buffer_result).ValueUnsafe();
127+
input_stream_->ReadAsync(reinterpret_cast<char*>(buffer->mutable_data()),
128+
static_cast<uint32_t>(nbytes), static_cast<uint64_t>(position),
129+
[fut, buffer](Status callback_status) mutable {
130+
if (callback_status.ok()) {
131+
fut.MarkFinished(std::move(buffer));
132+
} else {
133+
fut.MarkFinished(ToArrowStatus(callback_status));
134+
}
135+
});
136+
return fut;
137+
}
138+
139+
arrow::Result<int64_t> ArrowInputStreamAdapter::Tell() const {
140+
Result<int64_t> position = input_stream_->GetPos();
141+
if (!position.ok()) {
142+
return ToArrowStatus(position.status());
143+
}
144+
return position.value();
145+
}
146+
147+
arrow::Result<int64_t> ArrowInputStreamAdapter::GetSize() {
148+
return static_cast<int64_t>(file_size_);
149+
}
150+
151+
bool ArrowInputStreamAdapter::closed() const {
152+
return closed_;
153+
}
154+
155+
arrow::Status ArrowInputStreamAdapter::DoClose() {
156+
if (!closed_) {
157+
Status status = input_stream_->Close();
158+
if (!status.ok()) {
159+
return ToArrowStatus(status);
160+
}
161+
closed_ = true;
162+
}
163+
return arrow::Status::OK();
164+
}
165+
166+
} // namespace paimon
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#pragma once
21+
22+
#include <cstdint>
23+
#include <memory>
24+
25+
#include "arrow/api.h"
26+
#include "arrow/io/interfaces.h"
27+
#include "arrow/util/future.h"
28+
#include "paimon/visibility.h"
29+
30+
namespace paimon {
31+
class InputStream;
32+
33+
class PAIMON_EXPORT ArrowInputStreamAdapter : public arrow::io::RandomAccessFile {
34+
public:
35+
ArrowInputStreamAdapter(const std::shared_ptr<paimon::InputStream>& input_stream,
36+
const std::shared_ptr<arrow::MemoryPool>& pool, uint64_t file_size);
37+
~ArrowInputStreamAdapter() override;
38+
39+
// NOTE: In paimon file system definition, position + nbytes should not exceed file_size_.
40+
arrow::Result<int64_t> Read(int64_t nbytes, void* out) override;
41+
arrow::Result<std::shared_ptr<arrow::Buffer>> Read(int64_t nbytes) override;
42+
arrow::Result<int64_t> ReadAt(int64_t position, int64_t nbytes, void* out) override;
43+
arrow::Result<std::shared_ptr<arrow::Buffer>> ReadAt(int64_t position, int64_t nbytes) override;
44+
arrow::Future<std::shared_ptr<arrow::Buffer>> ReadAsync(const arrow::io::IOContext& io_context,
45+
int64_t position,
46+
int64_t nbytes) override;
47+
arrow::Status Seek(int64_t position) override;
48+
arrow::Result<int64_t> Tell() const override;
49+
arrow::Result<int64_t> GetSize() override;
50+
arrow::Status Close() override {
51+
return DoClose();
52+
}
53+
bool closed() const override;
54+
55+
private:
56+
arrow::Status DoClose();
57+
58+
std::shared_ptr<paimon::InputStream> input_stream_;
59+
std::shared_ptr<arrow::MemoryPool> pool_;
60+
uint64_t file_size_;
61+
bool closed_ = false;
62+
};
63+
64+
} // namespace paimon
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#include "paimon/common/utils/arrow/arrow_output_stream_adapter.h"
21+
22+
#include "arrow/result.h"
23+
#include "fmt/format.h"
24+
#include "paimon/common/utils/arrow/status_utils.h"
25+
#include "paimon/common/utils/math.h"
26+
#include "paimon/fs/file_system.h"
27+
#include "paimon/result.h"
28+
29+
namespace paimon {
30+
31+
ArrowOutputStreamAdapter::ArrowOutputStreamAdapter(const std::shared_ptr<paimon::OutputStream>& out)
32+
: out_(out) {}
33+
34+
arrow::Status ArrowOutputStreamAdapter::Close() {
35+
// output stream close is called by paimon framework(such as single file writer), no need to
36+
// close here
37+
closed_ = true;
38+
return arrow::Status::OK();
39+
}
40+
41+
arrow::Result<int64_t> ArrowOutputStreamAdapter::Tell() const {
42+
paimon::Result<int64_t> pos = out_->GetPos();
43+
if (!pos.ok()) {
44+
return ToArrowStatus(pos.status());
45+
}
46+
return pos.value();
47+
}
48+
49+
bool ArrowOutputStreamAdapter::closed() const {
50+
return closed_;
51+
}
52+
53+
arrow::Status ArrowOutputStreamAdapter::Write(const void* data, int64_t nbytes) {
54+
if (!InRange<uint32_t>(nbytes)) {
55+
return arrow::Status::Invalid(
56+
fmt::format("nbytes value {} is out of bound of uint32_t", nbytes));
57+
}
58+
Result<int32_t> len =
59+
out_->Write(static_cast<const char*>(data), static_cast<uint32_t>(nbytes));
60+
if (!len.ok()) {
61+
return ToArrowStatus(len.status());
62+
}
63+
return arrow::Status::OK();
64+
}
65+
66+
arrow::Status ArrowOutputStreamAdapter::Flush() {
67+
return ToArrowStatus(out_->Flush());
68+
}
69+
70+
} // namespace paimon
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#pragma once
21+
22+
#include <cstdint>
23+
#include <memory>
24+
25+
#include "arrow/io/interfaces.h"
26+
#include "arrow/result.h"
27+
#include "arrow/status.h"
28+
#include "paimon/visibility.h"
29+
30+
namespace paimon {
31+
class OutputStream;
32+
33+
class PAIMON_EXPORT ArrowOutputStreamAdapter : public arrow::io::OutputStream {
34+
public:
35+
explicit ArrowOutputStreamAdapter(const std::shared_ptr<paimon::OutputStream>& out);
36+
37+
arrow::Status Close() override;
38+
arrow::Result<int64_t> Tell() const override;
39+
bool closed() const override;
40+
arrow::Status Write(const void* data, int64_t nbytes) override;
41+
arrow::Status Flush() override;
42+
43+
private:
44+
std::shared_ptr<paimon::OutputStream> out_;
45+
bool closed_ = false;
46+
};
47+
48+
} // namespace paimon

0 commit comments

Comments
 (0)