Skip to content

Commit 3d196fb

Browse files
FokkoOussamaSaoudinicklandengsh12rtyler
authored
Pull in latest main (delta-io#44)
* feat: Add CheckpointManifestReader to process sidecar files (delta-io#1500) ## 🥞 Stacked PR Use this [link](https://github.com/delta-io/delta-kernel-rs/pull/1500/files) to review incremental changes. - [**stack/dlr_manifest**](delta-io#1500) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1500/files)] - [stack/dlr_driver](delta-io#1502) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1502/files/2f0a14caf7cd1070625525868e18da9c300b8a0f..4285e9c8ae504fe697b83f4719c0e0995e0e3bd1)] - [stack/dlr_serialization_helpers](delta-io#1543) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1543/files/4285e9c8ae504fe697b83f4719c0e0995e0e3bd1..60f13ec6ee1f7cc2b57006a09d4b0e82b59733b9)] - [stack/dlr_serde](delta-io#1503) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1503/files/60f13ec6ee1f7cc2b57006a09d4b0e82b59733b9..377ae3f2596116d00cba596268090d2f69118b2e)] - [stack/dlr_add_rm_dedup](delta-io#1537) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1537/files/377ae3f2596116d00cba596268090d2f69118b2e..06fdf84431d7ee9cf693149784b11e4afb242de1)] - [stack/dlr_immutable_add_rm_dedup](delta-io#1538) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1538/files/06fdf84431d7ee9cf693149784b11e4afb242de1..991cdd69f18eb680dbafae3c213093b036cb7a85)] - [stack/dlr_leaf](delta-io#1501) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1501/files/991cdd69f18eb680dbafae3c213093b036cb7a85..1f52bbc6512d7cb0a5e2a68954eb434be7313ef0)] - [stack/dlr_executor](delta-io#1539) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1539/files/1f52bbc6512d7cb0a5e2a68954eb434be7313ef0..9a4f638d613121fe5819e3fef6c03b3e5102ab73)] - [stack/dlr_api](delta-io#1547) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1547/files/9a4f638d613121fe5819e3fef6c03b3e5102ab73..f385656ab1aa1f34caf77fa8518834d0ac0b998c)] - [stack/dlr_scan_state_serde](delta-io#1549) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1549/files/f385656ab1aa1f34caf77fa8518834d0ac0b998c..ac99eeec1f5d19fe76e8589f87cf53a7aa140e54)] --------- This PR adds a CheckpointManifestReader that is responsible for reading both manifest checkpoints and single-part checkpoints. For manifest checkpoints, it collects all the sidecar files that are present and returns them for further processing. * feat: Distributed Log Replay Sequential Phase (delta-io#1502) ## 🥞 Stacked PR Use this [link](https://github.com/delta-io/delta-kernel-rs/pull/1502/files) to review incremental changes. - [**stack/dlr_driver**](delta-io#1502) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1502/files)] - [stack/dlr_serialization_helpers](delta-io#1543) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1543/files/8f86b459613c0f018dd0e45473ba3e6e50d127af..0286f1d09006b099e73333c3d2d6a0873ede6cdd)] - [stack/dlr_serde](delta-io#1503) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1503/files/0286f1d09006b099e73333c3d2d6a0873ede6cdd..ee68c851e338a83584b004d919c40eca301e2ee3)] - [stack/dlr_add_rm_dedup](delta-io#1537) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1537/files/ee68c851e338a83584b004d919c40eca301e2ee3..436ce448e2dbf08ceb8f13350cb609ae3f554a7c)] - [stack/dlr_immutable_add_rm_dedup](delta-io#1538) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1538/files/436ce448e2dbf08ceb8f13350cb609ae3f554a7c..b2c2703bef78ef814c0579e82857cd67a2d1364b)] - [stack/dlr_leaf](delta-io#1501) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1501/files/b2c2703bef78ef814c0579e82857cd67a2d1364b..5f04e2059209c09a3ac8f5981d018347829bd8ab)] - [stack/dlr_executor](delta-io#1539) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1539/files/5f04e2059209c09a3ac8f5981d018347829bd8ab..7e2d26a6b063927e8b9a9fa62043ad30c705cc43)] - [stack/dlr_api](delta-io#1547) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1547/files/7e2d26a6b063927e8b9a9fa62043ad30c705cc43..b608475ed1402d8640b89e5948d066e0867585b3)] - [stack/dlr_scan_state_serde](delta-io#1549) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1549/files/b608475ed1402d8640b89e5948d066e0867585b3..c35994fbf457ed95556acc7688456feb81923abf)] --------- ## What changes are proposed in this pull request? This pull request introduces the SequentialPhase for distributed log replay. This phase reads the commit and checkpoint files for a logsegment and performs the log replay processor over the batches. Upon completion, the `finish` method produces `AfterSequential` which has two variants: * `Done`: Indicates that the metadata phase is complete and there is no more work to do. * `Distributed`: Indicates that a distributed phase is required (see the pr at stack/dlr_executor) ## How was this change tested? Ensure that the sequential phase extracts the expected actions for: * commits * single-part checkpoints Ensure that sequential phase produces `AfterSequential::Distributed` in the presence of: * sidecar files in a manifest checkpoint * multi-part checkpoints * feat/bugfix: Passing schema from C, plus example/tests in C (delta-io#1535) ## What changes are proposed in this pull request? * Don't use a macro to generate primitive visitors. `cbindgen` runs before macro expansion, so previously none of those visitors were actually being generated * Add code to `read_table` to allow specifying which columns to select, plus all the associated code to pass that back to kernel * Add c based tests to make sure it's working ## How was this change tested? New tests when running `make test` in `read_table` --------- Co-authored-by: OussamaSaoudi <45303303+OussamaSaoudi@users.noreply.github.com> * feat!: expose mod time in scan metadata callbacks (delta-io#1565) * feat: Support sidecar in inspect-table (delta-io#1566) <!-- Thanks for sending a pull request! Here are some tips for you: 1. If this is your first time, please read our contributor guidelines: https://github.com/delta-incubator/delta-kernel-rs/blob/main/CONTRIBUTING.md 2. Run `cargo t --all-features --all-targets` to get started testing, and run `cargo fmt`. 3. Ensure you have added or run the appropriate tests for your PR. 4. If the PR is unfinished, add '[WIP]' in your PR title, e.g., '[WIP] Your PR title ...'. 5. Be sure to keep the PR description updated to reflect all changes. --> <!-- PR title formatting: This project uses conventional commits: https://www.conventionalcommits.org/ Each PR corresponds to a commit on the `main` branch, with the title of the PR (typically) being used for the commit message on main. In order to ensure proper formatting in the CHANGELOG please ensure your PR title adheres to the conventional commit specification. Examples: - new feature PR: "feat: new API for snapshot.update()" - bugfix PR: "fix: correctly apply DV in read-table example" --> ## What changes are proposed in this pull request? <!-- Please clarify what changes you are proposing and why the changes are needed. The purpose of this section is to outline the changes, why they are needed, and how this PR fixes the issue. If the reason for the change is already explained clearly in an issue, then it does not need to be restated here. 1. If you propose a new API or feature, clarify the use case for a new API or feature. 2. If you fix a bug, you can clarify why it is a bug. --> Support sidecar in inspect-table. Solves the issue delta-io#695. <!-- Uncomment this section if there are any changes affecting public APIs: ### This PR affects the following public APIs If there are breaking changes, please ensure the `breaking-changes` label gets added by CI, and describe why the changes are needed. Note that _new_ public APIs are not considered breaking. --> ## How was this change tested? <!-- Please make sure to add test cases that check the changes thoroughly including negative and positive cases if possible. If it was tested in a way different from regular unit tests, please clarify how you tested, ideally via a reproducible test documented in the PR description. --> Test locally. Used `./kernel/tests/data/v2-checkpoints-parquet-with-sidecars.tar.zst`. The output successfully print sidecar actions: ``` cargo run -p inspect-table -- v2-checkpoints-parquet-with-sidecars actions | head -17 Action 1: Sidecar { path: "00000000000000000006.checkpoint.0000000001.0000000002.76931b15-ead3-480d-b86c-afe55a577fc3.parquet", size_in_bytes: 12461, modification_time: 1739329719752, tags: None, } Action 2: Sidecar { path: "00000000000000000006.checkpoint.0000000002.0000000002.4367b29c-0e87-447f-8e81-9814cc01ad1f.parquet", size_in_bytes: 12109, modification_time: 1739329719746, tags: None, } ``` * fix: force usage of ListedLogFiles::try_new() (delta-io#1562) <!-- Thanks for sending a pull request! Here are some tips for you: 1. If this is your first time, please read our contributor guidelines: https://github.com/delta-incubator/delta-kernel-rs/blob/main/CONTRIBUTING.md 2. Run `cargo t --all-features --all-targets` to get started testing, and run `cargo fmt`. 3. Ensure you have added or run the appropriate tests for your PR. 4. If the PR is unfinished, add '[WIP]' in your PR title, e.g., '[WIP] Your PR title ...'. 5. Be sure to keep the PR description updated to reflect all changes. --> <!-- PR title formatting: This project uses conventional commits: https://www.conventionalcommits.org/ Each PR corresponds to a commit on the `main` branch, with the title of the PR (typically) being used for the commit message on main. In order to ensure proper formatting in the CHANGELOG please ensure your PR title adheres to the conventional commit specification. Examples: - new feature PR: "feat: new API for snapshot.update()" - bugfix PR: "fix: correctly apply DV in read-table example" --> ## What changes are proposed in this pull request? <!-- Please clarify what changes you are proposing and why the changes are needed. The purpose of this section is to outline the changes, why they are needed, and how this PR fixes the issue. If the reason for the change is already explained clearly in an issue, then it does not need to be restated here. 1. If you propose a new API or feature, clarify the use case for a new API or feature. 2. If you fix a bug, you can clarify why it is a bug. --> Change field of `ListedLogFiles` to private to force the usage of `ListedLogFiles::try_new()` Solves the issue delta-io#1143 <!-- Uncomment this section if there are any changes affecting public APIs: ### This PR affects the following public APIs If there are breaking changes, please ensure the `breaking-changes` label gets added by CI, and describe why the changes are needed. Note that _new_ public APIs are not considered breaking. --> ## How was this change tested? Existing tests <!-- Please make sure to add test cases that check the changes thoroughly including negative and positive cases if possible. If it was tested in a way different from regular unit tests, please clarify how you tested, ideally via a reproducible test documented in the PR description. --> * fix: improve parse_json performance by removing line-by-line parsing (delta-io#1561) Co-authored-by: emkornfield <emkornfield@gmail.com> Co-authored-by: Nick Lanham <nick@databricks.com> * sync changelog from `0.18.2` (delta-io#1570) cherry-picks f105333 Co-authored-by: OussamaSaoudi <45303303+OussamaSaoudi@users.noreply.github.com> Co-authored-by: Drake Lin <drakelin18@gmail.com> * feature: short-circuit coalesce evaluation when array has no nulls (delta-io#1568) ## What changes are proposed in this pull request? <!-- Please clarify what changes you are proposing and why the changes are needed. The purpose of this section is to outline the changes, why they are needed, and how this PR fixes the issue. If the reason for the change is already explained clearly in an issue, then it does not need to be restated here. 1. If you propose a new API or feature, clarify the use case for a new API or feature. 2. If you fix a bug, you can clarify why it is a bug. --> Optimizes the coalesce expression evaluation in the default Arrow engine to short-circuit when an evaluated array has no null values. Previously, all expressions were eagerly evaluated before coalescing. - After evaluating each expression, check if `null_count() == 0` - If no nulls exist, validate the result type and return immediately without evaluating remaining expressions - `null_count()` on Arrow arrays is O(1) (cached value), so the check is essentially free. This optimization avoids evaluating potentially expensive expressions when earlier expressions already provide complete (non-null) results. Usecase: - For ParsedStats, we will see coalesces in both read/write - In read: we want to coalesce(parsed_stats, ParseJson(json_stats)) - In write: - ParsedStats: coalesce(parsed_stats, ParseJson(json_stats)) - JsonStats: coalesce(json_stats, ToJson(ParsedStats)) In each of these cases, all of one column will either be Null or non-Null so this optimization actually completely removes the need to evaluate the expensive parseJson/ToJson if unnecessary. Future improvements: - Track each row such that it short-circuits as soon as all rows are filled, even if no single array was 100% non-null - This can be implemented with FilteredEngineData, but that lacks support across the engine <!-- Uncomment this section if there are any changes affecting public APIs: ### This PR affects the following public APIs If there are breaking changes, please ensure the `breaking-changes` label gets added by CI, and describe why the changes are needed. Note that _new_ public APIs are not considered breaking. --> ## How was this change tested? <!-- Please make sure to add test cases that check the changes thoroughly including negative and positive cases if possible. If it was tested in a way different from regular unit tests, please clarify how you tested, ideally via a reproducible test documented in the PR description. --> new and existing unit tests * release 0.19.0 (delta-io#1571) release 0.19.0: [link to rendered changelog](https://github.com/zachschuermann/delta-kernel-rs/blob/a23efae27cf8bd7859a24ad66f57dcb0f6fac851/CHANGELOG.md) * [Test Only] Minor refactor to log_segment tests (delta-io#1581) ## 🥞 Stacked PR Use this [link](https://github.com/delta-io/delta-kernel-rs/pull/1581/files) to review incremental changes. - [**stack/log_segment_tests_refactor**](delta-io#1581) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1581/files)] --------- This PR refactors the `create_segment_for` test helper method inside of `log_segment/tests.rs`. Instead of taking in N params, we take in a struct (that contains those N params). This will make adding new params in the future easier and cleaner (e.g. staged catalog commits) * Refactor `ListedLogFiles::try_new` to be more extensible and with default values by using builder pattern (delta-io#1585) ## 🥞 Stacked PR Use this [link](https://github.com/delta-io/delta-kernel-rs/pull/1585/files) to review incremental changes. - [**stack/listed_log_files_refactor**](delta-io#1585) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1585/files)] --------- This PR refactors `ListedLogFiles::try_new` to instead be `ListedLogFilesBuilder::build()`. This allows using default values in the `ListedLogFilesBuilder`, which will make creating `ListedLogFiles` easier in the future (e.g. when we add `max_known_published_commit_version`). * Fix: add type validation for `evaluate_expression` (delta-io#1575) <!-- Thanks for sending a pull request! Here are some tips for you: 1. If this is your first time, please read our contributor guidelines: https://github.com/delta-incubator/delta-kernel-rs/blob/main/CONTRIBUTING.md 2. Run `cargo t --all-features --all-targets` to get started testing, and run `cargo fmt`. 3. Ensure you have added or run the appropriate tests for your PR. 4. If the PR is unfinished, add '[WIP]' in your PR title, e.g., '[WIP] Your PR title ...'. 5. Be sure to keep the PR description updated to reflect all changes. --> <!-- PR title formatting: This project uses conventional commits: https://www.conventionalcommits.org/ Each PR corresponds to a commit on the `main` branch, with the title of the PR (typically) being used for the commit message on main. In order to ensure proper formatting in the CHANGELOG please ensure your PR title adheres to the conventional commit specification. Examples: - new feature PR: "feat: new API for snapshot.update()" - bugfix PR: "fix: correctly apply DV in read-table example" --> ## What changes are proposed in this pull request? <!-- Please clarify what changes you are proposing and why the changes are needed. The purpose of this section is to outline the changes, why they are needed, and how this PR fixes the issue. If the reason for the change is already explained clearly in an issue, then it does not need to be restated here. 1. If you propose a new API or feature, clarify the use case for a new API or feature. 2. If you fix a bug, you can clarify why it is a bug. --> Add missing `result_type` validation in `evaluate_expression` for `Literal`, `Column`, and `Binary` branches. This resolves delta-io#1572 <!-- Uncomment this section if there are any changes affecting public APIs: ### This PR affects the following public APIs If there are breaking changes, please ensure the `breaking-changes` label gets added by CI, and describe why the changes are needed. Note that _new_ public APIs are not considered breaking. --> ## How was this change tested? <!-- Please make sure to add test cases that check the changes thoroughly including negative and positive cases if possible. If it was tested in a way different from regular unit tests, please clarify how you tested, ideally via a reproducible test documented in the PR description. --> new and existing unit tests * refactor: move doctest into mods (delta-io#1574) <!-- Thanks for sending a pull request! Here are some tips for you: 1. If this is your first time, please read our contributor guidelines: https://github.com/delta-incubator/delta-kernel-rs/blob/main/CONTRIBUTING.md 2. Run `cargo t --all-features --all-targets` to get started testing, and run `cargo fmt`. 3. Ensure you have added or run the appropriate tests for your PR. 4. If the PR is unfinished, add '[WIP]' in your PR title, e.g., '[WIP] Your PR title ...'. 5. Be sure to keep the PR description updated to reflect all changes. --> <!-- PR title formatting: This project uses conventional commits: https://www.conventionalcommits.org/ Each PR corresponds to a commit on the `main` branch, with the title of the PR (typically) being used for the commit message on main. In order to ensure proper formatting in the CHANGELOG please ensure your PR title adheres to the conventional commit specification. Examples: - new feature PR: "feat: new API for snapshot.update()" - bugfix PR: "fix: correctly apply DV in read-table example" --> ## What changes are proposed in this pull request? <!-- Please clarify what changes you are proposing and why the changes are needed. The purpose of this section is to outline the changes, why they are needed, and how this PR fixes the issue. If the reason for the change is already explained clearly in an issue, then it does not need to be restated here. 1. If you propose a new API or feature, clarify the use case for a new API or feature. 2. If you fix a bug, you can clarify why it is a bug. --> Currently all doctests live inline in `kernel/src/lib.rs`. This PR moves them to `kernel/src/doctests/` with separate files per macro, making it easier to add new macro tests without enlarging `lib.rs`. Related: delta-io#991 <!-- Uncomment this section if there are any changes affecting public APIs: ### This PR affects the following public APIs If there are breaking changes, please ensure the `breaking-changes` label gets added by CI, and describe why the changes are needed. Note that _new_ public APIs are not considered breaking. --> ## How was this change tested? <!-- Please make sure to add test cases that check the changes thoroughly including negative and positive cases if possible. If it was tested in a way different from regular unit tests, please clarify how you tested, ideally via a reproducible test documented in the PR description. --> Ran existing tests * feat: add checkpoint schema discovery for stats_parsed detection (delta-io#1550) ## What changes are proposed in this pull request? <!-- Please clarify what changes you are proposing and why the changes are needed. The purpose of this section is to outline the changes, why they are needed, and how this PR fixes the issue. If the reason for the change is already explained clearly in an issue, then it does not need to be restated here. 1. If you propose a new API or feature, clarify the use case for a new API or feature. 2. If you fix a bug, you can clarify why it is a bug. --> This PR adds infrastructure for discovering checkpoint schemas and detecting whether `stats_parsed` is available for data skipping optimization. 1. Store checkpoint schema in LogSegment (`log_segment.rs`) 2. Add stats_parsed detection (`log_segment.rs`) - During log replay / sidecar visiting, we figure out the schema for the file action files (whether the sidecar parquet files for V2 checkpoints or the V1 checkpoint parquet. ## How was this change tested? <!-- Please make sure to add test cases that check the changes thoroughly including negative and positive cases if possible. If it was tested in a way different from regular unit tests, please clarify how you tested, ideally via a reproducible test documented in the PR description. --> - Existing log segment tests updated * refactor: deny panics in ffi crate (delta-io#1576) <!-- Thanks for sending a pull request! Here are some tips for you: 1. If this is your first time, please read our contributor guidelines: https://github.com/delta-incubator/delta-kernel-rs/blob/main/CONTRIBUTING.md 2. Run `cargo t --all-features --all-targets` to get started testing, and run `cargo fmt`. 3. Ensure you have added or run the appropriate tests for your PR. 4. If the PR is unfinished, add '[WIP]' in your PR title, e.g., '[WIP] Your PR title ...'. 5. Be sure to keep the PR description updated to reflect all changes. --> <!-- PR title formatting: This project uses conventional commits: https://www.conventionalcommits.org/ Each PR corresponds to a commit on the `main` branch, with the title of the PR (typically) being used for the commit message on main. In order to ensure proper formatting in the CHANGELOG please ensure your PR title adheres to the conventional commit specification. Examples: - new feature PR: "feat: new API for snapshot.update()" - bugfix PR: "fix: correctly apply DV in read-table example" --> ## What changes are proposed in this pull request? <!-- Please clarify what changes you are proposing and why the changes are needed. The purpose of this section is to outline the changes, why they are needed, and how this PR fixes the issue. If the reason for the change is already explained clearly in an issue, then it does not need to be restated here. 1. If you propose a new API or feature, clarify the use case for a new API or feature. 2. If you fix a bug, you can clarify why it is a bug. --> 1. Add clippy lints to deny panics in the FFI crate (non-test code) 2. Fix violations by returning errors instead of panicking 3. Allow `expect` in theoretically unreachable paths <!-- Uncomment this section if there are any changes affecting public APIs: ### This PR affects the following public APIs If there are breaking changes, please ensure the `breaking-changes` label gets added by CI, and describe why the changes are needed. Note that _new_ public APIs are not considered breaking. --> ## How was this change tested? <!-- Please make sure to add test cases that check the changes thoroughly including negative and positive cases if possible. If it was tested in a way different from regular unit tests, please clarify how you tested, ideally via a reproducible test documented in the PR description. --> Existing tests in `ffi/examples/read-table` * Remove comments and text from `pull_request_template.md` (delta-io#1589) ## What changes are proposed in this pull request? Move text from `pull_request_template.md` to `CONTRIBUTING.md`. Make PR template file name all-caps. ## How was this change tested? N/A. * feat!: add deletion vector APIs to transaction (delta-io#1430) Adds the ability to update deletion vectors on delta tables. Co-authored-by: Drake Lin <drakelin18@gmail.com> Co-authored-by: Nick Lanham <nicklan@users.noreply.github.com> * feat: Add doctests for `IntoEngineData` derive macro (delta-io#1580) <!-- PR title formatting: This project uses conventional commits: https://www.conventionalcommits.org/ Each PR corresponds to a commit on the `main` branch, with the title of the PR (typically) being used for the commit message on main. In order to ensure proper formatting in the CHANGELOG please ensure your PR title adheres to the conventional commit specification. Examples: - new feature PR: "feat: new API for snapshot.update()" - bugfix PR: "fix: correctly apply DV in read-table example" --> ## What changes are proposed in this pull request? <!-- Please clarify what changes you are proposing and why the changes are needed. The purpose of this section is to outline the changes, why they are needed, and how this PR fixes the issue. If the reason for the change is already explained clearly in an issue, then it does not need to be restated here. 1. If you propose a new API or feature, clarify the use case for a new API or feature. 2. If you fix a bug, you can clarify why it is a bug. --> This PR: - Changes the `IntoEngineData` macro to use `delta_kernel::` paths - Adds doctests for the derive macro Related: delta-io#991 <!-- Uncomment this section if there are any changes affecting public APIs: ### This PR affects the following public APIs If there are breaking changes, please ensure the `breaking-changes` label gets added by CI, and describe why the changes are needed. Note that _new_ public APIs are not considered breaking. --> ## How was this change tested? <!-- Please make sure to add test cases that check the changes thoroughly including negative and positive cases if possible. If it was tested in a way different from regular unit tests, please clarify how you tested, ideally via a reproducible test documented in the PR description. --> Added tests. * feat: Create `DefaultEngineBuilder` to build `DefaultEngine` (delta-io#1582) ## 🥞 Stacked PR Use this [link](https://github.com/delta-io/delta-kernel-rs/pull/1582/files) to review incremental changes. - [**stack/engine-builder**](delta-io#1582) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1582/files)] - [stack/remove-constructor](delta-io#1583) [[Files changed](https://github.com/delta-io/delta-kernel-rs/pull/1583/files/29e082a58b9382149285f30351d53468d6ed49dc..0026634ac5bf5f546d45a4d25dd0f46cb8d39d1b)] --------- ## What changes are proposed in this pull request? <!-- Please clarify what changes you are proposing and why the changes are needed. The purpose of this section is to outline the changes, why they are needed, and how this PR fixes the issue. If the reason for the change is already explained clearly in an issue, then it does not need to be restated here. 1. If you propose a new API or feature, clarify the use case for a new API or feature. 2. If you fix a bug, you can clarify why it is a bug. --> Add `DefaultEngineBuilder` for more flexible engine construction and align with the builder pattern used elsewhere in this repo. ## Detail changes - Add generic `DefaultEngineBuilder<E>` with builder pattern - Support `with_task_executor()` to use custom executors - Support `with_metrics_reporter()` for metrics collection - Add `DefaultEngine::builder()` convenience method <!-- Uncomment this section if there are any changes affecting public APIs: ### This PR affects the following public APIs If there are breaking changes, please ensure the `breaking-changes` label gets added by CI, and describe why the changes are needed. Note that _new_ public APIs are not considered breaking. --> ## How was this change tested? <!-- Please make sure to add test cases that check the changes thoroughly including negative and positive cases if possible. If it was tested in a way different from regular unit tests, please clarify how you tested, ideally via a reproducible test documented in the PR description. --> Added tests. * refactor: extract shared HTTP utilities to http.rs (delta-io#1590) ## What changes are proposed in this pull request? Extract `build_http_client`, `execute_with_retry`, and `handle_response` from `UCClient` into a shared `http.rs` module. This enables reuse by other client implementations (and is used in the child stacked PR delta-io#1590) ## How was this change tested? `cargo build -p uc-client -p uc-catalog` * Fix conflicts * Fix dangling conflicts * Fix the tests --------- Co-authored-by: OussamaSaoudi <45303303+OussamaSaoudi@users.noreply.github.com> Co-authored-by: Nick Lanham <nicklan@users.noreply.github.com> Co-authored-by: dengsh12 <62536982+dengsh12@users.noreply.github.com> Co-authored-by: R. Tyler Croy <rtyler@brokenco.de> Co-authored-by: emkornfield <emkornfield@gmail.com> Co-authored-by: Nick Lanham <nick@databricks.com> Co-authored-by: Zach Schuermann <zachary.zvs@gmail.com> Co-authored-by: Drake Lin <drakelin18@gmail.com> Co-authored-by: Scott Sandre <scott.sandre@databricks.com>
1 parent 54e1286 commit 3d196fb

36 files changed

Lines changed: 2903 additions & 652 deletions

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
## What changes are proposed in this pull request?
2+
3+
<!--
4+
**Uncomment** this section if there are any changes affecting public APIs. Else, **delete** this section.
5+
6+
### This PR affects the following public APIs
7+
8+
If there are breaking changes, please ensure the `breaking-changes` label gets added by CI, and describe why the changes are needed.
9+
10+
Note that _new_ public APIs are not considered breaking.
11+
-->
12+
13+
## How was this change tested?

.github/pull_request_template.md

Lines changed: 0 additions & 46 deletions
This file was deleted.

CONTRIBUTING.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,34 @@ Our trunk branch is named `main`. Here's the typical workflow:
8484

8585
**Note**: We require two approvals from code owners for any PR to be merged.
8686

87+
## Pull Request Best Practices
88+
89+
#### General Tips
90+
91+
1. When making your first PR, please read our contributor guidelines: https://github.com/delta-incubator/delta-kernel-rs/blob/main/CONTRIBUTING.md
92+
2. Run `cargo t --all-features --all-targets` to get started testing, and run `cargo fmt`.
93+
3. Ensure you have added or run the appropriate tests for your PR.
94+
4. If the PR is unfinished, add '[WIP]' in your PR title, e.g., '[WIP] Your PR title ...'.
95+
5. Be sure to keep the PR description updated to reflect all changes.
96+
97+
#### PR Title Formatting
98+
99+
This project uses conventional commits: https://www.conventionalcommits.org/
100+
101+
Each PR corresponds to a commit on the `main` branch, with the title of the PR (typically) being
102+
used for the commit message on main. In order to ensure proper formatting in the CHANGELOG please
103+
ensure your PR title adheres to the conventional commit specification.
104+
105+
Examples:
106+
- new feature PR: "feat: new API for snapshot.update()"
107+
- bugfix PR: "fix: correctly apply DV in read-table example"
108+
109+
#### PR Testing
110+
111+
Please make sure to add test cases that check the changes thoroughly including negative and positive cases if possible.
112+
If it was tested in a way different from regular unit tests, please clarify how you tested, ideally via a reproducible test documented in the PR description.
113+
87114
## Resources
88115

89116
- [Delta Protocol](https://github.com/delta-io/delta/blob/master/PROTOCOL.md)
90-
- [Delta Lake Slack](https://go.delta.io/slack) - Join us in the `#delta-kernel` channel
117+
- [Delta Lake Slack](https://go.delta.io/slack) - Join us in the `#delta-kernel` channel

derive-macros/src/lib.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -218,17 +218,17 @@ pub fn into_engine_data_derive(input: proc_macro::TokenStream) -> proc_macro::To
218218

219219
let expanded = quote! {
220220
#[automatically_derived]
221-
impl crate::IntoEngineData for #struct_name
221+
impl delta_kernel::IntoEngineData for #struct_name
222222
where
223-
#(#field_types: Into<crate::expressions::Scalar>),*
223+
#(#field_types: Into<delta_kernel::expressions::Scalar>),*
224224
{
225225
fn into_engine_data(
226226
self,
227-
schema: crate::schema::SchemaRef,
228-
engine: &dyn crate::Engine)
229-
-> crate::DeltaResult<Box<dyn crate::EngineData>> {
227+
schema: delta_kernel::schema::SchemaRef,
228+
engine: &dyn delta_kernel::Engine)
229+
-> delta_kernel::DeltaResult<Box<dyn delta_kernel::EngineData>> {
230230
// NB: we `use` here to avoid polluting the caller's namespace
231-
use crate::EvaluationHandlerExtension as _;
231+
use delta_kernel::EvaluationHandlerExtension as _;
232232
let values = [
233233
#(self.#field_idents.into()),*
234234
];

ffi/examples/common/kernel_utils.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,17 @@ void* allocate_string(const KernelStringSlice slice)
6161
}
6262

6363
// utility function to convert key/val into slices and set them on a builder
64-
void set_builder_opt(EngineBuilder* engine_builder, char* key, char* val)
64+
// returns false on failure
65+
bool set_builder_opt(EngineBuilder* engine_builder, char* key, char* val)
6566
{
6667
KernelStringSlice key_slice = { key, strlen(key) };
6768
KernelStringSlice val_slice = { val, strlen(val) };
68-
set_builder_option(engine_builder, key_slice, val_slice);
69+
ExternResultbool res = set_builder_option(engine_builder, key_slice, val_slice);
70+
if (res.tag != Okbool) {
71+
print_error("Failed to set builder option.", (Error*)res.err);
72+
free_error((Error*)res.err);
73+
return false;
74+
}
75+
return true;
6976
}
7077

ffi/examples/common/kernel_utils.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <stdbool.h>
34
#include <delta_kernel_ffi.h>
45

56
// This is how we represent our errors. The kernel will ask us to contruct this struct whenever it
@@ -21,4 +22,5 @@ void* allocate_string(const KernelStringSlice slice);
2122
// error
2223
EngineError* allocate_error(KernelError etype, const KernelStringSlice msg);
2324
// utility function to convert key/val into slices and set them on a builder
24-
void set_builder_opt(EngineBuilder* engine_builder, char* key, char* val);
25+
// returns false on failure
26+
bool set_builder_opt(EngineBuilder* engine_builder, char* key, char* val);

ffi/examples/read-table/read_table.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,13 @@ void print_partition_info(struct EngineContext* context, const CStringMap* parti
3131
for (uintptr_t i = 0; i < context->partition_cols->len; i++) {
3232
char* col = context->partition_cols->cols[i];
3333
KernelStringSlice key = { col, strlen(col) };
34-
char* partition_val = get_from_string_map(partition_values, key, allocate_string);
34+
ExternResultNullableCvoid res = get_from_string_map(partition_values, key, allocate_string, context->engine);
35+
if (res.tag != OkNullableCvoid) {
36+
print_error("Failed to get from string map.", (Error*)res.err);
37+
free_error((Error*)res.err);
38+
continue;
39+
}
40+
char* partition_val = res.ok;
3541
if (partition_val) {
3642
print_diag(" partition '%s' here: %s\n", col, partition_val);
3743
free(partition_val);
@@ -117,7 +123,11 @@ void do_visit_scan_metadata(void* engine_context, HandleSharedScanMetadata scan_
117123

118124
// Ask kernel to iterate each individual file and call us back with extracted metadata
119125
print_diag("Asking kernel to call us back for each scan row (file to read)\n");
120-
visit_scan_metadata(scan_metadata, engine_context, scan_row_callback);
126+
ExternResultbool visit_res = visit_scan_metadata(scan_metadata, context->engine, engine_context, scan_row_callback);
127+
if (visit_res.tag != Okbool) {
128+
print_error("Failed to visit scan metadata.", (Error*)visit_res.err);
129+
free_error((Error*)visit_res.err);
130+
}
121131
free_bool_slice(selection_vector);
122132
free_scan_metadata(scan_metadata);
123133
}
@@ -276,7 +286,9 @@ int main(int argc, char* argv[])
276286

277287
// an example of using a builder to set options when building an engine
278288
EngineBuilder* engine_builder = engine_builder_res.ok;
279-
set_builder_opt(engine_builder, "aws_region", "us-west-2");
289+
if (!set_builder_opt(engine_builder, "aws_region", "us-west-2")) {
290+
return -1;
291+
}
280292
// potentially set credentials here
281293
// set_builder_opt(engine_builder, "aws_access_key_id" , "[redacted]");
282294
// set_builder_opt(engine_builder, "aws_secret_access_key", "[redacted]");
@@ -306,7 +318,7 @@ int main(int argc, char* argv[])
306318
uint64_t v = version(snapshot);
307319
printf("version: %" PRIu64 "\n\n", v);
308320

309-
CSchema *cschema = get_cschema(snapshot);
321+
CSchema *cschema = get_cschema(snapshot, engine);
310322
print_cschema(cschema);
311323

312324
char* table_root = snapshot_table_root(snapshot, allocate_string);

ffi/examples/read-table/schema.h

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ typedef struct
4949
{
5050
int list_count;
5151
SchemaItemList* lists;
52+
SharedExternEngine* engine;
5253
} SchemaBuilder;
5354

5455
typedef struct
@@ -109,12 +110,18 @@ void print_list(SchemaBuilder* builder, uintptr_t list_id, int indent, int paren
109110
}
110111
}
111112

112-
void print_physical_name(const char *name, const CStringMap* metadata)
113+
void print_physical_name(const char *name, const CStringMap* metadata, SharedExternEngine* engine)
113114
{
114115
#ifdef VERBOSE
115116
char* key_str = "delta.columnMapping.physicalName";
116117
KernelStringSlice key = { key_str, strlen(key_str) };
117-
char* value = get_from_string_map(metadata, key, allocate_string);
118+
ExternResultNullableCvoid res = get_from_string_map(metadata, key, allocate_string, engine);
119+
if (res.tag != OkNullableCvoid) {
120+
printf("Failed to get physical name\n");
121+
free_error((Error*)res.err);
122+
return;
123+
}
124+
char* value = res.ok;
118125
if (value) {
119126
printf("Physical name of %s is %s\n", name, value);
120127
free(value);
@@ -124,6 +131,7 @@ void print_physical_name(const char *name, const CStringMap* metadata)
124131
#else
125132
(void)name;
126133
(void)metadata;
134+
(void)engine;
127135
#endif
128136
}
129137

@@ -157,7 +165,7 @@ void visit_struct(
157165
SchemaBuilder* builder = data;
158166
char* name_ptr = allocate_string(name);
159167
PRINT_CHILD_VISIT("struct", name_ptr, sibling_list_id, "Children", child_list_id);
160-
print_physical_name(name_ptr, metadata);
168+
print_physical_name(name_ptr, metadata, builder->engine);
161169
SchemaItem* struct_item = add_to_list(&builder->lists[sibling_list_id], name_ptr, "struct", is_nullable);
162170
struct_item->children = child_list_id;
163171
}
@@ -172,7 +180,7 @@ void visit_array(
172180
{
173181
SchemaBuilder* builder = data;
174182
char* name_ptr = allocate_string(name);
175-
print_physical_name(name_ptr, metadata);
183+
print_physical_name(name_ptr, metadata, builder->engine);
176184
PRINT_CHILD_VISIT("array", name_ptr, sibling_list_id, "Types", child_list_id);
177185
SchemaItem* array_item = add_to_list(&builder->lists[sibling_list_id], name_ptr, "array", is_nullable);
178186
array_item->children = child_list_id;
@@ -188,7 +196,7 @@ void visit_map(
188196
{
189197
SchemaBuilder* builder = data;
190198
char* name_ptr = allocate_string(name);
191-
print_physical_name(name_ptr, metadata);
199+
print_physical_name(name_ptr, metadata, builder->engine);
192200
PRINT_CHILD_VISIT("map", name_ptr, sibling_list_id, "Types", child_list_id);
193201
SchemaItem* map_item = add_to_list(&builder->lists[sibling_list_id], name_ptr, "map", is_nullable);
194202
map_item->children = child_list_id;
@@ -207,7 +215,7 @@ void visit_decimal(
207215
char* name_ptr = allocate_string(name);
208216
char* type = malloc(19 * sizeof(char));
209217
snprintf(type, 19, "decimal(%u)(%d)", precision, scale);
210-
print_physical_name(name_ptr, metadata);
218+
print_physical_name(name_ptr, metadata, builder->engine);
211219
PRINT_NO_CHILD_VISIT(type, name_ptr, sibling_list_id);
212220
add_to_list(&builder->lists[sibling_list_id], name_ptr, type, is_nullable);
213221
}
@@ -222,7 +230,7 @@ void visit_simple_type(
222230
{
223231
SchemaBuilder* builder = data;
224232
char* name_ptr = allocate_string(name);
225-
print_physical_name(name_ptr, metadata);
233+
print_physical_name(name_ptr, metadata, builder->engine);
226234
PRINT_NO_CHILD_VISIT(type, name_ptr, sibling_list_id);
227235
add_to_list(&builder->lists[sibling_list_id], name_ptr, type, is_nullable);
228236
}
@@ -273,12 +281,13 @@ void free_cschema(CSchema *schema) {
273281
}
274282

275283
// Get the schema of the snapshot
276-
CSchema* get_cschema(SharedSnapshot* snapshot)
284+
CSchema* get_cschema(SharedSnapshot* snapshot, SharedExternEngine* engine)
277285
{
278286
print_diag("Building schema\n");
279287
SchemaBuilder* builder = malloc(sizeof(SchemaBuilder));
280288
builder->list_count = 0;
281289
builder->lists = NULL;
290+
builder->engine = engine;
282291
EngineSchemaVisitor visitor = {
283292
.data = builder,
284293
.make_field_list = make_field_list,

ffi/src/lib.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
//!
33
//! Exposes that an engine needs to call from C/C++ to interface with kernel
44
5+
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
6+
// we re-allow panics in tests
7+
#![cfg_attr(test, allow(clippy::unwrap_used, clippy::expect_used, clippy::panic))]
8+
59
#[cfg(feature = "default-engine-base")]
610
use std::collections::HashMap;
711
use std::default::Default;
@@ -274,8 +278,10 @@ mod private {
274278
let len = val.len();
275279
let boxed = val.into_boxed_slice();
276280
let leaked_ptr = Box::leak(boxed).as_mut_ptr();
281+
// safety: Box::leak always returns a valid, non-null pointer
282+
#[allow(clippy::expect_used)]
277283
let ptr = NonNull::new(leaked_ptr)
278-
.expect("This should never be non-null please report this bug.");
284+
.expect("This should never be null please report this bug.");
279285
KernelBoolSlice { ptr, len }
280286
}
281287
}
@@ -328,8 +334,10 @@ mod private {
328334
let len = vec.len();
329335
let boxed = vec.into_boxed_slice();
330336
let leaked_ptr = Box::leak(boxed).as_mut_ptr();
337+
// safety: Box::leak always returns a valid, non-null pointer
338+
#[allow(clippy::expect_used)]
331339
let ptr = NonNull::new(leaked_ptr)
332-
.expect("This should never be non-null please report this bug.");
340+
.expect("This should never be null please report this bug.");
333341
KernelRowIndexArray { ptr, len }
334342
}
335343
}
@@ -489,11 +497,19 @@ pub unsafe extern "C" fn set_builder_option(
489497
builder: &mut EngineBuilder,
490498
key: KernelStringSlice,
491499
value: KernelStringSlice,
492-
) {
493-
let key = unsafe { String::try_from_slice(&key) };
494-
let value = unsafe { String::try_from_slice(&value) };
495-
// TODO: Return ExternalError if key or value is invalid? (builder has an error allocator)
496-
builder.set_option(key.unwrap(), value.unwrap());
500+
) -> ExternResult<bool> {
501+
set_builder_option_impl(builder, key, value).into_extern_result(&builder.allocate_fn)
502+
}
503+
#[cfg(feature = "default-engine-base")]
504+
fn set_builder_option_impl(
505+
builder: &mut EngineBuilder,
506+
key: KernelStringSlice,
507+
value: KernelStringSlice,
508+
) -> DeltaResult<bool> {
509+
let key = unsafe { String::try_from_slice(&key) }?;
510+
let value = unsafe { String::try_from_slice(&value) }?;
511+
builder.set_option(key, value);
512+
Ok(true)
497513
}
498514

499515
/// Consume the builder and return a `default` engine. After calling, the passed pointer is _no

0 commit comments

Comments
 (0)