Skip to content

Commit

Permalink
Add documentation for using XA distributed transactions in GraalVM Na…
Browse files Browse the repository at this point in the history
…tive Image (#31975)
  • Loading branch information
linghengqian authored Jul 4, 2024
1 parent 39ad643 commit aa18c5d
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 300 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,29 @@ Caused by: java.io.UnsupportedEncodingException: Codepage Cp1252 is not supporte
[...]
```

5. 当使用 Seata 的 BASE 集成时,用户需要使用特定的 `io.seata:seata-all:1.8.0` 版本以避开对 ByteBuddy Java API 的使用,
5. 讨论在 ShardingSphere JDBC 的 GraalVM Native Image 下使用 XA 分布式事务的所需步骤,则需要引入额外的已知前提,
- `org.apache.shardingsphere.transaction.xa.jta.datasource.swapper.DataSourceSwapper#loadXADataSource(String)` 会通过 `java.lang.Class#getDeclaredConstructors` 实例化各数据库驱动的 `javax.sql.XADataSource` 实现类。
- 各数据库驱动的 `javax.sql.XADataSource` 实现类的全类名通过实现 `org.apache.shardingsphere.transaction.xa.jta.datasource.properties.XADataSourceDefinition` 的 SPI,来存入 ShardingSphere 的元数据。

在 GraalVM Native Image 内部,这实际上要求定义第三方依赖的 GraalVM Reachability Metadata,而 ShardingSphere 自身仅为 `com.h2database:h2` 提供对应的 GraalVM Reachability Metadata。
`com.mysql:mysql-connector-j` 等其他数据库驱动的 GraalVM Reachability Metadata 应自行定义,
或将对应 JSON 提交到 https://github.com/oracle/graalvm-reachability-metadata 一侧。

以 `com.mysql:mysql-connector-j:9.0.0` 的 `com.mysql.cj.jdbc.MysqlXADataSource` 类为例,这是 MySQL JDBC Driver 的 `javax.sql.XADataSource` 的实现。
用户需要在自有项目的 claapath 的 `/META-INF/native-image/com.mysql/mysql-connector-j/9.0.0/` 文件夹的 `reflect-config.json`文件内定义如下 JSON,
以在 GraalVM Native Image 内部定义 `com.mysql.cj.jdbc.MysqlXADataSource` 的构造函数。

```json
[
{
"condition":{"typeReachable":"com.mysql.cj.jdbc.MysqlXADataSource"},
"name":"com.mysql.cj.jdbc.MysqlXADataSource",
"allDeclaredConstructors": true
}
]
```

6. 当使用 Seata 的 BASE 集成时,用户需要使用特定的 `io.seata:seata-all:1.8.0` 版本以避开对 ByteBuddy Java API 的使用,
并排除 `io.seata:seata-all:1.8.0` 中过时的 `org.antlr:antlr4-runtime:4.8` 的 Maven 依赖。可能的配置例子如下,

```xml
Expand Down Expand Up @@ -265,7 +287,7 @@ Caused by: java.io.UnsupportedEncodingException: Codepage Cp1252 is not supporte
</project>
```

6. 当需要通过 ShardingSphere JDBC 使用 ClickHouse 方言时,
7. 当需要通过 ShardingSphere JDBC 使用 ClickHouse 方言时,
用户需要手动引入相关的可选模块和 classifier 为 `http` 的 ClickHouse JDBC 驱动。
原则上,ShardingSphere 的 GraalVM Native Image 集成不希望使用 classifier 为 `all` 的 `com.clickhouse:clickhouse-jdbc`,
因为 Uber Jar 会导致采集重复的 GraalVM Reachability Metadata。
Expand Down Expand Up @@ -318,7 +340,7 @@ curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install java 22.0.1-graalce
sdk use java 22.0.1-graalce
sudo apt-get install build-essential libz-dev zlib1g-dev -y
sudo apt-get install build-essential zlib1g-dev -y
git clone git@github.com:apache/shardingsphere.git
cd ./shardingsphere/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,33 @@ Caused by: java.io.UnsupportedEncodingException: Codepage Cp1252 is not supporte
[...]
```

5. When using Seata's BASE integration,
5. To discuss the steps required to use XA distributed transactions under the GraalVM Native Image of ShardingSphere JDBC,
additional known prerequisites need to be introduced,
- `org.apache.shardingsphere.transaction.xa.jta.datasource.swapper.DataSourceSwapper#loadXADataSource(String)` will instantiate the `javax.sql.XADataSource` implementation class of each database driver through `java.lang.Class#getDeclaredConstructors`.
- The full class name of the `javax.sql.XADataSource` implementation class of each database driver is stored in the metadata of ShardingSphere by implementing the SPI of `org.apache.shardingsphere.transaction.xa.jta.datasource.properties.XADataSourceDefinition`.

In the GraalVM Native Image, this actually requires the definition of the GraalVM Reachability Metadata of the third-party dependencies,
while ShardingSphere itself only provides the corresponding GraalVM Reachability Metadata for `com.h2database:h2`.

GraalVM Reachability Metadata of other database drivers such as `com.mysql:mysql-connector-j` should be defined by themselves,
or the corresponding JSON should be submitted to https://github.com/oracle/graalvm-reachability-metadata .

Take the `com.mysql.cj.jdbc.MysqlXADataSource` class of `com.mysql:mysql-connector-j:9.0.0` as an example,
which is the implementation of `javax.sql.XADataSource` of MySQL JDBC Driver.
Users need to define the following JSON in the `reflect-config.json` file in the `/META-INF/native-image/com.mysql/mysql-connector-j/9.0.0/` folder of their own project's claapath,
to define the constructor of `com.mysql.cj.jdbc.MysqlXADataSource` inside the GraalVM Native Image.

```json
[
{
"condition":{"typeReachable":"com.mysql.cj.jdbc.MysqlXADataSource"},
"name":"com.mysql.cj.jdbc.MysqlXADataSource",
"allDeclaredConstructors": true
}
]
```

6. When using Seata's BASE integration,
users need to use a specific `io.seata:seata-all:1.8.0` version to avoid using the ByteBuddy Java API,
and exclude the outdated Maven dependency of `org.antlr:antlr4-runtime:4.8` in `io.seata:seata-all:1.8.0`.
Possible configuration examples are as follows,
Expand Down Expand Up @@ -276,7 +302,7 @@ Possible configuration examples are as follows,
</project>
```

6. When using the ClickHouse dialect through ShardingSphere JDBC,
7. When using the ClickHouse dialect through ShardingSphere JDBC,
users need to manually introduce the relevant optional modules and the ClickHouse JDBC driver with the classifier `http`.
In principle, ShardingSphere's GraalVM Native Image integration does not want to use `com.clickhouse:clickhouse-jdbc` with classifier `all`,
because Uber Jar will cause the collection of duplicate GraalVM Reachability Metadata.
Expand Down Expand Up @@ -330,7 +356,7 @@ curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install java 21.0.2-graalce
sdk use java 21.0.2-graalce
sudo apt-get install build-essential libz-dev zlib1g-dev -y
sudo apt-get install build-essential zlib1g-dev -y
git clone git@github.com:apache/shardingsphere.git
cd ./shardingsphere/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@
import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
import org.apache.shardingsphere.infra.database.core.type.DatabaseTypeFactory;
import org.apache.shardingsphere.infra.datasource.pool.CatalogSwitchableDataSource;
import org.apache.shardingsphere.infra.datasource.pool.hikari.metadata.HikariDataSourcePoolFieldMetaData;
import org.apache.shardingsphere.infra.datasource.pool.hikari.metadata.HikariDataSourcePoolMetaData;
import org.apache.shardingsphere.infra.exception.core.external.sql.type.wrapper.SQLWrapperException;
import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
import org.apache.shardingsphere.infra.util.reflection.ReflectionUtils;

import javax.sql.DataSource;
import java.sql.Connection;
Expand Down Expand Up @@ -115,7 +118,7 @@ public static Map<String, DatabaseType> getStorageTypes(final DatabaseConfigurat
/**
* Get storage type.
* Similar to apache/hive 4.0.0's `org.apache.hive.jdbc.HiveDatabaseMetaData`, it does not implement {@link java.sql.DatabaseMetaData#getURL()}.
* So use {@link CatalogSwitchableDataSource#getUrl()} to try fuzzy matching.
* So use {@link CatalogSwitchableDataSource#getUrl()} and {@link ReflectionUtils#getFieldValue(Object, String)} to try fuzzy matching.
*
* @param dataSource data source
* @return storage type
Expand All @@ -128,6 +131,12 @@ public static DatabaseType getStorageType(final DataSource dataSource) {
if (dataSource instanceof CatalogSwitchableDataSource) {
return DatabaseTypeFactory.get(((CatalogSwitchableDataSource) dataSource).getUrl());
}
if (dataSource.getClass().getName().equals(new HikariDataSourcePoolMetaData().getType())) {
HikariDataSourcePoolFieldMetaData dataSourcePoolFieldMetaData = new HikariDataSourcePoolFieldMetaData();
String jdbcUrlFieldName = ReflectionUtils.<String>getFieldValue(dataSource, dataSourcePoolFieldMetaData.getJdbcUrlFieldName())
.orElseThrow(() -> new SQLWrapperException(sqlFeatureNotSupportedException));
return DatabaseTypeFactory.get(jdbcUrlFieldName);
}
throw new SQLWrapperException(sqlFeatureNotSupportedException);
} catch (final SQLException ex) {
throw new SQLWrapperException(ex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,6 @@
{
"condition":{"typeReachable":"org.h2.jdbcx.JdbcDataSource"},
"name":"org.h2.jdbcx.JdbcDataSource",
"allDeclaredClasses": true,
"allDeclaredMethods": true,
"allDeclaredFields": true,
"allDeclaredConstructors": true,
"allPublicClasses": true,
"allPublicMethods": true,
"allPublicFields": true,
"allPublicConstructors": true,
"allRecordComponents": true,
"allNestMembers": true,
"allSigners": true,
"allPermittedSubclasses": true,
"queryAllDeclaredMethods": true,
"queryAllDeclaredConstructors": true,
"queryAllPublicMethods": true,
"queryAllPublicConstructors": true,
"unsafeAllocated": true
"allDeclaredConstructors": true
}
]
Loading

0 comments on commit aa18c5d

Please sign in to comment.