Просмотр исходного кода

HPCC-25752 Roxie may crash at startup if parallel-loading R queries

Provide a way to specify which queries are to be preloaded (we may in the
future want to default this list to be empty), and add code to the R plugin to
fail if it is not preloaded.

Signed-off-by: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 4 лет назад
Родитель
Сommit
9b6444cf13

+ 34 - 0
common/dllserver/thorplugin.cpp

@@ -846,6 +846,40 @@ void SafePluginMap::loadFromList(const char * pluginsList)
     }
 }
 
+bool SafePluginMap::loadNamed(const char * pluginDirectories, const char * plugin)
+{
+    const char *pluginDir = pluginDirectories;
+    for (;*pluginDir;)
+    {
+        StringBuffer thisFile;
+        while (*pluginDir && *pluginDir != ENVSEPCHAR)
+            thisFile.append(*pluginDir++);
+        if(*pluginDir)
+            pluginDir++;
+
+        if(!thisFile.length())
+            continue;
+        Owned<IFile> dir = createIFile(thisFile);
+        if (dir->isDirectory() == fileBool::foundYes)
+        {
+            Owned<IFile> file = createIFile(addPathSepChar(thisFile).append(plugin));
+            if (file->exists())
+            {
+                if (addPlugin(thisFile, plugin))
+                    return true;
+            }
+        }
+        else if (dir->isFile() == fileBool::foundYes)
+        {
+            StringBuffer tail;
+            splitFilename(thisFile, NULL, NULL, &tail, &tail);
+            if (streq(tail, plugin) && addPlugin(thisFile, plugin))
+                return true;
+        }
+    }
+    return false;
+}
+
 void SafePluginMap::loadFromDirectory(const char * pluginDirectory)
 {
     const char * mask = "*" SharedObjectExtension;

+ 2 - 0
common/dllserver/thorplugin.hpp

@@ -91,6 +91,8 @@ public:
     bool addPlugin(const char *path, const char *dllname);
     void loadFromList(const char * pluginsList);
     void loadFromDirectory(const char * pluginDirectory);
+    bool loadNamed(const char * pluginDirectories, const char * plugin);
+
 };
 
 #endif // THORPLUGIN_HPP

+ 5 - 0
helm/hpcc/values.schema.json

@@ -720,6 +720,11 @@
         "logging": {
           "$ref": "#/definitions/logging"
         },
+        "preload": {
+          "description": "Preloaded plugins",
+          "type": "array",
+          "items": { "type": "string" }
+        },
         "services": {
           "description": "Roxie query services",
           "type": "array",

+ 4 - 0
plugins/Rembed/Rembed.cpp

@@ -218,7 +218,11 @@ static RGlobalState *queryGlobalState()
 {
     CriticalBlock b(RCrit);
     if (!globalState)
+    {
+        if (!isMainThread())
+            FAIL("R embed support must be loaded or preloaded on main thread");
         globalState = new RGlobalState;
+    }
     return globalState;
 }
 

+ 16 - 1
roxie/ccd/ccdstate.cpp

@@ -2896,7 +2896,22 @@ extern void loadPlugins()
     if (pluginDirectory.length())
     {
         plugins = new SafePluginMap(&PluginCtx, traceLevel >= 1);
-        plugins->loadFromList(pluginDirectory);
+        if (topology->hasProp("preload"))
+        {
+            Owned<IPropertyTreeIterator> preloads = topology->getElements("preload");
+            ForEach(*preloads)
+            {
+                const char *preload = preloads->query().queryProp(".");
+                if (!streq(preload, "none"))
+                {
+                    VStringBuffer soname(SharedObjectPrefix "%s" SharedObjectExtension, preload);
+                    if (!plugins->loadNamed(pluginDirectory, soname))
+                        DBGLOG("Could not preload plugin %s at any of the following locations: %s", soname.str(), pluginDirectory.str());
+                }
+            }
+        }
+        else
+            plugins->loadFromList(pluginDirectory);
     }
 }
 

+ 5 - 0
system/jlib/jthread.cpp

@@ -54,6 +54,11 @@ static struct MainThreadIdHelper
     }
 } mainThreadIdHelper;
 
+extern bool isMainThread()
+{
+    return GetCurrentThreadId() == mainThreadIdHelper.tid;
+}
+
 /*
  * NB: Thread termination hook functions are tracked using a thread local vector (threadTermHooks).
  * However, hook functions installed on the main thread must be tracked separately in a non thread local vector (mainThreadTermHooks).

+ 1 - 1
system/jlib/jthread.hpp

@@ -44,7 +44,7 @@ interface jlib_decl IThreadName
 };
 
 
-
+extern jlib_decl bool isMainThread();
 extern jlib_decl void addThreadExceptionHandler(IExceptionHandler *handler);
 extern jlib_decl void removeThreadExceptionHandler(IExceptionHandler *handler);
 extern jlib_decl void enableThreadSEH();