yuqi1129 opened a new issue, #13462:
URL: https://github.com/apache/gravitino/issues/13462
### Version
main branch
### Describe what's wrong
`TestRelationalEntityStoreBatchGetLateFill.testBatchGetRemovesValueWrittenAfterClear`
hangs forever on `main`, so `./gradlew :core:test` never finishes. The `build
(17)` job on the merge commit of #13400 (`cd72eac711`) ran `:core:test` for
1h47m with no further output before being cancelled.
The test injects `store::clearCache` into `CaffeineEntityCache.doPut`, which
runs inside `SegmentedLock.withLock`. Since #13400, `withLock` holds the
`globalGate` read lock across its whole critical section and `withGlobalLock`
takes the write lock. A `ReentrantReadWriteLock` read lock cannot upgrade, so
the thread blocks on itself. #13400's own javadoc states the rule the test
breaks:
> Must not be called from inside a `withLock` action on the same instance:
the read lock cannot upgrade to the write lock, so such a call would deadlock.
Neither PR is wrong alone: #13374 (`3b4778feb3`) added the re-entrant hook
while `withGlobalLock` took no gate lock, and #13400 (`cd72eac711`) added the
gate without knowing about the hook. Both were green in isolation.
This is test-only. The sole production callers of `cache.clear()` are
`EntityCacheChangeLogListener.onEntityChange` (poller thread; `target.clear()`
runs in the catch block, after `withLock`'s `finally` released the read lock)
and `RelationalEntityStore.clearCache()`. No production path calls `clear()`
from inside a `withLock` action.
### Error message and/or stacktrace
```
"Test worker" #1 waiting on condition
java.lang.Thread.State: WAITING (parking)
- parking to wait for <0x...> (a
java.util.concurrent.locks.ReentrantReadWriteLock$FairSync)
at
java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock.lock(ReentrantReadWriteLock.java:959)
at
org.apache.gravitino.cache.SegmentedLock.withGlobalLock(SegmentedLock.java:245)
at
org.apache.gravitino.cache.CaffeineEntityCache.clear(CaffeineEntityCache.java:202)
at
org.apache.gravitino.storage.relational.RelationalEntityStore.clearCache(RelationalEntityStore.java:580)
at
...TestRelationalEntityStoreBatchGetLateFill$RecordingCache.doPut(TestRelationalEntityStoreBatchGetLateFill.java:254)
at
org.apache.gravitino.cache.BaseEntityCache.put(BaseEntityCache.java:120)
at
org.apache.gravitino.storage.relational.RelationalEntityStore.lambda$batchGet$3(RelationalEntityStore.java:279)
at
org.apache.gravitino.cache.SegmentedLock.withLockAndThrow(SegmentedLock.java:197)
<-- holds globalGate.readLock
```
### How to reproduce
On `main`:
```
./gradlew :core:test -PskipITs --tests
'*TestRelationalEntityStoreBatchGetLateFill*'
```
It never terminates.
Reverting only `SegmentedLock.java` to `cd72eac711^` (the sole main-code
file #13400 touched) makes the same 8 tests pass in 36s, which isolates the
interaction to a single variable.
### Additional context
The test targets the inner re-check at
`RelationalEntityStore.batchGet:289-293`. After #13400 a whole-cache clear can
no longer interleave there at all, so a clear is the wrong way to simulate it.
A hierarchical or unrelated invalidation still can — it advances the epoch
without taking the key's lock — and that is the window the re-check genuinely
defends.
--
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]