-
Notifications
You must be signed in to change notification settings - Fork 3.9k
[feat](fluss) Support reading Apache Fluss tables through a fluss catalog #66399
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
morningman
wants to merge
35
commits into
apache:master
Choose a base branch
from
morningman:fluss-connector
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
360ac6f
[feat](fluss) Add the fluss connector module and its remote-call seam
morningman ef2f341
[feat](fluss) Map fluss column types onto Doris types
morningman f48edfb
[feat](fluss) Describe a fluss table through the connector metadata SPI
morningman da79d18
[feat](fluss) Add the fluss e2e docker environment
morningman fbf1049
[feat](fluss) Carry a fluss scan range to BE
morningman 67d8e72
[feat](fluss) Plan the scan of a fluss log table
morningman 6868277
[feat](fluss) Read a fluss log range in the BE java extension
morningman a242fb1
[feat](fluss) Route a fluss scan range to the BE java scanner
morningman 59e9fc7
[feat](fluss) Add the end-to-end suite for fluss log tables
morningman 8f66082
[fix](fluss) Depend on the fluss test-jar by classifier
morningman d27b62e
[fix](fluss) Read a range whose projection selects no column
morningman e6adf98
[feat](fluss) Plan a primary-key table read as snapshot plus change log
morningman f65d795
[feat](fluss) Read a primary-key range as a snapshot merged with its log
morningman 98d3d7e
[test](fluss) Bake a kv snapshot into the e2e fixtures and read them …
morningman 4b9d666
[fix](be) Stop exporting the statically linked RocksDB symbols
morningman 6a5d5d4
[feat](fluss) Read a fluss lake table through the paimon connector
morningman a3ae2b7
[fix](fluss) Call the lake sibling under its own classloader
morningman d9b5559
[feat](fluss) Read a tiered log table as its lake plus the log after it
morningman 3efa3f2
[fix](paimon) Claim the table handles this connector produces
morningman 927de84
[fix](be) Pick the table reader per scan range, not per scan node
morningman 03e73d6
[fix](fluss) Fail loudly when the lake sibling disowns its own handle
morningman b2a22df
[test](fluss) Read a tiered table end to end, lake only and lake plus…
morningman 82aab4f
[feat](fluss) Read a tiered primary-key table from fluss alone
morningman cbbab7d
[test](fluss) Pin what a tiered primary-key table reads as
morningman e754eb5
[test](fluss) Record the fluss suites' results in baseline files
morningman 212f086
[feat](paimon) Say which bucket a scan range came from
morningman 3285a8e
[test](fluss) Drive the reader from a projection BE built itself
morningman cc317fe
[feat](connector) Let a connector name the columns its reader must read
morningman 46a6dc7
[feat](fluss) Plan a primary-key lake table as its lake plus its log …
morningman 846c50a
[feat](fluss) Read the log tail of a primary-key table as the state i…
morningman ecfec2a
[feat](fluss) Read a primary-key lake split without the rows its log …
morningman bdf964e
[feat](be) Dispatch a wrapped lake split to the reader that unwraps it
morningman 432ff2f
[test](fluss) Read a primary-key lake table on the shapes one bucket …
morningman c052dfc
[feat](fluss) Refuse a partition column fluss cannot keep the value of
morningman 64b1fb8
[test](fluss) Read every type, every partition type and a hundred tho…
morningman File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| // Licensed to the Apache Software Foundation (ASF) under one | ||
| // or more contributor license agreements. See the NOTICE file | ||
| // distributed with this work for additional information | ||
| // regarding copyright ownership. The ASF licenses this file | ||
| // to you under the Apache License, Version 2.0 (the | ||
| // "License"); you may not use this file except in compliance | ||
| // with the License. You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, | ||
| // software distributed under the License is distributed on an | ||
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| // KIND, either express or implied. See the License for the | ||
| // specific language governing permissions and limitations | ||
| // under the License. | ||
|
|
||
| #include "format_v2/jni/fluss_jni_reader.h" | ||
|
|
||
| #include "core/block/block.h" | ||
| #include "exprs/vexpr_context.h" | ||
| #include "format_v2/column_mapper.h" | ||
|
|
||
| namespace doris::format::fluss { | ||
|
|
||
| Status FlussJniReader::validate_scan_range(const TFileRangeDesc& range) const { | ||
| if (!range.__isset.table_format_params) { | ||
| return Status::InternalError("missing table_format_params for fluss jni reader"); | ||
| } | ||
| if (!range.table_format_params.__isset.fluss_params || | ||
| range.table_format_params.fluss_params.empty()) { | ||
| return Status::InternalError( | ||
| "missing fluss_params for fluss jni reader, possibly caused by FE/BE protocol " | ||
| "mismatch"); | ||
| } | ||
| if (_scan_params == nullptr || !_scan_params->__isset.fluss_properties || | ||
| _scan_params->fluss_properties.empty()) { | ||
| return Status::InternalError( | ||
| "missing fluss_properties for fluss jni reader, possibly caused by FE/BE protocol " | ||
| "mismatch"); | ||
| } | ||
| return Status::OK(); | ||
| } | ||
|
|
||
| std::string FlussJniReader::connector_class() const { | ||
| return "org/apache/doris/fluss/FlussJniScanner"; | ||
| } | ||
|
|
||
| Status FlussJniReader::build_scanner_params(std::map<std::string, std::string>* params) const { | ||
| DORIS_CHECK(params != nullptr); | ||
| DORIS_CHECK(_scan_params != nullptr); | ||
| // Scan level first, then the range: the range is the more specific of the two, and it is the one | ||
| // that says which bucket and offsets to read. No key is transcribed - both maps are written by FE | ||
| // and read by the Java scanner, so naming them here would only add a place to drift. | ||
| *params = _scan_params->fluss_properties; | ||
| for (const auto& kv : _current_range.table_format_params.fluss_params) { | ||
| (*params)[kv.first] = kv.second; | ||
| } | ||
| return Status::OK(); | ||
| } | ||
|
|
||
| Status FlussJniReader::build_jni_columns( | ||
| std::vector<format::JniTableReader::JniColumn>* columns) const { | ||
| DORIS_CHECK(columns != nullptr); | ||
| columns->clear(); | ||
| columns->reserve(_projected_columns.size()); | ||
| for (size_t i = 0; i < _projected_columns.size(); ++i) { | ||
| const auto& table_column = _projected_columns[i]; | ||
| // A fluss row physically carries its partition column values, but FE declares the partition | ||
| // keys as path_partition_keys and ships them per range, so they are constants here. Asking | ||
| // the scanner for them would read per row what the split already states once - and would | ||
| // read them differently from the legacy JNI path, whose file slots exclude them outright. | ||
| if (table_column.is_partition_key && | ||
| find_partition_value(table_column, _partition_values) != nullptr) { | ||
| continue; | ||
| } | ||
| columns->push_back({ | ||
| .java_name = table_column.name, | ||
| .output_index = i, | ||
| .output_type = table_column.type, | ||
| .transfer_type = table_column.type, | ||
| .replace_type = "not_replace", | ||
| }); | ||
| } | ||
| return Status::OK(); | ||
| } | ||
|
|
||
| Status FlussJniReader::finalize_jni_block(Block* jni_block, Block* output_block, size_t* rows) { | ||
| DORIS_CHECK(jni_block != nullptr); | ||
| DORIS_CHECK(output_block != nullptr); | ||
| DORIS_CHECK(rows != nullptr); | ||
| const auto original_rows = *rows; | ||
|
|
||
| const auto& columns = jni_columns(); | ||
| DORIS_CHECK(columns.size() == jni_block->columns()); | ||
| for (size_t i = 0; i < columns.size(); ++i) { | ||
| const auto& column = columns[i]; | ||
| DORIS_CHECK(column.output_index < output_block->columns()); | ||
| output_block->get_by_position(column.output_index).type = column.output_type; | ||
| output_block->replace_by_position(column.output_index, | ||
| jni_block->get_by_position(i).column); | ||
| } | ||
|
|
||
| // The columns build_jni_columns() left out: materialized from the range instead of read. | ||
| for (size_t i = 0; i < _projected_columns.size(); ++i) { | ||
| const auto& table_column = _projected_columns[i]; | ||
| const auto* partition_value = find_partition_value(table_column, _partition_values); | ||
| if (!table_column.is_partition_key || partition_value == nullptr) { | ||
| continue; | ||
| } | ||
| output_block->get_by_position(i).type = table_column.type; | ||
| output_block->replace_by_position( | ||
| i, table_column.type->create_column_const(original_rows, *partition_value)); | ||
| } | ||
| DORIS_CHECK(output_block->rows() == original_rows); | ||
| if (!_conjuncts.empty()) { | ||
| RETURN_IF_ERROR( | ||
| VExprContext::filter_block(_conjuncts, output_block, output_block->columns())); | ||
| } | ||
| *rows = output_block->rows(); | ||
| return Status::OK(); | ||
| } | ||
|
|
||
| } // namespace doris::format::fluss |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| // Licensed to the Apache Software Foundation (ASF) under one | ||
| // or more contributor license agreements. See the NOTICE file | ||
| // distributed with this work for additional information | ||
| // regarding copyright ownership. The ASF licenses this file | ||
| // to you under the Apache License, Version 2.0 (the | ||
| // "License"); you may not use this file except in compliance | ||
| // with the License. You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, | ||
| // software distributed under the License is distributed on an | ||
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| // KIND, either express or implied. See the License for the | ||
| // specific language governing permissions and limitations | ||
| // under the License. | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <map> | ||
| #include <string> | ||
| #include <vector> | ||
|
|
||
| #include "common/status.h" | ||
| #include "format_v2/jni/jni_table_reader.h" | ||
| #include "gen_cpp/PlanNodes_types.h" | ||
|
|
||
| namespace doris::format::fluss { | ||
|
|
||
| /** | ||
| * Reads one fluss scan range through org.apache.doris.fluss.FlussJniScanner. | ||
| * | ||
| * This layer holds no fluss logic. FE writes two untyped string maps - the scan-level | ||
| * `fluss_properties` (connection, table identity, client options) and the per-range `fluss_params` | ||
| * (which bucket, which offsets) - and the only decision made here is that the range wins where both | ||
| * set a key. | ||
| */ | ||
| class FlussJniReader final : public format::JniTableReader { | ||
| public: | ||
| ~FlussJniReader() override = default; | ||
|
|
||
| protected: | ||
| std::string connector_class() const override; | ||
| Status validate_scan_range(const TFileRangeDesc& range) const override; | ||
| Status build_scanner_params(std::map<std::string, std::string>* params) const override; | ||
| Status build_jni_columns( | ||
| std::vector<format::JniTableReader::JniColumn>* columns) const override; | ||
| Status finalize_jni_block(Block* jni_block, Block* output_block, size_t* rows) override; | ||
| }; | ||
|
|
||
| } // namespace doris::format::fluss |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[P2] Please handle the legacy-scanner selection explicitly. All Fluss reader dispatch added by this PR exists only in
FileScannerV2, butFileScanLocalState::_should_use_file_scanner_v2still honorsenable_file_scanner_v2=false; in that supported session configuration the scan falls intoFileScanner, whoseFORMAT_JNIdispatch has nofluss/fluss_unionbranch and returnsNot supported create reader for table format. Either force V2 for Fluss ranges (if the variable is only a preference for scans supported by both implementations), or fail during planning with a clear requirement; add a test with the variable disabled so this does not remain a late BE runtime surprise.