Selaa lähdekoodia

HPCC-9535 Rationalize Roxie topology info

Ensure that all components use only the information really needed - this will
be backward compatible on all environments that are internally consistent,
i.e. those generated by configmgr. Duplicate nodes in the server list will be
ignored, port information will be taken from RoxieFarmProcess nodes, and
RoxieSlaveProcess and RoxieSlave nodes will be ignored.

This commit does not update configmgr to stop it generating the additional
info (yet).

Remove the creation of the (unused, as far as I can see) 'farm' group for a
roxie when environment is loaded to Dali. All roxie schemes now generate
groups that contain all nodes, just once - as far as I can tell the previous
code would have done so for schemes other than 'full redundancy', which would
have generated a group with most of the servers missing.

Signed-off-by: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 12 vuotta sitten
vanhempi
commit
1c085ee3ed

+ 6 - 63
dali/base/dadfs.cpp

@@ -6036,23 +6036,6 @@ public:
 
 #define GROUP_CACHE_INTERVAL (1000*60)
 
-static const char *translateGroupType(GroupType groupType)
-{
-    switch (groupType)
-    {
-        case grp_thor:
-            return "Thor";
-        case grp_roxie:
-            return "Roxie";
-        case grp_roxiefarm:
-            return "RoxieFarm";
-        case grp_hthor:
-            return "hthor";
-        default:
-            return NULL;
-    }
-}
-
 static GroupType translateGroupType(const char *groupType)
 {
     if (!groupType)
@@ -6061,8 +6044,6 @@ static GroupType translateGroupType(const char *groupType)
         return grp_thor;
     else if (strieq(groupType, "Roxie"))
         return grp_roxie;
-    else if (strieq(groupType, "RoxieFarm"))
-        return grp_roxiefarm;
     else if (strieq(groupType, "hthor"))
         return grp_hthor;
     else
@@ -7762,9 +7743,6 @@ class CInitGroups
                 processName = "ThorSpareProcess";
                 break;
             case grp_roxie:
-                processName = "RoxieSlave";
-                break;
-            case grp_roxiefarm:
                 processName = "RoxieServerProcess";
                 break;
             default:
@@ -7782,7 +7760,10 @@ class CInitGroups
             }
             SocketEndpoint ep = (*m)->ep;
             switch (groupType) {
-                case grp_roxiefarm:
+                case grp_roxie:
+                // Redundant copies are located via the flags.
+                // Old environments may contain duplicated sever information for multiple ports
+                // MORE - it's not clear whether this is correct for full redundancy and overloaded clusters
                 {
                     unsigned k;
                     for (k=0;k<eps.ordinality();k++)
@@ -7792,26 +7773,6 @@ class CInitGroups
                         eps.append(ep); // just add (don't care about order and no duplicates)
                     break;
                 }
-                case grp_roxie:
-                {
-                    Owned<IPropertyTreeIterator> channels;
-                    channels.setown(node.getElements("RoxieChannel"));
-                    unsigned thisNodePrimaryChannel = 0;
-                    ForEach(*channels) {
-                        unsigned channel = channels->query().getPropInt("@number");
-                        unsigned level = channels->query().getPropInt("@level", 0);
-                        if (level == 0)  // level 0 means primary copy
-                            thisNodePrimaryChannel = channel;
-                    }
-                    if (thisNodePrimaryChannel==0) {
-                        ERRLOG("Cannot construct roxie cluster %s, no channel for node",cluster.queryProp("@name"));
-                        return NULL;
-                    }
-                    while (eps.ordinality()<thisNodePrimaryChannel)
-                        eps.append(nullep);
-                    eps.item(thisNodePrimaryChannel-1) = ep;
-                    break;
-                }
                 case grp_thor:
                 case grp_thorspares:
                     eps.append(ep);
@@ -7826,7 +7787,8 @@ class CInitGroups
         unsigned slavesPerNode = 0;
         if (grp_thor == groupType)
             slavesPerNode = cluster.getPropInt("@slavesPerNode");
-        if (slavesPerNode) {
+        if (slavesPerNode)
+        {
             SocketEndpointArray msEps;
             for (unsigned s=0; s<slavesPerNode; s++) {
                 ForEachItemIn(e, eps)
@@ -7872,9 +7834,6 @@ class CInitGroups
             case grp_roxie:
                 kind = "Roxie";
                 break;
-            case grp_roxiefarm:
-                kind = "RoxieFarm";
-                break;
             case grp_hthor:
                 kind = "hthor";
                 break;
@@ -7921,8 +7880,6 @@ class CInitGroups
             case grp_roxie:
                 gname.append(cluster.queryProp("@name"));
                 break;
-            case grp_roxiefarm:
-                break;
             default:
                 throwUnexpected();
         }
@@ -7979,19 +7936,6 @@ class CInitGroups
         }
     }
 
-    bool constructFarmGroup(IPropertyTree &cluster, IPropertyTree *oldCluster, bool force, StringBuffer &messages)
-    {
-        Owned<IPropertyTreeIterator> farms = cluster.getElements("RoxieFarmProcess");  // probably only one but...
-        bool ret = true;
-        ForEach(*farms) {
-            IPropertyTree &farm = farms->query();
-            VStringBuffer gname("%s__%s", cluster.queryProp("@name"), farm.queryProp("@name"));
-            if (!constructGroup(farm, gname, oldCluster, grp_roxiefarm, force, messages))
-                ret = false;
-        }
-        return ret;
-    }
-
     enum CgCmd { cg_null, cg_reset, cg_add, cg_remove };
 public:
 
@@ -8159,7 +8103,6 @@ public:
                     oldCluster = oldEnvironment->queryPropTree(xpath.str());
                 }
                 constructGroup(cluster,NULL,oldCluster,grp_roxie,force,messages);
-                constructFarmGroup(clusters->query(),oldCluster,force,messages);
             }
             clusters.setown(root->getElements("EclAgentProcess"));
             ForEach(*clusters) {

+ 1 - 1
dali/base/dadfs.hpp

@@ -570,7 +570,7 @@ extern da_decl IDistributedFileDirectory &queryDistributedFileDirectory();
 
 // ==GROUP STORE=================================================================================================
 
-enum GroupType { grp_thor, grp_thorspares, grp_roxie, grp_roxiefarm, grp_hthor, grp_unknown };
+enum GroupType { grp_thor, grp_thorspares, grp_roxie, grp_hthor, grp_unknown };
 
 interface INamedGroupIterator: extends IInterface
 {

+ 0 - 2
deployment/configgen/main.cpp

@@ -532,8 +532,6 @@ int processRequest(const char* in_cfgname, const char* out_dirname, const char*
               isMaster = true;
               out.appendf("%s=%s;%s%c%s;%s\n", pComponent->queryProp("@name"), pComponent->queryProp("@buildSet"), out_dirname, PATHSEPCHAR, pComponent->queryProp("@name"),"master");
             }
-            else if (!strcmp(instName.toCharArray(), "RoxieSlaveProcess"))
-              sbChildren.appendf("%s=%s;%s%c%s;%s\n", pComponent->queryProp("@name"), pComponent->queryProp("@buildSet"), out_dirname, PATHSEPCHAR, pComponent->queryProp("@name"),"slave");
           }
 
           if (!isMaster)

+ 2 - 2
deployment/deploy/deploy.cpp

@@ -1136,7 +1136,7 @@ IPropertyTree* getInstances(const IPropertyTree* pEnvRoot, const char* compName,
 {
   Owned<IPropertyTree> pSelComps(createPTree("SelectedComponents"));
   Owned<IPropertyTreeIterator> iter = pEnvRoot->getElements("Software/*");
-  const char* instanceNodeNames[] = { "Instance", "RoxieServerProcess", "RoxieSlaveProcess" };
+  const char* instanceNodeNames[] = { "Instance", "RoxieServerProcess" };
   const char* logDirNames[] = { "@logDir", "@LogDir", "@dfuLogDir", "@eclLogDir" };
 
   ForEach(*iter)
@@ -1228,7 +1228,7 @@ IPropertyTree* getInstances(const IPropertyTree* pEnvRoot, const char* compName,
             for (UINT i=0; i<sizeof(instanceNodeNames) / sizeof(instanceNodeNames[0]); i++)
               if (!strcmp(sb.str(), instanceNodeNames[i]))
               {
-                //allow multiple instances but do not allow either roxie servers or slaves more than once per computer
+                //allow multiple instances but do not allow roxie servers more than once per computer
                 if (listall || sb.str()[0] != 'R' || !pSelComp->queryPropTree(StringBuffer().appendf("*[@computer=\"%s\"]", computer)))
                 {
                   IPropertyTree* pInstance = pSelComp->addPropTree(sb.str(), createPTree());

+ 6 - 61
deployment/deployutils/configenvhelper.cpp

@@ -319,47 +319,6 @@ bool CConfigEnvHelper::checkComputerUse(/*IPropertyTree* pComputerNode*/ const c
 }
 
 
-bool CConfigEnvHelper::makePlatformSpecificAbsolutePath(const char* computer, StringBuffer& path)
-{
-  bool rc = false;
-  if (computer && *computer && path.length())
-  {
-    IPropertyTree* pComputer = lookupComputerByName(computer);
-    const char* computerType = pComputer ? pComputer->queryProp(XML_ATTR_COMPUTERTYPE) : NULL;
-    if (computerType && *computerType)
-    {
-      StringBuffer xpath;
-      xpath.appendf("Hardware/ComputerType[@name='%s']", computerType);
-
-      Owned<IPropertyTreeIterator> iter = m_pRoot->getElements(xpath.str());
-      if (iter->first() && iter->isValid())
-      {
-        const char* os = iter->query().queryProp("@opSys");
-        if (os && *os)
-        {
-          const bool bLinux = 0 != stricmp(os, "W2K");
-          if (bLinux)
-          {
-            path.replace('\\', '/');
-            path.replace(':', '$');
-            if (*path.str() != '/')
-              path.insert(0, '/');
-          }
-          else
-          {
-            path.replace('/', '\\');
-            path.replace('$', ':');
-            if (*path.str() == '\\')
-              path.remove(0, 1);
-          }
-          rc = true;
-        }
-      }
-    }
-  }
-  return rc;
-}
-
 IPropertyTree* CConfigEnvHelper::addLegacyServer(const char* name, IPropertyTree* pServer, 
                                                  IPropertyTree* pFarm, const char* roxieClusterName)
 {
@@ -850,10 +809,6 @@ bool CConfigEnvHelper::handleRoxieSlaveConfig(const char* xmlArg)
         const char* pszRoxie = pSrcTree->queryProp("@roxieName");
         const char* val1 = pSrcTree->queryProp("@val1");
         const char* sOffset = pSrcTree->queryProp("@val2");
-        StringBuffer dir1, dir2, dir3;
-    getCommonDir(m_pRoot.get(), "data", "roxie", pszRoxie, dir1);
-        getCommonDir(m_pRoot.get(), "data2", "roxie", pszRoxie, dir2);
-        getCommonDir(m_pRoot.get(), "data3", "roxie", pszRoxie, dir3);
 
         StringBuffer xpath;
         xpath.clear().appendf("Software/RoxieCluster[@name='%s']", pszRoxie);
@@ -882,7 +837,7 @@ bool CConfigEnvHelper::handleRoxieSlaveConfig(const char* xmlArg)
 
         if (!strcmp(type, "Circular"))
         {
-            if (!GenerateCyclicRedConfig(pRoxie, computers, val1, sOffset, dir1.str(), dir2.str(), dir3.str()))
+            if (!GenerateCyclicRedConfig(pRoxie, computers, val1, sOffset))
                 return false;
 
             confType = "cyclic redundancy";
@@ -894,7 +849,7 @@ bool CConfigEnvHelper::handleRoxieSlaveConfig(const char* xmlArg)
         {
             if (!strcmp(type, "Overloaded"))
             {
-                if (!GenerateOverloadedConfig(pRoxie, computers, val1, dir1.str(), dir2.str(), dir3.str()))
+                if (!GenerateOverloadedConfig(pRoxie, computers, val1))
                     return false;
 
                 confType = "overloaded";
@@ -913,16 +868,13 @@ bool CConfigEnvHelper::handleRoxieSlaveConfig(const char* xmlArg)
                     confType = "simple";
                 }
 
-                if (!GenerateFullRedConfig(pRoxie, m_numDataCopies, computers, dir1.str()))
+                if (!GenerateFullRedConfig(pRoxie, m_numDataCopies, computers))
                     return false;
             }
 
             if (pRoxie->hasProp("@cyclicOffset"))
                 pRoxie->removeProp("@cyclicOffset");
         }
-        StringBuffer sDataDir;
-        sDataDir.appendf("%s", dir1.str());
-
         //give legacy slaves unique names
         UINT i = 1;
         Owned<IPropertyTreeIterator> it = pRoxie->getElements(XML_TAG_ROXIE_SLAVE);
@@ -933,16 +885,12 @@ bool CConfigEnvHelper::handleRoxieSlaveConfig(const char* xmlArg)
 
             IPropertyTree* pLegacySlave = &it->query();
             pLegacySlave->setProp(XML_ATTR_NAME, name.str() );
-
-            if (i++==1)
-                makePlatformSpecificAbsolutePath( pLegacySlave->queryProp(XML_ATTR_COMPUTER), sDataDir);
         }
 
         pRoxie->setProp("@slaveConfig", confType);
         pRoxie->setPropInt("@clusterWidth", computers.size());
         pRoxie->setPropInt("@numChannels",   m_numChannels);
         pRoxie->setPropInt("@numDataCopies", m_numDataCopies);
-        pRoxie->setProp("@baseDataDir", sDataDir.str());
         pRoxie->setProp("@localSlave", computers.size() > 1 ? "false" : "true");
 
         //change all legacy servers
@@ -962,8 +910,7 @@ bool CConfigEnvHelper::handleRoxieSlaveConfig(const char* xmlArg)
 }
 
 bool CConfigEnvHelper::GenerateCyclicRedConfig(IPropertyTree* pRoxie, IPropertyTreePtrArray& computers, 
-                                                                                             const char* copies, const char* pszOffset,
-                                                                                             const char* dir1, const char* dir2, const char* dir3)
+                                                                                             const char* copies, const char* pszOffset)
 {
     const int nComputers = computers.size();
     if (!nComputers)
@@ -1004,7 +951,6 @@ bool CConfigEnvHelper::GenerateCyclicRedConfig(IPropertyTree* pRoxie, IPropertyT
         int channel;
         for (int c=0; c<m_numDataCopies; c++)
         {
-            const char drive = 'c' + c;
             channel = 1 + ((baseChannel + c*(nComputers-offset)) % nComputers);
 
             IPropertyTree* pInstance = pSlave->addPropTree(XML_TAG_ROXIE_CHANNEL, createPTree());
@@ -1022,8 +968,7 @@ bool CConfigEnvHelper::GenerateCyclicRedConfig(IPropertyTree* pRoxie, IPropertyT
     return true;
 }
 
-bool CConfigEnvHelper::GenerateOverloadedConfig(IPropertyTree* pRoxie, IPropertyTreePtrArray& computers, const char* copies,
-                                                                                                const char* dir1, const char* dir2, const char* dir3)
+bool CConfigEnvHelper::GenerateOverloadedConfig(IPropertyTree* pRoxie, IPropertyTreePtrArray& computers, const char* copies)
 {
     const UINT nComputers = computers.size();
     if (!nComputers)
@@ -1069,7 +1014,7 @@ bool CConfigEnvHelper::GenerateOverloadedConfig(IPropertyTree* pRoxie, IProperty
     return true;
 }
 
-bool CConfigEnvHelper::GenerateFullRedConfig(IPropertyTree* pRoxie, int copies, IPropertyTreePtrArray& computers, const char* dir1)
+bool CConfigEnvHelper::GenerateFullRedConfig(IPropertyTree* pRoxie, int copies, IPropertyTreePtrArray& computers)
 {
     int nComputers = computers.size();
     if (!nComputers)

+ 3 - 6
deployment/deployutils/configenvhelper.hpp

@@ -44,7 +44,6 @@ private:
     IPropertyTree* getSoftwareNode(const char* compType, const char* compName);
     bool addRoxieServers(const char* xmlStr);
     bool checkComputerUse(/*IPropertyTree* pComputerNode*/ const char* szComputer, IPropertyTree* pParentNode) const;
-    bool makePlatformSpecificAbsolutePath(const char* computer, StringBuffer& path);
     IPropertyTree* addLegacyServer(const char* name, IPropertyTree* pServer, IPropertyTree*pFarm, const char* roxieClusterName);
     void setComputerState(IPropertyTree* pNode, COMPUTER_STATE state);
     void setAttribute(IPropertyTree* pNode, const char* szName, const char* szValue);
@@ -65,11 +64,9 @@ private:
     bool handleRoxieSlaveConfig(const char* params);
     bool handleReplaceRoxieServer(const char* xmlArg);
     void addSlaveProcessConfig(IPropertyTree *pRoxie, IPropertyTree *pSlaveNode, int channel, int level, const char* netAddress);
-    bool GenerateCyclicRedConfig(IPropertyTree* pRoxie, IPropertyTreePtrArray& computers, const char* copies, const char* pszOffset,
-                                                             const char* dir1, const char* dir2, const char* dir3);
-    bool GenerateOverloadedConfig(IPropertyTree* pRoxie, IPropertyTreePtrArray& computers, const char* copies,
-                                                                const char* dir1, const char* dir2, const char* dir3);
-    bool GenerateFullRedConfig(IPropertyTree* pRoxie, int copies, IPropertyTreePtrArray& computers, const char* dir1);
+    bool GenerateCyclicRedConfig(IPropertyTree* pRoxie, IPropertyTreePtrArray& computers, const char* copies, const char* pszOffset);
+    bool GenerateOverloadedConfig(IPropertyTree* pRoxie, IPropertyTreePtrArray& computers, const char* copies);
+    bool GenerateFullRedConfig(IPropertyTree* pRoxie, int copies, IPropertyTreePtrArray& computers);
     void RemoveSlaves(IPropertyTree* pRoxie, bool bLegacySlaves/*=false*/);
     void RenameThorInstances(IPropertyTree* pThor);
     void UpdateThorAttributes(IPropertyTree* pParentNode);

+ 0 - 1
esp/eclwatch/ws_XSLT/machines.xslt

@@ -340,7 +340,6 @@
                     <xsl:when test="Type='ThorSlaveProcess'">Thor Slave</xsl:when>
                     <xsl:when test="Type='ThorSpareProcess'">Thor Spare</xsl:when>
                     <xsl:when test="Type='RoxieServerProcess'">Roxie Server</xsl:when>
-                    <xsl:when test="Type='RoxieSlaveProcess'">Roxie Slave</xsl:when>
                     <xsl:when test="Type='DropZone'">Drop Zone</xsl:when>
                     <xsl:otherwise>
                         <xsl:value-of select="Type"/>

+ 1 - 1
esp/services/WsDeploy/WsDeployService.cpp

@@ -3645,7 +3645,7 @@ bool CWsDeployFileInfo::getDeployableComps(IEspContext &context, IEspGetDeployab
             for (UINT i=0; i<sizeof(instanceNodeNames) / sizeof(instanceNodeNames[0]); i++)
               if (!strcmp(nodeName, instanceNodeNames[i]))
               {
-                if (*nodeName != 'R')// || //neither RoxieServerProcess nor RoxieSlaveProcess
+                if (*nodeName != 'R')// || // neither RoxieServerProcess nor RoxieSlaveProcess
                 {
                   IPropertyTree* pInstanceNode = pCompNode->addPropTree(XML_TAG_INSTANCES, createPTree());
                   const char* directory = pNode->queryProp(*nodeName == 'R' ? XML_ATTR_LEVEL : XML_ATTR_DIRECTORY);

+ 1 - 6
esp/services/ws_machine/ws_machineService.cpp

@@ -64,10 +64,6 @@
 #define eqRoxieServerProcess    "RoxieServerProcess"
 #endif
 
-#ifndef eqRoxieSlaveProcess
-#define eqRoxieSlaveProcess    "RoxieSlaveProcess"
-#endif
-
 static const int THREAD_POOL_SIZE = 40;
 static const int THREAD_POOL_STACK_SIZE = 64000;
 static const char* FEATURE_URL = "MachineInfoAccess";
@@ -660,7 +656,6 @@ void Cws_machineEx::readTargetClusterProcesses(IPropertyTree &processNode, const
     {
         BoolHash uniqueRoxieProcesses;
         getProcesses(constEnv, pClusterProcess, process, eqRoxieServerProcess, dirStr.str(), machineInfoData, uniqueProcesses, &uniqueRoxieProcesses);
-        getProcesses(constEnv, pClusterProcess, process, eqRoxieSlaveProcess, dirStr.str(), machineInfoData, uniqueProcesses, &uniqueRoxieProcesses);
     }
 }
 
@@ -1991,7 +1986,7 @@ const char* Cws_machineEx::getProcessTypeFromMachineType(const char* machineType
     {
         processType = eqThorCluster;
     }
-    else    if (strieq(machineType, eqRoxieServerProcess) || strieq(machineType, eqRoxieSlaveProcess))
+    else    if (strieq(machineType, eqRoxieServerProcess))
     {
         processType = eqRoxieCluster;
     }

+ 0 - 1
esp/smc/SMCLib/TpWrapper.cpp

@@ -122,7 +122,6 @@ void CTpWrapper::getClusterMachineList(double clientVersion,
         else if (strcmp(eqROXIEMACHINES,ClusterType) == 0)
         {
             getMachineList("RoxieServerProcess",path.str(),"", ClusterDirectory, MachineList, &machineNames);
-            getMachineList("RoxieSlaveProcess",path.str(),"", ClusterDirectory, MachineList, &machineNames);
         }
         else if (strcmp(eqMACHINES,ClusterType) == 0)
         {

+ 0 - 1
esp/xslt/ui_configmgr.xslt

@@ -620,7 +620,6 @@
                       rowsServers[rowsServers.length] = i;
                     </xsl:for-each>
                   </xsl:when>
-                    <xsl:when test="(name() = 'RoxieSlaveProcess')"/>
                     <xsl:when test="(name() = 'RoxieServerProcess')"/>
                     <xsl:when test="(name() = 'RoxieSlave')">
                       id = rowsSlaves.length;

+ 6 - 68
initfiles/componentfiles/configxml/RoxieTopology.xsl

@@ -146,31 +146,16 @@
                     <xsl:copy-of select="@regex"/>
                 </xsl:copy>
             </xsl:for-each>
-            <xsl:for-each select="RoxieServerProcess">
-                <xsl:variable name="computer" select="@computer"/>
-                <xsl:element name="RoxieServerProcess">
-                    <xsl:attribute name="netAddress"><xsl:value-of select="/Environment/Hardware/Computer[@name=$computer]/@netAddress"/></xsl:attribute>
-                    <xsl:copy-of select="@port"/>
-                    <xsl:copy-of select="@*[name()!='netAddress' and name()!='computer' and name()!='name' and name()!='port']"/>
+            <xsl:for-each select="RoxieFarmProcess">
+                <xsl:element name="RoxieFarmProcess">
+                    <xsl:copy-of select="@*[name()!='name' and name()!='level']"/>
                 </xsl:element>
             </xsl:for-each>
-            <xsl:for-each select="RoxieSlaveProcess">
-                <xsl:sort select="@level"/>
-                <xsl:sort select="@channel" data-type="number"/>
-                <xsl:element name="RoxieSlaveProcess">
-                    <xsl:variable name="computer" select="@computer"/>
-                    <xsl:attribute name="netAddress"><xsl:value-of select="/Environment/Hardware/Computer[@name=$computer]/@netAddress"/></xsl:attribute>
-                    <xsl:attribute name="channel"><xsl:value-of select="@channel"/></xsl:attribute>
-                    <xsl:if test="string(@level)=''">
-                        <xsl:attribute name="level">0</xsl:attribute>
-                    </xsl:if>
-                    <xsl:copy-of select="@*[name()!='netAddress' and name()!='computer' and name()!='name' and name()!='channel']"/>
-                </xsl:element>
-            </xsl:for-each>
-            <xsl:for-each select="RoxieMonitorProcess">
+            <xsl:for-each select="RoxieServerProcess">
                 <xsl:variable name="computer" select="@computer"/>
-                <xsl:element name="RoxieMonitorProcess">
+                <xsl:element name="RoxieServerProcess">
                     <xsl:attribute name="netAddress"><xsl:value-of select="/Environment/Hardware/Computer[@name=$computer]/@netAddress"/></xsl:attribute>
+                    <xsl:copy-of select="@*[name()!='netAddress' and name()!='computer' and name()!='name' and name()!='port' and name()!='level' and name()!='listenQueue' and name()!='numThreads' and name()!='requestArrayThreads']"/>
                 </xsl:element>
             </xsl:for-each>
         </xsl:element>
@@ -179,56 +164,9 @@
     
     <xsl:template name="validateChannels">
         <xsl:variable name="numChannels" select="@numChannels"/>
-        <xsl:variable name="numSets" select="count(RoxieSlaveProcess[@channel='1'])"/>
-        
         <xsl:if test="$numChannels &lt; 1">
             <xsl:message terminate="yes">Number of channels must be at least 1.</xsl:message>
         </xsl:if>
-        
-        <xsl:if test="RoxieSlaveProcess[@channel &lt; '1' or @channel &gt; $numChannels]">
-            <xsl:message terminate="yes">Roxie slaves must not have channel numbers outside the range 1 to <xsl:value-of select="$numChannels"/>.</xsl:message>
-        </xsl:if>
-        
-        <!--make sure that there are exactly $numChannels sets for each channel-->
-        <!--we don't have incremental looping in xslt so start the 'domino effect' with channel 1-->
-        <xsl:if test="not(RoxieSlaveProcess[@channel='1'])">
-            <xsl:message terminate="yes">No Roxie slaves defined for channel 1.</xsl:message>
-        </xsl:if>
-        <xsl:apply-templates select="RoxieSlaveProcess[@channel='1' and count(preceding-sibling::RoxieSlaveProcess[@channel=1])=0]" mode="validateChannels">
-            <xsl:with-param name="channel" select="1"/>
-            <xsl:with-param name="numChannels" select="$numChannels"/>
-            <xsl:with-param name="numSets" select="$numSets"/>
-        </xsl:apply-templates>
-        
-    </xsl:template>
-
-
-    <xsl:template match="RoxieSlaveProcess" mode="validateChannels">
-    <xsl:param name="channel"/>
-    <xsl:param name="numChannels"/>
-    <xsl:param name="numSets"/>
-        <!--only process the first slave for each unique channel number to avoid duplicate validation-->
-        <xsl:if test="not(preceding-sibling::RoxieSlaveProcess[@channel=$channel])">
-            <xsl:variable name="setsize" select="count(../RoxieSlaveProcess[@channel=$channel])"/>
-            <!--note that setsize cannot be 0 since the current node has that channel already-->
-            <xsl:if test="$setsize != $numSets">
-                <xsl:call-template name="message">
-                    <xsl:with-param name="text">Number of Roxie slaves for channel <xsl:value-of select="$channel"/> are different than those for channel 1.</xsl:with-param>
-                </xsl:call-template>                
-            </xsl:if>
-            <xsl:if test="$channel &lt; $numChannels">
-                <xsl:variable name="nextChannel" select="$channel+1"/>
-                <xsl:variable name="nextChannelSlaveSet" select="../RoxieSlaveProcess[@channel=$nextChannel]"/>
-                <xsl:if test="not($nextChannelSlaveSet)">
-                    <xsl:message terminate="yes">No Roxie slaves defined for channel <xsl:value-of select="$nextChannel"/>.</xsl:message>
-                </xsl:if>
-                <xsl:apply-templates select="$nextChannelSlaveSet" mode="validateChannels">
-                    <xsl:with-param name="channel" select="$nextChannel"/>
-                    <xsl:with-param name="numChannels" select="$numChannels"/>
-                    <xsl:with-param name="numSets" select="$numSets"/>
-                </xsl:apply-templates>
-            </xsl:if>
-        </xsl:if>
     </xsl:template>
 
     <xsl:template name="makeAbsolutePath">

+ 11 - 31
initfiles/componentfiles/configxml/roxie.xsd.in

@@ -25,34 +25,26 @@
     </xs:annotation>
     <xs:complexType>
       <xs:choice maxOccurs="unbounded">
-        <xs:element name="RoxieServerProcess" maxOccurs="unbounded">
+
+        <xs:element name="RoxieFarmProcess" maxOccurs="unbounded">
           <xs:annotation>
             <xs:appinfo>
-              <viewType>RoxieServers</viewType>
-              <title>Servers</title>
+              <title>Farms</title>
             </xs:appinfo>
           </xs:annotation>
           <xs:complexType>
-            <xs:attribute name="computer" type="computerType" use="required"/>
-            <xs:attribute name="netAddress" type="ipAddress">
-              <xs:annotation>
-                <xs:appinfo>
-                  <viewType>readonly</viewType>
-                </xs:appinfo>
-              </xs:annotation>
-            </xs:attribute>
             <xs:attribute name="port" type="xs:nonNegativeInteger" use="optional" default="9876">
               <xs:annotation>
                 <xs:appinfo>
                   <required>true</required>
-                  <tooltip>the network port on which the Roxie server accepts connections</tooltip>
+                  <tooltip>the network port on which the Roxie servers accept connections</tooltip>
                 </xs:appinfo>
               </xs:annotation>
             </xs:attribute>
             <xs:attribute name="numThreads" type="xs:nonNegativeInteger" use="optional" default="30">
               <xs:annotation>
                 <xs:appinfo>
-                  <tooltip>Number of simultaneous queries this Roxie server will accept on this port</tooltip>
+                  <tooltip>Number of simultaneous queries Roxie servers will accept on this port</tooltip>
                 </xs:appinfo>
               </xs:annotation>
             </xs:attribute>
@@ -66,7 +58,7 @@
             <xs:attribute name="requestArrayThreads" type="xs:nonNegativeInteger" use="optional" default="5">
               <xs:annotation>
                 <xs:appinfo>
-                  <tooltip>Number of simultaneous queries this Roxie server will process using the MERGE option of SOAPCALL</tooltip>
+                  <tooltip>Number of simultaneous queries Roxie servers will process using the MERGE option of SOAPCALL</tooltip>
                 </xs:appinfo>
               </xs:annotation>
             </xs:attribute>
@@ -81,11 +73,12 @@
             </xs:attribute>
           </xs:complexType>
         </xs:element>
-        <xs:element name="RoxieSlaveProcess" maxOccurs="unbounded">
+
+        <xs:element name="RoxieServerProcess" maxOccurs="unbounded">
           <xs:annotation>
             <xs:appinfo>
-              <viewType>RoxieSlaves</viewType>
-              <title>Agents</title>
+              <viewType>RoxieServers</viewType>
+              <title>Servers</title>
             </xs:appinfo>
           </xs:annotation>
           <xs:complexType>
@@ -97,22 +90,9 @@
                 </xs:appinfo>
               </xs:annotation>
             </xs:attribute>
-            <xs:attribute name="channel" type="xs:nonNegativeInteger" use="required">
-              <xs:annotation>
-                <xs:appinfo>
-                  <tooltip>Channel number for this agent</tooltip>
-                </xs:appinfo>
-              </xs:annotation>
-            </xs:attribute>
-            <xs:attribute name="level" type="xs:nonNegativeInteger" use="optional" default="0">
-              <xs:annotation>
-                <xs:appinfo>
-                  <tooltip>Replication level of this slave</tooltip>
-                </xs:appinfo>
-              </xs:annotation>
-            </xs:attribute>
           </xs:complexType>
         </xs:element>
+
         <xs:element name="ACL" maxOccurs="unbounded">
           <xs:annotation>
             <xs:appinfo>

+ 2 - 2
initfiles/componentfiles/configxml/slaves.xsl

@@ -28,8 +28,8 @@
 </xsl:template>
 
 <xsl:template  match="RoxieCluster">
-   <xsl:for-each select="RoxieServerProcess|RoxieSlaveProcess">
-    <xsl:if test="string(@computer) != '' and not(@computer = preceding-sibling::RoxieServerProcess/@computer) and not(@computer = preceding-sibling::RoxieSlaveProcess/@computer)">
+   <xsl:for-each select="RoxieServerProcess">
+    <xsl:if test="string(@computer) != '' and not(@computer = preceding-sibling::RoxieServerProcess/@computer)">
         <xsl:value-of select="/Environment/Hardware/Computer[@name=current()/@computer]/@netAddress"/>
         <xsl:text>
 </xsl:text>

+ 5 - 36
initfiles/etc/DIR_NAME/environment.xml.in

@@ -768,7 +768,6 @@
              program="${EXEC_PATH}/ftslave"/>
   </FTSlaveProcess>
   <RoxieCluster allFilesDynamic="true"
-                baseDataDir="${RUNTIME_PATH}/hpcc-data/roxie"
                 blindLogging="false"
                 blobCacheMem="0"
                 build="${projname}_${version}-${stagever}"
@@ -894,50 +893,20 @@
                 useMemoryMappedIndexes="false"
                 useRemoteResources="true"
                 useTreeCopy="false">
-   <RoxieFarmProcess 
-                     level="0"
-                     listenQueue="200"
+   <RoxieFarmProcess listenQueue="200"
                      name="farm1"
                      numThreads="30"
                      port="9876"
-                     requestArrayThreads="5">
-    <RoxieServerProcess computer="localhost" name="farm1_s1"/>
-   </RoxieFarmProcess>
-   <RoxieFarmProcess
-                      level="0"
-                      listenQueue="200"
+                     requestArrayThreads="5"/>
+   <RoxieFarmProcess  listenQueue="200"
                       name="farm2"
                       numThreads="30"
                       port="0"
-                      requestArrayThreads="5">
-      <RoxieServerProcess computer="localhost" name="farm2_s1"/>
-    </RoxieFarmProcess>
-    <RoxieServerProcess
-                       computer="localhost"
-                       level="0"
-                       listenQueue="200"
-                       name="farm1_s1"
-                       netAddress="."
-                       numThreads="30"
-                       port="9876"
-                       requestArrayThreads="5"/>
+                      requestArrayThreads="5"/>
    <RoxieServerProcess 
                        computer="localhost"
-                       level="0"
-                       listenQueue="200"
                        name="farm2_s1"
-                       netAddress="."
-                       numThreads="30"
-                       port="0"
-                       requestArrayThreads="5"/>
-   <RoxieSlave computer="localhost" name="s1">
-    <RoxieChannel level="0" number="1"/>
-   </RoxieSlave>
-   <RoxieSlaveProcess channel="1"
-                      computer="localhost"
-                      level="0"
-                      name="s1"
-                      netAddress="."/>
+                       netAddress="."/>
   </RoxieCluster>
   <SashaServerProcess autoRestartInterval="0"
                       build="${projname}_${version}-${stagever}"

+ 2 - 3
roxie/ccd/ccd.hpp

@@ -311,10 +311,8 @@ interface IRoxieQueryPacket : extends IInterface
 interface IQueryDll;
 
 // Global configuration info
-extern bool isMonitor;
 extern bool shuttingDown;
 extern unsigned numChannels;
-extern unsigned numActiveChannels;
 extern unsigned callbackRetries;
 extern unsigned callbackTimeout;
 extern unsigned lowTimeout;
@@ -349,7 +347,6 @@ extern unsigned indexReadChunkSize;
 extern SocketEndpoint ownEP;
 extern unsigned maxBlockSize;
 extern unsigned maxLockAttempts;
-extern SocketEndpointArray allRoxieServers;
 extern bool enableHeartBeat;
 extern bool checkVersion;
 extern unsigned memoryStatsInterval;
@@ -397,6 +394,8 @@ extern bool mergeSlaveStatistics;
 extern bool roxieMulticastEnabled;   // enable use of multicast for sending requests to slaves
 extern bool preloadOnceData;
 
+extern unsigned roxiePort;     // If listening on multiple, this is the first. Used for lock cascading
+
 extern unsigned udpMulticastBufferSize;
 extern size32_t diskReadBufferSize;
 

+ 5 - 10
roxie/ccd/ccdlistener.cpp

@@ -244,16 +244,11 @@ class CascadeManager : public CInterface
         }
     }
 
-    SocketEndpoint &queryEndpoint(unsigned idx)
-    {
-        return allRoxieServers.item(idx);
-    }
-
     void connectChild(unsigned idx)
     {
-        if (allRoxieServers.isItem(idx))
+        if (idx < getNumNodes())
         {
-            SocketEndpoint &ep = queryEndpoint(idx);
+            SocketEndpoint ep(roxiePort, getNodeAddress(idx));
             try
             {
                 if (traceLevel)
@@ -518,11 +513,11 @@ public:
         if (traceLevel > 5)
             DBGLOG("doLockGlobal got %d locks", locksGot);
         reply.append("<Lock>").append(locksGot).append("</Lock>");
-        reply.append("<NumServers>").append(allRoxieServers.ordinality()).append("</NumServers>");
+        reply.append("<NumServers>").append(getNumNodes()).append("</NumServers>");
         if (lockAll)
-            return locksGot == allRoxieServers.ordinality();
+            return locksGot == getNumNodes();
         else
-            return locksGot > allRoxieServers.ordinality()/2;
+            return locksGot > getNumNodes()/2;
     }
 
     void doControlQuery(SocketEndpoint &ep, const char *queryText, StringBuffer &reply)

+ 95 - 157
roxie/ccd/ccdmain.cpp

@@ -48,7 +48,6 @@
 
 bool shuttingDown = false;
 unsigned numChannels;
-unsigned numActiveChannels;
 unsigned callbackRetries = 3;
 unsigned callbackTimeout = 500;
 unsigned lowTimeout = 10000;
@@ -157,7 +156,6 @@ unsigned minFilesOpen[2] = {2000, 500};
 unsigned maxFilesOpen[2] = {4000, 1000};
 
 SocketEndpoint ownEP;
-SocketEndpointArray allRoxieServers;
 HardwareInfo hdwInfo;
 unsigned parallelAggregate;
 bool inMemoryKeysEnabled = true;
@@ -168,6 +166,8 @@ unsigned nodeCacheMB = 100;
 unsigned leafCacheMB = 50;
 unsigned blobCacheMB = 0;
 
+unsigned roxiePort = 0;
+
 MODULE_INIT(INIT_PRIORITY_STANDARD)
 {
     topology = NULL;
@@ -254,15 +254,15 @@ void closedown()
     waiter.onAbort();
 }
 
-void getAccessList(const char *aclName, IPropertyTree *topology, IPropertyTree *serverInfo)
+void getAccessList(const char *aclName, const IPropertyTree *topology, IPropertyTree *aclInfo)
 {
     StringBuffer xpath;
     xpath.append("ACL[@name='").append(aclName).append("']");
-    if (serverInfo->queryPropTree(xpath))
+    if (aclInfo->queryPropTree(xpath))
         throw MakeStringException(MSGAUD_operator, ROXIE_INVALID_TOPOLOGY, "Invalid topology file - recursive ACL definition of %s", aclName);
     Owned<IPropertyTree> X = createPTree("ACL");
     X->setProp("@name", aclName);
-    serverInfo->addPropTree("ACL", X.getClear());
+    aclInfo->addPropTree("ACL", X.getClear());
 
     Owned<IPropertyTree> acl = topology->getPropTree(xpath.str());
     if (!acl)
@@ -274,32 +274,11 @@ void getAccessList(const char *aclName, IPropertyTree *topology, IPropertyTree *
         IPropertyTree &child = access->query();
         const char *base = child.queryProp("@base");
         if (base)
-            getAccessList(base, topology, serverInfo);
+            getAccessList(base, topology, aclInfo);
         else
-            serverInfo->addPropTree(child.queryName(), LINK(&child));
+            aclInfo->addPropTree(child.queryName(), LINK(&child));
     }
-    serverInfo->removeProp(xpath);
-}
-
-void addServerChannel(unsigned port, unsigned threads, const char *access, IPropertyTree *topology)
-{
-    if (!ownEP.port)
-        ownEP.set(port, queryHostIP());
-    Owned<IPropertyTreeIterator> servers = ccdChannels->getElements("RoxieServerProcess");
-    ForEach(*servers)
-    {
-        IPropertyTree &f = servers->query();
-        if (f.getPropInt("@port", 0) == port)
-            throw MakeStringException(MSGAUD_operator, ROXIE_INVALID_TOPOLOGY, "Invalid topology file - Roxie server port repeated");
-    }
-    IPropertyTree *ci = createPTree("RoxieServerProcess");
-    ci->setPropInt("@port", port);
-    ci->setPropInt("@numThreads", threads);
-    if (access && *access)
-    {
-        getAccessList(access, topology,  ci);
-    }
-    ccdChannels->addPropTree("RoxieServerProcess", ci);
+    aclInfo->removeProp(xpath);
 }
 
 bool ipMatch(IpAddress &ip)
@@ -307,7 +286,7 @@ bool ipMatch(IpAddress &ip)
     return ip.isLocal();
 }
 
-void addSlaveChannel(unsigned channel, unsigned level, bool suspended)
+void addSlaveChannel(unsigned channel, unsigned level)
 {
     StringBuffer xpath;
     xpath.appendf("RoxieSlaveProcess[@channel=\"%d\"]", channel);
@@ -315,24 +294,23 @@ void addSlaveChannel(unsigned channel, unsigned level, bool suspended)
         throw MakeStringException(MSGAUD_operator, ROXIE_INVALID_TOPOLOGY, "Invalid topology file - channel %d repeated", channel);
     IPropertyTree *ci = createPTree("RoxieSlaveProcess");
     ci->setPropInt("@channel", channel);
-    ci->setPropBool("@suspended", suspended);
-    ci->setPropInt("@subChannel", numSlaves[channel]);   // Alternatively could probably use replication level as subchannel ?
-    suspendedChannels[channel] = suspended;
-    assertex(!replicationLevel[channel]);  // implies channel repeated, caught above
-    replicationLevel[channel] = level;
+    ci->setPropInt("@subChannel", numSlaves[channel]);
     ccdChannels->addPropTree("RoxieSlaveProcess", ci);
 }
 
-void addChannel(unsigned channel, unsigned level, bool isMe, bool suspended, IpAddress& slaveIp)
+void addChannel(unsigned nodeNumber, unsigned channel, unsigned level)
 {
     numSlaves[channel]++;
-    if (isMe && channel > 0 && channel <= numChannels)
+    if (nodeNumber == myNodeIndex && channel > 0)
     {
-        addSlaveChannel(channel, level, suspended);
+        assertex(channel <= numChannels);
+        assertex(!replicationLevel[channel]);
+        replicationLevel[channel] = level;
+        addSlaveChannel(channel, level);
     }
     if (!localSlave)
     {
-        addEndpoint(channel, slaveIp, CCD_MULTICAST_PORT);
+        addEndpoint(channel, getNodeAddress(nodeNumber), CCD_MULTICAST_PORT);
     }
 }
 
@@ -516,12 +494,12 @@ int STARTQUERY_API start_query(int argc, const char *argv[])
             }
             topology=createPTreeFromXMLString(
                 "<RoxieTopology numChannels='1' localSlave='1'>"
-                 "<RoxieServerProcess netAddress='.'/>"
-                 "<RoxieSlaveProcess netAddress='.' channel='1' level='0'/>"
+                " <RoxieFarmProcess/>"
+                " <RoxieServerProcess netAddress='.'/>"
                 "</RoxieTopology>"
                 );
             int port = globals->getPropInt("--port", 9876);
-            topology->setPropInt("RoxieServerProcess/@port", port);
+            topology->setPropInt("RoxieFarmProcess/@port", port);
             topology->setProp("@daliServers", globals->queryProp("--daliServers"));
             topology->setProp("@traceLevel", globals->queryProp("--traceLevel"));
             topology->setProp("@memTraceLevel", globals->queryProp("--memTraceLevel"));
@@ -625,8 +603,6 @@ int STARTQUERY_API start_query(int argc, const char *argv[])
             if (!setPreferredSubnet(preferredSubnet, preferredSubnetMask))
                 throw MakeStringException(ROXIE_INTERNAL_ERROR, "Error setting preferred subnet %s mask %s", preferredSubnet, preferredSubnetMask);
         }
-        bool multiHostMode = globals->hasProp("--host");
-        unsigned myHostNumber = globals->getPropInt("--host", 0);
         if (restarts)
         {
             if (traceLevel)
@@ -645,7 +621,6 @@ int STARTQUERY_API start_query(int argc, const char *argv[])
 
         headRegionSize = topology->getPropInt("@headRegionSize", 50);
         numChannels = topology->getPropInt("@numChannels", 0);
-        numActiveChannels = topology->getPropInt("@numActiveChannels", numChannels);
         statsExpiryTime = topology->getPropInt("@statsExpiryTime", 3600);
         roxiemem::memTraceSizeLimit = (memsize_t) topology->getPropInt64("@memTraceSizeLimit", 0);
         callbackRetries = topology->getPropInt("@callbackRetries", 3);
@@ -846,58 +821,62 @@ int STARTQUERY_API start_query(int argc, const char *argv[])
         if (!numChannels)
             throw MakeStringException(MSGAUD_operator, ROXIE_INVALID_TOPOLOGY, "Invalid topology file - numChannels attribute must be specified");
 
-        bool myIPadded = false;
         Owned<IPropertyTreeIterator> roxieServers = topology->getElements("./RoxieServerProcess");
         ForEach(*roxieServers)
         {
             IPropertyTree &roxieServer = roxieServers->query();
             const char *iptext = roxieServer.queryProp("@netAddress");
             unsigned nodeIndex = addRoxieNode(iptext);
-            unsigned port = roxieServer.getPropInt("@port", ROXIE_SERVER_PORT);
-            if (iptext)
+            if (traceLevel > 3)
+                DBGLOG("Roxie server %u is at %s", nodeIndex, iptext);
+        }
+
+        // Generate the slave channels
+        unsigned numDataCopies = topology->getPropInt("@numDataCopies", 1);
+        unsigned cyclicOffset = topology->getPropInt("@cyclicOffset", 0);
+        unsigned numNodes = getNumNodes();
+        if (cyclicOffset)
+        {
+            if (numChannels != numNodes)
+                throw MakeStringException(MSGAUD_operator, ROXIE_INVALID_TOPOLOGY, "Invalid topology file - numChannels does not match number of servers");
+            for (int i=0; i<numNodes; i++)
             {
-                SocketEndpoint ep(iptext, port);
-                unsigned roxieServerHost = roxieServer.getPropInt("@multihost", 0);
-                if (ipMatch(ep) && ((roxieServerHost == myHostNumber) || (myHostNumber==-1)))
+                int channel = i+1;
+                for (int copy=0; copy<numDataCopies; copy++)
                 {
-                    unsigned numThreads = roxieServer.getPropInt("@numThreads", numServerThreads);
-                    const char *aclName = roxieServer.queryProp("@aclName");
-                    addServerChannel(port, numThreads, aclName, topology);
-                    if (!myIPadded || (myHostNumber==-1))
-                    {
-                        myNodeIndex = nodeIndex;
-                        allRoxieServers.append(ep);
-                        myIPadded = true;
-                    }
+                    channel = channel + cyclicOffset;
+                    if (channel > numNodes)
+                        channel = channel - numNodes;
+                    addChannel(i, channel, copy);
                 }
-                else if (multiHostMode || !roxieServerHost)
+            }
+        }
+        else if (numChannels > numNodes)   // overloaded mode
+        {
+            if (numChannels != numNodes * numDataCopies)
+                throw MakeStringException(MSGAUD_operator, ROXIE_INVALID_TOPOLOGY, "Invalid topology file - numChannels does not match expected value");
+            for (int i=0; i<numNodes; i++)
+            {
+                int channel = i+1;
+                for (int copy=0; copy<numDataCopies; copy++)
                 {
-                    bool found = false;
-                    ForEachItemIn(idx, allRoxieServers)
-                    {
-                        if (multiHostMode)
-                        {
-                            if (ep.equals(allRoxieServers.item(idx)))
-                            {
-                                found = true;
-                                break;
-                            }
-                        }
-                        else
-                        {
-                            if (ep.ipequals(allRoxieServers.item(idx)))
-                            {
-                                found = true;
-                                break;
-                            }
-                        }
-                    }
-                    if (!found)
-                        allRoxieServers.append(ep);
+                    channel = channel + copy*numNodes;
+                    addChannel(i, channel, copy);
                 }
             }
-            else
-                throw MakeStringException(MSGAUD_operator, ROXIE_INVALID_TOPOLOGY, "Invalid topology file - missing netAddress or port specification on RoxieServerProcess element");
+        }
+        else    // 'Full redundancy' or 'simple' mode
+        {
+            if (numChannels != numNodes / numDataCopies)
+                throw MakeStringException(MSGAUD_operator, ROXIE_INVALID_TOPOLOGY, "Invalid topology file - numChannels does not match expected value");
+            int channel = 1;
+            for (int i=0; i<numNodes; i++)
+            {
+                addChannel(i, channel, 0);
+                channel++;
+                if (channel > numChannels)
+                    channel = 1;
+            }
         }
         if (!localSlave)
         {
@@ -911,59 +890,10 @@ int STARTQUERY_API start_query(int argc, const char *argv[])
                     multicastLast.ipset(topology->queryProp("@multicastLast"));
                 else
                     throw MakeStringException(MSGAUD_operator, ROXIE_INVALID_TOPOLOGY, "Invalid topology file - multicastLast not set");
+                joinMulticastChannel(0); // all slaves also listen on channel 0
             }
         }
-        Owned<IPropertyTreeIterator> slaves = topology->getElements("./RoxieSlaveProcess");
-        IpAddress *primaries = new IpAddress[numChannels+1];    // check each channel has a different primary, if possible. Leaks on fatal errors, but who cares
-        ForEach(*slaves)
-        {
-            IPropertyTree &slave = slaves->query();
-            const char *iptext = slave.queryProp("@netAddress");
-            if (iptext)
-            {
-                addRoxieNode(iptext);
-                IpAddress slaveIp(iptext);
-                bool isMe = ipMatch(slaveIp) && slave.getPropInt("@multihost", 0) == myHostNumber;
-                bool suspended = slave.getPropBool("@suspended", false);
-                unsigned channel = slave.getPropInt("@channel", 0);
-                if (!channel)
-                    channel = slave.getPropInt("@channels", 0); // legacy support
-                unsigned replicationLevel = slave.getPropInt("@level", 0);
-                if (channel && channel <= numChannels)
-                {
-                    if (isMe)
-                        isCCD = true;
-                    if (!replicationLevel)
-                        primaries[channel] = slaveIp;
-                    addChannel(channel, replicationLevel, isMe, suspended, slaveIp);
-                    if (isMe)
-                        joinMulticastChannel(channel);
-                }
-                else
-                    throw MakeStringException(MSGAUD_operator, ROXIE_INVALID_TOPOLOGY, "Invalid topology file - missing or invalid channel attribute on RoxieSlaveProcess element");
-            }
-            else
-                throw MakeStringException(MSGAUD_operator, ROXIE_INVALID_TOPOLOGY, "Invalid topology file - missing netAddress attribute on RoxieSlaveProcess element");
-        }
-        if (numActiveChannels)
-            joinMulticastChannel(0); // all slaves also listen on channel 0
 
-        for (unsigned n = 1; n < numActiveChannels; n++)
-        {
-            if (!numSlaves[n])
-                throw MakeStringException(MSGAUD_operator, ROXIE_INVALID_TOPOLOGY, "Invalid topology file - no slaves for channel %d", n);
-            if (checkPrimaries)
-            {
-                for (unsigned m = n+1; m <= numChannels; m++)
-                    if (primaries[n].ipequals(primaries[m]))
-                    {
-                        StringBuffer s;
-                        primaries[n].getIpText(s);
-                        throw MakeStringException(MSGAUD_operator, ROXIE_INVALID_TOPOLOGY, "Invalid topology file - slave %s is primary for multiple channels", s.str());
-                    }
-            }
-        }
-        delete [] primaries;
         setDaliServixSocketCaching(true);  // enable daliservix caching
         loadPlugins();
         globalPackageSetManager = createRoxiePackageSetManager(standAloneDll.getClear());
@@ -1009,35 +939,44 @@ int STARTQUERY_API start_query(int argc, const char *argv[])
         }
         else
         {
-            Owned<IPropertyTreeIterator> it = ccdChannels->getElements("RoxieServerProcess");
-            ForEach(*it)
+            Owned<IPropertyTreeIterator> roxieFarms = topology->getElements("./RoxieFarmProcess");
+            ForEach(*roxieFarms)
             {
-                // MORE - there are assumptions that everyone is a server (in deployment)
-                IPropertyTree &serverInfo = it->query();
-                unsigned port = serverInfo.getPropInt("@port", -1);
-                bool suspended = serverInfo.getPropBool("@suspended", false);
-                unsigned numThreads = serverInfo.getPropInt("@numThreads", -1);
-                unsigned listenQueue = serverInfo.getPropInt("@listenQueue", DEFAULT_LISTEN_QUEUE_SIZE);
+                IPropertyTree &roxieFarm = roxieFarms->query();
+                unsigned listenQueue = roxieFarm.getPropInt("@listenQueue", DEFAULT_LISTEN_QUEUE_SIZE);
+                unsigned numThreads = roxieFarm.getPropInt("@numThreads", numServerThreads);
+                unsigned port = roxieFarm.getPropInt("@port", ROXIE_SERVER_PORT);
+                unsigned requestArrayThreads = roxieFarm.getPropInt("@requestArrayThreads", 5);
+                if (!roxiePort)
+                    roxiePort = port;
+                bool suspended = roxieFarm.getPropBool("@suspended", false);
                 Owned <IRoxieListener> roxieServer;
                 if (port)
                     roxieServer.setown(createRoxieSocketListener(port, numThreads, listenQueue, suspended));
                 else
                     roxieServer.setown(createRoxieWorkUnitListener(numThreads, suspended));
-                Owned<IPropertyTreeIterator> accesses = serverInfo.getElements("Access");
-                ForEach(*accesses)
+
+                const char *aclName = roxieFarm.queryProp("@aclName");
+                if (aclName)
                 {
-                    IPropertyTree &access = accesses->query();
-                    try
+                    Owned<IPropertyTree> aclInfo = createPTree("AccessInfo");
+                    getAccessList(aclName, topology, aclInfo);
+                    Owned<IPropertyTreeIterator> accesses = aclInfo->getElements("Access");
+                    ForEach(*accesses)
                     {
-                        roxieServer->addAccess(access.getPropBool("@allow", true), access.getPropBool("@allowBlind", true), access.queryProp("@ip"), access.queryProp("@mask"), access.queryProp("@query"), access.queryProp("@error"), access.getPropInt("@errorCode"));
-                    }
-                    catch (IException *E)
-                    {
-                        StringBuffer s, x;
-                        E->errorMessage(s);
-                        E->Release();
-                        toXML(&access, x, 0, 0);
-                        throw MakeStringException(ROXIE_ACL_ERROR, "Error in access statement %s: %s", x.str(), s.str());
+                        IPropertyTree &access = accesses->query();
+                        try
+                        {
+                            roxieServer->addAccess(access.getPropBool("@allow", true), access.getPropBool("@allowBlind", true), access.queryProp("@ip"), access.queryProp("@mask"), access.queryProp("@query"), access.queryProp("@error"), access.getPropInt("@errorCode"));
+                        }
+                        catch (IException *E)
+                        {
+                            StringBuffer s, x;
+                            E->errorMessage(s);
+                            E->Release();
+                            toXML(&access, x, 0, 0);
+                            throw MakeStringException(ROXIE_ACL_ERROR, "Error in access statement %s: %s", x.str(), s.str());
+                        }
                     }
                 }
                 socketListeners.append(*roxieServer.getLink());
@@ -1075,7 +1014,6 @@ int STARTQUERY_API start_query(int argc, const char *argv[])
     }
 
     roxieMetrics.clear();
-    allRoxieServers.kill();
     stopPerformanceMonitor();
     ::Release(globalPackageSetManager);
     globalPackageSetManager = NULL;

+ 1 - 1
roxie/ccd/ccdserver.cpp

@@ -3557,7 +3557,7 @@ public:
                 // Need to add first, then send
                 unsigned i;
                 bool allCached = true;
-                for (i = 1; i <= numActiveChannels; i++)
+                for (i = 1; i <= numChannels; i++)
                 {
                     IRoxieQueryPacket *q = p->clonePacket(i);
                     bool thisChannelCached;

+ 0 - 5
roxie/ccd/ccdstate.cpp

@@ -2121,11 +2121,6 @@ private:
                 ReadLockBlock readBlock(packageCrit);
                 reply.appendf("<State hash='%"I64F"u'/>", (unsigned __int64) allQueryPackages->queryHash());
             }
-            else if (stricmp(queryName, "control:status")==0)
-            {
-                CriticalBlock b(ccdChannelsCrit);
-                toXML(ccdChannels, reply);
-            }
             else if (stricmp(queryName, "control:steppingEnabled")==0)
             {
                 steppingEnabled = control->getPropBool("@val", true);