roxiedebug.cpp 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302
  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 "jexcept.hpp"
  14. #include "thorherror.h"
  15. #include "roxiehelper.hpp"
  16. #include "roxiedebug.hpp"
  17. #include "portlist.h"
  18. #include "eclrtl.hpp"
  19. #include "deftype.hpp"
  20. #include "eclhelper.hpp"
  21. #include "thorcommon.hpp"
  22. //=======================================================================================
  23. bool CDebugCommandHandler::checkCommand(IXmlWriter &out, const char *&supplied, const char *expected)
  24. {
  25. unsigned i = 0;
  26. loop
  27. {
  28. if (!supplied[i])
  29. {
  30. out.outputBeginNested(expected, true);
  31. supplied = expected;
  32. return true;
  33. }
  34. if (!expected[i])
  35. return false;
  36. if (supplied[i] != expected[i])
  37. return false;
  38. i++;
  39. }
  40. }
  41. void CDebugCommandHandler::doDebugCommand(IPropertyTree *query, IDebuggerContext *debugContext, IXmlWriter &out)
  42. {
  43. const char *commandName = query->queryName();
  44. if (strnicmp(commandName, "b", 1)==0 && checkCommand(out, commandName, "breakpoint"))
  45. {
  46. const char *mode = query->queryProp("@mode");
  47. const char *id = query->queryProp("@id");
  48. const char *action = query->queryProp("@action");
  49. const char *fieldName = query->queryProp("@fieldName");
  50. const char *condition = query->queryProp("@condition");
  51. bool caseSensitive = query->getPropBool("@caseSensitive", false);
  52. const char *value = query->queryProp("@value");
  53. unsigned rowCount = query->getPropInt("@rowCount", 0);
  54. const char *rowCountMode = query->queryProp("@rowCountMode");
  55. debugContext->addBreakpoint(&out, mode, id, action, fieldName, condition, value, caseSensitive, rowCount, rowCountMode);
  56. }
  57. else if (strnicmp(commandName, "c", 1)==0 && checkCommand(out, commandName, "continue"))
  58. {
  59. const char *mode = query->queryProp("@mode");
  60. const char *id = query->queryProp("@id");
  61. debugContext->debugContinue(&out, mode, id);
  62. }
  63. else if (strnicmp(commandName, "c", 1)==0 && checkCommand(out, commandName, "changes"))
  64. {
  65. unsigned sequence = query->getPropInt("@sequence", -1);
  66. debugContext->debugChanges(&out, sequence);
  67. }
  68. else if (strnicmp(commandName, "c", 1)==0 && checkCommand(out, commandName, "counts"))
  69. {
  70. // MORE It could be argued that this is really more a "changes" with a "global" vs "active" option....
  71. unsigned sequence = query->getPropInt("@sequence", -1);
  72. debugContext->debugCounts(&out, sequence, false);
  73. }
  74. else if (strnicmp(commandName, "d", 1)==0 && checkCommand(out, commandName, "delete"))
  75. {
  76. const char *idx = query->queryProp("@idx");
  77. if (!idx)
  78. throw MakeStringException(THORHELPER_DEBUG_ERROR, "delete must specify breakpoint index, or all");
  79. if (stricmp(idx, "all")==0)
  80. debugContext->removeAllBreakpoints(&out);
  81. else
  82. {
  83. char *ep;
  84. unsigned bpIdx = strtoul(idx, &ep, 10);
  85. if (ep != idx && *ep==0)
  86. {
  87. if (bpIdx)
  88. debugContext->removeBreakpoint(&out, bpIdx);
  89. else
  90. debugContext->removeAllBreakpoints(&out);
  91. }
  92. else
  93. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Invalid value for idx - expected number or all");
  94. }
  95. }
  96. else if (strnicmp(commandName, "g", 1)==0 && checkCommand(out, commandName, "graph"))
  97. {
  98. const char *graphName = query->queryProp("@name");
  99. if (!graphName)
  100. {
  101. bool original = query->getPropBool("@original", true);
  102. debugContext->getCurrentGraphXGMML(&out, original);
  103. }
  104. else if (stricmp(graphName, "all")==0)
  105. debugContext->getQueryXGMML(&out);
  106. else
  107. debugContext->getGraphXGMML(&out, graphName);
  108. }
  109. else if (strnicmp(commandName, "g", 1)==0 && checkCommand(out, commandName, "get"))
  110. {
  111. const char *name = query->queryProp("@name");
  112. const char *id = query->queryProp("@id");
  113. debugContext->debugGetConfig(&out, name, id);
  114. }
  115. else if (strnicmp(commandName, "i", 1)==0 && checkCommand(out, commandName, "interrupt"))
  116. {
  117. debugContext->debugInterrupt(&out);
  118. }
  119. else if (strnicmp(commandName, "l", 1)==0 && checkCommand(out, commandName, "list"))
  120. {
  121. const char *idx = query->queryProp("@idx");
  122. if (!idx || strcmp(idx, "all")==0)
  123. debugContext->listAllBreakpoints(&out);
  124. else
  125. {
  126. char *ep;
  127. unsigned bpIdx = strtoul(idx, &ep, 10);
  128. if (ep != idx && *ep==0)
  129. debugContext->listBreakpoint(&out, bpIdx);
  130. else
  131. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Invalid value for idx - expected number or all");
  132. }
  133. }
  134. else if (strnicmp(commandName, "n", 1)==0 && checkCommand(out, commandName, "next"))
  135. {
  136. debugContext->debugNext(&out);
  137. }
  138. else if (strnicmp(commandName, "o", 1)==0 && checkCommand(out, commandName, "over"))
  139. {
  140. debugContext->debugOver(&out);
  141. }
  142. else if (strnicmp(commandName, "p", 1)==0 && checkCommand(out, commandName, "print"))
  143. {
  144. const char *edgeId = query->queryProp("@edgeId");
  145. unsigned numRows = query->getPropInt("@numRows", 1);
  146. unsigned startRow= query->getPropInt("@startRow", 0);
  147. debugContext->debugPrint(&out, edgeId, startRow, numRows);
  148. }
  149. else if (strnicmp(commandName, "q", 1)==0 && checkCommand(out, commandName, "quit"))
  150. {
  151. debugContext->debugQuit(&out);
  152. }
  153. else if (strnicmp(commandName, "r", 1)==0 && checkCommand(out, commandName, "run"))
  154. {
  155. debugContext->debugRun(&out);
  156. }
  157. else if (strnicmp(commandName, "s", 1)==0 && checkCommand(out, commandName, "step"))
  158. {
  159. const char *mode = query->queryProp("@mode");
  160. debugContext->debugStep(&out, mode);
  161. }
  162. else if (strnicmp(commandName, "s", 1)==0 && checkCommand(out, commandName, "status"))
  163. {
  164. debugContext->debugStatus(&out);
  165. }
  166. else if (strnicmp(commandName, "s", 1)==0 && checkCommand(out, commandName, "skip"))
  167. {
  168. debugContext->debugSkip(&out);
  169. }
  170. else if (strnicmp(commandName, "s", 1)==0 && checkCommand(out, commandName, "search"))
  171. {
  172. const char *fieldName = query->queryProp("@fieldName");
  173. const char *condition = query->queryProp("@condition");
  174. if (!condition)
  175. condition="contains";
  176. const char *value = query->queryProp("@value");
  177. bool caseSensitive = query->getPropBool("@caseSensitive", false);
  178. bool fullRows = query->getPropBool("@fullRows", false);
  179. debugContext->debugSearch(&out, fieldName, condition, value, caseSensitive, fullRows);
  180. }
  181. else if (strnicmp(commandName, "s", 1)==0 && checkCommand(out, commandName, "set"))
  182. {
  183. const char *name = query->queryProp("@name");
  184. const char *value = query->queryProp("@value");
  185. const char *id = query->queryProp("@id");
  186. debugContext->debugSetConfig(&out, name, value, id);
  187. }
  188. else if (strnicmp(commandName, "v", 1)==0 && checkCommand(out, commandName, "variable"))
  189. {
  190. const char *name = query->queryProp("@name");
  191. const char *type = query->queryProp("@type");
  192. debugContext->debugPrintVariable(&out, name, type);
  193. }
  194. else if (strnicmp(commandName, "w", 1)==0 && checkCommand(out, commandName, "where"))
  195. {
  196. debugContext->debugWhere(&out);
  197. }
  198. else
  199. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Unknown command %s", commandName);
  200. out.outputEndNested(commandName);
  201. }
  202. //=======================================================================================
  203. typedef ArrayOf<const RtlTypeInfo *> RtlTypeInfoArray;
  204. class SimpleFieldSearcher : public CInterface, implements IRowMatcher
  205. {
  206. protected:
  207. unsigned searchStringLength;
  208. const char *searchString;
  209. StringAttr expression;
  210. StringAttr searchFieldName;
  211. MemoryBuffer searchQString;
  212. bool matchSeen;
  213. bool boolValueSet;
  214. bool intValueSet;
  215. bool uintValueSet;
  216. bool realValueSet;
  217. bool decimalValueSet;
  218. bool udecimalValueSet;
  219. bool qstringValueSet;
  220. bool boolValue;
  221. __int64 intValue;
  222. double realValue;
  223. BreakpointConditionMode mode;
  224. bool caseSensitive;
  225. RtlTypeInfoArray recordTypesCanMatch;
  226. RtlTypeInfoArray recordTypesCannotMatch;
  227. bool checkCondition(int diff)
  228. {
  229. switch (mode)
  230. {
  231. case BreakpointConditionLess:
  232. return (diff < 0);
  233. case BreakpointConditionLessEqual:
  234. return (diff <= 0);
  235. case BreakpointConditionGreater:
  236. return (diff > 0);
  237. case BreakpointConditionGreaterEqual:
  238. return (diff >= 0);
  239. case BreakpointConditionNotEqual:
  240. return (diff != 0);
  241. default:
  242. return (diff == 0);
  243. }
  244. }
  245. inline bool checkFieldName(const char *fieldname)
  246. {
  247. return searchFieldName.isEmpty() || stricmp(searchFieldName, fieldname)==0;
  248. }
  249. public:
  250. SimpleFieldSearcher(const char *_searchFieldName, const char *_expression, BreakpointConditionMode _mode, bool _caseSensitive)
  251. : searchFieldName(_searchFieldName), expression(_expression), mode(_mode), caseSensitive(_caseSensitive)
  252. {
  253. searchString = expression.get();
  254. searchStringLength = expression.length();
  255. matchSeen = false;
  256. boolValueSet = false;
  257. intValueSet = false;
  258. uintValueSet = false;
  259. realValueSet = false;
  260. decimalValueSet = false;
  261. udecimalValueSet = false;
  262. qstringValueSet = false;
  263. if (searchString)
  264. {
  265. if (stricmp(searchString, "true")==0)
  266. boolValueSet = boolValue = true;
  267. else if (stricmp(searchString, "false")==0)
  268. {
  269. boolValueSet = true; boolValue = false;
  270. }
  271. else
  272. {
  273. // MORE - should really support decimal, real, and perhaps esoteric forms of integer (0x.... etc) here....
  274. const char *v = searchString;
  275. bool isNegative = false;
  276. while (isspace(*v))
  277. v++;
  278. if (*v=='-')
  279. {
  280. isNegative = true;
  281. v++;
  282. }
  283. if (isdigit(*v))
  284. {
  285. intValue = 0;
  286. char c;
  287. loop
  288. {
  289. c = *v++;
  290. if ((c >= '0') && (c <= '9'))
  291. intValue = intValue * 10 + (c-'0');
  292. else
  293. break;
  294. }
  295. switch (c)
  296. {
  297. case ' ':
  298. while (isspace(c = *v))
  299. v++;
  300. if (c)
  301. break;
  302. // fall into...
  303. case '\0':
  304. intValueSet = true;
  305. if (isNegative)
  306. intValue = -intValue;
  307. else
  308. uintValueSet = true;
  309. break;
  310. // MORE - want something like...
  311. // case '.':
  312. // TempDecimal.setString().getDecimal()
  313. }
  314. }
  315. }
  316. }
  317. }
  318. virtual bool matched() const { return matchSeen; }
  319. virtual void reset() { matchSeen = false; }
  320. virtual const char *queryFieldName() const { return searchFieldName; }
  321. virtual const char *queryValue() const { return expression; }
  322. virtual bool queryCaseSensitive() const { return caseSensitive; }
  323. virtual void serialize(MemoryBuffer &out) const
  324. {
  325. out.append(searchFieldName).append((char) mode).append(expression).append(caseSensitive);
  326. }
  327. bool canMatchAny(const RtlTypeInfo *recordType)
  328. {
  329. bool sawMatch = false;
  330. ForEachItemIn (idx1, recordTypesCanMatch)
  331. {
  332. if (recordTypesCanMatch.item(idx1) == recordType)
  333. {
  334. if (idx1)
  335. recordTypesCanMatch.swap(0, idx1);
  336. return true;
  337. }
  338. }
  339. ForEachItemIn (idx2, recordTypesCannotMatch)
  340. {
  341. if (recordTypesCannotMatch.item(idx2) == recordType)
  342. {
  343. if (idx2)
  344. recordTypesCannotMatch.swap(0, idx2);
  345. return false;
  346. }
  347. }
  348. const RtlFieldInfo * const * fields = recordType->queryFields();
  349. assertex(fields);
  350. while (*fields)
  351. {
  352. const RtlTypeInfo *childType = fields[0]->type->queryChildType();
  353. if (childType)
  354. {
  355. // MORE - get funky with fieldname.fieldname ? Possible future feature....
  356. if (canMatchAny(childType))
  357. sawMatch = true;
  358. }
  359. if (stricmp(str(fields[0]->name), searchFieldName)==0)
  360. sawMatch = true;
  361. fields++;
  362. }
  363. if (sawMatch)
  364. recordTypesCanMatch.add(recordType, 0);
  365. else
  366. recordTypesCannotMatch.add(recordType, 0);
  367. return sawMatch;
  368. }
  369. virtual bool canMatchAny(IOutputMetaData *meta)
  370. {
  371. bool canMatch = true; // safest assumption...
  372. if (searchFieldName.length())
  373. {
  374. const RtlTypeInfo *typeInfo = meta->queryTypeInfo();
  375. assertex(typeInfo);
  376. if (!canMatchAny(typeInfo))
  377. canMatch = false;
  378. }
  379. return canMatch;
  380. }
  381. IMPLEMENT_IINTERFACE;
  382. virtual void outputInlineXml(const char *xml){}
  383. virtual void outputQuoted(const char *text) { }
  384. virtual void outputString(unsigned len, const char *field, const char *fieldname)
  385. {
  386. if (!matchSeen && checkFieldName(fieldname) && (len >= searchStringLength))
  387. {
  388. int diff = caseSensitive ? memcmp(field,searchString,searchStringLength) : memicmp(field,searchString,searchStringLength);
  389. if (!diff) // little bit suboptimal as some modes don't care about difference between equal and gt - but who cares!
  390. {
  391. // if any remaining char is not space, it's gt
  392. unsigned i = searchStringLength;
  393. while (i < len)
  394. {
  395. if (field[i] != ' ')
  396. {
  397. diff++;
  398. break;
  399. }
  400. i++;
  401. }
  402. }
  403. matchSeen = checkCondition(diff);
  404. }
  405. }
  406. virtual void outputBool(bool field, const char *fieldname)
  407. {
  408. if (boolValueSet && !matchSeen && checkFieldName(fieldname))
  409. {
  410. matchSeen = checkCondition((int) field - (int) boolValue);
  411. }
  412. }
  413. virtual void outputData(unsigned len, const void *field, const char *fieldname)
  414. {
  415. // MORE
  416. }
  417. virtual void outputInt(__int64 field, unsigned size, const char *fieldname)
  418. {
  419. if (intValueSet && !matchSeen && checkFieldName(fieldname))
  420. {
  421. matchSeen = checkCondition((field == intValue) ? 0 : ((field > intValue) ? 1 : -1));
  422. }
  423. }
  424. virtual void outputUInt(unsigned __int64 field, unsigned size, const char *fieldname)
  425. {
  426. // NOTE - "contains" is interpreted as "equals" on numeric fields
  427. if (uintValueSet && !matchSeen && checkFieldName(fieldname))
  428. {
  429. matchSeen = checkCondition((field == intValue) ? 0 : ((field > (unsigned __int64) intValue) ? 1 : -1));
  430. }
  431. }
  432. virtual void outputReal(double field, const char *fieldname)
  433. {
  434. // NOTE - "contains" is interpreted as "equals" on numeric fields
  435. if (realValueSet && !matchSeen && checkFieldName(fieldname))
  436. {
  437. matchSeen = checkCondition((field == realValue) ? 0 : ((field > realValue) ? 1 : -1));
  438. }
  439. }
  440. virtual void outputDecimal(const void *field, unsigned size, unsigned precision, const char *fieldname)
  441. {
  442. // Searching/breaking on decimal not supported at the moment
  443. }
  444. virtual void outputUDecimal(const void *field, unsigned size, unsigned precision, const char *fieldname)
  445. {
  446. // Searching/breaking on decimal not supported at the moment
  447. }
  448. virtual void outputUnicode(unsigned len, const UChar *field, const char *fieldname)
  449. {
  450. // Searching/breaking on unicode not supported at the moment
  451. }
  452. virtual void outputQString(unsigned len, const char *field, const char *fieldname)
  453. {
  454. if (!matchSeen && checkFieldName(fieldname))
  455. {
  456. if (!qstringValueSet)
  457. {
  458. size32_t outlen;
  459. char *out;
  460. rtlStrToQStrX(outlen, out, searchStringLength, searchString);
  461. searchQString.setBuffer(outlen, out, true);
  462. }
  463. matchSeen = checkCondition(rtlCompareQStrQStr(len, field, searchQString.length(), searchQString.toByteArray()));
  464. }
  465. }
  466. virtual void outputUtf8(unsigned len, const char *field, const char *fieldname)
  467. {
  468. // Searching/breaking on unicode not supported at the moment
  469. }
  470. virtual void outputBeginDataset(const char *dsname, bool nestChildren)
  471. {
  472. // nothing for now
  473. }
  474. virtual void outputEndDataset(const char *dsname)
  475. {
  476. // nothing for now
  477. }
  478. virtual void outputBeginNested(const char *fieldname, bool nestChildren)
  479. {
  480. // nothing for now
  481. }
  482. virtual void outputEndNested(const char *fieldname)
  483. {
  484. // nothing for now
  485. }
  486. virtual void outputBeginArray(const char *fieldname)
  487. {
  488. // nothing for now
  489. }
  490. virtual void outputEndArray(const char *fieldname)
  491. {
  492. // nothing for now
  493. }
  494. virtual void outputSetAll()
  495. {
  496. // nothing for now
  497. }
  498. virtual void outputXmlns(const char *prefix, const char *uri)
  499. {
  500. // nothing for now
  501. }
  502. };
  503. class ContainsFieldSearcher : public SimpleFieldSearcher
  504. {
  505. // For most field types, just use equals version. Only meaningful for string types (and only implemented so far for plain ascii)
  506. public:
  507. ContainsFieldSearcher(const char *_searchFieldName, const char *_expression, bool _caseSensitive=true) : SimpleFieldSearcher(_searchFieldName, _expression, BreakpointConditionContains, _caseSensitive)
  508. {
  509. // This is where you set up Boyer-Moore tables...
  510. }
  511. virtual void outputString(unsigned len, const char *field, const char *fieldname)
  512. {
  513. if (!matchSeen && checkFieldName(fieldname) && (len >= searchStringLength)) // could swap those last two tests - last is faster but filters less out...
  514. {
  515. if (searchStringLength==1)
  516. {
  517. if (memchr(field, searchString[0], len))
  518. matchSeen = true;
  519. }
  520. else
  521. {
  522. unsigned steps = len-searchStringLength+1;
  523. for ( unsigned i = 0; i < steps; i++ )
  524. {
  525. if ( !memcmp((char *)field+i,searchString,searchStringLength) ) // MORE - Should I use Boyer-Moore? Probably. Is it worth it in (typically) small search targets?
  526. {
  527. matchSeen = true;
  528. return;
  529. }
  530. }
  531. }
  532. }
  533. }
  534. };
  535. class ContainsNoCaseFieldSearcher : public ContainsFieldSearcher
  536. {
  537. // For most field types, just use equals version. Only meaningful for string types (and only implemented so far for plain ascii)
  538. public:
  539. ContainsNoCaseFieldSearcher(const char *_searchFieldName, const char *_expression) : ContainsFieldSearcher(_searchFieldName, _expression, false)
  540. {
  541. }
  542. virtual void outputString(unsigned len, const char *field, const char *fieldname)
  543. {
  544. if (!matchSeen && checkFieldName(fieldname) && (len >= searchStringLength))
  545. {
  546. unsigned steps = len-searchStringLength+1;
  547. for ( unsigned i = 0; i < steps; i++ )
  548. {
  549. if ( !memicmp((char *)field+i,searchString,searchStringLength) )
  550. {
  551. matchSeen = true;
  552. return;
  553. }
  554. }
  555. }
  556. }
  557. };
  558. class StartsWithFieldSearcher : public SimpleFieldSearcher
  559. {
  560. // For most field types, just use equals version. Only meaningful for string types (and only implemented so far for plain ascii)
  561. public:
  562. StartsWithFieldSearcher(const char *_searchFieldName, const char *_expression, bool _caseSensitive) : SimpleFieldSearcher(_searchFieldName, _expression, BreakpointConditionStartsWith, _caseSensitive)
  563. {
  564. }
  565. virtual void outputString(unsigned len, const char *field, const char *fieldname)
  566. {
  567. if (!matchSeen && checkFieldName(fieldname) && (len >= searchStringLength))
  568. {
  569. int diff = caseSensitive ? memcmp(field,searchString,searchStringLength) : memicmp(field,searchString,searchStringLength);
  570. if (diff == 0)
  571. matchSeen = true;
  572. }
  573. }
  574. };
  575. extern IRowMatcher *createRowMatcher(const char *fieldName, BreakpointConditionMode condition, const char *value, bool caseSensitive)
  576. {
  577. switch (condition)
  578. {
  579. case BreakpointConditionNone:
  580. case BreakpointConditionEOG:
  581. case BreakpointConditionEOF:
  582. return NULL;
  583. case BreakpointConditionLess:
  584. case BreakpointConditionLessEqual:
  585. case BreakpointConditionGreater:
  586. case BreakpointConditionGreaterEqual:
  587. case BreakpointConditionNotEqual:
  588. case BreakpointConditionEquals:
  589. return new SimpleFieldSearcher(fieldName, value, condition, caseSensitive);
  590. case BreakpointConditionContains:
  591. if (caseSensitive)
  592. return new ContainsFieldSearcher(fieldName, value);
  593. else
  594. return new ContainsNoCaseFieldSearcher(fieldName, value);
  595. case BreakpointConditionStartsWith:
  596. return new StartsWithFieldSearcher(fieldName, value, caseSensitive);
  597. default:
  598. throwUnexpected();
  599. }
  600. }
  601. extern IRowMatcher *createRowMatcher(MemoryBuffer &serialized)
  602. {
  603. StringAttr fieldName;
  604. char condition;
  605. StringAttr value;
  606. bool caseSensitive;
  607. serialized.read(fieldName).read(condition).read(value).read(caseSensitive);
  608. return createRowMatcher(fieldName, (BreakpointConditionMode) condition, value, caseSensitive);
  609. }
  610. //===============================================================================================
  611. CBreakpointInfo::CBreakpointInfo(BreakpointMode _mode, const char *_id, BreakpointActionMode _action,
  612. const char *_fieldName, BreakpointConditionMode _condition, const char *_value, bool _caseSensitive,
  613. unsigned _rowCount, BreakpointCountMode _rowCountMode)
  614. : mode(_mode), id(_id), action(_action), condition(_condition),
  615. rowCount(_rowCount), rowCountMode(_rowCountMode)
  616. {
  617. uid = nextUID();
  618. rowMatcher.setown(createRowMatcher(_fieldName, _condition, _value, _caseSensitive));
  619. }
  620. CBreakpointInfo::CBreakpointInfo(BreakpointMode _mode) : mode(_mode)
  621. {
  622. uid = 0; // reserved for the dummy breakpoint
  623. action = BreakpointActionContinue;
  624. rowCount = 0;
  625. rowCountMode = BreakpointCountNone;
  626. condition = BreakpointConditionNone;
  627. }
  628. CBreakpointInfo::CBreakpointInfo(MemoryBuffer &from)
  629. {
  630. from.read(uid);
  631. from.read(id);
  632. char temp;
  633. from.read(temp); mode = (BreakpointMode) temp;
  634. from.read(temp); action = (BreakpointActionMode) temp;
  635. from.read(rowCount);
  636. from.read(temp); rowCountMode = (BreakpointCountMode) temp;
  637. from.read(temp); condition = (BreakpointConditionMode) temp;
  638. switch (condition)
  639. {
  640. case BreakpointConditionNone:
  641. case BreakpointConditionEOG:
  642. case BreakpointConditionEOF:
  643. break;
  644. default:
  645. StringAttr fieldName, value;
  646. bool caseSensitive;
  647. from.read(fieldName);
  648. from.read(value);
  649. from.read(caseSensitive);
  650. rowMatcher.setown(createRowMatcher(fieldName, condition, value, caseSensitive));
  651. }
  652. }
  653. void CBreakpointInfo::serialize(MemoryBuffer &to) const
  654. {
  655. to.append(uid);
  656. to.append(id);
  657. to.append((char) mode);
  658. to.append((char) action);
  659. to.append(rowCount);
  660. to.append((char) rowCountMode);
  661. to.append((char) condition);
  662. if (rowMatcher)
  663. {
  664. to.append(rowMatcher->queryFieldName());
  665. to.append(rowMatcher->queryValue());
  666. to.append(rowMatcher->queryCaseSensitive());
  667. }
  668. }
  669. SpinLock CBreakpointInfo::UIDlock;
  670. unsigned CBreakpointInfo::nextUIDvalue;
  671. unsigned CBreakpointInfo::queryUID() const
  672. {
  673. return uid;
  674. }
  675. void CBreakpointInfo::noteEdge(IActivityDebugContext &edge)
  676. {
  677. activeEdges.append(edge);
  678. }
  679. void CBreakpointInfo::removeEdge(IActivityDebugContext &edge)
  680. {
  681. activeEdges.zap(edge);
  682. }
  683. bool CBreakpointInfo::equals(IBreakpointInfo &other) const
  684. {
  685. CBreakpointInfo *bp = QUERYINTERFACE(&other, CBreakpointInfo);
  686. if (bp)
  687. {
  688. // NOTE - not very efficient but that's not an issue here!
  689. CommonXmlWriter me(0,0);
  690. CommonXmlWriter him(0,0);
  691. toXML(&me);
  692. bp->toXML(&him);
  693. return strcmp(me.str(), him.str())==0;
  694. }
  695. else
  696. return false;
  697. }
  698. bool CBreakpointInfo::canMatchAny(IOutputMetaData *meta)
  699. {
  700. if (rowMatcher)
  701. return rowMatcher->canMatchAny(meta);
  702. else
  703. return true;
  704. }
  705. bool CBreakpointInfo::matches(const void *row, bool isEOF, unsigned edgeRowCount, IOutputMetaData *meta) const
  706. {
  707. // First check the conditions
  708. switch (condition)
  709. {
  710. case BreakpointConditionNone:
  711. break;
  712. case BreakpointConditionEOG:
  713. if (row)
  714. return false;
  715. break;
  716. case BreakpointConditionEOF:
  717. if (row || !(meta->isGrouped() || isEOF))
  718. return false;
  719. break;
  720. default:
  721. if (rowMatcher)
  722. {
  723. if (!row)
  724. return false;
  725. rowMatcher->reset();
  726. meta->toXML((const byte *) row, *rowMatcher);
  727. if (!rowMatcher->matched())
  728. return false; // expression failed
  729. }
  730. else
  731. throwUnexpected();
  732. }
  733. // ok, we've been hit.
  734. if (rowCount)
  735. {
  736. switch (rowCountMode)
  737. {
  738. case BreakpointCountEquals:
  739. return (edgeRowCount == rowCount);
  740. case BreakpointCountAtleast:
  741. return (edgeRowCount >= rowCount);
  742. default:
  743. throwUnexpected();
  744. }
  745. }
  746. else
  747. return true;
  748. }
  749. bool CBreakpointInfo::idMatch(BreakpointMode _mode, const char *_id) const
  750. {
  751. if (mode==_mode)
  752. {
  753. if (mode==BreakpointModeGraph && !id.length())
  754. return true;
  755. if (strcmp(id.get(), _id)==0)
  756. return true;
  757. // See if it matches up to the first .
  758. const char *dotpos = strchr(_id, '.');
  759. if (dotpos)
  760. {
  761. unsigned len = dotpos-_id;
  762. if (len == id.length() && strncmp(id.get(), _id, len)==0)
  763. return true;
  764. }
  765. }
  766. return false;
  767. }
  768. BreakpointMode CBreakpointInfo::queryMode() const
  769. {
  770. return mode;
  771. }
  772. BreakpointActionMode CBreakpointInfo::queryAction() const
  773. {
  774. return action;
  775. }
  776. void CBreakpointInfo::toXML(IXmlWriter *output) const
  777. {
  778. output->outputCString(BreakpointModes[mode], "@mode");
  779. if (id) output->outputCString(id, "@id");
  780. output->outputCString(BreakpointActionModes[action], "@action");
  781. if (condition != BreakpointConditionNone)
  782. {
  783. output->outputCString(BreakpointConditionModes[condition], "@condition");
  784. if (rowMatcher)
  785. {
  786. if (rowMatcher->queryFieldName()) output->outputCString(rowMatcher->queryFieldName(), "@fieldName");
  787. if (rowMatcher->queryValue()) output->outputCString(rowMatcher->queryValue(), "@value");
  788. output->outputBool(rowMatcher->queryCaseSensitive(), "@caseSensitive");
  789. }
  790. }
  791. if (rowCount)
  792. {
  793. output->outputInt(rowCount, sizeof(int), "@rowCount");
  794. output->outputCString(BreakpointCountModes[rowCountMode], "@rowCountMode");
  795. }
  796. ForEachItemIn(edgeIdx, activeEdges)
  797. {
  798. IActivityDebugContext &edge = activeEdges.item(edgeIdx);
  799. output->outputBeginNested("edge", false);
  800. output->outputCString(edge.queryEdgeId(), "@edgeId");
  801. output->outputEndNested("edge");
  802. }
  803. }
  804. //=======================================================================================
  805. DebugActivityRecord::DebugActivityRecord (IActivityBase *_activity, unsigned _iteration, unsigned _channel, unsigned _sequence)
  806. : activity(_activity),iteration(_iteration),channel(_channel),sequence(_sequence)
  807. {
  808. localCycles = 0;
  809. totalCycles = 0;
  810. StringAttrBuilder fullId(idText);
  811. fullId.append(activity->queryId());
  812. if (iteration || channel)
  813. fullId.appendf(".%d", iteration);
  814. if (channel)
  815. fullId.appendf("#%d", channel);
  816. }
  817. void DebugActivityRecord::outputId(IXmlWriter *output, const char *fieldName)
  818. {
  819. output->outputString(idText.length(), idText.str(), fieldName);
  820. }
  821. const char *DebugActivityRecord::queryIdString()
  822. {
  823. return idText;
  824. }
  825. void DebugActivityRecord::outputProperties(IXmlWriter *output)
  826. {
  827. if (properties)
  828. {
  829. Owned<IPropertyIterator> iterator = properties->getIterator();
  830. iterator->first();
  831. while (iterator->isValid())
  832. {
  833. const char *propName = iterator->getPropKey();
  834. const char *propValue = properties->queryProp(propName);
  835. output->outputBeginNested("att", false); output->outputCString(propName, "@name"); output->outputCString(propValue, "@value"); output->outputEndNested("att");
  836. iterator->next();
  837. }
  838. }
  839. if (localCycles)
  840. {
  841. output->outputBeginNested("att", false);
  842. output->outputCString("localTime", "@name");
  843. output->outputUInt((unsigned) (cycle_to_nanosec(localCycles)/1000), sizeof(unsigned), "@value");
  844. output->outputEndNested("att");
  845. }
  846. if (totalCycles)
  847. {
  848. output->outputBeginNested("att", false);
  849. output->outputCString("totalTime", "@name");
  850. output->outputUInt((unsigned) (cycle_to_nanosec(totalCycles)/1000), sizeof(unsigned), "@value");
  851. output->outputEndNested("att");
  852. }
  853. }
  854. void DebugActivityRecord::setProperty(const char *propName, const char *propValue, unsigned _sequence)
  855. {
  856. if (!properties)
  857. properties.setown(createProperties(false));
  858. properties->setProp(propName, propValue);
  859. sequence = _sequence;
  860. }
  861. void DebugActivityRecord::updateTimes(unsigned _sequence)
  862. {
  863. unsigned __int64 newTotal = activity->queryTotalCycles();
  864. unsigned __int64 newLocal = activity->queryLocalCycles();
  865. if (localCycles != newLocal || totalCycles != newTotal)
  866. {
  867. localCycles = newLocal;
  868. totalCycles = newTotal;
  869. sequence = _sequence;
  870. }
  871. }
  872. //=======================================================================================
  873. const char * CBaseDebugContext::queryStateString(DebugState state)
  874. {
  875. switch (state)
  876. {
  877. case DebugStateCreated: return "created";
  878. case DebugStateLoading: return "loading";
  879. case DebugStateRunning: return "running";
  880. case DebugStateEdge: return "edge";
  881. case DebugStateBreakpoint: return "breakpoint";
  882. case DebugStateReady: return "created";
  883. case DebugStateGraphCreate: return "graph create";
  884. case DebugStateGraphStart: return "graph start";
  885. case DebugStateGraphEnd: return "graph end";
  886. case DebugStateGraphAbort: return "graph abort";
  887. case DebugStateException: return "exception";
  888. case DebugStateFailed: return "failed";
  889. case DebugStateFinished: return "finished";
  890. case DebugStateUnloaded: return "unloaded";
  891. case DebugStateQuit: return "quit";
  892. case DebugStateDetached: return "detached";
  893. case DebugStateLimit: return "limit hit";
  894. case DebugStateGraphFinished: return "graph finished";
  895. default: throwUnexpected();
  896. }
  897. }
  898. bool CBaseDebugContext::_checkPendingBreakpoints(DebugState state, const char *graphName)
  899. {
  900. bool stop = false;
  901. ForEachItemIn(idx, breakpoints)
  902. {
  903. IBreakpointInfo &bp = breakpoints.item(idx);
  904. if (bp.queryMode()==BreakpointModeGraph)
  905. {
  906. stop = stop || bp.idMatch(BreakpointModeGraph, graphName);
  907. }
  908. else
  909. {
  910. if (state==DebugStateGraphStart)
  911. currentGraph->setBreakpoint(bp);
  912. }
  913. }
  914. return stop;
  915. }
  916. CBaseDebugContext::CBaseDebugContext(const IContextLogger &_logctx) : logctx(_logctx)
  917. {
  918. currentGraph = NULL;
  919. graphChangeSequence = 0;
  920. prevGraphChangeSequence = 0;
  921. pendingBreakpointsDone = false;
  922. sequence = 1;
  923. defaultHistoryCapacity = 10;
  924. executeSequentially = true;
  925. running = true;
  926. detached = false;
  927. watchState = WatchStateContinue;
  928. currentBreakpointUID = (unsigned) -1;
  929. debuggerActive = 0;
  930. currentState = DebugStateCreated;
  931. skipRequested = false;
  932. stopOnLimits = true;
  933. debugCyclesAdjust = 0;
  934. }
  935. unsigned __int64 CBaseDebugContext::getCyclesAdjustment() const
  936. {
  937. return debugCyclesAdjust;
  938. }
  939. void CBaseDebugContext::noteGraphChanged()
  940. {
  941. graphChangeSequence++;
  942. }
  943. IGlobalEdgeRecord *CBaseDebugContext::getEdgeRecord(const char *edgeId)
  944. {
  945. Linked<IGlobalEdgeRecord> edgeRecord = globalCounts.getValue(edgeId);
  946. if (!edgeRecord)
  947. {
  948. edgeRecord.setown(new DebugEdgeRecord(sequence));
  949. globalCounts.setValue(edgeId, edgeRecord);
  950. }
  951. return edgeRecord.getClear();
  952. }
  953. void CBaseDebugContext::addBreakpoint(IBreakpointInfo &bp)
  954. {
  955. if (currentGraph)
  956. currentGraph->setBreakpoint(bp);
  957. breakpoints.append(bp);
  958. }
  959. void CBaseDebugContext::removeBreakpoint(IBreakpointInfo &bp)
  960. {
  961. ForEachItemIn(idx, breakpoints)
  962. {
  963. if (breakpoints.item(idx).queryUID()==bp.queryUID())
  964. {
  965. if (currentGraph)
  966. currentGraph->removeBreakpoint(breakpoints.item(idx));
  967. breakpoints.remove(idx);
  968. break;
  969. }
  970. }
  971. }
  972. unsigned CBaseDebugContext::queryChannel() const
  973. {
  974. return 0;
  975. }
  976. void CBaseDebugContext::debugInitialize(const char *id, const char *_queryName, bool _breakAtStart)
  977. {
  978. throwUnexpected(); // Should only happen on server
  979. }
  980. void CBaseDebugContext::debugTerminate()
  981. {
  982. throwUnexpected(); // Should only happen on server
  983. }
  984. IBreakpointInfo *CBaseDebugContext::findBreakpoint(unsigned uid) const
  985. {
  986. ForEachItemIn(idx, breakpoints)
  987. {
  988. if (breakpoints.item(idx).queryUID()==uid)
  989. return &breakpoints.item(idx);
  990. }
  991. // we don't really expect to get here...
  992. throwUnexpected();
  993. return NULL;
  994. }
  995. BreakpointActionMode CBaseDebugContext::checkBreakpoint(DebugState state, IActivityDebugContext *probe, const void *extra)
  996. {
  997. if (detached)
  998. return BreakpointActionContinue;
  999. class ActivityTimer
  1000. {
  1001. cycle_t startCycles;
  1002. cycle_t &accumulator;
  1003. public:
  1004. inline ActivityTimer(cycle_t &_accumulator) : accumulator(_accumulator)
  1005. {
  1006. startCycles = get_cycles_now();
  1007. }
  1008. inline ~ActivityTimer()
  1009. {
  1010. cycle_t elapsed = get_cycles_now() - startCycles;
  1011. accumulator += elapsed;
  1012. }
  1013. } timer(debugCyclesAdjust);
  1014. CriticalBlock b(breakCrit); // Note - this may block for a while if program is suspended!
  1015. assertex(running);
  1016. bool stop = false;
  1017. currentNode.clear();
  1018. if (watchState == WatchStateQuit)
  1019. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Query aborted by debugger");
  1020. if (state==DebugStateEdge)
  1021. {
  1022. // Check whether there is a breakpoint etc active for this activityId
  1023. IBreakpointInfo *bp;
  1024. if (currentBreakpointUID != (unsigned) -1)
  1025. bp = findBreakpoint(currentBreakpointUID);
  1026. else if (probe)
  1027. bp = probe->debuggerCallback(sequence, extra);
  1028. else
  1029. bp = NULL;
  1030. if (bp)
  1031. {
  1032. BreakpointActionMode action = bp->queryAction();
  1033. if (action != BreakpointActionBreak)
  1034. return action;
  1035. stop = true;
  1036. currentBreakpointUID = bp->queryUID();
  1037. }
  1038. else
  1039. {
  1040. switch (watchState)
  1041. {
  1042. case WatchStateStep:
  1043. stop = true;
  1044. break;
  1045. case WatchStateNext:
  1046. stop = (probe==nextActivity); // MORE - proxy activities need to be compared more carefully
  1047. break;
  1048. case WatchStateOver:
  1049. stop = (probe->queryInputActivity()==nextActivity); // MORE - doesn't work where multiple inputs or when debugging slave graph - think about proxy too
  1050. break;
  1051. case WatchStateGraph:
  1052. case WatchStateContinue:
  1053. stop = false;
  1054. break;
  1055. default:
  1056. throwUnexpected();
  1057. break;
  1058. }
  1059. }
  1060. }
  1061. else if (state==DebugStateGraphCreate)
  1062. pendingBreakpointsDone = false;
  1063. else if (state==DebugStateGraphStart || state==DebugStateGraphEnd || state==DebugStateGraphAbort)
  1064. {
  1065. stop = _checkPendingBreakpoints(state, (const char *) extra);
  1066. pendingBreakpointsDone = true;
  1067. switch (watchState)
  1068. {
  1069. case WatchStateGraph:
  1070. stop = true;
  1071. break;
  1072. case WatchStateStep:
  1073. case WatchStateNext:
  1074. stop = true;
  1075. break;
  1076. case WatchStateContinue:
  1077. // stop already set above...
  1078. break;
  1079. default:
  1080. throwUnexpected();
  1081. break;
  1082. }
  1083. #if 0
  1084. // I don't think this works, and the global count stuff will supercede it
  1085. if (state==DebugStateGraphEnd || state==DebugStateGraphAbort)
  1086. {
  1087. CommonXmlWriter finalGraphXML(0, 1);
  1088. currentGraph->getXGMML(&finalGraphXML, 0, false);
  1089. if (!completedGraphs)
  1090. completedGraphs.setown(createProperties(false));
  1091. completedGraphs->setProp(currentGraph->queryGraphName(), finalGraphXML.str());
  1092. }
  1093. #endif
  1094. }
  1095. else if (state==DebugStateFinished)
  1096. {
  1097. currentGraph = NULL;
  1098. graphChangeSequence++;
  1099. stop = true;
  1100. }
  1101. else if (state==DebugStateException)
  1102. {
  1103. IException *E = (IException *) extra;
  1104. if (E != currentException)
  1105. {
  1106. currentException.set(E);
  1107. stop = true;
  1108. }
  1109. else
  1110. stop = false;
  1111. }
  1112. else if (state==DebugStateLimit)
  1113. {
  1114. if (stopOnLimits)
  1115. {
  1116. stop = true;
  1117. IActivityBase *activity = (IActivityBase *) extra;
  1118. assertex(currentGraph);
  1119. currentNode.setown(currentGraph->getNodeByActivityBase(activity));
  1120. }
  1121. }
  1122. else
  1123. stop = true;
  1124. if (!stop)
  1125. return BreakpointActionContinue;
  1126. {
  1127. CriticalBlock b(debugCrit);
  1128. currentActivity.set(probe);
  1129. running = false;
  1130. currentState = state;
  1131. if (currentActivity)
  1132. logctx.CTXLOG("DEBUG: paused waiting for debugger, state %s, edge %s", queryStateString(state), currentActivity->queryEdgeId());
  1133. else
  1134. logctx.CTXLOG("DEBUG: paused waiting for debugger, state %s, edge '(none)'", queryStateString(state));
  1135. if (debuggerActive) // Was the debugger actively waiting for the program to hit a breakpoint?
  1136. {
  1137. debuggerSem.signal(debuggerActive);
  1138. debuggerActive = 0;
  1139. }
  1140. }
  1141. waitForDebugger(state, probe);
  1142. {
  1143. CriticalBlock b(debugCrit);
  1144. running = true;
  1145. BreakpointActionMode ret = skipRequested ? BreakpointActionSkip : BreakpointActionContinue;
  1146. skipRequested = false;
  1147. currentBreakpointUID = (unsigned) -1;
  1148. return ret;
  1149. }
  1150. }
  1151. void CBaseDebugContext::noteManager(IDebugGraphManager *mgr)
  1152. {
  1153. currentGraph = mgr;
  1154. graphChangeSequence++;
  1155. }
  1156. void CBaseDebugContext::releaseManager(IDebugGraphManager *mgr)
  1157. {
  1158. if(currentGraph==mgr)
  1159. currentGraph = NULL;
  1160. graphChangeSequence++;
  1161. }
  1162. unsigned CBaseDebugContext::querySequence()
  1163. {
  1164. return ++sequence;
  1165. }
  1166. unsigned CBaseDebugContext::getDefaultHistoryCapacity() const
  1167. {
  1168. return defaultHistoryCapacity;
  1169. }
  1170. bool CBaseDebugContext::getExecuteSequentially() const
  1171. {
  1172. return executeSequentially;
  1173. }
  1174. void CBaseDebugContext::checkDelayedBreakpoints(IActivityDebugContext *edge)
  1175. {
  1176. if (pendingBreakpointsDone) // Don't bother if the graph is still being created.... we can do them all more efficiently.
  1177. {
  1178. // This code is for edges created AFTER the bulk of the graph is created, which missed out on the normal delayed breakpoint setting...
  1179. graphChangeSequence++;
  1180. ForEachItemIn(bpIdx, breakpoints)
  1181. {
  1182. IBreakpointInfo &breakpoint = breakpoints.item(bpIdx);
  1183. if (breakpoint.idMatch(BreakpointModeEdge, edge->queryEdgeId()))
  1184. edge->setBreakpoint(breakpoint);
  1185. }
  1186. }
  1187. }
  1188. void CBaseDebugContext::serialize(MemoryBuffer &buff) const
  1189. {
  1190. buff.append((unsigned short) breakpoints.length());
  1191. ForEachItemIn(idx, breakpoints)
  1192. {
  1193. breakpoints.item(idx).serialize(buff);
  1194. }
  1195. buff.append(running).append(detached).append((unsigned char) watchState).append(sequence).append(skipRequested).append(stopOnLimits);
  1196. }
  1197. void CBaseDebugContext::deserialize(MemoryBuffer &buff)
  1198. {
  1199. // MORE - this is rather inefficient - we remove all breakpoints then reapply. But may be good enough...
  1200. if (currentGraph)
  1201. {
  1202. ForEachItemIn(idx, breakpoints)
  1203. {
  1204. IBreakpointInfo &bp = breakpoints.item(idx);
  1205. currentGraph->removeBreakpoint(bp);
  1206. }
  1207. }
  1208. breakpoints.kill();
  1209. unsigned short numBreaks;
  1210. buff.read(numBreaks);
  1211. while (numBreaks--)
  1212. {
  1213. IBreakpointInfo &bp = *new CBreakpointInfo(buff);
  1214. breakpoints.append(bp);
  1215. if (currentGraph)
  1216. currentGraph->setBreakpoint(bp);
  1217. }
  1218. pendingBreakpointsDone = true;
  1219. unsigned char watchStateChar;
  1220. buff.read(running).read(detached).read(watchStateChar).read(sequence).read(skipRequested).read(stopOnLimits);
  1221. watchState = (WatchState) watchStateChar;
  1222. }
  1223. //=======================================================================================
  1224. void CBaseServerDebugContext::doStandardResult(IXmlWriter *output) const
  1225. {
  1226. const char *stateString = running ? "running" : queryStateString(currentState);
  1227. output->outputInt(sequence, sizeof(int), "@sequence");
  1228. output->outputString(strlen(stateString), stateString, "@state");
  1229. if (currentNode)
  1230. currentNode->outputId(output, "@nodeId");
  1231. if (currentActivity)
  1232. output->outputCString(currentActivity->queryEdgeId(), "@edgeId");
  1233. if (skipRequested)
  1234. output->outputBool(true, "@skip");
  1235. if (currentGraph)
  1236. output->outputCString(currentGraph->queryGraphName(), "@graphId");
  1237. output->outputInt(graphChangeSequence, sizeof(int), "@graphSequenceNum");
  1238. if (graphChangeSequence != prevGraphChangeSequence)
  1239. output->outputBool(true, "@graphChanged");
  1240. if (currentBreakpointUID != (unsigned) -1)
  1241. {
  1242. IBreakpointInfo *bp = findBreakpoint(currentBreakpointUID);
  1243. _listBreakpoint(output, *bp, breakpoints.find(*bp));
  1244. }
  1245. if (currentException)
  1246. {
  1247. output->outputBeginNested("Exception", true);
  1248. output->outputCString("Roxie", "Source");
  1249. output->outputInt(currentException->errorCode(), sizeof(int), "Code");
  1250. StringBuffer s;
  1251. currentException->errorMessage(s);
  1252. output->outputString(s.length(), s.str(), "Message");
  1253. output->outputEndNested("Exception");
  1254. }
  1255. }
  1256. void CBaseServerDebugContext::_listBreakpoint(IXmlWriter *output, IBreakpointInfo &bp, unsigned idx) const
  1257. {
  1258. if (bp.queryMode() != BreakpointModeNone)
  1259. {
  1260. output->outputBeginNested("break", true);
  1261. output->outputInt(idx, sizeof(int), "@idx");
  1262. bp.toXML(output);
  1263. output->outputEndNested("break");
  1264. }
  1265. }
  1266. void CBaseServerDebugContext::_continue(WatchState watch)
  1267. {
  1268. if (running)
  1269. throw MakeStringException(THORHELPER_INTERNAL_ERROR, "Query already running");
  1270. if (watch==WatchStateNext || watch==WatchStateOver)
  1271. {
  1272. if (!currentActivity)
  1273. throw MakeStringException(THORHELPER_INTERNAL_ERROR, "next: no current activity");
  1274. nextActivity.set(currentActivity);
  1275. }
  1276. else
  1277. nextActivity.clear();
  1278. watchState = watch;
  1279. previousSequence = sequence;
  1280. prevGraphChangeSequence = graphChangeSequence;
  1281. debuggerActive++;
  1282. debugeeSem.signal();
  1283. {
  1284. CriticalUnblock b(debugCrit);
  1285. debuggerSem.wait(); // MORE - is that actually correct, to release the crit while waiting? Think...
  1286. }
  1287. }
  1288. unsigned CBaseServerDebugContext::checkOption(const char *supplied, const char *name, const char *accepted[])
  1289. {
  1290. if (supplied)
  1291. {
  1292. unsigned idx = 0;
  1293. while (accepted[idx])
  1294. {
  1295. if (strcmp(accepted[idx], supplied)==0)
  1296. return idx;
  1297. idx++;
  1298. }
  1299. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Invalid parameter value %s='%s'", name, supplied);
  1300. }
  1301. else
  1302. return 0; // first is default
  1303. }
  1304. IBreakpointInfo *CBaseServerDebugContext::createDummyBreakpoint()
  1305. {
  1306. return new CBreakpointInfo(BreakpointModeNone);
  1307. }
  1308. IBreakpointInfo *CBaseServerDebugContext::_createBreakpoint(const char *modeString, const char *id, const char *action,
  1309. const char *fieldName, const char *condition, const char *value, bool caseSensitive,
  1310. unsigned hitCount, const char *hitCountMode)
  1311. {
  1312. BreakpointMode mode = (BreakpointMode) checkOption(modeString, "mode", BreakpointModes);
  1313. if (!id)
  1314. {
  1315. if (mode==BreakpointModeEdge)
  1316. {
  1317. if (!currentActivity)
  1318. throw MakeStringException(THORHELPER_DEBUG_ERROR, "No current activity");
  1319. id = currentActivity->queryEdgeId();
  1320. }
  1321. else if (mode==BreakpointModeNode)
  1322. {
  1323. if (!currentActivity)
  1324. throw MakeStringException(THORHELPER_DEBUG_ERROR, "No current activity");
  1325. id = currentActivity->querySourceId();
  1326. }
  1327. }
  1328. return new CBreakpointInfo(mode, id, (BreakpointActionMode) checkOption(action, "action", BreakpointActionModes),
  1329. fieldName, (BreakpointConditionMode) checkOption(condition, "condition", BreakpointConditionModes), value, caseSensitive,
  1330. hitCount, (BreakpointCountMode) checkOption(hitCountMode, "hitCountMode", BreakpointCountModes));
  1331. }
  1332. void CBaseServerDebugContext::waitForDebugger(DebugState state, IActivityDebugContext *probe)
  1333. {
  1334. sequence++;
  1335. while (!debugeeSem.wait(DEBUGEE_TIMEOUT))
  1336. {
  1337. if (onDebuggerTimeout())
  1338. break;
  1339. }
  1340. sequence++;
  1341. }
  1342. CBaseServerDebugContext::CBaseServerDebugContext(const IContextLogger &_logctx, IPropertyTree *_queryXGMML, SafeSocket &_client)
  1343. : CBaseDebugContext(_logctx), queryXGMML(_queryXGMML), client(_client)
  1344. {
  1345. sequence = 0;
  1346. previousSequence = 0;
  1347. breakpoints.append(*createDummyBreakpoint()); // temporary breakpoint always present
  1348. }
  1349. void CBaseServerDebugContext::serializeBreakpoints(MemoryBuffer &to)
  1350. {
  1351. to.append(breakpoints.length());
  1352. ForEachItemIn(idx, breakpoints)
  1353. breakpoints.item(idx).serialize(to);
  1354. }
  1355. void CBaseServerDebugContext::debugInitialize(const char *id, const char *_queryName, bool _breakAtStart)
  1356. {
  1357. if (!_breakAtStart)
  1358. detached = true;
  1359. debugId.set(id);
  1360. queryName.set(_queryName);
  1361. currentState = DebugStateLoading;
  1362. }
  1363. void CBaseServerDebugContext::debugTerminate()
  1364. {
  1365. CriticalBlock b(debugCrit);
  1366. assertex(running);
  1367. currentState = DebugStateUnloaded;
  1368. running = false;
  1369. if (debuggerActive)
  1370. {
  1371. debuggerSem.signal(debuggerActive);
  1372. debuggerActive = 0;
  1373. }
  1374. }
  1375. void CBaseServerDebugContext::addBreakpoint(IXmlWriter *output, const char *modeString, const char *id, const char *action,
  1376. const char *fieldName, const char *condition, const char *value, bool caseSensitive,
  1377. unsigned hitCount, const char *hitCountMode)
  1378. {
  1379. CriticalBlock b(debugCrit);
  1380. if (running)
  1381. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available while query is running");
  1382. Owned<IBreakpointInfo> newBreakpoint = _createBreakpoint(modeString, id, action, fieldName, condition, value, caseSensitive, hitCount, hitCountMode);
  1383. // For breakpoints to be efficient we need to set them in the probe, though because the activity probe may not exist yet, we should also
  1384. // keep a central list (also makes it easier to do things like list breakpoint info...)
  1385. ForEachItemIn(idx, breakpoints)
  1386. {
  1387. IBreakpointInfo &bp = breakpoints.item(idx);
  1388. if (bp.equals(*newBreakpoint))
  1389. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Breakpoint already exists");
  1390. }
  1391. _listBreakpoint(output, *newBreakpoint, breakpoints.ordinality());
  1392. CBaseDebugContext::addBreakpoint(*newBreakpoint.getClear());
  1393. }
  1394. void CBaseServerDebugContext::removeBreakpoint(IXmlWriter *output, unsigned removeIdx)
  1395. {
  1396. CriticalBlock b(debugCrit);
  1397. if (running)
  1398. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available while query is running");
  1399. assertex(removeIdx);
  1400. if (!breakpoints.isItem(removeIdx))
  1401. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Breakpoint %d does not exist", removeIdx);
  1402. IBreakpointInfo &bp = breakpoints.item(removeIdx);
  1403. _listBreakpoint(output, bp, removeIdx);
  1404. if (currentGraph)
  1405. currentGraph->removeBreakpoint(bp);
  1406. breakpoints.replace(*createDummyBreakpoint(), removeIdx);
  1407. }
  1408. void CBaseServerDebugContext::removeAllBreakpoints(IXmlWriter *output)
  1409. {
  1410. ForEachItemIn(idx, breakpoints)
  1411. {
  1412. IBreakpointInfo &bp = breakpoints.item(idx);
  1413. _listBreakpoint(output, bp, idx);
  1414. if (currentGraph)
  1415. currentGraph->removeBreakpoint(bp);
  1416. breakpoints.replace(*createDummyBreakpoint(), idx);
  1417. }
  1418. }
  1419. void CBaseServerDebugContext::listBreakpoint(IXmlWriter *output, unsigned listIdx) const
  1420. {
  1421. // MORE - fair amount could be commoned up with remove...
  1422. CriticalBlock b(debugCrit);
  1423. if (running)
  1424. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available while query is running");
  1425. assertex(listIdx);
  1426. if (!breakpoints.isItem(listIdx))
  1427. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Breakpoint %d does not exist", listIdx);
  1428. IBreakpointInfo &bp = breakpoints.item(listIdx);
  1429. _listBreakpoint(output, bp, listIdx);
  1430. }
  1431. void CBaseServerDebugContext::listAllBreakpoints(IXmlWriter *output) const
  1432. {
  1433. ForEachItemIn(idx, breakpoints)
  1434. {
  1435. IBreakpointInfo &bp = breakpoints.item(idx);
  1436. _listBreakpoint(output, bp, idx);
  1437. }
  1438. }
  1439. void CBaseServerDebugContext::debugInterrupt(IXmlWriter *output)
  1440. {
  1441. CriticalBlock b(debugCrit);
  1442. if (!running)
  1443. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Query is already paused"); // MORE - or has terminated?
  1444. detached = false;
  1445. nextActivity.clear();
  1446. watchState = WatchStateStep;
  1447. debuggerActive++;
  1448. {
  1449. CriticalUnblock b(debugCrit);
  1450. debuggerSem.wait(); // MORE - should this be inside critsec? Should it be there at all?
  1451. }
  1452. doStandardResult(output);
  1453. }
  1454. void CBaseServerDebugContext::debugContinue(IXmlWriter *output, const char *modeString, const char *id)
  1455. {
  1456. CriticalBlock b(debugCrit);
  1457. Owned<IBreakpointInfo> tempBreakpoint;
  1458. if (id)
  1459. {
  1460. tempBreakpoint.setown(_createBreakpoint(modeString, id));
  1461. if (currentGraph)
  1462. currentGraph->setBreakpoint(*tempBreakpoint);
  1463. breakpoints.replace(*LINK(tempBreakpoint), 0);
  1464. }
  1465. _continue(WatchStateContinue);
  1466. doStandardResult(output);
  1467. if (tempBreakpoint)
  1468. {
  1469. if (currentGraph)
  1470. currentGraph->removeBreakpoint(*tempBreakpoint);
  1471. breakpoints.replace(*createDummyBreakpoint(), 0);
  1472. }
  1473. }
  1474. void CBaseServerDebugContext::debugRun(IXmlWriter *output)
  1475. {
  1476. CriticalBlock b(debugCrit);
  1477. if (running)
  1478. throw MakeStringException(THORHELPER_INTERNAL_ERROR, "Query already running");
  1479. watchState = WatchStateContinue;
  1480. detached = true;
  1481. if (currentGraph)
  1482. currentGraph->clearHistories();
  1483. currentState = DebugStateDetached;
  1484. currentActivity.clear();
  1485. currentBreakpointUID = (unsigned) -1;
  1486. previousSequence = sequence;
  1487. debugeeSem.signal();
  1488. doStandardResult(output);
  1489. }
  1490. void CBaseServerDebugContext::debugQuit(IXmlWriter *output)
  1491. {
  1492. CriticalBlock b(debugCrit);
  1493. detached = false;
  1494. nextActivity.clear();
  1495. watchState = WatchStateQuit;
  1496. currentState = DebugStateQuit;
  1497. currentActivity.clear();
  1498. currentBreakpointUID = (unsigned) -1;
  1499. if (!running)
  1500. {
  1501. debugeeSem.signal();
  1502. }
  1503. doStandardResult(output);
  1504. }
  1505. void CBaseServerDebugContext::debugSkip(IXmlWriter *output)
  1506. {
  1507. CriticalBlock b(debugCrit);
  1508. if (running)
  1509. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available while query is running");
  1510. if (!currentActivity)
  1511. throw MakeStringException(THORHELPER_DEBUG_ERROR, "No current activity");
  1512. skipRequested = true;
  1513. doStandardResult(output);
  1514. }
  1515. void CBaseServerDebugContext::debugStatus(IXmlWriter *output) const
  1516. {
  1517. CriticalBlock b(debugCrit);
  1518. doStandardResult(output);
  1519. }
  1520. void CBaseServerDebugContext::debugStep(IXmlWriter *output, const char *modeString)
  1521. {
  1522. CriticalBlock b(debugCrit);
  1523. WatchState state;
  1524. if (modeString)
  1525. {
  1526. if (strcmp(modeString, "graph")==0)
  1527. state = WatchStateGraph;
  1528. else if (strcmp(modeString, "edge")==0)
  1529. state = WatchStateStep;
  1530. else
  1531. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Step mode should be edge or graph");
  1532. }
  1533. else
  1534. state = WatchStateStep;
  1535. _continue(state);
  1536. doStandardResult(output);
  1537. }
  1538. void CBaseServerDebugContext::debugNext(IXmlWriter *output)
  1539. {
  1540. CriticalBlock b(debugCrit);
  1541. _continue(WatchStateNext);
  1542. doStandardResult(output);
  1543. }
  1544. void CBaseServerDebugContext::debugOver(IXmlWriter *output)
  1545. {
  1546. CriticalBlock b(debugCrit);
  1547. _continue(WatchStateOver);
  1548. doStandardResult(output);
  1549. }
  1550. void CBaseServerDebugContext::debugChanges(IXmlWriter *output, unsigned sinceSequence) const
  1551. {
  1552. CriticalBlock b(debugCrit);
  1553. if (running)
  1554. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available while query is running");
  1555. if (sinceSequence == (unsigned) -1)
  1556. sinceSequence = previousSequence;
  1557. if (!currentGraph)
  1558. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available when no graph active");
  1559. // MORE - if current graph has changed since specified sequence, then ??
  1560. currentGraph->getXGMML(output, sinceSequence, true);
  1561. }
  1562. void CBaseServerDebugContext::debugCounts(IXmlWriter *output, unsigned sinceSequence, bool reset)
  1563. {
  1564. CriticalBlock b(debugCrit);
  1565. if (running)
  1566. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available while query is running");
  1567. if (sinceSequence == (unsigned) -1)
  1568. sinceSequence = previousSequence;
  1569. HashIterator edges(globalCounts);
  1570. ForEach(edges)
  1571. {
  1572. IGlobalEdgeRecord *edge = globalCounts.mapToValue(&edges.query());
  1573. if (!sinceSequence || edge->queryLastSequence() > sinceSequence)
  1574. {
  1575. output->outputBeginNested("edge", true);
  1576. output->outputCString((const char *) edges.query().getKey(), "@edgeId");
  1577. output->outputUInt(edge->queryCount(), sizeof(unsigned), "@count");
  1578. output->outputEndNested("edge");
  1579. }
  1580. if (reset)
  1581. edge->reset();
  1582. }
  1583. }
  1584. void CBaseServerDebugContext::debugWhere(IXmlWriter *output) const
  1585. {
  1586. CriticalBlock b(debugCrit);
  1587. if (running)
  1588. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available while query is running");
  1589. if (!currentActivity)
  1590. throw MakeStringException(THORHELPER_DEBUG_ERROR, "No current activity");
  1591. output->outputCString(currentGraph->queryGraphName(), "@graphId");
  1592. output->outputCString(currentActivity->queryEdgeId(), "@edgeId");
  1593. IActivityDebugContext *activityCtx = currentActivity;
  1594. while (activityCtx)
  1595. {
  1596. activityCtx->printEdge(output, 0, 1);
  1597. output->outputEndNested("Edge");
  1598. activityCtx = activityCtx->queryInputActivity();
  1599. }
  1600. }
  1601. void CBaseServerDebugContext::debugPrintVariable(IXmlWriter *output, const char *name, const char *type) const
  1602. {
  1603. throwUnexpected(); // must be implemented by platform-specific derived class
  1604. }
  1605. void CBaseServerDebugContext::debugSearch(IXmlWriter *output, const char *fieldName, const char *condition, const char *value, bool caseSensitive, bool fullRows) const
  1606. {
  1607. CriticalBlock b(debugCrit);
  1608. if (running)
  1609. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available while query is running");
  1610. if (!currentGraph)
  1611. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available when no graph active");
  1612. Owned<IRowMatcher> searcher = createRowMatcher(fieldName, (BreakpointConditionMode) checkOption(condition, "condition", BreakpointConditionModes), value, caseSensitive);
  1613. currentGraph->searchHistories(output, searcher, fullRows);
  1614. }
  1615. void CBaseServerDebugContext::debugPrint(IXmlWriter *output, const char *edgeId, unsigned startRow, unsigned numRows) const
  1616. {
  1617. CriticalBlock b(debugCrit);
  1618. if (running)
  1619. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available while query is running");
  1620. if (!currentGraph)
  1621. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available when no graph active");
  1622. IActivityDebugContext *activityCtx;
  1623. if (edgeId)
  1624. {
  1625. activityCtx = currentGraph->lookupActivityByEdgeId(edgeId);
  1626. if (!activityCtx)
  1627. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Edge %s not found in current graph", edgeId);
  1628. }
  1629. else if (currentActivity)
  1630. activityCtx = currentActivity;
  1631. else
  1632. throw MakeStringException(THORHELPER_DEBUG_ERROR, "An edge id must be specified if there is no current edge");
  1633. output->outputCString(currentGraph->queryGraphName(), "@graphId");
  1634. #if 1
  1635. CommonXmlWriter dummyOutput(0, 0);
  1636. activityCtx->printEdge(&dummyOutput, startRow, numRows); // MORE - need to suppress the <Edge> if we want backward compatibility!
  1637. Owned<IPropertyTree> result = createPTreeFromXMLString(dummyOutput.str());
  1638. if (result)
  1639. {
  1640. Owned<IAttributeIterator> attributes = result->getAttributes();
  1641. ForEach(*attributes)
  1642. {
  1643. output->outputCString(attributes->queryValue(),attributes->queryName());
  1644. }
  1645. output->outputString(0, NULL, NULL);
  1646. Owned<IPropertyTreeIterator> elems = result->getElements("*");
  1647. ForEach(*elems)
  1648. {
  1649. StringBuffer e;
  1650. IPropertyTree &elem = elems->query();
  1651. toXML(&elem, e);
  1652. output->outputQuoted(e.str());
  1653. }
  1654. }
  1655. #else
  1656. activityCtx->printEdge(output, startRow, numRows); // MORE - need to suppress the <Edge> if we want backward compatibility!
  1657. #endif
  1658. }
  1659. void CBaseServerDebugContext::debugGetConfig(IXmlWriter *output, const char *name, const char *id) const
  1660. {
  1661. CriticalBlock b(debugCrit);
  1662. if (running)
  1663. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available while query is running");
  1664. if (!name)
  1665. throw MakeStringException(THORHELPER_DEBUG_ERROR, "configuration setting name must be supplied");
  1666. if (stricmp(name, "executeSequentially")==0)
  1667. {
  1668. output->outputBool(executeSequentially, "@value");
  1669. }
  1670. else if (stricmp(name, "stopOnLimits")==0)
  1671. {
  1672. output->outputInt(stopOnLimits, sizeof(int), "@value");
  1673. }
  1674. else if (stricmp(name, "historySize")==0)
  1675. {
  1676. if (id)
  1677. {
  1678. if (!currentGraph)
  1679. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available when no graph active");
  1680. IActivityDebugContext *activityCtx = currentGraph->lookupActivityByEdgeId(id);
  1681. if (!activityCtx)
  1682. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Edge %s not found in current graph", id);
  1683. output->outputInt(activityCtx->queryHistoryCapacity(), sizeof(int), "@value");
  1684. }
  1685. else
  1686. {
  1687. output->outputInt(defaultHistoryCapacity, sizeof(int), "@value");
  1688. }
  1689. }
  1690. else
  1691. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Unknown configuration setting '%s'", name);
  1692. output->outputCString(name, "@name");
  1693. if (id) output->outputCString(id, "@id");
  1694. }
  1695. void CBaseServerDebugContext::debugSetConfig(IXmlWriter *output, const char *name, const char *value, const char *id)
  1696. {
  1697. CriticalBlock b(debugCrit);
  1698. if (running)
  1699. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available while query is running");
  1700. if (!name)
  1701. throw MakeStringException(THORHELPER_DEBUG_ERROR, "configuration setting name must be supplied");
  1702. unsigned intval = value ? atoi(value) : 0;
  1703. if (stricmp(name, "executeSequentially")==0)
  1704. {
  1705. if (id)
  1706. throw MakeStringException(THORHELPER_DEBUG_ERROR, "id not supported here");
  1707. if (!value || clipStrToBool(value))
  1708. executeSequentially = true;
  1709. else
  1710. executeSequentially = false;
  1711. }
  1712. else if (stricmp(name, "stopOnLimits")==0)
  1713. {
  1714. if (id)
  1715. throw MakeStringException(THORHELPER_DEBUG_ERROR, "id not supported here");
  1716. if (!value || clipStrToBool(value))
  1717. stopOnLimits = true;
  1718. else
  1719. stopOnLimits = false;
  1720. }
  1721. else if (stricmp(name, "historySize")==0)
  1722. {
  1723. if (!value)
  1724. throw MakeStringException(THORHELPER_DEBUG_ERROR, "No value supplied");
  1725. if (id)
  1726. {
  1727. if (!currentGraph)
  1728. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available when no graph active");
  1729. IActivityDebugContext *activityCtx = currentGraph->lookupActivityByEdgeId(id);
  1730. if (!activityCtx)
  1731. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Edge %s not found in current graph", id);
  1732. activityCtx->setHistoryCapacity(intval);
  1733. }
  1734. else
  1735. {
  1736. defaultHistoryCapacity = intval;
  1737. if (currentGraph)
  1738. currentGraph->setHistoryCapacity(intval);
  1739. }
  1740. }
  1741. else
  1742. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Unknown configuration setting '%s'", name);
  1743. if (name) output->outputCString(name, "@name");
  1744. if (value) output->outputCString(value, "@value");
  1745. if (id) output->outputCString(id, "@id");
  1746. }
  1747. void CBaseServerDebugContext::getCurrentGraphXGMML(IXmlWriter *output, bool original) const
  1748. {
  1749. CriticalBlock b(debugCrit);
  1750. if (running)
  1751. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available while query is running");
  1752. if (!currentGraph)
  1753. throw MakeStringException(THORHELPER_DEBUG_ERROR, "No current graph");
  1754. if (original)
  1755. getGraphXGMML(output, currentGraph->queryGraphName());
  1756. else
  1757. {
  1758. #if 0
  1759. if (completedGraphs)
  1760. {
  1761. Owned<IPropertyIterator> iterator = completedGraphs->getIterator();
  1762. iterator->first();
  1763. while (iterator->isValid())
  1764. {
  1765. const char *graphName = iterator->getPropKey();
  1766. const char *graphXML = completedGraphs->queryProp(graphName);
  1767. output->outputString(0, 0, NULL);
  1768. output->outputQuoted(graphXML);
  1769. iterator->next();
  1770. }
  1771. }
  1772. #endif
  1773. currentGraph->getXGMML(output, 0, true);
  1774. }
  1775. }
  1776. void CBaseServerDebugContext::getQueryXGMML(IXmlWriter *output) const
  1777. {
  1778. CriticalBlock b(debugCrit);
  1779. if (running)
  1780. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available while query is running");
  1781. StringBuffer s;
  1782. toXML(queryXGMML, s, 2);
  1783. output->outputString(0, NULL, NULL); // closes any open tags....
  1784. output->outputQuoted(s.str());
  1785. }
  1786. void CBaseServerDebugContext::getGraphXGMML(IXmlWriter *output, const char *graphName) const
  1787. {
  1788. CriticalBlock b(debugCrit);
  1789. if (running)
  1790. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Command not available while query is running");
  1791. StringBuffer xpath;
  1792. xpath.appendf("Graph[@id='%s']", graphName);
  1793. Owned<IPropertyTree> graph = queryXGMML->getPropTree(xpath.str());
  1794. if (!graph)
  1795. throw MakeStringException(THORHELPER_DEBUG_ERROR, "Graph %s not found", graphName);
  1796. StringBuffer s;
  1797. toXML(graph, s, 2);
  1798. output->outputString(0, NULL, NULL); // closes any open tags....
  1799. output->outputQuoted(s.str());
  1800. }
  1801. const char *CBaseServerDebugContext::queryQueryName() const
  1802. {
  1803. return queryName.get();
  1804. }
  1805. const char *CBaseServerDebugContext::queryDebugId() const
  1806. {
  1807. return debugId.get();
  1808. }
  1809. //=======================================================================================
  1810. DebugActivityRecord *CBaseDebugGraphManager::noteActivity(IActivityBase *activity, unsigned iteration, unsigned channel, unsigned sequence)
  1811. {
  1812. Linked<DebugActivityRecord> node = allActivities.getValue(activity);
  1813. if (!node)
  1814. {
  1815. node.setown(new DebugActivityRecord(activity, iteration, channel, sequence));
  1816. allActivities.setValue(activity, node);
  1817. }
  1818. else
  1819. {
  1820. node->iteration = iteration;
  1821. node->channel = channel;
  1822. node->sequence = sequence;
  1823. }
  1824. return node; // note - does not link
  1825. }
  1826. IDebuggableContext *CBaseDebugGraphManager::queryContext() const
  1827. {
  1828. return debugContext;
  1829. }
  1830. DebugActivityRecord *CBaseDebugGraphManager::getNodeByActivityBase(IActivityBase *activity) const
  1831. {
  1832. Linked<DebugActivityRecord> node = allActivities.getValue(activity);
  1833. if (!node)
  1834. {
  1835. ForEachItemIn(idx, childGraphs)
  1836. {
  1837. node.setown(childGraphs.item(idx).getNodeByActivityBase(activity));
  1838. if (node)
  1839. break;
  1840. }
  1841. }
  1842. return node.getClear();
  1843. }
  1844. void CBaseDebugGraphManager::outputLinksForChildGraph(IXmlWriter *output, const char *parentId)
  1845. {
  1846. ForEachItemIn(idx, sinks)
  1847. {
  1848. Linked<DebugActivityRecord> childNode = allActivities.getValue(&sinks.item(idx));
  1849. output->outputBeginNested("edge", true);
  1850. output->outputCString("Child", "@label");
  1851. StringBuffer idText;
  1852. idText.append(childNode->idText).append('_').append(parentId);
  1853. output->outputCString(idText.str(), "@id"); // MORE - is this guaranteed to be unique?
  1854. output->outputBeginNested("att", false); output->outputCString("_childGraph", "@name"); output->outputInt(1, sizeof(int), "@value"); output->outputEndNested("att");
  1855. output->outputBeginNested("att", false); output->outputCString("_sourceActivity", "@name"); childNode->outputId(output, "@value"); output->outputEndNested("att"); // MORE!!!
  1856. output->outputBeginNested("att", false); output->outputCString("_targetActivity", "@name"); output->outputCString(parentId, "@value"); output->outputEndNested("att");
  1857. output->outputEndNested("edge");
  1858. }
  1859. }
  1860. void CBaseDebugGraphManager::outputChildGraph(IXmlWriter *output, unsigned sequence)
  1861. {
  1862. if (allActivities.count())
  1863. {
  1864. output->outputBeginNested("graph", true);
  1865. HashIterator edges(allProbes);
  1866. ForEach(edges)
  1867. {
  1868. IActivityDebugContext *edge = allProbes.mapToValue(&edges.query());
  1869. if (!sequence || edge->queryLastSequence() > sequence)
  1870. edge->getXGMML(output);
  1871. }
  1872. HashIterator nodes(allActivities);
  1873. ForEach(nodes)
  1874. {
  1875. DebugActivityRecord *node = allActivities.mapToValue(&nodes.query());
  1876. if (!sequence || node->sequence > sequence) // MORE - if we start reporting any stats on nodes (seeks? scans?) this may need to change
  1877. {
  1878. output->outputBeginNested("node", true);
  1879. node->outputId(output, "@id");
  1880. ThorActivityKind kind = node->activity->getKind();
  1881. StringBuffer kindStr(getActivityText(kind));
  1882. output->outputString(kindStr.length(), kindStr.str(), "@shortlabel");
  1883. if (node->activity->isPassThrough())
  1884. {
  1885. output->outputBeginNested("att", false); output->outputCString("_isPassthrough", "@name"); output->outputInt(1, sizeof(int), "@value"); output->outputEndNested("att");
  1886. }
  1887. if (node->totalCycles)
  1888. {
  1889. output->outputBeginNested("att", false);
  1890. output->outputCString("totalTime", "@name");
  1891. output->outputUInt((unsigned) (cycle_to_nanosec(node->totalCycles)/1000), sizeof(unsigned), "@value");
  1892. output->outputEndNested("att");
  1893. }
  1894. if (node->localCycles)
  1895. {
  1896. output->outputBeginNested("att", false);
  1897. output->outputCString("localTime", "@name");
  1898. output->outputUInt((unsigned) (cycle_to_nanosec(node->localCycles)/1000), sizeof(unsigned), "@value");
  1899. output->outputEndNested("att");
  1900. }
  1901. node->outputProperties(output);
  1902. }
  1903. if (!sequence || node->sequence > sequence)
  1904. output->outputEndNested("node");
  1905. ForEachItemIn(idx, node->childGraphs)
  1906. {
  1907. output->outputBeginNested("node", true);
  1908. IDebugGraphManager &childGraph = node->childGraphs.item(idx);
  1909. output->outputCString(childGraph.queryIdString(), "@id");
  1910. childGraph.outputChildGraph(output, sequence);
  1911. output->outputEndNested("node");
  1912. childGraph.outputLinksForChildGraph(output, node->queryIdString());
  1913. }
  1914. }
  1915. output->outputEndNested("graph");
  1916. }
  1917. else
  1918. {
  1919. // This is a bit of a hack. Slave-side graphs have no outer-level node, so we have to do the childgraphs instead
  1920. ForEachItemIn(idx, childGraphs)
  1921. {
  1922. childGraphs.item(idx).outputChildGraph(output, sequence);
  1923. }
  1924. }
  1925. }
  1926. void CBaseDebugGraphManager::Link() const
  1927. {
  1928. CInterface::Link();
  1929. }
  1930. bool CBaseDebugGraphManager::Release() const
  1931. {
  1932. if (!IsShared())
  1933. {
  1934. if (!id)
  1935. debugContext->releaseManager(const_cast<CBaseDebugGraphManager*> (this));
  1936. }
  1937. return CInterface::Release();
  1938. }
  1939. CBaseDebugGraphManager::CBaseDebugGraphManager(IDebuggableContext *_debugContext, unsigned _id, const char *_graphName) : debugContext(_debugContext), id(_id), graphName(_graphName)
  1940. {
  1941. if (_graphName)
  1942. debugContext->noteManager(this);
  1943. idString.append(_id);
  1944. proxyId = 0;
  1945. }
  1946. IDebugGraphManager *CBaseDebugGraphManager::queryDebugManager()
  1947. {
  1948. return this;
  1949. }
  1950. const char *CBaseDebugGraphManager::queryIdString() const
  1951. {
  1952. return idString;
  1953. }
  1954. unsigned CBaseDebugGraphManager::queryId() const
  1955. {
  1956. return id;
  1957. }
  1958. void CBaseDebugGraphManager::noteSink(IActivityBase *sink)
  1959. {
  1960. CriticalBlock b(crit);
  1961. sinks.append(*LINK(sink));
  1962. }
  1963. void CBaseDebugGraphManager::noteDependency(IActivityBase *sourceActivity, unsigned sourceIndex, unsigned controlId, const char *edgeId, IActivityBase *targetActivity)
  1964. {
  1965. CriticalBlock b(crit);
  1966. dependencies.append(*new DebugDependencyRecord(sourceActivity, sourceIndex, controlId, edgeId, targetActivity, debugContext->querySequence()));
  1967. }
  1968. void CBaseDebugGraphManager::setNodeProperty(IActivityBase *node, const char *propName, const char *propValue)
  1969. {
  1970. CriticalBlock b(crit);
  1971. Linked<DebugActivityRecord> nodeInfo = allActivities.getValue(node);
  1972. if (nodeInfo)
  1973. nodeInfo->setProperty(propName, propValue, debugContext->querySequence());
  1974. ForEachItemIn(idx, childGraphs)
  1975. {
  1976. childGraphs.item(idx).setNodeProperty(node, propName, propValue);
  1977. }
  1978. }
  1979. void CBaseDebugGraphManager::setNodePropertyInt(IActivityBase *node, const char *propName, unsigned __int64 propValue)
  1980. {
  1981. StringBuffer s;
  1982. s.append(propValue);
  1983. setNodeProperty(node, propName, s.str());
  1984. }
  1985. void CBaseDebugGraphManager::getProbeResponse(IPropertyTree *query)
  1986. {
  1987. throwUnexpected();
  1988. }
  1989. void CBaseDebugGraphManager::setHistoryCapacity(unsigned newCapacity)
  1990. {
  1991. HashIterator edges(allProbes);
  1992. ForEach(edges)
  1993. {
  1994. IActivityDebugContext *edge = allProbes.mapToValue(&edges.query());
  1995. edge->setHistoryCapacity(newCapacity);
  1996. }
  1997. }
  1998. void CBaseDebugGraphManager::clearHistories()
  1999. {
  2000. HashIterator edges(allProbes);
  2001. ForEach(edges)
  2002. {
  2003. IActivityDebugContext *edge = allProbes.mapToValue(&edges.query());
  2004. edge->clearHistory();
  2005. }
  2006. }
  2007. void CBaseDebugGraphManager::setBreakpoint(IBreakpointInfo &bp)
  2008. {
  2009. // May want a hash lookup here, but the non-uniqueness makes it slightly non-trivial so bruteforce for now
  2010. HashIterator edges(allProbes);
  2011. ForEach(edges)
  2012. {
  2013. IActivityDebugContext *edge = allProbes.mapToValue(&edges.query());
  2014. if (bp.queryMode()==BreakpointModeGlobal || bp.idMatch(BreakpointModeEdge, edge->queryEdgeId()))
  2015. edge->setBreakpoint(bp);
  2016. }
  2017. ForEachItemIn(idx, childGraphs)
  2018. {
  2019. childGraphs.item(idx).setBreakpoint(bp);
  2020. }
  2021. }
  2022. void CBaseDebugGraphManager::mergeRemoteCounts(IDebuggableContext *into) const
  2023. {
  2024. ForEachItemIn(idx, childGraphs)
  2025. {
  2026. childGraphs.item(idx).mergeRemoteCounts(into);
  2027. }
  2028. }
  2029. void CBaseDebugGraphManager::removeBreakpoint(IBreakpointInfo &bp)
  2030. {
  2031. // May want a hash lookup here, but the non-uniqueness makes it slightly non-trivial so bruteforce for now
  2032. HashIterator edges(allProbes);
  2033. ForEach(edges)
  2034. {
  2035. IActivityDebugContext *edge = allProbes.mapToValue(&edges.query());
  2036. if (bp.queryMode()==BreakpointModeGlobal || bp.idMatch(BreakpointModeEdge, edge->queryEdgeId()))
  2037. edge->removeBreakpoint(bp);
  2038. }
  2039. ForEachItemIn(idx, childGraphs)
  2040. {
  2041. childGraphs.item(idx).removeBreakpoint(bp);
  2042. }
  2043. }
  2044. IActivityDebugContext *CBaseDebugGraphManager::lookupActivityByEdgeId(const char *edgeId)
  2045. {
  2046. // MORE - if structured ID's, behave differently?
  2047. IActivityDebugContext *edge = allProbes.getValue(edgeId);
  2048. if (!edge)
  2049. {
  2050. ForEachItemIn(idx, childGraphs)
  2051. {
  2052. edge = childGraphs.item(idx).lookupActivityByEdgeId(edgeId);
  2053. if (edge)
  2054. break;
  2055. }
  2056. }
  2057. return edge;
  2058. }
  2059. const char *CBaseDebugGraphManager::queryGraphName() const
  2060. {
  2061. return graphName.get();
  2062. }
  2063. void CBaseDebugGraphManager::getXGMML(IXmlWriter *output, unsigned sequence, bool isActive)
  2064. {
  2065. // Build xgmml for this graph... as currently executing...
  2066. CriticalBlock b(crit);
  2067. output->outputBeginNested("Graph", true);
  2068. output->outputString(graphName.length(), graphName.get(), "@id"); // MORE here
  2069. output->outputBool(isActive, "@active");
  2070. output->outputBeginNested("xgmml", true);
  2071. outputChildGraph(output, sequence);
  2072. ForEachItemIn(dependencyIdx, dependencies)
  2073. {
  2074. DebugDependencyRecord &dependency = dependencies.item(dependencyIdx);
  2075. if (!sequence || dependency.sequence > sequence) // MORE - if we start reporting any stats on nodes (seeks? scans?) this may need to change
  2076. {
  2077. DebugActivityRecord *source = allActivities.getValue(dependency.sourceActivity);
  2078. DebugActivityRecord *target = allActivities.getValue(dependency.targetActivity);
  2079. if (source && target)
  2080. {
  2081. output->outputBeginNested("edge", true);
  2082. output->outputCString(dependency.edgeId, "@id");
  2083. output->outputBeginNested("att", false); output->outputCString("_dependsOn", "@name"); output->outputInt(1, sizeof(int), "@value"); output->outputEndNested("att");
  2084. output->outputBeginNested("att", false); output->outputCString("_sourceActivity", "@name"); source->outputId(output, "@value"); output->outputEndNested("att");
  2085. output->outputBeginNested("att", false); output->outputCString("_targetActivity", "@name"); target->outputId(output, "@value"); output->outputEndNested("att");
  2086. output->outputEndNested("edge");
  2087. }
  2088. // MORE - work out why sometimes source and/or target is NULL
  2089. }
  2090. }
  2091. output->outputEndNested("xgmml");
  2092. output->outputEndNested("Graph");
  2093. }
  2094. void CBaseDebugGraphManager::searchHistories(IXmlWriter *output, IRowMatcher *matcher, bool fullRows)
  2095. {
  2096. HashIterator edges(allProbes); // MORE - could find ones that have named field
  2097. ForEach(edges)
  2098. {
  2099. IActivityDebugContext *edge = allProbes.mapToValue(&edges.query());
  2100. edge->searchHistories(output, matcher, fullRows);
  2101. }
  2102. ForEachItemIn(idx, childGraphs)
  2103. {
  2104. IDebugGraphManager &graph = childGraphs.item(idx);
  2105. graph.searchHistories(output, matcher, fullRows);
  2106. }
  2107. }
  2108. void CBaseDebugGraphManager::serializeProxyGraphs(MemoryBuffer &buff)
  2109. {
  2110. buff.append(childGraphs.length());
  2111. ForEachItemIn(idx, childGraphs)
  2112. {
  2113. IDebugGraphManager &graph = childGraphs.item(idx);
  2114. buff.append(graph.queryId());
  2115. buff.append((__uint64)graph.queryProxyId());
  2116. }
  2117. }
  2118. void CBaseDebugGraphManager::endChildGraph(IProbeManager *child, IActivityBase *parent)
  2119. {
  2120. CriticalBlock b(crit);
  2121. if (parent)
  2122. {
  2123. Linked<DebugActivityRecord> node = allActivities.getValue(parent);
  2124. if (!node)
  2125. {
  2126. node.setown(new DebugActivityRecord(parent, 0, debugContext->queryChannel(), 0));
  2127. allActivities.setValue(parent, node);
  2128. }
  2129. IDebugGraphManager *childManager = QUERYINTERFACE(child, CBaseDebugGraphManager); // yuk
  2130. node->childGraphs.append(*LINK(childManager));
  2131. }
  2132. }