ws_workunitsQuerySets.cpp 76 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958
  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 "daclient.hpp"
  17. #include "dalienv.hpp"
  18. #include "dadfs.hpp"
  19. #include "dfuwu.hpp"
  20. #include "eclhelper.hpp"
  21. #include "roxiecontrol.hpp"
  22. #include "dfuutil.hpp"
  23. #include "dautils.hpp"
  24. #include "referencedfilelist.hpp"
  25. #define DALI_FILE_LOOKUP_TIMEOUT (1000*15*1) // 15 seconds
  26. const unsigned ROXIECONNECTIONTIMEOUT = 1000; //1 second
  27. const unsigned ROXIECONTROLQUERYTIMEOUT = 3000; //3 second
  28. const unsigned ROXIELOCKCONNECTIONTIMEOUT = 60000; //60 second
  29. #define SDS_LOCK_TIMEOUT (5*60*1000) // 5mins, 30s a bit short
  30. bool isRoxieProcess(const char *process)
  31. {
  32. if (!process)
  33. return false;
  34. Owned<IRemoteConnection> conn = querySDS().connect("Environment", myProcessSession(), RTM_LOCK_READ, SDS_LOCK_TIMEOUT);
  35. if (!conn)
  36. return false;
  37. VStringBuffer xpath("Software/RoxieCluster[@name=\"%s\"]", process);
  38. return conn->queryRoot()->hasProp(xpath.str());
  39. }
  40. void checkUseEspOrDaliIP(SocketEndpoint &ep, const char *ip, const char *esp)
  41. {
  42. if (!ip || !*ip)
  43. return;
  44. ep.set(ip, 7070);
  45. if (ep.isLoopBack() || *ip=='.' || (ip[0]=='0' && ip[1]=='.'))
  46. ep.ipset(esp);
  47. }
  48. IClientWUQuerySetDetailsResponse *fetchQueryDetails(IEspContext &context, IClientWsWorkunits *_ws, const char *target, const char *queryid)
  49. {
  50. Linked<IClientWsWorkunits> ws = _ws;
  51. if (!ws)
  52. {
  53. StringBuffer host;
  54. short port=0;
  55. context.getServAddress(host, port);
  56. VStringBuffer url("http://%s:%d/WsWorkunits", host.str(), port);
  57. ws.setown(createWsWorkunitsClient());
  58. ws->addServiceUrl(url.str());
  59. }
  60. //using existing WUQuerysetDetails rather than extending WUQueryDetails, to support copying query meta data from prior releases
  61. Owned<IClientWUQuerySetDetailsRequest> reqQueryInfo = ws->createWUQuerysetDetailsRequest();
  62. reqQueryInfo->setClusterName(target);
  63. reqQueryInfo->setQuerySetName(target);
  64. reqQueryInfo->setFilter(queryid);
  65. reqQueryInfo->setFilterType("Id");
  66. return ws->WUQuerysetDetails(reqQueryInfo);
  67. }
  68. void fetchRemoteWorkunit(IEspContext &context, 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)
  69. {
  70. Owned<IClientWsWorkunits> ws;
  71. ws.setown(createWsWorkunitsClient());
  72. VStringBuffer url("http://%s%s/WsWorkunits", netAddress, (!strchr(netAddress, ':')) ? ":8010" : "");
  73. ws->addServiceUrl(url.str());
  74. if (context.queryUserId() && *context.queryUserId())
  75. ws->setUsernameToken(context.queryUserId(), context.queryPassword(), NULL);
  76. Owned<IClientWULogFileRequest> req = ws->createWUFileRequest();
  77. if (queryset && *queryset)
  78. req->setQuerySet(queryset);
  79. if (query && *query)
  80. req->setQuery(query);
  81. if (wuid && *wuid)
  82. req->setWuid(wuid);
  83. req->setType("xml");
  84. Owned<IClientWULogFileResponse> resp = ws->WUFile(req);
  85. if (!resp || resp->getExceptions().ordinality() || !resp->getThefile().length())
  86. throw MakeStringException(ECLWATCH_CANNOT_GET_WORKUNIT, "Cannot retrieve remote workunit");
  87. xml.append(resp->getThefile().length(), resp->getThefile().toByteArray());
  88. req->setType("dll");
  89. resp.setown(ws->WUFile(req));
  90. if (!resp || resp->getExceptions().ordinality() || !resp->getThefile().length())
  91. throw MakeStringException(ECLWATCH_CANNOT_GET_WORKUNIT, "Cannot retrieve remote workunit shared object");
  92. dll.append(resp->getThefile());
  93. dllname.append(resp->getFileName());
  94. name.append(resp->getQueryName());
  95. SocketEndpoint ep;
  96. checkUseEspOrDaliIP(ep, resp->getDaliServer(), netAddress);
  97. if (!ep.isNull())
  98. ep.getUrlStr(daliServer);
  99. respQueryInfo.setown(fetchQueryDetails(context, ws, queryset, query));
  100. }
  101. void doWuFileCopy(IClientFileSpray &fs, IEspWULogicalFileCopyInfo &info, const char *logicalname, const char *cluster, bool isRoxie, bool supercopy)
  102. {
  103. try
  104. {
  105. Owned<IClientCopy> req = fs.createCopyRequest();
  106. req->setSourceLogicalName(logicalname);
  107. req->setDestLogicalName(logicalname);
  108. req->setDestGroup(cluster);
  109. req->setSuperCopy(supercopy);
  110. if (isRoxie)
  111. req->setDestGroupRoxie("Yes");
  112. Owned<IClientCopyResponse> resp = fs.Copy(req);
  113. info.setDfuCopyWuid(resp->getResult());
  114. }
  115. catch (IException *e)
  116. {
  117. StringBuffer msg;
  118. info.setDfuCopyError(e->errorMessage(msg).str());
  119. e->Release();
  120. }
  121. }
  122. bool copyWULogicalFiles(IEspContext &context, IConstWorkUnit &cw, const char *cluster, bool copyLocal, IEspWUCopyLogicalClusterFileSections &lfinfo)
  123. {
  124. if (isEmpty(cluster))
  125. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "copyWULogicalFiles Cluster parameter not set.");
  126. Owned<IUserDescriptor> udesc = createUserDescriptor();
  127. udesc->set(context.queryUserId(), context.queryPassword());
  128. IArrayOf<IEspWULogicalFileCopyInfo> foreign;
  129. IArrayOf<IEspWULogicalFileCopyInfo> onCluster;
  130. IArrayOf<IEspWULogicalFileCopyInfo> notOnCluster;
  131. IArrayOf<IEspWULogicalFileCopyInfo> notFound;
  132. Owned<IClientFileSpray> fs;
  133. if (copyLocal)
  134. {
  135. fs.setown(createFileSprayClient());
  136. VStringBuffer url("http://.:%d/FileSpray", 8010);
  137. fs->addServiceUrl(url.str());
  138. }
  139. bool isRoxie = isRoxieProcess(cluster);
  140. Owned<IConstWUGraphIterator> graphs = &cw.getGraphs(GraphTypeActivities);
  141. ForEach(*graphs)
  142. {
  143. Owned <IPropertyTree> xgmml = graphs->query().getXGMMLTree(false);
  144. Owned<IPropertyTreeIterator> iter = xgmml->getElements(".//node");
  145. ForEach(*iter)
  146. {
  147. try
  148. {
  149. IPropertyTree &node = iter->query();
  150. ThorActivityKind kind = (ThorActivityKind) node.getPropInt("att[@name='_kind']/@value", TAKnone);
  151. if(kind==TAKdiskwrite || kind==TAKindexwrite || kind==TAKcsvwrite || kind==TAKxmlwrite)
  152. continue;
  153. if (node.getPropBool("att[@name='_isSpill']/@value") || node.getPropBool("att[@name='_isTransformSpill']/@value"))
  154. continue;
  155. Owned<IEspWULogicalFileCopyInfo> info = createWULogicalFileCopyInfo();
  156. const char *logicalname = node.queryProp("att[@name='_indexFileName']/@value");
  157. if (logicalname)
  158. info->setIsIndex(true);
  159. else
  160. logicalname = node.queryProp("att[@name='_fileName']/@value");
  161. info->setLogicalName(logicalname);
  162. if (logicalname)
  163. {
  164. if (!strnicmp("~foreign::", logicalname, 10))
  165. foreign.append(*info.getClear());
  166. else
  167. {
  168. Owned<IDistributedFile> df = queryDistributedFileDirectory().lookup(logicalname, udesc);
  169. if(!df)
  170. notFound.append(*info.getClear());
  171. else if (df->findCluster(cluster)!=NotFound)
  172. {
  173. onCluster.append(*info.getClear());
  174. }
  175. else
  176. {
  177. StringArray clusters;
  178. df->getClusterNames(clusters);
  179. info->setClusters(clusters);
  180. if (copyLocal)
  181. {
  182. StringBuffer wuid;
  183. bool supercopy = queryDistributedFileDirectory().isSuperFile(logicalname, udesc, NULL);
  184. doWuFileCopy(*fs, *info, logicalname, cluster, isRoxie, supercopy);
  185. }
  186. notOnCluster.append(*info.getClear());
  187. }
  188. }
  189. }
  190. }
  191. catch(IException *e)
  192. {
  193. e->Release();
  194. }
  195. }
  196. lfinfo.setClusterName(cluster);
  197. lfinfo.setNotOnCluster(notOnCluster);
  198. lfinfo.setOnCluster(onCluster);
  199. lfinfo.setForeign(foreign);
  200. lfinfo.setNotFound(notFound);
  201. }
  202. return true;
  203. }
  204. void copyWULogicalFilesToTarget(IEspContext &context, IConstWUClusterInfo &clusterInfo, IConstWorkUnit &cw, IArrayOf<IConstWUCopyLogicalClusterFileSections> &clusterfiles, bool doLocalCopy)
  205. {
  206. const StringArray &thors = clusterInfo.getThorProcesses();
  207. ForEachItemIn(i, thors)
  208. {
  209. Owned<IEspWUCopyLogicalClusterFileSections> files = createWUCopyLogicalClusterFileSections();
  210. copyWULogicalFiles(context, cw, thors.item(i), doLocalCopy, *files);
  211. clusterfiles.append(*files.getClear());
  212. }
  213. SCMStringBuffer roxie;
  214. clusterInfo.getRoxieProcess(roxie);
  215. if (roxie.length())
  216. {
  217. Owned<IEspWUCopyLogicalClusterFileSections> files = createWUCopyLogicalClusterFileSections();
  218. copyWULogicalFiles(context, cw, roxie.str(), doLocalCopy, *files);
  219. clusterfiles.append(*files.getClear());
  220. }
  221. }
  222. void QueryFilesInUse::loadTarget(IPropertyTree *t, const char *target, unsigned flags)
  223. {
  224. if (!target || !*target)
  225. return;
  226. Owned<IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(target);
  227. if (!clusterInfo || !(clusterInfo->getPlatform() == RoxieCluster))
  228. return;
  229. Owned<IPropertyTree> queryRegistry = getQueryRegistry(target, true);
  230. if (!queryRegistry)
  231. return;
  232. SCMStringBuffer process;
  233. clusterInfo->getRoxieProcess(process);
  234. if (!process.length())
  235. return;
  236. Owned<IHpccPackageSet> ps = createPackageSet(process.str());
  237. const IHpccPackageMap *pm = (ps) ? ps->queryActiveMap(target) : NULL;
  238. const char *pmid = (pm) ? pm->queryPackageId() : NULL;
  239. VStringBuffer xpath("%s/@pmid", target);
  240. const char *pmidPrev = t->queryProp(xpath);
  241. if ((flags & UFO_RELOAD_TARGETS_CHANGED_PMID) && (pmid || pmidPrev))
  242. {
  243. if (!(pmid && pmidPrev) || !streq(pmid, pmidPrev))
  244. t->removeProp(target);
  245. }
  246. IPropertyTree *targetTree = ensurePTree(t, target);
  247. if (pm)
  248. targetTree->setProp("@pmid", pmid);
  249. if (flags & UFO_REMOVE_QUERIES_NOT_IN_QUERYSET)
  250. {
  251. Owned<IPropertyTreeIterator> cachedQueries = targetTree->getElements("Query");
  252. ForEach(*cachedQueries)
  253. {
  254. IPropertyTree &cachedQuery = cachedQueries->query();
  255. VStringBuffer xpath("Query[@id='%s']", cachedQuery.queryProp("@id"));
  256. if (!queryRegistry->hasProp(xpath))
  257. targetTree->removeTree(&cachedQuery);
  258. }
  259. }
  260. Owned<IPropertyTreeIterator> queries = queryRegistry->getElements("Query");
  261. ForEach(*queries)
  262. {
  263. if (aborting)
  264. return;
  265. IPropertyTree &query = queries->query();
  266. const char *queryid = query.queryProp("@id");
  267. if (!queryid || !*queryid)
  268. continue;
  269. const char *wuid = query.queryProp("@wuid");
  270. if (!wuid || !*wuid)
  271. continue;
  272. const char *pkgid=NULL;
  273. if (pm)
  274. {
  275. const IHpccPackage *pkg = pm->matchPackage(queryid);
  276. if (pkg)
  277. pkgid = pkg->queryId();
  278. }
  279. VStringBuffer xpath("Query[@id='%s']", queryid);
  280. IPropertyTree *queryTree = targetTree->queryPropTree(xpath);
  281. if (queryTree)
  282. {
  283. const char *cachedPkgid = queryTree->queryProp("@pkgid");
  284. if (pkgid && *pkgid)
  285. {
  286. if (!(flags & UFO_RELOAD_MAPPED_QUERIES) && (cachedPkgid && streq(pkgid, cachedPkgid)))
  287. continue;
  288. }
  289. else if (!cachedPkgid || !*cachedPkgid)
  290. continue;
  291. targetTree->removeTree(queryTree);
  292. queryTree = NULL;
  293. }
  294. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  295. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid, false);
  296. if (!cw)
  297. continue;
  298. queryTree = targetTree->addPropTree("Query", createPTree("Query"));
  299. queryTree->setProp("@id", queryid);
  300. if (pkgid && *pkgid)
  301. queryTree->setProp("@pkgid", pkgid);
  302. IUserDescriptor **roxieUser = roxieUserMap.getValue(target);
  303. Owned<IReferencedFileList> wufiles = createReferencedFileList(roxieUser ? *roxieUser : NULL, true);
  304. wufiles->addFilesFromQuery(cw, pm, queryid);
  305. if (aborting)
  306. return;
  307. wufiles->resolveFiles(process.str(), NULL, NULL, NULL, true, true, false);
  308. Owned<IReferencedFileIterator> files = wufiles->getFiles();
  309. ForEach(*files)
  310. {
  311. if (aborting)
  312. return;
  313. IReferencedFile &rf = files->query();
  314. //if (!(rf.getFlags() & RefSubFile))
  315. // continue;
  316. const char *lfn = rf.getLogicalName();
  317. if (!lfn || !*lfn)
  318. continue;
  319. if (!queryTree->hasProp(xpath.setf("File[@lfn='%s']", lfn)))
  320. {
  321. IPropertyTree *fileTree = queryTree->addPropTree("File", createPTree("File"));
  322. fileTree->setProp("@lfn", lfn);
  323. if (rf.getFlags() & RefFileSuper)
  324. fileTree->setPropBool("@super", true);
  325. const char *fpkgid = rf.queryPackageId();
  326. if (fpkgid && *fpkgid)
  327. fileTree->setProp("@pkgid", fpkgid);
  328. }
  329. }
  330. }
  331. }
  332. void QueryFilesInUse::loadTargets(IPropertyTree *t, unsigned flags)
  333. {
  334. Owned<IStringIterator> targets = getTargetClusters("RoxieCluster", NULL);
  335. SCMStringBuffer s;
  336. ForEach(*targets)
  337. {
  338. if (aborting)
  339. return;
  340. loadTarget(t, targets->str(s).str(), flags);
  341. }
  342. }
  343. IPropertyTreeIterator *QueryFilesInUse::findQueriesUsingFile(const char *target, const char *lfn)
  344. {
  345. CriticalBlock b(crit);
  346. if (!target || !*target || !lfn || !*lfn)
  347. return NULL;
  348. IPropertyTree *targetTree = tree->getPropTree(target);
  349. if (!targetTree)
  350. return NULL;
  351. VStringBuffer xpath("Query[File/@lfn='%s']", lfn);
  352. return targetTree->getElements(xpath);
  353. }
  354. bool CWsWorkunitsEx::onWUCopyLogicalFiles(IEspContext &context, IEspWUCopyLogicalFilesRequest &req, IEspWUCopyLogicalFilesResponse &resp)
  355. {
  356. StringBuffer wuid = req.getWuid();
  357. WsWuHelpers::checkAndTrimWorkunit("WUCopyLogicalFiles", wuid);
  358. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  359. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str(), false);
  360. if (!cw)
  361. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot open workunit %s", wuid.str());
  362. resp.setWuid(wuid.str());
  363. SCMStringBuffer cluster;
  364. if (notEmpty(req.getCluster()))
  365. cluster.set(req.getCluster());
  366. else
  367. cw->getClusterName(cluster);
  368. if (!isValidCluster(req.getCluster()))
  369. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid cluster name: %s", cluster.str());
  370. Owned <IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(cluster.str());
  371. IArrayOf<IConstWUCopyLogicalClusterFileSections> clusterfiles;
  372. copyWULogicalFilesToTarget(context, *clusterInfo, *cw, clusterfiles, req.getCopyLocal());
  373. resp.setClusterFiles(clusterfiles);
  374. return true;
  375. }
  376. static inline unsigned remainingMsWait(unsigned wait, unsigned start)
  377. {
  378. if (wait==0 || wait==(unsigned)-1)
  379. return wait;
  380. unsigned waited = msTick()-start;
  381. return (wait>waited) ? wait-waited : 0;
  382. }
  383. bool reloadCluster(IConstWUClusterInfo *clusterInfo, unsigned wait)
  384. {
  385. if (0==wait || !clusterInfo || clusterInfo->getPlatform()!=RoxieCluster)
  386. return true;
  387. const SocketEndpointArray &addrs = clusterInfo->getRoxieServers();
  388. if (addrs.length())
  389. {
  390. try
  391. {
  392. Owned<IPropertyTree> result = sendRoxieControlAllNodes(addrs.item(0), "<control:reload/>", false, wait);
  393. const char *status = result->queryProp("Endpoint[1]/Status");
  394. if (!status || !strieq(status, "ok"))
  395. return false;
  396. }
  397. catch(IMultiException *me)
  398. {
  399. StringBuffer err;
  400. DBGLOG("ERROR control:reloading roxie query info %s", me->errorMessage(err.append(me->errorCode()).append(' ')).str());
  401. me->Release();
  402. return false;
  403. }
  404. catch(IException *e)
  405. {
  406. StringBuffer err;
  407. DBGLOG("ERROR control:reloading roxie query info %s", e->errorMessage(err.append(e->errorCode()).append(' ')).str());
  408. e->Release();
  409. return false;
  410. }
  411. }
  412. return true;
  413. }
  414. bool reloadCluster(const char *cluster, unsigned wait)
  415. {
  416. Owned <IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(cluster);
  417. return (clusterInfo) ? reloadCluster(clusterInfo, wait) : true;
  418. }
  419. static inline void updateQuerySetting(bool ignore, IPropertyTree *queryTree, const char *xpath, int value)
  420. {
  421. if (ignore || !queryTree)
  422. return;
  423. if (value!=0)
  424. queryTree->setPropInt(xpath, value);
  425. else
  426. queryTree->removeProp(xpath);
  427. }
  428. static inline void updateTimeLimitSetting(IPropertyTree *queryTree, bool valueNotSet, int value, IConstQuerySetQuery *srcInfo=NULL)
  429. {
  430. if (valueNotSet && srcInfo && !srcInfo->getTimeLimit_isNull())
  431. {
  432. value = srcInfo->getTimeLimit();
  433. valueNotSet=false;
  434. }
  435. updateQuerySetting(valueNotSet, queryTree, "@timeLimit", value);
  436. }
  437. static inline void updateWarnTimeLimitSetting(IPropertyTree *queryTree, bool valueNotSet, int value, IConstQuerySetQuery *srcInfo=NULL)
  438. {
  439. if (valueNotSet && srcInfo && !srcInfo->getWarnTimeLimit_isNull())
  440. {
  441. value = srcInfo->getWarnTimeLimit();
  442. valueNotSet=false;
  443. }
  444. updateQuerySetting(valueNotSet, queryTree, "@warnTimeLimit", value);
  445. }
  446. static inline unsigned __int64 memoryLimitUInt64FromString(const char *value)
  447. {
  448. if (!value || !*value || !isdigit(*value))
  449. return 0;
  450. unsigned __int64 result = (*value - '0');
  451. const char *s = value+1;
  452. while (isdigit(*s))
  453. {
  454. result = 10 * result + ((*s) - '0');
  455. s++;
  456. }
  457. if (*s)
  458. {
  459. const char unit = toupper(*s++);
  460. if (*s && !strieq("B", s)) //more?
  461. return 0;
  462. switch (unit)
  463. {
  464. case 'E':
  465. result <<=60;
  466. break;
  467. case 'P':
  468. result <<=50;
  469. break;
  470. case 'T':
  471. result <<=40;
  472. break;
  473. case 'G':
  474. result <<=30;
  475. break;
  476. case 'M':
  477. result <<=20;
  478. break;
  479. case 'K':
  480. result <<=10;
  481. break;
  482. case 'B':
  483. break;
  484. default:
  485. return 0;
  486. }
  487. }
  488. return result;
  489. }
  490. const char memUnitAbbrev[] = {'B', 'K', 'M', 'G', 'T', 'P', 'E'};
  491. #define MAX_MEMUNIT_ABBREV 6
  492. static inline StringBuffer &memoryLimitStringFromUInt64(StringBuffer &s, unsigned __int64 in)
  493. {
  494. if (!in)
  495. return s;
  496. unsigned __int64 value = in;
  497. unsigned char unit = 0;
  498. while (!(value & 0x3FF) && unit < MAX_MEMUNIT_ABBREV)
  499. {
  500. value >>= 10;
  501. unit++;
  502. }
  503. return s.append(value).append(memUnitAbbrev[unit]);
  504. }
  505. static inline void updateMemoryLimitSetting(IPropertyTree *queryTree, const char *value, IConstQuerySetQuery *srcInfo=NULL)
  506. {
  507. if (!queryTree)
  508. return;
  509. if (!value && srcInfo)
  510. value = srcInfo->getMemoryLimit();
  511. if (!value)
  512. return;
  513. unsigned __int64 limit = memoryLimitUInt64FromString(value);
  514. if (0==limit)
  515. queryTree->removeProp("@memoryLimit");
  516. else
  517. queryTree->setPropInt64("@memoryLimit", limit);
  518. }
  519. enum QueryPriority {
  520. QueryPriorityNone = -1,
  521. QueryPriorityLow = 0,
  522. QueryPriorityHigh = 1,
  523. QueryPrioritySLA = 2,
  524. QueryPriorityInvalid = 3
  525. };
  526. static inline const char *getQueryPriorityName(int value)
  527. {
  528. switch (value)
  529. {
  530. case QueryPriorityLow:
  531. return "LOW";
  532. case QueryPriorityHigh:
  533. return "HIGH";
  534. case QueryPrioritySLA:
  535. return "SLA";
  536. case QueryPriorityNone:
  537. return "NONE";
  538. }
  539. return "INVALID";
  540. }
  541. static inline void updateQueryPriority(IPropertyTree *queryTree, const char *value, IConstQuerySetQuery *srcInfo=NULL)
  542. {
  543. if (!queryTree)
  544. return;
  545. if ((!value || !*value) && srcInfo)
  546. value = srcInfo->getPriority();
  547. if (!value || !*value)
  548. return;
  549. int priority = QueryPriorityInvalid;
  550. if (strieq("LOW", value))
  551. priority=QueryPriorityLow;
  552. else if (strieq("HIGH", value))
  553. priority=QueryPriorityHigh;
  554. else if (strieq("SLA", value))
  555. priority=QueryPrioritySLA;
  556. else if (strieq("NONE", value))
  557. priority=QueryPriorityNone;
  558. switch (priority)
  559. {
  560. case QueryPriorityInvalid:
  561. break;
  562. case QueryPriorityNone:
  563. queryTree->removeProp("@priority");
  564. break;
  565. default:
  566. queryTree->setPropInt("@priority", priority);
  567. break;
  568. }
  569. }
  570. void copyQueryFilesToCluster(IEspContext &context, IConstWorkUnit *cw, const char *remoteIP, const char *remotePrefix, const char *target, const char *srcCluster, const char *queryname, bool overwrite, bool allowForeignFiles)
  571. {
  572. if (!target || !*target)
  573. return;
  574. SCMStringBuffer process;
  575. Owned <IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(target);
  576. if (clusterInfo && clusterInfo->getPlatform()==RoxieCluster)
  577. {
  578. clusterInfo->getRoxieProcess(process);
  579. if (!process.length())
  580. return;
  581. Owned<IReferencedFileList> wufiles = createReferencedFileList(context.queryUserId(), context.queryPassword(), allowForeignFiles);
  582. Owned<IHpccPackageSet> ps = createPackageSet(process.str());
  583. StringBuffer queryid;
  584. if (queryname && *queryname)
  585. queryname = queryid.append(queryname).append(".0").str(); //prepublish dummy version number to support fuzzy match like queries="myquery.*" in package
  586. wufiles->addFilesFromQuery(cw, (ps) ? ps->queryActiveMap(target) : NULL, queryname);
  587. wufiles->resolveFiles(process.str(), remoteIP, remotePrefix, srcCluster, !overwrite, true);
  588. Owned<IDFUhelper> helper = createIDFUhelper();
  589. wufiles->cloneAllInfo(helper, overwrite, true);
  590. }
  591. }
  592. bool CWsWorkunitsEx::isQuerySuspended(const char* query, IConstWUClusterInfo *clusterInfo, unsigned wait, StringBuffer& errorMessage)
  593. {
  594. try
  595. {
  596. if (0==wait || !clusterInfo || clusterInfo->getPlatform()!=RoxieCluster)
  597. return false;
  598. const SocketEndpointArray &addrs = clusterInfo->getRoxieServers();
  599. if (addrs.length() < 1)
  600. return false;
  601. StringBuffer control;
  602. control.appendf("<control:queries><Query id='%s'/></control:queries>", query);
  603. Owned<IPropertyTree> result = sendRoxieControlAllNodes(addrs.item(0), control.str(), false, wait);
  604. if (!result)
  605. return false;
  606. Owned<IPropertyTreeIterator> suspendedQueries = result->getElements("Endpoint/Queries/Query[@suspended='1']");
  607. if (!suspendedQueries->first())
  608. return false;
  609. errorMessage.set(suspendedQueries->query().queryProp("@error"));
  610. return true;
  611. }
  612. catch(IMultiException *me)
  613. {
  614. StringBuffer err;
  615. DBGLOG("ERROR control:queries roxie query info %s", me->errorMessage(err.append(me->errorCode()).append(' ')).str());
  616. me->Release();
  617. return false;
  618. }
  619. catch(IException *e)
  620. {
  621. StringBuffer err;
  622. DBGLOG("ERROR control:queries roxie query info %s", e->errorMessage(err.append(e->errorCode()).append(' ')).str());
  623. e->Release();
  624. return false;
  625. }
  626. }
  627. bool CWsWorkunitsEx::onWUPublishWorkunit(IEspContext &context, IEspWUPublishWorkunitRequest & req, IEspWUPublishWorkunitResponse & resp)
  628. {
  629. StringBuffer wuid = req.getWuid();
  630. WsWuHelpers::checkAndTrimWorkunit("WUPublishWorkunit", wuid);
  631. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  632. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str(), false);
  633. if (!cw)
  634. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot find the workunit %s", wuid.str());
  635. resp.setWuid(wuid.str());
  636. SCMStringBuffer queryName;
  637. if (notEmpty(req.getJobName()))
  638. queryName.set(req.getJobName());
  639. else
  640. cw->getJobName(queryName).str();
  641. if (!queryName.length())
  642. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Query/Job name not defined for publishing workunit %s", wuid.str());
  643. SCMStringBuffer target;
  644. if (notEmpty(req.getCluster()))
  645. target.set(req.getCluster());
  646. else
  647. cw->getClusterName(target);
  648. if (!target.length())
  649. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Cluster name not defined for publishing workunit %s", wuid.str());
  650. if (!isValidCluster(target.str()))
  651. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid cluster name: %s", target.str());
  652. StringBuffer daliIP;
  653. StringBuffer srcCluster;
  654. StringBuffer srcPrefix;
  655. splitDerivedDfsLocation(req.getRemoteDali(), srcCluster, daliIP, srcPrefix, req.getSourceProcess(),req.getSourceProcess(), NULL, NULL);
  656. if (srcCluster.length())
  657. {
  658. if (!isProcessCluster(daliIP, srcCluster))
  659. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Process cluster %s not found on %s DALI", srcCluster.str(), daliIP.length() ? daliIP.str() : "local");
  660. }
  661. if (!req.getDontCopyFiles())
  662. copyQueryFilesToCluster(context, cw, daliIP, srcPrefix, target.str(), srcCluster, queryName.str(), req.getUpdateDfs(), req.getAllowForeignFiles());
  663. WorkunitUpdate wu(&cw->lock());
  664. if (req.getUpdateWorkUnitName() && notEmpty(req.getJobName()))
  665. wu->setJobName(req.getJobName());
  666. StringBuffer queryId;
  667. WUQueryActivationOptions activate = (WUQueryActivationOptions)req.getActivate();
  668. addQueryToQuerySet(wu, target.str(), queryName.str(), NULL, activate, queryId, context.queryUserId());
  669. if (req.getMemoryLimit() || !req.getTimeLimit_isNull() || !req.getWarnTimeLimit_isNull() || req.getPriority() || req.getComment())
  670. {
  671. Owned<IPropertyTree> queryTree = getQueryById(target.str(), queryId, false);
  672. updateMemoryLimitSetting(queryTree, req.getMemoryLimit());
  673. updateQuerySetting(req.getTimeLimit_isNull(), queryTree, "@timeLimit", req.getTimeLimit());
  674. updateQuerySetting(req.getWarnTimeLimit_isNull(), queryTree, "@warnTimeLimit", req.getWarnTimeLimit());
  675. updateQueryPriority(queryTree, req.getPriority());
  676. if (req.getComment())
  677. queryTree->setProp("@comment", req.getComment());
  678. }
  679. wu->commit();
  680. wu.clear();
  681. if (queryId.length())
  682. resp.setQueryId(queryId.str());
  683. resp.setQueryName(queryName.str());
  684. resp.setQuerySet(target.str());
  685. Owned <IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(target.str());
  686. bool reloadFailed = false;
  687. if (0!=req.getWait() && !req.getNoReload())
  688. reloadFailed = !reloadCluster(clusterInfo, (unsigned)req.getWait());
  689. resp.setReloadFailed(reloadFailed);
  690. double version = context.getClientVersion();
  691. if (version > 1.38)
  692. {
  693. StringBuffer errorMessage;
  694. if (!reloadFailed && !req.getNoReload() && isQuerySuspended(queryName.str(), clusterInfo, (unsigned)req.getWait(), errorMessage))
  695. {
  696. resp.setSuspended(true);
  697. resp.setErrorMessage(errorMessage);
  698. }
  699. }
  700. return true;
  701. }
  702. bool CWsWorkunitsEx::onWUQuerysets(IEspContext &context, IEspWUQuerysetsRequest & req, IEspWUQuerysetsResponse & resp)
  703. {
  704. IArrayOf<IEspQuerySet> querySets;
  705. Owned<IStringIterator> targets = getTargetClusters(NULL, NULL);
  706. SCMStringBuffer target;
  707. ForEach(*targets)
  708. {
  709. Owned<IEspQuerySet> qs = createQuerySet();
  710. qs->setQuerySetName(targets->str(target).str());
  711. querySets.append(*qs.getClear());
  712. }
  713. resp.setQuerysets(querySets);
  714. return true;
  715. }
  716. void addClusterQueryStates(IPropertyTree* queriesOnCluster, const char *target, const char *id, IArrayOf<IEspClusterQueryState>& clusterStates, double version)
  717. {
  718. queriesOnCluster = queriesOnCluster->queryPropTree("Endpoint[1]/Queries[1]");
  719. if (!queriesOnCluster)
  720. return;
  721. int reporting = queriesOnCluster->getPropInt("@reporting");
  722. Owned<IEspClusterQueryState> clusterState = createClusterQueryState();
  723. clusterState->setCluster(target);
  724. VStringBuffer xpath("Query[@id='%s']", id);
  725. IPropertyTree *query = queriesOnCluster->getPropTree(xpath.str());
  726. int suspended = query->getPropInt("@suspended");
  727. const char* error = query->queryProp("@error");
  728. if (!query)
  729. clusterState->setState("Not Found");
  730. else if (suspended)
  731. {
  732. clusterState->setState("Suspended");
  733. if (suspended<reporting)
  734. clusterState->setMixedNodeStates(true);
  735. }
  736. else
  737. clusterState->setState("Available");
  738. if ((version >=1.46) && error && *error)
  739. clusterState->setErrors(error);
  740. clusterStates.append(*clusterState.getClear());
  741. }
  742. void gatherQuerySetQueryDetails(IEspContext &context, IPropertyTree *query, IEspQuerySetQuery *queryInfo, const char *cluster, IPropertyTree *queriesOnCluster)
  743. {
  744. queryInfo->setId(query->queryProp("@id"));
  745. queryInfo->setName(query->queryProp("@name"));
  746. queryInfo->setDll(query->queryProp("@dll"));
  747. queryInfo->setWuid(query->queryProp("@wuid"));
  748. queryInfo->setSuspended(query->getPropBool("@suspended", false));
  749. if (query->hasProp("@memoryLimit"))
  750. {
  751. StringBuffer s;
  752. memoryLimitStringFromUInt64(s, query->getPropInt64("@memoryLimit"));
  753. queryInfo->setMemoryLimit(s);
  754. }
  755. if (query->hasProp("@timeLimit"))
  756. queryInfo->setTimeLimit(query->getPropInt("@timeLimit"));
  757. if (query->hasProp("@warnTimeLimit"))
  758. queryInfo->setWarnTimeLimit(query->getPropInt("@warnTimeLimit"));
  759. if (query->hasProp("@priority"))
  760. queryInfo->setPriority(getQueryPriorityName(query->getPropInt("@priority")));
  761. if (query->hasProp("@comment"))
  762. queryInfo->setComment(query->queryProp("@comment"));
  763. if (query->hasProp("@snapshot"))
  764. queryInfo->setSnapshot(query->queryProp("@snapshot"));
  765. double version = context.getClientVersion();
  766. if (version >= 1.46)
  767. {
  768. queryInfo->setPublishedBy(query->queryProp("@publishedBy"));
  769. queryInfo->setIsLibrary(query->getPropBool("@isLibrary"));
  770. }
  771. if (queriesOnCluster)
  772. {
  773. IArrayOf<IEspClusterQueryState> clusters;
  774. addClusterQueryStates(queriesOnCluster, cluster, query->queryProp("@id"), clusters, version);
  775. queryInfo->setClusters(clusters);
  776. }
  777. }
  778. void gatherQuerySetAliasDetails(IPropertyTree *alias, IEspQuerySetAlias *aliasInfo)
  779. {
  780. aliasInfo->setName(alias->queryProp("@name"));
  781. aliasInfo->setId(alias->queryProp("@id"));
  782. }
  783. 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)
  784. {
  785. Owned<IPropertyTreeIterator> regQueries = registry->getElements("Query");
  786. ForEach(*regQueries)
  787. {
  788. IPropertyTree &query = regQueries->query();
  789. Owned<IEspQuerySetQuery> q = createQuerySetQuery();
  790. gatherQuerySetQueryDetails(context, &query, q, cluster, queriesOnCluster);
  791. if (isEmpty(cluster) || isEmpty(type) || isEmpty(value) || !strieq(type, "Status"))
  792. queries.append(*q.getClear());
  793. else
  794. {
  795. IArrayOf<IConstClusterQueryState>& cs = q->getClusters();
  796. ForEachItemIn(i, cs)
  797. {
  798. IConstClusterQueryState& c = cs.item(i);
  799. if (strieq(c.getCluster(), cluster) && (strieq(value, "All") || strieq(c.getState(), value)))
  800. {
  801. queries.append(*q.getClear());
  802. break;
  803. }
  804. }
  805. }
  806. }
  807. Owned<IPropertyTreeIterator> regAliases = registry->getElements("Alias");
  808. ForEach(*regAliases)
  809. {
  810. IPropertyTree &alias = regAliases->query();
  811. Owned<IEspQuerySetAlias> a = createQuerySetAlias();
  812. gatherQuerySetAliasDetails(&alias, a);
  813. aliases.append(*a.getClear());
  814. }
  815. }
  816. void retrieveQuerysetDetailsFromAlias(IEspContext &context, IPropertyTree *registry, const char *name, IArrayOf<IEspQuerySetQuery> &queries, IArrayOf<IEspQuerySetAlias> &aliases, const char *cluster, IPropertyTree *queriesOnCluster)
  817. {
  818. StringBuffer xpath;
  819. xpath.append("Alias[@name='").append(name).append("']");
  820. IPropertyTree *alias = registry->queryPropTree(xpath);
  821. if (!alias)
  822. {
  823. DBGLOG("Alias %s not found", name);
  824. return;
  825. }
  826. Owned<IEspQuerySetAlias> a = createQuerySetAlias();
  827. gatherQuerySetAliasDetails(alias, a);
  828. xpath.clear().append("Query[@id='").append(a->getId()).append("']");
  829. aliases.append(*a.getClear());
  830. IPropertyTree *query = registry->queryPropTree(xpath);
  831. if (!query)
  832. {
  833. DBGLOG("No matching Query %s found for Alias %s", a->getId(), name);
  834. return;
  835. }
  836. Owned<IEspQuerySetQuery> q = createQuerySetQuery();
  837. gatherQuerySetQueryDetails(context, query, q, cluster, queriesOnCluster);
  838. queries.append(*q.getClear());
  839. }
  840. 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)
  841. {
  842. if (!strieq(type, "Id") && !strieq(type, "Name"))
  843. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Unrecognized queryset filter type %s", type);
  844. StringBuffer attributeName(type);
  845. StringBuffer xpath;
  846. xpath.clear().append("Query[@").append(attributeName.toLowerCase()).append("='").append(value).append("']");
  847. IPropertyTree *query = registry->queryPropTree(xpath);
  848. if (!query)
  849. {
  850. DBGLOG("No matching Query %s found for %s", value, type);
  851. return;
  852. }
  853. Owned<IEspQuerySetQuery> q = createQuerySetQuery();
  854. gatherQuerySetQueryDetails(context, query, q, cluster, queriesOnCluster);
  855. xpath.clear().append("Alias[@id='").append(q->getId()).append("']");
  856. queries.append(*q.getClear());
  857. Owned<IPropertyTreeIterator> regAliases = registry->getElements(xpath.str());
  858. ForEach(*regAliases)
  859. {
  860. IPropertyTree &alias = regAliases->query();
  861. Owned<IEspQuerySetAlias> a = createQuerySetAlias();
  862. gatherQuerySetAliasDetails(&alias, a);
  863. aliases.append(*a.getClear());
  864. }
  865. }
  866. 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)
  867. {
  868. if (strieq(type, "All"))
  869. return retrieveAllQuerysetDetails(context, registry, queries, aliases, cluster, queriesOnCluster);
  870. if (!value || !*value)
  871. return;
  872. if (strieq(type, "Alias"))
  873. return retrieveQuerysetDetailsFromAlias(context, registry, value, queries, aliases, cluster, queriesOnCluster);
  874. if (strieq(type, "Status") && !isEmpty(cluster))
  875. return retrieveAllQuerysetDetails(context, registry, queries, aliases, cluster, queriesOnCluster, type, value);
  876. return retrieveQuerysetDetailsFromQuery(context, registry, value, type, queries, aliases, cluster, queriesOnCluster);
  877. }
  878. void retrieveQuerysetDetails(IEspContext &context, IArrayOf<IEspWUQuerySetDetail> &details, IPropertyTree *registry, const char *type, const char *value, const char *cluster=NULL, IPropertyTree *queriesOnCluster=NULL)
  879. {
  880. if (!registry)
  881. return;
  882. IArrayOf<IEspQuerySetQuery> queries;
  883. IArrayOf<IEspQuerySetAlias> aliases;
  884. retrieveQuerysetDetails(context, registry, type, value, queries, aliases, cluster, queriesOnCluster);
  885. Owned<IEspWUQuerySetDetail> detail = createWUQuerySetDetail();
  886. detail->setQuerySetName(registry->queryProp("@id"));
  887. detail->setQueries(queries);
  888. detail->setAliases(aliases);
  889. details.append(*detail.getClear());
  890. }
  891. void retrieveQuerysetDetails(IEspContext &context, IArrayOf<IEspWUQuerySetDetail> &details, const char *queryset, const char *type, const char *value, const char *cluster=NULL, IPropertyTree *queriesOnCluster=NULL)
  892. {
  893. if (!queryset || !*queryset)
  894. return;
  895. Owned<IPropertyTree> registry = getQueryRegistry(queryset, true);
  896. if (!registry)
  897. return;
  898. retrieveQuerysetDetails(context, details, registry, type, value, cluster, queriesOnCluster);
  899. }
  900. IPropertyTree* getQueriesOnCluster(const char *target, const char *queryset)
  901. {
  902. if (isEmpty(target))
  903. target = queryset;
  904. Owned<IConstWUClusterInfo> info = getTargetClusterInfo(target);
  905. if (!info)
  906. throw MakeStringException(ECLWATCH_CANNOT_RESOLVE_CLUSTER_NAME, "Cluster %s not found", target);
  907. if (queryset && *queryset && !strieq(target, queryset))
  908. throw MakeStringException(ECLWATCH_QUERYSET_NOT_ON_CLUSTER, "Target %s and QuerySet %s should match", target, queryset);
  909. if (info->getPlatform()!=RoxieCluster)
  910. return NULL;
  911. const SocketEndpointArray &eps = info->getRoxieServers();
  912. if (!eps.length())
  913. return NULL;
  914. try
  915. {
  916. Owned<ISocket> sock = ISocket::connect_timeout(eps.item(0), ROXIECONNECTIONTIMEOUT);
  917. return sendRoxieControlAllNodes(sock, "<control:queries/>", true, ROXIECONTROLQUERYTIMEOUT);
  918. }
  919. catch(IException* e)
  920. {
  921. StringBuffer err;
  922. DBGLOG("Get exception in control:queries: %s", e->errorMessage(err.append(e->errorCode()).append(' ')).str());
  923. e->Release();
  924. return NULL;
  925. }
  926. }
  927. void retrieveQuerysetDetailsByCluster(IEspContext &context, IArrayOf<IEspWUQuerySetDetail> &details, const char *target, const char *queryset, const char *type, const char *value)
  928. {
  929. Owned<IPropertyTree> queriesOnCluster = getQueriesOnCluster(target, queryset);
  930. retrieveQuerysetDetails(context, details, target, type, value, target, queriesOnCluster);
  931. }
  932. void retrieveAllQuerysetDetails(IEspContext &context, IArrayOf<IEspWUQuerySetDetail> &details, const char *type, const char *value)
  933. {
  934. Owned<IPropertyTree> root = getQueryRegistryRoot();
  935. if (!root)
  936. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "QuerySet Registry not found");
  937. Owned<IPropertyTreeIterator> querysets = root->getElements("QuerySet");
  938. ForEach(*querysets)
  939. retrieveQuerysetDetails(context, details, &querysets->query(), type, value);
  940. }
  941. bool CWsWorkunitsEx::onWUQuerysetDetails(IEspContext &context, IEspWUQuerySetDetailsRequest & req, IEspWUQuerySetDetailsResponse & resp)
  942. {
  943. resp.setQuerySetName(req.getQuerySetName());
  944. double version = context.getClientVersion();
  945. if (version > 1.36)
  946. {
  947. Owned<IPropertyTree> queryRegistry = getQueryRegistry(req.getQuerySetName(), false);
  948. resp.setClusterName(req.getClusterName());
  949. resp.setFilter(req.getFilter());
  950. resp.setFilterType(req.getFilterType());
  951. }
  952. Owned<IPropertyTree> registry = getQueryRegistry(req.getQuerySetName(), true);
  953. if (!registry)
  954. return false;
  955. IArrayOf<IEspQuerySetQuery> respQueries;
  956. IArrayOf<IEspQuerySetAlias> respAliases;
  957. if (isEmpty(req.getClusterName()) || isEmpty(req.getFilterTypeAsString()) || !strieq(req.getFilterTypeAsString(), "Status") || isEmpty(req.getFilter()))
  958. {
  959. const char* cluster = req.getClusterName();
  960. if (isEmpty(cluster))
  961. cluster = req.getQuerySetName();
  962. Owned<IPropertyTree> queriesOnCluster = getQueriesOnCluster(cluster, req.getQuerySetName());
  963. retrieveQuerysetDetails(context, registry, req.getFilterTypeAsString(), req.getFilter(), respQueries, respAliases, cluster, queriesOnCluster);
  964. resp.setQuerysetQueries(respQueries);
  965. resp.setQuerysetAliases(respAliases);
  966. }
  967. else
  968. {
  969. IArrayOf<IEspWUQuerySetDetail> respDetails;
  970. retrieveQuerysetDetailsByCluster(context, respDetails, req.getClusterName(), req.getQuerySetName(), req.getFilterTypeAsString(), req.getFilter());
  971. if (respDetails.ordinality())
  972. {
  973. IEspWUQuerySetDetail& detail = respDetails.item(0);
  974. resp.setQuerysetQueries(detail.getQueries());
  975. resp.setQuerysetAliases(detail.getAliases());
  976. }
  977. }
  978. return true;
  979. }
  980. bool CWsWorkunitsEx::onWUMultiQuerysetDetails(IEspContext &context, IEspWUMultiQuerySetDetailsRequest & req, IEspWUMultiQuerySetDetailsResponse & resp)
  981. {
  982. IArrayOf<IEspWUQuerySetDetail> respDetails;
  983. if (notEmpty(req.getClusterName()))
  984. retrieveQuerysetDetailsByCluster(context, respDetails, req.getClusterName(), req.getQuerySetName(), req.getFilterTypeAsString(), req.getFilter());
  985. else if (notEmpty(req.getQuerySetName()))
  986. retrieveQuerysetDetails(context, respDetails, req.getQuerySetName(), req.getFilterTypeAsString(), req.getFilter());
  987. else
  988. retrieveAllQuerysetDetails(context, respDetails, req.getFilterTypeAsString(), req.getFilter());
  989. resp.setQuerysets(respDetails);
  990. return true;
  991. }
  992. bool addWUQSQueryFilter(WUQuerySortField *filters, unsigned short &count, MemoryBuffer &buff, const char* value, WUQuerySortField name)
  993. {
  994. if (isEmpty(value))
  995. return false;
  996. filters[count++] = name;
  997. buff.append(value);
  998. return true;
  999. }
  1000. bool addWUQSQueryFilterInt(WUQuerySortField *filters, unsigned short &count, MemoryBuffer &buff, int value, WUQuerySortField name)
  1001. {
  1002. VStringBuffer vBuf("%d", value);
  1003. filters[count++] = name;
  1004. buff.append(vBuf.str());
  1005. return true;
  1006. }
  1007. bool addWUQSQueryFilterInt64(WUQuerySortField *filters, unsigned short &count, MemoryBuffer &buff, __int64 value, WUQuerySortField name)
  1008. {
  1009. VStringBuffer vBuf("%"I64F"d", value);
  1010. filters[count++] = name;
  1011. buff.append(vBuf.str());
  1012. return true;
  1013. }
  1014. unsigned CWsWorkunitsEx::getGraphIdsByQueryId(const char *target, const char *queryId, StringArray& graphIds)
  1015. {
  1016. if (!target || !*target)
  1017. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Target name required");
  1018. if (!queryId || !*queryId)
  1019. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Query Id required");
  1020. Owned<IConstWUClusterInfo> info = getTargetClusterInfo(target);
  1021. if (!info || (info->getPlatform()!=RoxieCluster)) //Only roxie query has query graph.
  1022. return 0;
  1023. const SocketEndpointArray &eps = info->getRoxieServers();
  1024. if (eps.empty())
  1025. return 0;
  1026. VStringBuffer xpath("<control:querystats><Query id='%s'/></control:querystats>", queryId);
  1027. Owned<ISocket> sock = ISocket::connect_timeout(eps.item(0), ROXIECONNECTIONTIMEOUT);
  1028. Owned<IPropertyTree> querystats = sendRoxieControlQuery(sock, xpath.str(), ROXIECONTROLQUERYTIMEOUT);
  1029. if (!querystats)
  1030. return 0;
  1031. Owned<IPropertyTreeIterator> graphs = querystats->getElements("Endpoint/Query/Graph");
  1032. ForEach(*graphs)
  1033. {
  1034. IPropertyTree &graph = graphs->query();
  1035. const char* graphId = graph.queryProp("@id");
  1036. if (graphId && *graphId)
  1037. graphIds.append(graphId);
  1038. }
  1039. return graphIds.length();
  1040. }
  1041. bool CWsWorkunitsEx::onWUListQueries(IEspContext &context, IEspWUListQueriesRequest & req, IEspWUListQueriesResponse & resp)
  1042. {
  1043. bool descending = req.getDescending();
  1044. const char *sortBy = req.getSortby();
  1045. WUQuerySortField sortOrder[2] = {WUQSFId, WUQSFterm};
  1046. if(notEmpty(sortBy))
  1047. {
  1048. if (strieq(sortBy, "Name"))
  1049. sortOrder[0] = WUQSFname;
  1050. else if (strieq(sortBy, "WUID"))
  1051. sortOrder[0] = WUQSFwuid;
  1052. else if (strieq(sortBy, "DLL"))
  1053. sortOrder[0] = WUQSFdll;
  1054. else if (strieq(sortBy, "Activated"))
  1055. sortOrder[0] = WUQSFActivited;
  1056. else if (strieq(sortBy, "MemoryLimit"))
  1057. sortOrder[0] = (WUQuerySortField) (WUQSFmemoryLimit | WUQSFnumeric);
  1058. else if (strieq(sortBy, "TimeLimit"))
  1059. sortOrder[0] = (WUQuerySortField) (WUQSFtimeLimit | WUQSFnumeric);
  1060. else if (strieq(sortBy, "WarnTimeLimit"))
  1061. sortOrder[0] = (WUQuerySortField) (WUQSFwarnTimeLimit | WUQSFnumeric);
  1062. else if (strieq(sortBy, "Priority"))
  1063. sortOrder[0] = (WUQuerySortField) (WUQSFpriority | WUQSFnumeric);
  1064. else
  1065. sortOrder[0] = WUQSFId;
  1066. sortOrder[0] = (WUQuerySortField) (sortOrder[0] | WUQSFnocase);
  1067. if (descending)
  1068. sortOrder[0] = (WUQuerySortField) (sortOrder[0] | WUQSFreverse);
  1069. }
  1070. WUQuerySortField filters[16];
  1071. unsigned short filterCount = 0;
  1072. MemoryBuffer filterBuf;
  1073. const char* clusterReq = req.getClusterName();
  1074. addWUQSQueryFilter(filters, filterCount, filterBuf, req.getQuerySetName(), WUQSFQuerySet);
  1075. addWUQSQueryFilter(filters, filterCount, filterBuf, req.getWUID(), WUQSFwuid);
  1076. if (!req.getMemoryLimitLow_isNull())
  1077. addWUQSQueryFilterInt64(filters, filterCount, filterBuf, req.getMemoryLimitLow(), (WUQuerySortField) (WUQSFmemoryLimit | WUQSFnumeric));
  1078. if (!req.getMemoryLimitHigh_isNull())
  1079. addWUQSQueryFilterInt64(filters, filterCount, filterBuf, req.getMemoryLimitHigh(), (WUQuerySortField) (WUQSFmemoryLimitHi | WUQSFnumeric));
  1080. if (!req.getTimeLimitLow_isNull())
  1081. addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getTimeLimitLow(), (WUQuerySortField) (WUQSFtimeLimit | WUQSFnumeric));
  1082. if (!req.getTimeLimitHigh_isNull())
  1083. addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getTimeLimitHigh(), (WUQuerySortField) (WUQSFtimeLimitHi | WUQSFnumeric));
  1084. if (!req.getWarnTimeLimitLow_isNull())
  1085. addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getWarnTimeLimitLow(), (WUQuerySortField) (WUQSFwarnTimeLimit | WUQSFnumeric));
  1086. if (!req.getWarnTimeLimitHigh_isNull())
  1087. addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getWarnTimeLimitHigh(), (WUQuerySortField) (WUQSFwarnTimeLimitHi | WUQSFnumeric));
  1088. if (!req.getPriorityLow_isNull())
  1089. addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getPriorityLow(), (WUQuerySortField) (WUQSFpriority | WUQSFnumeric));
  1090. if (!req.getPriorityHigh_isNull())
  1091. addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getPriorityHigh(), (WUQuerySortField) (WUQSFpriorityHi | WUQSFnumeric));
  1092. if (!req.getActivated_isNull())
  1093. addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getActivated(), (WUQuerySortField) (WUQSFActivited | WUQSFnumeric));
  1094. if (!req.getSuspendedByUser_isNull())
  1095. addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getSuspendedByUser(), (WUQuerySortField) (WUQSFSuspendedByUser | WUQSFnumeric));
  1096. filters[filterCount] = WUQSFterm;
  1097. unsigned numberOfQueries = 0;
  1098. unsigned pageSize = req.getPageSize();
  1099. unsigned pageStartFrom = req.getPageStartFrom();
  1100. if(pageSize < 1)
  1101. pageSize = 100;
  1102. __int64 cacheHint = 0;
  1103. if (!req.getCacheHint_isNull())
  1104. cacheHint = req.getCacheHint();
  1105. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1106. Owned<IConstQuerySetQueryIterator> it = factory->getQuerySetQueriesSorted(sortOrder, filters, filterBuf.bufferBase(), pageStartFrom, pageSize, &cacheHint, &numberOfQueries);
  1107. resp.setCacheHint(cacheHint);
  1108. IArrayOf<IEspQuerySetQuery> queries;
  1109. double version = context.getClientVersion();
  1110. ForEach(*it)
  1111. {
  1112. IPropertyTree &query=it->query();
  1113. Owned<IEspQuerySetQuery> q = createQuerySetQuery();
  1114. q->setId(query.queryProp("@id"));
  1115. q->setName(query.queryProp("@name"));
  1116. q->setQuerySetId(query.queryProp("@querySetId"));
  1117. q->setDll(query.queryProp("@dll"));
  1118. q->setWuid(query.queryProp("@wuid"));
  1119. q->setActivated(query.getPropBool("@activated", false));
  1120. q->setSuspended(query.getPropBool("@suspended", false));
  1121. if (query.hasProp("@memoryLimit"))
  1122. {
  1123. StringBuffer s;
  1124. memoryLimitStringFromUInt64(s, query.getPropInt64("@memoryLimit"));
  1125. q->setMemoryLimit(s);
  1126. }
  1127. if (query.hasProp("@timeLimit"))
  1128. q->setTimeLimit(query.getPropInt("@timeLimit"));
  1129. if (query.hasProp("@warnTimeLimit"))
  1130. q->setWarnTimeLimit(query.getPropInt("@warnTimeLimit"));
  1131. if (query.hasProp("@priority"))
  1132. q->setPriority(getQueryPriorityName(query.getPropInt("@priority")));
  1133. if (query.hasProp("@comment"))
  1134. q->setComment(query.queryProp("@comment"));
  1135. if (version >= 1.46)
  1136. {
  1137. q->setPublishedBy(query.queryProp("@publishedBy"));
  1138. q->setIsLibrary(query.getPropBool("@isLibrary"));
  1139. }
  1140. try
  1141. {
  1142. const char* cluster = clusterReq;
  1143. const char* querySetId = query.queryProp("@querySetId");
  1144. if (isEmpty(cluster))
  1145. cluster = querySetId;
  1146. Owned<IPropertyTree> queriesOnCluster = getQueriesOnCluster(cluster, querySetId);
  1147. if (queriesOnCluster)
  1148. {
  1149. IArrayOf<IEspClusterQueryState> clusters;
  1150. addClusterQueryStates(queriesOnCluster, cluster, query.queryProp("@id"), clusters, version);
  1151. q->setClusters(clusters);
  1152. }
  1153. }
  1154. catch(IException *e)
  1155. {
  1156. StringBuffer err;
  1157. DBGLOG("Get exception in WUListQueries: %s", e->errorMessage(err.append(e->errorCode()).append(' ')).str());
  1158. e->Release();
  1159. }
  1160. queries.append(*q.getClear());
  1161. }
  1162. resp.setQuerysetQueries(queries);
  1163. resp.setNumberOfQueries(numberOfQueries);
  1164. return true;
  1165. }
  1166. bool CWsWorkunitsEx::onWUListQueriesUsingFile(IEspContext &context, IEspWUListQueriesUsingFileRequest &req, IEspWUListQueriesUsingFileResponse &resp)
  1167. {
  1168. const char *target = req.getTarget();
  1169. const char *process = req.getProcess();
  1170. StringBuffer lfn(req.getFileName());
  1171. resp.setFileName(lfn.toLowerCase());
  1172. resp.setProcess(process);
  1173. StringArray targets;
  1174. if (target && *target)
  1175. targets.append(target);
  1176. else // if (process && *process)
  1177. {
  1178. SCMStringBuffer targetStr;
  1179. Owned<IStringIterator> targetClusters = getTargetClusters("RoxieCluster", process);
  1180. ForEach(*targetClusters)
  1181. targets.append(targetClusters->str(targetStr).str());
  1182. }
  1183. IArrayOf<IEspTargetQueriesUsingFile> respTargets;
  1184. ForEachItemIn(i, targets)
  1185. {
  1186. target = targets.item(i);
  1187. Owned<IEspTargetQueriesUsingFile> respTarget = createTargetQueriesUsingFile();
  1188. respTarget->setTarget(target);
  1189. const char *pmid = filesInUse.getPackageMap(target);
  1190. if (pmid && *pmid)
  1191. respTarget->setPackageMap(pmid);
  1192. Owned<IPropertyTreeIterator> queries = filesInUse.findQueriesUsingFile(target, lfn);
  1193. if (queries)
  1194. {
  1195. IArrayOf<IEspQueryUsingFile> respQueries;
  1196. ForEach(*queries)
  1197. {
  1198. IPropertyTree &query = queries->query();
  1199. Owned<IEspQueryUsingFile> q = createQueryUsingFile();
  1200. q->setId(query.queryProp("@id"));
  1201. VStringBuffer xpath("File[@lfn='%s']/@pkgid", lfn.str());
  1202. if (query.hasProp(xpath))
  1203. q->setPackage(query.queryProp(xpath));
  1204. respQueries.append(*q.getClear());
  1205. }
  1206. respTarget->setQueries(respQueries);
  1207. }
  1208. respTargets.append(*respTarget.getClear());
  1209. }
  1210. resp.setTargets(respTargets);
  1211. return true;
  1212. }
  1213. bool CWsWorkunitsEx::onWUQueryDetails(IEspContext &context, IEspWUQueryDetailsRequest & req, IEspWUQueryDetailsResponse & resp)
  1214. {
  1215. const char* querySet = req.getQuerySet();
  1216. const char* queryId = req.getQueryId();
  1217. bool includeStateOnClusters = req.getIncludeStateOnClusters();
  1218. if (!querySet || !*querySet)
  1219. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "QuerySet not specified");
  1220. if (!queryId || !*queryId)
  1221. throw MakeStringException(ECLWATCH_QUERYID_NOT_FOUND, "QueryId not specified");
  1222. resp.setQueryId(queryId);
  1223. resp.setQuerySet(querySet);
  1224. Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySet, false);
  1225. StringBuffer xpath;
  1226. xpath.clear().append("Query[@id='").append(queryId).append("']");
  1227. IPropertyTree *query = queryRegistry->queryPropTree(xpath.str());
  1228. if (!query)
  1229. {
  1230. DBGLOG("No matching Query");
  1231. return false;
  1232. }
  1233. const char* queryName = query->queryProp("@name");
  1234. const char* wuid = query->queryProp("@wuid");
  1235. resp.setQueryName(queryName);
  1236. resp.setWuid(wuid);
  1237. resp.setDll(query->queryProp("@dll"));
  1238. resp.setPublishedBy(query->queryProp("@publishedBy"));
  1239. resp.setSuspended(query->getPropBool("@suspended", false));
  1240. resp.setSuspendedBy(query->queryProp("@suspendedBy"));
  1241. resp.setComment(query->queryProp("@comment"));
  1242. double version = context.getClientVersion();
  1243. if (version >= 1.46)
  1244. {
  1245. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1246. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid, false);
  1247. if(!cw)
  1248. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT,"Cannot open workunit %s.",wuid);
  1249. if (query->hasProp("@priority"))
  1250. resp.setPriority(getQueryPriorityName(query->getPropInt("@priority")));
  1251. resp.setIsLibrary(query->getPropBool("@isLibrary"));
  1252. SCMStringBuffer s;
  1253. resp.setWUSnapShot(cw->getSnapshot(s).str()); //Label
  1254. cw->getTimeStamp("Compiled", "EclCCServer", s);
  1255. if (!s.length())
  1256. cw->getTimeStamp("Compiled", "EclServer", s);
  1257. if (s.length())
  1258. resp.setCompileTime(s.str());
  1259. StringArray libUsed, graphIds;
  1260. Owned<IConstWULibraryIterator> libs = &cw->getLibraries();
  1261. ForEach(*libs)
  1262. libUsed.append(libs->query().getName(s).str());
  1263. if (libUsed.length())
  1264. resp.setLibrariesUsed(libUsed);
  1265. unsigned numGraphIds = getGraphIdsByQueryId(querySet, queryId, graphIds);
  1266. resp.setCountGraphs(numGraphIds);
  1267. if (numGraphIds > 0)
  1268. resp.setGraphIds(graphIds);
  1269. }
  1270. StringArray logicalFiles;
  1271. IArrayOf<IEspQuerySuperFile> superFiles;
  1272. getQueryFiles(queryId, querySet, logicalFiles, req.getIncludeSuperFiles() ? &superFiles : NULL);
  1273. if (logicalFiles.length())
  1274. resp.setLogicalFiles(logicalFiles);
  1275. if (superFiles.length())
  1276. resp.setSuperFiles(superFiles);
  1277. if (version >= 1.42)
  1278. {
  1279. xpath.clear().appendf("Alias[@id='%s']", queryId);
  1280. IPropertyTree *alias = queryRegistry->queryPropTree(xpath.str());
  1281. if (!alias)
  1282. resp.setActivated(false);
  1283. else
  1284. resp.setActivated(true);
  1285. }
  1286. if (includeStateOnClusters && (version >= 1.43))
  1287. {
  1288. Owned<IPropertyTree> queriesOnCluster = getQueriesOnCluster(querySet, querySet);
  1289. if (queriesOnCluster)
  1290. {
  1291. IArrayOf<IEspClusterQueryState> clusterStates;
  1292. addClusterQueryStates(queriesOnCluster, querySet, queryId, clusterStates, version);
  1293. resp.setClusters(clusterStates);
  1294. }
  1295. }
  1296. if (version >= 1.50)
  1297. {
  1298. WsWuInfo winfo(context, wuid);
  1299. resp.setResourceURLCount(winfo.getResourceURLCount());
  1300. }
  1301. return true;
  1302. }
  1303. bool CWsWorkunitsEx::getQueryFiles(const char* query, const char* target, StringArray& logicalFiles, IArrayOf<IEspQuerySuperFile> *respSuperFiles)
  1304. {
  1305. try
  1306. {
  1307. Owned<IConstWUClusterInfo> info = getTargetClusterInfo(target);
  1308. if (!info || (info->getPlatform()!=RoxieCluster))
  1309. return false;
  1310. const SocketEndpointArray &eps = info->getRoxieServers();
  1311. if (eps.empty())
  1312. return false;
  1313. StringBuffer control;
  1314. control.appendf("<control:getQueryXrefInfo full='1'><Query id='%s'/></control:getQueryXrefInfo>", query);
  1315. Owned<ISocket> sock = ISocket::connect_timeout(eps.item(0), ROXIECONNECTIONTIMEOUT);
  1316. Owned<IPropertyTree> result = sendRoxieControlQuery(sock, control.str(), ROXIECONTROLQUERYTIMEOUT);
  1317. if (!result)
  1318. return false;
  1319. StringBuffer xpath("Endpoint/Queries/Query/");
  1320. if (!respSuperFiles)
  1321. xpath.append('/');
  1322. xpath.append("File");
  1323. Owned<IPropertyTreeIterator> files = result->getElements(xpath);
  1324. ForEach (*files)
  1325. {
  1326. IPropertyTree &file = files->query();
  1327. const char* fileName = file.queryProp("@name");
  1328. if (fileName && *fileName)
  1329. logicalFiles.append(fileName);
  1330. }
  1331. if (respSuperFiles)
  1332. {
  1333. Owned<IPropertyTreeIterator> superFiles = result->getElements("Endpoint/Queries/Query/SuperFile");
  1334. ForEach (*superFiles)
  1335. {
  1336. IPropertyTree &super = superFiles->query();
  1337. Owned<IEspQuerySuperFile> respSuperFile = createQuerySuperFile();
  1338. respSuperFile->setName(super.queryProp("@name"));
  1339. Owned<IPropertyTreeIterator> fileIter = super.getElements("File");
  1340. StringArray respSubFiles;
  1341. ForEach (*fileIter)
  1342. {
  1343. IPropertyTree &fileItem = fileIter->query();
  1344. const char* fileName = fileItem.queryProp("@name");
  1345. if (fileName && *fileName)
  1346. respSubFiles.append(fileName);
  1347. }
  1348. respSuperFile->setSubFiles(respSubFiles);
  1349. respSuperFiles->append(*respSuperFile.getClear());
  1350. }
  1351. }
  1352. return true;
  1353. }
  1354. catch(IMultiException *me)
  1355. {
  1356. StringBuffer err;
  1357. DBGLOG("ERROR control:getQueryXrefInfo roxie query info %s", me->errorMessage(err.append(me->errorCode()).append(' ')).str());
  1358. me->Release();
  1359. return false;
  1360. }
  1361. catch(IException *e)
  1362. {
  1363. StringBuffer err;
  1364. DBGLOG("ERROR control:getQueryXrefInfo roxie query info %s", e->errorMessage(err.append(e->errorCode()).append(' ')).str());
  1365. e->Release();
  1366. return false;
  1367. }
  1368. }
  1369. inline void verifyQueryActionAllowsWild(bool &allowWildChecked, CQuerySetQueryActionTypes action)
  1370. {
  1371. if (allowWildChecked)
  1372. return;
  1373. switch (action)
  1374. {
  1375. case CQuerySetQueryActionTypes_ToggleSuspend:
  1376. throw MakeStringException(ECLWATCH_INVALID_ACTION, "Wildcards not supported for toggling suspended state");
  1377. case CQuerySetQueryActionTypes_Activate:
  1378. throw MakeStringException(ECLWATCH_INVALID_ACTION, "Wildcards not supported for Activating queries");
  1379. }
  1380. allowWildChecked=true;
  1381. }
  1382. inline bool verifyQueryActionAllowsAlias(CQuerySetQueryActionTypes action)
  1383. {
  1384. return (action!=CQuerySetQueryActionTypes_Activate && action!=CQuerySetQueryActionTypes_RemoveAllAliases);
  1385. }
  1386. void expandQueryActionTargetList(IProperties *queryIds, IPropertyTree *queryset, IArrayOf<IConstQuerySetQueryActionItem> &items, CQuerySetQueryActionTypes action)
  1387. {
  1388. bool allowWildChecked=false;
  1389. ForEachItemIn(i, items)
  1390. {
  1391. const char *itemId = items.item(i).getQueryId();
  1392. if (!isWildString(itemId))
  1393. {
  1394. bool suspendedByUser = false;
  1395. const char *itemSuspendState = items.item(i).getClientState().getSuspended();
  1396. if (itemSuspendState && (strieq(itemSuspendState, "By User") || strieq(itemSuspendState, "1")))
  1397. suspendedByUser = true;
  1398. if (!verifyQueryActionAllowsAlias(action))
  1399. queryIds->setProp(itemId, suspendedByUser);
  1400. else
  1401. {
  1402. Owned<IPropertyTree> query = resolveQueryAlias(queryset, itemId);
  1403. if (query)
  1404. {
  1405. const char *id = query->queryProp("@id");
  1406. if (id && *id)
  1407. queryIds->setProp(id, suspendedByUser);
  1408. }
  1409. }
  1410. }
  1411. else
  1412. {
  1413. verifyQueryActionAllowsWild(allowWildChecked, action);
  1414. if (verifyQueryActionAllowsAlias(action))
  1415. {
  1416. Owned<IPropertyTreeIterator> active = queryset->getElements("Alias");
  1417. ForEach(*active)
  1418. {
  1419. const char *name = active->query().queryProp("@name");
  1420. const char *id = active->query().queryProp("@id");
  1421. if (name && id && WildMatch(name, itemId))
  1422. queryIds->setProp(id, 0);
  1423. }
  1424. }
  1425. Owned<IPropertyTreeIterator> queries = queryset->getElements("Query");
  1426. ForEach(*queries)
  1427. {
  1428. const char *id = queries->query().queryProp("@id");
  1429. if (id && WildMatch(id, itemId))
  1430. queryIds->setProp(id, 0);
  1431. }
  1432. }
  1433. }
  1434. }
  1435. void expandQueryActionTargetList(IProperties *queryIds, IPropertyTree *queryset, const char *id, CQuerySetQueryActionTypes action)
  1436. {
  1437. IArrayOf<IConstQuerySetQueryActionItem> items;
  1438. Owned<IEspQuerySetQueryActionItem> item = createQuerySetQueryActionItem();
  1439. item->setQueryId(id);
  1440. items.append(*(IConstQuerySetQueryActionItem*)item.getClear());
  1441. expandQueryActionTargetList(queryIds, queryset, items, action);
  1442. }
  1443. bool CWsWorkunitsEx::onWUQueryConfig(IEspContext &context, IEspWUQueryConfigRequest & req, IEspWUQueryConfigResponse & resp)
  1444. {
  1445. StringAttr target(req.getTarget());
  1446. if (target.isEmpty())
  1447. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Target name required");
  1448. if (!isValidCluster(target))
  1449. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid target name: %s", target.get());
  1450. Owned<IPropertyTree> queryset = getQueryRegistry(target.get(), false);
  1451. if (!queryset)
  1452. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Target Queryset %s not found", req.getTarget());
  1453. Owned<IProperties> queryIds = createProperties();
  1454. expandQueryActionTargetList(queryIds, queryset, req.getQueryId(), QuerySetQueryActionTypes_Undefined);
  1455. IArrayOf<IEspWUQueryConfigResult> results;
  1456. Owned<IPropertyIterator> it = queryIds->getIterator();
  1457. ForEach(*it)
  1458. {
  1459. Owned<IEspWUQueryConfigResult> result = createWUQueryConfigResult();
  1460. result->setQueryId(it->getPropKey());
  1461. VStringBuffer xpath("Query[@id='%s']", it->getPropKey());
  1462. IPropertyTree *queryTree = queryset->queryPropTree(xpath);
  1463. if (queryTree)
  1464. {
  1465. updateMemoryLimitSetting(queryTree, req.getMemoryLimit());
  1466. updateQueryPriority(queryTree, req.getPriority());
  1467. updateQuerySetting(req.getTimeLimit_isNull(), queryTree, "@timeLimit", req.getTimeLimit());
  1468. updateQuerySetting(req.getWarnTimeLimit_isNull(), queryTree, "@warnTimeLimit", req.getWarnTimeLimit());
  1469. if (req.getComment())
  1470. queryTree->setProp("@comment", req.getComment());
  1471. }
  1472. results.append(*result.getClear());
  1473. }
  1474. resp.setResults(results);
  1475. bool reloadFailed = false;
  1476. if (0!=req.getWait() && !req.getNoReload())
  1477. reloadFailed = !reloadCluster(target.get(), (unsigned)req.getWait());
  1478. resp.setReloadFailed(reloadFailed);
  1479. return true;
  1480. }
  1481. bool CWsWorkunitsEx::onWUQuerysetQueryAction(IEspContext &context, IEspWUQuerySetQueryActionRequest & req, IEspWUQuerySetQueryActionResponse & resp)
  1482. {
  1483. resp.setQuerySetName(req.getQuerySetName());
  1484. resp.setAction(req.getAction());
  1485. if (isEmpty(req.getQuerySetName()))
  1486. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Queryset name required");
  1487. Owned<IPropertyTree> queryset = getQueryRegistry(req.getQuerySetName(), true);
  1488. if (!queryset)
  1489. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Queryset %s not found", req.getQuerySetName());
  1490. Owned<IProperties> queryIds = createProperties();
  1491. expandQueryActionTargetList(queryIds, queryset, req.getQueries(), req.getAction());
  1492. IArrayOf<IEspQuerySetQueryActionResult> results;
  1493. Owned<IPropertyIterator> it = queryIds->getIterator();
  1494. ForEach(*it)
  1495. {
  1496. const char *id = it->getPropKey();
  1497. Owned<IEspQuerySetQueryActionResult> result = createQuerySetQueryActionResult();
  1498. result->setQueryId(id);
  1499. try
  1500. {
  1501. Owned<IPropertyTree> query = getQueryById(queryset, id);
  1502. if (!query)
  1503. throw MakeStringException(ECLWATCH_QUERYID_NOT_FOUND, "Query %s/%s not found.", req.getQuerySetName(), id);
  1504. switch (req.getAction())
  1505. {
  1506. case CQuerySetQueryActionTypes_ToggleSuspend:
  1507. setQuerySuspendedState(queryset, id, !queryIds->getPropBool(id), context.queryUserId());
  1508. break;
  1509. case CQuerySetQueryActionTypes_Suspend:
  1510. setQuerySuspendedState(queryset, id, true, context.queryUserId());
  1511. break;
  1512. case CQuerySetQueryActionTypes_Unsuspend:
  1513. setQuerySuspendedState(queryset, id, false, NULL);
  1514. break;
  1515. case CQuerySetQueryActionTypes_Activate:
  1516. setQueryAlias(queryset, query->queryProp("@name"), id);
  1517. break;
  1518. case CQuerySetQueryActionTypes_Delete:
  1519. removeNamedQuery(queryset, id);
  1520. query.clear();
  1521. break;
  1522. case CQuerySetQueryActionTypes_RemoveAllAliases:
  1523. removeAliasesFromNamedQuery(queryset, id);
  1524. break;
  1525. }
  1526. result->setSuccess(true);
  1527. if (query)
  1528. result->setSuspended(query->getPropBool("@suspended"));
  1529. }
  1530. catch(IException *e)
  1531. {
  1532. StringBuffer msg;
  1533. result->setMessage(e->errorMessage(msg).str());
  1534. result->setCode(e->errorCode());
  1535. result->setSuccess(false);
  1536. e->Release();
  1537. }
  1538. results.append(*result.getClear());
  1539. }
  1540. resp.setResults(results);
  1541. return true;
  1542. }
  1543. bool CWsWorkunitsEx::onWUQuerysetAliasAction(IEspContext &context, IEspWUQuerySetAliasActionRequest &req, IEspWUQuerySetAliasActionResponse &resp)
  1544. {
  1545. resp.setQuerySetName(req.getQuerySetName());
  1546. resp.setAction(req.getAction());
  1547. if (isEmpty(req.getQuerySetName()))
  1548. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Queryset name required");
  1549. Owned<IPropertyTree> queryset = getQueryRegistry(req.getQuerySetName(), true);
  1550. if (!queryset)
  1551. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Queryset %s not found", req.getQuerySetName());
  1552. IArrayOf<IEspQuerySetAliasActionResult> results;
  1553. ForEachItemIn(i, req.getAliases())
  1554. {
  1555. IConstQuerySetAliasActionItem& item=req.getAliases().item(i);
  1556. Owned<IEspQuerySetAliasActionResult> result = createQuerySetAliasActionResult();
  1557. try
  1558. {
  1559. VStringBuffer xpath("Alias[@name='%s']", item.getName());
  1560. IPropertyTree *alias = queryset->queryPropTree(xpath.str());
  1561. if (!alias)
  1562. throw MakeStringException(ECLWATCH_ALIAS_NOT_FOUND, "Alias %s/%s not found.", req.getQuerySetName(), item.getName());
  1563. switch (req.getAction())
  1564. {
  1565. case CQuerySetAliasActionTypes_Deactivate:
  1566. removeQuerySetAlias(req.getQuerySetName(), item.getName());
  1567. break;
  1568. }
  1569. result->setSuccess(true);
  1570. }
  1571. catch(IException *e)
  1572. {
  1573. StringBuffer msg;
  1574. result->setMessage(e->errorMessage(msg).str());
  1575. result->setCode(e->errorCode());
  1576. result->setSuccess(false);
  1577. e->Release();
  1578. }
  1579. results.append(*result.getClear());
  1580. }
  1581. resp.setResults(results);
  1582. return true;
  1583. }
  1584. #define QUERYPATH_SEP_CHAR '/'
  1585. bool nextQueryPathNode(const char *&path, StringBuffer &node)
  1586. {
  1587. if (*path==QUERYPATH_SEP_CHAR)
  1588. path++;
  1589. while (*path && *path!=QUERYPATH_SEP_CHAR)
  1590. node.append(*path++);
  1591. return (*path && *++path);
  1592. }
  1593. bool splitQueryPath(const char *path, StringBuffer &netAddress, StringBuffer &queryset, StringBuffer &query)
  1594. {
  1595. if (!path || !*path)
  1596. return false;
  1597. if (*path==QUERYPATH_SEP_CHAR && path[1]==QUERYPATH_SEP_CHAR)
  1598. {
  1599. path+=2;
  1600. if (!nextQueryPathNode(path, netAddress))
  1601. return false;
  1602. }
  1603. if (!nextQueryPathNode(path, queryset))
  1604. return false;
  1605. if (nextQueryPathNode(path, query))
  1606. return false; //query path too deep
  1607. return true;
  1608. }
  1609. bool CWsWorkunitsEx::onWUQuerysetCopyQuery(IEspContext &context, IEspWUQuerySetCopyQueryRequest &req, IEspWUQuerySetCopyQueryResponse &resp)
  1610. {
  1611. unsigned start = msTick();
  1612. const char *source = req.getSource();
  1613. if (!source || !*source)
  1614. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "No source query specified");
  1615. const char *target = req.getTarget();
  1616. if (!target || !*target)
  1617. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "No destination specified");
  1618. if (strchr(target, '/')) //for future use
  1619. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid target queryset name");
  1620. if (req.getCluster() && *req.getCluster() && !strieq(req.getCluster(), target)) //backward compatability check
  1621. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid target cluster and queryset must match");
  1622. if (!isValidCluster(target))
  1623. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid target name: %s", target);
  1624. StringBuffer srcAddress, srcQuerySet, srcQuery;
  1625. if (!splitQueryPath(source, srcAddress, srcQuerySet, srcQuery))
  1626. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid source query path");
  1627. StringAttr targetQueryName(req.getDestName());
  1628. Owned<IClientWUQuerySetDetailsResponse> sourceQueryInfoResp;
  1629. StringBuffer remoteIP;
  1630. StringBuffer wuid;
  1631. if (srcAddress.length())
  1632. {
  1633. StringBuffer xml;
  1634. MemoryBuffer dll;
  1635. StringBuffer dllname;
  1636. StringBuffer queryName;
  1637. fetchRemoteWorkunit(context, srcAddress.str(), srcQuerySet.str(), srcQuery.str(), NULL, queryName, xml, dllname, dll, remoteIP, sourceQueryInfoResp);
  1638. if (targetQueryName.isEmpty())
  1639. targetQueryName.set(queryName);
  1640. deploySharedObject(context, wuid, dllname.str(), target, targetQueryName.get(), dll, queryDirectory.str(), xml.str());
  1641. }
  1642. else
  1643. {
  1644. //Could get the atributes without soap call, but this creates a common data structure shared with fetching remote query info
  1645. //Get query attributes before resolveQueryAlias, to avoid deadlock
  1646. sourceQueryInfoResp.setown(fetchQueryDetails(context, NULL, srcQuerySet, srcQuery));
  1647. Owned<IPropertyTree> queryset = getQueryRegistry(srcQuerySet.str(), true);
  1648. if (!queryset)
  1649. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Source Queryset %s not found", srcQuery.str());
  1650. Owned<IPropertyTree> query = resolveQueryAlias(queryset, srcQuery.str());
  1651. if (!query)
  1652. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Source query %s not found", source);
  1653. wuid.set(query->queryProp("@wuid"));
  1654. if (targetQueryName.isEmpty())
  1655. targetQueryName.set(query->queryProp("@name"));
  1656. }
  1657. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1658. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str(), false);
  1659. if (!req.getDontCopyFiles())
  1660. {
  1661. StringBuffer daliIP;
  1662. StringBuffer srcCluster;
  1663. StringBuffer srcPrefix;
  1664. splitDerivedDfsLocation(req.getDaliServer(), srcCluster, daliIP, srcPrefix, req.getSourceProcess(), req.getSourceProcess(), remoteIP.str(), NULL);
  1665. copyQueryFilesToCluster(context, cw, daliIP.str(), srcPrefix, target, srcCluster, targetQueryName.get(), req.getOverwrite(), req.getAllowForeignFiles());
  1666. }
  1667. WorkunitUpdate wu(&cw->lock());
  1668. if (!wu)
  1669. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT, "Error opening wuid %s for query %s", wuid.str(), source);
  1670. StringBuffer targetQueryId;
  1671. WUQueryActivationOptions activate = (WUQueryActivationOptions)req.getActivate();
  1672. addQueryToQuerySet(wu, target, targetQueryName.get(), NULL, activate, targetQueryId, context.queryUserId());
  1673. Owned<IPropertyTree> queryTree = getQueryById(target, targetQueryId, false);
  1674. if (queryTree)
  1675. {
  1676. IConstQuerySetQuery *srcInfo=NULL;
  1677. if (sourceQueryInfoResp && sourceQueryInfoResp->getQuerysetQueries().ordinality())
  1678. srcInfo = &sourceQueryInfoResp->getQuerysetQueries().item(0);
  1679. updateMemoryLimitSetting(queryTree, req.getMemoryLimit(), srcInfo);
  1680. updateQueryPriority(queryTree, req.getPriority(), srcInfo);
  1681. updateTimeLimitSetting(queryTree, req.getTimeLimit_isNull(), req.getTimeLimit(), srcInfo);
  1682. updateWarnTimeLimitSetting(queryTree, req.getWarnTimeLimit_isNull(), req.getWarnTimeLimit(), srcInfo);
  1683. if (req.getComment())
  1684. queryTree->setProp("@comment", req.getComment());
  1685. else if (srcInfo && srcInfo->getComment())
  1686. queryTree->setProp("@comment", srcInfo->getComment());
  1687. }
  1688. wu.clear();
  1689. resp.setQueryId(targetQueryId.str());
  1690. if (0!=req.getWait() && !req.getNoReload())
  1691. reloadCluster(target, remainingMsWait(req.getWait(), start));
  1692. return true;
  1693. }
  1694. void CWsWorkunitsEx::getGraphsByQueryId(const char *target, const char *queryId, const char *graphId, const char *subGraphId, IArrayOf<IEspECLGraphEx>& ECLGraphs)
  1695. {
  1696. if (!target || !*target)
  1697. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Target name required");
  1698. if (!queryId || !*queryId)
  1699. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Query Id required");
  1700. Owned<IConstWUClusterInfo> info = getTargetClusterInfo(target);
  1701. if (!info || (info->getPlatform()!=RoxieCluster)) //Only support roxie for now
  1702. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid Roxie name");
  1703. const SocketEndpointArray &eps = info->getRoxieServers();
  1704. if (eps.empty())
  1705. return;
  1706. VStringBuffer control("<control:querystats><Query id='%s'/></control:querystats>", queryId);
  1707. Owned<IPropertyTree> querystats = sendRoxieControlAllNodes(eps.item(0), control.str(), false, ROXIELOCKCONNECTIONTIMEOUT);
  1708. if (!querystats)
  1709. return;
  1710. Owned<IPropertyTreeIterator> graphs = querystats->getElements("Endpoint/Query/Graph");
  1711. ForEach(*graphs)
  1712. {
  1713. IPropertyTree &graph = graphs->query();
  1714. const char* aGraphId = graph.queryProp("@id");
  1715. if (graphId && *graphId && !strieq(graphId, aGraphId))
  1716. continue;
  1717. IPropertyTree* xgmml = graph.getBranch("xgmml/graph");
  1718. if (!xgmml)
  1719. continue;
  1720. Owned<IEspECLGraphEx> g = createECLGraphEx("","");
  1721. g->setName(aGraphId);
  1722. StringBuffer xml;
  1723. if (!subGraphId || !*subGraphId)
  1724. toXML(xgmml, xml);
  1725. else
  1726. {
  1727. VStringBuffer xpath("//node[@id='%s']", subGraphId);
  1728. toXML(xgmml->queryPropTree(xpath.str()), xml);
  1729. }
  1730. g->setGraph(xml.str());
  1731. ECLGraphs.append(*g.getClear());
  1732. }
  1733. return;
  1734. }
  1735. bool CWsWorkunitsEx::onWUQueryGetGraph(IEspContext& context, IEspWUQueryGetGraphRequest& req, IEspWUQueryGetGraphResponse& resp)
  1736. {
  1737. try
  1738. {
  1739. IArrayOf<IEspECLGraphEx> graphs;
  1740. getGraphsByQueryId(req.getTarget(), req.getQueryId(), req.getGraphName(), req.getSubGraphId(), graphs);
  1741. resp.setGraphs(graphs);
  1742. }
  1743. catch(IException* e)
  1744. {
  1745. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1746. }
  1747. return true;
  1748. }