LuciferYang opened a new pull request, #12124:
URL: https://github.com/apache/gravitino/pull/12124

   ### What changes were proposed in this pull request?
   
   Two additions to `ClassLoaderResourceCleanerUtils.closeClassLoaderResource`:
   
   - Shut down MySQL's `AbandonedConnectionCleanupThread` via 
`uncheckedShutdown()`, which also clears the tracked-connection map so the 
driver's ClassLoader can be collected. The call is guarded by 
`isOwnedByClassLoader`, matching the other cleanup steps in this class, so it 
never stops a cleanup thread owned by a parent or shared ClassLoader (for 
example a MySQL entity store loaded on the app ClassLoader, whose driver class 
delegates up to the app loader).
   - Broaden the ThreadLocal sweep from `Gravitino-webserver-*` threads to all 
application threads, skipping only the JVM `system` thread group. Only entries 
whose value was loaded by the target ClassLoader are cleared, so ThreadLocals 
owned by other ClassLoaders are left alone.
   
   ### Why are the changes needed?
   
   After a MySQL-backed catalog is dropped, its isolated ClassLoader stays 
reachable through the `mysql-cj-abandoned-connection-cleanup` thread's context 
ClassLoader and through ThreadLocals on non-webserver threads (Caffeine 
ForkJoinPool, catalog-cleaner, Hadoop daemons). `closeClassLoaderResource` 
releases neither today, so the ClassLoader leaks on every reload and Metaspace 
grows until `OutOfMemoryError: Metaspace`.
   
   Fix: #12123
   
   ### Does this PR introduce _any_ user-facing change?
   
   No.
   
   ### How was this patch tested?
   
   Added `TestClassLoaderResourceCleanerUtils` cases (`mysql-connector-j` added 
as a test-only dependency):
   
   - `testShutdownMySQLAbandonedConnectionCleanupThreadStopsThread`: loading 
`AbandonedConnectionCleanupThread` in a child `URLClassLoader` starts the 
cleanup thread bound to that loader; after 
`shutdownMySQLAbandonedConnectionCleanupThread` the thread is gone. It loads 
the cleanup-thread class directly rather than the driver, so the test does not 
register a driver into the JVM-global `DriverManager`.
   - `testShutdownMySQLAbandonedConnectionCleanupThreadSkipsParentOwnedClass`: 
when the class resolves to a parent loader, a child-scoped cleanup leaves the 
parent's thread alive; an owner-scoped cleanup stops it.
   - `testClearThreadLocalMapClearsOnlyTargetClassLoaderValues`: on a 
non-webserver thread, a ThreadLocal whose value is loaded by the target 
ClassLoader is cleared, while one loaded by a different (non-null) ClassLoader 
is kept.
   - `testClearThreadLocalMapSkipsSystemThreadGroup`: a ThreadLocal on a 
`system`-group thread is left untouched.
   
   Ran `./gradlew :catalogs:catalog-common:test --tests 
"org.apache.gravitino.utils.TestClassLoaderResourceCleanerUtils"`: 7/7 green.
   


-- 
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