morningman commented on PR #60709:
URL: https://github.com/apache/doris/pull/60709#issuecomment-3980274362

   **1. Type coupling in 
[ExpiringMap](cci:2://file:///Users/morningman/workspace/git/doris/fe/be-java-extensions/java-common/src/main/java/org/apache/doris/common/jni/utils/ExpiringMap.java:27:0-105:1)**
   
   
[ExpiringMap](cci:2://file:///Users/morningman/workspace/git/doris/fe/be-java-extensions/java-common/src/main/java/org/apache/doris/common/jni/utils/ExpiringMap.java:27:0-105:1)
 is a generic class `ExpiringMap<K, V>`, but the 
[remove()](cci:1://file:///Users/morningman/workspace/git/doris/fe/be-java-extensions/java-common/src/main/java/org/apache/doris/common/jni/utils/ExpiringMap.java:71:4-89:5)
 method directly checks `value instanceof UdfClassCache`. This violates the 
design principle of generic containers by coupling a general-purpose data 
structure to a specific business type. If 
[ExpiringMap](cci:2://file:///Users/morningman/workspace/git/doris/fe/be-java-extensions/java-common/src/main/java/org/apache/doris/common/jni/utils/ExpiringMap.java:27:0-105:1)
 is used to cache other types of objects in the future, this code will still 
perform unnecessary `instanceof` checks.
   
   **Suggestion**: A better approach would be to have 
[UdfClassCache](cci:2://file:///Users/morningman/workspace/git/doris/fe/be-java-extensions/java-common/src/main/java/org/apache/doris/common/jni/utils/UdfClassCache.java:28:0-49:1)
 implement the `AutoCloseable` interface, and then handle `AutoCloseable` 
values uniformly in `ExpiringMap.remove()`:
   
   ```java
   // UdfClassCache.java
   public class UdfClassCache implements AutoCloseable {
       // ... existing fields ...
       @Override
       public void close() {
           if (classLoader != null) {
               try {
                   classLoader.close();
               } catch (IOException e) {
                   LOG.warn("Failed to close ClassLoader", e);
               }
               classLoader = null;
           }
       }
   }
   
   // ExpiringMap.java - remove()
   if (value instanceof AutoCloseable) {
       try {
           ((AutoCloseable) value).close();
       } catch (Exception e) {
           LOG.warn("Failed to close cached resource: " + key, e);
       }
   }
   ```
   
   Alternatively, introduce a `RemovalListener<K, V>` callback interface so 
that 
[ExpiringMap](cci:2://file:///Users/morningman/workspace/git/doris/fe/be-java-extensions/java-common/src/main/java/org/apache/doris/common/jni/utils/ExpiringMap.java:27:0-105:1)
 delegates cleanup to the caller.
   
   **2. `classLoader` being `null` when `jarPath` is empty**
   
   In 
[getClassCache()](cci:1://file:///Users/morningman/workspace/git/doris/fe/be-java-extensions/java-udf/src/main/java/org/apache/doris/udf/BaseExecutor.java:134:4-169:5),
 when `jarPath` is empty (i.e., UDF JAR is in `custom_lib`), the system class 
loader is used via `ClassLoader.getSystemClassLoader()`, and the member 
variable `classLoader` is never assigned — it remains `null`. Then 
`cache.classLoader = classLoader;` also stores `null`. This is functionally 
correct since the system class loader should never be closed, but the intent is 
not immediately clear. Consider adding a comment to clarify this:
   
   ```java
   // When jarPath is empty, the UDF is loaded from custom_lib using the system 
class loader.
   // In this case, classLoader remains null intentionally — the system class 
loader
   // should not be closed and does not need to be cached.
   ```
   


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


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to