Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7bac92e
Added graal vm plugin to pom.xml and classes to reflection-config.json
subkanthi Jul 7, 2025
27d6cfa
Fixed steps to build ice native image
subkanthi Nov 20, 2025
b1bef04
include amd64 in supported architecture
subkanthi Nov 20, 2025
a2f6743
Added runtime depedencies for native image.
subkanthi Nov 20, 2025
fc1d23a
Added runtime depedencies for native image.
subkanthi Nov 20, 2025
371c0f8
Fixed reflection-config.json
subkanthi Nov 21, 2025
ddbcf9f
remove verify binary step.
subkanthi Nov 21, 2025
303357d
Add support for ARM.
subkanthi Nov 21, 2025
12ef6b0
Added Dockerfile.
subkanthi Nov 22, 2025
d0b8aaf
Remove autogenerated files.
subkanthi Nov 23, 2025
48e0a04
Removed accidentally committed files.
subkanthi Nov 23, 2025
3b3ddbb
Added GITHUB_RELEASE_TEMPLATE.md
subkanthi Nov 23, 2025
3bbcf76
Updated README.md with instructions to build native image.
subkanthi Nov 23, 2025
50ac8e3
Merge x86 and arm native builds into the same profile
xieandrew Apr 27, 2026
96405ee
Fix verify workflow
xieandrew Apr 27, 2026
ed93d90
Try fix workflow
xieandrew Apr 30, 2026
c6662c6
Merge remote-tracking branch 'origin/master' into 29-ice-make-a-downl…
xieandrew Apr 30, 2026
4dd6346
Update reflect-config.json
xieandrew Apr 30, 2026
b98ee64
Add aarch64 paths to resource-config.json
xieandrew Apr 30, 2026
1348f73
Add describe-parquet test
xieandrew May 7, 2026
7a074e4
Merge remote-tracking branch 'origin/master' into 29-ice-make-a-downl…
xieandrew May 8, 2026
321c38a
Add more cases to schema-evolution scenario
xieandrew May 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .bin/agent-ice
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
PROJECT_ROOT=$(cd -- "$SCRIPT_DIR/.." && pwd)

shopt -s nullglob
jars=("$PROJECT_ROOT"/ice/target/ice-*-shaded.jar)
shopt -u nullglob
if (( ${#jars[@]} == 0 )); then
echo "agent-ice: no ice-*-shaded.jar in $PROJECT_ROOT/ice/target/." >&2
exit 1
fi
jar=$(ls -t "${jars[@]}" | head -n1)

exec "${JAVA_HOME:?JAVA_HOME not set — run inside direnv shell}/bin/java" \
-agentlib:native-image-agent=config-merge-dir=$PROJECT_ROOT/ice/src/main/resources/META-INF/native-image/com.altinity/ice,experimental-class-loader-support \
-jar "$jar" "$@"
31 changes: 30 additions & 1 deletion .github/workflows/verify.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ jobs:
- run: ./mvnw clean verify
- name: Install
run: ./mvnw install
# TODO: check native-image can build ice
- name: Run Scenario-Based Integration Tests
run: ../mvnw test -Dtest=ScenarioBasedIT
working-directory: ice-rest-catalog
Expand Down Expand Up @@ -58,3 +57,33 @@ jobs:
-Dit.test=DockerScenarioBasedIT,DockerLocalFileIOClickHouseIT
-Ddocker.image=altinity/ice-rest-catalog:debug-with-ice-latest-master-amd64
-Dclickhouse.image=altinity/clickhouse-server:25.8.16.20002.altinityantalya
native-build:
name: Build and test native image (${{ matrix.arch }})
runs-on: ${{ matrix.runner }}
strategy:
matrix:
include:
- arch: amd64
runner: ubuntu-24.04
artifact: ice-native-amd64-dynamic
- arch: arm64
runner: ubuntu-24.04-arm
artifact: ice-native-arm64-dynamic
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'graalvm'
cache: maven
- name: Build native image (dynamic linking - no musl required)
run: ./mvnw -Pnative clean install -Dmaven.test.skip=true
- name: Run Scenario-Based Integration Tests
run: ../mvnw test -Dtest=ScenarioBasedIT -Dice.native=true
working-directory: ice-rest-catalog
- name: Upload native binary as artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact }}
path: ice/target/ice
if-no-files-found: error
29 changes: 27 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,23 @@ Create/delete tables, insert data with `ice insert -p ns1.table1 file://example.

## Installation

Pre-built binaries\* (+ links to Docker images for [ice](https://hub.docker.com/r/altinity/ice) and [ice-rest-catalog](https://hub.docker.com/r/altinity/ice-rest-catalog)) are available from [GitHub Releases](https://github.com/Altinity/ice/releases) page.
> \* currently require `java` 21+ to run (available [here](https://adoptium.net/installation/)).
Pre-built binaries (+ links to Docker images for [ice](https://hub.docker.com/r/altinity/ice) and [ice-rest-catalog](https://hub.docker.com/r/altinity/ice-rest-catalog)) are available from [GitHub Releases](https://github.com/Altinity/ice/releases) page.

**Two types of binaries are available:**

1. **Java-based binaries** - Require Java 21+ to run (available [here](https://adoptium.net/installation/))
2. **Native binaries** - Standalone executables with no Java dependency
- `ice-native-amd64` - Dynamic binary for x86_64 Linux (requires glibc)
- `ice-native-arm64` - Dynamic binary for ARM64 Linux (requires glibc)

## Usage

See [examples/](examples/).

## Development

### Standard Build (Java-based)

Install [sdkman](https://sdkman.io/install), then

```shell
Expand All @@ -35,6 +43,23 @@ sdk env
./mvnw
```

### Native Image Build (Standalone)

Build standalone native binaries with no Java dependency:

```shell
# Install prerequisites
sdk env # or ensure Java 21+ and GraalVM are available

# Build ice binary (both amd64 and arm64)
mvn -Pnative -pl ice clean package -Dmaven.test.skip=true

# Docker builds
docker build -f ice/Dockerfile.native -t ice-native:amd64 .

docker build -f ice/Dockerfile.native -t ice-native:arm64 .
```

## License

Copyright (c) 2025, Altinity Inc and/or its affiliates. All rights reserved.
Expand Down
2 changes: 1 addition & 1 deletion examples/scratch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ ice insert nyc.taxis_p_by_day -p \

# delete partition
ice delete nyc.taxis_p_by_day \
--partition '[{"name": "tpep_pickup_datetime", "values": ["2024-12-31T23:51:20"]}]' --dry-run=false
--partition '[{"name": "tpep_pickup_datetime_day", "values": ["2024-12-31"]}]' --dry-run=false

# insert data ordered by tpep_pickup_datetime column
ice insert nyc.taxis_s_by_day -p \
Expand Down
4 changes: 4 additions & 0 deletions ice-rest-catalog/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<jetcd.version>0.8.5</jetcd.version>
<grpc.version>1.70.0</grpc.version>
<testcontainers.version>1.21.4</testcontainers.version>
<ice.native>false</ice.native>
</properties>

<dependencies>
Expand Down Expand Up @@ -562,6 +563,9 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<ice.native>${ice.native}</ice.native>
</systemPropertyVariables>
<excludes>
<exclude>**/DockerScenarioBasedIT.java</exclude>
<exclude>**/DockerLocalFileIOClickHouseIT.java</exclude>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
*/
public class ScenarioBasedIT extends RESTCatalogTestBase {

private static final boolean USE_NATIVE = Boolean.getBoolean("ice.native");

@Override
protected ScenarioTestRunner createScenarioRunner(String scenarioName) throws Exception {
Path scenariosDir = getScenariosDirectory();
Expand All @@ -42,18 +44,24 @@ protected ScenarioTestRunner createScenarioRunner(String scenarioName) throws Ex

// Try to find ice-jar in the build
String projectRoot = Paths.get("").toAbsolutePath().getParent().toString();
String iceJar = projectRoot + "/ice/target/ice-jar";
String iceJar =
USE_NATIVE ? projectRoot + "/ice/target/ice" : projectRoot + "/ice/target/ice-jar";
File iceJarFile = new File(iceJar);

if (iceJarFile.exists() && iceJarFile.canExecute()) {
// Use pre-built ice-jar if available
templateVars.put("ICE_CLI", iceJar);
logger.info("Using ice-jar from: {}", iceJar);
String override = System.getenv("ICE_CLI_OVERRIDE");
if (override != null) {
templateVars.put("ICE_CLI", override);
} else {
// Fall back to using local-ice wrapper script
String localIce = projectRoot + "/.bin/local-ice";
templateVars.put("ICE_CLI", localIce);
logger.info("Using local-ice script from: {}", localIce);
if (iceJarFile.exists() && iceJarFile.canExecute()) {
// Use pre-built ice-jar if available
templateVars.put("ICE_CLI", iceJar);
logger.info("Using ice-jar from: {}", iceJar);
} else {
// Fall back to using local-ice wrapper script
String localIce = projectRoot + "/.bin/local-ice";
templateVars.put("ICE_CLI", localIce);
logger.info("Using local-ice script from: {}", localIce);
}
}

return new ScenarioTestRunner(scenariosDir, templateVars);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ echo "OK list-namespaces listed ${NAMESPACE_NAME}"
{{ICE_CLI}} --config {{CLI_CONFIG}} describe
echo "OK Listed namespaces"

# Check configuration
{{ICE_CLI}} --config {{CLI_CONFIG}} check
echo "OK checked configuration"

# Insert from file (like README: ice insert flowers.iris -p file://...)
{{ICE_CLI}} --config {{CLI_CONFIG}} insert ${TABLE_IRIS} -p "file://${INPUT_PATH}"
echo "Inserted from file into ${TABLE_IRIS}"
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#!/bin/bash
set -e

echo "Running describe-parquet test..."

SCENARIO_DIR="{{SCENARIO_DIR}}"
INPUT_PATH="${SCENARIO_DIR}/${INPUT_FILE}"
TARGET="file://${INPUT_PATH}"

# Default invocation: YAML, summary only
DEFAULT_OUT=$({{ICE_CLI}} --config {{CLI_CONFIG}} describe-parquet "${TARGET}")
for expected in "summary:" "rows: ${EXPECTED_ROWS}" "rowGroups:" "compressedSize:" "uncompressedSize:" "columnCount: ${EXPECTED_COLUMN_COUNT}" "createdBy:"; do
if ! grep -qF "${expected}" <<<"${DEFAULT_OUT}"; then
echo "FAIL default describe-parquet output missing '${expected}'"
printf '%s\n' "${DEFAULT_OUT}"
exit 1
fi
done
if grep -q "^columns:" <<<"${DEFAULT_OUT}"; then
echo "FAIL default describe-parquet output should not include columns section"
printf '%s\n' "${DEFAULT_OUT}"
exit 1
fi
echo "OK Default output verified"

# -s / --summary
SUMMARY_OUT=$({{ICE_CLI}} --config {{CLI_CONFIG}} describe-parquet -s "${TARGET}")
if ! grep -qF "rows: ${EXPECTED_ROWS}" <<<"${SUMMARY_OUT}"; then
echo "FAIL --summary output missing expected row count"
printf '%s\n' "${SUMMARY_OUT}"
exit 1
fi
echo "OK --summary output verified"

# --columns: each iris column with type and repetition
COLUMNS_OUT=$({{ICE_CLI}} --config {{CLI_CONFIG}} describe-parquet --columns "${TARGET}")
if ! grep -q "^columns:" <<<"${COLUMNS_OUT}"; then
echo "FAIL --columns output missing 'columns:' section"
printf '%s\n' "${COLUMNS_OUT}"
exit 1
fi
for col in "sepal.length" "sepal.width" "petal.length" "petal.width" "variety"; do
if ! grep -qF "name: ${col}" <<<"${COLUMNS_OUT}" && ! grep -qF "name: \"${col}\"" <<<"${COLUMNS_OUT}"; then
echo "FAIL --columns output missing column '${col}'"
printf '%s\n' "${COLUMNS_OUT}"
exit 1
fi
done
if ! grep -qE 'repetition: "?(REQUIRED|OPTIONAL|REPEATED)"?' <<<"${COLUMNS_OUT}"; then
echo "FAIL --columns output missing repetition field"
printf '%s\n' "${COLUMNS_OUT}"
exit 1
fi
if ! grep -qE 'type: "?(DOUBLE|FLOAT|INT32|INT64|BINARY|BOOLEAN|FIXED_LEN_BYTE_ARRAY|INT96)"?' <<<"${COLUMNS_OUT}"; then
echo "FAIL --columns output missing primitive type field"
printf '%s\n' "${COLUMNS_OUT}"
exit 1
fi
echo "OK --columns output verified"

# -r / --row-groups (no per-column details)
ROWGROUPS_OUT=$({{ICE_CLI}} --config {{CLI_CONFIG}} describe-parquet -r "${TARGET}")
if ! grep -q "^rowGroups:" <<<"${ROWGROUPS_OUT}"; then
echo "FAIL -r output missing 'rowGroups:' section"
printf '%s\n' "${ROWGROUPS_OUT}"
exit 1
fi
for expected in "index:" "rowCount:" "totalSize:" "compressedSize:" "startingPos:"; do
if ! grep -qF "${expected}" <<<"${ROWGROUPS_OUT}"; then
echo "FAIL -r output missing '${expected}'"
printf '%s\n' "${ROWGROUPS_OUT}"
exit 1
fi
done
if grep -qE "encodings:|codec:" <<<"${ROWGROUPS_OUT}"; then
echo "FAIL -r output should not include per-column details (encodings/codec)"
printf '%s\n' "${ROWGROUPS_OUT}"
exit 1
fi
echo "OK -r output verified"

# -d / --row-group-details: encodings, codec, stats
DETAILS_OUT=$({{ICE_CLI}} --config {{CLI_CONFIG}} describe-parquet -d "${TARGET}")
for expected in "rowGroups:" "encodings:" "codec:" "valueCount:" "path:"; do
if ! grep -qF "${expected}" <<<"${DETAILS_OUT}"; then
echo "FAIL -d output missing '${expected}'"
printf '%s\n' "${DETAILS_OUT}"
exit 1
fi
done
if ! grep -q "nulls:" <<<"${DETAILS_OUT}"; then
echo "FAIL -d output missing column stats ('nulls:')"
printf '%s\n' "${DETAILS_OUT}"
exit 1
fi
echo "OK -d output verified"

# -a / --all: every section present
ALL_OUT=$({{ICE_CLI}} --config {{CLI_CONFIG}} describe-parquet -a "${TARGET}")
for expected in "summary:" "columns:" "rowGroups:" "encodings:" "codec:" "nulls:"; do
if ! grep -qF "${expected}" <<<"${ALL_OUT}"; then
echo "FAIL -a output missing '${expected}'"
printf '%s\n' "${ALL_OUT}"
exit 1
fi
done
echo "OK -a output verified"

# --json: JSON output instead of YAML
JSON_OUT=$({{ICE_CLI}} --config {{CLI_CONFIG}} describe-parquet -a --json "${TARGET}")
if ! grep -q '^{' <<<"${JSON_OUT}"; then
echo "FAIL --json output is not a JSON object"
printf '%s\n' "${JSON_OUT}"
exit 1
fi
for expected in '"summary"' '"columns"' '"rowGroups"' "\"rows\":${EXPECTED_ROWS}" "\"columnCount\":${EXPECTED_COLUMN_COUNT}"; do
if ! grep -qF "${expected}" <<<"${JSON_OUT}"; then
echo "FAIL --json output missing '${expected}'"
printf '%s\n' "${JSON_OUT}"
exit 1
fi
done
if grep -qE "^summary:" <<<"${JSON_OUT}"; then
echo "FAIL --json output looks like YAML"
printf '%s\n' "${JSON_OUT}"
exit 1
fi
echo "OK --json output verified"

# Combined --summary --columns: both sections, no rowGroups
COMBINED_OUT=$({{ICE_CLI}} --config {{CLI_CONFIG}} describe-parquet -s --columns "${TARGET}")
if ! grep -q "^summary:" <<<"${COMBINED_OUT}" || ! grep -q "^columns:" <<<"${COMBINED_OUT}"; then
echo "FAIL combined -s --columns missing summary or columns section"
printf '%s\n' "${COMBINED_OUT}"
exit 1
fi
if grep -q "^rowGroups:" <<<"${COMBINED_OUT}"; then
echo "FAIL combined -s --columns should not include rowGroups section"
printf '%s\n' "${COMBINED_OUT}"
exit 1
fi
echo "OK Combined --summary --columns output verified"

# Missing file should fail
if {{ICE_CLI}} --config {{CLI_CONFIG}} describe-parquet "file://${SCENARIO_DIR}/does-not-exist.parquet" >/dev/null 2>&1; then
echo "FAIL describe-parquet should fail on missing file"
exit 1
fi
echo "OK Missing file rejected"

echo "Describe-parquet test completed successfully"
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: "Describe parquet metadata"
description: "Tests describe-parquet against a local iris parquet file across all option flags and both YAML and JSON output formats"

catalogConfig:
warehouse: "s3://test-bucket/warehouse"

env:
INPUT_FILE: "input.parquet"
EXPECTED_ROWS: "150"
EXPECTED_COLUMN_COUNT: "5"
Loading
Loading