loustler commented on PR #11648:
URL: https://github.com/apache/seatunnel/pull/11648#issuecomment-5186777161

   Thank you for the review — three of the four blockers were things I would 
not have found on my own, and you were right that `-am` walks dependencies 
rather than dependents, which is exactly why my verification missed Issue 1.
   
   Pushed an update. All numbers below are measured on the new head. Doing what 
you asked also turned up four defects that changed the PR itself, not just its 
description — they have their own sections after the six issues.
   
   ## Issue 1 — stale `seatunnel-hadoop3-3.1.4-uber` in 
`seatunnel-engine-examples`
   
   Fixed: **artifactId rename only**, no classifier or scope. You were right to 
ask — every other consumer uses `<classifier>optional</classifier>` + 
`<scope>provided</scope>`, but this module deliberately wants the main 
artifact, which the shade plugin still produces. `git grep 
'seatunnel-hadoop3-3\.1\.4-uber' -- . ':!docs'` is now empty (the two 
`incompatible-changes.md` matches name the old artifactId on purpose, as the 
"renamed from" side).
   
   ## Issue 2 — license bookkeeping
   
   Fixed by running the gate and reflecting its output rather than editing by 
hand. Delta: **36 removals / 39 additions**.
   
   | change | n | cause |
   |---|---:|---|
   | awssdk `2.31.30` → `2.35.4` | 26 | the SDK version bump, via 
`transforms-v2` |
   | `netty-*` `4.1.118.Final` → `4.1.126.Final` | 10 | netty is managed by the 
AWS SDK BOM |
   | `okhttp-2.7.5.jar`, `okio-1.6.0.jar` | +2 | §5; okio 1.6.0 is what okhttp 
2.7.5's parent pom pins — resolved, not assumed |
   | `utils-lite-2.35.4.jar` | +1 | did not exist in the 2.31.30 closure |
   
   `checkLicense.sh` ends in a **two-way** `diff` under `set -e`, so the stale 
awssdk entries would have failed it even with okhttp added. The netty rename is 
the part inspection would miss: **no netty version appears anywhere in this 
diff.** Gate now exits 0 with an empty diff.
   
   Also added OkHttp 2.7.5 and Okio 1.6.0 to `release-docs/LICENSE` — neither 
ships as a standalone jar, but `seatunnel-starter.jar` bundles 184 
`com/squareup/okhttp/` and 35 `okio/` classes.
   
   Worth recording: the gate never sees `seatunnel-shade` 
(`<skip>${e2e.dependency.skip}</skip>`, default `true`) or `seatunnel-dist` 
(`-pl '!seatunnel-dist'`), which is why the Hadoop bump and the SDK narrowing 
add no license work at all. `release-docs/LICENSE` has also drifted from the 
gate file independently of this PR (all 26 awssdk and all 10 netty filenames 
have no counterpart there) — happy to open an issue if that's worth tracking.
   
   ## Issue 3 — `hadoop-aliyun`
   
   The analysis came back **dirty**, so this PR moves `hadoop-aliyun` to 3.4.3 
in lockstep, unified onto one root property across all five call sites.
   
   Same method as for `hadoop-aws` — resolve every external `Class` / 
`Methodref` / `InterfaceMethodref` / `Fieldref` against the target with 
descriptor matching and hierarchy walking, with `<init>` resolved only against 
its declaring class since constructors are never inherited (JVMS 5.4.3.3):
   
   | `hadoop-aliyun` | vs `hadoop-common` | unresolved |
   |---|---|---|
   | 3.1.4 | 3.1.4 *(control)* | **0** |
   | 3.1.4 | **3.4.3** | **1** |
   | 3.0.0 | 3.0.0 *(control)* | 0 |
   | 3.0.0 | 3.4.3 | 0 |
   | **3.4.3** | **3.4.3** | **0** |
   
   The one break is the same one that forced `hadoop-aws` to move — 
`AliyunOSSFileSystem` calling a constructor 3.4.3 replaced:
   
   ```
   hadoop-common 3.0.0   SemaphoredDelegatingExecutor does not exist
   hadoop-common 3.1.4   
<init>(Lcom/google/common/util/concurrent/ListeningExecutorService;IZ)V
   hadoop-common 3.4.3   <init>(Ljava/util/concurrent/ExecutorService;IZ)V   (+ 
a DurationTrackerFactory variant)
   ```
   
   **On the blast radius:** the compile surface is nil. Repo-wide there is 
exactly one compile-time reference to a `hadoop-aliyun` type — 
`OssHadoopConf.java:23` reads three `Constants` fields; everything else names 
`AliyunOSSFileSystem` as a string. Those fields are `public static final 
String` with identical values at both versions (`fs.oss.accessKeyId`, 
`fs.oss.accessKeySecret`, `fs.oss.endpoint`). I compared the *values*, not just 
the names, because javac folds constant variables into the caller's constant 
pool (JLS 13.1) — a renamed key would have left the connector silently writing 
the old config key with nothing visible at build time.
   
   **One correction to the premise:** `hadoop-aliyun` declares `hadoop-common` 
as **`compile`**, not `provided` (`hadoop-aws` is `provided` at both versions). 
The coupling is real but arrives differently — SeaTunnel declares 
`hadoop-aliyun` `provided` and ships only that jar, so it links at runtime 
against the uber jar's `hadoop-common`. Same conclusion.
   
   **On the evidence you wanted:** there is no OSS E2E module in this 
repository and MinIO speaks S3 rather than the Aliyun OSS protocol, so I can't 
offer one — only the analysis with matching control runs showing the break 
comes from the version gap and not from the method. Glad to build an OSS E2E as 
a follow-up.
   
   ## Issue 4 — distribution size
   
   Done: `seatunnel-hadoop-aws.jar` **~658 MB → 24,187,329 B (23.1 MB)**, below 
even the ~83 MB it was at on 3.1.4.
   
   I kept `bundle` with a path allowlist rather than switching to individual 
modules, and the deciding factor was risk rather than size.
   
   **Size is a wash.** `hadoop-aws` 3.4.3 references 3 of the bundle's 411 
service packages — `s3` (1248 refs), `sts` (82), `kms` (2 symbols) — with 
**zero** reflective service lookups, and no `dynamodb` since S3Guard was 
removed in 3.4.0 (my PR description was wrong to list it). The allowlist keeps 
16,585,287 B and drops 564,461,442 B; the individual-module closure is 34 
artifacts / 11,219,489 B plus BOM-managed externals (netty ≈ 4.5 MB, 
httpclient+httpcore ≈ 1.1 MB, …) ≈ 16.5 MiB, versus 15.8 MiB filtered.
   
   **The measured difference.** `ConfigureShadedAWSSocketFactory` references 
`software/amazon/awssdk/thirdparty/org/apache/http/conn/socket/ConnectionSocketFactory`
 and `…/conn/ssl/SSLConnectionSocketFactory` — FQCNs that exist **only inside 
`bundle`**; standalone `apache-client` brings plain `org.apache.http`. 
`NetworkBinding` loads that class reflectively and swallows the failure, so 
individual modules would not fail the build — they would quietly turn 
`fs.s3a.ssl.channel.mode` into a no-op. They would also need a 
`ServicesResourceTransformer` (each module ships its own `SdkHttpService` / 
`SdkAsyncHttpService` file; shade's default is last-one-wins) and would put 
unrelocated `org.apache.http`, `io.netty`, `org.reactivestreams` and 
`org.slf4j` at the root of a `lib/` jar.
   
   Two deliberate details: it is an **allowlist** because shade's 
`SimpleFilter` is `!(isIncluded && !isExcluded)` — an exclude can never be 
re-included, and an allowlist can't silently regrow as AWS adds services. And 
all 25 non-service packages are kept rather than hand-picked (4.3 MB total; 
`imds`, for one, is reached reflectively via `IAMInstanceCredentialsProvider`). 
The entire saving comes from `services/`.
   
   Verified on the built jar: service packages exactly `kms`/`s3`/`sts`; `imds` 
intact; both relocated socket-factory classes present; root `org/slf4j/impl/**` 
and `org/apache/log4j/**` empty while the SDK's own 16 relocated slf4j entries 
survive.
   
   **Happy to switch to individual modules if you still prefer it** after these 
numbers — it's a contained change.
   
   **You were more right here than my first fix was.** The distribution *also* 
shipped the raw bundle as a standalone `lib/` jar: 
`assembly-seatunnel-bin-ci.xml` had `com.amazonaws:aws-java-sdk-bundle` and my 
first pass simply swapped it for `software.amazon.awssdk:bundle` — 86,220,098 B 
becoming **686,119,507 B** — so the built distribution carried a filtered *and* 
an unfiltered copy of `software/amazon/awssdk/**` on one classpath. The include 
was already redundant before this PR, which is why it's dropped rather than 
swapped: `seatunnel-hadoop-aws` shades `hadoop-aws` with its whole SDK 
unrelocated (the released 2.3.13 jar holds 42,579 `com/amazonaws/` classes), 
`assembly-seatunnel-bin.xml` — the release descriptor — never included a 
standalone bundle, and nothing can depend on a **v2** SDK from `lib/` because 
`dev`'s `lib/` had none (`transforms-v2` already shades its own). Dropped along 
with its `provided` declaration in `seatunnel-dist/pom.xml`: **−686,119,507 B** 
on t
 he CI distribution, release tarball unchanged.
   
   ## Issue 5 — okhttp 2.x
   
   Option A, as you recommended. The 2.7.5 declaration stays; the PR 
description now records explicitly that this newly *ships* a 2016-era EOL 
library where SeaTunnel previously only borrowed the classes from Hadoop. 
Follow-up: **#11656** — one main file plus two tests, and I'd appreciate your 
review on it.
   
   ## Issue 6 — version-neutral artifactId
   
   Keeping `seatunnel-hadoop3-3.4.3-uber` for now, taking you at your word that 
it's a project naming convention rather than your call to make unilaterally and 
doesn't block merge. I'd rather not churn another ~56 files in a PR that 
already had four blockers — but your reasoning is right, and if another 
maintainer weighs in for `seatunnel-hadoop3-uber` I'll do it here, which would 
also mean `incompatible-changes.md` documents one rename instead of two.
   
   ---
   
   ## Defect 1 — a shipped `NoClassDefFoundError` the Hadoop bump introduced
   
   Found only because you insisted on the `hadoop-aliyun` analysis, and the 
strongest argument for the position you took.
   
   `WALReader` and `DefaultReader` in `imap-storage-file` call 
`CollectionUtils.isEmpty` / `isNotEmpty` from 
**`org.apache.commons.collections`** (3.x), which no pom in their ancestry 
declares. It arrived two ways at once and the bump removes both: on the compile 
classpath via `hadoop-aliyun` → `hadoop-common` (compile scope), and at runtime 
from inside the shaded uber jar. 3.4.3 declares `commons-collections4` instead, 
and the built uber jar has **zero** `org/apache/commons/collections/` entries. 
Both classes ship inside `seatunnel-starter.jar`, and the shipped bytecode 
holds an unrelocated `invokestatic 
org/apache/commons/collections/CollectionUtils.isEmpty` — verified by 
disassembly, with no other jar on the core runtime classpath carrying the class.
   
   So the Hadoop bump alone would have produced a `NoClassDefFoundError` on the 
IMap file-storage WAL read path (cluster restart, IMap recovery with the file 
backend) with **nothing failing at build time**. Moving `hadoop-aliyun` to 
3.4.3 removed the compile-time transitive too, which is what turned it into a 
loud compile error.
   
   Fixed by switching both imports to `commons-collections4` (identical 
null-safe semantics; all four call sites pass a `List`) and declaring it 
explicitly at the root-managed version, as the sibling 
`checkpoint-storage-local-file` already does. No license change — that jar is 
already known.
   
   ## Defect 2 — the #11436 credentials-provider validation had silently 
stopped working
   
   `S3HadoopConf` validates `fs.s3a.aws.credentials.provider` at config-parse 
time by resolving two classes: the configured provider, and the provider 
interface named as a string — `"com.amazonaws.auth.AWSCredentialsProvider"`, 
exactly what this PR stops shipping. `checkCredentialsProviderClass` needs 
**both** to resolve before checking assignability and `continue`s otherwise, so 
the whole thing falls through to its closing `LOGGER.warn` for **every** 
provider value, including correct v2 ones — while telling the user their 
provider "could not be fully validated" and that "the job will fail at 
runtime". No exception, no failing test.
   
   It now names 
`software.amazon.awssdk.auth.credentials.AwsCredentialsProvider`, which is what 
S3A itself checks (`CredentialProviderListFactory` references it, and the 
narrowed jar carries that class and no 
`com/amazonaws/auth/AWSCredentialsProvider`). The unit test's 
`AbstractTestCredentialsProvider` moved to the v2 interface.
   
   I found it via a test-compile error, which exposed a problem in my own 
process: `-Dmaven.test.skip=true` skips test *compilation*, so I was reporting 
a green full-reactor `install` while a test source in my change set did not 
compile. `install -DskipTests` from now on.
   
   ## Defects 3 and 4 — found by the MinIO E2E you asked for
   
   `connector-file-s3-e2e` is green: **BUILD SUCCESS**, `S3FileWithFilterIT` 2 
tests / 0 failures / 0 errors in 31.6 s, thread-leak check included. 
(`S3FileIT` and `S3FileWithMultipleTableIT` are `@Disabled("have no s3 
environment to run this test")`.) Two failures on the way there were real 
defects rather than flakes.
   
   **The harness was injecting the very mismatch this PR removes.** All three 
ITs downloaded `hadoop-aws-3.1.4.jar` and `aws-java-sdk-bundle-1.11.271.jar` 
from Maven Central into the container, so both tests failed with 
`IllegalArgumentException: The S3A credentials provider class 
'org.apache.hadoop.fs.s3a.SimpleAWSCredentialsProvider' does not implement 
'software.amazon.awssdk.auth.credentials.AwsCredentialsProvider'` — 3.1.4's 
provider implements the v1 interface. What caught it was the #11436 validation 
repaired above; on the head you reviewed it would have fallen through to a 
warning and failed later inside S3A, far less legibly. Fixed by copying the 
built `seatunnel-hadoop-aws.jar` into `lib/` instead of downloading anything — 
how `SeaTunnelContainer` already handles the uber jar, and what a real 
distribution looks like. `S3FileWithFilterIT` moved from `buildStartCommand()` 
to `executeExtraCommands(GenericContainer)`, which runs before `server.start()`.
   
   **Then the assertions passed and the thread-leak check failed.** AWS SDK v2 
leaves two daemon threads behind, traced by scanning the shipped jars' constant 
pools for the literal names: `response-input-stream-timeout-scheduler` 
(`software/amazon/awssdk/core/ResponseInputStream$TimeoutScheduler`) and 
`FailsafeDelayScheduler` (the shaded Failsafe inside the S3 Access Grants 
plugin). Both are lazily created, not owned by an `SdkClient` — so closing the 
filesystem can't shut them down — and both are daemon threads parked on a delay 
queue, so they can't hold the JVM open. Added to `isSystemThread`, the same 
treatment that method already gives 
`java-sdk-progress-listener-callback-thread`, the SDK **v1** analogue. If you'd 
rather see the SDK shut down properly than allowlisted, say so — I couldn't 
find a hook that isn't owned by client lifecycle.
   
   **What the green run does not cover:** static credentials only, so no 
`IAMInstanceCredentialsProvider` (the changed default), no STS, no assumed 
roles. And it does **not** validate the assembly change — the harness never 
deploys the dist tarball; `ContainerUtil`/`SeaTunnelContainer` assemble the 
container from module `target/` directories. I assumed otherwise at first and 
want to correct it: dropping the standalone bundle rests on the three static 
grounds in Issue 4, not on this test.
   
   **One thing I did not change, and would like your call on:** 
`connector-hive-e2e` has the same stale downloads (`hadoop-aws/3.1.4`, 
`hadoop-aliyun/3.1.4`, `aliyun-sdk-oss/3.4.1`, `hadoop-cos`) into 
`/tmp/seatunnel/plugins/Hive/lib`. Only the four 
`testFakeSinkHiveOn{HDFS,S3,OSS,Cos}` tests use that directory and all four are 
`@Disabled`, so I can't verify a change to it. Happy to do it here if you 
prefer that to a follow-up.
   
   ---
   
   ## `incompatible-changes.md`, with a correction to my own claim
   
   My first draft said any explicit `com.amazonaws.auth.*` value fails with 
`ClassNotFoundException`. That's wrong for five of them: 
`CredentialProviderListFactory` holds a fixed `V1_V2_CREDENTIAL_PROVIDER_MAP`, 
consulted **before** the class is resolved, that rewrites
   
   | configured v1 name | remapped to |
   |---|---|
   | `com.amazonaws.auth.InstanceProfileCredentialsProvider` | 
`org.apache.hadoop.fs.s3a.auth.IAMInstanceCredentialsProvider` |
   | `com.amazonaws.auth.EC2ContainerCredentialsProviderWrapper` | 
`org.apache.hadoop.fs.s3a.auth.IAMInstanceCredentialsProvider` |
   | `com.amazonaws.auth.EnvironmentVariableCredentialsProvider` | 
`software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider`
 |
   | `com.amazonaws.auth.profile.ProfileCredentialsProvider` | 
`software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider` |
   | `com.amazonaws.auth.AnonymousAWSCredentials` | 
`org.apache.hadoop.fs.s3a.AnonymousAWSCredentialsProvider` |
   
   each with a `LogExactlyOnce` warning. So those five keep working, and the 
docs now say so.
   
   That also reframes the `S3FileBaseOptions` default: the old value is the 
first row above, mapping to exactly the `IAMInstanceCredentialsProvider` this 
PR now names — so the edit is a **cleanup** (dropping a dependency on a shim 
that warns on every use and is documented as transitional), not a rescue from a 
hard break. PR description corrected.
   
   Everything outside those five does fail, and the docs now describe it 
concretely rather than as `ClassNotFoundException`: S3A logs `Failed to create 
{} as v2 credentials, trying to instantiate as v1`, falls back to its v1-to-v2 
adapter, and fails with `AWS V1 SDK is not on the classpath`, because the 
adapter needs `com.amazonaws:aws-java-sdk-core` which `hadoop-aws-3.4.3.pom` 
declares `provided`. `com.amazonaws.auth.ContainerCredentialsProvider`, which 
earlier S3File docs offered as an example, is in this group. The docs also 
point at `fs.s3a.aws.credentials.provider.mapping` as the escape hatch for 
arbitrary v1 names.
   
   ## Two pre-existing items swept up
   
   Both instances of the same drift this PR argues against: 
`imap-storage-file/pom.xml` pinned `hadoop-aws` at 3.1.4 in a module-local 
property (now inherited from root — consistency rather than a live break, since 
that module holds no compiled reference to a `hadoop-aws` type), and 
`connector-hudi/pom.xml` carried a dead `<hadoop-aws.version>` property 
(removed).
   
   ## CI
   
   You noted Issues 1 and 2 would both surface as `Build` failures. There was a 
third: **`code-style` would have failed too** — `spotless:apply` reformatted a 
javadoc block in `S3FileBaseOptions.java` that I'd touched in the previous push 
without running spotless. Now clean.
   
   Gates run locally before pushing: full-reactor `install -DskipTests` 
(284/284 BUILD SUCCESS, test sources compiled), `checkLicense.sh` (exit 0, 
empty diff), root `spotless:check` (exit 0), and the S3 MinIO E2E above.
   
   ## Your answers to my questions
   
   - **#9599** — understood; leaving the `Closes` line for a maintainer with 
write access.
   - **SDK v1 in the two E2E modules** — agreed, follow-up. Test scope only, no 
effect on the shipped artifact.
   - **`JsonSerialization.getMapper()`** — opened as **#11655**, with three 
possible directions. I haven't measured which is best and would welcome a 
preference before I put a PR together.
   
   Thanks again for the depth here. Please re-review whenever convenient — and 
if any of the measurements above look wrong to you, I'd rather hear it than 
have it merged.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to