waterWang opened a new pull request, #19584:
URL: https://github.com/apache/hudi/pull/19584
### Bug
Under concurrent multi-table writes from a single Spark driver JVM with
`hoodie.metrics.on=true`, `LocalRegistry.getCounter()` can return null when a
racing `clear()` lands between the `containsKey` check and the `get` call,
causing a `NullPointerException` mid-commit (inside `DataFileWriter.close()`).
The exception leaves a **truncated completed-instant metadata file** that
permanently breaks the table.
### Root Cause
`LocalRegistry.getCounter()` uses `containsKey` + `put` + `get` — a
non-atomic check-then-act. `clear()` is unsynchronized and can race with
`getCounter()`:
```java
private synchronized Counter getCounter(String name) {
if (!counters.containsKey(name)) { // Thread A: passes
counters.put(name, new Counter());
}
return counters.get(name); // Thread A: clear() from Thread B hit
between check and get → null
}
```
### Fix
Replace the check-then-act with `ConcurrentHashMap.computeIfAbsent()`, which
is atomic and never returns null:
```java
private Counter getCounter(String name) {
return counters.computeIfAbsent(name, k -> new Counter());
}
```
This also removes the `synchronized` lock on the hot path (every FS write in
the JVM calls `getCounter()`), since `computeIfAbsent` handles concurrency
natively.
### Stack trace
```
java.lang.NullPointerException: Cannot invoke
"org.apache.hudi.common.metrics.Counter.add(long)"
because the return value of
"org.apache.hudi.common.metrics.LocalRegistry.getCounter(String)" is null
at
org.apache.hudi.common.metrics.LocalRegistry.add(LocalRegistry.java:48)
at
org.apache.hudi.hadoop.fs.HoodieWrapperFileSystem.executeFuncWithTimeAndByteMetrics(HoodieWrapperFileSystem.java:133)
at
org.apache.hudi.hadoop.fs.SizeAwareFSDataOutputStream.write(SizeAwareFSDataOutputStream.java:59)
at
org.apache.avro.file.DataFileWriter$BufferedFileOutputStream$PositionFilter.write(DataFileWriter.java:485)
at org.apache.avro.file.DataFileWriter.close(DataFileWriter.java:469)
at
org.apache.hudi.common.table.timeline.CommitMetadataSerDe.lambda$getInstantWriter$0(CommitMetadataSerDe.java:52)
at
org.apache.hudi.storage.HoodieStorage.createImmutableFileInPath(HoodieStorage.java:349)
```
Fixes #19570
--
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]