فهرست منبع

HPCC-13002 Allow roxie target to be specified in the url

If the same query exists in multiple targets on the same roxie process
the URL can be used to disambiguate.

Example: http://host:9876/roxie1?.trim=0

Signed-off-by: Anthony Fishbeck <anthony.fishbeck@lexisnexis.com>
Anthony Fishbeck 10 سال پیش
والد
کامیت
39d1c789f3

+ 15 - 1
common/thorhelper/roxiehelper.cpp

@@ -1555,7 +1555,21 @@ void IRoxieContextLogger::CTXLOGae(IException *E, const char *file, unsigned lin
 
 void HttpHelper::gatherUrlParameters()
 {
-    const char *finger = strchr(urlPath, '?');
+    const char *start = urlPath.str();
+    while (isspace(*start))
+        start++;
+    if (*start=='/')
+        start++;
+    const char *finger = strpbrk(start, "/?");
+    if (!finger)
+    {
+        target.set(start);
+        return;
+    }
+
+    target.set(start, finger-start);
+    if (*finger=='/')
+        finger = strchr(finger, '?');
     if (!finger)
         return;
     finger++;

+ 2 - 0
common/thorhelper/roxiehelper.hpp

@@ -34,6 +34,7 @@ private:
     StringAttr urlPath;
     StringAttr authToken;
     StringAttr contentType;
+    StringAttr target;
     Owned<IProperties> parameters;
 private:
     inline void setHttpHeaderValue(StringAttr &s, const char *v, bool ignoreExt)
@@ -55,6 +56,7 @@ public:
     bool getTrim() {return parameters->getPropBool(".trim", true); /*http currently defaults to true, maintain compatibility */}
     void setIsHttp(bool __isHttp) { _isHttp = __isHttp; }
     const char *queryAuthToken() { return authToken.sget(); }
+    const char *queryTarget() { return target.get(); }
     inline void setAuthToken(const char *v)
     {
         setHttpHeaderValue(authToken, v, false);

+ 14 - 4
esp/services/ws_ecl/ws_ecl_service.cpp

@@ -252,8 +252,16 @@ bool CWsEclService::init(const char * name, const char * type, IPropertyTree * c
         if (!process.length())
             continue;
         const char *vip = NULL;
+        bool includeTargetInURL = true;
         if (vips)
-            vip = vips->queryProp(xpath.clear().appendf("ProcessCluster[@name='%s']/@vip", process.str()).str());
+        {
+            IPropertyTree *pc = vips->queryPropTree(xpath.clear().appendf("ProcessCluster[@name='%s']", process.str()));
+            if (pc)
+            {
+                vip = pc->queryProp("@vip");
+                includeTargetInURL = pc->getPropBool("@includeTargetInURL", true);
+            }
+        }
         StringBuffer list;
         bool loadBalanced = false;
         if (vip && *vip)
@@ -274,7 +282,7 @@ bool CWsEclService::init(const char * name, const char * type, IPropertyTree * c
         }
         if (list.length())
         {
-            Owned<ISmartSocketFactory> sf = createSmartSocketFactory(list.str(), !loadBalanced);
+            Owned<RoxieConnEndpoint> sf = new RoxieConnEndpoint(list.str(), !loadBalanced, includeTargetInURL);
             connMap.setValue(target.str(), sf.get());
         }
     }
@@ -1839,14 +1847,16 @@ void CWsEclBinding::sendRoxieRequest(const char *target, StringBuffer &req, Stri
     SocketEndpoint ep;
     try
     {
-        ISmartSocketFactory *conn = wsecl->connMap.getValue(target);
+        RoxieConnEndpoint *conn = wsecl->connMap.getValue(target);
         if (!conn)
             throw MakeStringException(-1, "roxie target cluster not mapped: %s", target);
         ep = conn->nextEndpoint();
 
         Owned<IHttpClientContext> httpctx = getHttpClientContext();
         StringBuffer url("http://");
-        ep.getIpText(url).append(':').append(ep.port).append('/').append(target);
+        ep.getIpText(url).append(':').append(ep.port ? ep.port : 9876).append('/');
+        if (conn->includeTargetInURL)
+            url.append(target);
         if (!trim)
             url.append("?.trim=0");
 

+ 12 - 2
esp/services/ws_ecl/ws_ecl_service.hpp

@@ -21,7 +21,7 @@
 
 #include "jliball.hpp"
 #include "junicode.hpp"
-#include "jsmartsock.hpp"
+#include "jsmartsock.ipp"
 #include "fileview.hpp"
 
 #include "esp.hpp"
@@ -87,11 +87,21 @@ typedef enum wsEclTypes_
 
 } wsEclType;
 
+class RoxieConnEndpoint : public CSmartSocketFactory
+{
+public:
+    bool includeTargetInURL;
+
+    RoxieConnEndpoint(const char *_socklist, bool _retry, bool includeTarget) : CSmartSocketFactory(_socklist, _retry), includeTargetInURL(includeTarget)
+    {
+    }
+};
+
 class CWsEclService : public CInterface,
     implements IEspService
 {
 public:
-    MapStringToMyClass<ISmartSocketFactory> connMap;
+    MapStringToMyClassViaBase<RoxieConnEndpoint, ISmartSocketFactory> connMap;
     StringArray targets;
     StringAttr auth_method;
     StringAttr portal_URL;

+ 7 - 1
initfiles/componentfiles/configxml/@temp/esp_service.xsl

@@ -939,7 +939,13 @@ xmlns:seisint="http://seisint.com"  xmlns:set="http://exslt.org/sets" exclude-re
                         <xsl:if test="string(@roxie) != '' and string(@vip) != ''">
                             <xsl:variable name="roxie" select="@roxie"/>
                             <xsl:variable name="vip" select="@vip"/>
-                            <ProcessCluster name="{$roxie}" vip="{$vip}"></ProcessCluster>
+                            <xsl:variable name="sendTarget">
+                                <xsl:choose>
+                                    <xsl:when test="@sendTargetToRoxie"><xsl:value-of select="@sendTargetToRoxie"/></xsl:when>
+                                    <xsl:otherwise>true</xsl:otherwise>
+                                </xsl:choose>
+                            </xsl:variable>
+                            <ProcessCluster name="{$roxie}" vip="{$vip}" includeTargetInURL="{$sendTarget}"></ProcessCluster>
                         </xsl:if>
                     </xsl:for-each>
                 </VIPS>

+ 15 - 0
initfiles/componentfiles/configxml/esp_service_wsecl2.xsd

@@ -52,6 +52,21 @@
                       </xs:appinfo>
                     </xs:annotation>
                   </xs:attribute>
+                  <xs:attribute name="sendTargetToRoxie" use="optional" default="true">
+                      <xs:annotation>
+                          <xs:appinfo>
+                              <tooltip>Send roxie the target from which to run query (disable for backward compatibility issues)</tooltip>
+                              <title>Send Target To Roxie</title>
+                              <colIndex>3</colIndex>
+                          </xs:appinfo>
+                      </xs:annotation>
+                      <xs:simpleType>
+                          <xs:restriction base="xs:string">
+                              <xs:enumeration value="true"/>
+                              <xs:enumeration value="false"/>
+                          </xs:restriction>
+                      </xs:simpleType>
+                  </xs:attribute>
                 </xs:complexType>
               </xs:element>
             </xs:sequence>

+ 9 - 3
roxie/ccd/ccdlistener.cpp

@@ -1651,10 +1651,10 @@ readAnother:
                     }
                     else
                     {
-                        StringBuffer querySetName;
-                        queryFactory.setown(globalPackageSetManager->getQuery(queryName, &querySetName, NULL, logctx));
                         if (isHTTP)
                             client->setHttpMode(queryName, isRequestArray, httpHelper.queryContentFormat());
+                        StringBuffer querySetName(httpHelper.queryTarget());
+                        queryFactory.setown(globalPackageSetManager->getQuery(queryName, &querySetName, NULL, logctx));
                         if (queryFactory)
                         {
                             queryFactory->checkSuspended();
@@ -1771,7 +1771,13 @@ readAnother:
                         {
                             pool->reportBadQuery(queryName.get(), logctx);
                             if (globalPackageSetManager->getActivePackageCount())
-                                throw MakeStringException(ROXIE_UNKNOWN_QUERY, "Unknown query %s", queryName.get());
+                            {
+                                StringBuffer targetMsg;
+                                const char *target = httpHelper.queryTarget();
+                                if (target && *target)
+                                    targetMsg.append(", in target ").append(target);
+                                throw MakeStringException(ROXIE_UNKNOWN_QUERY, "Unknown query %s%s", queryName.get(), targetMsg.str());
+                            }
                             else
                                 throw MakeStringException(ROXIE_NO_PACKAGES_ACTIVE, "Unknown query %s (no packages active)", queryName.get());
                         }

+ 4 - 0
roxie/ccd/ccdstate.cpp

@@ -1076,6 +1076,8 @@ public:
 
     virtual IQueryFactory *getQuery(const char *id, StringBuffer *querySet, const IRoxieContextLogger &logctx) const
     {
+        if (querySet && querySet->length() && !streq(querySet->str(), querySetName))
+            return NULL;
         IQueryFactory *ret;
         ret = aliases.getValue(id);
         if (ret && logctx.queryTraceLevel() > 5)
@@ -1569,6 +1571,8 @@ public:
 
     IQueryFactory *getQuery(const char *id, StringBuffer *querySet, IArrayOf<IQueryFactory> *slaveQueries, const IRoxieContextLogger &logctx) const
     {
+        if (querySet && querySet->length() && !allQuerySetNames.contains(querySet->str()))
+            throw MakeStringException(ROXIE_INVALID_TARGET, "Target %s not found", querySet->str());
         ForEachItemIn(idx, allQueryPackages)
         {
             Owned<IRoxieQuerySetManager> sm = allQueryPackages.item(idx).getRoxieServerManager();

+ 1 - 0
roxie/roxie/roxie.hpp

@@ -84,6 +84,7 @@
 #define ROXIE_ABORT_ERROR           ROXIE_ERROR_START+62
 #define ROXIE_OPT_REPORTING         ROXIE_ERROR_START+63
 #define ROXIE_MISSING_DLL           ROXIE_ERROR_START+64
+#define ROXIE_INVALID_TARGET        ROXIE_ERROR_START+65
 
 
 

+ 5 - 0
system/jlib/jsmartsock.cpp

@@ -19,6 +19,11 @@
 #include "jsmartsock.ipp"
 #include "jdebug.hpp"
 
+ISmartSocketException *createSmartSocketException(int errorCode, const char *msg)
+{
+    return new SmartSocketException(errorCode, msg);
+}
+
 class SmartSocketListParser
 {
 public:

+ 0 - 5
system/jlib/jsmartsock.ipp

@@ -115,10 +115,5 @@ private:
     StringAttr msg;
 };
 
-ISmartSocketException *createSmartSocketException(int errorCode, const char *msg)
-{
-    return new SmartSocketException(errorCode, msg);
-}
-
 #endif