Skip to content

Commit d3f7e1c

Browse files
committed
feat(fs): introduce Jindo file system support
1 parent 781b48b commit d3f7e1c

22 files changed

Lines changed: 3780 additions & 0 deletions

src/paimon/fs/jindo/CMakeLists.txt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
if(PAIMON_ENABLE_JINDO)
18+
set(PAIMON_JINDO_FILE_SYSTEM jindo_file_system.cpp jindo_file_system_factory.cpp)
19+
20+
add_paimon_lib(paimon_jindo_file_system
21+
SOURCES
22+
${PAIMON_JINDO_FILE_SYSTEM}
23+
EXTRA_INCLUDES
24+
${JINDOSDK_INCLUDE_DIR}
25+
DEPENDENCIES
26+
paimon_shared
27+
jindosdk::nextarch
28+
STATIC_LINK_LIBS
29+
jindosdk::nextarch
30+
fmt
31+
SHARED_LINK_LIBS
32+
paimon_shared
33+
SHARED_LINK_FLAGS
34+
${PAIMON_VERSION_SCRIPT_FLAGS})
35+
endif()
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#pragma once
20+
21+
#include <string>
22+
#include <utility>
23+
24+
#include "JdoFileInfo.hpp" // NOLINT(build/include_subdir)
25+
#include "paimon/fs/file_system.h"
26+
27+
namespace paimon::jindo {
28+
class JindoBasicFileStatus : public BasicFileStatus {
29+
public:
30+
explicit JindoBasicFileStatus(JdoFileInfo&& file_info) : file_info_(std::move(file_info)) {}
31+
32+
std::string GetPath() const override {
33+
return file_info_.getPath();
34+
}
35+
36+
bool IsDir() const override {
37+
return file_info_.isDir();
38+
}
39+
40+
private:
41+
JdoFileInfo file_info_;
42+
};
43+
44+
class JindoFileStatus : public FileStatus {
45+
public:
46+
explicit JindoFileStatus(JdoFileInfo&& file_info) : file_info_(std::move(file_info)) {}
47+
48+
std::string GetPath() const override {
49+
return file_info_.getPath();
50+
}
51+
52+
uint64_t GetLen() const override {
53+
return file_info_.getLength();
54+
}
55+
56+
int64_t GetModificationTime() const override {
57+
return file_info_.getMtime();
58+
}
59+
60+
bool IsDir() const override {
61+
return file_info_.isDir();
62+
}
63+
64+
private:
65+
JdoFileInfo file_info_;
66+
};
67+
} // namespace paimon::jindo
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
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, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#include "paimon/fs/jindo/jindo_file_system.h"
20+
21+
#include <cassert>
22+
#include <utility>
23+
24+
#include "JdoFileInfo.hpp" // NOLINT(build/include_subdir)
25+
#include "JdoFileSystem.hpp" // NOLINT(build/include_subdir)
26+
#include "JdoListResult.hpp" // NOLINT(build/include_subdir)
27+
#include "JdoStatus.hpp" // NOLINT(build/include_subdir)
28+
#include "fmt/format.h"
29+
#include "jdo_error.h" // NOLINT(build/include_subdir)
30+
#include "paimon/fs/jindo/jindo_file_status.h"
31+
#include "paimon/fs/jindo/jindo_utils.h"
32+
33+
namespace paimon::jindo {
34+
35+
class JindoFileSystemImpl {
36+
public:
37+
explicit JindoFileSystemImpl(std::unique_ptr<JdoFileSystem>&& fs) : fs_(std::move(fs)) {
38+
assert(fs_);
39+
}
40+
~JindoFileSystemImpl() {
41+
if (fs_) {
42+
[[maybe_unused]] auto status = fs_->destroy();
43+
assert(status.ok());
44+
fs_.reset();
45+
}
46+
}
47+
JdoFileSystem* GetFileSystem() {
48+
assert(fs_);
49+
return fs_.get();
50+
}
51+
52+
private:
53+
std::unique_ptr<JdoFileSystem> fs_;
54+
};
55+
56+
JindoFileSystem::JindoFileSystem(std::unique_ptr<JdoFileSystem>&& fs)
57+
: impl_(std::make_shared<JindoFileSystemImpl>(std::move(fs))) {}
58+
59+
Result<std::unique_ptr<InputStream>> JindoFileSystem::Open(const std::string& path) const {
60+
std::unique_ptr<JdoReader> reader;
61+
PAIMON_RETURN_NOT_OK_FROM_JINDO(impl_->GetFileSystem()->openReader(path, &reader));
62+
return std::make_unique<JindoInputStream>(impl_, std::move(reader));
63+
}
64+
65+
Result<std::unique_ptr<OutputStream>> JindoFileSystem::Create(const std::string& path,
66+
bool overwrite) const {
67+
PAIMON_ASSIGN_OR_RAISE(bool exist, Exists(path));
68+
if (exist && !overwrite) {
69+
return Status::Invalid(
70+
fmt::format("do not allow overwrite, but the file {} already exists", path));
71+
}
72+
std::unique_ptr<JdoWriter> writer;
73+
PAIMON_RETURN_NOT_OK_FROM_JINDO(impl_->GetFileSystem()->openWriter(path, &writer));
74+
return std::make_unique<JindoOutputStream>(impl_, std::move(writer));
75+
}
76+
77+
Status JindoFileSystem::Mkdirs(const std::string& path) const {
78+
PAIMON_RETURN_NOT_OK_FROM_JINDO(impl_->GetFileSystem()->mkdir(path, /*recursive=*/true));
79+
return Status::OK();
80+
}
81+
82+
Status JindoFileSystem::Rename(const std::string& src, const std::string& dst) const {
83+
PAIMON_ASSIGN_OR_RAISE(bool is_src_exist, Exists(src));
84+
if (!is_src_exist) {
85+
return Status::NotExist(
86+
fmt::format("rename {} to {} failed, because: src file not exist", src, dst));
87+
}
88+
PAIMON_ASSIGN_OR_RAISE(bool is_dst_exist, Exists(dst));
89+
if (is_dst_exist) {
90+
return Status::Invalid(
91+
fmt::format("rename {} to {} failed, because: dst file already exist", src, dst));
92+
}
93+
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<FileStatus> file_status, GetFileStatus(src));
94+
if (!file_status->IsDir() && dst.back() == '/') {
95+
return Status::Invalid(
96+
fmt::format("rename {} to {} failed, because: src file is not a dir", src, dst));
97+
}
98+
PAIMON_RETURN_NOT_OK_FROM_JINDO(impl_->GetFileSystem()->rename(src, dst));
99+
return Status::OK();
100+
}
101+
102+
Result<bool> JindoFileSystem::Exists(const std::string& path) const {
103+
auto status = impl_->GetFileSystem()->exists(path);
104+
if (status.ok()) {
105+
return true;
106+
} else if (status.getErrCode() == JDO_FILE_NOT_FOUND_ERROR) {
107+
return false;
108+
}
109+
return Status::IOError(status.errMsg());
110+
}
111+
112+
Status JindoFileSystem::Delete(const std::string& path, bool recursive) const {
113+
PAIMON_RETURN_NOT_OK_FROM_JINDO(impl_->GetFileSystem()->remove(path, recursive));
114+
return Status::OK();
115+
}
116+
117+
Result<std::unique_ptr<FileStatus>> JindoFileSystem::GetFileStatus(const std::string& path) const {
118+
JdoFileInfo file_info;
119+
PAIMON_RETURN_NOT_OK_FROM_JINDO(impl_->GetFileSystem()->getFileInfo(path, &file_info));
120+
return std::make_unique<JindoFileStatus>(std::move(file_info));
121+
}
122+
123+
Status JindoFileSystem::ListDir(
124+
const std::string& directory,
125+
std::vector<std::unique_ptr<BasicFileStatus>>* file_status_list) const {
126+
PAIMON_ASSIGN_OR_RAISE(bool exist, Exists(directory));
127+
if (!exist) {
128+
return Status::OK();
129+
}
130+
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<FileStatus> file_status, GetFileStatus(directory));
131+
if (!file_status->IsDir()) {
132+
return Status::Invalid(
133+
fmt::format("file {} already exists and is not a directory", file_status->GetPath()));
134+
}
135+
JdoListResult list_result;
136+
while (true) {
137+
PAIMON_RETURN_NOT_OK_FROM_JINDO(
138+
impl_->GetFileSystem()->listDir(directory, /*recursive=*/false, &list_result));
139+
auto file_infos = list_result.getFileInfos();
140+
file_status_list->reserve(file_status_list->size() + file_infos.size());
141+
for (auto& file_info : file_infos) {
142+
file_status_list->push_back(
143+
std::make_unique<JindoBasicFileStatus>(std::move(file_info)));
144+
}
145+
if (!list_result.isTruncated()) {
146+
break;
147+
}
148+
// TODO(xinyu.lxy): test truncated
149+
list_result.setFileInfos({});
150+
list_result.setTruncated(false);
151+
}
152+
return Status::OK();
153+
}
154+
155+
Status JindoFileSystem::ListFileStatus(
156+
const std::string& path, std::vector<std::unique_ptr<FileStatus>>* file_status_list) const {
157+
PAIMON_ASSIGN_OR_RAISE(bool exist, Exists(path));
158+
if (!exist) {
159+
return Status::OK();
160+
}
161+
162+
JdoListResult list_result;
163+
while (true) {
164+
PAIMON_RETURN_NOT_OK_FROM_JINDO(
165+
impl_->GetFileSystem()->listDir(path, /*recursive=*/false, &list_result));
166+
auto file_infos = list_result.getFileInfos();
167+
file_status_list->reserve(file_status_list->size() + file_infos.size());
168+
for (auto& file_info : file_infos) {
169+
// oss not support list FileStatus, only return BasicFileStatus
170+
// call GetFileStatus to return FileStatus
171+
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<FileStatus> file_status,
172+
GetFileStatus(file_info.getPath()));
173+
file_status_list->push_back(std::move(file_status));
174+
}
175+
if (!list_result.isTruncated()) {
176+
break;
177+
}
178+
list_result.setFileInfos({});
179+
list_result.setTruncated(false);
180+
}
181+
return Status::OK();
182+
}
183+
184+
JindoInputStream::JindoInputStream(const std::shared_ptr<JindoFileSystemImpl>& fs,
185+
std::unique_ptr<JdoReader>&& reader)
186+
: fs_(fs), reader_(std::move(reader)) {}
187+
188+
Status JindoInputStream::Seek(int64_t offset, SeekOrigin origin) {
189+
if (origin == FS_SEEK_SET) {
190+
PAIMON_RETURN_NOT_OK_FROM_JINDO(reader_->seek(offset));
191+
} else if (origin == FS_SEEK_CUR) {
192+
PAIMON_ASSIGN_OR_RAISE(int64_t pos, GetPos());
193+
PAIMON_RETURN_NOT_OK_FROM_JINDO(reader_->seek(offset + pos));
194+
} else if (origin == FS_SEEK_END) {
195+
PAIMON_ASSIGN_OR_RAISE(uint64_t len, Length());
196+
PAIMON_RETURN_NOT_OK_FROM_JINDO(reader_->seek(len + offset));
197+
} else {
198+
return Status::Invalid("unsupported seek origin");
199+
}
200+
return Status::OK();
201+
}
202+
203+
Result<int64_t> JindoInputStream::GetPos() const {
204+
int64_t pos = -1;
205+
PAIMON_RETURN_NOT_OK_FROM_JINDO(reader_->tell(pos));
206+
return pos;
207+
}
208+
209+
Result<uint64_t> JindoInputStream::Length() const {
210+
int64_t len = -1;
211+
PAIMON_RETURN_NOT_OK_FROM_JINDO(reader_->getFileLength(len));
212+
return len;
213+
}
214+
215+
Result<int32_t> JindoInputStream::Read(char* buffer, uint32_t size) {
216+
PAIMON_RETURN_NOT_OK_FROM_JINDO(reader_->read(size, &result_, buffer));
217+
return result_.length();
218+
}
219+
220+
Result<int32_t> JindoInputStream::Read(char* buffer, uint32_t size, uint64_t offset) {
221+
PAIMON_RETURN_NOT_OK_FROM_JINDO(reader_->pread(offset, size, &result_, buffer));
222+
return result_.length();
223+
}
224+
225+
void JindoInputStream::ReadAsync(char* buffer, uint32_t size, uint64_t offset,
226+
std::function<void(Status)>&& callback) {
227+
auto outer_callback = [=](JdoStatus status) {
228+
callback(status.ok() ? Status::OK() : Status::IOError(status.errMsg()));
229+
};
230+
auto task = reader_->preadAsync(offset, size, &result_, buffer, outer_callback);
231+
assert(task);
232+
auto status = task->perform();
233+
}
234+
235+
Status JindoInputStream::Close() {
236+
PAIMON_RETURN_NOT_OK_FROM_JINDO(reader_->close());
237+
return Status::OK();
238+
}
239+
240+
Result<std::string> JindoInputStream::GetUri() const {
241+
std::string_view uri;
242+
PAIMON_RETURN_NOT_OK_FROM_JINDO(reader_->name(&uri));
243+
return std::string(uri);
244+
}
245+
246+
JindoOutputStream::JindoOutputStream(const std::shared_ptr<JindoFileSystemImpl>& fs,
247+
std::unique_ptr<JdoWriter>&& writer)
248+
: fs_(fs), writer_(std::move(writer)) {}
249+
250+
Result<int64_t> JindoOutputStream::GetPos() const {
251+
int64_t pos = -1;
252+
PAIMON_RETURN_NOT_OK_FROM_JINDO(writer_->tell(pos));
253+
return pos;
254+
}
255+
256+
Result<int32_t> JindoOutputStream::Write(const char* buffer, uint32_t size) {
257+
std::string_view data(buffer, size);
258+
PAIMON_RETURN_NOT_OK_FROM_JINDO(writer_->write(data));
259+
return size;
260+
}
261+
262+
Status JindoOutputStream::Flush() {
263+
PAIMON_RETURN_NOT_OK_FROM_JINDO(writer_->flush());
264+
return Status::OK();
265+
}
266+
267+
Status JindoOutputStream::Close() {
268+
PAIMON_RETURN_NOT_OK_FROM_JINDO(writer_->close());
269+
return Status::OK();
270+
}
271+
272+
Result<std::string> JindoOutputStream::GetUri() const {
273+
std::string_view name;
274+
PAIMON_RETURN_NOT_OK_FROM_JINDO(writer_->name(&name));
275+
return std::string(name);
276+
}
277+
278+
} // namespace paimon::jindo

0 commit comments

Comments
 (0)