Skip to content

Commit 0493742

Browse files
Merge branch 'main' into fluss-admin-inst-and-cache
2 parents 44f8f47 + 5b7f839 commit 0493742

52 files changed

Lines changed: 1602 additions & 588 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.asf.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919

2020
github:
2121
description: "Rust Client for Apache Fluss (Incubating)"
22-
homepage: https://fluss.apache.org/
22+
homepage: https://clients.fluss.apache.org/
23+
ghp_branch: gh-pages
24+
ghp_path: /
2325
features:
2426
issues: true
2527
projects: false

.github/workflows/build_and_test_cpp.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ jobs:
7070
cmake -B build -DFLUSS_ENABLE_TESTING=ON -DCMAKE_BUILD_TYPE=Debug
7171
cmake --build build --parallel
7272
73-
- name: Run C++ integration tests
73+
- name: Run C++ integration tests (parallel)
7474
working-directory: bindings/cpp
75-
run: cd build && ctest --output-on-failure --timeout 300
75+
run: cd build && ctest -j$(nproc) --output-on-failure --timeout 300
7676
env:
7777
RUST_LOG: DEBUG
7878
RUST_BACKTRACE: full

.github/workflows/build_and_test_python.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ jobs:
7373
uv sync --extra dev
7474
uv run maturin develop
7575
76-
- name: Run Python integration tests
76+
- name: Run Python integration tests (parallel)
7777
working-directory: bindings/python
78-
run: uv run pytest test/ -v
78+
run: uv run pytest test/ -v -n auto
7979
env:
8080
RUST_LOG: DEBUG
8181
RUST_BACKTRACE: full
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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+
name: Deploy Documentation
19+
20+
on:
21+
workflow_dispatch:
22+
23+
permissions:
24+
contents: write
25+
26+
jobs:
27+
deploy:
28+
runs-on: ubuntu-latest
29+
defaults:
30+
run:
31+
working-directory: ./website
32+
steps:
33+
- uses: actions/checkout@v6
34+
with:
35+
fetch-depth: 0
36+
37+
- uses: actions/setup-node@v6
38+
with:
39+
node-version: 24
40+
41+
- name: Install dependencies
42+
run: npm install
43+
44+
- name: Build website
45+
run: npm run build
46+
47+
- name: Deploy to gh-pages branch
48+
working-directory: .
49+
env:
50+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
51+
run: |
52+
git config user.name "github-actions[bot]"
53+
git config user.email "github-actions[bot]@users.noreply.github.com"
54+
55+
# Create a temporary directory with the built site
56+
TMPDIR=$(mktemp -d)
57+
cp -r website/build/* "$TMPDIR"
58+
59+
# Switch to the gh-pages branch (create orphan if it doesn't exist)
60+
if git ls-remote --exit-code origin gh-pages; then
61+
git fetch origin gh-pages
62+
git checkout gh-pages
63+
else
64+
git checkout --orphan gh-pages
65+
git rm -rf .
66+
fi
67+
68+
# Replace contents with the new build
69+
git rm -rf . || true
70+
git clean -fdx
71+
cp -r "$TMPDIR"/* .
72+
rm -rf "$TMPDIR"
73+
74+
# Commit and push
75+
git add -A
76+
if git diff --cached --quiet; then
77+
echo "No changes to deploy."
78+
else
79+
git commit -m "Deploy website from ${GITHUB_SHA::8}"
80+
git push origin gh-pages
81+
fi

.github/workflows/release_python.yml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,37 +94,55 @@ jobs:
9494

9595
- name: Install protoc (Windows)
9696
if: runner.os == 'Windows'
97-
run: choco install protobuf -y
97+
run: choco install protoc -y
9898
shell: pwsh
9999

100+
# Install protoc in manylinux container (x86_64/aarch64); script shared via YAML anchor
100101
- uses: PyO3/maturin-action@v1
101102
with:
102103
working-directory: bindings/python
103104
target: ${{ matrix.target }}
104105
command: build
105106
args: --release -o dist -i python3.9
106107
manylinux: ${{ matrix.manylinux || 'auto' }}
108+
before-script-linux: &protoc-install |
109+
set -e
110+
ARCH=$(uname -m)
111+
case "$ARCH" in
112+
x86_64) ZIP=protoc-27.1-linux-x86_64.zip ;;
113+
aarch64) ZIP=protoc-27.1-linux-aarch_64.zip ;;
114+
*) echo "Unsupported arch $ARCH"; exit 1 ;;
115+
esac
116+
curl -sLO "https://github.com/protocolbuffers/protobuf/releases/download/v27.1/${ZIP}"
117+
python3 -c "import zipfile; zipfile.ZipFile('${ZIP}').extractall('/tmp/protoc_install')"
118+
chmod +x /tmp/protoc_install/bin/protoc
119+
rm -f "${ZIP}"
120+
export PATH="/tmp/protoc_install/bin:$PATH"
121+
export PROTOC=/tmp/protoc_install/bin/protoc
107122
- uses: PyO3/maturin-action@v1
108123
with:
109124
working-directory: bindings/python
110125
target: ${{ matrix.target }}
111126
command: build
112127
args: --release -o dist -i python3.10
113128
manylinux: ${{ matrix.manylinux || 'auto' }}
129+
before-script-linux: *protoc-install
114130
- uses: PyO3/maturin-action@v1
115131
with:
116132
working-directory: bindings/python
117133
target: ${{ matrix.target }}
118134
command: build
119135
args: --release -o dist -i python3.11
120136
manylinux: ${{ matrix.manylinux || 'auto' }}
137+
before-script-linux: *protoc-install
121138
- uses: PyO3/maturin-action@v1
122139
with:
123140
working-directory: bindings/python
124141
target: ${{ matrix.target }}
125142
command: build
126143
args: --release -o dist -i python3.12
127144
manylinux: ${{ matrix.manylinux || 'auto' }}
145+
before-script-linux: *protoc-install
128146

129147
- name: Upload wheels
130148
uses: actions/upload-artifact@v4

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ __pycache__/
2525
*.py[cod]
2626
*$py.class
2727
*.so
28+
*.dylib
29+
*.dSYM/
2830
*.egg-info/
2931
dist/
3032
build/

bindings/cpp/CMakeLists.txt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ if (FLUSS_ENABLE_TESTING)
256256
FetchContent_MakeAvailable(googletest)
257257

258258
enable_testing()
259+
include(GoogleTest)
259260

260261
file(GLOB TEST_SOURCE_FILES "test/*.cpp")
261262
add_executable(fluss_cpp_test ${TEST_SOURCE_FILES})
@@ -267,5 +268,17 @@ if (FLUSS_ENABLE_TESTING)
267268
${PROJECT_SOURCE_DIR}/test
268269
)
269270

270-
add_test(NAME fluss_cpp_integration_tests COMMAND fluss_cpp_test)
271+
# Individual tests for parallel execution via ctest -j.
272+
gtest_discover_tests(fluss_cpp_test
273+
PROPERTIES
274+
TIMEOUT 120
275+
FIXTURES_REQUIRED fluss_cluster
276+
)
277+
278+
# Cleanup: stop Docker containers after all tests finish.
279+
# Mirrors Python's pytest_unconfigure and Rust's atexit cleanup.
280+
add_test(NAME fluss_cluster_cleanup COMMAND fluss_cpp_test --cleanup)
281+
set_tests_properties(fluss_cluster_cleanup PROPERTIES
282+
FIXTURES_CLEANUP fluss_cluster
283+
)
271284
endif()

bindings/cpp/src/connection.cpp

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,13 @@ Connection& Connection::operator=(Connection&& other) noexcept {
4747
}
4848

4949
Result Connection::Create(const Configuration& config, Connection& out) {
50-
try {
51-
auto ffi_config = utils::to_ffi_config(config);
52-
out.conn_ = ffi::new_connection(ffi_config);
53-
return utils::make_ok();
54-
} catch (const rust::Error& e) {
55-
return utils::make_client_error(e.what());
56-
} catch (const std::exception& e) {
57-
return utils::make_client_error(e.what());
50+
auto ffi_config = utils::to_ffi_config(config);
51+
auto ffi_result = ffi::new_connection(ffi_config);
52+
auto result = utils::from_ffi_result(ffi_result.result);
53+
if (result.Ok()) {
54+
out.conn_ = utils::ptr_from_ffi<ffi::Connection>(ffi_result);
5855
}
56+
return result;
5957
}
6058

6159
bool Connection::Available() const { return conn_ != nullptr; }
@@ -65,30 +63,26 @@ Result Connection::GetAdmin(Admin& out) {
6563
return utils::make_client_error("Connection not available");
6664
}
6765

68-
try {
69-
out.admin_ = conn_->get_admin();
70-
return utils::make_ok();
71-
} catch (const rust::Error& e) {
72-
return utils::make_client_error(e.what());
73-
} catch (const std::exception& e) {
74-
return utils::make_client_error(e.what());
66+
auto ffi_result = conn_->get_admin();
67+
auto result = utils::from_ffi_result(ffi_result.result);
68+
if (result.Ok()) {
69+
out.admin_ = utils::ptr_from_ffi<ffi::Admin>(ffi_result);
7570
}
71+
return result;
7672
}
7773

7874
Result Connection::GetTable(const TablePath& table_path, Table& out) {
7975
if (!Available()) {
8076
return utils::make_client_error("Connection not available");
8177
}
8278

83-
try {
84-
auto ffi_path = utils::to_ffi_table_path(table_path);
85-
out.table_ = conn_->get_table(ffi_path);
86-
return utils::make_ok();
87-
} catch (const rust::Error& e) {
88-
return utils::make_client_error(e.what());
89-
} catch (const std::exception& e) {
90-
return utils::make_client_error(e.what());
79+
auto ffi_path = utils::to_ffi_table_path(table_path);
80+
auto ffi_result = conn_->get_table(ffi_path);
81+
auto result = utils::from_ffi_result(ffi_result.result);
82+
if (result.Ok()) {
83+
out.table_ = utils::ptr_from_ffi<ffi::Table>(ffi_result);
9184
}
85+
return result;
9286
}
9387

9488
} // namespace fluss

bindings/cpp/src/ffi_converter.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
#pragma once
2121

22+
#include <cassert>
23+
2224
#include "fluss.hpp"
2325
#include "lib.rs.h"
2426

@@ -37,6 +39,12 @@ inline Result from_ffi_result(const ffi::FfiResult& ffi_result) {
3739
return Result{ffi_result.error_code, std::string(ffi_result.error_message)};
3840
}
3941

42+
template <typename T>
43+
inline T* ptr_from_ffi(const ffi::FfiPtrResult& r) {
44+
assert(r.ptr != 0 && "ptr_from_ffi: null pointer in FfiPtrResult");
45+
return reinterpret_cast<T*>(r.ptr);
46+
}
47+
4048
inline ffi::FfiTablePath to_ffi_table_path(const TablePath& path) {
4149
ffi::FfiTablePath ffi_path;
4250
ffi_path.database_name = rust::String(path.database_name);

0 commit comments

Comments
 (0)