浏览代码

gh-3157 Roxie using target cluster names to load QuerySets

Signed-off-by: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 13 年之前
父节点
当前提交
47bbbb2ae5

+ 13 - 0
initfiles/componentfiles/configxml/RoxieTopology.xsl

@@ -87,6 +87,11 @@
                     <xsl:with-param name="daliservers" select="@daliServers"/>
                 </xsl:call-template>
             </xsl:attribute>
+            <xsl:attribute name="querySets">
+                <xsl:call-template name="GetQueueNames">
+                    <xsl:with-param name="roxie" select="@name"/>
+                </xsl:call-template>
+            </xsl:attribute>
             <xsl:attribute name="pluginDirectory">
                 <xsl:variable name="path" select="translate(@pluginsPath, '/$', '\:')"/>
                 <xsl:variable name="path2">
@@ -307,4 +312,12 @@
   </xsl:if>
 </xsl:template>
 
+<xsl:template name="GetQueueNames">
+  <xsl:param name="roxie"/>
+  <xsl:for-each select="/Environment/Software/Topology/Cluster/RoxieCluster[@process=$roxie]">
+   <xsl:value-of select="../@name"/>
+   <xsl:if test="position() != last()">,</xsl:if>
+  </xsl:for-each>
+</xsl:template>
+
 </xsl:stylesheet>

+ 2 - 0
roxie/ccd/ccd.hpp

@@ -323,6 +323,8 @@ extern unsigned headRegionSize;
 extern CriticalSection ccdChannelsCrit;
 extern IPropertyTree* ccdChannels;
 extern IPropertyTree* topology;
+extern StringArray allQuerySetNames;
+
 extern bool crcResources;
 extern bool logFullQueries;
 extern bool blindLogging;

+ 5 - 12
roxie/ccd/ccddali.cpp

@@ -310,19 +310,12 @@ public:
         return ret.getClear();
     }
 
-    static const char *getPackageSetPath(StringBuffer &buf, const char *id)
+    virtual IPropertyTree *getPackageSets()
     {
-        buf.appendf("PackageSets/PackageSet[@id='%s']", id);
-        return buf.str();
-    }
-
-    virtual IPropertyTree *getPackageSet(const char *id)
-    {
-        Owned<IPropertyTree> ret = loadDaliTree("PackageSets/PackageSet", id);
+        Owned<IPropertyTree> ret = loadDaliTree("PackageSets", NULL);
         if (!ret)
         {
-            ret.setown(createPTree("PackageSet"));
-            ret->setProp("@id", id);
+            ret.setown(createPTree("PackageSets"));
         }
         return ret.getClear();
     }
@@ -514,10 +507,10 @@ public:
         return getSubscription(id, getQuerySetPath(xpath, id), notifier);
     }
 
-    virtual IDaliPackageWatcher *getPackageSetSubscription(const char *id, ISDSSubscription *notifier)
+    virtual IDaliPackageWatcher *getPackageSetsSubscription(ISDSSubscription *notifier)
     {
         StringBuffer xpath;
-        return getSubscription(id, getPackageSetPath(xpath, id), notifier);
+        return getSubscription("PackageSets", "PackageSets", notifier);
     }
 
     virtual IDaliPackageWatcher *getPackageMapSubscription(const char *id, ISDSSubscription *notifier)

+ 2 - 2
roxie/ccd/ccddali.hpp

@@ -44,8 +44,8 @@ interface IRoxieDaliHelper : extends IInterface
     virtual IConstWorkUnit *attachWorkunit(const char *wuid, ILoadedDllEntry *source) = 0;
     virtual IPropertyTree *getQuerySet(const char *id) = 0;
     virtual IDaliPackageWatcher *getQuerySetSubscription(const char *id, ISDSSubscription *notifier) = 0;
-    virtual IPropertyTree *getPackageSet(const char *id) = 0;
-    virtual IDaliPackageWatcher *getPackageSetSubscription(const char *id, ISDSSubscription *notifier) = 0;
+    virtual IPropertyTree *getPackageSets() = 0;
+    virtual IDaliPackageWatcher *getPackageSetsSubscription(ISDSSubscription *notifier) = 0;
     virtual IPropertyTree *getPackageMap(const char *id) = 0;
     virtual IDaliPackageWatcher *getPackageMapSubscription(const char *id, ISDSSubscription *notifier) = 0;
     virtual void releaseSubscription(IDaliPackageWatcher *subscription) = 0;

+ 2 - 1
roxie/ccd/ccdmain.cpp

@@ -92,6 +92,7 @@ bool roxieMulticastEnabled = true;
 IPropertyTree* topology;
 CriticalSection ccdChannelsCrit;
 IPropertyTree* ccdChannels;
+StringArray allQuerySetNames;
 
 bool crcResources;
 bool useRemoteResources;
@@ -834,7 +835,7 @@ int STARTQUERY_API start_query(int argc, const char *argv[])
 #else
         topology->addPropBool("@linuxOS", true);
 #endif
-
+        CslToStringArray(topology->queryProp("@querySets"), allQuerySetNames, true);
         if (!numChannels)
             throw MakeStringException(MSGAUD_operator, ROXIE_INVALID_TOPOLOGY, "Invalid topology file - numChannels attribute must be specified");
 

+ 36 - 32
roxie/ccd/ccdquery.cpp

@@ -117,19 +117,12 @@ public:
             return new CQueryDll(dllName, dll.getClear());
         }
     }
-    static const IQueryDll *getWorkUnitDll(const char *wuid)
+    static const IQueryDll *getWorkUnitDll(IConstWorkUnit *wu)
     {
-        Owned <IRoxieDaliHelper> daliHelper = connectToDali();
-        Owned<IConstWorkUnit> wu = daliHelper->attachWorkunit(wuid, NULL);
-        if (wu)
-        {
-            SCMStringBuffer dllName;
-            Owned<IConstWUQuery> q = wu->getQuery();
-            q->getQueryDllName(dllName);
-            return getQueryDll(dllName.str(), false);
-        }
-        else
-            return NULL;
+        SCMStringBuffer dllName;
+        Owned<IConstWUQuery> q = wu->getQuery();
+        q->getQueryDllName(dllName);
+        return getQueryDll(dllName.str(), false);
     }
     virtual HelperFactory *getFactory(const char *helperName) const
     {
@@ -157,9 +150,9 @@ extern const IQueryDll *createExeQueryDll(const char *exeName)
     return CQueryDll::getQueryDll(exeName, true);
 }
 
-extern const IQueryDll *createWuQueryDll(const char *wuid)
+extern const IQueryDll *createWuQueryDll(IConstWorkUnit *wu)
 {
-    return CQueryDll::getWorkUnitDll(wuid);
+    return CQueryDll::getWorkUnitDll(wu);
 }
 
 
@@ -174,6 +167,7 @@ extern const IQueryDll *createWuQueryDll(const char *wuid)
 class CQueryFactory : public CInterface, implements IQueryFactory, implements IResourceContext
 {
 protected:
+    IRoxieLibraryLookupContext *libraryContext;  // has linked to me
     const IRoxiePackage &package;
     Owned<const IQueryDll> dll;
     MapStringToActivityArray graphMap;
@@ -721,8 +715,8 @@ public:
     IMPLEMENT_IINTERFACE;
     unsigned channelNo;
 
-    CQueryFactory(const char *_id, const IQueryDll *_dll, const IRoxiePackage &_package, hash64_t _hashValue, unsigned _channelNo) 
-        : id(_id), package(_package), dll(_dll), channelNo(_channelNo), hashValue(_hashValue)
+    CQueryFactory(const char *_id, const IQueryDll *_dll, const IRoxiePackage &_package, hash64_t _hashValue, unsigned _channelNo, IRoxieLibraryLookupContext *_libraryContext)
+        : id(_id), package(_package), dll(_dll), channelNo(_channelNo), hashValue(_hashValue), libraryContext(_libraryContext)
     {
         package.Link();
         isSuspended = false;
@@ -746,6 +740,11 @@ public:
         package.Release();
     }
 
+    virtual IQueryFactory *lookupLibrary(const char *libraryName, unsigned expectedInterfaceHash, const IRoxieContextLogger &logctx) const
+    {
+        return libraryContext->lookupLibrary(libraryName, expectedInterfaceHash, logctx);
+    }
+
     virtual void beforeDispose()
     {
         SpinBlock b(queriesCrit);
@@ -766,10 +765,12 @@ public:
             return NULL;
     }
 
-    static hash64_t getQueryHash(const char *id, const IQueryDll *dll, const IRoxiePackage &package, const IPropertyTree *stateInfo)
+    static hash64_t getQueryHash(const char *id, const IQueryDll *dll, const IRoxiePackage &package, const IPropertyTree *stateInfo, IRoxieLibraryLookupContext *libraryContext)
     {
         hash64_t hashValue = rtlHash64VStr(dll->queryDll()->queryName(), package.queryHash());
         hashValue = rtlHash64VStr(id, hashValue);
+        if (libraryContext)  // Unit tests don't set it
+            hashValue = rtlHash64VStr(libraryContext->queryId(), hashValue);  // MORE - bit odd...
         if (stateInfo)
         {
             StringBuffer xml;
@@ -1144,7 +1145,8 @@ protected:
     }
 
 public:
-    CRoxieServerQueryFactory(const char *_id, const IQueryDll *_dll, const IRoxiePackage &_package, hash64_t _hashValue) : CQueryFactory(_id, _dll, _package, _hashValue, 0)
+    CRoxieServerQueryFactory(const char *_id, const IQueryDll *_dll, const IRoxiePackage &_package, hash64_t _hashValue, IRoxieLibraryLookupContext *_libraryContext)
+        : CQueryFactory(_id, _dll, _package, _hashValue, 0, _libraryContext)
     {
         queryStats.setown(createQueryStatsAggregator(id.get(), statsExpiryTime));
     }
@@ -1262,27 +1264,28 @@ public:
 
 };
 
-IQueryFactory *createServerQueryFactory(const char *id, const IQueryDll *dll, const IRoxiePackage &package, const IPropertyTree *stateInfo)
+extern IQueryFactory *createServerQueryFactory(const char *id, const IQueryDll *dll, const IRoxiePackage &package, const IPropertyTree *stateInfo, IRoxieLibraryLookupContext *libraryContext)
 {
     CriticalBlock b(CQueryFactory::queryCreateLock);
-    hash64_t hashValue = CQueryFactory::getQueryHash(id, dll, package, stateInfo);
+    hash64_t hashValue = CQueryFactory::getQueryHash(id, dll, package, stateInfo, libraryContext);
     IQueryFactory *cached = getQueryFactory(hashValue, 0);
     if (cached)
     {
         ::Release(dll);
         return cached;
     }
-    Owned<CRoxieServerQueryFactory> newFactory = new CRoxieServerQueryFactory(id, dll, package, hashValue);
+    Owned<CRoxieServerQueryFactory> newFactory = new CRoxieServerQueryFactory(id, dll, package, hashValue, libraryContext);
     newFactory->load(stateInfo);
     return newFactory.getClear();
 }
 
-extern IQueryFactory *createServerQueryFactoryFromWu(const char *wuid)
+extern IQueryFactory *createServerQueryFactoryFromWu(IConstWorkUnit *wu, IRoxieLibraryLookupContext *libraryContext)
 {
-    Owned<const IQueryDll> dll = createWuQueryDll(wuid);
+    Owned<const IQueryDll> dll = createWuQueryDll(wu);
     if (!dll)
         return NULL;
-    return createServerQueryFactory(wuid, dll.getClear(), queryRootPackage(), NULL); // MORE - if use a constant for id might cache better?
+    SCMStringBuffer wuid;
+    return createServerQueryFactory(wu->getWuid(wuid).str(), dll.getClear(), queryRootPackage(), NULL, libraryContext); // MORE - if use a constant for id might cache better?
 }
 
 //==============================================================================================================================================
@@ -1460,8 +1463,8 @@ class CSlaveQueryFactory : public CQueryFactory
     }
 
 public:
-    CSlaveQueryFactory(const char *_id, const IQueryDll *_dll, const IRoxiePackage &_package, hash64_t _hashValue, unsigned _channelNo)
-        : CQueryFactory(_id, _dll, _package, _hashValue, _channelNo)
+    CSlaveQueryFactory(const char *_id, const IQueryDll *_dll, const IRoxiePackage &_package, hash64_t _hashValue, unsigned _channelNo, IRoxieLibraryLookupContext *_libraryContext)
+        : CQueryFactory(_id, _dll, _package, _hashValue, _channelNo, _libraryContext)
     {
     }
 
@@ -1510,27 +1513,28 @@ public:
     }
 };
 
-IQueryFactory *createSlaveQueryFactory(const char *id, const IQueryDll *dll, const IRoxiePackage &package, unsigned channel, const IPropertyTree *stateInfo)
+IQueryFactory *createSlaveQueryFactory(const char *id, const IQueryDll *dll, const IRoxiePackage &package, unsigned channel, const IPropertyTree *stateInfo, IRoxieLibraryLookupContext *libraryContext)
 {
     CriticalBlock b(CQueryFactory::queryCreateLock);
-    hash64_t hashValue = CQueryFactory::getQueryHash(id, dll, package, stateInfo);
+    hash64_t hashValue = CQueryFactory::getQueryHash(id, dll, package, stateInfo, libraryContext);
     IQueryFactory *cached = getQueryFactory(hashValue, channel);
     if (cached)
     {
         ::Release(dll);
         return cached;
     }
-    Owned<CSlaveQueryFactory> newFactory = new CSlaveQueryFactory(id, dll, package, hashValue, channel);
+    Owned<CSlaveQueryFactory> newFactory = new CSlaveQueryFactory(id, dll, package, hashValue, channel, libraryContext);
     newFactory->load(stateInfo);
     return newFactory.getClear();
 }
 
-extern IQueryFactory *createSlaveQueryFactoryFromWu(const char *wuid, unsigned channelNo)
+extern IQueryFactory *createSlaveQueryFactoryFromWu(IConstWorkUnit *wu, unsigned channelNo, IRoxieLibraryLookupContext *libraryContext)
 {
-    Owned<const IQueryDll> dll = createWuQueryDll(wuid);
+    Owned<const IQueryDll> dll = createWuQueryDll(wu);
     if (!dll)
         return NULL;
-    return createSlaveQueryFactory(wuid, dll.getClear(), queryRootPackage(), channelNo, NULL);  // MORE - if use a constant for id might cache better?
+    SCMStringBuffer wuid;
+    return createSlaveQueryFactory(wu->getWuid(wuid).str(), dll.getClear(), queryRootPackage(), channelNo, NULL, libraryContext);  // MORE - if use a constant for id might cache better?
 }
 
 IRecordLayoutTranslator * createRecordLayoutTranslator(const char *logicalName, IDefRecordMeta const * diskMeta, IDefRecordMeta const * activityMeta)

+ 9 - 4
roxie/ccd/ccdquery.hpp

@@ -110,6 +110,8 @@ interface IQueryFactory : extends IInterface
     virtual void noteQuery(time_t startTime, bool failed, unsigned elapsed, unsigned memused, unsigned slavesReplyLen, unsigned bytesOut) = 0;
     virtual IPropertyTree *getQueryStats(time_t from, time_t to) = 0;
     virtual void getGraphNames(StringArray &ret) const = 0;
+
+    virtual IQueryFactory *lookupLibrary(const char *libraryName, unsigned expectedInterfaceHash, const IRoxieContextLogger &logctx) const = 0;
 };
 
 class ActivityArray : public CInterface
@@ -215,13 +217,16 @@ interface IQueryDll : public IInterface
 
 extern const IQueryDll *createQueryDll(const char *dllName);
 extern const IQueryDll *createExeQueryDll(const char *exeName);
+extern const IQueryDll *createWuQueryDll(IConstWorkUnit *wu);
+
+interface IRoxieLibraryLookupContext;
 
 extern IRecordLayoutTranslator *createRecordLayoutTranslator(const char *logicalName, IDefRecordMeta const * diskMeta, IDefRecordMeta const * activityMeta);
-extern IQueryFactory *createServerQueryFactory(const char *id, const IQueryDll *dll, const IRoxiePackage &package, const IPropertyTree *stateInfo);
-extern IQueryFactory *createSlaveQueryFactory(const char *id, const IQueryDll *dll, const IRoxiePackage &package, unsigned _channelNo, const IPropertyTree *stateInfo);
+extern IQueryFactory *createServerQueryFactory(const char *id, const IQueryDll *dll, const IRoxiePackage &package, const IPropertyTree *stateInfo, IRoxieLibraryLookupContext *libraryContext);
+extern IQueryFactory *createSlaveQueryFactory(const char *id, const IQueryDll *dll, const IRoxiePackage &package, unsigned _channelNo, const IPropertyTree *stateInfo, IRoxieLibraryLookupContext *libraryContext);
 extern IQueryFactory *getQueryFactory(hash64_t hashvalue, unsigned channel);
-extern IQueryFactory *createServerQueryFactoryFromWu(const char *wuid);
-extern IQueryFactory *createSlaveQueryFactoryFromWu(const char *wuid, unsigned channelNo);
+extern IQueryFactory *createServerQueryFactoryFromWu(IConstWorkUnit *wu, IRoxieLibraryLookupContext *libraryContext);
+extern IQueryFactory *createSlaveQueryFactoryFromWu(IConstWorkUnit *wu, unsigned channelNo, IRoxieLibraryLookupContext *libraryContext);
 
 inline unsigned findParentId(IPropertyTree &node)
 {

+ 13 - 3
roxie/ccd/ccdqueue.cpp

@@ -595,6 +595,7 @@ void decIbytiDelay(unsigned channel, unsigned factor = 2)
 
 static SpinLock onDemandQueriesCrit;
 static MapXToMyClass<hash64_t, hash64_t, IQueryFactory> onDemandQueryCache;
+static MapXToMyClass<hash64_t, hash64_t, IRoxieLibraryLookupContext> onDemandLibraryLookupCache;
 
 void sendUnloadMessage(hash64_t hash, const char *id, const IRoxieContextLogger &logctx)
 {
@@ -622,12 +623,14 @@ void doUnload(IRoxieQueryPacket *packet, const IRoxieContextLogger &logctx)
     hash64_t hashValue = header.queryHash;
     SpinBlock b(onDemandQueriesCrit);
     onDemandQueryCache.remove(hashValue+channelNo);
+    onDemandLibraryLookupCache.remove(hashValue+channelNo);
 }
 
-void cacheOnDemandQuery(hash64_t hashValue, unsigned channelNo, IQueryFactory *query)
+void cacheOnDemandQuery(hash64_t hashValue, unsigned channelNo, IQueryFactory *query, IRoxieLibraryLookupContext *libraryContext)
 {
     SpinBlock b(onDemandQueriesCrit);
     onDemandQueryCache.setValue(hashValue+channelNo, query);
+    onDemandLibraryLookupCache.setValue(hashValue+channelNo, libraryContext);
 }
 
 //=================================================================================
@@ -994,11 +997,18 @@ public:
         hash64_t queryHash = packet->queryHeader().queryHash;
         unsigned activityId = packet->queryHeader().activityId & ~ROXIE_PRIORITY_MASK;
         Owned<IQueryFactory> queryFactory = getQueryFactory(queryHash, channel);
+        Owned<IRoxieLibraryLookupContext> libraryContext;
         if (!queryFactory && logctx.queryWuid())
         {
-            queryFactory.setown(createSlaveQueryFactoryFromWu(logctx.queryWuid(), channel));
+            // Ensure that any library lookup is done in the correct QuerySet...
+            Owned <IRoxieDaliHelper> daliHelper = connectToDali();
+            Owned<IConstWorkUnit> wu = daliHelper->attachWorkunit(logctx.queryWuid(), NULL);
+            SCMStringBuffer target;
+            wu->getClusterName(target);
+            libraryContext.setown(globalPackageSetManager->getLibraryLookupContext(target.str()));
+            queryFactory.setown(createSlaveQueryFactoryFromWu(wu, channel, libraryContext));
             if (queryFactory)
-                cacheOnDemandQuery(queryHash, channel, queryFactory);
+                cacheOnDemandQuery(queryHash, channel, queryFactory, libraryContext);
         }
         if (!queryFactory)
         {

+ 15 - 10
roxie/ccd/ccdserver.cpp

@@ -27816,7 +27816,8 @@ public:
         }
         else
         {
-            Owned<IQueryFactory> libraryQuery = globalPackageSetManager->lookupLibrary(extra.libraryName, extra.interfaceHash, *this);
+            Owned<IQueryFactory> libraryQuery = factory->lookupLibrary(extra.libraryName, extra.interfaceHash, *this);
+            assertex(libraryQuery);
             return libraryQuery->lookupGraph("graph1", probeManager, *this, parentActivity);
         }
     }
@@ -28233,8 +28234,7 @@ public:
     virtual void debugInitialize(const char *id, const char *_queryName, bool _breakAtStart)
     {
         CBaseServerDebugContext::debugInitialize(id, _queryName, _breakAtStart);
-        Owned<IRoxieDebugSessionManager> QM = globalPackageSetManager->getRoxieDebugSessionManager();
-        QM->registerDebugId(id, this);
+        queryRoxieDebugSessionManager().registerDebugId(id, this);
     }
 
     virtual void debugTerminate()
@@ -28243,8 +28243,7 @@ public:
         assertex(running);
         currentState = DebugStateUnloaded;
         running = false;
-        Owned<IRoxieDebugSessionManager> QM = globalPackageSetManager->getRoxieDebugSessionManager();
-        QM->deregisterDebugId(debugId);
+        queryRoxieDebugSessionManager().deregisterDebugId(debugId);
         if (debuggerActive)
         {
             debuggerSem.signal(debuggerActive);
@@ -30641,7 +30640,7 @@ public:
 
         public:
             casyncfor(const char *_queryText, CascadeManager *_parent, IPropertyTree *_mergedStats, 
-                      StringBuffer &_reply, SocketEndpoint &_ep, unsigned _numChildren, const IRoxieContextLogger &_logctx) 
+                      StringBuffer &_reply, SocketEndpoint &_ep, unsigned _numChildren, const IRoxieContextLogger &_logctx)
                 : queryText(_queryText), parent(_parent), mergedStats(_mergedStats), reply(_reply), ep(_ep), numChildren(_numChildren), logctx(_logctx)
             {
             }
@@ -31290,7 +31289,14 @@ public:
         daliHelper->noteWorkunitRunning(wuid.get(), true);
         if (!wu)
             throw MakeStringException(ROXIE_DALI_ERROR, "Failed to open workunit %s", wuid.get());
-        Owned<IQueryFactory> queryFactory = createServerQueryFactoryFromWu(wuid.get());
+        // Ensure that any library lookup is done in the correct QuerySet...
+        // MORE - Not 100% sure if this is right
+        // - there's no package file resolution in play for WUs read from a queue (should there be?),
+        // but as this stands we will resolve libraries using those packages defined as loading for this QuerySet.
+        SCMStringBuffer target;
+        wu->getClusterName(target);
+        Owned<IRoxieLibraryLookupContext> libraryContext = globalPackageSetManager->getLibraryLookupContext(target.str());
+        Owned<IQueryFactory> queryFactory = createServerQueryFactoryFromWu(wu, libraryContext);
         Owned<StringContextLogger> logctx = new StringContextLogger(wuid.get());
         doMain(wu, queryFactory, *logctx);
         sendUnloadMessage(queryFactory->queryHash(), wuid.get(), *logctx);
@@ -31721,8 +31727,7 @@ readAnother:
 #else
                             throw MakeStringException(ROXIE_DEBUG_ERROR, "Debug id not specified");
 #endif
-                        Owned<IRoxieDebugSessionManager> QM = globalPackageSetManager->getRoxieDebugSessionManager();
-                        debuggerContext.setown(QM->lookupDebuggerContext(uid));
+                        debuggerContext.setown(queryRoxieDebugSessionManager().lookupDebuggerContext(uid));
                         if (!debuggerContext)
                             throw MakeStringException(ROXIE_DEBUG_ERROR, "No active query matching context %s found", uid);
                         if (!debugCmdHandler.get())
@@ -32330,7 +32335,7 @@ protected:
         package.setown(createPackage(NULL));
         ctx.setown(createSlaveContext(NULL, logctx, 0, 50*1024*1024, NULL));
         queryDll.setown(createExeQueryDll("roxie"));
-        queryFactory.setown(createServerQueryFactory("test", queryDll.getLink(), *package, NULL));
+        queryFactory.setown(createServerQueryFactory("test", queryDll.getLink(), *package, NULL, NULL));
         timer->reset();
     }
 

+ 114 - 114
roxie/ccd/ccdstate.cpp

@@ -144,7 +144,7 @@ public:
  * A particular instantiation of a roxie query (i.e. a IQueryFactory) will have a pointer to the specific IRoxiePackage within the active PackageMap
  * that is providing its environment.
  *
- * A PackageMap can also indicate the name of the QuerySet it is to load. The default QuerySet name is the same as the roxie cluster name.
+ * A PackageMap can also indicate the name of the QuerySet it applies to. If not specified, at will apply to all QuerySets on the Roxie.
  *
  * A PackageSet is a list of PackageMap id's, and is used to tell Roxie what PackageMaps to load.
  * A Roxie can have multiple PackageMap's active. When updating the data, you might:
@@ -152,19 +152,15 @@ public:
  *  - once it has loaded, mark it active, and mark the previous one as inactive
  *  - Once sure no queries in flight, unload the previous one
  *
- * If more than one are active they are searched in order by incoming queries, so adding a new one at the top of the list will effectively
- * make an existing one inactive if they use the same QuerySets and thus expose the same queries.
- *
- * by default each Roxie will load all PackageMaps that are in the PackageSet matching the cluster name. This can be overridden in the RoxieTopology
- * if you want several Roxie clusters sharing the same package set, for example
+ * Each Roxie will load all PackageMaps that are in any PackageSet whose id matches the cluster name.
  *
  * All package information is stored in Dali (and cached locally)
  *
  * <PackageSets>
- *  <PackageSet id='myroxie'>
- *   <PackageMap id='pm1b' querySet='qs1' active='true'/>  # load the querySet qs1 using the PackageMap pm1b and make it active
- *   <PackageMap id='pm1a' querySet='qs1' active='false'/> # load the querySet qs1 using the PackageMap pm1a and don't make it active
- *   <PackageMap id='pm2' querySet='qs2' active='true'/>   # load the querySet qs2 using the PackageMap pm2 and make it active
+ *  <PackageSet id='*'>                                    # use this packageset for all roxies (same as omitting id)
+ *   <PackageMap id='pm1b' querySet='qs1' active='true'/>  # Use the PackageMap pm1b for QuerySet qs1 and make it active
+ *   <PackageMap id='pm1a' querySet='qs1' active='false'/> # Use the PackageMap pm1a for QuerySet qs1 but don't make it active
+ *   <PackageMap id='pm2' querySet='dev*' active='true'/>  # Use the PackageMap pm1a for all QuerySets with names starting dev and make it active
  *  </PackageMapSet>
  * </PackageSets>
  *
@@ -595,13 +591,12 @@ class CPackageMap : public CInterface, implements IPackageMap
 {
     MapStringToMyClass<IRoxiePackage> packages;
     StringAttr packageId;
-    StringAttr querySetId;
     bool active;
     StringArray wildMatches, wildIds;
 public:
     IMPLEMENT_IINTERFACE;
-    CPackageMap(const char *_packageId, const char *_querySetId, bool _active)
-        : packageId(_packageId), querySetId(_querySetId), active(_active), packages(true)
+    CPackageMap(const char *_packageId, bool _active)
+        : packageId(_packageId), active(_active), packages(true)
     {
     }
 
@@ -626,13 +621,6 @@ public:
         }
         return NULL;
     }
-    virtual const char *queryQuerySetId() const
-    {
-        if (querySetId.length())
-            return querySetId.get();
-        else
-            return roxieName;
-    }
     virtual const char *queryPackageId() const
     {
         return packageId;
@@ -665,6 +653,7 @@ public:
 static CPackageMap *emptyPackageMap;
 static CRoxiePackage *rootPackage;
 static SpinLock emptyPackageMapCrit;
+static IRoxieDebugSessionManager *debugSessionManager;
 
 extern const IRoxiePackage &queryRootPackage()
 {
@@ -682,13 +671,14 @@ extern const IPackageMap &queryEmptyPackageMap()
 {
     SpinBlock b(emptyPackageMapCrit);
     if (!emptyPackageMap)
-        emptyPackageMap = new CPackageMap("<none>", NULL, true);
+        emptyPackageMap = new CPackageMap("<none>", true);
     return *emptyPackageMap;
 }
 
 MODULE_INIT(INIT_PRIORITY_STANDARD)
 {
     emptyPackageMap = NULL;
+    debugSessionManager = NULL;
     return true;
 }
 
@@ -696,6 +686,7 @@ MODULE_EXIT()
 {
     ::Release(emptyPackageMap); // You can't use static Owned to release anything that may own a IPropertyTree
     ::Release(rootPackage);
+    ::Release(debugSessionManager);
 }
 
 // IRoxieQuerySetManager
@@ -733,6 +724,7 @@ protected:
     MapStringToMyClass<IQueryFactory> aliases;   // Do we gain anything by having two tables?
     unsigned channelNo;
     bool active;
+    StringAttr querySetName;
 
     void addQuery(const char *id, IQueryFactory *n, hash64_t &hash)
     {
@@ -759,22 +751,27 @@ protected:
             throw MakeStringException(ROXIE_INTERNAL_ERROR, "Invalid parameters to addAlias");
     }
 
-    virtual IQueryFactory *loadQueryFromDll(const char *id, const IQueryDll *dll, const IRoxiePackage &package, const IPropertyTree *stateInfo) = 0;
+    virtual IQueryFactory *loadQueryFromDll(const char *id, const IQueryDll *dll, const IRoxiePackage &package, const IPropertyTree *stateInfo, IRoxieLibraryLookupContext *libraryContext) = 0;
 
 public:
     IMPLEMENT_IINTERFACE;
-    CRoxieQuerySetManager(unsigned _channelNo)
-        : queries(true), aliases(true), active(false)
+    CRoxieQuerySetManager(unsigned _channelNo, const char *_querySetName)
+        : queries(true), aliases(true), active(false), querySetName(_querySetName)
     {
         channelNo = _channelNo;
     }
 
+    virtual const char *queryId() const
+    {
+        return querySetName;
+    }
+
     virtual bool isActive() const
     {
         return active;
     }
 
-    virtual void load(const IPropertyTree *querySet, const IPackageMap &packages, hash64_t &hash)
+    virtual void load(const IPropertyTree *querySet, const IPackageMap &packages, hash64_t &hash, IRoxieLibraryLookupContext *libraryContext)
     {
         Owned<IPropertyTreeIterator> queryNames = querySet->getElements("Query");
         ForEach (*queryNames)
@@ -802,7 +799,7 @@ public:
                     if (!package) package = &queryRootPackage();
                 }
                 assertex(package);
-                addQuery(id, loadQueryFromDll(id, queryDll.getClear(), *package, &query), hash);
+                addQuery(id, loadQueryFromDll(id, queryDll.getClear(), *package, &query, libraryContext), hash);
             }
             catch (IException *E)
             {
@@ -942,21 +939,21 @@ class CRoxieServerQuerySetManager : public CRoxieQuerySetManager
 {
 public:
     IMPLEMENT_IINTERFACE;
-    CRoxieServerQuerySetManager()
-        : CRoxieQuerySetManager(0)
+    CRoxieServerQuerySetManager(const char *_querySetName)
+        : CRoxieQuerySetManager(0, _querySetName)
     {
     }
 
-    virtual IQueryFactory * loadQueryFromDll(const char *id, const IQueryDll *dll, const IRoxiePackage &package, const IPropertyTree *stateInfo)
+    virtual IQueryFactory * loadQueryFromDll(const char *id, const IQueryDll *dll, const IRoxiePackage &package, const IPropertyTree *stateInfo, IRoxieLibraryLookupContext *libraryContext)
     {
-        return createServerQueryFactory(id, dll, package, stateInfo);
+        return createServerQueryFactory(id, dll, package, stateInfo, libraryContext);
     }
 
 };
 
-extern IRoxieQuerySetManager *createServerManager()
+extern IRoxieQuerySetManager *createServerManager(const char *querySet)
 {
-    return new CRoxieServerQuerySetManager();
+    return new CRoxieServerQuerySetManager(querySet);
 }
 
 //===============================================================================================================
@@ -965,29 +962,24 @@ class CRoxieSlaveQuerySetManager : public CRoxieQuerySetManager
 {
 public:
     IMPLEMENT_IINTERFACE;
-    CRoxieSlaveQuerySetManager(unsigned _channelNo)
-        : CRoxieQuerySetManager(_channelNo)
+    CRoxieSlaveQuerySetManager(unsigned _channelNo, const char *_querySetName)
+        : CRoxieQuerySetManager(_channelNo, _querySetName)
     {
         channelNo = _channelNo;
     }
 
-    virtual IQueryFactory *loadQueryFromDll(const char *id, const IQueryDll *dll, const IRoxiePackage &package, const IPropertyTree *stateInfo)
+    virtual IQueryFactory *loadQueryFromDll(const char *id, const IQueryDll *dll, const IRoxiePackage &package, const IPropertyTree *stateInfo, IRoxieLibraryLookupContext *libraryContext)
     {
-        return createSlaveQueryFactory(id, dll, package, channelNo, stateInfo);
+        return createSlaveQueryFactory(id, dll, package, channelNo, stateInfo, libraryContext);
     }
 
 };
 
-extern IRoxieQuerySetManager *createSlaveResourceManager(unsigned _channel)
-{
-    return new CRoxieSlaveQuerySetManager(_channel);
-}
-
 class CRoxieSlaveQuerySetManagerSet : public CInterface, implements IRoxieQuerySetManagerSet
 {
 public:
     IMPLEMENT_IINTERFACE;
-    CRoxieSlaveQuerySetManagerSet(unsigned _numChannels)
+    CRoxieSlaveQuerySetManagerSet(unsigned _numChannels, const char *querySetName)
         : numChannels(_numChannels)
     {
         CriticalBlock b(ccdChannelsCrit);
@@ -999,7 +991,7 @@ public:
             unsigned channelNo = it->query().getPropInt("@channel", 0);
             assertex(channelNo>0 && channelNo<=numChannels);
             if (managers[channelNo-1] == NULL)
-                managers[channelNo-1] = new CRoxieSlaveQuerySetManager(channelNo);
+                managers[channelNo-1] = new CRoxieSlaveQuerySetManager(channelNo, querySetName);
             else
                 throw MakeStringException(ROXIE_INVALID_TOPOLOGY, "Invalid topology file - channel %d repeated for this slave", channelNo);
         }
@@ -1017,11 +1009,11 @@ public:
         return managers[idx];
     }
 
-    virtual void load(const IPropertyTree *querySets, const IPackageMap &packages, hash64_t &hash)
+    virtual void load(const IPropertyTree *querySets, const IPackageMap &packages, hash64_t &hash, IRoxieLibraryLookupContext *libraryContext)
     {
         for (unsigned channel = 0; channel < numChannels; channel++)
             if (managers[channel])
-                managers[channel]->load(querySets, packages, hash); // MORE - this means the hash depends on the number of channels. Is that desirable?
+                managers[channel]->load(querySets, packages, hash, libraryContext); // MORE - this means the hash depends on the number of channels. Is that desirable?
     }
 
 private:
@@ -1099,8 +1091,8 @@ class CRoxieQueryPackageManager : public CInterface
 public:
     IMPLEMENT_IINTERFACE;
 
-    CRoxieQueryPackageManager(unsigned _numChannels, const IPackageMap *_packages)
-        : numChannels(_numChannels), packages(_packages)
+    CRoxieQueryPackageManager(unsigned _numChannels, const char *_querySet, const IPackageMap *_packages)
+        : numChannels(_numChannels), packages(_packages), querySet(_querySet)
     {
         queryHash = 0;
     }
@@ -1219,6 +1211,7 @@ protected:
     Owned<const IPackageMap> packages;
     unsigned numChannels;
     hash64_t queryHash;
+    StringAttr querySet;
 };
 
 /**
@@ -1248,8 +1241,8 @@ class CRoxieDaliQueryPackageManager : public CRoxieQueryPackageManager, implemen
 
 public:
     IMPLEMENT_IINTERFACE;
-    CRoxieDaliQueryPackageManager(unsigned _numChannels, const IPackageMap *_packages)
-        : CRoxieQueryPackageManager(_numChannels, _packages)
+    CRoxieDaliQueryPackageManager(unsigned _numChannels, const IPackageMap *_packages, const char *_querySet)
+        : CRoxieQueryPackageManager(_numChannels, _querySet, _packages)
     {
         daliHelper.setown(connectToDali());
     }
@@ -1268,20 +1261,18 @@ public:
 
     virtual void load()
     {
-        const char *querySetId = packages->queryQuerySetId();
-        notifier.setown(daliHelper->getQuerySetSubscription(querySetId, this));
+        notifier.setown(daliHelper->getQuerySetSubscription(querySet, this));
         reload();
     }
 
     virtual void reload()
     {
         hash64_t newHash = numChannels;
-        const char *querySetId = packages->queryQuerySetId();
-        Owned<IPropertyTree> newQuerySet = daliHelper->getQuerySet(querySetId);
-        Owned<CRoxieSlaveQuerySetManagerSet> newSlaveManagers = new CRoxieSlaveQuerySetManagerSet(numChannels);
-        Owned<IRoxieQuerySetManager> newServerManager = createServerManager();
-        newServerManager->load(newQuerySet, *packages, newHash);
-        newSlaveManagers->load(newQuerySet, *packages, newHash);
+        Owned<IPropertyTree> newQuerySet = daliHelper->getQuerySet(querySet);
+        Owned<CRoxieSlaveQuerySetManagerSet> newSlaveManagers = new CRoxieSlaveQuerySetManagerSet(numChannels, querySet);
+        Owned<IRoxieQuerySetManager> newServerManager = createServerManager(querySet);
+        newServerManager->load(newQuerySet, *packages, newHash, newServerManager);
+        newSlaveManagers->load(newQuerySet, *packages, newHash, newServerManager);
         reloadQueryManagers(newSlaveManagers.getClear(), newServerManager.getClear(), newHash);
         clearKeyStoreCache(false);   // Allows us to fully release files we no longer need because of unloaded queries
     }
@@ -1295,8 +1286,8 @@ class CStandaloneQueryPackageManager : public CRoxieQueryPackageManager
 public:
     IMPLEMENT_IINTERFACE;
 
-    CStandaloneQueryPackageManager(unsigned _numChannels, const IPackageMap *_packages, IPropertyTree *_standaloneDll)
-        : CRoxieQueryPackageManager(_numChannels, _packages), standaloneDll(_standaloneDll)
+    CStandaloneQueryPackageManager(unsigned _numChannels, const char *_querySet, const IPackageMap *_packages, IPropertyTree *_standaloneDll)
+        : CRoxieQueryPackageManager(_numChannels, _querySet, _packages), standaloneDll(_standaloneDll)
     {
         assertex(standaloneDll);
     }
@@ -1311,14 +1302,23 @@ public:
         Owned<IPropertyTree> newQuerySet = createPTree("QuerySet");
         newQuerySet->setProp("@name", "_standalone");
         newQuerySet->addPropTree("Query", standaloneDll.getLink());
-        Owned<CRoxieSlaveQuerySetManagerSet> newSlaveManagers = new CRoxieSlaveQuerySetManagerSet(numChannels);
-        Owned<IRoxieQuerySetManager> newServerManager = createServerManager();
-        newServerManager->load(newQuerySet, *packages, newHash);
-        newSlaveManagers->load(newQuerySet, *packages, newHash);
+        Owned<CRoxieSlaveQuerySetManagerSet> newSlaveManagers = new CRoxieSlaveQuerySetManagerSet(numChannels, querySet);
+        Owned<IRoxieQuerySetManager> newServerManager = createServerManager(querySet);
+        newServerManager->load(newQuerySet, *packages, newHash, newServerManager);
+        newSlaveManagers->load(newQuerySet, *packages, newHash, newServerManager);
         reloadQueryManagers(newSlaveManagers.getClear(), newServerManager.getClear(), newHash);
     }
 };
 
+static SpinLock roxieDebugSessionManagerLock;
+extern IRoxieDebugSessionManager &queryRoxieDebugSessionManager()
+{
+    SpinBlock b(roxieDebugSessionManagerLock);
+    if (!debugSessionManager)
+        debugSessionManager = new CRoxieDebugSessionManager();
+    return *debugSessionManager;
+}
+
 class CRoxiePackageSetManager : public CInterface, implements IRoxieQueryPackageManagerSet, implements ISDSSubscription
 {
 public:
@@ -1326,7 +1326,6 @@ public:
     CRoxiePackageSetManager(const IQueryDll *_standAloneDll) :
         standAloneDll(_standAloneDll)
     {
-        debugSessionManager.setown(new CRoxieDebugSessionManager);
         daliHelper.setown(connectToDali(ROXIE_DALI_CONNECT_TIMEOUT));
     }
 
@@ -1374,23 +1373,14 @@ public:
         controlSem.signal();
     }
 
-    virtual IRoxieDebugSessionManager* getRoxieDebugSessionManager() const
-    {
-        return debugSessionManager.getLink();
-    }
-
-    virtual IQueryFactory *lookupLibrary(const char *libraryName, unsigned expectedInterfaceHash, const IRoxieContextLogger &logctx) const
+    virtual IRoxieLibraryLookupContext *getLibraryLookupContext(const char *querySet) const
     {
         CriticalBlock b(packageCrit);
         ForEachItemIn(idx, allQueryPackages)
         {
             Owned<IRoxieQuerySetManager> sm = allQueryPackages.item(idx).getRoxieServerManager();
-            if (sm->isActive())
-            {
-                IQueryFactory *query = sm->lookupLibrary(libraryName, expectedInterfaceHash, logctx);
-                if (query)
-                    return query;
-            }
+            if (sm->isActive() && strcmp(sm->queryId(), querySet)==0)
+                return sm.getClear();
         }
         return NULL;
     }
@@ -1430,10 +1420,13 @@ private:
     void reload()
     {
         CriticalBlock b(packageCrit);
-        if (standAloneDll)
-            loadStandaloneQuery(standAloneDll, numChannels);
-        else
-            createQueryPackageManagers(numChannels);
+        ForEachItemIn(idx, allQuerySetNames)
+        {
+            if (standAloneDll)
+                loadStandaloneQuery(standAloneDll, numChannels, allQuerySetNames.item(idx));
+            else
+                createQueryPackageManagers(numChannels, allQuerySetNames.item(idx));
+        }
     }
 
     void _doControlMessage(IPropertyTree *control, StringBuffer &reply, const IRoxieContextLogger &logctx)
@@ -2294,16 +2287,16 @@ private:
         throw MakeStringException(ROXIE_INVALID_INPUT, "Badly formated control query");
     }
 
-    void createQueryPackageManager(unsigned numChannels, const IPackageMap *packageMap)
+    void createQueryPackageManager(unsigned numChannels, const IPackageMap *packageMap, const char *querySet)
     {
         // Called from reload inside critical block
-        Owned<CRoxieQueryPackageManager> qpm = new CRoxieDaliQueryPackageManager(numChannels, packageMap);
+        Owned<CRoxieQueryPackageManager> qpm = new CRoxieDaliQueryPackageManager(numChannels, packageMap, querySet);
         qpm->load();
         stateHash = rtlHash64Data(sizeof(stateHash), &stateHash, qpm->getHash());
         allQueryPackages.append(*qpm.getClear());
     }
 
-    void createQueryPackageManagers(unsigned numChannels)
+    void createQueryPackageManagers(unsigned numChannels, const char *querySet)
     {
         // Called from reload inside critical block
         unsubscribe();
@@ -2314,58 +2307,65 @@ private:
         allQueryPackages.kill();
         stateHash = 0;
 
-        Owned<IDaliPackageWatcher> notifier = daliHelper->getPackageSetSubscription(roxieName, this);
+        Owned<IDaliPackageWatcher> notifier = daliHelper->getPackageSetsSubscription(this);
         if (notifier)
             notifiers.append(*notifier.getClear());
-        Owned<IPropertyTree> packageTree = daliHelper->getPackageSet(roxieName);
-        Owned<IPropertyTreeIterator> packageMaps = packageTree->getElements("PackageMap");
-        ForEach(*packageMaps)
+        Owned<IPropertyTree> packageTree = daliHelper->getPackageSets();
+        Owned<IPropertyTreeIterator> packageSets = packageTree->getElements("PackageSet");
+        ForEach(*packageSets)
         {
-            IPropertyTree &ps = packageMaps->query();
-            const char *packageId = ps.queryProp("@id");
-            if (packageId && *packageId)
-            {
-                bool isActive = ps.getPropBool("@active", true);
-                const char *querySet = ps.queryProp("@querySet");
-                if (!querySet)
-                    querySet = roxieName.str();
-                if (traceLevel)
-                    DBGLOG("Loading package map %s, querySet %s, active %s", packageId, querySet, isActive ? "true" : "false");
-                try
-                {
-                    Owned<CPackageMap> packageMap = new CPackageMap(packageId, querySet, isActive);
-                    Owned<IPropertyTree> xml = daliHelper->getPackageMap(packageId);
-                    packageMap->load(xml);
-                    createQueryPackageManager(numChannels, packageMap.getLink());
-                    notifiers.append(*daliHelper->getPackageMapSubscription(packageId, this));
-                }
-                catch (IException *E)
+            IPropertyTree &ps = packageSets->query();
+            const char *packageSetId = ps.queryProp("@id");
+            if (!packageSetId || WildMatch(roxieName, packageSetId, false))
+            {
+                Owned<IPropertyTreeIterator> packageMaps = ps.getElements("PackageMap");
+                ForEach(*packageMaps)
                 {
-                    StringBuffer msg;
-                    msg.appendf("Failed to load package map %s", packageId);
-                    EXCLOG(E, msg.str());
-                    E->Release();
+                    IPropertyTree &pm = packageMaps->query();
+                    const char *packageMapId = pm.queryProp("@id");
+                    const char *packageMapFilter = pm.queryProp("@querySet");
+                    if (packageMapId && *packageMapId && (!packageMapFilter || WildMatch(querySet, packageMapFilter, false)))
+                    {
+                        bool isActive = pm.getPropBool("@active", true);
+                        if (traceLevel)
+                            DBGLOG("Loading package map %s, active %s", packageMapId, isActive ? "true" : "false");
+                        try
+                        {
+                            Owned<CPackageMap> packageMap = new CPackageMap(packageMapId, isActive);
+                            Owned<IPropertyTree> xml = daliHelper->getPackageMap(packageMapId);
+                            packageMap->load(xml);
+                            createQueryPackageManager(numChannels, packageMap.getLink(), querySet);
+                            notifiers.append(*daliHelper->getPackageMapSubscription(packageMapId, this));
+                        }
+                        catch (IException *E)
+                        {
+                            StringBuffer msg;
+                            msg.appendf("Failed to load package map %s", packageMapId);
+                            EXCLOG(E, msg.str());
+                            E->Release();
+                        }
+                    }
                 }
             }
         }
         if (!allQueryPackages.length())
         {
             if (traceLevel)
-                DBGLOG("Loading empty package");
-            createQueryPackageManager(numChannels, LINK(&queryEmptyPackageMap()));
+                DBGLOG("Loading empty package for QuerySet %s", querySet);
+            createQueryPackageManager(numChannels, LINK(&queryEmptyPackageMap()), querySet);
         }
         if (traceLevel)
             DBGLOG("Loaded packages");
     }
 
-    void loadStandaloneQuery(const IQueryDll *standAloneDll, unsigned numChannels)
+    void loadStandaloneQuery(const IQueryDll *standAloneDll, unsigned numChannels, const char *querySet)
     {
         // Called from reload inside critical block
         Owned<IPropertyTree> standAloneDllTree;
         standAloneDllTree.setown(createPTree("Query"));
         standAloneDllTree->setProp("@id", "roxie");
         standAloneDllTree->setProp("@dll", standAloneDll->queryDll()->queryName());
-        Owned<CRoxieQueryPackageManager> qpm = new CStandaloneQueryPackageManager(numChannels, LINK(&queryEmptyPackageMap()), standAloneDllTree.getClear());
+        Owned<CRoxieQueryPackageManager> qpm = new CStandaloneQueryPackageManager(numChannels, querySet, LINK(&queryEmptyPackageMap()), standAloneDllTree.getClear());
         qpm->load();
         stateHash = rtlHash64Data(sizeof(stateHash), &stateHash, qpm->getHash());
         allQueryPackages.append(*qpm.getClear());

+ 13 - 8
roxie/ccd/ccdstate.hpp

@@ -49,7 +49,6 @@ interface IPackageMap : public IInterface
     virtual const IRoxiePackage *queryPackage(const char *name) const = 0;
     // Lookup package using fuzzy id
     virtual const IRoxiePackage *matchPackage(const char *name) const = 0;
-    virtual const char *queryQuerySetId() const = 0;
     virtual const char *queryPackageId() const = 0;
     virtual bool isActive() const = 0;
 };
@@ -100,12 +99,17 @@ interface IFileIOArray : extends IInterface
     virtual StringBuffer &getId(StringBuffer &) const = 0;
 };
 
-interface IRoxieQuerySetManager : extends IInterface
+interface IRoxieLibraryLookupContext : extends IInterface
 {
-    virtual bool isActive() const = 0;
     virtual IQueryFactory *lookupLibrary(const char * libraryName, unsigned expectedInterfaceHash, const IRoxieContextLogger &logctx) const = 0;
+    virtual const char *queryId() const = 0;
+};
+
+interface IRoxieQuerySetManager : extends IRoxieLibraryLookupContext
+{
+    virtual bool isActive() const = 0;
     virtual IQueryFactory *getQuery(const char *id, const IRoxieContextLogger &ctx) const = 0;
-    virtual void load(const IPropertyTree *querySet, const IPackageMap &packages, hash64_t &hash) = 0;
+    virtual void load(const IPropertyTree *querySet, const IPackageMap &packages, hash64_t &hash, IRoxieLibraryLookupContext *libraryContext) = 0;
     virtual void getStats(const char *queryName, const char *graphName, StringBuffer &reply, const IRoxieContextLogger &logctx) const = 0;
     virtual void resetQueryTimings(const char *queryName, const IRoxieContextLogger &logctx) = 0;
     virtual void resetAllQueryTimings() = 0;
@@ -122,19 +126,20 @@ interface IRoxieDebugSessionManager : extends IInterface
 
 interface IRoxieQuerySetManagerSet : extends IInterface
 {
-    virtual void load(const IPropertyTree *querySets, const IPackageMap &packages, hash64_t &hash) = 0;
+    virtual void load(const IPropertyTree *querySets, const IPackageMap &packages, hash64_t &hash, IRoxieLibraryLookupContext *libraryContext) = 0;
 };
 
 interface IRoxieQueryPackageManagerSet : extends IInterface
 {
     virtual void load() = 0;
     virtual void doControlMessage(IPropertyTree *xml, StringBuffer &reply, const IRoxieContextLogger &ctx) = 0;
-    virtual IRoxieDebugSessionManager* getRoxieDebugSessionManager() const = 0;
-    virtual IQueryFactory *lookupLibrary(const char *libraryName, unsigned expectedInterfaceHash, const IRoxieContextLogger &logctx) const = 0;
     virtual IQueryFactory *getQuery(const char *id, const IRoxieContextLogger &logctx) const = 0;
+    virtual IRoxieLibraryLookupContext *getLibraryLookupContext(const char *querySet) const = 0;
 };
 
-extern IRoxieQuerySetManager *createServerManager();
+extern IRoxieDebugSessionManager &queryRoxieDebugSessionManager();
+
+extern IRoxieQuerySetManager *createServerManager(const char *querySet);
 extern IRoxieQuerySetManager *createSlaveManager();
 extern IRoxieQueryPackageManagerSet *createRoxiePackageSetManager(const IQueryDll *standAloneDll);
 extern IRoxieQueryPackageManagerSet *globalPackageSetManager;