wombatu-kun commented on issue #8548:
URL: https://github.com/apache/paimon/issues/8548#issuecomment-5139672841

   I looked into this and I am preparing a PR. Answering the two design 
questions first, since the fix hinges on them.
   
   **Is `HadoopFileIO` intended to own the `FileSystem` instances in its 
`fsMap`?** Only some of them, and there is an exact test for which. 
`createFileSystem` calls `path.getFileSystem(conf)`, which is Hadoop's 
`FileSystem.get(URI, Configuration)`:
   
   ```java
   String disableCacheName = String.format("fs.%s.impl.disable.cache", scheme);
   if (conf.getBoolean(disableCacheName, false)) {
       return createFileSystem(uri, conf);   // a fresh instance nobody else 
can reach
   }
   return CACHE.get(uri, conf);              // shared, owned by Hadoop's 
global cache
   ```
   
   So a `HadoopFileIO` owns a `FileSystem` if and only if 
`fs.<scheme>.impl.disable.cache` is true for the scheme of the path it was 
created for. That is exactly the configuration you are running, which is why 
you see one `AliyunOSSFileSystem` per `HadoopFileIO`.
   
   **How should cleanup behave when the global cache is enabled?** It should do 
nothing at all. Those instances are shared with every other user in the JVM, 
including other `FileIO`s and the compute engine itself, and Hadoop releases 
them through `FileSystem.closeAll()` on its shutdown hook. Closing one from 
`HadoopFileIO.close()` would surface as `IOException: Filesystem closed` in 
unrelated readers.
   
   Two details that matter for getting the predicate right, both verified 
against the Hadoop bytecode rather than assumed: the scheme comes from the 
**path**, not from `FileSystem#getUri()`, and it is matched **as written** with 
no lower casing, because that is what Hadoop itself looks up. Lower casing 
would be the dangerous direction: a path spelled `OSS://bucket` is served from 
the shared cache, but a case-insensitive check would find 
`fs.oss.impl.disable.cache=true` and close it.
   
   Beyond `HadoopFileIO.close()` itself, three things turned out to be needed 
before any of it is reachable, so the PR covers them too:
   
   - `ResolvingFileIO` and `PluginFileIO` cache delegates and never forwarded 
`close()`, so the call was swallowed one level above `HadoopFileIO`. Notably 
this also means `OSSFileIO.close()`, which already releases uncached file 
systems, has never actually run in production.
   - `HadoopSecuredFileSystem` extends `FileSystem` without overriding 
`close()`, so on a Kerberised deployment the wrapped instance was never closed.
   - `FileIO.checkAccess` probes a loader by calling `exists()` on a throwaway 
`FileIO` and then drops it. With the cache disabled that probe creates a fully 
initialised `FileSystem`, with its connector threads, on **every** 
`FileIO.get()` call, and nothing ever closes it. This one leaks without anybody 
calling `close()` at all, so it may well be the larger half of what you are 
seeing.
   
   Out of scope, and I would rather state it than leave it implicit: the 
per-module `HadoopCompliantFileIO` copies under `paimon-filesystems` obtain 
their file systems from module-level static caches, so releasing those per 
instance needs a separate design.
   
   One behaviour change worth flagging for reviewers: `RESTTokenFileIO` keeps a 
static cache of `FileIO`s whose removal listener already calls `closeQuietly`. 
That call has been landing on the empty default `close()`; once `close()` does 
real work, a size-based eviction can release a file system another table is 
still reading through. `OSSFileIO` already carries the same exposure today, so 
this is not a new class of hazard, but it is new reach.
   
   I will link the PR here shortly.
   


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