ws_workunitsQuerySets.cpp 141 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "ws_workunitsService.hpp"
  14. #include "ws_fs.hpp"
  15. #include "jlib.hpp"
  16. #include "jflz.hpp"
  17. #include "daclient.hpp"
  18. #include "dalienv.hpp"
  19. #include "dadfs.hpp"
  20. #include "dfuwu.hpp"
  21. #include "eclhelper.hpp"
  22. #include "roxiecontrol.hpp"
  23. #include "dfuutil.hpp"
  24. #include "dautils.hpp"
  25. #include "httpclient.hpp"
  26. #include "portlist.h" //ROXIE_SERVER_PORT
  27. #define DALI_FILE_LOOKUP_TIMEOUT (1000*15*1) // 15 seconds
  28. const unsigned ROXIECONNECTIONTIMEOUT = 1000; //1 second
  29. const unsigned ROXIECONTROLQUERYTIMEOUT = 3000; //3 second
  30. const unsigned ROXIECONTROLQUERIESTIMEOUT = 30000; //30 second
  31. const unsigned ROXIELOCKCONNECTIONTIMEOUT = 60000; //60 second
  32. #define SDS_LOCK_TIMEOUT (5*60*1000) // 5mins, 30s a bit short
  33. //The CQuerySetQueryActionTypes[] has to match with the ESPenum QuerySetQueryActionTypes in the ecm file.
  34. static unsigned NumOfQuerySetQueryActionTypes = 7;
  35. static const char *QuerySetQueryActionTypes[] = { "Suspend", "Unsuspend", "ToggleSuspend", "Activate",
  36. "Delete", "RemoveAllAliases", "ResetQueryStats", NULL };
  37. //The CQuerySetAliasActionTypes[] has to match with the ESPenum QuerySetAliasActionTypes in the ecm file.
  38. static unsigned NumOfQuerySetAliasActionTypes = 1;
  39. static const char *QuerySetAliasActionTypes[] = { "Deactivate", NULL };
  40. bool isRoxieProcess(const char *process)
  41. {
  42. if (!process)
  43. return false;
  44. Owned<IEnvironmentFactory> factory = getEnvironmentFactory(true);
  45. Owned<IConstEnvironment> env = factory->openEnvironment();
  46. Owned<IPropertyTree> root = &env->getPTree();
  47. VStringBuffer xpath("Software/RoxieCluster[@name=\"%s\"]", process);
  48. return root->hasProp(xpath.str());
  49. }
  50. void checkUseEspOrDaliIP(SocketEndpoint &ep, const char *ip, const char *esp)
  51. {
  52. if (!ip || !*ip)
  53. return;
  54. ep.set(ip, 7070);
  55. if (ep.isLoopBack() || *ip=='.' || (ip[0]=='0' && ip[1]=='.'))
  56. ep.ipset(esp);
  57. }
  58. void ensureInputString(const char* input, bool lowerCase, StringBuffer& inputStr, int code, const char* msg)
  59. {
  60. inputStr.set(input).trim();
  61. if (inputStr.isEmpty())
  62. throw MakeStringException(code, "%s", msg);
  63. if (lowerCase)
  64. inputStr.toLowerCase();
  65. }
  66. static IClientWsWorkunits *ensureWsWorkunitsClient(IClientWsWorkunits *ws, IEspContext *ctx, const char *netAddress)
  67. {
  68. if (ws)
  69. return LINK(ws);
  70. StringBuffer url;
  71. if (netAddress && *netAddress)
  72. url.appendf("http://%s%s/WsWorkunits", netAddress, (!strchr(netAddress, ':')) ? ":8010" : "");
  73. else
  74. {
  75. if (!ctx)
  76. throw MakeStringException(ECLWATCH_INVALID_IP, "Missing WsWorkunits service address");
  77. StringBuffer ip;
  78. short port = 0;
  79. ctx->getServAddress(ip, port);
  80. url.appendf("http://%s:%d/WsWorkunits", ip.str(), port);
  81. }
  82. Owned<IClientWsWorkunits> cws = createWsWorkunitsClient();
  83. cws->addServiceUrl(url);
  84. if (ctx && ctx->queryUserId() && *ctx->queryUserId())
  85. cws->setUsernameToken(ctx->queryUserId(), ctx->queryPassword(), NULL);
  86. return cws.getClear();
  87. }
  88. IClientWUQuerySetDetailsResponse *fetchQueryDetails(IClientWsWorkunits *_ws, IEspContext *ctx, const char *netAddress, const char *target, const char *queryid)
  89. {
  90. Owned<IClientWsWorkunits> ws = ensureWsWorkunitsClient(_ws, ctx, netAddress);
  91. //using existing WUQuerysetDetails rather than extending WUQueryDetails, to support copying query meta data from prior releases
  92. Owned<IClientWUQuerySetDetailsRequest> reqQueryInfo = ws->createWUQuerysetDetailsRequest();
  93. reqQueryInfo->setClusterName(target);
  94. reqQueryInfo->setQuerySetName(target);
  95. reqQueryInfo->setFilter(queryid);
  96. reqQueryInfo->setFilterType("Id");
  97. return ws->WUQuerysetDetails(reqQueryInfo);
  98. }
  99. void fetchRemoteWorkunit(IClientWsWorkunits *_ws, IEspContext *ctx, const char *netAddress, const char *queryset, const char *query, const char *wuid, StringBuffer &name, StringBuffer &xml, StringBuffer &dllname, MemoryBuffer &dll, StringBuffer &daliServer)
  100. {
  101. Owned<IClientWsWorkunits> ws = ensureWsWorkunitsClient(_ws, ctx, netAddress);
  102. Owned<IClientWULogFileRequest> req = ws->createWUFileRequest();
  103. if (queryset && *queryset)
  104. req->setQuerySet(queryset);
  105. if (query && *query)
  106. req->setQuery(query);
  107. if (wuid && *wuid)
  108. req->setWuid(wuid);
  109. req->setErrorMessageFormat(CErrorMessageFormat_XML);
  110. req->setType("xml");
  111. Owned<IClientWULogFileResponse> resp = ws->WUFile(req);
  112. if (!resp || resp->getExceptions().ordinality() || !resp->getThefile().length())
  113. throw MakeStringException(ECLWATCH_CANNOT_GET_WORKUNIT, "Cannot retrieve remote workunit");
  114. xml.append(resp->getThefile().length(), resp->getThefile().toByteArray());
  115. req->setType("dll");
  116. resp.setown(ws->WUFile(req));
  117. if (!resp || resp->getExceptions().ordinality() || !resp->getThefile().length())
  118. throw MakeStringException(ECLWATCH_CANNOT_GET_WORKUNIT, "Cannot retrieve remote workunit shared object");
  119. dll.append(resp->getThefile());
  120. dllname.append(resp->getFileName());
  121. name.append(resp->getQueryName());
  122. SocketEndpoint ep;
  123. checkUseEspOrDaliIP(ep, resp->getDaliServer(), netAddress);
  124. if (!ep.isNull())
  125. ep.getUrlStr(daliServer);
  126. }
  127. void fetchRemoteWorkunitAndQueryDetails(IClientWsWorkunits *_ws, IEspContext *ctx, const char *netAddress, const char *queryset, const char *query, const char *wuid, StringBuffer &name, StringBuffer &xml, StringBuffer &dllname, MemoryBuffer &dll, StringBuffer &daliServer, Owned<IClientWUQuerySetDetailsResponse> &respQueryInfo)
  128. {
  129. Owned<IClientWsWorkunits> ws = ensureWsWorkunitsClient(_ws, ctx, netAddress);
  130. fetchRemoteWorkunit(ws, ctx, netAddress, queryset, query, wuid, name, xml, dllname, dll, daliServer);
  131. respQueryInfo.setown(fetchQueryDetails(ws, ctx, netAddress, queryset, query));
  132. }
  133. void doWuFileCopy(IClientFileSpray &fs, IEspWULogicalFileCopyInfo &info, const char *logicalname, const char *cluster, bool isRoxie, bool supercopy)
  134. {
  135. try
  136. {
  137. Owned<IClientCopy> req = fs.createCopyRequest();
  138. req->setSourceLogicalName(logicalname);
  139. req->setDestLogicalName(logicalname);
  140. req->setDestGroup(cluster);
  141. req->setSuperCopy(supercopy);
  142. if (isRoxie)
  143. req->setDestGroupRoxie("Yes");
  144. Owned<IClientCopyResponse> resp = fs.Copy(req);
  145. info.setDfuCopyWuid(resp->getResult());
  146. }
  147. catch (IException *e)
  148. {
  149. StringBuffer msg;
  150. info.setDfuCopyError(e->errorMessage(msg).str());
  151. e->Release();
  152. }
  153. }
  154. bool copyWULogicalFiles(IEspContext &context, IConstWorkUnit &cw, const char *cluster, bool copyLocal, IEspWUCopyLogicalClusterFileSections &lfinfo)
  155. {
  156. if (isEmpty(cluster))
  157. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "copyWULogicalFiles Cluster parameter not set.");
  158. Owned<IUserDescriptor> udesc = createUserDescriptor();
  159. udesc->set(context.queryUserId(), context.queryPassword(), context.querySignature());
  160. IArrayOf<IEspWULogicalFileCopyInfo> foreign;
  161. IArrayOf<IEspWULogicalFileCopyInfo> onCluster;
  162. IArrayOf<IEspWULogicalFileCopyInfo> notOnCluster;
  163. IArrayOf<IEspWULogicalFileCopyInfo> notFound;
  164. Owned<IClientFileSpray> fs;
  165. if (copyLocal)
  166. {
  167. fs.setown(createFileSprayClient());
  168. VStringBuffer url("http://.:%d/FileSpray", 8010);
  169. fs->addServiceUrl(url.str());
  170. }
  171. bool isRoxie = isRoxieProcess(cluster);
  172. Owned<IConstWUGraphIterator> graphs = &cw.getGraphs(GraphTypeActivities);
  173. ForEach(*graphs)
  174. {
  175. Owned <IPropertyTree> xgmml = graphs->query().getXGMMLTree(false);
  176. Owned<IPropertyTreeIterator> iter = xgmml->getElements(".//node");
  177. ForEach(*iter)
  178. {
  179. try
  180. {
  181. IPropertyTree &node = iter->query();
  182. ThorActivityKind kind = (ThorActivityKind) node.getPropInt("att[@name='_kind']/@value", TAKnone);
  183. if(kind==TAKdiskwrite || kind==TAKspillwrite || kind==TAKindexwrite || kind==TAKcsvwrite || kind==TAKxmlwrite || kind==TAKjsonwrite)
  184. continue;
  185. if (node.getPropBool("att[@name='_isSpill']/@value") || node.getPropBool("att[@name='_isTransformSpill']/@value"))
  186. continue;
  187. Owned<IEspWULogicalFileCopyInfo> info = createWULogicalFileCopyInfo();
  188. const char *logicalname = node.queryProp("att[@name='_indexFileName']/@value");
  189. if (logicalname)
  190. info->setIsIndex(true);
  191. else
  192. logicalname = node.queryProp("att[@name='_fileName']/@value");
  193. info->setLogicalName(logicalname);
  194. if (logicalname)
  195. {
  196. if (!strnicmp("~foreign::", logicalname, 10))
  197. foreign.append(*info.getClear());
  198. else
  199. {
  200. Owned<IDistributedFile> df = queryDistributedFileDirectory().lookup(logicalname, udesc, false, false, false, nullptr, defaultPrivilegedUser);
  201. if(!df)
  202. notFound.append(*info.getClear());
  203. else if (df->findCluster(cluster)!=NotFound)
  204. {
  205. onCluster.append(*info.getClear());
  206. }
  207. else
  208. {
  209. StringArray clusters;
  210. df->getClusterNames(clusters);
  211. info->setClusters(clusters);
  212. if (copyLocal)
  213. {
  214. StringBuffer wuid;
  215. bool supercopy = queryDistributedFileDirectory().isSuperFile(logicalname, udesc, NULL);
  216. doWuFileCopy(*fs, *info, logicalname, cluster, isRoxie, supercopy);
  217. }
  218. notOnCluster.append(*info.getClear());
  219. }
  220. }
  221. }
  222. }
  223. catch(IException *e)
  224. {
  225. e->Release();
  226. }
  227. }
  228. lfinfo.setClusterName(cluster);
  229. lfinfo.setNotOnCluster(notOnCluster);
  230. lfinfo.setOnCluster(onCluster);
  231. lfinfo.setForeign(foreign);
  232. lfinfo.setNotFound(notFound);
  233. }
  234. return true;
  235. }
  236. void copyWULogicalFilesToTarget(IEspContext &context, IConstWUClusterInfo &clusterInfo, IConstWorkUnit &cw, IArrayOf<IConstWUCopyLogicalClusterFileSections> &clusterfiles, bool doLocalCopy)
  237. {
  238. const StringArray &thors = clusterInfo.getThorProcesses();
  239. ForEachItemIn(i, thors)
  240. {
  241. Owned<IEspWUCopyLogicalClusterFileSections> files = createWUCopyLogicalClusterFileSections();
  242. copyWULogicalFiles(context, cw, thors.item(i), doLocalCopy, *files);
  243. clusterfiles.append(*files.getClear());
  244. }
  245. SCMStringBuffer roxie;
  246. clusterInfo.getRoxieProcess(roxie);
  247. if (roxie.length())
  248. {
  249. Owned<IEspWUCopyLogicalClusterFileSections> files = createWUCopyLogicalClusterFileSections();
  250. copyWULogicalFiles(context, cw, roxie.str(), doLocalCopy, *files);
  251. clusterfiles.append(*files.getClear());
  252. }
  253. }
  254. void QueryFilesInUse::loadTarget(IPropertyTree *t, const char *target, unsigned flags)
  255. {
  256. if (!target || !*target)
  257. return;
  258. Owned<IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(target);
  259. if (!clusterInfo || !(clusterInfo->getPlatform() == RoxieCluster))
  260. return;
  261. Owned<IPropertyTree> queryRegistry = getQueryRegistry(target, true);
  262. if (!queryRegistry)
  263. return;
  264. SCMStringBuffer process;
  265. clusterInfo->getRoxieProcess(process);
  266. if (!process.length())
  267. return;
  268. Owned<IHpccPackageSet> ps = createPackageSet(process.str());
  269. const IHpccPackageMap *pm = (ps) ? ps->queryActiveMap(target) : NULL;
  270. const char *pmid = (pm) ? pm->queryPackageId() : NULL;
  271. VStringBuffer xpath("%s/@pmid", target);
  272. const char *pmidPrev = t->queryProp(xpath);
  273. if ((flags & UFO_RELOAD_TARGETS_CHANGED_PMID) && (pmid || pmidPrev))
  274. {
  275. if (!(pmid && pmidPrev) || !streq(pmid, pmidPrev))
  276. t->removeProp(target);
  277. }
  278. IPropertyTree *targetTree = ensurePTree(t, target);
  279. if (pm)
  280. targetTree->setProp("@pmid", pmid);
  281. if (flags & UFO_REMOVE_QUERIES_NOT_IN_QUERYSET)
  282. {
  283. Owned<IPropertyTreeIterator> cachedQueries = targetTree->getElements("Query");
  284. ForEach(*cachedQueries)
  285. {
  286. IPropertyTree &cachedQuery = cachedQueries->query();
  287. VStringBuffer xpath("Query[@id='%s']", cachedQuery.queryProp("@id"));
  288. if (!queryRegistry->hasProp(xpath))
  289. targetTree->removeTree(&cachedQuery);
  290. }
  291. }
  292. Owned<IPropertyTreeIterator> queries = queryRegistry->getElements("Query");
  293. ForEach(*queries)
  294. {
  295. if (aborting)
  296. return;
  297. IPropertyTree &query = queries->query();
  298. const char *queryid = query.queryProp("@id");
  299. if (!queryid || !*queryid)
  300. continue;
  301. const char *wuid = query.queryProp("@wuid");
  302. if (!wuid || !*wuid)
  303. continue;
  304. const char *pkgid=NULL;
  305. if (pm)
  306. {
  307. const IHpccPackage *pkg = pm->matchPackage(queryid);
  308. if (pkg)
  309. pkgid = pkg->queryId();
  310. }
  311. VStringBuffer xpath("Query[@id='%s']", queryid);
  312. IPropertyTree *queryTree = targetTree->queryPropTree(xpath);
  313. if (queryTree)
  314. {
  315. const char *cachedPkgid = queryTree->queryProp("@pkgid");
  316. if (pkgid && *pkgid)
  317. {
  318. if (!(flags & UFO_RELOAD_MAPPED_QUERIES) && (cachedPkgid && streq(pkgid, cachedPkgid)))
  319. continue;
  320. }
  321. else if (!cachedPkgid || !*cachedPkgid)
  322. continue;
  323. targetTree->removeTree(queryTree);
  324. queryTree = NULL;
  325. }
  326. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  327. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid);
  328. if (!cw)
  329. continue;
  330. queryTree = targetTree->addPropTree("Query", createPTree("Query"));
  331. queryTree->setProp("@target", target); //for reference when searching across targets
  332. queryTree->setProp("@id", queryid);
  333. if (pkgid && *pkgid)
  334. queryTree->setProp("@pkgid", pkgid);
  335. IUserDescriptor **roxieUser = roxieUserMap.getValue(target);
  336. Owned<IReferencedFileList> wufiles = createReferencedFileList(roxieUser ? *roxieUser : NULL, true, true);
  337. wufiles->addFilesFromQuery(cw, pm, queryid);
  338. if (aborting)
  339. return;
  340. wufiles->resolveFiles(process.str(), NULL, NULL, NULL, true, true, false, false);
  341. Owned<IReferencedFileIterator> files = wufiles->getFiles();
  342. ForEach(*files)
  343. {
  344. if (aborting)
  345. return;
  346. IReferencedFile &rf = files->query();
  347. //if (!(rf.getFlags() & RefSubFile))
  348. // continue;
  349. const char *lfn = rf.getLogicalName();
  350. if (!lfn || !*lfn)
  351. continue;
  352. if (!queryTree->hasProp(xpath.setf("File[@lfn='%s']", lfn)))
  353. {
  354. IPropertyTree *fileTree = queryTree->addPropTree("File", createPTree("File"));
  355. fileTree->setProp("@lfn", lfn);
  356. if (rf.getFlags() & RefFileSuper)
  357. fileTree->setPropBool("@super", true);
  358. if (rf.getFlags() & RefFileNotFound)
  359. fileTree->setPropBool("@notFound", true);
  360. const char *fpkgid = rf.queryPackageId();
  361. if (fpkgid && *fpkgid)
  362. fileTree->setProp("@pkgid", fpkgid);
  363. if (rf.getFileSize())
  364. fileTree->setPropInt64("@size", rf.getFileSize());
  365. if (rf.getNumParts())
  366. fileTree->setPropInt("@numparts", rf.getNumParts());
  367. }
  368. }
  369. }
  370. }
  371. void QueryFilesInUse::loadTargets(IPropertyTree *t, unsigned flags)
  372. {
  373. Owned<IStringIterator> targets = getTargetClusters("RoxieCluster", NULL);
  374. SCMStringBuffer s;
  375. ForEach(*targets)
  376. {
  377. if (aborting)
  378. return;
  379. loadTarget(t, targets->str(s).str(), flags);
  380. }
  381. }
  382. IPropertyTreeIterator *QueryFilesInUse::findAllQueriesUsingFile(const char *lfn)
  383. {
  384. if (!lfn || !*lfn)
  385. return NULL;
  386. Owned<IPropertyTree> t = getTree();
  387. VStringBuffer xpath("*/Query[File/@lfn='%s']", lfn);
  388. return t->getElements(xpath);
  389. }
  390. IPropertyTreeIterator *QueryFilesInUse::findQueriesUsingFile(const char *target, const char *lfn, StringAttr &pmid)
  391. {
  392. if (!lfn || !*lfn)
  393. return NULL;
  394. if (!target || !*target)
  395. return findAllQueriesUsingFile(lfn);
  396. Owned<IPropertyTree> t = getTree();
  397. IPropertyTree *targetTree = t->queryPropTree(target);
  398. if (!targetTree)
  399. return NULL;
  400. pmid.set(targetTree->queryProp("@pmid"));
  401. VStringBuffer xpath("Query[File/@lfn='%s']", lfn);
  402. return targetTree->getElements(xpath);
  403. }
  404. bool CWsWorkunitsEx::onWUCopyLogicalFiles(IEspContext &context, IEspWUCopyLogicalFilesRequest &req, IEspWUCopyLogicalFilesResponse &resp)
  405. {
  406. StringBuffer wuid(req.getWuid());
  407. WsWuHelpers::checkAndTrimWorkunit("WUCopyLogicalFiles", wuid);
  408. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  409. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  410. if (!cw)
  411. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot open workunit %s", wuid.str());
  412. ensureWsWorkunitAccess(context, *cw, SecAccess_Full);
  413. resp.setWuid(wuid.str());
  414. StringAttr cluster;
  415. if (notEmpty(req.getCluster()))
  416. cluster.set(req.getCluster());
  417. else
  418. cluster.set(cw->queryClusterName());
  419. if (!isValidCluster(cluster))
  420. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid cluster name: %s", cluster.str());
  421. Owned <IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(cluster.str());
  422. IArrayOf<IConstWUCopyLogicalClusterFileSections> clusterfiles;
  423. PROGLOG("WUCopyLogicalFiles: %s", wuid.str());
  424. copyWULogicalFilesToTarget(context, *clusterInfo, *cw, clusterfiles, req.getCopyLocal());
  425. resp.setClusterFiles(clusterfiles);
  426. return true;
  427. }
  428. static inline unsigned remainingMsWait(unsigned wait, unsigned start)
  429. {
  430. if (wait==0 || wait==(unsigned)-1)
  431. return wait;
  432. unsigned waited = msTick()-start;
  433. return (wait>waited) ? wait-waited : 0;
  434. }
  435. bool reloadCluster(IConstWUClusterInfo *clusterInfo, unsigned wait)
  436. {
  437. if (0==wait || !clusterInfo || clusterInfo->getPlatform()!=RoxieCluster)
  438. return true;
  439. const SocketEndpointArray &addrs = clusterInfo->getRoxieServers();
  440. if (addrs.length())
  441. {
  442. try
  443. {
  444. Owned<IPropertyTree> result = sendRoxieControlAllNodes(addrs.item(0), "<control:reload/>", false, wait);
  445. const char *status = result->queryProp("Endpoint[1]/Status");
  446. if (!status || !strieq(status, "ok"))
  447. return false;
  448. }
  449. catch(IMultiException *me)
  450. {
  451. StringBuffer err;
  452. IERRLOG("ERROR control:reloading roxie query info %s", me->errorMessage(err.append(me->errorCode()).append(' ')).str());
  453. me->Release();
  454. return false;
  455. }
  456. catch(IException *e)
  457. {
  458. StringBuffer err;
  459. IERRLOG("ERROR control:reloading roxie query info %s", e->errorMessage(err.append(e->errorCode()).append(' ')).str());
  460. e->Release();
  461. return false;
  462. }
  463. }
  464. return true;
  465. }
  466. bool reloadCluster(const char *cluster, unsigned wait)
  467. {
  468. Owned <IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(cluster);
  469. return (clusterInfo) ? reloadCluster(clusterInfo, wait) : true;
  470. }
  471. static inline void updateQuerySetting(bool ignore, IPropertyTree *queryTree, const char *xpath, int value)
  472. {
  473. if (ignore || !queryTree)
  474. return;
  475. if (value!=0)
  476. queryTree->setPropInt(xpath, value);
  477. else
  478. queryTree->removeProp(xpath);
  479. }
  480. static inline void updateTimeLimitSetting(IPropertyTree *queryTree, bool valueNotSet, int value, IConstQuerySetQuery *srcInfo=NULL)
  481. {
  482. if (valueNotSet && srcInfo && !srcInfo->getTimeLimit_isNull())
  483. {
  484. value = srcInfo->getTimeLimit();
  485. valueNotSet=false;
  486. }
  487. updateQuerySetting(valueNotSet, queryTree, "@timeLimit", value);
  488. }
  489. static inline void updateWarnTimeLimitSetting(IPropertyTree *queryTree, bool valueNotSet, int value, IConstQuerySetQuery *srcInfo=NULL)
  490. {
  491. if (valueNotSet && srcInfo && !srcInfo->getWarnTimeLimit_isNull())
  492. {
  493. value = srcInfo->getWarnTimeLimit();
  494. valueNotSet=false;
  495. }
  496. updateQuerySetting(valueNotSet, queryTree, "@warnTimeLimit", value);
  497. }
  498. static inline unsigned __int64 memoryLimitUInt64FromString(const char *value)
  499. {
  500. if (!value || !*value || !isdigit(*value))
  501. return 0;
  502. unsigned __int64 result = (*value - '0');
  503. const char *s = value+1;
  504. while (isdigit(*s))
  505. {
  506. result = 10 * result + ((*s) - '0');
  507. s++;
  508. }
  509. if (*s)
  510. {
  511. const char unit = toupper(*s++);
  512. if (*s && !strieq("B", s)) //more?
  513. return 0;
  514. switch (unit)
  515. {
  516. case 'E':
  517. result <<=60;
  518. break;
  519. case 'P':
  520. result <<=50;
  521. break;
  522. case 'T':
  523. result <<=40;
  524. break;
  525. case 'G':
  526. result <<=30;
  527. break;
  528. case 'M':
  529. result <<=20;
  530. break;
  531. case 'K':
  532. result <<=10;
  533. break;
  534. case 'B':
  535. break;
  536. default:
  537. return 0;
  538. }
  539. }
  540. return result;
  541. }
  542. const char memUnitAbbrev[] = {'B', 'K', 'M', 'G', 'T', 'P', 'E'};
  543. #define MAX_MEMUNIT_ABBREV 6
  544. static inline StringBuffer &memoryLimitStringFromUInt64(StringBuffer &s, unsigned __int64 in)
  545. {
  546. if (!in)
  547. return s;
  548. unsigned __int64 value = in;
  549. unsigned char unit = 0;
  550. while (!(value & 0x3FF) && unit < MAX_MEMUNIT_ABBREV)
  551. {
  552. value >>= 10;
  553. unit++;
  554. }
  555. return s.append(value).append(memUnitAbbrev[unit]);
  556. }
  557. static inline void updateMemoryLimitSetting(IPropertyTree *queryTree, const char *value, IConstQuerySetQuery *srcInfo=NULL)
  558. {
  559. if (!queryTree)
  560. return;
  561. if (!value && srcInfo)
  562. value = srcInfo->getMemoryLimit();
  563. if (!value)
  564. return;
  565. unsigned __int64 limit = memoryLimitUInt64FromString(value);
  566. if (0==limit)
  567. queryTree->removeProp("@memoryLimit");
  568. else
  569. queryTree->setPropInt64("@memoryLimit", limit);
  570. }
  571. enum QueryPriority {
  572. QueryPriorityNone = -1,
  573. QueryPriorityLow = 0,
  574. QueryPriorityHigh = 1,
  575. QueryPrioritySLA = 2,
  576. QueryPriorityInvalid = 3
  577. };
  578. static inline const char *getQueryPriorityName(int value)
  579. {
  580. switch (value)
  581. {
  582. case QueryPriorityLow:
  583. return "LOW";
  584. case QueryPriorityHigh:
  585. return "HIGH";
  586. case QueryPrioritySLA:
  587. return "SLA";
  588. case QueryPriorityNone:
  589. return "NONE";
  590. }
  591. return "INVALID";
  592. }
  593. static inline void updateQueryPriority(IPropertyTree *queryTree, const char *value, IConstQuerySetQuery *srcInfo=NULL)
  594. {
  595. if (!queryTree)
  596. return;
  597. if ((!value || !*value) && srcInfo)
  598. value = srcInfo->getPriority();
  599. if (!value || !*value)
  600. return;
  601. int priority = QueryPriorityInvalid;
  602. if (strieq("LOW", value))
  603. priority=QueryPriorityLow;
  604. else if (strieq("HIGH", value))
  605. priority=QueryPriorityHigh;
  606. else if (strieq("SLA", value))
  607. priority=QueryPrioritySLA;
  608. else if (strieq("NONE", value))
  609. priority=QueryPriorityNone;
  610. switch (priority)
  611. {
  612. case QueryPriorityInvalid:
  613. break;
  614. case QueryPriorityNone:
  615. queryTree->removeProp("@priority");
  616. break;
  617. default:
  618. queryTree->setPropInt("@priority", priority);
  619. break;
  620. }
  621. }
  622. void gatherFileErrors(IReferencedFileList *files, IArrayOf<IConstLogicalFileError> &errors)
  623. {
  624. if (!files)
  625. return;
  626. Owned<IReferencedFileIterator> it = files->getFiles();
  627. ForEach(*it)
  628. {
  629. IReferencedFile &file = it->query();
  630. unsigned flags = file.getFlags();
  631. if (!(flags & (RefFileNotFound | RefFileCopyInfoFailed)))
  632. continue;
  633. StringBuffer msg;
  634. if (flags & RefFileOptional)
  635. msg.append("OPT ");
  636. if (flags & RefFileNotFound)
  637. msg.append("Not Found");
  638. else
  639. msg.append("Copy Failed");
  640. Owned<IEspLogicalFileError> error = createLogicalFileError();
  641. error->setLogicalName(file.getLogicalName());
  642. error->setError(msg);
  643. errors.append(*static_cast<IConstLogicalFileError*>(error.getClear()));
  644. }
  645. }
  646. class QueryFileCopier
  647. {
  648. public:
  649. QueryFileCopier(const char *target_) : target(target_) {}
  650. void init(IEspContext &context, bool allowForeignFiles)
  651. {
  652. files.setown(createReferencedFileList(context.queryUserId(), context.queryPassword(), allowForeignFiles, false));
  653. clusterInfo.setown(getTargetClusterInfo(target));
  654. StringBufferAdaptor sba(process);
  655. if (clusterInfo && clusterInfo->getPlatform()==RoxieCluster)
  656. clusterInfo->getRoxieProcess(sba);
  657. if (!process.length())
  658. return;
  659. ps.setown(createPackageSet(process.str()));
  660. if (ps)
  661. pm = ps->queryActiveMap(target);
  662. }
  663. void copy(IConstWorkUnit *cw, unsigned updateFlags)
  664. {
  665. StringBuffer queryid;
  666. if (queryname && *queryname)
  667. queryname = queryid.append(queryname).append(".0").str(); //prepublish dummy version number to support fuzzy match like queries="myquery.*" in package
  668. files->addFilesFromQuery(cw, pm, queryname);
  669. files->resolveFiles(process.str(), remoteIP, remotePrefix, srcCluster, !(updateFlags & (DALI_UPDATEF_REPLACE_FILE | DALI_UPDATEF_CLONE_FROM | DALI_UPDATEF_SUPERFILES)), true, false, true);
  670. StringBuffer defReplicateFolder;
  671. getConfigurationDirectory(NULL, "data2", "roxie", process.str(), defReplicateFolder);
  672. Owned<IDFUhelper> helper = createIDFUhelper();
  673. files->cloneAllInfo(updateFlags, helper, true, true, clusterInfo->getRoxieRedundancy(), clusterInfo->getChannelsPerNode(), clusterInfo->getRoxieReplicateOffset(), defReplicateFolder);
  674. }
  675. void gatherFileErrors(IArrayOf<IConstLogicalFileError> &errors)
  676. {
  677. ::gatherFileErrors(files, errors);
  678. }
  679. private:
  680. Owned <IConstWUClusterInfo> clusterInfo;
  681. Owned<IHpccPackageSet> ps;
  682. const IHpccPackageMap *pm = nullptr;
  683. StringAttr target;
  684. public:
  685. Owned<IReferencedFileList> files;
  686. StringBuffer process;
  687. StringAttr remoteIP;
  688. StringAttr remotePrefix;
  689. StringAttr srcCluster;
  690. StringAttr queryname;
  691. };
  692. bool CWsWorkunitsEx::isQuerySuspended(const char* query, IConstWUClusterInfo *clusterInfo, unsigned wait, StringBuffer& errorMessage)
  693. {
  694. try
  695. {
  696. if (0==wait || !clusterInfo || clusterInfo->getPlatform()!=RoxieCluster)
  697. return false;
  698. const SocketEndpointArray &addrs = clusterInfo->getRoxieServers();
  699. if (addrs.length() < 1)
  700. return false;
  701. StringBuffer control;
  702. control.appendf("<control:queries><Query id='%s'/></control:queries>", query);
  703. Owned<IPropertyTree> result = sendRoxieControlAllNodes(addrs.item(0), control.str(), false, wait);
  704. if (!result)
  705. return false;
  706. Owned<IPropertyTreeIterator> suspendedQueries = result->getElements("Endpoint/Queries/Query[@suspended='1']");
  707. if (!suspendedQueries->first())
  708. return false;
  709. errorMessage.set(suspendedQueries->query().queryProp("@error"));
  710. return true;
  711. }
  712. catch(IMultiException *me)
  713. {
  714. StringBuffer err;
  715. IERRLOG("ERROR control:queries roxie query info %s", me->errorMessage(err.append(me->errorCode()).append(' ')).str());
  716. me->Release();
  717. return false;
  718. }
  719. catch(IException *e)
  720. {
  721. StringBuffer err;
  722. IERRLOG("ERROR control:queries roxie query info %s", e->errorMessage(err.append(e->errorCode()).append(' ')).str());
  723. e->Release();
  724. return false;
  725. }
  726. }
  727. bool CWsWorkunitsEx::onWUPublishWorkunit(IEspContext &context, IEspWUPublishWorkunitRequest & req, IEspWUPublishWorkunitResponse & resp)
  728. {
  729. StringBuffer wuid(req.getWuid());
  730. WsWuHelpers::checkAndTrimWorkunit("WUPublishWorkunit", wuid);
  731. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  732. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  733. if (!cw)
  734. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot find the workunit %s", wuid.str());
  735. ensureWsWorkunitAccess(context, *cw, SecAccess_Full);
  736. resp.setWuid(wuid.str());
  737. StringAttr queryName;
  738. if (notEmpty(req.getJobName()))
  739. queryName.set(req.getJobName());
  740. else
  741. queryName.set(cw->queryJobName());
  742. if (!queryName.length())
  743. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Query/Job name not defined for publishing workunit %s", wuid.str());
  744. StringAttr target;
  745. if (notEmpty(req.getCluster()))
  746. target.set(req.getCluster());
  747. else
  748. target.set(cw->queryClusterName());
  749. if (!target.length())
  750. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Cluster name not defined for publishing workunit %s", wuid.str());
  751. if (!isValidCluster(target.str()))
  752. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid cluster name: %s", target.str());
  753. DBGLOG("%s publishing wuid %s to target %s as query %s", context.queryUserId(), wuid.str(), target.str(), queryName.str());
  754. StringBuffer daliIP;
  755. StringBuffer srcCluster;
  756. StringBuffer srcPrefix;
  757. splitDerivedDfsLocation(req.getRemoteDali(), srcCluster, daliIP, srcPrefix, req.getSourceProcess(),req.getSourceProcess(), NULL, NULL);
  758. if (srcCluster.length())
  759. {
  760. if (!isProcessCluster(daliIP, srcCluster))
  761. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Process cluster %s not found on %s DALI", srcCluster.str(), daliIP.length() ? daliIP.str() : "local");
  762. }
  763. unsigned updateFlags = 0;
  764. if (req.getUpdateDfs())
  765. updateFlags |= (DALI_UPDATEF_SUPERFILES | DALI_UPDATEF_REPLACE_FILE | DALI_UPDATEF_CLONE_FROM);
  766. if (req.getUpdateCloneFrom())
  767. updateFlags |= DALI_UPDATEF_CLONE_FROM;
  768. if (req.getUpdateSuperFiles())
  769. updateFlags |= DALI_UPDATEF_SUPERFILES;
  770. if (req.getAppendCluster())
  771. updateFlags |= DALI_UPDATEF_APPEND_CLUSTER;
  772. if (!req.getDontCopyFiles())
  773. {
  774. QueryFileCopier cpr(target);
  775. cpr.init(context, req.getAllowForeignFiles());
  776. cpr.remoteIP.set(daliIP);
  777. cpr.remotePrefix.set(srcPrefix);
  778. cpr.srcCluster.set(srcCluster);
  779. cpr.queryname.set(queryName);
  780. cpr.copy(cw, updateFlags);
  781. if (req.getIncludeFileErrors())
  782. cpr.gatherFileErrors(resp.getFileErrors());
  783. }
  784. WorkunitUpdate wu(&cw->lock());
  785. if (req.getUpdateWorkUnitName() && notEmpty(req.getJobName()))
  786. wu->setJobName(req.getJobName());
  787. StringBuffer queryId;
  788. WUQueryActivationOptions activate = (WUQueryActivationOptions)req.getActivate();
  789. addQueryToQuerySet(wu, target.str(), queryName.str(), activate, queryId, context.queryUserId());
  790. if (req.getMemoryLimit() || !req.getTimeLimit_isNull() || !req.getWarnTimeLimit_isNull() || req.getPriority() || req.getComment())
  791. {
  792. Owned<IPropertyTree> queryTree = getQueryById(target.str(), queryId, false);
  793. updateMemoryLimitSetting(queryTree, req.getMemoryLimit());
  794. updateQuerySetting(req.getTimeLimit_isNull(), queryTree, "@timeLimit", req.getTimeLimit());
  795. updateQuerySetting(req.getWarnTimeLimit_isNull(), queryTree, "@warnTimeLimit", req.getWarnTimeLimit());
  796. updateQueryPriority(queryTree, req.getPriority());
  797. if (req.getComment())
  798. queryTree->setProp("@comment", req.getComment());
  799. }
  800. wu->commit();
  801. wu.clear();
  802. if (queryId.length())
  803. resp.setQueryId(queryId.str());
  804. resp.setQueryName(queryName.str());
  805. resp.setQuerySet(target.str());
  806. Owned <IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(target.str());
  807. bool reloadFailed = false;
  808. if (0!=req.getWait() && !req.getNoReload())
  809. reloadFailed = !reloadCluster(clusterInfo, (unsigned)req.getWait());
  810. resp.setReloadFailed(reloadFailed);
  811. double version = context.getClientVersion();
  812. if (version > 1.38)
  813. {
  814. StringBuffer errorMessage;
  815. if (!reloadFailed && !req.getNoReload() && isQuerySuspended(queryName.str(), clusterInfo, (unsigned)req.getWait(), errorMessage))
  816. {
  817. resp.setSuspended(true);
  818. resp.setErrorMessage(errorMessage);
  819. }
  820. }
  821. return true;
  822. }
  823. bool CWsWorkunitsEx::onWUQuerysets(IEspContext &context, IEspWUQuerysetsRequest & req, IEspWUQuerysetsResponse & resp)
  824. {
  825. IArrayOf<IEspQuerySet> querySets;
  826. Owned<IStringIterator> targets = getTargetClusters(NULL, NULL);
  827. SCMStringBuffer target;
  828. ForEach(*targets)
  829. {
  830. Owned<IEspQuerySet> qs = createQuerySet();
  831. qs->setQuerySetName(targets->str(target).str());
  832. querySets.append(*qs.getClear());
  833. }
  834. resp.setQuerysets(querySets);
  835. return true;
  836. }
  837. void addClusterQueryStates(IPropertyTree* queriesOnCluster, const char *target, const char *id, IArrayOf<IEspClusterQueryState>& clusterStates, double version)
  838. {
  839. if (queriesOnCluster)
  840. queriesOnCluster = queriesOnCluster->queryPropTree("Endpoint[1]/Queries[1]");
  841. if (!queriesOnCluster)
  842. return;
  843. int reporting = queriesOnCluster->getPropInt("@reporting");
  844. Owned<IEspClusterQueryState> clusterState = createClusterQueryState();
  845. clusterState->setCluster(target);
  846. VStringBuffer xpath("Query[@id='%s']", id);
  847. IPropertyTree *query = queriesOnCluster->queryPropTree(xpath.str());
  848. if (!query)
  849. clusterState->setState("Not Found");
  850. else
  851. {
  852. int suspended = query->getPropInt("@suspended");
  853. const char* error = query->queryProp("@error");
  854. if (0==suspended)
  855. clusterState->setState("Available");
  856. else
  857. {
  858. clusterState->setState("Suspended");
  859. if (suspended<reporting)
  860. clusterState->setMixedNodeStates(true);
  861. }
  862. if (error && *error)
  863. clusterState->setErrors(error);
  864. }
  865. clusterStates.append(*clusterState.getClear());
  866. }
  867. void gatherQuerySetQueryDetails(IEspContext &context, IPropertyTree *query, IEspQuerySetQuery *queryInfo, const char *cluster, IPropertyTree *queriesOnCluster)
  868. {
  869. queryInfo->setId(query->queryProp("@id"));
  870. queryInfo->setName(query->queryProp("@name"));
  871. queryInfo->setDll(query->queryProp("@dll"));
  872. queryInfo->setWuid(query->queryProp("@wuid"));
  873. queryInfo->setSuspended(query->getPropBool("@suspended", false));
  874. if (query->hasProp("@memoryLimit"))
  875. {
  876. StringBuffer s;
  877. memoryLimitStringFromUInt64(s, query->getPropInt64("@memoryLimit"));
  878. queryInfo->setMemoryLimit(s);
  879. }
  880. if (query->hasProp("@timeLimit"))
  881. queryInfo->setTimeLimit(query->getPropInt("@timeLimit"));
  882. if (query->hasProp("@warnTimeLimit"))
  883. queryInfo->setWarnTimeLimit(query->getPropInt("@warnTimeLimit"));
  884. if (query->hasProp("@priority"))
  885. queryInfo->setPriority(getQueryPriorityName(query->getPropInt("@priority")));
  886. if (query->hasProp("@comment"))
  887. queryInfo->setComment(query->queryProp("@comment"));
  888. if (query->hasProp("@snapshot"))
  889. queryInfo->setSnapshot(query->queryProp("@snapshot"));
  890. double version = context.getClientVersion();
  891. if (version >= 1.46)
  892. {
  893. queryInfo->setPublishedBy(query->queryProp("@publishedBy"));
  894. queryInfo->setIsLibrary(query->getPropBool("@isLibrary"));
  895. }
  896. if (queriesOnCluster)
  897. {
  898. IArrayOf<IEspClusterQueryState> clusters;
  899. addClusterQueryStates(queriesOnCluster, cluster, query->queryProp("@id"), clusters, version);
  900. queryInfo->setClusters(clusters);
  901. }
  902. }
  903. void gatherQuerySetAliasDetails(IPropertyTree *alias, IEspQuerySetAlias *aliasInfo)
  904. {
  905. aliasInfo->setName(alias->queryProp("@name"));
  906. aliasInfo->setId(alias->queryProp("@id"));
  907. }
  908. void retrieveAllQuerysetDetails(IEspContext &context, IPropertyTree *registry, IArrayOf<IEspQuerySetQuery> &queries, IArrayOf<IEspQuerySetAlias> &aliases, const char *cluster=NULL, IPropertyTree *queriesOnCluster=NULL, const char *type=NULL, const char *value=NULL)
  909. {
  910. Owned<IPropertyTreeIterator> regQueries = registry->getElements("Query");
  911. ForEach(*regQueries)
  912. {
  913. IPropertyTree &query = regQueries->query();
  914. Owned<IEspQuerySetQuery> q = createQuerySetQuery();
  915. gatherQuerySetQueryDetails(context, &query, q, cluster, queriesOnCluster);
  916. if (isEmpty(cluster) || isEmpty(type) || isEmpty(value) || !strieq(type, "Status"))
  917. queries.append(*q.getClear());
  918. else
  919. {
  920. IArrayOf<IConstClusterQueryState>& cs = q->getClusters();
  921. ForEachItemIn(i, cs)
  922. {
  923. IConstClusterQueryState& c = cs.item(i);
  924. if (strieq(c.getCluster(), cluster) && (strieq(value, "All") || strieq(c.getState(), value)))
  925. {
  926. queries.append(*q.getClear());
  927. break;
  928. }
  929. }
  930. }
  931. }
  932. Owned<IPropertyTreeIterator> regAliases = registry->getElements("Alias");
  933. ForEach(*regAliases)
  934. {
  935. IPropertyTree &alias = regAliases->query();
  936. Owned<IEspQuerySetAlias> a = createQuerySetAlias();
  937. gatherQuerySetAliasDetails(&alias, a);
  938. aliases.append(*a.getClear());
  939. }
  940. }
  941. void retrieveQuerysetDetailsFromAlias(IEspContext &context, IPropertyTree *registry, const char *name, IArrayOf<IEspQuerySetQuery> &queries, IArrayOf<IEspQuerySetAlias> &aliases, const char *cluster, IPropertyTree *queriesOnCluster)
  942. {
  943. StringBuffer xpath;
  944. xpath.append("Alias[@name='").append(name).append("']");
  945. Owned<IPropertyTreeIterator> regAliases = registry->getElements(xpath.str());
  946. if (!regAliases->first())
  947. {
  948. UWARNLOG("Alias %s not found", name);
  949. return;
  950. }
  951. ForEach(*regAliases)
  952. {
  953. IPropertyTree& alias = regAliases->query();
  954. Owned<IEspQuerySetAlias> a = createQuerySetAlias();
  955. gatherQuerySetAliasDetails(&alias, a);
  956. xpath.clear().append("Query[@id='").append(a->getId()).append("']");
  957. aliases.append(*a.getClear());
  958. IPropertyTree *query = registry->queryPropTree(xpath);
  959. if (!query)
  960. {
  961. UWARNLOG("No matching Query %s found for Alias %s", a->getId(), name);
  962. return;
  963. }
  964. Owned<IEspQuerySetQuery> q = createQuerySetQuery();
  965. gatherQuerySetQueryDetails(context, query, q, cluster, queriesOnCluster);
  966. queries.append(*q.getClear());
  967. }
  968. }
  969. void retrieveQuerysetDetailsFromQuery(IEspContext &context, IPropertyTree *registry, const char *value, const char *type, IArrayOf<IEspQuerySetQuery> &queries, IArrayOf<IEspQuerySetAlias> &aliases, const char *cluster=NULL, IPropertyTree *queriesOnCluster=NULL)
  970. {
  971. if (!strieq(type, "Id") && !strieq(type, "Name"))
  972. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Unrecognized queryset filter type %s", type);
  973. StringBuffer attributeName(type);
  974. StringBuffer xpath;
  975. xpath.clear().append("Query[@").append(attributeName.toLowerCase()).append("='").append(value).append("']");
  976. Owned<IPropertyTreeIterator> regQueries = registry->getElements(xpath.str());
  977. if (!regQueries->first())
  978. {
  979. UWARNLOG("No matching Query %s found for %s", value, type);
  980. return;
  981. }
  982. ForEach(*regQueries)
  983. {
  984. IPropertyTree& query = regQueries->query();
  985. Owned<IEspQuerySetQuery> q = createQuerySetQuery();
  986. gatherQuerySetQueryDetails(context, &query, q, cluster, queriesOnCluster);
  987. xpath.clear().append("Alias[@id='").append(q->getId()).append("']");
  988. queries.append(*q.getClear());
  989. Owned<IPropertyTreeIterator> regAliases = registry->getElements(xpath.str());
  990. ForEach(*regAliases)
  991. {
  992. IPropertyTree &alias = regAliases->query();
  993. Owned<IEspQuerySetAlias> a = createQuerySetAlias();
  994. gatherQuerySetAliasDetails(&alias, a);
  995. aliases.append(*a.getClear());
  996. }
  997. }
  998. }
  999. void retrieveQuerysetDetails(IEspContext &context, IPropertyTree *registry, const char *type, const char *value, IArrayOf<IEspQuerySetQuery> &queries, IArrayOf<IEspQuerySetAlias> &aliases, const char *cluster=NULL, IPropertyTree *queriesOnCluster=NULL)
  1000. {
  1001. if (strieq(type, "All"))
  1002. return retrieveAllQuerysetDetails(context, registry, queries, aliases, cluster, queriesOnCluster);
  1003. if (!value || !*value)
  1004. return;
  1005. if (strieq(type, "Alias"))
  1006. return retrieveQuerysetDetailsFromAlias(context, registry, value, queries, aliases, cluster, queriesOnCluster);
  1007. if (strieq(type, "Status") && !isEmpty(cluster))
  1008. return retrieveAllQuerysetDetails(context, registry, queries, aliases, cluster, queriesOnCluster, type, value);
  1009. return retrieveQuerysetDetailsFromQuery(context, registry, value, type, queries, aliases, cluster, queriesOnCluster);
  1010. }
  1011. void retrieveQuerysetDetails(IEspContext &context, IArrayOf<IEspWUQuerySetDetail> &details, IPropertyTree *registry, const char *type, const char *value, const char *cluster=NULL, IPropertyTree *queriesOnCluster=NULL)
  1012. {
  1013. if (!registry)
  1014. return;
  1015. IArrayOf<IEspQuerySetQuery> queries;
  1016. IArrayOf<IEspQuerySetAlias> aliases;
  1017. retrieveQuerysetDetails(context, registry, type, value, queries, aliases, cluster, queriesOnCluster);
  1018. Owned<IEspWUQuerySetDetail> detail = createWUQuerySetDetail();
  1019. detail->setQuerySetName(registry->queryProp("@id"));
  1020. detail->setQueries(queries);
  1021. detail->setAliases(aliases);
  1022. details.append(*detail.getClear());
  1023. }
  1024. void retrieveQuerysetDetails(IEspContext &context, IArrayOf<IEspWUQuerySetDetail> &details, const char *queryset, const char *type, const char *value, const char *cluster=NULL, IPropertyTree *queriesOnCluster=NULL)
  1025. {
  1026. if (!queryset || !*queryset)
  1027. return;
  1028. Owned<IPropertyTree> registry = getQueryRegistry(queryset, true);
  1029. if (!registry)
  1030. return;
  1031. retrieveQuerysetDetails(context, details, registry, type, value, cluster, queriesOnCluster);
  1032. }
  1033. IPropertyTree* getQueriesOnCluster(const char *target, const char *queryset, StringArray *queryIDs, bool checkAllNodes)
  1034. {
  1035. if (isEmpty(target))
  1036. target = queryset;
  1037. Owned<IConstWUClusterInfo> info = getTargetClusterInfo(target);
  1038. if (!info)
  1039. throw MakeStringException(ECLWATCH_CANNOT_RESOLVE_CLUSTER_NAME, "Cluster %s not found", target);
  1040. if (queryset && *queryset && !strieq(target, queryset))
  1041. throw MakeStringException(ECLWATCH_QUERYSET_NOT_ON_CLUSTER, "Target %s and QuerySet %s should match", target, queryset);
  1042. if (info->getPlatform()!=RoxieCluster)
  1043. return NULL;
  1044. const SocketEndpointArray &eps = info->getRoxieServers();
  1045. if (!eps.length())
  1046. return NULL;
  1047. try
  1048. {
  1049. StringBuffer control;
  1050. if (!queryIDs || (queryIDs->ordinality() == 0))
  1051. control.append("<control:queries/>");
  1052. else
  1053. {
  1054. control.append("<control:queries>");
  1055. ForEachItemIn(i, *queryIDs)
  1056. control.appendf("<Query id='%s'/>", queryIDs->item(i));
  1057. control.append("</control:queries>");
  1058. }
  1059. Owned<ISocket> sock = ISocket::connect_timeout(eps.item(0), ROXIECONNECTIONTIMEOUT);
  1060. if (checkAllNodes)
  1061. return sendRoxieControlAllNodes(sock, control, false, ROXIECONTROLQUERIESTIMEOUT);
  1062. else
  1063. return sendRoxieControlQuery(sock, control, ROXIECONTROLQUERIESTIMEOUT);
  1064. }
  1065. catch(IException* e)
  1066. {
  1067. StringBuffer err;
  1068. DBGLOG("Get exception in control:queries: %s", e->errorMessage(err.append(e->errorCode()).append(' ')).str());
  1069. e->Release();
  1070. return NULL;
  1071. }
  1072. }
  1073. void retrieveQuerysetDetailsByCluster(IEspContext &context, IArrayOf<IEspWUQuerySetDetail> &details, const char *target, const char *queryset, const char *type, const char *value, bool checkAllNodes)
  1074. {
  1075. Owned<IPropertyTree> queriesOnCluster = getQueriesOnCluster(target, queryset, nullptr, checkAllNodes);
  1076. retrieveQuerysetDetails(context, details, target, type, value, target, queriesOnCluster);
  1077. }
  1078. void retrieveAllQuerysetDetails(IEspContext &context, IArrayOf<IEspWUQuerySetDetail> &details, const char *type, const char *value)
  1079. {
  1080. Owned<IPropertyTree> root = getQueryRegistryRoot();
  1081. if (!root)
  1082. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "QuerySet Registry not found");
  1083. Owned<IPropertyTreeIterator> querysets = root->getElements("QuerySet");
  1084. ForEach(*querysets)
  1085. retrieveQuerysetDetails(context, details, &querysets->query(), type, value);
  1086. }
  1087. bool CWsWorkunitsEx::onWUQuerysetDetails(IEspContext &context, IEspWUQuerySetDetailsRequest & req, IEspWUQuerySetDetailsResponse & resp)
  1088. {
  1089. resp.setQuerySetName(req.getQuerySetName());
  1090. double version = context.getClientVersion();
  1091. if (version > 1.36)
  1092. {
  1093. Owned<IPropertyTree> queryRegistry = getQueryRegistry(req.getQuerySetName(), false);
  1094. resp.setClusterName(req.getClusterName());
  1095. resp.setFilter(req.getFilter());
  1096. resp.setFilterType(req.getFilterType());
  1097. }
  1098. Owned<IPropertyTree> registry = getQueryRegistry(req.getQuerySetName(), true);
  1099. if (!registry)
  1100. return false;
  1101. PROGLOG("WUQuerysetDetails for queryset %s", req.getQuerySetName());
  1102. IArrayOf<IEspQuerySetQuery> respQueries;
  1103. IArrayOf<IEspQuerySetAlias> respAliases;
  1104. if (isEmpty(req.getClusterName()) || isEmpty(req.getFilterTypeAsString()) || !strieq(req.getFilterTypeAsString(), "Status") || isEmpty(req.getFilter()))
  1105. {
  1106. const char* cluster = req.getClusterName();
  1107. if (isEmpty(cluster))
  1108. cluster = req.getQuerySetName();
  1109. Owned<IPropertyTree> queriesOnCluster = getQueriesOnCluster(cluster, req.getQuerySetName(), nullptr, req.getCheckAllNodes());
  1110. retrieveQuerysetDetails(context, registry, req.getFilterTypeAsString(), req.getFilter(), respQueries, respAliases, cluster, queriesOnCluster);
  1111. resp.setQuerysetQueries(respQueries);
  1112. resp.setQuerysetAliases(respAliases);
  1113. }
  1114. else
  1115. {
  1116. IArrayOf<IEspWUQuerySetDetail> respDetails;
  1117. retrieveQuerysetDetailsByCluster(context, respDetails, req.getClusterName(), req.getQuerySetName(), req.getFilterTypeAsString(), req.getFilter(), false);
  1118. if (respDetails.ordinality())
  1119. {
  1120. IEspWUQuerySetDetail& detail = respDetails.item(0);
  1121. resp.setQuerysetQueries(detail.getQueries());
  1122. resp.setQuerysetAliases(detail.getAliases());
  1123. }
  1124. }
  1125. return true;
  1126. }
  1127. bool CWsWorkunitsEx::onWUMultiQuerysetDetails(IEspContext &context, IEspWUMultiQuerySetDetailsRequest & req, IEspWUMultiQuerySetDetailsResponse & resp)
  1128. {
  1129. IArrayOf<IEspWUQuerySetDetail> respDetails;
  1130. if (notEmpty(req.getClusterName()))
  1131. {
  1132. PROGLOG("WUMultiQuerysetDetails for cluster %s", req.getClusterName());
  1133. retrieveQuerysetDetailsByCluster(context, respDetails, req.getClusterName(), req.getQuerySetName(), req.getFilterTypeAsString(), req.getFilter(), req.getCheckAllNodes());
  1134. }
  1135. else if (notEmpty(req.getQuerySetName()))
  1136. {
  1137. PROGLOG("WUMultiQuerysetDetails for queryset %s", req.getQuerySetName());
  1138. retrieveQuerysetDetails(context, respDetails, req.getQuerySetName(), req.getFilterTypeAsString(), req.getFilter());
  1139. }
  1140. else
  1141. {
  1142. VStringBuffer logMsg("WUMultiQuerysetDetails: FilterType %s", req.getFilterTypeAsString());
  1143. if (notEmpty(req.getFilter()))
  1144. logMsg.append(", Filter ").append(req.getFilter());
  1145. PROGLOG("%s", logMsg.str());
  1146. retrieveAllQuerysetDetails(context, respDetails, req.getFilterTypeAsString(), req.getFilter());
  1147. }
  1148. resp.setQuerysets(respDetails);
  1149. return true;
  1150. }
  1151. bool addWUQSQueryFilter(WUQuerySortField *filters, unsigned short &count, MemoryBuffer &buff, const char* value, WUQuerySortField name)
  1152. {
  1153. if (isEmpty(value))
  1154. return false;
  1155. filters[count++] = name;
  1156. buff.append(value);
  1157. return true;
  1158. }
  1159. bool addWUQSQueryFilterInt(WUQuerySortField *filters, unsigned short &count, MemoryBuffer &buff, int value, WUQuerySortField name)
  1160. {
  1161. VStringBuffer vBuf("%d", value);
  1162. filters[count++] = name;
  1163. buff.append(vBuf.str());
  1164. return true;
  1165. }
  1166. bool addWUQSQueryFilterInt64(WUQuerySortField *filters, unsigned short &count, MemoryBuffer &buff, __int64 value, WUQuerySortField name)
  1167. {
  1168. VStringBuffer vBuf("%" I64F "d", value);
  1169. filters[count++] = name;
  1170. buff.append(vBuf.str());
  1171. return true;
  1172. }
  1173. unsigned CWsWorkunitsEx::getGraphIdsByQueryId(const char *target, const char *queryId, StringArray& graphIds)
  1174. {
  1175. if (!target || !*target)
  1176. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Target name required");
  1177. if (!queryId || !*queryId)
  1178. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Query Id required");
  1179. Owned<IConstWUClusterInfo> info = getTargetClusterInfo(target);
  1180. if (!info || (info->getPlatform()!=RoxieCluster)) //Only roxie query has query graph.
  1181. return 0;
  1182. const SocketEndpointArray &eps = info->getRoxieServers();
  1183. if (eps.empty())
  1184. return 0;
  1185. VStringBuffer xpath("<control:querystats><Query id='%s'/></control:querystats>", queryId);
  1186. Owned<ISocket> sock = ISocket::connect_timeout(eps.item(0), ROXIECONNECTIONTIMEOUT);
  1187. Owned<IPropertyTree> querystats = sendRoxieControlQuery(sock, xpath.str(), ROXIECONTROLQUERYTIMEOUT);
  1188. if (!querystats)
  1189. return 0;
  1190. Owned<IPropertyTreeIterator> graphs = querystats->getElements("Endpoint/Query/Graph");
  1191. ForEach(*graphs)
  1192. {
  1193. IPropertyTree &graph = graphs->query();
  1194. const char* graphId = graph.queryProp("@id");
  1195. if (graphId && *graphId)
  1196. graphIds.appendUniq(graphId);
  1197. }
  1198. return graphIds.length();
  1199. }
  1200. //This method is thread safe because a query belongs to a single queryset. The method may be called by different threads.
  1201. //Since one thread is for one queryset and a query only belongs to a single queryset, it is impossible for different threads
  1202. //to update the same query object.
  1203. void CWsWorkunitsEx::checkAndSetClusterQueryState(IEspContext &context, const char* cluster, const char* querySetId, IArrayOf<IEspQuerySetQuery>& queries, bool checkAllNodes)
  1204. {
  1205. try
  1206. {
  1207. double version = context.getClientVersion();
  1208. if (isEmpty(cluster))
  1209. cluster = querySetId;
  1210. StringArray queryIDs;
  1211. ForEachItemIn(j, queries)
  1212. {
  1213. IEspQuerySetQuery& query = queries.item(j);
  1214. const char* queryId = query.getId();
  1215. const char* querySetId0 = query.getQuerySetId();
  1216. if (queryId && querySetId0 && strieq(querySetId0, querySetId))
  1217. queryIDs.append(queryId);
  1218. }
  1219. if (queryIDs.ordinality() == 0)
  1220. return;
  1221. Owned<IPropertyTree> queriesOnCluster = getQueriesOnCluster(cluster, querySetId, &queryIDs, checkAllNodes);
  1222. if (!queriesOnCluster)
  1223. {
  1224. UWARNLOG("getQueriesOnCluster() returns NULL for cluster<%s> and querySetId<%s>", cluster, querySetId);
  1225. return;
  1226. }
  1227. ForEachItemIn(i, queries)
  1228. {
  1229. IEspQuerySetQuery& query = queries.item(i);
  1230. const char* queryId = query.getId();
  1231. const char* querySetId0 = query.getQuerySetId();
  1232. if (!queryId || !querySetId0 || !strieq(querySetId0, querySetId))
  1233. continue;
  1234. IArrayOf<IEspClusterQueryState> clusters;
  1235. addClusterQueryStates(queriesOnCluster, cluster, queryId, clusters, version);
  1236. query.setClusters(clusters);
  1237. }
  1238. }
  1239. catch(IException *e)
  1240. {
  1241. EXCLOG(e, "CWsWorkunitsEx::checkAndSetClusterQueryState: Failed to read Query State On Cluster");
  1242. e->Release();
  1243. }
  1244. }
  1245. void CWsWorkunitsEx::checkAndSetClusterQueryState(IEspContext &context, const char* cluster, StringArray& querySetIds, IArrayOf<IEspQuerySetQuery>& queries, bool checkAllNodes)
  1246. {
  1247. UnsignedArray threadHandles;
  1248. ForEachItemIn(i, querySetIds)
  1249. {
  1250. const char* querySetId = querySetIds.item(i);
  1251. if(!querySetId || !*querySetId)
  1252. continue;
  1253. Owned<CClusterQueryStateParam> threadReq = new CClusterQueryStateParam(this, context, cluster, querySetId, queries, checkAllNodes);
  1254. PooledThreadHandle handle = clusterQueryStatePool->start( threadReq.getClear() );
  1255. threadHandles.append(handle);
  1256. }
  1257. //block for worker threads to finish, if necessary and then collect results
  1258. //Not use joinAll() because multiple threads may call this method. Each call uses the pool to create
  1259. //its own threads of checking query state. Each call should only join the ones created by that call.
  1260. ForEachItemIn(ii, threadHandles)
  1261. clusterQueryStatePool->join(threadHandles.item(ii));
  1262. }
  1263. bool CWsWorkunitsEx::onWUListQueries(IEspContext &context, IEspWUListQueriesRequest & req, IEspWUListQueriesResponse & resp)
  1264. {
  1265. bool descending = req.getDescending();
  1266. const char *sortBy = req.getSortby();
  1267. WUQuerySortField sortOrder[2] = {WUQSFId, WUQSFterm};
  1268. if(notEmpty(sortBy))
  1269. {
  1270. if (strieq(sortBy, "Name"))
  1271. sortOrder[0] = WUQSFname;
  1272. else if (strieq(sortBy, "WUID"))
  1273. sortOrder[0] = WUQSFwuid;
  1274. else if (strieq(sortBy, "DLL"))
  1275. sortOrder[0] = WUQSFdll;
  1276. else if (strieq(sortBy, "Activated"))
  1277. sortOrder[0] = WUQSFActivited;
  1278. else if (strieq(sortBy, "MemoryLimit"))
  1279. sortOrder[0] = (WUQuerySortField) (WUQSFmemoryLimit | WUQSFnumeric);
  1280. else if (strieq(sortBy, "TimeLimit"))
  1281. sortOrder[0] = (WUQuerySortField) (WUQSFtimeLimit | WUQSFnumeric);
  1282. else if (strieq(sortBy, "WarnTimeLimit"))
  1283. sortOrder[0] = (WUQuerySortField) (WUQSFwarnTimeLimit | WUQSFnumeric);
  1284. else if (strieq(sortBy, "Priority"))
  1285. sortOrder[0] = (WUQuerySortField) (WUQSFpriority | WUQSFnumeric);
  1286. else if (strieq(sortBy, "PublishedBy"))
  1287. sortOrder[0] = WUQSFPublishedBy;
  1288. else if (strieq(sortBy, "QuerySetId"))
  1289. sortOrder[0] = WUQSFQuerySet;
  1290. else
  1291. sortOrder[0] = WUQSFId;
  1292. sortOrder[0] = (WUQuerySortField) (sortOrder[0] | WUQSFnocase);
  1293. if (descending)
  1294. sortOrder[0] = (WUQuerySortField) (sortOrder[0] | WUQSFreverse);
  1295. }
  1296. WUQuerySortField filters[16];
  1297. unsigned short filterCount = 0;
  1298. MemoryBuffer filterBuf;
  1299. const char* clusterReq = req.getClusterName();
  1300. addWUQSQueryFilter(filters, filterCount, filterBuf, req.getQuerySetName(), WUQSFQuerySet);
  1301. addWUQSQueryFilter(filters, filterCount, filterBuf, req.getQueryID(), (WUQuerySortField) (WUQSFId | WUQSFwild | WUSFnocase));
  1302. addWUQSQueryFilter(filters, filterCount, filterBuf, req.getQueryName(), (WUQuerySortField) (WUQSFname | WUQSFwild | WUSFnocase));
  1303. addWUQSQueryFilter(filters, filterCount, filterBuf, req.getWUID(), (WUQuerySortField) (WUQSFwuid | WUSFnocase));
  1304. addWUQSQueryFilter(filters, filterCount, filterBuf, req.getLibraryName(), (WUQuerySortField) (WUQSFLibrary | WUQSFnocase));
  1305. addWUQSQueryFilter(filters, filterCount, filterBuf, req.getPublishedBy(), (WUQuerySortField) (WUQSFPublishedBy | WUQSFwild | WUSFnocase));
  1306. if (!req.getMemoryLimitLow_isNull())
  1307. addWUQSQueryFilterInt64(filters, filterCount, filterBuf, req.getMemoryLimitLow(), (WUQuerySortField) (WUQSFmemoryLimit | WUQSFnumeric));
  1308. if (!req.getMemoryLimitHigh_isNull())
  1309. addWUQSQueryFilterInt64(filters, filterCount, filterBuf, req.getMemoryLimitHigh(), (WUQuerySortField) (WUQSFmemoryLimitHi | WUQSFnumeric));
  1310. if (!req.getTimeLimitLow_isNull())
  1311. addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getTimeLimitLow(), (WUQuerySortField) (WUQSFtimeLimit | WUQSFnumeric));
  1312. if (!req.getTimeLimitHigh_isNull())
  1313. addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getTimeLimitHigh(), (WUQuerySortField) (WUQSFtimeLimitHi | WUQSFnumeric));
  1314. if (!req.getWarnTimeLimitLow_isNull())
  1315. addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getWarnTimeLimitLow(), (WUQuerySortField) (WUQSFwarnTimeLimit | WUQSFnumeric));
  1316. if (!req.getWarnTimeLimitHigh_isNull())
  1317. addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getWarnTimeLimitHigh(), (WUQuerySortField) (WUQSFwarnTimeLimitHi | WUQSFnumeric));
  1318. if (!req.getPriorityLow_isNull())
  1319. addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getPriorityLow(), (WUQuerySortField) (WUQSFpriority | WUQSFnumeric));
  1320. if (!req.getPriorityHigh_isNull())
  1321. addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getPriorityHigh(), (WUQuerySortField) (WUQSFpriorityHi | WUQSFnumeric));
  1322. if (!req.getActivated_isNull())
  1323. addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getActivated(), (WUQuerySortField) (WUQSFActivited | WUQSFnumeric));
  1324. if (!req.getSuspendedByUser_isNull())
  1325. addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getSuspendedByUser(), (WUQuerySortField) (WUQSFSuspendedByUser | WUQSFnumeric));
  1326. filters[filterCount] = WUQSFterm;
  1327. unsigned numberOfQueries = 0;
  1328. unsigned pageSize = req.getPageSize();
  1329. unsigned pageStartFrom = req.getPageStartFrom();
  1330. if(pageSize < 1)
  1331. pageSize = 100;
  1332. __int64 cacheHint = 0;
  1333. if (!req.getCacheHint_isNull())
  1334. cacheHint = req.getCacheHint();
  1335. Owned<MapStringTo<bool> > queriesUsingFileMap;
  1336. const char *lfn = req.getFileName();
  1337. if (lfn && *lfn)
  1338. {
  1339. queriesUsingFileMap.setown(new MapStringTo<bool>());
  1340. StringAttr dummy;
  1341. Owned<IPropertyTreeIterator> queriesUsingFile = filesInUse.findQueriesUsingFile(clusterReq, lfn, dummy);
  1342. ForEach (*queriesUsingFile)
  1343. {
  1344. IPropertyTree &queryUsingFile = queriesUsingFile->query();
  1345. const char *queryTarget = queryUsingFile.queryProp("@target");
  1346. const char *queryId = queryUsingFile.queryProp("@id");
  1347. if (queryTarget && *queryTarget && queryId && *queryId)
  1348. {
  1349. VStringBuffer targetQuery("%s/%s", queryTarget, queryId);
  1350. queriesUsingFileMap->setValue(targetQuery, true);
  1351. }
  1352. }
  1353. }
  1354. PROGLOG("WUListQueries: getQuerySetQueriesSorted");
  1355. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1356. Owned<IConstQuerySetQueryIterator> it = factory->getQuerySetQueriesSorted(sortOrder, filters, filterBuf.bufferBase(), pageStartFrom, pageSize, &cacheHint, &numberOfQueries, queriesUsingFileMap);
  1357. resp.setCacheHint(cacheHint);
  1358. PROGLOG("WUListQueries: getQuerySetQueriesSorted done");
  1359. StringArray querySetIds;
  1360. IArrayOf<IEspQuerySetQuery> queries;
  1361. double version = context.getClientVersion();
  1362. ForEach(*it)
  1363. {
  1364. IPropertyTree &query=it->query();
  1365. const char *queryId = query.queryProp("@id");
  1366. const char *queryTarget = query.queryProp("@querySetId");
  1367. Owned<IEspQuerySetQuery> q = createQuerySetQuery();
  1368. q->setId(queryId);
  1369. q->setQuerySetId(queryTarget);
  1370. q->setName(query.queryProp("@name"));
  1371. q->setDll(query.queryProp("@dll"));
  1372. q->setWuid(query.queryProp("@wuid"));
  1373. q->setActivated(query.getPropBool("@activated", false));
  1374. q->setSuspended(query.getPropBool("@suspended", false));
  1375. if (query.hasProp("@memoryLimit"))
  1376. {
  1377. StringBuffer s;
  1378. memoryLimitStringFromUInt64(s, query.getPropInt64("@memoryLimit"));
  1379. q->setMemoryLimit(s);
  1380. }
  1381. if (query.hasProp("@timeLimit"))
  1382. q->setTimeLimit(query.getPropInt("@timeLimit"));
  1383. if (query.hasProp("@warnTimeLimit"))
  1384. q->setWarnTimeLimit(query.getPropInt("@warnTimeLimit"));
  1385. if (query.hasProp("@priority"))
  1386. q->setPriority(getQueryPriorityName(query.getPropInt("@priority")));
  1387. if (query.hasProp("@comment"))
  1388. q->setComment(query.queryProp("@comment"));
  1389. if (version >= 1.46)
  1390. {
  1391. q->setPublishedBy(query.queryProp("@publishedBy"));
  1392. q->setIsLibrary(query.getPropBool("@isLibrary"));
  1393. }
  1394. if (!querySetIds.contains(queryTarget))
  1395. querySetIds.append(queryTarget);
  1396. queries.append(*q.getClear());
  1397. }
  1398. if (queries.ordinality() > 0)
  1399. checkAndSetClusterQueryState(context, clusterReq, querySetIds, queries, req.getCheckAllNodes());
  1400. resp.setQuerysetQueries(queries);
  1401. resp.setNumberOfQueries(numberOfQueries);
  1402. return true;
  1403. }
  1404. bool CWsWorkunitsEx::onWUListQueriesUsingFile(IEspContext &context, IEspWUListQueriesUsingFileRequest &req, IEspWUListQueriesUsingFileResponse &resp)
  1405. {
  1406. const char *target = req.getTarget();
  1407. const char *process = req.getProcess();
  1408. StringBuffer lfn(req.getFileName());
  1409. resp.setFileName(lfn.toLowerCase());
  1410. resp.setProcess(process);
  1411. if (lfn.isEmpty())
  1412. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "FileName required");
  1413. VStringBuffer logMsg("WUListQueriesUsingFile: %s", lfn.str());
  1414. StringArray targets;
  1415. if (target && *target)
  1416. {
  1417. targets.append(target);
  1418. logMsg.append(", target ").append(target);
  1419. }
  1420. else // if (process && *process)
  1421. {
  1422. SCMStringBuffer targetStr;
  1423. Owned<IStringIterator> targetClusters = getTargetClusters("RoxieCluster", process);
  1424. ForEach(*targetClusters)
  1425. targets.append(targetClusters->str(targetStr).str());
  1426. logMsg.append(", process ").append(process);
  1427. }
  1428. PROGLOG("%s", logMsg.str());
  1429. IArrayOf<IEspTargetQueriesUsingFile> respTargets;
  1430. ForEachItemIn(i, targets)
  1431. {
  1432. target = targets.item(i);
  1433. Owned<IEspTargetQueriesUsingFile> respTarget = createTargetQueriesUsingFile();
  1434. respTarget->setTarget(target);
  1435. StringAttr pmid;
  1436. Owned<IPropertyTreeIterator> queries = filesInUse.findQueriesUsingFile(target, lfn, pmid);
  1437. if (!pmid.isEmpty())
  1438. respTarget->setPackageMap(pmid);
  1439. if (queries)
  1440. {
  1441. IArrayOf<IEspQueryUsingFile> respQueries;
  1442. ForEach(*queries)
  1443. {
  1444. IPropertyTree &query = queries->query();
  1445. Owned<IEspQueryUsingFile> q = createQueryUsingFile();
  1446. q->setId(query.queryProp("@id"));
  1447. VStringBuffer xpath("File[@lfn='%s']/@pkgid", lfn.str());
  1448. if (query.hasProp(xpath))
  1449. q->setPackage(query.queryProp(xpath));
  1450. respQueries.append(*q.getClear());
  1451. }
  1452. respTarget->setQueries(respQueries);
  1453. }
  1454. respTargets.append(*respTarget.getClear());
  1455. }
  1456. resp.setTargets(respTargets);
  1457. return true;
  1458. }
  1459. bool CWsWorkunitsEx::onWUQueryFiles(IEspContext &context, IEspWUQueryFilesRequest &req, IEspWUQueryFilesResponse &resp)
  1460. {
  1461. const char *target = req.getTarget();
  1462. const char *query = req.getQueryId();
  1463. if (!target || !*target)
  1464. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Target not specified");
  1465. if (!isValidCluster(target))
  1466. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid target name: %s", target);
  1467. if (!query || !*query)
  1468. throw MakeStringException(ECLWATCH_QUERYID_NOT_FOUND, "Query not specified");
  1469. Owned<IPropertyTree> registeredQuery = resolveQueryAlias(target, query, true);
  1470. if (!registeredQuery)
  1471. throw MakeStringException(ECLWATCH_QUERYID_NOT_FOUND, "Query not found");
  1472. PROGLOG("WUQueryFiles: target %s, query %s", target, query);
  1473. StringAttr queryid(registeredQuery->queryProp("@id"));
  1474. registeredQuery.clear();
  1475. Owned<IPropertyTree> tree = filesInUse.getTree();
  1476. VStringBuffer xpath("%s/Query[@id='%s']", target, queryid.get());
  1477. IPropertyTree *queryTree = tree->queryPropTree(xpath);
  1478. if (!queryTree)
  1479. throw MakeStringException(ECLWATCH_QUERYID_NOT_FOUND, "Query not found in file cache (%s)", xpath.str());
  1480. IArrayOf<IEspFileUsedByQuery> referencedFiles;
  1481. Owned<IPropertyTreeIterator> files = queryTree->getElements("File");
  1482. ForEach(*files)
  1483. {
  1484. IPropertyTree &file = files->query();
  1485. if (file.getPropBool("@super", 0))
  1486. continue;
  1487. Owned<IEspFileUsedByQuery> respFile = createFileUsedByQuery();
  1488. respFile->setFileName(file.queryProp("@lfn"));
  1489. respFile->setFileSize(file.getPropInt64("@size"));
  1490. respFile->setNumberOfParts(file.getPropInt("@numparts"));
  1491. referencedFiles.append(*respFile.getClear());
  1492. }
  1493. resp.setFiles(referencedFiles);
  1494. return true;
  1495. }
  1496. void copyWorkunitForRecompile(IEspContext &context, IWorkUnitFactory *factory, const char *srcWuid, StringAttr &wuid, StringAttr &jobname)
  1497. {
  1498. Owned<IConstWorkUnit> src(factory->openWorkUnit(srcWuid));
  1499. if (!src)
  1500. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot open workunit %s.", srcWuid);
  1501. WsWuInfo info(context, src);
  1502. StringBuffer archiveText;
  1503. info.getWorkunitArchiveQuery(archiveText); //archive required, fail otherwise
  1504. if (!isArchiveQuery(archiveText))
  1505. throw MakeStringException(ECLWATCH_RESOURCE_NOT_FOUND,"Cannot retrieve workunit ECL archive %s.", srcWuid);
  1506. SCMStringBuffer mainDefinition;
  1507. Owned <IConstWUQuery> query = src->getQuery();
  1508. if (query)
  1509. query->getQueryMainDefinition(mainDefinition);
  1510. NewWsWorkunit wu(factory, context);
  1511. wuid.set(wu->queryWuid());
  1512. wu->setAction(WUActionCompile);
  1513. jobname.set(src->queryJobName());
  1514. if (jobname.length())
  1515. wu->setJobName(jobname);
  1516. wu.setQueryText(archiveText.str());
  1517. if (mainDefinition.length())
  1518. wu.setQueryMain(mainDefinition.str());
  1519. wu->setResultLimit(src->getResultLimit());
  1520. IStringIterator &names = src->getDebugValues();
  1521. ForEach(names)
  1522. {
  1523. SCMStringBuffer name, value;
  1524. names.str(name);
  1525. if (0==strncmp(name.str(), "eclcc", 5))
  1526. wu->setDebugValue(name.str(), src->getDebugValue(name.str(), value).str(), true);
  1527. }
  1528. }
  1529. bool CWsWorkunitsEx::onWURecreateQuery(IEspContext &context, IEspWURecreateQueryRequest &req, IEspWURecreateQueryResponse &resp)
  1530. {
  1531. try
  1532. {
  1533. const char* srcTarget = req.getTarget();
  1534. const char* queryIdOrAlias = req.getQueryId();
  1535. if (!srcTarget || !*srcTarget)
  1536. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Target not specified");
  1537. if (!queryIdOrAlias || !*queryIdOrAlias)
  1538. throw MakeStringException(ECLWATCH_QUERYID_NOT_FOUND, "QueryId not specified");
  1539. const char *target = req.getDestTarget();
  1540. if (isEmptyString(target))
  1541. target = srcTarget;
  1542. Owned<IPropertyTree> queryRegistry = getQueryRegistry(srcTarget, false);
  1543. Owned<IPropertyTree> srcQueryTree = resolveQueryAlias(queryRegistry, queryIdOrAlias);
  1544. if (!srcQueryTree)
  1545. {
  1546. DBGLOG("WURecreateQuery - No matching Query");
  1547. throw MakeStringException(ECLWATCH_QUERYID_NOT_FOUND,"No matching query for given id or alias %s.", queryIdOrAlias);
  1548. }
  1549. resp.setPriority(isEmptyString(req.getPriority()) ? srcQueryTree->queryProp("@priority") : req.getPriority());
  1550. resp.setComment(isEmptyString(req.getComment()) ? srcQueryTree->queryProp("@comment") : req.getComment());
  1551. resp.setMemoryLimit(isEmptyString(req.getMemoryLimit()) ? srcQueryTree->queryProp("@memoryLimit") : req.getMemoryLimit());
  1552. resp.setTimeLimit(req.getTimeLimit_isNull() ? srcQueryTree->getPropInt("@timeLimit") : req.getTimeLimit());
  1553. resp.setWarnTimeLimit(req.getWarnTimeLimit_isNull() ? srcQueryTree->getPropInt("@warnTimeLimit") : req.getWarnTimeLimit());
  1554. StringAttr wuid;
  1555. StringAttr jobname;
  1556. const char* srcQueryId = srcQueryTree->queryProp("@id");
  1557. const char* srcQueryName = srcQueryTree->queryProp("@name");
  1558. const char *srcWuid = srcQueryTree->queryProp("@wuid");
  1559. PROGLOG("WURecreateQuery: QuerySet %s, query %s, wuid %s", srcTarget, srcQueryId, srcWuid);
  1560. ensureWsWorkunitAccess(context, srcWuid, SecAccess_Write);
  1561. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1562. copyWorkunitForRecompile(context, factory, srcWuid, wuid, jobname);
  1563. resp.setWuid(wuid);
  1564. WsWuHelpers::submitWsWorkunit(context, wuid.str(), target, NULL, 0, true, false, false, NULL, NULL, &req.getDebugValues());
  1565. waitForWorkUnitToCompile(wuid.str(), req.getWait());
  1566. Owned<IConstWorkUnit> cw(factory->openWorkUnit(wuid.str()));
  1567. if (!cw)
  1568. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot open recreated workunit %s.",wuid.str());
  1569. if (jobname.length())
  1570. {
  1571. StringBuffer name;
  1572. origValueChanged(jobname.str(), cw->queryJobName(), name, false);
  1573. if (name.length()) //non generated user specified name, so override #Workunit('name')
  1574. {
  1575. WorkunitUpdate wx(&cw->lock());
  1576. wx->setJobName(name.str());
  1577. }
  1578. }
  1579. PROGLOG("WURecreateQuery generated: %s", wuid.str());
  1580. AuditSystemAccess(context.queryUserId(), true, "Updated %s", wuid.str());
  1581. queryRegistry.clear();
  1582. srcQueryTree.clear();
  1583. if (req.getRepublish())
  1584. {
  1585. if (!req.getDontCopyFiles())
  1586. {
  1587. StringBuffer daliIP;
  1588. StringBuffer srcCluster;
  1589. StringBuffer srcPrefix;
  1590. splitDerivedDfsLocation(req.getRemoteDali(), srcCluster, daliIP, srcPrefix, req.getSourceProcess(),req.getSourceProcess(), NULL, NULL);
  1591. if (srcCluster.length())
  1592. {
  1593. if (!isProcessCluster(daliIP, srcCluster))
  1594. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Process cluster %s not found on %s DALI", srcCluster.str(), daliIP.length() ? daliIP.str() : "local");
  1595. }
  1596. unsigned updateFlags = 0;
  1597. if (req.getUpdateDfs())
  1598. updateFlags |= (DALI_UPDATEF_SUPERFILES | DALI_UPDATEF_REPLACE_FILE | DALI_UPDATEF_CLONE_FROM);
  1599. if (req.getUpdateCloneFrom())
  1600. updateFlags |= DALI_UPDATEF_CLONE_FROM;
  1601. if (req.getUpdateSuperFiles())
  1602. updateFlags |= DALI_UPDATEF_SUPERFILES;
  1603. if (req.getAppendCluster())
  1604. updateFlags |= DALI_UPDATEF_APPEND_CLUSTER;
  1605. QueryFileCopier cpr(target);
  1606. cpr.init(context, req.getAllowForeignFiles());
  1607. cpr.remoteIP.set(daliIP);
  1608. cpr.remotePrefix.set(srcPrefix);
  1609. cpr.srcCluster.set(srcCluster);
  1610. cpr.queryname.set(srcQueryName);
  1611. cpr.copy(cw, updateFlags);
  1612. if (req.getIncludeFileErrors())
  1613. cpr.gatherFileErrors(resp.getFileErrors());
  1614. }
  1615. StringBuffer queryId;
  1616. WorkunitUpdate wu(&cw->lock());
  1617. WUQueryActivationOptions activate = (WUQueryActivationOptions)req.getActivate();
  1618. addQueryToQuerySet(wu, target, srcQueryName, activate, queryId, context.queryUserId());
  1619. {
  1620. Owned<IPropertyTree> queryTree = getQueryById(target, queryId, false);
  1621. if (queryTree)
  1622. {
  1623. queryTree->setProp("@priority", resp.getPriority());
  1624. updateMemoryLimitSetting(queryTree, resp.getMemoryLimit());
  1625. updateQuerySetting(resp.getTimeLimit_isNull(), queryTree, "@timeLimit", resp.getTimeLimit());
  1626. updateQuerySetting(resp.getWarnTimeLimit_isNull(), queryTree, "@warnTimeLimit", resp.getWarnTimeLimit());
  1627. updateQueryPriority(queryTree, resp.getPriority());
  1628. queryTree->setProp("@comment", resp.getComment());
  1629. }
  1630. }
  1631. wu->commit();
  1632. wu.clear();
  1633. PROGLOG("WURecreateQuery published: %s as %s/%s", wuid.str(), target, queryId.str());
  1634. resp.setQuerySet(target);
  1635. resp.setQueryName(srcQueryName);
  1636. resp.setQueryId(queryId.str());
  1637. Owned <IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(target);
  1638. bool reloadFailed = false;
  1639. if (0!=req.getWait() && !req.getNoReload())
  1640. reloadFailed = !reloadCluster(clusterInfo, (unsigned)req.getWait());
  1641. resp.setReloadFailed(reloadFailed);
  1642. StringBuffer errorMessage;
  1643. if (!reloadFailed && !req.getNoReload() && isQuerySuspended(queryId.str(), clusterInfo, (unsigned)req.getWait(), errorMessage))
  1644. {
  1645. resp.setSuspended(true);
  1646. resp.setErrorMessage(errorMessage);
  1647. }
  1648. }
  1649. }
  1650. catch(IException* e)
  1651. {
  1652. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1653. }
  1654. return true;
  1655. }
  1656. bool CWsWorkunitsEx::onWUQueryDetails(IEspContext &context, IEspWUQueryDetailsRequest & req, IEspWUQueryDetailsResponse & resp)
  1657. {
  1658. const char* querySet = req.getQuerySet();
  1659. const char* queryIdOrAlias = req.getQueryId();
  1660. bool includeStateOnClusters = req.getIncludeStateOnClusters();
  1661. if (!querySet || !*querySet)
  1662. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "QuerySet not specified");
  1663. if (!queryIdOrAlias || !*queryIdOrAlias)
  1664. throw MakeStringException(ECLWATCH_QUERYID_NOT_FOUND, "QueryId not specified");
  1665. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySet, false);
  1666. Owned<IPropertyTree> query = resolveQueryAlias(queryRegistry, queryIdOrAlias);
  1667. if (!query)
  1668. {
  1669. DBGLOG("No matching Query");
  1670. throw MakeStringException(ECLWATCH_QUERYID_NOT_FOUND,"No matching query for given id or alias %s.", queryIdOrAlias);
  1671. }
  1672. const char* queryId = query->queryProp("@id");
  1673. resp.setQueryId(queryId);
  1674. resp.setQuerySet(querySet);
  1675. PROGLOG("WUQueryDetails: QuerySet %s, query %s", querySet, queryId);
  1676. const char* queryName = query->queryProp("@name");
  1677. const char* wuid = query->queryProp("@wuid");
  1678. resp.setQueryName(queryName);
  1679. resp.setWuid(wuid);
  1680. resp.setDll(query->queryProp("@dll"));
  1681. resp.setPublishedBy(query->queryProp("@publishedBy"));
  1682. resp.setSuspended(query->getPropBool("@suspended", false));
  1683. resp.setSuspendedBy(query->queryProp("@suspendedBy"));
  1684. resp.setComment(query->queryProp("@comment"));
  1685. double version = context.getClientVersion();
  1686. if (version >= 1.46)
  1687. {
  1688. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1689. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid);
  1690. if(!cw)
  1691. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT,"Cannot open workunit %s.",wuid);
  1692. ensureWsWorkunitAccess(context, *cw, SecAccess_Read);
  1693. if (query->hasProp("@priority"))
  1694. resp.setPriority(getQueryPriorityName(query->getPropInt("@priority")));
  1695. resp.setIsLibrary(query->getPropBool("@isLibrary"));
  1696. SCMStringBuffer s;
  1697. resp.setWUSnapShot(cw->getSnapshot(s).str()); //Label
  1698. stat_type whenCompiled;
  1699. if (cw->getStatistic(whenCompiled, "", StWhenCompiled))
  1700. {
  1701. formatStatistic(s.s.clear(), whenCompiled, StWhenCompiled);
  1702. resp.setCompileTime(s.str());
  1703. }
  1704. StringArray libUsed, graphIds;
  1705. Owned<IConstWULibraryIterator> libs = &cw->getLibraries();
  1706. ForEach(*libs)
  1707. libUsed.append(libs->query().getName(s).str());
  1708. if (libUsed.length())
  1709. resp.setLibrariesUsed(libUsed);
  1710. if (version < 1.64)
  1711. {
  1712. unsigned numGraphIds = getGraphIdsByQueryId(querySet, queryId, graphIds);
  1713. resp.setCountGraphs(numGraphIds);
  1714. if (numGraphIds > 0)
  1715. resp.setGraphIds(graphIds);
  1716. }
  1717. }
  1718. StringArray logicalFiles;
  1719. IArrayOf<IEspQuerySuperFile> superFiles;
  1720. getQueryFiles(context, wuid, queryId, querySet, logicalFiles, req.getIncludeSuperFiles() ? &superFiles : NULL);
  1721. if (logicalFiles.length())
  1722. resp.setLogicalFiles(logicalFiles);
  1723. if (superFiles.length())
  1724. resp.setSuperFiles(superFiles);
  1725. if (version >= 1.42)
  1726. {
  1727. VStringBuffer xpath("Alias[@id='%s']", queryId);
  1728. IPropertyTree *alias = queryRegistry->queryPropTree(xpath.str());
  1729. if (!alias)
  1730. resp.setActivated(false);
  1731. else
  1732. resp.setActivated(true);
  1733. }
  1734. if (includeStateOnClusters && (version >= 1.43))
  1735. {
  1736. StringArray queryIds;
  1737. queryIds.append(queryId);
  1738. Owned<IPropertyTree> queriesOnCluster = getQueriesOnCluster(querySet, querySet, &queryIds, req.getCheckAllNodes());
  1739. if (queriesOnCluster)
  1740. {
  1741. IArrayOf<IEspClusterQueryState> clusterStates;
  1742. addClusterQueryStates(queriesOnCluster, querySet, queryId, clusterStates, version);
  1743. resp.setClusters(clusterStates);
  1744. }
  1745. }
  1746. if (version >= 1.50)
  1747. {
  1748. WsWuInfo winfo(context, wuid);
  1749. resp.setResourceURLCount(winfo.getResourceURLCount());
  1750. if (version >= 1.64)
  1751. {
  1752. IArrayOf<IEspECLTimer> timers;
  1753. winfo.doGetTimers(timers); //Graph Duration
  1754. if (timers.length())
  1755. resp.setWUTimers(timers);
  1756. IArrayOf<IEspECLGraph> graphs;
  1757. winfo.doGetGraphs(graphs); //Graph Name, Label, Started, Finished, Type
  1758. unsigned numGraphIds = graphs.length();
  1759. resp.setCountGraphs(numGraphIds);
  1760. if (numGraphIds > 0)
  1761. resp.setWUGraphs(graphs);
  1762. }
  1763. }
  1764. if (req.getIncludeWsEclAddresses())
  1765. {
  1766. StringArray wseclAddresses;
  1767. Owned<IEnvironmentFactory> factory = getEnvironmentFactory(true);
  1768. Owned<IConstEnvironment> env = factory->openEnvironment();
  1769. Owned<IPropertyTree> root = &env->getPTree();
  1770. Owned<IPropertyTreeIterator> services = root->getElements("Software/EspService[Properties/@type='ws_ecl']");
  1771. StringArray serviceNames;
  1772. VStringBuffer xpath("Target[@name='%s']", querySet);
  1773. ForEach(*services)
  1774. {
  1775. IPropertyTree &service = services->query();
  1776. if (!service.hasProp("Target") || service.hasProp(xpath))
  1777. serviceNames.append(service.queryProp("@name"));
  1778. }
  1779. Owned<IPropertyTreeIterator> processes = root->getElements("Software/EspProcess");
  1780. ForEach(*processes)
  1781. {
  1782. StringArray netAddrs;
  1783. IPropertyTree &process = processes->query();
  1784. Owned<IPropertyTreeIterator> instances = process.getElements("Instance");
  1785. ForEach(*instances)
  1786. {
  1787. IPropertyTree &instance = instances->query();
  1788. const char *netAddr = instance.queryProp("@netAddress");
  1789. if (!netAddr || !*netAddr)
  1790. continue;
  1791. if (streq(netAddr, "."))
  1792. netAddrs.appendUniq(envLocalAddress); //not necessarily local to this server
  1793. else
  1794. netAddrs.appendUniq(netAddr);
  1795. }
  1796. Owned<IPropertyTreeIterator> bindings = process.getElements("EspBinding");
  1797. ForEach(*bindings)
  1798. {
  1799. IPropertyTree &binding = bindings->query();
  1800. const char *srvName = binding.queryProp("@service");
  1801. if (!serviceNames.contains(srvName))
  1802. continue;
  1803. const char *port = binding.queryProp("@port"); //should always be an integer, but we're just concatenating strings
  1804. if (!port || !*port)
  1805. continue;
  1806. ForEachItemIn(i, netAddrs)
  1807. {
  1808. VStringBuffer wseclAddr("%s:%s", netAddrs.item(i), port);
  1809. wseclAddresses.append(wseclAddr);
  1810. }
  1811. }
  1812. }
  1813. resp.setWsEclAddresses(wseclAddresses);
  1814. }
  1815. return true;
  1816. }
  1817. int EspQuerySuperFileCompareFunc(IInterface * const *i1, IInterface * const *i2)
  1818. {
  1819. if (!i1 || !*i1 || !i2 || !*i2)
  1820. return 0;
  1821. IEspQuerySuperFile *sf1 = QUERYINTERFACE(*i1, IEspQuerySuperFile);
  1822. IEspQuerySuperFile *sf2 = QUERYINTERFACE(*i2, IEspQuerySuperFile);
  1823. if (!sf1 || !sf2)
  1824. return 0;
  1825. const char *name1 = sf1->getName();
  1826. const char *name2 = sf2->getName();
  1827. if (!name1 || !name2)
  1828. return 0;
  1829. return strcmp(name1, name2);
  1830. }
  1831. IReferencedFile* CWsWorkunitsEx::getReferencedFileByName(const char* name, IReferencedFileList* wufiles)
  1832. {
  1833. Owned<IReferencedFileIterator> refFileItr = wufiles->getFiles();
  1834. ForEach(*refFileItr)
  1835. {
  1836. IReferencedFile& rf = refFileItr->query();
  1837. const char* lfn = rf.getLogicalName();
  1838. if (lfn && strieq(lfn, name))
  1839. return &rf;
  1840. }
  1841. return NULL;
  1842. }
  1843. void CWsWorkunitsEx::readSuperFiles(IEspContext &context, IReferencedFile* rf, const char* fileName, IReferencedFileList* wufiles, IArrayOf<IEspQuerySuperFile>* files)
  1844. {
  1845. double version = context.getClientVersion();
  1846. StringArray subFiles;
  1847. IArrayOf<IEspQuerySuperFile> superFiles;
  1848. const StringArray& subFileNames = rf->getSubFileNames();
  1849. ForEachItemIn(i, subFileNames)
  1850. {
  1851. const char* name = subFileNames.item(i);
  1852. if (!name || !*name)
  1853. continue;
  1854. IReferencedFile* pRF = getReferencedFileByName(name, wufiles);
  1855. if (!pRF)
  1856. continue;
  1857. if (!(pRF->getFlags() & RefFileSuper))
  1858. {
  1859. subFiles.append(name);
  1860. }
  1861. else if (version >= 1.57)
  1862. {
  1863. readSuperFiles(context, pRF, name, wufiles, &superFiles);
  1864. }
  1865. }
  1866. Owned<IEspQuerySuperFile> newSuperFile = createQuerySuperFile();
  1867. newSuperFile->setName(fileName);
  1868. if (subFiles.length())
  1869. {
  1870. subFiles.sortAscii();
  1871. newSuperFile->setSubFiles(subFiles);
  1872. }
  1873. if ((version >= 1.57) && superFiles.length())
  1874. {
  1875. superFiles.sort(EspQuerySuperFileCompareFunc);
  1876. newSuperFile->setSuperFiles(superFiles);
  1877. }
  1878. files->append(*newSuperFile.getClear());
  1879. }
  1880. bool CWsWorkunitsEx::getQueryFiles(IEspContext &context, const char* wuid, const char* query, const char* target, StringArray& logicalFiles, IArrayOf<IEspQuerySuperFile> *respSuperFiles)
  1881. {
  1882. try
  1883. {
  1884. Owned<IConstWUClusterInfo> info = getTargetClusterInfo(target);
  1885. if (!info || (info->getPlatform()!=RoxieCluster))
  1886. return false;
  1887. SCMStringBuffer process;
  1888. info->getRoxieProcess(process);
  1889. if (!process.length())
  1890. return false;
  1891. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  1892. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid);
  1893. if (!cw)
  1894. return false;
  1895. StringArray superFileNames;
  1896. Owned<IHpccPackageSet> ps = createPackageSet(process.str());
  1897. Owned<IReferencedFileList> wufiles = createReferencedFileList(context.queryUserId(),
  1898. context.queryPassword(), true, true);
  1899. wufiles->addFilesFromQuery(cw, (ps) ? ps->queryActiveMap(target) : NULL, query);
  1900. wufiles->resolveFiles(process.str(), NULL, NULL, NULL, true, true, true, true);
  1901. Owned<IReferencedFileIterator> refFileItr = wufiles->getFiles();
  1902. ForEach(*refFileItr)
  1903. {
  1904. IReferencedFile &rf = refFileItr->query();
  1905. const char *lfn = rf.getLogicalName();
  1906. if (lfn && *lfn)
  1907. {
  1908. logicalFiles.append(lfn);
  1909. if (respSuperFiles && (rf.getFlags() & RefFileSuper))
  1910. readSuperFiles(context, &rf, lfn, wufiles, respSuperFiles);
  1911. }
  1912. }
  1913. logicalFiles.sortAscii();
  1914. if (respSuperFiles)
  1915. respSuperFiles->sort(EspQuerySuperFileCompareFunc);
  1916. return true;
  1917. }
  1918. catch(IMultiException *me)
  1919. {
  1920. StringBuffer err;
  1921. IERRLOG("ERROR control:getQueryXrefInfo roxie query info %s", me->errorMessage(err.append(me->errorCode()).append(' ')).str());
  1922. me->Release();
  1923. return false;
  1924. }
  1925. catch(IException *e)
  1926. {
  1927. StringBuffer err;
  1928. IERRLOG("ERROR control:getQueryXrefInfo roxie query info %s", e->errorMessage(err.append(e->errorCode()).append(' ')).str());
  1929. e->Release();
  1930. return false;
  1931. }
  1932. }
  1933. inline void verifyQueryActionAllowsWild(bool &allowWildChecked, CQuerySetQueryActionTypes action)
  1934. {
  1935. if (allowWildChecked)
  1936. return;
  1937. switch (action)
  1938. {
  1939. case CQuerySetQueryActionTypes_ToggleSuspend:
  1940. throw MakeStringException(ECLWATCH_INVALID_ACTION, "Wildcards not supported for toggling suspended state");
  1941. case CQuerySetQueryActionTypes_Activate:
  1942. throw MakeStringException(ECLWATCH_INVALID_ACTION, "Wildcards not supported for Activating queries");
  1943. }
  1944. allowWildChecked=true;
  1945. }
  1946. inline bool verifyQueryActionAllowsAlias(CQuerySetQueryActionTypes action)
  1947. {
  1948. return (action!=CQuerySetQueryActionTypes_Activate && action!=CQuerySetQueryActionTypes_RemoveAllAliases);
  1949. }
  1950. void expandQueryActionTargetList(IProperties *queryIds, IPropertyTree *queryset, IArrayOf<IConstQuerySetQueryActionItem> &items, CQuerySetQueryActionTypes action)
  1951. {
  1952. bool allowWildChecked=false;
  1953. ForEachItemIn(i, items)
  1954. {
  1955. const char *itemId = items.item(i).getQueryId();
  1956. if (!isWildString(itemId))
  1957. {
  1958. bool suspendedByUser = false;
  1959. const char *itemSuspendState = items.item(i).getClientState().getSuspended();
  1960. if (itemSuspendState && (strieq(itemSuspendState, "By User") || strieq(itemSuspendState, "1")))
  1961. suspendedByUser = true;
  1962. if (!verifyQueryActionAllowsAlias(action))
  1963. queryIds->setProp(itemId, suspendedByUser);
  1964. else
  1965. {
  1966. Owned<IPropertyTree> query = resolveQueryAlias(queryset, itemId);
  1967. if (query)
  1968. {
  1969. const char *id = query->queryProp("@id");
  1970. if (id && *id)
  1971. queryIds->setProp(id, suspendedByUser);
  1972. }
  1973. }
  1974. }
  1975. else
  1976. {
  1977. verifyQueryActionAllowsWild(allowWildChecked, action);
  1978. if (verifyQueryActionAllowsAlias(action))
  1979. {
  1980. Owned<IPropertyTreeIterator> active = queryset->getElements("Alias");
  1981. ForEach(*active)
  1982. {
  1983. const char *name = active->query().queryProp("@name");
  1984. const char *id = active->query().queryProp("@id");
  1985. if (name && id && WildMatch(name, itemId))
  1986. queryIds->setProp(id, 0);
  1987. }
  1988. }
  1989. Owned<IPropertyTreeIterator> queries = queryset->getElements("Query");
  1990. ForEach(*queries)
  1991. {
  1992. const char *id = queries->query().queryProp("@id");
  1993. if (id && WildMatch(id, itemId))
  1994. queryIds->setProp(id, 0);
  1995. }
  1996. }
  1997. }
  1998. }
  1999. void expandQueryActionTargetList(IProperties *queryIds, IPropertyTree *queryset, const char *id, CQuerySetQueryActionTypes action)
  2000. {
  2001. IArrayOf<IConstQuerySetQueryActionItem> items;
  2002. Owned<IEspQuerySetQueryActionItem> item = createQuerySetQueryActionItem();
  2003. item->setQueryId(id);
  2004. items.append(*(IConstQuerySetQueryActionItem*)item.getClear());
  2005. expandQueryActionTargetList(queryIds, queryset, items, action);
  2006. }
  2007. bool CWsWorkunitsEx::onWUQueryConfig(IEspContext &context, IEspWUQueryConfigRequest & req, IEspWUQueryConfigResponse & resp)
  2008. {
  2009. StringAttr target(req.getTarget());
  2010. if (target.isEmpty())
  2011. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Target name required");
  2012. if (!isValidCluster(target))
  2013. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid target name: %s", target.get());
  2014. Owned<IPropertyTree> queryset = getQueryRegistry(target.get(), false);
  2015. if (!queryset)
  2016. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Target Queryset %s not found", req.getTarget());
  2017. PROGLOG("WUQueryConfig: target %s", target.get());
  2018. Owned<IProperties> queryIds = createProperties();
  2019. expandQueryActionTargetList(queryIds, queryset, req.getQueryId(), QuerySetQueryActionTypes_Undefined);
  2020. IArrayOf<IEspWUQueryConfigResult> results;
  2021. Owned<IPropertyIterator> it = queryIds->getIterator();
  2022. ForEach(*it)
  2023. {
  2024. Owned<IEspWUQueryConfigResult> result = createWUQueryConfigResult();
  2025. result->setQueryId(it->getPropKey());
  2026. VStringBuffer xpath("Query[@id='%s']", it->getPropKey());
  2027. IPropertyTree *queryTree = queryset->queryPropTree(xpath);
  2028. if (queryTree)
  2029. {
  2030. updateMemoryLimitSetting(queryTree, req.getMemoryLimit());
  2031. updateQueryPriority(queryTree, req.getPriority());
  2032. updateQuerySetting(req.getTimeLimit_isNull(), queryTree, "@timeLimit", req.getTimeLimit());
  2033. updateQuerySetting(req.getWarnTimeLimit_isNull(), queryTree, "@warnTimeLimit", req.getWarnTimeLimit());
  2034. if (req.getComment())
  2035. queryTree->setProp("@comment", req.getComment());
  2036. }
  2037. results.append(*result.getClear());
  2038. }
  2039. resp.setResults(results);
  2040. bool reloadFailed = false;
  2041. if (0!=req.getWait() && !req.getNoReload())
  2042. reloadFailed = !reloadCluster(target.get(), (unsigned)req.getWait());
  2043. resp.setReloadFailed(reloadFailed);
  2044. return true;
  2045. }
  2046. bool CWsWorkunitsEx::onWUQuerysetQueryAction(IEspContext &context, IEspWUQuerySetQueryActionRequest & req, IEspWUQuerySetQueryActionResponse & resp)
  2047. {
  2048. resp.setQuerySetName(req.getQuerySetName());
  2049. resp.setAction(req.getAction());
  2050. if (isEmpty(req.getQuerySetName()))
  2051. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Queryset name required");
  2052. Owned<IPropertyTree> queryset = getQueryRegistry(req.getQuerySetName(), true);
  2053. if (!queryset)
  2054. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Queryset %s not found", req.getQuerySetName());
  2055. Owned<IProperties> queryIds = createProperties();
  2056. expandQueryActionTargetList(queryIds, queryset, req.getQueries(), req.getAction());
  2057. if (req.getAction() == CQuerySetQueryActionTypes_ResetQueryStats)
  2058. return resetQueryStats(context, req.getQuerySetName(), queryIds, resp);
  2059. IArrayOf<IEspQuerySetQueryActionResult> results;
  2060. Owned<IPropertyIterator> it = queryIds->getIterator();
  2061. ForEach(*it)
  2062. {
  2063. const char *id = it->getPropKey();
  2064. Owned<IEspQuerySetQueryActionResult> result = createQuerySetQueryActionResult();
  2065. result->setQueryId(id);
  2066. try
  2067. {
  2068. Owned<IPropertyTree> query = getQueryById(queryset, id);
  2069. if (!query)
  2070. throw MakeStringException(ECLWATCH_QUERYID_NOT_FOUND, "Query %s/%s not found.", req.getQuerySetName(), id);
  2071. CQuerySetQueryActionTypes action = req.getAction();
  2072. const char* strAction = (action > -1) && (action < NumOfQuerySetQueryActionTypes) ? QuerySetQueryActionTypes[action] : "Undefined";
  2073. PROGLOG("%s: queryset %s, query %s", strAction, req.getQuerySetName(), id);
  2074. switch (action)
  2075. {
  2076. case CQuerySetQueryActionTypes_ToggleSuspend:
  2077. setQuerySuspendedState(queryset, id, !queryIds->getPropBool(id), context.queryUserId());
  2078. break;
  2079. case CQuerySetQueryActionTypes_Suspend:
  2080. setQuerySuspendedState(queryset, id, true, context.queryUserId());
  2081. break;
  2082. case CQuerySetQueryActionTypes_Unsuspend:
  2083. setQuerySuspendedState(queryset, id, false, NULL);
  2084. break;
  2085. case CQuerySetQueryActionTypes_Activate:
  2086. setQueryAlias(queryset, query->queryProp("@name"), id);
  2087. break;
  2088. case CQuerySetQueryActionTypes_Delete:
  2089. removeNamedQuery(queryset, id);
  2090. query.clear();
  2091. break;
  2092. case CQuerySetQueryActionTypes_RemoveAllAliases:
  2093. removeAliasesFromNamedQuery(queryset, id);
  2094. break;
  2095. }
  2096. result->setSuccess(true);
  2097. if (query)
  2098. result->setSuspended(query->getPropBool("@suspended"));
  2099. }
  2100. catch(IException *e)
  2101. {
  2102. StringBuffer msg;
  2103. result->setMessage(e->errorMessage(msg).str());
  2104. result->setCode(e->errorCode());
  2105. result->setSuccess(false);
  2106. e->Release();
  2107. }
  2108. results.append(*result.getClear());
  2109. }
  2110. resp.setResults(results);
  2111. return true;
  2112. }
  2113. bool CWsWorkunitsEx::onWUQuerysetAliasAction(IEspContext &context, IEspWUQuerySetAliasActionRequest &req, IEspWUQuerySetAliasActionResponse &resp)
  2114. {
  2115. resp.setQuerySetName(req.getQuerySetName());
  2116. resp.setAction(req.getAction());
  2117. if (isEmpty(req.getQuerySetName()))
  2118. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Queryset name required");
  2119. Owned<IPropertyTree> queryset = getQueryRegistry(req.getQuerySetName(), true);
  2120. if (!queryset)
  2121. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Queryset %s not found", req.getQuerySetName());
  2122. IArrayOf<IEspQuerySetAliasActionResult> results;
  2123. ForEachItemIn(i, req.getAliases())
  2124. {
  2125. IConstQuerySetAliasActionItem& item=req.getAliases().item(i);
  2126. Owned<IEspQuerySetAliasActionResult> result = createQuerySetAliasActionResult();
  2127. try
  2128. {
  2129. VStringBuffer xpath("Alias[@name='%s']", item.getName());
  2130. IPropertyTree *alias = queryset->queryPropTree(xpath.str());
  2131. if (!alias)
  2132. throw MakeStringException(ECLWATCH_ALIAS_NOT_FOUND, "Alias %s/%s not found.", req.getQuerySetName(), item.getName());
  2133. CQuerySetAliasActionTypes action = req.getAction();
  2134. const char* strAction = (action > -1) && (action < NumOfQuerySetAliasActionTypes) ? QuerySetAliasActionTypes[action] : "Undefined";
  2135. PROGLOG("%s: queryset %s, alias %s", strAction, req.getQuerySetName(), item.getName());
  2136. switch (action)
  2137. {
  2138. case CQuerySetAliasActionTypes_Deactivate:
  2139. removeQuerySetAlias(req.getQuerySetName(), item.getName());
  2140. break;
  2141. }
  2142. result->setSuccess(true);
  2143. }
  2144. catch(IException *e)
  2145. {
  2146. StringBuffer msg;
  2147. result->setMessage(e->errorMessage(msg).str());
  2148. result->setCode(e->errorCode());
  2149. result->setSuccess(false);
  2150. e->Release();
  2151. }
  2152. results.append(*result.getClear());
  2153. }
  2154. resp.setResults(results);
  2155. return true;
  2156. }
  2157. #define QUERYPATH_SEP_CHAR '/'
  2158. bool nextQueryPathNode(const char *&path, StringBuffer &node)
  2159. {
  2160. if (*path==QUERYPATH_SEP_CHAR)
  2161. path++;
  2162. while (*path && *path!=QUERYPATH_SEP_CHAR)
  2163. node.append(*path++);
  2164. return (*path && *++path);
  2165. }
  2166. bool splitQueryPath(const char *path, StringBuffer &netAddress, StringBuffer &queryset, StringBuffer *query)
  2167. {
  2168. if (!path || !*path)
  2169. return false;
  2170. if (*path==QUERYPATH_SEP_CHAR && path[1]==QUERYPATH_SEP_CHAR)
  2171. {
  2172. path+=2;
  2173. if (!nextQueryPathNode(path, netAddress))
  2174. return false;
  2175. }
  2176. if (!nextQueryPathNode(path, queryset))
  2177. return (query==NULL);
  2178. if (!query)
  2179. return false;
  2180. if (nextQueryPathNode(path, *query))
  2181. return false; //query path too deep
  2182. return true;
  2183. }
  2184. IPropertyTree *fetchRemoteQuerySetInfo(IEspContext *context, const char *srcAddress, const char *srcTarget)
  2185. {
  2186. if (!srcAddress || !*srcAddress || !srcTarget || !*srcTarget)
  2187. return NULL;
  2188. VStringBuffer url("http://%s%s/WsWorkunits/WUQuerysetDetails.xml?ver_=1.51&QuerySetName=%s&FilterType=All", srcAddress, (!strchr(srcAddress, ':')) ? ":8010" : "", srcTarget);
  2189. Owned<IHttpClientContext> httpCtx = getHttpClientContext();
  2190. Owned<IHttpClient> httpclient = httpCtx->createHttpClient(NULL, url);
  2191. const char *user = context->queryUserId();
  2192. if (user && *user)
  2193. httpclient->setUserID(user);
  2194. const char *pw = context->queryPassword();
  2195. if (pw && *pw)
  2196. httpclient->setPassword(pw);
  2197. StringBuffer request; //empty
  2198. StringBuffer response;
  2199. StringBuffer status;
  2200. if (0 > httpclient->sendRequest("GET", NULL, request, response, status) || !response.length() || strncmp("200", status, 3))
  2201. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Error fetching remote queryset information: %s %s %s", srcAddress, srcTarget, status.str());
  2202. return createPTreeFromXMLString(response);
  2203. }
  2204. class QueryCloner
  2205. {
  2206. public:
  2207. QueryCloner(IEspContext *_context, const char *address, const char *source, const char *_target) :
  2208. context(_context), target(_target), srcAddress(address)
  2209. {
  2210. if (srcAddress.length())
  2211. srcQuerySet.setown(fetchRemoteQuerySetInfo(context, srcAddress, source));
  2212. else
  2213. srcQuerySet.setown(getQueryRegistry(source, true));
  2214. if (!srcQuerySet)
  2215. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Source Queryset %s %s not found", srcAddress.str(), source);
  2216. destQuerySet.setown(getQueryRegistry(target, false));
  2217. if (!destQuerySet) // getQueryRegistry should have created if not found
  2218. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Destination Queryset %s could not be created, or found", target.str());
  2219. factory.setown(getWorkUnitFactory(context->querySecManager(), context->queryUser()));
  2220. }
  2221. QueryCloner(IEspContext *_context, IPropertyTree *srcTree, const char *_target) :
  2222. context(_context), target(_target)
  2223. {
  2224. srcQuerySet.set(srcTree);
  2225. destQuerySet.setown(getQueryRegistry(target, false));
  2226. if (!destQuerySet) // getQueryRegistry should have created if not found
  2227. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Destination Queryset %s could not be created, or found", target.str());
  2228. factory.setown(getWorkUnitFactory(context->querySecManager(), context->queryUser()));
  2229. }
  2230. void setQueryDirectory(const char *dir)
  2231. {
  2232. queryDirectory.set(dir);
  2233. }
  2234. void cloneQueryRemote(IPropertyTree *query, bool makeActive)
  2235. {
  2236. StringBuffer wuid(query->queryProp("Wuid"));
  2237. if (!wuid.length())
  2238. return;
  2239. const char *queryName = query->queryProp("Name");
  2240. if (!queryName || !*queryName)
  2241. return;
  2242. StringBuffer xml;
  2243. MemoryBuffer dll;
  2244. StringBuffer dllname;
  2245. StringBuffer fetchedName;
  2246. StringBuffer remoteDfs;
  2247. fetchRemoteWorkunit(NULL, context, srcAddress.str(), NULL, NULL, wuid, fetchedName, xml, dllname, dll, remoteDfs);
  2248. deploySharedObject(*context, wuid, dllname, target, queryName, dll, queryDirectory, xml.str());
  2249. SCMStringBuffer existingQueryId;
  2250. queryIdFromQuerySetWuid(destQuerySet, wuid, queryName, existingQueryId);
  2251. if (existingQueryId.length())
  2252. {
  2253. existingQueryIds.append(existingQueryId.str());
  2254. if (makeActive)
  2255. activateQuery(destQuerySet, ACTIVATE_SUSPEND_PREVIOUS, queryName, existingQueryId.str(), context->queryUserId());
  2256. return;
  2257. }
  2258. StringBuffer newQueryId;
  2259. Owned<IWorkUnit> workunit = factory->updateWorkUnit(wuid);
  2260. addQueryToQuerySet(workunit, destQuerySet, queryName, makeActive ? ACTIVATE_SUSPEND_PREVIOUS : DO_NOT_ACTIVATE, newQueryId, context->queryUserId());
  2261. copiedQueryIds.append(newQueryId);
  2262. Owned<IPropertyTree> destQuery = getQueryById(destQuerySet, newQueryId);
  2263. if (destQuery)
  2264. {
  2265. Owned<IAttributeIterator> aiter = query->getAttributes();
  2266. ForEach(*aiter)
  2267. {
  2268. const char *atname = aiter->queryName();
  2269. if (!destQuery->hasProp(atname))
  2270. destQuery->setProp(atname, aiter->queryValue());
  2271. }
  2272. if (cloneFilesEnabled && wufiles)
  2273. wufiles->addFilesFromQuery(workunit, pm, newQueryId);
  2274. }
  2275. }
  2276. void cloneQueryLocal(IPropertyTree *query, bool makeActive)
  2277. {
  2278. const char *wuid = query->queryProp("@wuid");
  2279. if (!wuid || !*wuid)
  2280. return;
  2281. const char *queryName = query->queryProp("@name");
  2282. if (!queryName || !*queryName)
  2283. return;
  2284. SCMStringBuffer existingQueryId;
  2285. queryIdFromQuerySetWuid(destQuerySet, wuid, queryName, existingQueryId);
  2286. if (existingQueryId.length())
  2287. {
  2288. existingQueryIds.append(existingQueryId.str());
  2289. if (makeActive)
  2290. activateQuery(destQuerySet, ACTIVATE_SUSPEND_PREVIOUS, queryName, existingQueryId.str(), context->queryUserId());
  2291. return;
  2292. }
  2293. StringBuffer newQueryId;
  2294. Owned<IWorkUnit> workunit = factory->updateWorkUnit(wuid);
  2295. if (!workunit)
  2296. {
  2297. StringBuffer msg(wuid);
  2298. msg.append(": ").append(query->queryProp("@id"));
  2299. missingWuids.append(msg);
  2300. return;
  2301. }
  2302. if (!newQueryId.length())
  2303. addQueryToQuerySet(workunit, destQuerySet, queryName, makeActive ? ACTIVATE_SUSPEND_PREVIOUS : DO_NOT_ACTIVATE, newQueryId, context->queryUserId());
  2304. copiedQueryIds.append(newQueryId);
  2305. Owned<IPropertyTree> destQuery = getQueryById(destQuerySet, newQueryId);
  2306. if (destQuery)
  2307. {
  2308. Owned<IAttributeIterator> aiter = query->getAttributes();
  2309. ForEach(*aiter)
  2310. {
  2311. const char *atname = aiter->queryName();
  2312. if (!destQuery->hasProp(atname))
  2313. destQuery->setProp(atname, aiter->queryValue());
  2314. }
  2315. Owned<IPropertyTreeIterator> children = query->getElements("*");
  2316. ForEach(*children)
  2317. {
  2318. IPropertyTree &child = children->query();
  2319. destQuery->addPropTree(child.queryName(), createPTreeFromIPT(&child));
  2320. }
  2321. if (cloneFilesEnabled && wufiles)
  2322. wufiles->addFilesFromQuery(workunit, pm, newQueryId);
  2323. }
  2324. }
  2325. void cloneActiveRemote(bool makeActive)
  2326. {
  2327. Owned<IPropertyTreeIterator> activeQueries = srcQuerySet->getElements("QuerysetAliases/QuerySetAlias");
  2328. ForEach(*activeQueries)
  2329. {
  2330. IPropertyTree &alias = activeQueries->query();
  2331. VStringBuffer xpath("QuerysetQueries/QuerySetQuery[Id='%s'][1]", alias.queryProp("Id"));
  2332. IPropertyTree *query = srcQuerySet->queryPropTree(xpath);
  2333. if (!query)
  2334. continue;
  2335. cloneQueryRemote(query, makeActive);
  2336. }
  2337. }
  2338. void cloneActiveLocal(bool makeActive, const char *mask)
  2339. {
  2340. StringBuffer xpath("Alias");
  2341. if (mask && *mask)
  2342. xpath.appendf("[@id='%s']", mask);
  2343. Owned<IPropertyTreeIterator> activeQueries = srcQuerySet->getElements(xpath);
  2344. ForEach(*activeQueries)
  2345. {
  2346. IPropertyTree &alias = activeQueries->query();
  2347. Owned<IPropertyTree> query = getQueryById(srcQuerySet, alias.queryProp("@id"));
  2348. if (!query)
  2349. return;
  2350. cloneQueryLocal(query, makeActive);
  2351. }
  2352. }
  2353. void cloneActive(bool makeActive)
  2354. {
  2355. if (srcAddress.length())
  2356. cloneActiveRemote(makeActive);
  2357. else
  2358. cloneActiveLocal(makeActive, nullptr);
  2359. }
  2360. void cloneAllRemote(bool cloneActiveState)
  2361. {
  2362. Owned<IPropertyTreeIterator> allQueries = srcQuerySet->getElements("QuerysetQueries/QuerySetQuery");
  2363. ForEach(*allQueries)
  2364. {
  2365. IPropertyTree &query = allQueries->query();
  2366. bool makeActive = false;
  2367. if (cloneActiveState)
  2368. {
  2369. VStringBuffer xpath("QuerysetAliases/QuerySetAlias[Id='%s']", query.queryProp("Id"));
  2370. makeActive = srcQuerySet->hasProp(xpath);
  2371. }
  2372. cloneQueryRemote(&query, makeActive);
  2373. }
  2374. }
  2375. void cloneAllLocal(bool cloneActiveState, const char *mask)
  2376. {
  2377. StringBuffer xpath("Query");
  2378. if (mask && *mask)
  2379. xpath.appendf("[@id='%s']", mask);
  2380. Owned<IPropertyTreeIterator> allQueries = srcQuerySet->getElements(xpath);
  2381. ForEach(*allQueries)
  2382. {
  2383. IPropertyTree &query = allQueries->query();
  2384. bool makeActive = false;
  2385. if (cloneActiveState)
  2386. {
  2387. VStringBuffer xpath("Alias[@id='%s']", query.queryProp("@id"));
  2388. makeActive = srcQuerySet->hasProp(xpath);
  2389. }
  2390. cloneQueryLocal(&query, makeActive);
  2391. }
  2392. }
  2393. void cloneAll(bool cloneActiveState)
  2394. {
  2395. if (srcAddress.length())
  2396. cloneAllRemote(cloneActiveState);
  2397. else
  2398. cloneAllLocal(cloneActiveState, nullptr);
  2399. }
  2400. void enableFileCloning(unsigned _updateFlags, const char *dfsServer, const char *destProcess, const char *sourceProcess, bool allowForeign)
  2401. {
  2402. cloneFilesEnabled = true;
  2403. updateFlags = _updateFlags;
  2404. splitDerivedDfsLocation(dfsServer, srcCluster, dfsIP, srcPrefix, sourceProcess, sourceProcess, NULL, NULL);
  2405. wufiles.setown(createReferencedFileList(context->queryUserId(), context->queryPassword(), allowForeign, false));
  2406. Owned<IHpccPackageSet> ps = createPackageSet(destProcess);
  2407. pm.set(ps->queryActiveMap(target));
  2408. process.set(destProcess);
  2409. }
  2410. void cloneFiles()
  2411. {
  2412. if (cloneFilesEnabled)
  2413. {
  2414. wufiles->resolveFiles(process, dfsIP, srcPrefix, srcCluster, !(updateFlags & (DALI_UPDATEF_REPLACE_FILE | DALI_UPDATEF_CLONE_FROM)), true, false, true);
  2415. Owned<IDFUhelper> helper = createIDFUhelper();
  2416. Owned <IConstWUClusterInfo> cl = getTargetClusterInfo(target);
  2417. if (cl)
  2418. {
  2419. SCMStringBuffer process;
  2420. StringBuffer defReplicateFolder;
  2421. getConfigurationDirectory(NULL, "data2", "roxie", cl->getRoxieProcess(process).str(), defReplicateFolder);
  2422. wufiles->cloneAllInfo(updateFlags, helper, true, true, cl->getRoxieRedundancy(), cl->getChannelsPerNode(), cl->getRoxieReplicateOffset(), defReplicateFolder);
  2423. }
  2424. }
  2425. }
  2426. void gatherFileErrors(IArrayOf<IConstLogicalFileError> &errors)
  2427. {
  2428. if (wufiles)
  2429. ::gatherFileErrors(wufiles, errors);
  2430. }
  2431. private:
  2432. Linked<IEspContext> context;
  2433. Linked<IWorkUnitFactory> factory;
  2434. Owned<IPropertyTree> destQuerySet;
  2435. Owned<IPropertyTree> srcQuerySet;
  2436. Owned<IReferencedFileList> wufiles;
  2437. Owned<const IHpccPackageMap> pm;
  2438. StringBuffer dfsIP;
  2439. StringBuffer srcAddress;
  2440. StringBuffer srcCluster;
  2441. StringBuffer srcPrefix;
  2442. StringAttr target;
  2443. StringAttr process;
  2444. StringAttr queryDirectory;
  2445. bool cloneFilesEnabled = false;
  2446. unsigned updateFlags = 0;
  2447. public:
  2448. StringArray existingQueryIds;
  2449. StringArray copiedQueryIds;
  2450. StringArray missingWuids;
  2451. };
  2452. bool CWsWorkunitsEx::onWUCopyQuerySet(IEspContext &context, IEspWUCopyQuerySetRequest &req, IEspWUCopyQuerySetResponse &resp)
  2453. {
  2454. const char *source = req.getSource();
  2455. if (!source || !*source)
  2456. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "No source target specified");
  2457. StringBuffer srcAddress;
  2458. StringBuffer srcTarget;
  2459. if (!splitQueryPath(source, srcAddress, srcTarget, NULL))
  2460. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid source target");
  2461. if (!srcAddress.length() && !isValidCluster(srcTarget))
  2462. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid source target name: %s", source);
  2463. const char *target = req.getTarget();
  2464. if (!target || !*target)
  2465. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "No destination target specified");
  2466. if (!isValidCluster(target))
  2467. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid destination target name: %s", target);
  2468. DBGLOG("%s copying queryset %s from %s target %s", context.queryUserId(), target, srcAddress.str(), srcTarget.str());
  2469. QueryCloner cloner(&context, srcAddress, srcTarget, target);
  2470. cloner.setQueryDirectory(queryDirectory);
  2471. SCMStringBuffer process;
  2472. if (req.getCopyFiles())
  2473. {
  2474. Owned <IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(target);
  2475. if (clusterInfo && clusterInfo->getPlatform()==RoxieCluster)
  2476. {
  2477. clusterInfo->getRoxieProcess(process);
  2478. if (!process.length())
  2479. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_INFO, "DFS process cluster not found for destination target %s", target);
  2480. unsigned updateFlags = 0;
  2481. if (req.getOverwriteDfs())
  2482. updateFlags |= (DALI_UPDATEF_REPLACE_FILE | DALI_UPDATEF_CLONE_FROM | DALI_UPDATEF_SUPERFILES);
  2483. if (req.getUpdateCloneFrom())
  2484. updateFlags |= DALI_UPDATEF_CLONE_FROM;
  2485. if (req.getUpdateSuperFiles())
  2486. updateFlags |= DALI_UPDATEF_SUPERFILES;
  2487. if (req.getAppendCluster())
  2488. updateFlags |= DALI_UPDATEF_APPEND_CLUSTER;
  2489. cloner.enableFileCloning(updateFlags, req.getDfsServer(), process.str(), req.getSourceProcess(), req.getAllowForeignFiles());
  2490. }
  2491. }
  2492. if (req.getActiveOnly())
  2493. cloner.cloneActive(req.getCloneActiveState());
  2494. else
  2495. cloner.cloneAll(req.getCloneActiveState());
  2496. cloner.cloneFiles();
  2497. if (req.getIncludeFileErrors())
  2498. cloner.gatherFileErrors(resp.getFileErrors());
  2499. resp.setCopiedQueries(cloner.copiedQueryIds);
  2500. resp.setExistingQueries(cloner.existingQueryIds);
  2501. return true;
  2502. }
  2503. bool CWsWorkunitsEx::onWUQuerysetCopyQuery(IEspContext &context, IEspWUQuerySetCopyQueryRequest &req, IEspWUQuerySetCopyQueryResponse &resp)
  2504. {
  2505. unsigned start = msTick();
  2506. const char *source = req.getSource();
  2507. if (!source || !*source)
  2508. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "No source query specified");
  2509. const char *target = req.getTarget();
  2510. if (!target || !*target)
  2511. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "No destination specified");
  2512. if (strchr(target, '/')) //for future use
  2513. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid target queryset name");
  2514. if (req.getCluster() && *req.getCluster() && !strieq(req.getCluster(), target)) //backward compatability check
  2515. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid target cluster and queryset must match");
  2516. if (!isValidCluster(target))
  2517. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid target name: %s", target);
  2518. StringBuffer srcAddress, srcQuerySet, srcQuery;
  2519. if (!splitQueryPath(source, srcAddress, srcQuerySet, &srcQuery))
  2520. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid source query path");
  2521. StringAttr targetQueryName(req.getDestName());
  2522. Owned<IClientWUQuerySetDetailsResponse> sourceQueryInfoResp;
  2523. IConstQuerySetQuery *srcInfo=NULL;
  2524. DBGLOG("%s copying query %s to target %s from %s target %s", context.queryUserId(), srcQuery.str(), target, srcAddress.str(), srcQuerySet.str());
  2525. StringBuffer remoteIP;
  2526. StringBuffer wuid;
  2527. if (srcAddress.length())
  2528. {
  2529. StringBuffer xml;
  2530. MemoryBuffer dll;
  2531. StringBuffer dllname;
  2532. StringBuffer queryName;
  2533. fetchRemoteWorkunitAndQueryDetails(NULL, &context, srcAddress.str(), srcQuerySet.str(), srcQuery.str(), NULL, queryName, xml, dllname, dll, remoteIP, sourceQueryInfoResp);
  2534. if (sourceQueryInfoResp && sourceQueryInfoResp->getQuerysetQueries().ordinality())
  2535. srcInfo = &sourceQueryInfoResp->getQuerysetQueries().item(0);
  2536. if (srcInfo)
  2537. wuid.set(srcInfo->getWuid());
  2538. if (targetQueryName.isEmpty())
  2539. targetQueryName.set(queryName);
  2540. deploySharedObject(context, wuid, dllname.str(), target, targetQueryName.get(), dll, queryDirectory.str(), xml.str());
  2541. }
  2542. else
  2543. {
  2544. //Could get the atributes without soap call, but this creates a common data structure shared with fetching remote query info
  2545. //Get query attributes before resolveQueryAlias, to avoid deadlock
  2546. sourceQueryInfoResp.setown(fetchQueryDetails(NULL, &context, NULL, srcQuerySet, srcQuery));
  2547. if (sourceQueryInfoResp && sourceQueryInfoResp->getQuerysetQueries().ordinality())
  2548. srcInfo = &sourceQueryInfoResp->getQuerysetQueries().item(0);
  2549. Owned<IPropertyTree> queryset = getQueryRegistry(srcQuerySet.str(), true);
  2550. if (!queryset)
  2551. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Source Queryset %s not found", srcQuery.str());
  2552. Owned<IPropertyTree> query = resolveQueryAlias(queryset, srcQuery.str());
  2553. if (!query)
  2554. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Source query %s not found", source);
  2555. wuid.set(query->queryProp("@wuid"));
  2556. if (targetQueryName.isEmpty())
  2557. targetQueryName.set(query->queryProp("@name"));
  2558. }
  2559. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  2560. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  2561. if (!req.getDontCopyFiles())
  2562. {
  2563. StringBuffer daliIP;
  2564. StringBuffer srcCluster;
  2565. StringBuffer srcPrefix;
  2566. splitDerivedDfsLocation(req.getDaliServer(), srcCluster, daliIP, srcPrefix, req.getSourceProcess(), req.getSourceProcess(), remoteIP.str(), NULL);
  2567. unsigned updateFlags = 0;
  2568. if (req.getOverwrite())
  2569. updateFlags |= (DALI_UPDATEF_REPLACE_FILE | DALI_UPDATEF_CLONE_FROM | DALI_UPDATEF_SUPERFILES);
  2570. if (req.getUpdateCloneFrom())
  2571. updateFlags |= DALI_UPDATEF_CLONE_FROM;
  2572. if (req.getUpdateSuperFiles())
  2573. updateFlags |= DALI_UPDATEF_SUPERFILES;
  2574. if (req.getAppendCluster())
  2575. updateFlags |= DALI_UPDATEF_APPEND_CLUSTER;
  2576. QueryFileCopier cpr(target);
  2577. cpr.init(context, req.getAllowForeignFiles());
  2578. cpr.remoteIP.set(daliIP);
  2579. cpr.remotePrefix.set(srcPrefix);
  2580. cpr.srcCluster.set(srcCluster);
  2581. cpr.queryname.set(targetQueryName);
  2582. cpr.copy(cw, updateFlags);
  2583. if (req.getIncludeFileErrors())
  2584. cpr.gatherFileErrors(resp.getFileErrors());
  2585. }
  2586. WorkunitUpdate wu(&cw->lock());
  2587. if (!wu)
  2588. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT, "Error opening wuid %s for query %s", wuid.str(), source);
  2589. StringBuffer targetQueryId;
  2590. WUQueryActivationOptions activate = (WUQueryActivationOptions)req.getActivate();
  2591. addQueryToQuerySet(wu, target, targetQueryName.get(), activate, targetQueryId, context.queryUserId());
  2592. Owned<IPropertyTree> queryTree = getQueryById(target, targetQueryId, false);
  2593. if (queryTree)
  2594. {
  2595. updateMemoryLimitSetting(queryTree, req.getMemoryLimit(), srcInfo);
  2596. updateQueryPriority(queryTree, req.getPriority(), srcInfo);
  2597. updateTimeLimitSetting(queryTree, req.getTimeLimit_isNull(), req.getTimeLimit(), srcInfo);
  2598. updateWarnTimeLimitSetting(queryTree, req.getWarnTimeLimit_isNull(), req.getWarnTimeLimit(), srcInfo);
  2599. if (req.getComment())
  2600. queryTree->setProp("@comment", req.getComment());
  2601. else if (srcInfo && srcInfo->getComment())
  2602. queryTree->setProp("@comment", srcInfo->getComment());
  2603. if (srcInfo && srcInfo->getSnapshot())
  2604. queryTree->setProp("@snapshot", srcInfo->getSnapshot());
  2605. }
  2606. wu.clear();
  2607. resp.setQueryId(targetQueryId.str());
  2608. if (0!=req.getWait() && !req.getNoReload())
  2609. reloadCluster(target, remainingMsWait(req.getWait(), start));
  2610. return true;
  2611. }
  2612. bool CWsWorkunitsEx::onWUQuerysetImport(IEspContext &context, IEspWUQuerysetImportRequest &req, IEspWUQuerysetImportResponse &resp)
  2613. {
  2614. try
  2615. {
  2616. const char* target = req.getTarget();
  2617. if (!target || !*target)
  2618. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Target not specified");
  2619. Owned <IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(target);
  2620. if (!clusterInfo)
  2621. throw MakeStringException(ECLWATCH_CANNOT_RESOLVE_CLUSTER_NAME, "Target not found");
  2622. if (req.getCopyFiles() && clusterInfo->getPlatform()!=RoxieCluster)
  2623. throw MakeStringException(ECLWATCH_INVALID_ACTION, "Copy files option only supported for Roxie");
  2624. MemoryBuffer &mb = const_cast<MemoryBuffer &>(req.getData()); //for efficiency, content of request shouldn't matter after
  2625. if (req.getCompressed())
  2626. {
  2627. MemoryBuffer decompressed;
  2628. fastLZDecompressToBuffer(decompressed, mb);
  2629. mb.swapWith(decompressed);
  2630. }
  2631. mb.append('\0');
  2632. Owned<IPropertyTree> srcTree = createPTreeFromXMLString(mb.toByteArray());
  2633. const char *archivedTarget = srcTree->queryProp("@target");
  2634. if (archivedTarget && *archivedTarget) //support simple queryset or with archived (exported) root format
  2635. {
  2636. VStringBuffer xpath("QuerySet[@id='%s']", archivedTarget);
  2637. IPropertyTree *qsTree = srcTree->queryPropTree(xpath);
  2638. if (qsTree)
  2639. srcTree.setown(LINK(qsTree));
  2640. }
  2641. if (req.getReplace())
  2642. {
  2643. Owned<IPropertyTree> queryRegistry = getQueryRegistry(target, false);
  2644. queryRegistry->removeProp("*");
  2645. resp.setClearedExisting(true);
  2646. }
  2647. const bool activate = CQuerysetImportActivation_ImportedActive == req.getActivation(); //only two options now but may evolve
  2648. QueryCloner cloner(&context, srcTree, target);
  2649. SCMStringBuffer process;
  2650. if (req.getCopyFiles())
  2651. {
  2652. clusterInfo->getRoxieProcess(process); //checked if roxie when copying files above
  2653. if (!process.length())
  2654. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_INFO, "DFS process cluster not found for destination target %s", target);
  2655. unsigned updateFlags = 0;
  2656. if (req.getOverwriteDfs())
  2657. updateFlags |= (DALI_UPDATEF_REPLACE_FILE | DALI_UPDATEF_CLONE_FROM | DALI_UPDATEF_SUPERFILES);
  2658. if (req.getUpdateCloneFrom())
  2659. updateFlags |= DALI_UPDATEF_CLONE_FROM;
  2660. if (req.getUpdateSuperFiles())
  2661. updateFlags |= DALI_UPDATEF_SUPERFILES;
  2662. if (req.getAppendCluster())
  2663. updateFlags |= DALI_UPDATEF_APPEND_CLUSTER;
  2664. cloner.enableFileCloning(updateFlags, req.getDfsServer(), process.str(), req.getSourceProcess(), req.getAllowForeignFiles());
  2665. }
  2666. if (req.getActiveOnly())
  2667. cloner.cloneActiveLocal(activate, req.getQueryMask());
  2668. else
  2669. cloner.cloneAllLocal(activate, req.getQueryMask());
  2670. cloner.cloneFiles();
  2671. if (req.getIncludeFileErrors())
  2672. cloner.gatherFileErrors(resp.getFileErrors());
  2673. resp.setImportedQueries(cloner.copiedQueryIds);
  2674. resp.setExistingQueries(cloner.existingQueryIds);
  2675. resp.setMissingWuids(cloner.missingWuids);
  2676. }
  2677. catch(IException* e)
  2678. {
  2679. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  2680. }
  2681. return true;
  2682. }
  2683. bool CWsWorkunitsEx::onWUQuerysetExport(IEspContext &context, IEspWUQuerysetExportRequest &req, IEspWUQuerysetExportResponse &resp)
  2684. {
  2685. try
  2686. {
  2687. const char* target = req.getTarget();
  2688. if (!target || !*target)
  2689. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Target not specified");
  2690. Owned<IPropertyTree> queryRegistry = getQueryRegistry(target, true);
  2691. if (req.getActiveOnly())
  2692. {
  2693. Owned<IPropertyTree> activeOnly = createPTree("QuerySet");
  2694. Owned<IAttributeIterator> attrs = queryRegistry->getAttributes();
  2695. ForEach(*attrs)
  2696. activeOnly->setProp(attrs->queryName(), attrs->queryValue());
  2697. Owned<IPropertyTreeIterator> aliases = queryRegistry->getElements("Alias");
  2698. ForEach(*aliases)
  2699. {
  2700. IPropertyTree &alias = aliases->query();
  2701. const char *id = alias.queryProp("@id");
  2702. if (id && *id)
  2703. {
  2704. VStringBuffer xpath("Query[@id='%s']", id);
  2705. IPropertyTree *query = queryRegistry->queryPropTree(xpath);
  2706. if (query)
  2707. {
  2708. activeOnly->addPropTree("Query", LINK(query));
  2709. activeOnly->addPropTree("Alias", LINK(&alias));
  2710. }
  2711. }
  2712. }
  2713. queryRegistry.setown(activeOnly.getClear());
  2714. }
  2715. if (req.getProtect())
  2716. {
  2717. StringArray wuids;
  2718. Owned<IPropertyTreeIterator> queries = queryRegistry->getElements("Query");
  2719. ForEach(*queries)
  2720. {
  2721. IPropertyTree &query = queries->query();
  2722. const char *wuid = query.queryProp("@wuid");
  2723. if (wuid && *wuid)
  2724. wuids.append(wuid);
  2725. }
  2726. if (wuids.length())
  2727. doProtectWorkunits(context, wuids, nullptr);
  2728. }
  2729. CDateTime dt;
  2730. dt.setNow();
  2731. StringBuffer dts;
  2732. VStringBuffer qs("<QuerySetArchive exported='%s' target='%s' activeOnly='%s'>\n", dt.getString(dts, true).str(), target, req.getActiveOnly() ? "true" : "false");
  2733. toXML(queryRegistry, qs);
  2734. qs.append("</QuerySetArchive>");
  2735. MemoryBuffer content;
  2736. if (req.getCompress())
  2737. fastLZCompressToBuffer(content, qs.length()+1, qs);
  2738. else
  2739. content.append(qs.str());
  2740. resp.setTarget(target);
  2741. resp.setCompressed(req.getCompress());
  2742. resp.setData(content);
  2743. }
  2744. catch(IException* e)
  2745. {
  2746. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  2747. }
  2748. return true;
  2749. }
  2750. void CWsWorkunitsEx::getGraphsByQueryId(const char *target, const char *queryId, const char *graphId, const char *subGraphId, IArrayOf<IEspECLGraphEx>& ECLGraphs)
  2751. {
  2752. if (!target || !*target)
  2753. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Target name required");
  2754. if (!queryId || !*queryId)
  2755. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Query Id required");
  2756. Owned<IConstWUClusterInfo> info = getTargetClusterInfo(target);
  2757. if (!info || (info->getPlatform()!=RoxieCluster)) //Only support roxie for now
  2758. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid Roxie name");
  2759. PROGLOG("getGraphsByQueryId: target %s, query %s", target, queryId);
  2760. const SocketEndpointArray &eps = info->getRoxieServers();
  2761. if (eps.empty())
  2762. return;
  2763. VStringBuffer control("<control:querystats><Query id='%s'/></control:querystats>", queryId);
  2764. Owned<IPropertyTree> querystats = sendRoxieControlAllNodes(eps.item(0), control.str(), false, ROXIELOCKCONNECTIONTIMEOUT);
  2765. if (!querystats)
  2766. return;
  2767. Owned<IPropertyTreeIterator> graphs = querystats->getElements("Endpoint/Query/Graph");
  2768. ForEach(*graphs)
  2769. {
  2770. IPropertyTree &graph = graphs->query();
  2771. const char* aGraphId = graph.queryProp("@id");
  2772. if (graphId && *graphId && !strieq(graphId, aGraphId))
  2773. continue;
  2774. IPropertyTree* xgmml = graph.getBranch("xgmml/graph");
  2775. if (!xgmml)
  2776. continue;
  2777. Owned<IEspECLGraphEx> g = createECLGraphEx("","");
  2778. g->setName(aGraphId);
  2779. StringBuffer xml;
  2780. if (!subGraphId || !*subGraphId)
  2781. toXML(xgmml, xml);
  2782. else
  2783. {
  2784. VStringBuffer xpath("//node[@id='%s']", subGraphId);
  2785. toXML(xgmml->queryPropTree(xpath.str()), xml);
  2786. }
  2787. g->setGraph(xml.str());
  2788. ECLGraphs.append(*g.getClear());
  2789. }
  2790. return;
  2791. }
  2792. bool CWsWorkunitsEx::onWUQueryGetGraph(IEspContext& context, IEspWUQueryGetGraphRequest& req, IEspWUQueryGetGraphResponse& resp)
  2793. {
  2794. try
  2795. {
  2796. IArrayOf<IEspECLGraphEx> graphs;
  2797. getGraphsByQueryId(req.getTarget(), req.getQueryId(), req.getGraphName(), req.getSubGraphId(), graphs);
  2798. resp.setGraphs(graphs);
  2799. }
  2800. catch(IException* e)
  2801. {
  2802. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  2803. }
  2804. return true;
  2805. }
  2806. bool CWsWorkunitsEx::resetQueryStats(IEspContext& context, const char* target, IProperties* queryIds, IEspWUQuerySetQueryActionResponse& resp)
  2807. {
  2808. IArrayOf<IEspQuerySetQueryActionResult> results;
  2809. Owned<IEspQuerySetQueryActionResult> result = createQuerySetQueryActionResult();
  2810. try
  2811. {
  2812. StringBuffer control;
  2813. Owned<IPropertyIterator> it = queryIds->getIterator();
  2814. ForEach(*it)
  2815. {
  2816. const char *queryId = it->getPropKey();
  2817. if (queryId && *queryId)
  2818. {
  2819. appendXMLOpenTag(control, "Query", NULL, false);
  2820. appendXMLAttr(control, "id", queryId);
  2821. if (target && *target)
  2822. appendXMLAttr(control, "target", target);
  2823. control.append("/>");
  2824. }
  2825. }
  2826. if (!control.length())
  2827. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "CWsWorkunitsEx::resetQueryStats: Query ID not specified");
  2828. control.insert(0, "<control:resetquerystats>");
  2829. control.append("</control:resetquerystats>");
  2830. if (!sendControlQuery(context, target, control.str(), ROXIECONNECTIONTIMEOUT))
  2831. throw MakeStringException(ECLWATCH_INTERNAL_ERROR, "CWsWorkunitsEx::resetQueryStats: Failed to send roxie control query");
  2832. result->setMessage("Query stats reset succeeded");
  2833. result->setSuccess(true);;
  2834. }
  2835. catch(IMultiException *me)
  2836. {
  2837. StringBuffer msg;
  2838. result->setMessage(me->errorMessage(msg).str());
  2839. result->setCode(me->errorCode());
  2840. result->setSuccess(false);
  2841. me->Release();
  2842. }
  2843. catch(IException *e)
  2844. {
  2845. StringBuffer msg;
  2846. result->setMessage(e->errorMessage(msg).str());
  2847. result->setCode(e->errorCode());
  2848. result->setSuccess(false);
  2849. e->Release();
  2850. }
  2851. results.append(*result.getClear());
  2852. resp.setResults(results);
  2853. return true;
  2854. }
  2855. IPropertyTree* CWsWorkunitsEx::sendControlQuery(IEspContext& context, const char* target, const char* query, unsigned timeout)
  2856. {
  2857. if (!target || !*target)
  2858. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "CWsWorkunitsEx::sendControlQuery: target not specified");
  2859. if (!query || !*query)
  2860. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "CWsWorkunitsEx::sendControlQuery: Control query not specified");
  2861. Owned<IConstWUClusterInfo> info = getTargetClusterInfo(target);
  2862. if (!info || (info->getPlatform()!=RoxieCluster)) //Only support roxie for now
  2863. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "CWsWorkunitsEx::sendControlQuery: Invalid target name %s", target);
  2864. const SocketEndpointArray &eps = info->getRoxieServers();
  2865. if (eps.empty())
  2866. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "CWsWorkunitsEx::sendControlQuery: Server not found for %s", target);
  2867. Owned<ISocket> sock = ISocket::connect_timeout(eps.item(0), timeout);
  2868. return sendRoxieControlQuery(sock, query, timeout);
  2869. }
  2870. bool CWsWorkunitsEx::onWUUpdateQueryEntry(IEspContext& context, IEspWUUpdateQueryEntryRequest& req, IEspWUUpdateQueryEntryResponse& resp)
  2871. {
  2872. try
  2873. {
  2874. StringBuffer querySetName, query;
  2875. ensureInputString(req.getQuerySet(), true, querySetName, ECLWATCH_QUERYSET_NOT_FOUND, "Query Set not specified");
  2876. ensureInputString(req.getQueryId(), true, query, ECLWATCH_QUERYID_NOT_FOUND, "Query not specified");
  2877. Owned<IPropertyTree> querySet = getQueryRegistry(querySetName.str(), true);
  2878. if (!querySet)
  2879. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Queryset %s not found", querySetName.str());
  2880. VStringBuffer xpath("Query[@id=\"%s\"]", query.str());
  2881. IPropertyTree *tree = querySet->queryPropTree(xpath);
  2882. if (!tree)
  2883. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Query %s not found", query.str());
  2884. StringBuffer comment(req.getComment());
  2885. if (comment.isEmpty())
  2886. tree->removeProp("@comment");
  2887. else
  2888. tree->setProp("@comment", comment.str());
  2889. }
  2890. catch(IException* e)
  2891. {
  2892. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  2893. }
  2894. return true;
  2895. }
  2896. bool CWsWorkunitsEx::onWUGetNumFileToCopy(IEspContext& context, IEspWUGetNumFileToCopyRequest& req, IEspWUGetNumFileToCopyResponse& resp)
  2897. {
  2898. class CWUGetNumFileToCopyPager : public CSimpleInterface, implements IElementsPager
  2899. {
  2900. StringAttr clusterName;
  2901. StringAttr sortOrder;
  2902. public:
  2903. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  2904. CWUGetNumFileToCopyPager(const char* _clusterName, const char *_sortOrder)
  2905. : clusterName(_clusterName), sortOrder(_sortOrder) { };
  2906. virtual IRemoteConnection* getElements(IArrayOf<IPropertyTree> &elements)
  2907. {
  2908. SocketEndpointArray servers;
  2909. getRoxieProcessServers(clusterName.get(), servers);
  2910. if (servers.length() < 1)
  2911. {
  2912. PROGLOG("WUGetNumFileToCopy: Process Server not found for %s", clusterName.get());
  2913. return NULL;
  2914. }
  2915. Owned<IPropertyTree> result = sendRoxieControlAllNodes(servers.item(0), "<control:numfilestoprocess/>", false, ROXIELOCKCONNECTIONTIMEOUT);
  2916. if (!result)
  2917. {
  2918. PROGLOG("WUGetNumFileToCopy: Empty result received for cluster %s", clusterName.get());
  2919. return NULL;
  2920. }
  2921. Owned<IPropertyTreeIterator> iter = result->getElements("*");
  2922. if (!iter)
  2923. return NULL;
  2924. StringArray unknownAttributes;
  2925. sortElements(iter, sortOrder.get(), NULL, NULL, unknownAttributes, elements);
  2926. return NULL;
  2927. }
  2928. virtual bool allMatchingElementsReceived() { return true; } //For now, roxie always returns all of matched items.
  2929. };
  2930. try
  2931. {
  2932. StringBuffer clusterName(req.getClusterName());
  2933. if (clusterName.isEmpty())
  2934. throw MakeStringException(ECLWATCH_CANNOT_RESOLVE_CLUSTER_NAME, "Cluster not specified");
  2935. StringBuffer so;
  2936. bool descending = req.getDescending();
  2937. if (descending)
  2938. so.set("-");
  2939. const char *sortBy = req.getSortby();
  2940. if (!isEmptyString(sortBy) && strieq(sortBy, "URL"))
  2941. so.append("?@ep");
  2942. else if (!isEmptyString(sortBy) && strieq(sortBy, "Status"))
  2943. so.append("?Status");
  2944. else
  2945. so.append("#FilesToProcess/@value");
  2946. unsigned pageSize = req.getPageSize();
  2947. unsigned pageStartFrom = req.getPageStartFrom();
  2948. if(pageSize < 1)
  2949. pageSize = 100;
  2950. __int64 cacheHint = 0;
  2951. if (!req.getCacheHint_isNull())
  2952. cacheHint = req.getCacheHint();
  2953. unsigned numberOfEndpoints = 0;
  2954. IArrayOf<IPropertyTree> results;
  2955. Owned<IElementsPager> elementsPager = new CWUGetNumFileToCopyPager(clusterName.str(), so.str());
  2956. getElementsPaged(elementsPager, pageStartFrom, pageSize, NULL, "", &cacheHint, results, &numberOfEndpoints, NULL, false);
  2957. IArrayOf<IEspClusterEndpoint> endpoints;
  2958. ForEachItemIn(i, results)
  2959. {
  2960. IPropertyTree &item = results.item(i);
  2961. Owned<IEspClusterEndpoint> endpoint = createClusterEndpoint();
  2962. endpoint->setURL(item.queryProp("@ep"));
  2963. endpoint->setStatus(item.queryProp("Status"));
  2964. endpoint->setNumQueryFileToCopy(item.getPropInt("FilesToProcess/@value", 0));
  2965. endpoints.append(*endpoint.getClear());
  2966. }
  2967. resp.setEndpoints(endpoints);
  2968. resp.setCacheHint(cacheHint);
  2969. resp.setTotal(numberOfEndpoints);
  2970. }
  2971. catch(IException* e)
  2972. {
  2973. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  2974. }
  2975. return true;
  2976. }
  2977. bool CWsWorkunitsEx::onWUQueryGetSummaryStats(IEspContext& context, IEspWUQueryGetSummaryStatsRequest& req, IEspWUQueryGetSummaryStatsResponse& resp)
  2978. {
  2979. try
  2980. {
  2981. const char *target = req.getTarget();
  2982. if (isEmptyString(target))
  2983. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Target name required");
  2984. Owned<IConstWUClusterInfo> info = getTargetClusterInfo(target);
  2985. if (!info || (info->getPlatform()!=RoxieCluster)) //Only support roxie for now
  2986. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Roxie name not found");
  2987. double version = context.getClientVersion();
  2988. const char *queryId = req.getQueryId();
  2989. if (!isEmptyString(queryId))
  2990. PROGLOG("WUQueryGetSummaryStats: target %s, query %s", target, queryId);
  2991. else
  2992. PROGLOG("WUQueryGetSummaryStats: target %s", target);
  2993. const SocketEndpointArray &eps = info->getRoxieServers();
  2994. if (eps.empty())
  2995. {
  2996. IERRLOG("WUQueryGetSummaryStats: Failed to getRoxieServers for %s", target);
  2997. return true;
  2998. }
  2999. bool includeRawStats = req.getIncludeRawStats();
  3000. const char *fromTime = req.getFromTime();
  3001. const char *toTime = req.getToTime();
  3002. VStringBuffer control("<control:queryAggregates");
  3003. if (!isEmpty(fromTime))
  3004. control.appendf(" from='%s'", fromTime);
  3005. if (!isEmpty(toTime))
  3006. control.appendf(" to='%s'", toTime);
  3007. if (includeRawStats)
  3008. {
  3009. if (!isEmptyString(queryId))
  3010. control.appendf(" rawStats='1'><Query id='%s'/></control:queryAggregates>", queryId);
  3011. else
  3012. control.append(" all='1' rawStats='1' />");
  3013. }
  3014. else if (!isEmptyString(queryId))
  3015. {
  3016. control.appendf("><Query id='%s'/></control:queryAggregates>", queryId);
  3017. }
  3018. else
  3019. control.append(" />");
  3020. Owned<IPropertyTree> queryAggregates = sendRoxieControlAllNodes(eps.item(0), control.str(), false, ROXIELOCKCONNECTIONTIMEOUT);
  3021. if (!queryAggregates)
  3022. {
  3023. PROGLOG("WUQueryGetSummaryStats: %s returns empty for %s", control.str(), target);
  3024. return true;
  3025. }
  3026. if (getEspLogLevel() >= LogMax)
  3027. {
  3028. StringBuffer sb;
  3029. toXML(queryAggregates, sb);
  3030. DBGLOG("getQueryStats(): '%s' => '%s'", control.str(), sb.str());
  3031. }
  3032. IArrayOf<IEspQuerySummaryStats> querySummaryStatsList;
  3033. IArrayOf<IEspEndpointQueryStats> queryStatsList;
  3034. Owned<IPropertyTreeIterator> queryStatsOnEndpointItr = queryAggregates->getElements("Endpoint");
  3035. ForEach(*queryStatsOnEndpointItr)
  3036. {
  3037. IPropertyTree &queryStatsOnEndpoint = queryStatsOnEndpointItr->query();
  3038. const char *status = queryStatsOnEndpoint.queryProp("Status");
  3039. const char *ep = queryStatsOnEndpoint.queryProp("@ep");
  3040. if (isEmptyString(ep))
  3041. continue;
  3042. if (version >= 1.75)
  3043. {
  3044. if (includeRawStats)
  3045. readQueryStatsList(&queryStatsOnEndpoint, status, ep, includeRawStats, queryStatsList);
  3046. else
  3047. readQueryAggregateStats(queryStatsOnEndpoint.queryPropTree("Query"), status, ep, querySummaryStatsList);
  3048. }
  3049. else if (!isEmptyString(queryId))
  3050. readQueryAggregateStats(queryStatsOnEndpoint.queryPropTree("Query"), status, ep, querySummaryStatsList);
  3051. }
  3052. resp.setStatsList(querySummaryStatsList);
  3053. resp.setQueryStatsList(queryStatsList);
  3054. }
  3055. catch(IException* e)
  3056. {
  3057. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  3058. }
  3059. return true;
  3060. }
  3061. void CWsWorkunitsEx::readQueryAggregateStats(IPropertyTree *queryStats, const char *status, const char *ep,
  3062. IArrayOf<IEspQuerySummaryStats> &querySummaryStatsList)
  3063. {
  3064. if (!queryStats)
  3065. return;
  3066. Owned<IEspQuerySummaryStats> querySummaryStats = createQuerySummaryStats();
  3067. if (!isEmptyString(ep))
  3068. querySummaryStats->setEndpoint(ep);
  3069. if (queryStats->hasProp("countFailed"))
  3070. querySummaryStats->setCountFailed(queryStats->getPropInt("countFailed"));
  3071. if (queryStats->hasProp("countTotal"))
  3072. querySummaryStats->setCountTotal(queryStats->getPropInt("countTotal"));
  3073. if (queryStats->hasProp("averageBytesOut"))
  3074. querySummaryStats->setAverageBytesOut(queryStats->getPropInt64("averageBytesOut"));
  3075. if (queryStats->hasProp("averageMemUsed"))
  3076. querySummaryStats->setSizeAvgPeakMemory(queryStats->getPropInt64("averageMemUsed"));
  3077. if (queryStats->hasProp("averageSlavesReplyLen"))
  3078. querySummaryStats->setAverageSlavesReplyLen(queryStats->getPropInt("averageSlavesReplyLen"));
  3079. if (queryStats->hasProp("averageTimeMs"))
  3080. querySummaryStats->setTimeAvgTotalExecuteMinutes(queryStats->getPropInt64("averageTimeMs"));
  3081. if (queryStats->hasProp("minTimeMs"))
  3082. querySummaryStats->setTimeMinTotalExecuteMinutes(queryStats->getPropInt64("minTimeMs"));
  3083. if (queryStats->hasProp("maxTimeMs"))
  3084. querySummaryStats->setTimeMaxTotalExecuteMinutes(queryStats->getPropInt64("maxTimeMs"));
  3085. if (queryStats->hasProp("percentile97"))
  3086. {
  3087. querySummaryStats->setPercentile97(queryStats->getPropInt("percentile97"));
  3088. if (queryStats->hasProp("percentile97/@estimate"))
  3089. querySummaryStats->setPercentile97Estimate(queryStats->getPropBool("percentile97/@estimate"));
  3090. }
  3091. const char *startTime = queryStats->queryProp("startTime");
  3092. const char *endTime = queryStats->queryProp("endTime");
  3093. if (!isEmptyString(startTime))
  3094. querySummaryStats->setStartTime(startTime);
  3095. if (!isEmptyString(endTime))
  3096. querySummaryStats->setEndTime(endTime);
  3097. if (!isEmptyString(status))
  3098. querySummaryStats->setStatus(status);
  3099. querySummaryStatsList.append(*querySummaryStats.getLink());
  3100. }
  3101. void CWsWorkunitsEx::readQueryStatsList(IPropertyTree *queryStatsTree, const char *status, const char *ep,
  3102. bool includeRawStats, IArrayOf<IEspEndpointQueryStats> &endpointQueryStatsList)
  3103. {
  3104. if (!queryStatsTree)
  3105. return;
  3106. IArrayOf<IEspQueryStats> queryStatsList;
  3107. Owned<IPropertyTreeIterator> queryItr = queryStatsTree->getElements("QueryStats/Query");
  3108. ForEach(*queryItr)
  3109. {
  3110. IPropertyTree &query = queryItr->query();
  3111. readQueryStats(&query, query.queryProp("@id"), includeRawStats, queryStatsList);
  3112. }
  3113. IPropertyTree *globalStats = queryStatsTree->queryPropTree("QueryStats/Global");
  3114. if (globalStats)
  3115. readQueryStats(globalStats, "Global", includeRawStats, queryStatsList);
  3116. if (queryStatsList.ordinality() == 0)
  3117. return;
  3118. Owned<IEspEndpointQueryStats> endpointQueryStats = createEndpointQueryStats();
  3119. endpointQueryStats->setEndpoint(ep);
  3120. if (!isEmptyString(status))
  3121. endpointQueryStats->setStatus(status);
  3122. endpointQueryStats->setQueryStatsList(queryStatsList);
  3123. endpointQueryStatsList.append(*endpointQueryStats.getLink());
  3124. }
  3125. void CWsWorkunitsEx::readQueryStats(IPropertyTree *queryStatsTree, const char *id, bool includeRawStats,
  3126. IArrayOf<IEspQueryStats> &queryStatsList)
  3127. {
  3128. if (!queryStatsTree)
  3129. return;
  3130. Owned<IEspQueryStats> queryStats = createQueryStats();
  3131. if (!isEmptyString(id))
  3132. queryStats->setID(id);
  3133. if (!includeRawStats)
  3134. {
  3135. IArrayOf<IEspQuerySummaryStats> aggregateQueryStatsList;
  3136. readQueryAggregateStats(queryStatsTree, nullptr, nullptr, aggregateQueryStatsList);
  3137. queryStats->setAggregateQueryStatsList(aggregateQueryStatsList);
  3138. queryStatsList.append(*queryStats.getLink());
  3139. return;
  3140. }
  3141. IArrayOf<IEspQuerySummaryStats> aggregateQueryStatsList;
  3142. Owned<IPropertyTreeIterator> aggregateRecordItr = queryStatsTree->getElements("QueryStatsAggregateRecord");
  3143. ForEach(*aggregateRecordItr)
  3144. {
  3145. IPropertyTree &query = aggregateRecordItr->query();
  3146. readQueryAggregateStats(&query, nullptr, nullptr, aggregateQueryStatsList);
  3147. }
  3148. queryStats->setAggregateQueryStatsList(aggregateQueryStatsList);
  3149. IArrayOf<IEspQueryStatsRecord> recordList;
  3150. Owned<IPropertyTreeIterator> recordItr = queryStatsTree->getElements("QueryStatsRecord");
  3151. ForEach(*recordItr)
  3152. {
  3153. IPropertyTree &query = recordItr->query();
  3154. readQueryStatsRecord(&query, recordList);
  3155. }
  3156. queryStats->setQueryStatsRecordList(recordList);
  3157. queryStatsList.append(*queryStats.getLink());
  3158. }
  3159. void CWsWorkunitsEx::readQueryStatsRecord(IPropertyTree *queryRecord, IArrayOf<IEspQueryStatsRecord> &recordList)
  3160. {
  3161. if (!queryRecord)
  3162. return;
  3163. Owned<IEspQueryStatsRecord> record = createQueryStatsRecord();
  3164. const char *startTime = queryRecord->queryProp("@startTime");
  3165. if (!isEmptyString(startTime))
  3166. record->setStartTime(startTime);
  3167. if (queryRecord->hasProp("elapsedTimeMs"))
  3168. record->setElapsedTimeMs(queryRecord->getPropInt64("elapsedTimeMs"));
  3169. if (queryRecord->hasProp("memUsed"))
  3170. record->setMemoryUsed(queryRecord->getPropInt64("memUsed"));
  3171. if (queryRecord->hasProp("bytesOut"))
  3172. record->setBytesOut(queryRecord->getPropInt64("bytesOut"));
  3173. if (queryRecord->hasProp("slavesReplyLen"))
  3174. record->setSlavesReplyLen(queryRecord->getPropInt("slavesReplyLen"));
  3175. recordList.append(*record.getLink());
  3176. }