Skip to content

Commit

Permalink
Provides built-in GraalVM Reachability Metadata for core features of …
Browse files Browse the repository at this point in the history
…ShardingSphere JDBC and adds nativeTest-related unit test subsets (#29000)

* Provides built-in GraalVM Reachability Metadata for core features of ShardingSphere JDBC and adds nativeTest-related unit test subsets

* Deal with coding style

* Use `java.util.Collection` instead of `java.util.List` in unit tests
  • Loading branch information
linghengqian authored Nov 16, 2023
1 parent 83c6214 commit a392e14
Show file tree
Hide file tree
Showing 47 changed files with 4,766 additions and 124 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/nightly-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ jobs:
ref: ${{ inputs.commit-id }}
- uses: graalvm/setup-graalvm@v1
with:
java-version: '17.0.8'
java-version: '17.0.9'
distribution: 'graalvm-community'
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/cache@v3
Expand All @@ -136,7 +136,6 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push Docker Image
run: |
./mvnw -PgenerateStandardMetadata -DskipNativeTests -B -T1C clean test
./mvnw -am -pl distribution/proxy-native -Prelease.native,docker.buildx.push.native -B -T1C -DskipTests -Dproxy.image.repository=${{ env.PROXY_NATIVE }} -Dproxy.image.tag=${{ github.sha }} clean package
build-cache:
Expand Down
28 changes: 28 additions & 0 deletions .github/workflows/nightly-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,31 @@ jobs:
java-version: 8
- name: Run Tests with JDK 8
run: ./mvnw test -B -ntp -fae -T1C

ci-native-test:
if: github.repository == 'apache/shardingsphere'
name: NativeTest CI - GraalVM CE on ${{ matrix.os }}
needs: global-environment
runs-on: ${{ matrix.os }}
timeout-minutes: 90
strategy:
max-parallel: 20
fail-fast: false
matrix:
os: [ ubuntu-latest ]
steps:
- uses: actions/checkout@v3
- uses: graalvm/setup-graalvm@v1
with:
java-version: '17.0.9'
distribution: 'graalvm-community'
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ needs.global-environment.outputs.GLOBAL_CACHE_PREFIX }}-maven-third-party-cache-${{ github.sha }}
restore-keys: |
${{ needs.global-environment.outputs.GLOBAL_CACHE_PREFIX }}-maven-third-party-cache-
${{ needs.global-environment.outputs.GLOBAL_CACHE_PREFIX }}-maven-third-party-
- name: Run nativeTest with GraalVM CE
run: ./mvnw -PnativeTestInShardingSphere -T1C -e clean test
17 changes: 0 additions & 17 deletions distribution/proxy-native/access-filter.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
+++
title = "GraalVM Native Image"
weight = 8
chapter = true
+++

## 背景信息

ShardingSphere JDBC 已在 GraalVM Native Image 下完成可用性验证。

构建包含 `org.apache.shardingsphere:shardingsphere-jdbc-core:${shardingsphere.version}` 的 Maven 依赖的 GraalVM Native
Image,你需要借助于 GraalVM Native Build Tools。GraalVM Native Build Tools 提供了 Maven Plugin 和 Gradle Plugin 来简化 GraalVM
CE 的 `native-image` 工具的长篇大论的 shell 命令。

ShardingSphere JDBC 要求在如下或更高版本的 `GraalVM CE` 完成构建 GraalVM Native Image。使用者可通过 SDKMAN! 快速切换 JDK。这同理
适用于 `Oracle GraalVM``Liberica Native Image Kit``Mandrel``GraalVM CE` 的下游发行版。

- GraalVM CE 23.0.2 For JDK 17.0.9,对应于 SDKMAN! 的 `17.0.9-graalce`
- GraalVM CE 23.0.2 For JDK 21.0.1,对应于 SDKMAN! 的 `21.0.1-graalce`

### Maven 生态

使用者需要配置额外的 BuildArgs ,以阻止 GroovyShell 的相关类在构建 GraalVM Native Image 时报错。并主动使用 GraalVM Reachability
Metadata 中央仓库。如下配置可供参考,以配置项目额外的 Maven Profile,以 GraalVM Native Build Tools 的文档为准。

```xml
<project>
<dependencies>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>0.9.28</version>
<extensions>true</extensions>
<configuration>
<buildArgs>
<arg>--report-unsupported-elements-at-runtime</arg>
</buildArgs>
<metadataRepository>
<enabled>true</enabled>
</metadataRepository>
</configuration>
<executions>
<execution>
<id>build-native</id>
<goals>
<goal>compile-no-fork</goal>
</goals>
<phase>package</phase>
</execution>
<execution>
<id>test-native</id>
<goals>
<goal>test</goal>
</goals>
<phase>test</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
```

### Gradle 生态

使用者需要配置额外的 BuildArgs ,以阻止 GroovyShell 的相关类在构建 GraalVM Native Image 时报错。并主动使用 GraalVM Reachability
Metadata 中央仓库。如下配置可供参考,以配置项目额外的 Gradle Task,以 GraalVM Native Build Tools 的文档为准。

```groovy
plugins {
id 'org.graalvm.buildtools.native' version '0.9.28'
}
dependencies {
implementation 'org.apache.shardingsphere:shardingsphere-jdbc-core:${shardingsphere.version}'
}
graalvmNative {
binaries {
main {
buildArgs.add('--report-unsupported-elements-at-runtime')
}
test {
buildArgs.add('--report-unsupported-elements-at-runtime')
}
}
metadataRepository {
enabled = true
}
}
```

### 对于 SBT 等不被 GraalVM Native Build Tools 支持的构建工具

此类需求需要在 https://github.com/graalvm/native-build-tools 打开额外的 issue 并提供对应构建工具的 Plugin 实现。


### 使用限制

1. 如下的算法类由于涉及到 https://github.com/oracle/graal/issues/5522 , 暂未可在 GraalVM Native Image 下使用。
- `org.apache.shardingsphere.sharding.algorithm.sharding.inline.InlineShardingAlgorithm`
- `org.apache.shardingsphere.sharding.algorithm.sharding.inline.ComplexInlineShardingAlgorithm`
- `org.apache.shardingsphere.sharding.algorithm.sharding.hint.HintInlineShardingAlgorithm`

对于常规案例,使用者可通过 CLASS_BASE 算法自行模拟 GroovyShell 的行为。例如对于如下配置。

```yaml
rules:
- !SHARDING
defaultDatabaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: inline
shardingAlgorithms:
inline:
type: INLINE
props:
algorithm-expression: ds_${user_id % 2}
allow-range-query-with-inline-sharding: false
```
可首先定义 CLASS_BASE 的实现类。
```java
package org.example.test;

import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;

import java.util.Collection;

public final class TestShardingAlgorithmFixture implements StandardShardingAlgorithm<Integer> {

@Override
public String doSharding(final Collection<String> availableTargetNames, final PreciseShardingValue<Integer> shardingValue) {
String resultDatabaseName = "ds_" + shardingValue.getValue() % 2;
for (String each : availableTargetNames) {
if (each.equals(resultDatabaseName)) {
return each;
}
}
return null;
}

@Override
public Collection<String> doSharding(final Collection<String> availableTargetNames, final RangeShardingValue<Integer> shardingValue) {
throw new RuntimeException("This algorithm class does not support range queries.");
}
}
```

修改相关 YAML 配置如下。

```yaml
rules:
- !SHARDING
defaultDatabaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: inline
shardingAlgorithms:
inline:
type: CLASS_BASED
props:
strategy: STANDARD
algorithmClassName: org.example.test.TestShardingAlgorithmFixture
```
`src/main/resources/META-INF/native-image/exmaple-test-metadata/reflect-config.json` 加入如下内容即可在正常在 GraalVM Native
Image 下使用。

```json
[
{
"name":"org.example.test.TestShardingAlgorithmFixture",
"methods":[{"name":"<init>","parameterTypes":[] }]
}
]
```

2. 对于 `读写分离` 的功能,你需要使用 `行表达式` SPI 的其他实现,以在配置 `logic database name`,`writeDataSourceName` 和 `readDataSourceNames`
时绕开对 GroovyShell 的调用。一个可能的配置是使用 `LITERAL` 的 `行表达式` SPI 的实现。对于 `数据分片` 的功能的 `actualDataNodes` 同理。
```yaml
rules:
- !READWRITE_SPLITTING
dataSources:
<LITERAL>readwrite_ds:
writeDataSourceName: <LITERAL>ds_0
readDataSourceNames:
- <LITERAL>ds_1
- <LITERAL>ds_2
```

3. 使用者依然需要在 `src/main/resources/META-INF/native-image` 文件夹或 `src/test/resources/META-INF/native-image` 文件夹配置独立
文件的 GraalVM Reachability Metadata。使用者可通过 GraalVM Native Build Tools 的 GraalVM Tracing Agent 来快速采集 GraalVM
Reachability Metadata。

4. 尚未验证 DistSQL 的可用性。使用者需自行添加额外的 GraalVM Reachability Metadata。

## 贡献 GraalVM Reachability Metadata

ShardingSphere 对在 GraalVM Native Image 下的可用性的验证,是通过 GraalVM Native Build Tools 的 Maven Plugin 子项目来完成的。
通过在 JVM 下运行单元测试,为单元测试打上 `junit-platform-unique-ids*` 标签,此后构建为 GraalVM Native Image 进行 nativeTest 来测试
在 GraalVM Native Image 下的单元测试覆盖率。请贡献者不要使用 `io.kotest:kotest-runner-junit5-jvm:5.5.4` 等在 `test listener` mode 下
failed to discover tests 的测试库。

ShardingSphere 定义了 `shardingsphere-infra-nativetest` 的 Maven Module 用于为 native Test 提供小型的单元测试子集,
此单元测试子集避免了使用 Mockito 等 native Test 下无法使用的第三方库。

ShardingSphere 定义了 `nativeTestInShardingSphere` 的 Maven Profile 用于为 `shardingsphere-infra-nativetest` 模块执行 nativeTest 。

假设贡献者处于新的 Ubuntu 22.04.3 LTS 实例下,其可通过如下 bash 命令通过 SDKMAN! 管理 JDK 和工具链,
并为 `shardingsphere-infra-nativetest` 子模块执行 nativeTest。

```bash
sudo apt install unzip zip curl sed -y
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install java 17.0.9-graalce
sdk use java 17.0.9-graalce
sudo apt-get install build-essential libz-dev zlib1g-dev -y
git clone [email protected]:apache/shardingsphere.git
cd ./shardingsphere/
./mvnw -PnativeTestInShardingSphere -T1C -e clean test
```

当贡献者发现缺少与 ShardingSphere 无关的第三方库的 GraalVM Reachability Metadata 时,应当在
https://github.com/oracle/graalvm-reachability-metadata 打开新的 issue, 并提交包含依赖的第三方库缺失的 GraalVM Reachability
Metadata 的 PR。ShardingSphere 在 `shardingsphere-infra-reachability-metadata` 子模块主动托管了部分第三方库的 GraalVM Reachability Metadata。

如果 nativeTest 执行失败, 应为单元测试生成初步的 GraalVM Reachability Metadata,并手动调整以修复 nativeTest。
如有需要,请使用 `org.junit.jupiter.api.condition.DisabledInNativeImage` 注解或 `org.graalvm.nativeimage.imagecode` 的
System Property 屏蔽部分单元测试在 GraalVM Native Image 下运行。

ShardingSphere 定义了 `generateMetadata` 的 Maven Profile 用于在 GraalVM JIT Compiler 下携带 GraalVM Tracing Agent 执行单元测试,并在特定目录下生成或合并
已有的 GraalVM Reachability Metadata 文件。可通过如下 bash 命令简单处理此流程。贡献者仍可能需要手动调整具体的 JSON 条目,并在适当的时候
调整 Maven Profile 和 GraalVM Tracing Agent 的 Filter 链。

以下命令仅为 `shardingsphere-infra-nativetest` 生成 Conditional 形态的 GraalVM Reachability Metadata 的一个举例。生成的 GraalVM
Reachability Metadata 位于 `shardingsphere-infra-reachability-metadata` 子模块下。

对于测试类和测试文件独立使用的 GraalVM Reachability Metadata,贡献者应该放置到
`${user.dir}/infra/nativetest/src/test/resources/META-INF/native-image/shardingsphere-infra-nativetest-test-metadata/`
文件夹下。`${}` 内为相关子模块对应的 POM 4.0 的常规系统变量,自行替换。

```bash
git clone [email protected]:apache/shardingsphere.git
cd ./shardingsphere/
./mvnw -PgenerateMetadata -DskipNativeTests -e -T1C clean test native:metadata-copy
```

请手动删除无任何具体条目的 JSON 文件。
Loading

0 comments on commit a392e14

Please sign in to comment.