You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2020/04/09 15:04:40 UTC

[incubator-doris] branch master updated: [Bug] Fix some bugs of install/uninstall plugins (#3267)

This is an automated email from the ASF dual-hosted git repository.

morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git


The following commit(s) were added to refs/heads/master by this push:
     new ce1d5ab  [Bug] Fix some bugs of install/uninstall plugins (#3267)
ce1d5ab is described below

commit ce1d5ab9ab0461cf5c245a08825b9c999b5670f9
Author: Mingyu Chen <mo...@gmail.com>
AuthorDate: Thu Apr 9 23:04:28 2020 +0800

    [Bug] Fix some bugs of install/uninstall plugins (#3267)
    
    1. Avoid losing plugin if plugin failed to load when replaying
        When in replay process, the plugin should always be added to the plugin manager,
        even if that plugin failed to be loaded.
    
    2. `show plugin` statement should show all plugins, not only the successfully installed plugins.
    
    3. plugin's name should be unique globally and case insensitive.
    
    4. Avoid creating new instances of plugins when doing metadata checkpoint.
    
    5. Add a __builtin_ prefix for builtin plugins.
---
 .../java/org/apache/doris/catalog/Catalog.java     |   2 +-
 .../apache/doris/plugin/DynamicPluginLoader.java   |  63 ++++++--
 .../java/org/apache/doris/plugin/PluginInfo.java   |  33 ++--
 .../java/org/apache/doris/plugin/PluginLoader.java |  24 ++-
 .../java/org/apache/doris/plugin/PluginMgr.java    | 167 ++++++++++++++-------
 .../java/org/apache/doris/qe/AuditLogBuilder.java  |   3 +-
 .../java/org/apache/doris/qe/ShowExecutor.java     |  34 +----
 .../apache/doris/service/FrontendServiceImpl.java  |  13 +-
 .../org/apache/doris/plugin/PluginLoaderTest.java  |   2 +-
 .../doris/plugin/audit/AuditLoaderPlugin.java      |   2 +
 10 files changed, 227 insertions(+), 116 deletions(-)

diff --git a/fe/src/main/java/org/apache/doris/catalog/Catalog.java b/fe/src/main/java/org/apache/doris/catalog/Catalog.java
index 603cbca..38cd584 100644
--- a/fe/src/main/java/org/apache/doris/catalog/Catalog.java
+++ b/fe/src/main/java/org/apache/doris/catalog/Catalog.java
@@ -6435,7 +6435,7 @@ public class Catalog {
 
     public void replayInstallPlugin(PluginInfo pluginInfo)  {
         try {
-            pluginMgr.loadDynamicPlugin(pluginInfo);
+            pluginMgr.replayLoadDynamicPlugin(pluginInfo);
         } catch (Exception e) {
             LOG.warn("replay install plugin failed.", e);
         }
diff --git a/fe/src/main/java/org/apache/doris/plugin/DynamicPluginLoader.java b/fe/src/main/java/org/apache/doris/plugin/DynamicPluginLoader.java
index 03c0970..6302e56 100644
--- a/fe/src/main/java/org/apache/doris/plugin/DynamicPluginLoader.java
+++ b/fe/src/main/java/org/apache/doris/plugin/DynamicPluginLoader.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.plugin;
 
+import org.apache.doris.catalog.Catalog;
 import org.apache.doris.common.UserException;
 
 import org.apache.commons.io.FileUtils;
@@ -70,16 +71,24 @@ public class DynamicPluginLoader extends PluginLoader {
             return pluginInfo;
         }
 
-        if (installPath == null) {
-            // download plugin and extract
-            PluginZip zip = new PluginZip(source);
-            // generation a tmp dir to extract the zip
-            Path tmpTarget = Files.createTempDirectory(pluginDir, ".install_");
-            // for now, installPath point to the temp dir which contains all extracted files from zip file.
-            installPath = zip.extract(tmpTarget);
-        }
+        Path tmpTarget = null;
 
-        pluginInfo = PluginInfo.readFromProperties(installPath, source);
+        try {
+            if (installPath == null) {
+                // download plugin and extract
+                PluginZip zip = new PluginZip(source);
+                // generation a tmp dir to extract the zip
+                tmpTarget = Files.createTempDirectory(pluginDir, ".install_");
+                // for now, installPath point to the temp dir which contains all extracted files from zip file.
+                installPath = zip.extract(tmpTarget);
+            }
+            pluginInfo = PluginInfo.readFromProperties(installPath, source);
+        } catch (Exception e) {
+            if (tmpTarget != null) {
+                Files.delete(tmpTarget);
+            }
+            throw e;
+        }
 
         return pluginInfo;
     }
@@ -89,14 +98,14 @@ public class DynamicPluginLoader extends PluginLoader {
      */
     public void install() throws UserException, IOException {
         if (hasInstalled()) {
-            throw new UserException("Plugin " + pluginInfo.getName() + " is already install.");
+            throw new UserException("Plugin " + pluginInfo.getName() + " has already been installed.");
         }
 
         getPluginInfo();
 
         movePlugin();
 
-        plugin = dynamicLoadPlugin();
+        plugin = dynamicLoadPlugin(true);
 
         pluginInstallValid();
 
@@ -132,13 +141,23 @@ public class DynamicPluginLoader extends PluginLoader {
     }
 
     /**
-     * reload plugin if plugin has already been installed, else will re-install
+     * reload plugin if plugin has already been installed, else will re-install.
+     * Notice that this method will create a new instance of plugin.
      * 
      * @throws PluginException
      */
     public void reload() throws IOException, UserException {
+        if (Catalog.isCheckpointThread()) {
+            /*
+             * No need to reload the plugin when this is a checkpoint thread.
+             * Because this reload() method will create a new instance of plugin and try to start it.
+             * But in checkpoint thread, we do not need a instance of plugin.
+             */
+            return;
+        }
+
         if (hasInstalled()) {
-            plugin = dynamicLoadPlugin();
+            plugin = dynamicLoadPlugin(true);
             pluginInstallValid();
             pluginContext.setPluginPath(installPath.toString());
             plugin.init(pluginInfo, pluginContext);
@@ -150,7 +169,23 @@ public class DynamicPluginLoader extends PluginLoader {
         }
     }
 
-    Plugin dynamicLoadPlugin() throws IOException, UserException {
+    /*
+     * Dynamic load the plugin.
+     * if closePreviousPlugin is true, we will check if there is already an instance of plugin, if yes, close it.
+     */
+    Plugin dynamicLoadPlugin(boolean closePreviousPlugin) throws IOException, UserException {
+        if (closePreviousPlugin) {
+            if (plugin != null) {
+                try {
+                    plugin.close();
+                } catch (Exception e) {
+                    LOG.warn("failed to close previous plugin {}, ignore it", e);
+                } finally {
+                    plugin = null;
+                }
+            }
+        }
+
         Set<URL> jarList = getJarUrl(installPath);
 
         // create a child to load the plugin in this bundle
diff --git a/fe/src/main/java/org/apache/doris/plugin/PluginInfo.java b/fe/src/main/java/org/apache/doris/plugin/PluginInfo.java
index ad7e597..e617615 100644
--- a/fe/src/main/java/org/apache/doris/plugin/PluginInfo.java
+++ b/fe/src/main/java/org/apache/doris/plugin/PluginInfo.java
@@ -17,6 +17,18 @@
 
 package org.apache.doris.plugin;
 
+import org.apache.doris.common.io.Text;
+import org.apache.doris.common.io.Writable;
+import org.apache.doris.common.util.DigitalVersion;
+import org.apache.doris.persist.gson.GsonUtils;
+
+import com.google.common.base.Strings;
+import com.google.gson.annotations.SerializedName;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
@@ -29,17 +41,6 @@ import java.util.Properties;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
-import org.apache.commons.lang.StringUtils;
-import org.apache.doris.common.io.Text;
-import org.apache.doris.common.io.Writable;
-import org.apache.doris.common.util.DigitalVersion;
-import org.apache.doris.persist.gson.GsonUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Strings;
-import com.google.gson.annotations.SerializedName;
-
 public class PluginInfo implements Writable {
     public static final Logger LOG = LoggerFactory.getLogger(PluginInfo.class);
 
@@ -53,7 +54,7 @@ public class PluginInfo implements Writable {
         IMPORT,
         STORAGE;
 
-        public static int MAX_PLUGIN_SIZE = PluginType.values().length;
+        public static int MAX_PLUGIN_TYPE_SIZE = PluginType.values().length;
     }
 
     @SerializedName("name")
@@ -77,11 +78,18 @@ public class PluginInfo implements Writable {
     @SerializedName("soName")
     protected String soName;
 
+    // this source field is only used for persisting. it should be passed to the source field in 'PluginLoader',
+    // and then use 'source' in 'PluginLoader' to get the source.
     @SerializedName("source")
     protected String source;
 
     public PluginInfo() { }
 
+    // used for persisting uninstall operation
+    public PluginInfo(String name) {
+        this.name = name;
+    }
+
     public PluginInfo(String name, PluginType type, String description) {
         this.name = name;
         this.type = type;
@@ -233,5 +241,4 @@ public class PluginInfo implements Writable {
         String s = Text.readString(in);
         return GsonUtils.GSON.fromJson(s, PluginInfo.class);
     }
-
 }
diff --git a/fe/src/main/java/org/apache/doris/plugin/PluginLoader.java b/fe/src/main/java/org/apache/doris/plugin/PluginLoader.java
index e72d878..a304b4c 100644
--- a/fe/src/main/java/org/apache/doris/plugin/PluginLoader.java
+++ b/fe/src/main/java/org/apache/doris/plugin/PluginLoader.java
@@ -19,6 +19,8 @@ package org.apache.doris.plugin;
 
 import org.apache.doris.common.UserException;
 
+import com.google.common.base.Strings;
+
 import java.io.IOException;
 import java.nio.file.FileSystems;
 import java.nio.file.Path;
@@ -31,7 +33,22 @@ public abstract class PluginLoader {
         INSTALLED,
         UNINSTALLING,
         UNINSTALLED,
-        ERROR,
+        ERROR;
+
+        private String msg;
+
+        public void setMsg(String msg) {
+            this.msg = msg;
+        }
+
+        @Override
+        public String toString() {
+            if (Strings.isNullOrEmpty(msg)) {
+                return this.name();
+            } else {
+                return this.name() + ": " + msg;
+            }
+        }
     }
 
     // the root dir of Frontend plugin, should always be Config.plugin_dir
@@ -80,7 +97,12 @@ public abstract class PluginLoader {
     }
 
     public void setStatus(PluginStatus status) {
+        setStatus(status, null);
+    }
+
+    public void setStatus(PluginStatus status, String msg) {
         this.status = status;
+        this.status.setMsg(msg);
     }
 
     public PluginStatus getStatus() {
diff --git a/fe/src/main/java/org/apache/doris/plugin/PluginMgr.java b/fe/src/main/java/org/apache/doris/plugin/PluginMgr.java
index 722a5a9..83fc01b 100644
--- a/fe/src/main/java/org/apache/doris/plugin/PluginMgr.java
+++ b/fe/src/main/java/org/apache/doris/plugin/PluginMgr.java
@@ -20,6 +20,7 @@ package org.apache.doris.plugin;
 import org.apache.doris.analysis.InstallPluginStmt;
 import org.apache.doris.catalog.Catalog;
 import org.apache.doris.common.Config;
+import org.apache.doris.common.DdlException;
 import org.apache.doris.common.UserException;
 import org.apache.doris.common.io.Writable;
 import org.apache.doris.plugin.PluginInfo.PluginType;
@@ -29,6 +30,7 @@ import org.apache.doris.qe.AuditLogBuilder;
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -41,17 +43,23 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 
 public class PluginMgr implements Writable {
     private final static Logger LOG = LogManager.getLogger(PluginMgr.class);
 
+    public final static String BUILTIN_PLUGIN_PREFIX = "__builtin_";
+
     private final Map<String, PluginLoader>[] plugins;
+    // all dynamic plugins should have unique names,
+    private final Set<String> dynamicPluginNames;
 
     public PluginMgr() {
-        plugins = new Map[PluginType.MAX_PLUGIN_SIZE];
-        for (int i = 0; i < PluginType.MAX_PLUGIN_SIZE; i++) {
-            plugins[i] = Maps.newConcurrentMap();
+        plugins = new Map[PluginType.MAX_PLUGIN_TYPE_SIZE];
+        for (int i = 0; i < PluginType.MAX_PLUGIN_TYPE_SIZE; i++) {
+            plugins[i] = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER);
         }
+        dynamicPluginNames = Sets.newTreeSet(String.CASE_INSENSITIVE_ORDER);
     }
 
     // create the plugin dir if missing
@@ -67,27 +75,47 @@ public class PluginMgr implements Writable {
             }
         }
 
-        registerBuiltinPlugins();
+        initBuiltinPlugins();
+    }
+
+    private boolean checkDynamicPluginNameExist(String name) {
+        synchronized (dynamicPluginNames) {
+            return dynamicPluginNames.contains(name);
+        }
+    }
+
+    private boolean addDynamicPluginNameIfAbsent(String name) {
+        synchronized (dynamicPluginNames) {
+            return dynamicPluginNames.add(name);
+        }
+    }
+
+    private boolean removeDynamicPluginName(String name) {
+        synchronized (dynamicPluginNames) {
+            return dynamicPluginNames.remove(name);
+        }
     }
 
-    private void registerBuiltinPlugins() {
+    private void initBuiltinPlugins() {
         // AuditLog
         AuditLogBuilder auditLogBuilder = new AuditLogBuilder();
-        if (!registerPlugin(auditLogBuilder.getPluginInfo(), auditLogBuilder)) {
+        if (!registerBuiltinPlugin(auditLogBuilder.getPluginInfo(), auditLogBuilder)) {
             LOG.warn("failed to register audit log builder");
         }
 
         // other builtin plugins
     }
 
+    // install a plugin from user's command.
+    // install should be successfully, or nothing should be left if failed to install.
     public PluginInfo installPlugin(InstallPluginStmt stmt) throws IOException, UserException {
         PluginLoader pluginLoader = new DynamicPluginLoader(Config.plugin_dir, stmt.getPluginPath());
         pluginLoader.setStatus(PluginStatus.INSTALLING);
 
         try {
             PluginInfo info = pluginLoader.getPluginInfo();
-
-            if (plugins[info.getTypeId()].containsKey(info.getName())) {
+            
+            if (checkDynamicPluginNameExist(info.getName())) {
                 throw new UserException("plugin " + info.getName() + " has already been installed.");
             }
             
@@ -95,48 +123,68 @@ public class PluginMgr implements Writable {
             pluginLoader.install();
             pluginLoader.setStatus(PluginStatus.INSTALLED);
             
-            if (plugins[info.getTypeId()].putIfAbsent(info.getName(), pluginLoader) != null) {
-                pluginLoader.uninstall();
+            if (!addDynamicPluginNameIfAbsent(info.getName())) {
                 throw new UserException("plugin " + info.getName() + " has already been installed.");
             }
-
+            plugins[info.getTypeId()].put(info.getName(), pluginLoader);
+            
             Catalog.getCurrentCatalog().getEditLog().logInstallPlugin(info);
-            LOG.info("install plugin = " + info.getName());
+            LOG.info("install plugin {}", info.getName());
             return info;
         } catch (IOException | UserException e) {
-            pluginLoader.setStatus(PluginStatus.ERROR);
+            pluginLoader.uninstall();
             throw e;
         }
     }
 
     /**
-     * Dynamic uninstall plugin
+     * Dynamic uninstall plugin.
+     * If uninstall failed, the plugin should NOT be removed from plugin manager.
      */
     public PluginInfo uninstallPlugin(String name) throws IOException, UserException {
-        for (int i = 0; i < PluginType.MAX_PLUGIN_SIZE; i++) {
+        if (!checkDynamicPluginNameExist(name)) {
+            throw new DdlException("Plugin " + name + " does not exist");
+        }
+
+        for (int i = 0; i < PluginType.MAX_PLUGIN_TYPE_SIZE; i++) {
             if (plugins[i].containsKey(name)) {
                 PluginLoader loader = plugins[i].get(name);
+                if (loader == null) {
+                    // this is not a atomic operation, so even if containsKey() is true,
+                    // we may still get null object by get() method
+                    continue;
+                }
 
-                if (null != loader && loader.isDynamicPlugin()) {
-                    loader.pluginUninstallValid();
-                    loader.setStatus(PluginStatus.UNINSTALLING);
-                    // uninstall plugin
-                    loader.uninstall();
-                    plugins[i].remove(name);
-
-                    loader.setStatus(PluginStatus.UNINSTALLED);
-                    return loader.getPluginInfo();
+                if (!loader.isDynamicPlugin()) {
+                    throw new DdlException("Only support uninstall dynamic plugins");
                 }
+
+                loader.pluginUninstallValid();
+                loader.setStatus(PluginStatus.UNINSTALLING);
+                // uninstall plugin
+                loader.uninstall();
+
+                // uninstall succeed, remove the plugin
+                plugins[i].remove(name);
+                loader.setStatus(PluginStatus.UNINSTALLED);
+                removeDynamicPluginName(name);
+
+                // do not get plugin info by calling loader.getPluginInfo(). That method will try to
+                // reload the plugin properties from source if this plugin is not installed successfully.
+                // Here we only need the plugin's name for persisting.
+                // TODO(cmy): This is a bad design to couple the persist info with PluginInfo, but for
+                // the compatibility, I till use this method.
+                return new PluginInfo(name);
             }
         }
 
-        return null;
+        throw new DdlException("Plugin " + name + " does not exist");
     }
 
     /**
      * For built-in Plugin register
      */
-    public boolean registerPlugin(PluginInfo pluginInfo, Plugin plugin) {
+    public boolean registerBuiltinPlugin(PluginInfo pluginInfo, Plugin plugin) {
         if (Objects.isNull(pluginInfo) || Objects.isNull(plugin) || Objects.isNull(pluginInfo.getType())
                 || Strings.isNullOrEmpty(pluginInfo.getName())) {
             return false;
@@ -148,20 +196,18 @@ public class PluginMgr implements Writable {
         return checkLoader == null;
     }
 
-    /**
-     * Load plugin:
-     * - if has already benn installed, return
-     * - if not installed, install
+    /*
+     * replay load plugin.
+     * It must add the plugin to the "plugins" and "dynamicPluginNames", even if the plugin
+     * is not loaded successfully.
      */
-    public void loadDynamicPlugin(PluginInfo info) throws IOException, UserException {
+    public void replayLoadDynamicPlugin(PluginInfo info) throws IOException, UserException {
         DynamicPluginLoader pluginLoader = new DynamicPluginLoader(Config.plugin_dir, info);
-
         try {
+            // should add to "plugins" first before loading.
             PluginLoader checkLoader = plugins[info.getTypeId()].putIfAbsent(info.getName(), pluginLoader);
-
             if (checkLoader != null) {
-                throw new UserException(
-                        "plugin " + info.getName() + " has already been installed.");
+                throw new UserException("plugin " + info.getName() + " has already been installed.");
             }
 
             pluginLoader.setStatus(PluginStatus.INSTALLING);
@@ -169,8 +215,11 @@ public class PluginMgr implements Writable {
             pluginLoader.reload();
             pluginLoader.setStatus(PluginStatus.INSTALLED);
         } catch (IOException | UserException e) {
-            pluginLoader.setStatus(PluginStatus.ERROR);
+            pluginLoader.setStatus(PluginStatus.ERROR, e.getMessage());
             throw e;
+        } finally {
+            // this is a replay process, so whether it is successful or not, add it's name.
+            addDynamicPluginNameIfAbsent(info.getName());
         }
     }
 
@@ -199,7 +248,6 @@ public class PluginMgr implements Writable {
 
     public final List<PluginInfo> getAllDynamicPluginInfo() {
         List<PluginInfo> list = Lists.newArrayList();
-
         for (Map<String, PluginLoader> map : plugins) {
             map.values().forEach(loader -> {
                 try {
@@ -215,29 +263,48 @@ public class PluginMgr implements Writable {
         return list;
     }
 
-    public final List<PluginLoader> getAllPluginLoader() {
-        List<PluginLoader> list = Lists.newArrayList();
-
+    public List<List<String>> getPluginShowInfos() {
+        List<List<String>> rows = Lists.newArrayList();
         for (Map<String, PluginLoader> map : plugins) {
-            map.values().forEach(loader -> {
+            for (Map.Entry<String, PluginLoader> entry : map.entrySet()) {
+                List<String> r = Lists.newArrayList();
+                PluginLoader loader = entry.getValue();
+
+                PluginInfo pi = null;
                 try {
-                    list.add(loader);
+                    pi = loader.getPluginInfo();
                 } catch (Exception e) {
-                    LOG.warn("load plugin from {} failed", loader.source, e);
+                    // plugin may not be loaded successfully
+                    LOG.warn("failed to get plugin info for plugin: {}", entry.getKey(), e);
+                }
+                
+                r.add(entry.getKey());
+                r.add(pi != null ? pi.getType().name() : "UNKNOWN");
+                r.add(pi != null ? pi.getDescription() : "UNKNOWN");
+                r.add(pi != null ? pi.getVersion().toString() : "UNKNOWN");
+                r.add(pi != null ? pi.getJavaVersion().toString() : "UNKNOWN");
+                r.add(pi != null ? pi.getClassName() : "UNKNOWN");
+                r.add(pi != null ? pi.getSoName() : "UNKNOWN");
+                if (Strings.isNullOrEmpty(loader.source)) {
+                    r.add("Builtin");
+                } else {
+                    r.add(loader.source);
                 }
-            });
-        }
 
-        return list;
+                r.add(loader.getStatus().toString());
+
+                rows.add(r);
+            }
+        }
+        return rows;
     }
 
     public void readFields(DataInputStream dis) throws IOException {
         int size = dis.readInt();
-
         for (int i = 0; i < size; i++) {
             try {
                 PluginInfo pluginInfo = PluginInfo.read(dis);
-                loadDynamicPlugin(pluginInfo);
+                replayLoadDynamicPlugin(pluginInfo);
             } catch (Exception e) {
                 LOG.warn("load plugin failed.", e);
             }
@@ -246,12 +313,10 @@ public class PluginMgr implements Writable {
 
     @Override
     public void write(DataOutput out) throws IOException {
+        // only need to persist dynamic plugins
         List<PluginInfo> list = getAllDynamicPluginInfo();
-
         int size = list.size();
-
         out.writeInt(size);
-
         for (PluginInfo pc : list) {
             pc.write(out);
         }
diff --git a/fe/src/main/java/org/apache/doris/qe/AuditLogBuilder.java b/fe/src/main/java/org/apache/doris/qe/AuditLogBuilder.java
index f85e26a..635bff7 100644
--- a/fe/src/main/java/org/apache/doris/qe/AuditLogBuilder.java
+++ b/fe/src/main/java/org/apache/doris/qe/AuditLogBuilder.java
@@ -27,6 +27,7 @@ import org.apache.doris.plugin.AuditPlugin;
 import org.apache.doris.plugin.Plugin;
 import org.apache.doris.plugin.PluginInfo;
 import org.apache.doris.plugin.PluginInfo.PluginType;
+import org.apache.doris.plugin.PluginMgr;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -41,7 +42,7 @@ public class AuditLogBuilder extends Plugin implements AuditPlugin {
     private PluginInfo pluginInfo;
 
     public AuditLogBuilder() {
-        pluginInfo = new PluginInfo("AuditLogBuilder", PluginType.AUDIT,
+        pluginInfo = new PluginInfo(PluginMgr.BUILTIN_PLUGIN_PREFIX + "AuditLogBuilder", PluginType.AUDIT,
                 "builtin audit logger", DigitalVersion.fromString("0.12.0"), 
                 DigitalVersion.fromString("1.8.31"), AuditLogBuilder.class.getName(), null, null);
     }
diff --git a/fe/src/main/java/org/apache/doris/qe/ShowExecutor.java b/fe/src/main/java/org/apache/doris/qe/ShowExecutor.java
index 3f2d2b2..5be3f7e 100644
--- a/fe/src/main/java/org/apache/doris/qe/ShowExecutor.java
+++ b/fe/src/main/java/org/apache/doris/qe/ShowExecutor.java
@@ -117,8 +117,6 @@ import org.apache.doris.load.LoadJob;
 import org.apache.doris.load.LoadJob.JobState;
 import org.apache.doris.load.routineload.RoutineLoadJob;
 import org.apache.doris.mysql.privilege.PrivPredicate;
-import org.apache.doris.plugin.PluginInfo;
-import org.apache.doris.plugin.PluginLoader;
 import org.apache.doris.system.Backend;
 import org.apache.doris.system.SystemInfoService;
 import org.apache.doris.transaction.GlobalTransactionMgr;
@@ -1523,37 +1521,7 @@ public class ShowExecutor {
 
     private void handleShowPlugins() throws AnalysisException {
         ShowPluginsStmt pluginsStmt = (ShowPluginsStmt) stmt;
-
-        List<PluginLoader> plugins = Catalog.getCurrentPluginMgr().getAllPluginLoader();
-
-        List<List<String>> rows = Lists.newArrayListWithCapacity(plugins.size());
-
-        for (PluginLoader p : plugins) {
-            try {
-                PluginInfo pi = p.getPluginInfo();
-
-                List<String> r = Lists.newArrayListWithCapacity(stmt.getMetaData().getColumnCount());
-                r.add(pi.getName());
-                r.add(pi.getType().name());
-                r.add(pi.getDescription());
-                r.add(pi.getVersion().toString());
-                r.add(pi.getJavaVersion().toString());
-                r.add(pi.getClassName());
-                r.add(pi.getSoName());
-                if (Strings.isNullOrEmpty(pi.getSource())) {
-                    r.add("Builtin");
-                } else {
-                    r.add(pi.getSource());
-                }
-
-                r.add(p.getStatus().name());
-
-                rows.add(r);
-            } catch (Exception e) {
-                LOG.warn("show plugins get plugin info failed.", e);
-            }
-        }
-
+        List<List<String>> rows = Catalog.getCurrentPluginMgr().getPluginShowInfos();
         resultSet = new ShowResultSet(pluginsStmt.getMetaData(), rows);
     }
 }
diff --git a/fe/src/main/java/org/apache/doris/service/FrontendServiceImpl.java b/fe/src/main/java/org/apache/doris/service/FrontendServiceImpl.java
index 7a4f446..6605c0b 100644
--- a/fe/src/main/java/org/apache/doris/service/FrontendServiceImpl.java
+++ b/fe/src/main/java/org/apache/doris/service/FrontendServiceImpl.java
@@ -26,6 +26,7 @@ import org.apache.doris.catalog.Column;
 import org.apache.doris.catalog.Database;
 import org.apache.doris.catalog.OlapTable;
 import org.apache.doris.catalog.Table;
+import org.apache.doris.catalog.Table.TableType;
 import org.apache.doris.cluster.ClusterNamespace;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.AuthenticationException;
@@ -671,7 +672,6 @@ public class FrontendServiceImpl implements FrontendService.Iface {
         Catalog catalog = Catalog.getInstance();
         String fullDbName = ClusterNamespace.getFullName(cluster, request.getDb());
         Database db = catalog.getDb(fullDbName);
-        Table table = db.getTable(request.tbl);
         if (db == null) {
             String dbName = fullDbName;
             if (Strings.isNullOrEmpty(request.getCluster())) {
@@ -680,6 +680,17 @@ public class FrontendServiceImpl implements FrontendService.Iface {
             throw new UserException("unknown database, database=" + dbName);
         }
 
+        Table table = null;
+        db.readLock();
+        try {
+            table = db.getTable(request.tbl);
+            if (table == null || table.getType() != TableType.OLAP) {
+                throw new UserException("unknown table, table=" + request.tbl);
+            }
+        } finally {
+            db.readUnlock();
+        }
+
         // begin
         long timeoutSecond = request.isSetTimeout() ? request.getTimeout() : Config.stream_load_default_timeout_second;
         return Catalog.getCurrentGlobalTransactionMgr().beginTransaction(
diff --git a/fe/src/test/java/org/apache/doris/plugin/PluginLoaderTest.java b/fe/src/test/java/org/apache/doris/plugin/PluginLoaderTest.java
index 67527fa..f97e389 100644
--- a/fe/src/test/java/org/apache/doris/plugin/PluginLoaderTest.java
+++ b/fe/src/test/java/org/apache/doris/plugin/PluginLoaderTest.java
@@ -72,7 +72,7 @@ public class PluginLoaderTest {
                     DigitalVersion.JDK_1_8_0, "plugin.PluginTest", "libtest.so", "plugin_test.jar");
 
             DynamicPluginLoader util = new DynamicPluginLoader(PluginTestUtil.getTestPathString(""), info);
-            Plugin p = util.dynamicLoadPlugin();
+            Plugin p = util.dynamicLoadPlugin(true);
 
             p.init(null, null);
             p.close();
diff --git a/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/AuditLoaderPlugin.java b/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/AuditLoaderPlugin.java
index c2d8c78..8d7fe95 100755
--- a/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/AuditLoaderPlugin.java
+++ b/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/AuditLoaderPlugin.java
@@ -77,6 +77,8 @@ public class AuditLoaderPlugin extends Plugin implements AuditPlugin {
             this.streamLoader = new DorisStreamLoader(conf);
             this.loadThread = new Thread(new LoadWorker(this.streamLoader), "audit loader thread");
             this.loadThread.start();
+
+            isInit = true;
         }
     }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org