Skip to content

Commit 62c145b

Browse files
author
Halliday, Gavin (RIS-HBE)
authored
Merge pull request #36512 from risk-hsy/campda01_risk/36493-nlp-manifest
fix(nlp): add DLL load fallback and fail fast when NLP manifest resources are missing Reviewed-by: Gordon Smith <gordon.smith@lexisnexisrisk.com> Merged-by: Gavin Halliday <gavin.halliday@lexisnexisrisk.com>
2 parents 3f27e12 + e9b3e4c commit 62c145b

3 files changed

Lines changed: 93 additions & 7 deletions

File tree

plugins/nlp/manifest.cpp

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88
#include <iostream>
99
#include <fstream>
1010

11+
namespace
12+
{
1113
std::shared_ptr<IManifest> instance;
12-
std::once_flag initFlag;
14+
std::mutex instanceMutex;
15+
}
1316

1417
class Manifest : public IManifest
1518
{
@@ -19,6 +22,47 @@ class Manifest : public IManifest
1922
Owned<IPropertyTree> manifest;
2023
StringBuffer manifestDir;
2124

25+
bool loadManifestFromDll(const char *dllname, bool resourcesOnly)
26+
{
27+
if (!dllname || !*dllname)
28+
return false;
29+
30+
if (resourcesOnly)
31+
dll.setown(queryDllServer().loadDllResources(dllname, DllLocationAnywhere));
32+
else
33+
dll.setown(queryDllServer().loadDll(dllname, DllLocationAnywhere));
34+
35+
if (!dll)
36+
return false;
37+
38+
StringBuffer xml;
39+
manifest.setown(getEmbeddedManifestXML(dll, xml) ? createPTreeFromXMLString(xml.str()) : createPTree());
40+
manifestDir.set(manifest->queryProp("@manifestDir"));
41+
return true;
42+
}
43+
44+
bool tryFallbackLoad(const char *dllname)
45+
{
46+
try
47+
{
48+
// Fallback for platforms where resource-only loading is not implemented.
49+
if (!loadManifestFromDll(dllname, false))
50+
DBGLOG("Fallback load failed for %s", dllname);
51+
return !!dll;
52+
}
53+
catch (IException *e)
54+
{
55+
VStringBuffer msg("Fallback load failed for %s", dllname);
56+
EXCLOG(e, msg.str());
57+
e->Release();
58+
}
59+
catch (...)
60+
{
61+
DBGLOG("Fallback load failed for %s", dllname);
62+
}
63+
return false;
64+
}
65+
2266
static IConstWorkUnit *getWorkunit(ICodeContext *ctx)
2367
{
2468
Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
@@ -36,12 +80,10 @@ class Manifest : public IManifest
3680
q->getQueryDllName(dllname);
3781
if (dllname.length())
3882
{
83+
bool loaded = false;
3984
try
4085
{
41-
dll.setown(queryDllServer().loadDllResources(dllname.str(), DllLocationAnywhere));
42-
StringBuffer xml;
43-
manifest.setown(getEmbeddedManifestXML(dll, xml) ? createPTreeFromXMLString(xml.str()) : createPTree());
44-
manifestDir.set(manifest->queryProp("@manifestDir"));
86+
loaded = loadManifestFromDll(dllname.str(), true);
4587
}
4688
catch (IException *e)
4789
{
@@ -53,6 +95,9 @@ class Manifest : public IManifest
5395
{
5496
DBGLOG("Failed to load %s", dllname.str());
5597
}
98+
99+
if (!loaded)
100+
tryFallbackLoad(dllname.str());
56101
}
57102
}
58103

@@ -72,8 +117,9 @@ class Manifest : public IManifest
72117

73118
static std::shared_ptr<IManifest> getInstance(ICodeContext *ctx)
74119
{
75-
std::call_once(initFlag, [ctx]()
76-
{ instance = std::shared_ptr<Manifest>(new Manifest(ctx)); });
120+
std::lock_guard<std::mutex> lock(instanceMutex);
121+
if (!instance)
122+
instance = std::shared_ptr<Manifest>(new Manifest(ctx));
77123
return instance;
78124
}
79125

@@ -144,6 +190,9 @@ class Manifest : public IManifest
144190
// --- IManifest ---
145191
virtual const char *extractResources(StringBuffer &sb) const
146192
{
193+
if (!dll)
194+
return sb.str();
195+
147196
// dll->queryManifestFiles extracts the manifest files to a tmp folder the paths as a StringArray
148197
const StringArray &resFiles = dll->queryManifestFiles("UNKNOWN", "nlp");
149198
if (resFiles.length() > 0)
@@ -161,6 +210,9 @@ class Manifest : public IManifest
161210

162211
virtual bool getResourceData(const char *partialPath, MemoryBuffer &mb) const
163212
{
213+
if (!dll)
214+
return false;
215+
164216
Linked<IPropertyTree> res = queryResourcePT(partialPath);
165217
if (!res)
166218
return false;

plugins/nlp/manifest.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
class IManifest
77
{
88
public:
9+
virtual ~IManifest() = default;
910
virtual const char *extractResources(StringBuffer &buff) const = 0; // Returns the location of the files.
1011
virtual bool getResourceData(const char *partialPath, MemoryBuffer &mb) const = 0;
1112
};

plugins/nlp/nlp.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "jexcept.hpp"
2727
#include "nlp.hpp"
2828
#include "manifest.hpp"
29+
#include "workunit.hpp"
2930

3031
#include "unicode/usearch.h"
3132
using namespace icu;
@@ -51,6 +52,8 @@ ECL_NLP_API bool getECLPluginDefinition(ECLPluginDefinitionBlock *pb)
5152
namespace nlp
5253
{
5354

55+
static constexpr int NLPERR_NO_RESOURCES_IN_MANIFEST = 20001;
56+
5457
IPluginContext *parentCtx = NULL;
5558
static CriticalSection cs;
5659
static NLPEng *nlpEng = NULL;
@@ -62,6 +65,36 @@ namespace nlp
6265
std::shared_ptr<IManifest> manifest(createIManifest(ctx));
6366
StringBuffer sb;
6467
manifest->extractResources(sb);
68+
if (sb.isEmpty())
69+
{
70+
StringAttr wuid;
71+
if (ctx)
72+
wuid.setown(ctx->getWuid());
73+
74+
StringBuffer dllName;
75+
if (wuid.length())
76+
{
77+
Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
78+
if (factory)
79+
{
80+
Owned<IConstWorkUnit> wu = factory->openWorkUnit(wuid);
81+
if (wu)
82+
{
83+
Owned<IConstWUQuery> q = wu->getQuery();
84+
if (q)
85+
{
86+
SCMStringBuffer queryDll;
87+
q->getQueryDllName(queryDll);
88+
dllName.set(queryDll.str());
89+
}
90+
}
91+
}
92+
}
93+
94+
throw makeStringExceptionV(NLPERR_NO_RESOURCES_IN_MANIFEST, "No NLP resources found in query manifest (wuid=%s, dll=%s)",
95+
wuid.length() ? wuid.get() : "<unknown>",
96+
dllName.length() ? dllName.str() : "<unknown>");
97+
}
6598
nlpEng = new NLPEng(sb.str());
6699
}
67100
}

0 commit comments

Comments
 (0)