| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759 |
- //
- // Copyright (c) 2017-2026, Manticore Software LTD (https://manticoresearch.com)
- // Copyright (c) 2001-2016, Andrew Aksyonoff
- // Copyright (c) 2008-2016, Sphinx Technologies Inc
- // All rights reserved
- //
- // This program is free software; you can redistribute it and/or modify
- // it under the terms of the GNU General Public License. You should have
- // received a copy of the GPL license along with this program; if you
- // did not, you can find it at http://www.gnu.org/
- //
- #include "sphinxint.h"
- #include "sphinxutils.h"
- #include "sphinxplugin.h"
- // for HAVE_DLOPEN
- #include "libutils.h"
- //////////////////////////////////////////////////////////////////////////
- // TYPES
- //////////////////////////////////////////////////////////////////////////
- /// loaded plugin library
- class PluginLib_c final : public ISphRefcountedMT
- {
- protected:
- CSphString m_sName;
- void * m_pHandle; ///< handle from dlopen()
- public:
- int m_iHashedPlugins; ///< how many active g_hPlugins entries reference this handle
- bool m_bDlGlobal = false;
- PluginLib_c ( void * pHandle, const char * sName, bool bDlGlobal );
- const CSphString & GetName() const { return m_sName; }
- void * GetHandle() const { return m_pHandle; }
- protected:
- ~PluginLib_c() final;
- };
- PluginLibRefPtr_c PluginDesc_c::GetLib() const
- {
- return m_pLib;
- }
- /// plugin key
- struct PluginKey_t
- {
- PluginType_e m_eType { PLUGIN_FUNCTION };
- CSphString m_sName;
- PluginKey_t() = default;
- PluginKey_t ( PluginType_e eType, const char * sName )
- : m_eType ( eType )
- , m_sName ( sName )
- {
- m_sName.ToLower();
- }
- static int Hash ( const PluginKey_t & v )
- {
- return sphCRC32 ( v.m_sName.cstr(), v.m_sName.Length(),
- sphCRC32 ( &v.m_eType, sizeof(v.m_eType) ) );
- }
- bool operator == ( const PluginKey_t & rhs )
- {
- return m_eType==rhs.m_eType && m_sName==rhs.m_sName;
- }
- };
- //////////////////////////////////////////////////////////////////////////
- // GLOBALS
- //////////////////////////////////////////////////////////////////////////
- const char * g_dPluginTypes[PLUGIN_TOTAL] = { "udf", "ranker", "index_token_filter", "query_token_filter" };
- //////////////////////////////////////////////////////////////////////////
- static bool g_bPluginsEnabled = true; ///< is there any plugin support at all?
- static CSphString g_sPluginDir = HARDCODED_PLUGIN_DIR;
- static CSphMutex g_tPluginMutex; ///< common plugin mutex (access to lib, func and ranker hashes)
- static SmallStringHash_T<PluginLibRefPtr_c> g_hPluginLibs GUARDED_BY ( g_tPluginMutex ); ///< key is the filename (no path)
- static CSphOrderedHash<PluginDescRefPtr_c, PluginKey_t, PluginKey_t, 256> g_hPlugins GUARDED_BY ( g_tPluginMutex );
- //////////////////////////////////////////////////////////////////////////
- // PLUGIN MANAGER
- //////////////////////////////////////////////////////////////////////////
- PluginLib_c::PluginLib_c ( void * pHandle, const char * sName, bool bDlGlobal )
- {
- assert ( pHandle );
- m_pHandle = pHandle;
- m_iHashedPlugins = 0;
- m_sName = sName;
- m_sName.ToLower();
- m_bDlGlobal = bDlGlobal;
- }
- PluginLib_c::~PluginLib_c()
- {
- #if HAVE_DLOPEN
- int iRes = dlclose ( m_pHandle );
- sphLogDebug ( "dlclose(%s)=%d", m_sName.cstr(), iRes );
- #endif
- }
- PluginDesc_c::PluginDesc_c ( PluginLibRefPtr_c pLib )
- {
- assert ( pLib );
- m_pLib = std::move (pLib);
- }
- PluginDesc_c::~PluginDesc_c() {}
- const CSphString & PluginDesc_c::GetLibName() const
- {
- assert ( m_pLib );
- return m_pLib->GetName();
- }
- //////////////////////////////////////////////////////////////////////////
- static bool SetPluginDir ( const char * sDir, CSphString & sPlugin )
- {
- bool bEmpty = ( !sDir || !*sDir );
- if ( !bEmpty )
- {
- if ( sphDirExists ( sDir, nullptr ) )
- {
- sPlugin = sDir;
- return true;
- }
- }
- if ( sphDirExists ( HARDCODED_PLUGIN_DIR, nullptr ) )
- {
- sPlugin = HARDCODED_PLUGIN_DIR;
- return true;
- } else
- {
- #if _WIN32
- CSphString sWinInstall = GetWinInstallDir();
- if ( !sWinInstall.IsEmpty() )
- {
- CSphString sWinInstallPlugin;
- sWinInstallPlugin.SetSprintf ( "%s/%s", sWinInstall.cstr(), HARDCODED_PLUGIN_DIR );
- if ( sphDirExists ( sWinInstallPlugin, nullptr ) )
- {
- sPlugin = sWinInstallPlugin;
- return true;
- }
- }
- #endif
- }
- return false;
- }
- void sphPluginInit ( const char * sDir )
- {
- g_bPluginsEnabled = SetPluginDir ( sDir, g_sPluginDir );
- }
- const CSphString & PluginGetDir()
- {
- return g_sPluginDir;
- }
- bool sphPluginParseSpec ( const CSphString & sParams, StrVec_t & dParams, CSphString & sError )
- {
- dParams.Resize ( 0 );
- sphSplit ( dParams, sParams.cstr(), ":" );
- switch ( dParams.GetLength() )
- {
- case 0:
- return true;
- case 1:
- sError = "filter name required in spec string; example: \"plugins.so:myfilter\"";
- return false;
- case 2:
- dParams.Add ( "" );
- return true;
- case 3:
- return true;
- }
- sError = "too many parts in spec string; must be in \"plugins.so:myfilter:options\" format";
- return false;
- }
- struct SymbolDesc_t
- {
- int m_iOffsetOf; ///< pointer member location in the descriptor structure
- const char * m_sPostfix; ///< symbol name postfix
- bool m_bRequired; ///< whether this symbol must be present
- };
- #if HAVE_DLOPEN
- static bool PluginLoadSymbols ( void * pDesc, const SymbolDesc_t * pSymbol, void * pHandle, const char * sName, CSphString & sError )
- {
- // sError = "no dlopen(), no plugins";
- // return false;
- CSphString s;
- while ( pSymbol->m_iOffsetOf>=0 )
- {
- s.SetSprintf ( pSymbol->m_sPostfix[0] ? "%s_%s" : "%s%s", sName, pSymbol->m_sPostfix );
- auto ** ppFunc = (void**)((BYTE*)pDesc + pSymbol->m_iOffsetOf);
- *ppFunc = dlsym ( pHandle, s.cstr() );
- if ( !*ppFunc && pSymbol->m_bRequired )
- {
- sError.SetSprintf ( "symbol %s() not found", s.cstr() );
- return false;
- }
- pSymbol++;
- }
- return true;
- }
- #endif // HAVE_DLOPEN
- #if !_WIN32
- #ifndef offsetof
- #define offsetof(T, M) \
- (reinterpret_cast<char*>(&(((T*)1000)->M)) - reinterpret_cast<char*>(1000))
- #endif
- #endif
- #if HAVE_DLOPEN
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Winvalid-offsetof"
- #endif
- static SymbolDesc_t g_dSymbolsUDF[] =
- {
- { static_cast<int>( offsetof(PluginUDF_c, m_fnInit)), "init", false },
- { static_cast<int>( offsetof(PluginUDF_c, m_fnFunc)), "", true },
- { static_cast<int>( offsetof(PluginUDF_c, m_fnDeinit)), "deinit", false },
- { -1, nullptr, false }
- };
- static SymbolDesc_t g_dSymbolsRanker[] =
- {
- { static_cast<int>( offsetof(PluginRanker_c, m_fnInit)), "init", false },
- { static_cast<int>( offsetof(PluginRanker_c, m_fnUpdate)), "update", false },
- { static_cast<int>( offsetof(PluginRanker_c, m_fnFinalize)), "finalize", true },
- { static_cast<int>( offsetof(PluginRanker_c, m_fnDeinit)), "deinit", false },
- { -1, nullptr, false }
- };
- static SymbolDesc_t g_dSymbolsTokenFilter[] =
- {
- { static_cast<int>( offsetof(PluginTokenFilter_c, m_fnInit)), "init", false },
- { static_cast<int>( offsetof(PluginTokenFilter_c, m_fnBeginDocument)), "begin_document", false },
- { static_cast<int>( offsetof(PluginTokenFilter_c, m_fnBeginField)), "begin_field", false },
- { static_cast<int>( offsetof(PluginTokenFilter_c, m_fnPushToken)), "push_token", true },
- { static_cast<int>( offsetof(PluginTokenFilter_c, m_fnGetExtraToken)), "get_extra_token", false },
- { static_cast<int>( offsetof(PluginTokenFilter_c, m_fnEndField)), "end_field", false },
- { static_cast<int>( offsetof(PluginTokenFilter_c, m_fnDeinit)), "deinit", false },
- { static_cast<int>( offsetof(PluginTokenFilter_c, m_fnTokenIsBlended)), "is_blended", false },
- { static_cast<int>( offsetof(PluginTokenFilter_c, m_fnTokenIsBlendedPart)), "is_blended_part", false },
- { -1, nullptr, false }
- };
- static SymbolDesc_t g_dSymbolsQueryTokenFilter[] =
- {
- { static_cast<int>( offsetof(PluginQueryTokenFilter_c, m_fnInit)), "init", false },
- { static_cast<int>( offsetof(PluginQueryTokenFilter_c, m_fnPreMorph)), "pre_morph", false },
- { static_cast<int>( offsetof(PluginQueryTokenFilter_c, m_fnPostMorph)), "post_morph", false },
- { static_cast<int>( offsetof(PluginQueryTokenFilter_c, m_fnPushToken)), "push_token", false },
- { static_cast<int>( offsetof(PluginQueryTokenFilter_c, m_fnDeinit)), "deinit", false },
- { -1, nullptr, false }
- };
- void PluginLog ( const char * szMsg, int iLen )
- {
- if ( iLen<0 )
- sphWarning ( "PLUGIN: %s", szMsg );
- else
- sphWarning ( "PLUGIN: %.*s", (int) iLen, szMsg );
- }
- static bool PluginOnLoadLibrary ( const PluginLibRefPtr_c& pLib, CSphString & sError ) REQUIRES ( g_tPluginMutex )
- {
- // library already loaded - no need to call plugin_load function
- if ( g_hPluginLibs ( pLib->GetName() ) )
- return true;
- auto fnPluginLoad = (PluginLoad_fn) dlsym ( pLib->GetHandle(), "plugin_load" );
- if ( fnPluginLoad )
- {
- char sErrBuf [ SPH_UDF_ERROR_LEN ] = { 0 };
- if ( fnPluginLoad ( sErrBuf )!=0 )
- {
- sError = sErrBuf;
- return false;
- }
- }
- return true;
- }
- static bool PluginOnUnloadLibrary ( const PluginLibRefPtr_c& pLib, CSphString & sError )
- {
- auto fnPluginUnload = (PluginLoad_fn) dlsym ( pLib->GetHandle(), "plugin_unload" );
- if ( fnPluginUnload )
- {
- char sErrBuf [ SPH_UDF_ERROR_LEN ] = { 0 };
- if ( fnPluginUnload ( sErrBuf )!=0 )
- {
- sError = sErrBuf;
- return false;
- }
- }
- return true;
- }
- static PluginLibRefPtr_c LoadPluginLibrary ( const char * sLibName, CSphString & sError, bool bDlGlobal, bool bLinuxReload )
- {
- CSphString sTmpfile;
- CSphString sLibfile;
- sLibfile.SetSprintf ( "%s/%s", g_sPluginDir.cstr(), sLibName );
- // dlopen caches the old file content, even if file was updated
- // let's reload library from the temporary file to invalidate the cache
- if ( bLinuxReload )
- {
- sTmpfile.SetSprintf ( "%s/%s.%u", g_sPluginDir.cstr(), sLibName, sphRand() );
- if ( sph::rename ( sLibfile.cstr(), sTmpfile.cstr() ) )
- {
- sError.SetSprintf ( "failed to rename file (src=%s, dst=%s, errno=%d, error=%s)", sLibfile.cstr(), sTmpfile.cstr(), errno, strerrorm(errno) );
- return nullptr;
- }
- }
- int iFlags = ( bDlGlobal ? ( RTLD_LAZY | RTLD_GLOBAL ) : ( RTLD_LAZY | RTLD_LOCAL ) );
- void * pHandle = dlopen ( bLinuxReload ? sTmpfile.cstr() : sLibfile.cstr(), iFlags );
- if ( !pHandle )
- {
- const char * sDlerror = dlerror();
- sError.SetSprintf ( "dlopen() failed: %s", sDlerror ? sDlerror : "(null)" );
- return nullptr;
- }
- sphLogDebug ( "dlopen(%s)=%p", bLinuxReload ? sTmpfile.cstr() : sLibfile.cstr(), pHandle );
- // rename file back to the original name
- if ( bLinuxReload )
- {
- if ( sph::rename ( sTmpfile.cstr(), sLibfile.cstr() ) )
- {
- sError.SetSprintf ( "failed to rename file (src=%s, dst=%s, errno=%d, error=%s)", sTmpfile.cstr(), sLibfile.cstr(), errno, strerrorm(errno) );
- dlclose ( pHandle );
- return nullptr;
- }
- }
- CSphString sBasename = sLibName;
- const char * pDot = strchr ( sBasename.cstr(), '.' );
- if ( pDot )
- sBasename = sBasename.SubString ( 0, pDot-sBasename.cstr() );
- CSphString sTmp;
- auto fnVer = (PluginVer_fn) dlsym ( pHandle, sTmp.SetSprintf ( "%s_ver", sBasename.cstr() ).cstr() );
- if ( !fnVer )
- {
- sError.SetSprintf ( "symbol '%s_ver' not found in '%s': update your UDF implementation", sBasename.cstr(), sLibName );
- dlclose ( pHandle );
- return nullptr;
- }
- if ( fnVer() < SPH_UDF_VERSION )
- {
- sError.SetSprintf ( "library '%s' was compiled using an older version of sphinxudf.h; it needs to be recompiled", sLibName );
- dlclose ( pHandle );
- return nullptr;
- }
- auto fnLogCb = (PluginLogCb_fn) dlsym ( pHandle, sTmp.SetSprintf ( "%s_setlogcb", sBasename.cstr ()).cstr ());
- if ( fnLogCb ) {
- fnLogCb(PluginLog);
- }
- return PluginLibRefPtr_c { new PluginLib_c ( pHandle, sLibName, bDlGlobal ) };
- }
- #endif
- bool sphPluginCreate ( const char * szLib, PluginType_e eType, const char * sName, ESphAttr eUDFRetType, CSphString & sError )
- {
- return sphPluginCreate ( szLib, eType, sName, eUDFRetType, false, sError );
- }
- bool sphPluginCreate ( const char * szLib, PluginType_e eType, const char * sName, ESphAttr eUDFRetType, bool bDlGlobal, CSphString & sError )
- {
- #if !HAVE_DLOPEN
- sError = "no dlopen(), no plugins";
- return false;
- #else
- if ( !g_bPluginsEnabled )
- {
- sError = "plugin support disabled (requires a valid plugin_dir)";
- return false;
- }
- // validate library name
- for ( const char * p = szLib; *p; p++ )
- if ( *p=='/' || *p=='\\' )
- {
- sError = "restricted character (path delimiter) in a library file name";
- return false;
- }
- CSphString sLib = szLib;
- sLib.ToLower();
- // FIXME? preregister known rankers instead?
- if ( eType==PLUGIN_RANKER )
- {
- for ( int i=0; i<SPH_RANK_TOTAL; i++ )
- {
- const char * r = sphGetRankerName ( ESphRankMode(i) );
- if ( r && strcasecmp ( sName, r )==0 )
- {
- sError.SetSprintf ( "%s is a reserved ranker name", r );
- return false;
- }
- }
- }
- // from here, we need a lock (we intend to update the plugin hash)
- ScopedMutex_t tLock ( g_tPluginMutex );
- // validate function name
- PluginKey_t k ( eType, sName );
- if ( g_hPlugins(k) )
- {
- sError.SetSprintf ( "plugin '%s' already exists", k.m_sName.cstr() );
- return false;
- }
- // lookup or load library
- PluginLibRefPtr_c pLib;
- if ( g_hPluginLibs ( sLib ) )
- pLib = g_hPluginLibs [ sLib ];
- else
- pLib = LoadPluginLibrary ( sLib.cstr(), sError, bDlGlobal, false );
- if ( !pLib )
- return false;
- assert ( pLib->GetHandle() );
- if ( !PluginOnLoadLibrary ( pLib, sError ) )
- return false;
- PluginDescRefPtr_c pPlugin;
- const SymbolDesc_t * pSym = nullptr;
- switch ( eType )
- {
- case PLUGIN_RANKER: pPlugin = new PluginRanker_c ( pLib ); pSym = g_dSymbolsRanker; break;
- case PLUGIN_INDEX_TOKEN_FILTER: pPlugin = new PluginTokenFilter_c ( pLib ); pSym = g_dSymbolsTokenFilter; break;
- case PLUGIN_QUERY_TOKEN_FILTER: pPlugin = new PluginQueryTokenFilter_c ( pLib ); pSym = g_dSymbolsQueryTokenFilter; break;
- case PLUGIN_FUNCTION: pPlugin = new PluginUDF_c ( pLib, eUDFRetType ); pSym = g_dSymbolsUDF; break;
- default:
- sError.SetSprintf ( "INTERNAL ERROR: unknown plugin type %d in CreatePlugin()", (int)eType );
- return false;
- }
- if ( !PluginLoadSymbols ( pPlugin, pSym, pLib->GetHandle(), k.m_sName.cstr(), sError ) )
- {
- sError.SetSprintf ( "%s in %s", sError.cstr(), sLib.cstr() );
- return false;
- }
- // add library if needed
- if ( !g_hPluginLibs ( sLib ) )
- Verify ( g_hPluginLibs.Add ( pLib, pLib->GetName() ) );
- // add function
- Verify ( g_hPlugins.Add ( pPlugin, k ) );
- ++pPlugin->GetLib()->m_iHashedPlugins;
- return true;
- #endif // HAVE_DLOPEN
- }
- bool sphPluginDrop ( PluginType_e eType, const char * sName, CSphString & sError )
- {
- #if !HAVE_DLOPEN
- sError = "no dlopen(), no plugins";
- return false;
- #else
- ScopedMutex_t tLock ( g_tPluginMutex );
- PluginKey_t tKey ( eType, sName );
- PluginDescRefPtr_c* ppPlugin = g_hPlugins(tKey);
- if ( !ppPlugin || !*ppPlugin )
- {
- sError.SetSprintf ( "plugin '%s' does not exist", sName );
- return false;
- }
- PluginLibRefPtr_c pLib = ( *ppPlugin )->GetLib();
- Verify ( g_hPlugins.Delete(tKey) );
- bool bUnloaded = true;
- if ( --pLib->m_iHashedPlugins==0 )
- {
- bUnloaded = PluginOnUnloadLibrary ( pLib, sError );
- g_hPluginLibs.Delete ( pLib->GetName() );
- }
- return bUnloaded;
- #endif // HAVE_DLOPEN
- }
- bool sphPluginReload ( const char * sName, CSphString & sError )
- {
- #if !HAVE_DLOPEN
- sError = "no dlopen(), no plugins";
- return false;
- #else
- // find all plugins from the given library
- ScopedMutex_t tLock ( g_tPluginMutex );
- CSphVector<PluginKey_t> dKeys;
- CSphVector<PluginDescRefPtr_c> dPlugins;
- bool bDlGlobal = false;
- for ( const auto& tPlugin : g_hPlugins )
- {
- PluginDescRefPtr_c v = tPlugin.second;
- if ( v->GetLibName()==sName )
- {
- dKeys.Add ( tPlugin.first );
- dPlugins.Add ( v );
- bDlGlobal = v->GetLib()->m_bDlGlobal;
- }
- }
- // no plugins loaded? oops
- if ( dPlugins.GetLength()==0 )
- {
- sError.SetSprintf ( "no active plugins loaded from %s", sName );
- return false;
- }
- // load new library and check every plugin
- PluginLibRefPtr_c pNewLib = LoadPluginLibrary ( sName, sError, bDlGlobal,
- #if !_WIN32
- true
- #else
- false
- #endif
- );
- if ( !pNewLib )
- return false;
- // load all plugins
- CSphVector<PluginDescRefPtr_c> dNewPlugins;
- ARRAY_FOREACH ( i, dPlugins )
- {
- PluginDescRefPtr_c pDesc;
- const SymbolDesc_t * pSym = nullptr;
- switch ( dKeys[i].m_eType )
- {
- case PLUGIN_RANKER: pDesc = new PluginRanker_c ( pNewLib ); pSym = g_dSymbolsRanker; break;
- case PLUGIN_INDEX_TOKEN_FILTER: pDesc = new PluginTokenFilter_c ( pNewLib ); pSym = g_dSymbolsTokenFilter; break;
- case PLUGIN_QUERY_TOKEN_FILTER: pDesc = new PluginQueryTokenFilter_c ( pNewLib ); pSym = g_dSymbolsQueryTokenFilter; break;
- case PLUGIN_FUNCTION: pDesc = new PluginUDF_c ( pNewLib, dPlugins[i]->GetUdfRetType() ); pSym = g_dSymbolsUDF; break;
- default:
- sphDie ( "INTERNAL ERROR: unknown plugin type %d in sphPluginReload()", (int)dKeys[i].m_eType );
- return false;
- }
- if ( !PluginLoadSymbols ( pDesc, pSym, pNewLib->GetHandle(), dKeys[i].m_sName.cstr(), sError ) )
- break;
- dNewPlugins.Add ( pDesc );
- }
- // if there was a problem loading any of the plugins, time to fail
- if ( dPlugins.GetLength()!=dNewPlugins.GetLength() )
- {
- sError.SetSprintf ( "failed to import plugin %s: %s", dKeys [ dNewPlugins.GetLength() ].m_sName.cstr(), sError.cstr() );
- return false;
- }
- // unregister and release the old references
- PluginLibRefPtr_c pOldLib = dPlugins[0]->GetLib();
- ARRAY_FOREACH ( i, dPlugins )
- {
- assert ( dPlugins[i]->GetLib()==pOldLib );
- Verify ( g_hPlugins.Delete ( dKeys[i] ) );
- }
- assert ( pOldLib->m_iHashedPlugins==dPlugins.GetLength() );
- pOldLib->m_iHashedPlugins = 0;
- PluginOnUnloadLibrary ( pOldLib, sError );
- Verify ( g_hPluginLibs.Delete ( pOldLib->GetName() ) );
- if ( !PluginOnLoadLibrary ( pNewLib, sError ) )
- return false;
- // register new references
- g_hPluginLibs.Add ( pNewLib, pNewLib->GetName() );
- ARRAY_FOREACH ( i, dNewPlugins )
- Verify ( g_hPlugins.Add ( dNewPlugins[i], dKeys[i] ) );
- assert ( pNewLib->m_iHashedPlugins==0 );
- pNewLib->m_iHashedPlugins = dNewPlugins.GetLength();
- sphLogDebug ( "reloaded %d plugins", dNewPlugins.GetLength() );
- return true;
- #endif // HAVE_DLOPEN
- }
- PluginDescRefPtr_c PluginAcquireDesc ( const char * szLib, PluginType_e eType, const char * szName, CSphString & sError )
- {
- PluginDescRefPtr_c pDesc = PluginGetDesc ( eType, szName );
- if ( !pDesc )
- {
- if ( !sphPluginCreate ( szLib, eType, szName, SPH_ATTR_NONE, false, sError ) )
- return nullptr;
- return PluginGetDesc ( eType, szName );
- }
- CSphString sLib ( szLib );
- sLib.ToLower();
- if ( pDesc->GetLibName()==sLib )
- return pDesc;
- sError.SetSprintf ( "unable to load plugin '%s' from '%s': it has already been loaded from library '%s'",
- szName, sLib.cstr(), pDesc->GetLibName().cstr() );
- return nullptr;
- }
- static const char * UdfReturnType ( ESphAttr eType )
- {
- switch ( eType )
- {
- case SPH_ATTR_INTEGER: return "INT";
- case SPH_ATTR_FLOAT: return "FLOAT";
- case SPH_ATTR_STRINGPTR: return "STRING";
- case SPH_ATTR_BIGINT: return "BIGINT";
- default: assert ( 0 && "unknown UDF return type" ); return "???";
- }
- }
- void sphPluginSaveState ( CSphWriter & tWriter )
- {
- ScopedMutex_t tLock ( g_tPluginMutex );
- for ( const auto& tPlugin : g_hPlugins )
- {
- const PluginKey_t & k = tPlugin.first;
- const PluginDescRefPtr_c v = tPlugin.second;
- CSphString sBuf;
- if ( k.m_eType==PLUGIN_FUNCTION )
- sBuf.SetSprintf ( "CREATE FUNCTION %s RETURNS %s SONAME '%s';\n", k.m_sName.cstr(),
- UdfReturnType ( ((PluginUDF_c*)v.Ptr())->m_eRetType ), v->GetLibName().cstr() );
- else
- sBuf.SetSprintf ( "CREATE PLUGIN %s TYPE '%s' SONAME '%s';\n",
- k.m_sName.cstr(), g_dPluginTypes[k.m_eType], v->GetLibName().cstr() );
- tWriter.PutBytes ( sBuf.cstr(), sBuf.Length() );
- }
- }
- PluginType_e sphPluginGetType ( const CSphString & s )
- {
- if ( s=="ranker" ) return PLUGIN_RANKER;
- if ( s=="index_token_filter" ) return PLUGIN_INDEX_TOKEN_FILTER;
- if ( s=="query_token_filter" ) return PLUGIN_QUERY_TOKEN_FILTER;
- return PLUGIN_TOTAL;
- }
- bool sphPluginExists ( PluginType_e eType, const char * sName )
- {
- if ( !g_bPluginsEnabled )
- return false;
- ScopedMutex_t tLock ( g_tPluginMutex );
- PluginKey_t k ( eType, sName );
- PluginDescRefPtr_c* pp = g_hPlugins(k);
- return pp && *pp;
- }
- PluginDescRefPtr_c PluginGetDesc ( PluginType_e eType, const char * sName )
- {
- if ( !g_bPluginsEnabled )
- return nullptr;
- ScopedMutex_t tLock ( g_tPluginMutex );
- PluginKey_t k ( eType, sName );
- PluginDescRefPtr_c* pp = g_hPlugins(k);
- if ( !pp || !*pp )
- return nullptr;
- return *pp;
- }
- void sphPluginList ( CSphVector<PluginInfo_t> & dResult )
- {
- if ( !g_bPluginsEnabled )
- return;
- ScopedMutex_t tLock ( g_tPluginMutex );
- for ( const auto& tPlugin : g_hPlugins )
- {
- const PluginKey_t & k = tPlugin.first;
- const PluginDescRefPtr_c v = tPlugin.second;
- PluginInfo_t & p = dResult.Add();
- p.m_eType = k.m_eType;
- p.m_sName = k.m_sName;
- p.m_sLib = v->GetLibName().cstr();
- p.m_iUsers = v->GetRefcount() - 1; // except the one reference from the hash itself
- if ( p.m_eType==PLUGIN_FUNCTION )
- p.m_sExtra = UdfReturnType ( ((PluginUDF_c*)v.Ptr())->m_eRetType );
- }
- }
- PluginUDF_c::PluginUDF_c ( PluginLibRefPtr_c pLib, ESphAttr eRetType )
- : PluginDesc_c ( std::move ( pLib ) )
- , m_eRetType ( eRetType )
- {}
- PluginRanker_c::PluginRanker_c ( PluginLibRefPtr_c pLib )
- : PluginDesc_c ( std::move ( pLib ) )
- {}
- PluginTokenFilter_c::PluginTokenFilter_c ( PluginLibRefPtr_c pLib )
- : PluginDesc_c ( std::move ( pLib ) )
- {}
- PluginQueryTokenFilter_c::PluginQueryTokenFilter_c ( PluginLibRefPtr_c pLib )
- : PluginDesc_c ( std::move ( pLib ) )
- {}
|