ws_workunitsQuerySets.cpp 86 KB

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