ccdqueue.cpp 99 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833
  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 <platform.h>
  14. #include <jlib.hpp>
  15. #include <jio.hpp>
  16. #include <jqueue.tpp>
  17. #include <jsocket.hpp>
  18. #include <jlog.hpp>
  19. #include "jisem.hpp"
  20. #include "udplib.hpp"
  21. #include "ccd.hpp"
  22. #include "ccddebug.hpp"
  23. #include "ccdquery.hpp"
  24. #include "ccdstate.hpp"
  25. #include "ccdqueue.ipp"
  26. #include "ccdsnmp.hpp"
  27. #ifdef _USE_CPPUNIT
  28. #include <cppunit/extensions/HelperMacros.h>
  29. #endif
  30. CriticalSection ibytiCrit; // CAUTION - not safe to use spinlocks as real-time thread accesses
  31. CriticalSection queueCrit;
  32. unsigned channels[MAX_CLUSTER_SIZE];
  33. unsigned channelCount;
  34. unsigned subChannels[MAX_CLUSTER_SIZE];
  35. unsigned numSlaves[MAX_CLUSTER_SIZE];
  36. unsigned replicationLevel[MAX_CLUSTER_SIZE];
  37. unsigned IBYTIDelays[MAX_CLUSTER_SIZE]; // MORE: this will cover only 2 slaves per channel, change to cover all.
  38. SpinLock suspendCrit;
  39. bool suspendedChannels[MAX_CLUSTER_SIZE];
  40. using roxiemem::OwnedRoxieRow;
  41. using roxiemem::OwnedConstRoxieRow;
  42. using roxiemem::IRowManager;
  43. using roxiemem::DataBuffer;
  44. //============================================================================================
  45. // This function maps a slave number to the multicast ip used to talk to it.
  46. IpAddress multicastBase("239.1.1.1"); // TBD IPv6 (need IPv6 multicast addresses?
  47. IpAddress multicastLast("239.1.5.254");
  48. const IpAddress &getChannelIp(IpAddress &ip, unsigned _channel)
  49. {
  50. // need to be careful to avoid the .0's and the .255's (not sure why...)
  51. ip = multicastBase;
  52. if (!ip.ipincrement(_channel,1,254,1,0xffff)
  53. ||(ip.ipcompare(multicastLast)>0))
  54. throw MakeStringException(ROXIE_MULTICAST_ERROR, "Out-of-range multicast channel %d", _channel);
  55. return ip;
  56. }
  57. Owned<ISocket> multicastSocket;
  58. SocketEndpointArray *slaveEndpoints; // indexed by channel
  59. bool isSlaveEndpoint(unsigned channel, const IpAddress &slaveIp)
  60. {
  61. SocketEndpointArray &eps = slaveEndpoints[channel];
  62. ForEachItemIn(idx, eps)
  63. {
  64. if (eps.item(idx).ipequals(slaveIp))
  65. return true;
  66. }
  67. return false;
  68. }
  69. void joinMulticastChannel(unsigned channel)
  70. {
  71. if (roxieMulticastEnabled && !localSlave)
  72. {
  73. IpAddress multicastIp;
  74. getChannelIp(multicastIp, channel);
  75. SocketEndpoint ep(ccdMulticastPort, multicastIp);
  76. StringBuffer epStr;
  77. ep.getUrlStr(epStr);
  78. if (!multicastSocket->join_multicast_group(ep))
  79. throw MakeStringException(ROXIE_MULTICAST_ERROR, "Failed to join multicast channel %d (%s)", channel, epStr.str());
  80. if (traceLevel)
  81. DBGLOG("Joined multicast channel %d (%s)", channel, epStr.str());
  82. }
  83. }
  84. void openMulticastSocket()
  85. {
  86. if (!multicastSocket)
  87. {
  88. multicastSocket.setown(ISocket::udp_create(ccdMulticastPort));
  89. multicastSocket->set_receive_buffer_size(udpMulticastBufferSize);
  90. size32_t actualSize = multicastSocket->get_receive_buffer_size();
  91. if (actualSize < udpMulticastBufferSize)
  92. {
  93. DBGLOG("Roxie: multicast socket buffer size could not be set (requested=%d actual %d", udpMulticastBufferSize, actualSize);
  94. throwUnexpected();
  95. }
  96. if (traceLevel)
  97. DBGLOG("Roxie: multicast socket created port=%d sockbuffsize=%d actual %d", ccdMulticastPort, udpMulticastBufferSize, actualSize);
  98. Owned<IPropertyTreeIterator> it = ccdChannels->getElements("RoxieSlaveProcess");
  99. ForEach(*it)
  100. {
  101. unsigned channel = it->query().getPropInt("@channel", 0);
  102. assertex(channel);
  103. joinMulticastChannel(channel);
  104. }
  105. joinMulticastChannel(0); // all slaves also listen on channel 0
  106. }
  107. }
  108. void addEndpoint(unsigned channel, const IpAddress &slaveIp, unsigned port)
  109. {
  110. if (!slaveEndpoints)
  111. slaveEndpoints = new SocketEndpointArray[numChannels + 1];
  112. IpAddress multicastIp;
  113. if (roxieMulticastEnabled)
  114. getChannelIp(multicastIp, channel);
  115. else
  116. multicastIp = slaveIp;
  117. if (!isSlaveEndpoint(channel, multicastIp))
  118. {
  119. SocketEndpoint &ep = *new SocketEndpoint(ccdMulticastPort, multicastIp);
  120. slaveEndpoints[channel].append(ep);
  121. }
  122. if (channel)
  123. addEndpoint(0, slaveIp, port);
  124. }
  125. void closeMulticastSockets()
  126. {
  127. delete[] slaveEndpoints;
  128. slaveEndpoints = NULL;
  129. multicastSocket.clear();
  130. }
  131. size32_t channelWrite(unsigned channel, void const* buf, size32_t size)
  132. {
  133. size32_t minwrote = 0;
  134. SocketEndpointArray &eps = slaveEndpoints[channel]; // if multicast is enabled, this will have a single multicast endpoint in it.
  135. assertex(eps.ordinality());
  136. ForEachItemIn(idx, eps)
  137. {
  138. size32_t wrote = multicastSocket->udp_write_to(eps.item(idx), buf, size);
  139. if (!idx || wrote < minwrote)
  140. minwrote = wrote;
  141. }
  142. return minwrote;
  143. }
  144. // #define TEST_SLAVE_FAILURE
  145. //============================================================================================
  146. StringBuffer &RoxiePacketHeader::toString(StringBuffer &ret) const
  147. {
  148. const IpAddress &serverIP = getNodeAddress(serverIdx);
  149. ret.appendf("uid="RUIDF" activityId=", uid);
  150. switch(activityId & ~ROXIE_PRIORITY_MASK)
  151. {
  152. case ROXIE_UNLOAD: ret.append("ROXIE_UNLOAD"); break;
  153. case ROXIE_PING: ret.append("ROXIE_PING"); break;
  154. case ROXIE_TRACEINFO: ret.append("ROXIE_TRACEINFO"); break;
  155. case ROXIE_DEBUGREQUEST: ret.append("ROXIE_DEBUGREQUEST"); break;
  156. case ROXIE_DEBUGCALLBACK: ret.append("ROXIE_DEBUGCALLBACK"); break;
  157. case ROXIE_FILECALLBACK: ret.append("ROXIE_FILECALLBACK"); break;
  158. case ROXIE_ALIVE: ret.append("ROXIE_ALIVE"); break;
  159. case ROXIE_KEYEDLIMIT_EXCEEDED: ret.append("ROXIE_KEYEDLIMIT_EXCEEDED"); break;
  160. case ROXIE_LIMIT_EXCEEDED: ret.append("ROXIE_LIMIT_EXCEEDED"); break;
  161. case ROXIE_EXCEPTION: ret.append("ROXIE_EXCEPTION"); break;
  162. default:
  163. ret.appendf("%u", (activityId & ~(ROXIE_ACTIVITY_FETCH | ROXIE_PRIORITY_MASK)));
  164. if (activityId & ROXIE_ACTIVITY_FETCH)
  165. ret.appendf(" (fetch part)");
  166. break;
  167. }
  168. ret.append(" pri=");
  169. switch(activityId & ROXIE_PRIORITY_MASK)
  170. {
  171. case ROXIE_SLA_PRIORITY: ret.append("SLA"); break;
  172. case ROXIE_HIGH_PRIORITY: ret.append("HIGH"); break;
  173. case ROXIE_LOW_PRIORITY: ret.append("LOW"); break;
  174. default: ret.append("???"); break;
  175. }
  176. ret.appendf(" queryHash=%"I64F"x ch=%u seq=%d cont=%d server=", queryHash, channel, overflowSequence, continueSequence);
  177. serverIP.getIpText(ret);
  178. if (retries)
  179. {
  180. if (retries==QUERY_ABORTED)
  181. ret.append(" retries=QUERY_ABORTED");
  182. else
  183. {
  184. if (retries & ROXIE_RETRIES_MASK)
  185. ret.appendf(" retries=%04x", retries);
  186. if (retries & ROXIE_FASTLANE)
  187. ret.appendf(" FASTLANE");
  188. if (retries & ROXIE_BROADCAST)
  189. ret.appendf(" BROADCAST");
  190. }
  191. }
  192. return ret;
  193. }
  194. class CRoxieQueryPacket : public CInterface, implements IRoxieQueryPacket
  195. {
  196. protected:
  197. RoxiePacketHeader *data;
  198. const byte *continuationData;
  199. unsigned continuationLength;
  200. const byte *smartStepInfoData;
  201. unsigned smartStepInfoLength;
  202. const byte *contextData;
  203. unsigned contextLength;
  204. const byte *traceInfo;
  205. unsigned traceLength;
  206. public:
  207. IMPLEMENT_IINTERFACE;
  208. CRoxieQueryPacket(const void *_data, int lengthRemaining) : data((RoxiePacketHeader *) _data)
  209. {
  210. assertex(lengthRemaining >= sizeof(RoxiePacketHeader));
  211. data->packetlength = lengthRemaining;
  212. const byte *finger = (const byte *) (data + 1);
  213. lengthRemaining -= sizeof(RoxiePacketHeader);
  214. if (data->activityId == ROXIE_FILECALLBACK || data->activityId == ROXIE_DEBUGCALLBACK)
  215. {
  216. continuationData = NULL;
  217. continuationLength = 0;
  218. smartStepInfoData = NULL;
  219. smartStepInfoLength = 0;
  220. traceInfo = NULL;
  221. traceLength = 0;
  222. }
  223. else
  224. {
  225. if (data->continueSequence & ~CONTINUE_SEQUENCE_SKIPTO)
  226. {
  227. assertex(lengthRemaining >= sizeof(unsigned short));
  228. continuationLength = *(unsigned short *) finger;
  229. continuationData = finger + sizeof(unsigned short);
  230. finger = continuationData + continuationLength;
  231. lengthRemaining -= continuationLength + sizeof(unsigned short);
  232. }
  233. else
  234. {
  235. continuationData = NULL;
  236. continuationLength = 0;
  237. }
  238. if (data->continueSequence & CONTINUE_SEQUENCE_SKIPTO)
  239. {
  240. assertex(lengthRemaining >= sizeof(unsigned short));
  241. smartStepInfoLength = *(unsigned short *) finger;
  242. smartStepInfoData = finger + sizeof(unsigned short);
  243. finger = smartStepInfoData + smartStepInfoLength;
  244. lengthRemaining -= smartStepInfoLength + sizeof(unsigned short);
  245. }
  246. else
  247. {
  248. smartStepInfoData = NULL;
  249. smartStepInfoLength = 0;
  250. }
  251. assertex(lengthRemaining > 1);
  252. traceInfo = finger;
  253. lengthRemaining--;
  254. if (*finger++ & LOGGING_DEBUGGERACTIVE)
  255. {
  256. assertex(lengthRemaining >= sizeof(unsigned short));
  257. unsigned short debugLen = *(unsigned short *) finger;
  258. finger += debugLen + sizeof(unsigned short);
  259. lengthRemaining -= debugLen + sizeof(unsigned short);
  260. }
  261. loop
  262. {
  263. assertex(lengthRemaining>0);
  264. if (!*finger)
  265. {
  266. lengthRemaining--;
  267. finger++;
  268. break;
  269. }
  270. lengthRemaining--;
  271. finger++;
  272. }
  273. traceLength = finger - traceInfo;
  274. }
  275. assertex(lengthRemaining >= 0);
  276. contextData = finger;
  277. contextLength = lengthRemaining;
  278. }
  279. ~CRoxieQueryPacket()
  280. {
  281. free(data);
  282. }
  283. virtual RoxiePacketHeader &queryHeader() const
  284. {
  285. return *data;
  286. }
  287. virtual const void *queryContinuationData() const
  288. {
  289. return continuationData;
  290. }
  291. virtual unsigned getContinuationLength() const
  292. {
  293. return continuationLength;
  294. }
  295. virtual const byte *querySmartStepInfoData() const
  296. {
  297. return smartStepInfoData;
  298. }
  299. virtual unsigned getSmartStepInfoLength() const
  300. {
  301. return smartStepInfoLength;
  302. }
  303. virtual const byte *queryTraceInfo() const
  304. {
  305. return traceInfo;
  306. }
  307. virtual unsigned getTraceLength() const
  308. {
  309. return traceLength;
  310. }
  311. virtual const void *queryContextData() const
  312. {
  313. return contextData;
  314. }
  315. virtual unsigned getContextLength() const
  316. {
  317. return contextLength;
  318. }
  319. virtual IRoxieQueryPacket *clonePacket(unsigned channel) const
  320. {
  321. unsigned length = data->packetlength;
  322. RoxiePacketHeader *newdata = (RoxiePacketHeader *) malloc(length);
  323. memcpy(newdata, data, length);
  324. newdata->channel = channel;
  325. newdata->retries |= ROXIE_BROADCAST;
  326. return createRoxiePacket(newdata, length);
  327. }
  328. virtual IRoxieQueryPacket *insertSkipData(size32_t skipDataLen, const void *skipData) const
  329. {
  330. assertex((data->continueSequence & CONTINUE_SEQUENCE_SKIPTO) == 0); // Should not already be any skipto info in the source packet
  331. unsigned newDataSize = data->packetlength + sizeof(unsigned short) + skipDataLen;
  332. char *newdata = (char *) malloc(newDataSize);
  333. unsigned headSize = sizeof(RoxiePacketHeader);
  334. if (data->continueSequence & ~CONTINUE_SEQUENCE_SKIPTO)
  335. headSize += sizeof(unsigned short) + continuationLength;
  336. memcpy(newdata, data, headSize); // copy in leading part of old data
  337. ((RoxiePacketHeader *) newdata)->continueSequence |= CONTINUE_SEQUENCE_SKIPTO; // set flag indicating new data is present
  338. *(unsigned short *) (newdata + headSize) = skipDataLen; // add length field for new data
  339. memcpy(newdata + headSize + sizeof(unsigned short), skipData, skipDataLen); // copy in new data
  340. memcpy(newdata + headSize + sizeof(unsigned short) + skipDataLen, ((char *) data) + headSize, data->packetlength - headSize); // copy in remaining old data
  341. return createRoxiePacket(newdata, newDataSize);
  342. }
  343. virtual unsigned hash() const
  344. {
  345. // This is used for Roxie server-side caching. The hash includes some of the header and all of the payload.
  346. unsigned hash = 0;
  347. if (continuationLength)
  348. hash = hashc((const unsigned char *) continuationData, continuationLength, hash);
  349. if (smartStepInfoLength)
  350. hash = hashc((const unsigned char *) smartStepInfoData, smartStepInfoLength, hash);
  351. // NOTE - don't hash the trace info!
  352. hash = hashc((const unsigned char *) contextData, contextLength, hash);
  353. hash = hashc((const unsigned char *) &data->channel, sizeof(data->channel), hash);
  354. hash = hashc((const unsigned char *) &data->overflowSequence, sizeof(data->overflowSequence), hash);
  355. hash = hashc((const unsigned char *) &data->continueSequence, sizeof(data->continueSequence), hash);
  356. // MORE - sequence fields should always be zero for anything we are caching I think... (?)
  357. // Note - no point hashing activityId (as cache is local to one activity) or serverIP (likewise)
  358. return hash;
  359. }
  360. virtual bool cacheMatch(const IRoxieQueryPacket *c) const
  361. {
  362. // note - this checks whether it's a repeat from Roxie server's point-of-view
  363. // So fields that are compared are the same as the ones that are hashed....
  364. RoxiePacketHeader &h = c->queryHeader();
  365. if (data->channel == h.channel && data->overflowSequence == h.overflowSequence && data->continueSequence == h.continueSequence)
  366. {
  367. if (continuationLength) // note - we already checked that sequences match
  368. {
  369. if (continuationLength != c->getContinuationLength())
  370. return false;
  371. if (memcmp(continuationData,c->queryContinuationData(),continuationLength)!=0)
  372. return false;
  373. }
  374. if (smartStepInfoLength)
  375. {
  376. if (smartStepInfoLength != c->getSmartStepInfoLength())
  377. return false;
  378. if (memcmp(smartStepInfoData,c->querySmartStepInfoData(),smartStepInfoLength)!=0)
  379. return false;
  380. }
  381. // NOTE - trace info NOT compared
  382. if (contextLength == c->getContextLength() && memcmp(contextData, c->queryContextData(), contextLength)==0)
  383. return true;
  384. }
  385. return false;
  386. }
  387. };
  388. extern IRoxieQueryPacket *createRoxiePacket(void *_data, unsigned _len)
  389. {
  390. if ((unsigned short)_len != _len)
  391. {
  392. StringBuffer s;
  393. RoxiePacketHeader *header = (RoxiePacketHeader *) _data;
  394. header->toString(s);
  395. free(_data);
  396. throw MakeStringException(ROXIE_PACKET_ERROR, "Packet length %d exceeded maximum sending packet %s", _len, s.str());
  397. }
  398. return new CRoxieQueryPacket(_data, _len);
  399. }
  400. extern IRoxieQueryPacket *createRoxiePacket(MemoryBuffer &m)
  401. {
  402. unsigned length = m.length(); // don't make assumptions about evaluation order of parameters...
  403. return createRoxiePacket(m.detachOwn(), length);
  404. }
  405. //=================================================================================
  406. SlaveContextLogger::SlaveContextLogger()
  407. {
  408. GetHostIp(ip);
  409. set(NULL);
  410. }
  411. SlaveContextLogger::SlaveContextLogger(IRoxieQueryPacket *packet)
  412. {
  413. GetHostIp(ip);
  414. set(packet);
  415. }
  416. void SlaveContextLogger::set(IRoxieQueryPacket *packet)
  417. {
  418. anyOutput = false;
  419. intercept = false;
  420. debuggerActive = false;
  421. checkingHeap = false;
  422. aborted = false;
  423. stats.reset();
  424. start = msTick();
  425. if (packet)
  426. {
  427. CriticalBlock b(crit);
  428. RoxiePacketHeader &header = packet->queryHeader();
  429. const byte *traceInfo = packet->queryTraceInfo();
  430. unsigned traceLength = packet->getTraceLength();
  431. unsigned char loggingFlags = *traceInfo;
  432. if (loggingFlags & LOGGING_FLAGSPRESENT) // should always be true.... but this flag is handy to avoid flags byte ever being NULL
  433. {
  434. traceInfo++;
  435. traceLength--;
  436. if (loggingFlags & LOGGING_INTERCEPTED)
  437. intercept = true;
  438. if (loggingFlags & LOGGING_TRACELEVELSET)
  439. {
  440. ctxTraceLevel = (*traceInfo++ - 1); // avoid null byte here in case anyone still thinks there's just a null-terminated string
  441. traceLength--;
  442. }
  443. if (loggingFlags & LOGGING_BLIND)
  444. blind = true;
  445. if (loggingFlags & LOGGING_CHECKINGHEAP)
  446. checkingHeap = true;
  447. if (loggingFlags & LOGGING_DEBUGGERACTIVE)
  448. {
  449. assertex(traceLength > sizeof(unsigned short));
  450. debuggerActive = true;
  451. unsigned short debugLen = *(unsigned short *) traceInfo;
  452. traceInfo += debugLen + sizeof(unsigned short);
  453. traceLength -= debugLen + sizeof(unsigned short);
  454. }
  455. // Passing the wuid via the logging context prefix is a bit of a hack...
  456. if (loggingFlags & LOGGING_WUID)
  457. {
  458. unsigned wuidLen = 0;
  459. while (wuidLen < traceLength)
  460. {
  461. if (traceInfo[wuidLen]=='@')
  462. break;
  463. wuidLen++;
  464. }
  465. wuid.set((const char *) traceInfo, wuidLen);
  466. }
  467. }
  468. channel = header.channel;
  469. StringBuffer s(traceLength, (const char *) traceInfo);
  470. s.append("|");
  471. ip.getIpText(s);
  472. s.append(':').append(channel);
  473. StringContextLogger::set(s.str());
  474. if (intercept || mergeSlaveStatistics)
  475. {
  476. RoxiePacketHeader newHeader(header, ROXIE_TRACEINFO);
  477. output.setown(ROQ->createOutputStream(newHeader, true, *this));
  478. }
  479. }
  480. else
  481. {
  482. StringContextLogger::set("");
  483. channel = 0;
  484. }
  485. }
  486. void SlaveContextLogger::putStatProcessed(unsigned subGraphId, unsigned actId, unsigned idx, unsigned processed) const
  487. {
  488. if (output && mergeSlaveStatistics)
  489. {
  490. MemoryBuffer buf;
  491. buf.append((char) LOG_CHILDCOUNT); // A special log entry for the stats
  492. buf.append(subGraphId);
  493. buf.append(actId);
  494. buf.append(idx);
  495. buf.append(processed);
  496. }
  497. }
  498. void SlaveContextLogger::putStats(unsigned subGraphId, unsigned actId, const CRuntimeStatisticCollection &stats) const
  499. {
  500. if (output && mergeSlaveStatistics)
  501. {
  502. MemoryBuffer buf;
  503. buf.append((char) LOG_CHILDSTATS); // A special log entry for the stats
  504. buf.append(subGraphId);
  505. buf.append(actId);
  506. if (stats.serialize(buf))
  507. {
  508. unsigned len = buf.length();
  509. void *ret = output->getBuffer(len, true);
  510. memcpy(ret, buf.toByteArray(), len);
  511. output->putBuffer(ret, len, true);
  512. anyOutput = true;
  513. }
  514. }
  515. }
  516. void SlaveContextLogger::flush()
  517. {
  518. if (output)
  519. {
  520. CriticalBlock b(crit);
  521. if (mergeSlaveStatistics)
  522. {
  523. MemoryBuffer buf;
  524. buf.append((char) LOG_STATVALUES); // A special log entry for the stats
  525. if (stats.serialize(buf))
  526. {
  527. unsigned len = buf.length();
  528. void *ret = output->getBuffer(len, true);
  529. memcpy(ret, buf.toByteArray(), len);
  530. output->putBuffer(ret, len, true);
  531. anyOutput = true;
  532. }
  533. }
  534. ForEachItemIn(idx, log)
  535. {
  536. MemoryBuffer buf;
  537. LogItem &logItem = log.item(idx);
  538. logItem.serialize(buf);
  539. unsigned len = buf.length();
  540. void *ret = output->getBuffer(len, true);
  541. memcpy(ret, buf.toByteArray(), len);
  542. output->putBuffer(ret, len, true);
  543. anyOutput = true;
  544. }
  545. log.kill();
  546. if (anyOutput)
  547. output->flush(true);
  548. output.clear();
  549. }
  550. }
  551. //=================================================================================
  552. unsigned getIbytiDelay(unsigned channel, const RoxiePacketHeader &header)
  553. {
  554. // MORE - adjust delay according to whether it's a retry, whether it was a broadcast etc
  555. CriticalBlock b(ibytiCrit);
  556. return IBYTIDelays[channel];
  557. }
  558. void resetIbytiDelay(unsigned channel)
  559. {
  560. unsigned prevVal;
  561. {
  562. CriticalBlock b(ibytiCrit);
  563. prevVal = IBYTIDelays[channel];
  564. IBYTIDelays[channel] = initIbytiDelay;
  565. }
  566. if (traceLevel > 8 && prevVal != initIbytiDelay)
  567. DBGLOG("Reset IBYTI delay value for channel %u from %u to %u", channel, prevVal, initIbytiDelay);
  568. }
  569. void decIbytiDelay(unsigned channel, unsigned factor = 2)
  570. {
  571. unsigned prevVal, newVal;
  572. {
  573. CriticalBlock b(ibytiCrit);
  574. prevVal = IBYTIDelays[channel];
  575. IBYTIDelays[channel] /= factor;
  576. if (IBYTIDelays[channel] < minIbytiDelay)
  577. IBYTIDelays[channel] = minIbytiDelay;
  578. newVal = IBYTIDelays[channel];
  579. }
  580. if (traceLevel > 8 && prevVal != newVal)
  581. DBGLOG("Dec IBYTI delay value for channel %u from %u to %u (factor=%u)", channel, prevVal, newVal, factor);
  582. }
  583. //=================================================================================
  584. static SpinLock onDemandQueriesCrit;
  585. static MapXToMyClass<hash64_t, hash64_t, IQueryFactory> onDemandQueryCache;
  586. void sendUnloadMessage(hash64_t hash, const char *id, const IRoxieContextLogger &logctx)
  587. {
  588. unsigned packetSize = sizeof(RoxiePacketHeader) + sizeof(char) + strlen(id) + 1;
  589. void *packetData = malloc(packetSize);
  590. RoxiePacketHeader *header = (RoxiePacketHeader *) packetData;
  591. RemoteActivityId unloadId(ROXIE_UNLOAD, hash);
  592. header->init(unloadId, 0, 0, 0);
  593. char *finger = (char *) (header + 1);
  594. *finger++ = (char) LOGGING_FLAGSPRESENT;
  595. strcpy(finger, id);
  596. finger += strlen(id)+1;
  597. if (traceLevel > 1)
  598. DBGLOG("UNLOAD sent for query %s", id);
  599. Owned<IRoxieQueryPacket> packet = createRoxiePacket(packetData, packetSize);
  600. ROQ->sendPacket(packet, logctx);
  601. }
  602. void doUnload(IRoxieQueryPacket *packet, const IRoxieContextLogger &logctx)
  603. {
  604. const RoxiePacketHeader &header = packet->queryHeader();
  605. unsigned channelNo = header.channel;
  606. logctx.CTXLOG("Unload received for channel %d", channelNo);
  607. hash64_t hashValue = header.queryHash;
  608. SpinBlock b(onDemandQueriesCrit);
  609. onDemandQueryCache.remove(hashValue+channelNo);
  610. }
  611. void cacheOnDemandQuery(hash64_t hashValue, unsigned channelNo, IQueryFactory *query)
  612. {
  613. SpinBlock b(onDemandQueriesCrit);
  614. onDemandQueryCache.setValue(hashValue+channelNo, query);
  615. }
  616. //=================================================================================
  617. struct PingRecord
  618. {
  619. unsigned tick;
  620. IpAddress senderIP;
  621. };
  622. void doPing(IRoxieQueryPacket *packet, const IRoxieContextLogger &logctx)
  623. {
  624. const RoxiePacketHeader &header = packet->queryHeader();
  625. const IpAddress &serverIP = getNodeAddress(header.serverIdx);
  626. unsigned contextLength = packet->getContextLength();
  627. if (contextLength != sizeof(PingRecord))
  628. {
  629. StringBuffer s;
  630. throw MakeStringException(ROXIE_UNKNOWN_SERVER, "Unexpected data size %d (expected %d) in PING: %s", contextLength, (unsigned) sizeof(PingRecord), header.toString(s).str());
  631. }
  632. const PingRecord *data = (const PingRecord *) packet->queryContextData();
  633. if (!serverIP.ipequals(data->senderIP))
  634. {
  635. StringBuffer s;
  636. throw MakeStringException(ROXIE_UNKNOWN_SERVER, "Message received from unknown Roxie server %s", header.toString(s).str());
  637. }
  638. RoxiePacketHeader newHeader(header, ROXIE_PING);
  639. Owned<IMessagePacker> output = ROQ->createOutputStream(newHeader, true, logctx);
  640. void *ret = output->getBuffer(contextLength, false);
  641. memcpy(ret, data, contextLength);
  642. output->putBuffer(ret, contextLength, false);
  643. output->flush(true);
  644. }
  645. //=================================================================================
  646. //
  647. // RoxieQueue - holds pending transactions on a roxie agent
  648. class RoxieQueue : public CInterface
  649. {
  650. QueueOf<IRoxieQueryPacket, true> waiting;
  651. Semaphore available;
  652. CriticalSection qcrit;
  653. unsigned headRegionSize;
  654. public:
  655. IMPLEMENT_IINTERFACE;
  656. RoxieQueue(unsigned _headRegionSize)
  657. {
  658. headRegionSize = _headRegionSize;
  659. }
  660. void enqueue(IRoxieQueryPacket *x)
  661. {
  662. {
  663. CriticalBlock qc(qcrit);
  664. #ifdef TIME_PACKETS
  665. header.tick = msTick();
  666. #endif
  667. waiting.enqueue(x);
  668. CriticalBlock b(counterCrit);
  669. queueLength++;
  670. if (queueLength>maxQueueLength)
  671. maxQueueLength = queueLength;
  672. }
  673. available.signal();
  674. }
  675. void enqueueUnique(IRoxieQueryPacket *x)
  676. {
  677. {
  678. CriticalBlock qc(qcrit);
  679. RoxiePacketHeader &header = x->queryHeader();
  680. #ifdef TIME_PACKETS
  681. header.tick = msTick();
  682. #endif
  683. unsigned len = waiting.ordinality();
  684. unsigned i;
  685. for (i = 0; i < len; i++)
  686. {
  687. IRoxieQueryPacket *queued = waiting.item(i);
  688. if (queued && queued->queryHeader().matchPacket(header))
  689. {
  690. bool primChannel = true;
  691. if (subChannels[header.channel] != 1) primChannel = false;
  692. if (traceLevel > 0)
  693. {
  694. StringBuffer xx;
  695. SlaveContextLogger l(x);
  696. l.CTXLOG("Ignored retry on %s channel for queued activity %s", primChannel?"primary":"secondary", header.toString(xx).str());
  697. }
  698. if (primChannel)
  699. atomic_inc(&retriesIgnoredPrm);
  700. else
  701. atomic_inc(&retriesIgnoredSec);
  702. x->Release();
  703. return;
  704. }
  705. }
  706. if (traceLevel > 10)
  707. {
  708. SlaveContextLogger l(x);
  709. StringBuffer xx;
  710. l.CTXLOG("enqueued %s", header.toString(xx).str());
  711. }
  712. waiting.enqueue(x);
  713. CriticalBlock b(counterCrit);
  714. queueLength++;
  715. if (queueLength>maxQueueLength)
  716. maxQueueLength = queueLength;
  717. }
  718. available.signal();
  719. }
  720. bool remove(RoxiePacketHeader &x)
  721. {
  722. CriticalBlock qc(qcrit);
  723. unsigned len = waiting.ordinality();
  724. unsigned i;
  725. unsigned scanLength = 0;
  726. for (i = 0; i < len; i++)
  727. {
  728. IRoxieQueryPacket *queued = waiting.item(i);
  729. if (queued)
  730. {
  731. scanLength++;
  732. if (queued->queryHeader().matchPacket(x))
  733. {
  734. #ifdef _DEBUG
  735. RoxiePacketHeader &header = queued->queryHeader();
  736. SlaveContextLogger l(queued);
  737. StringBuffer xx;
  738. l.CTXLOG("discarded %s", header.toString(xx).str());
  739. #endif
  740. // Already done in doIBYTI()...queue.remove() !!!!! atomic_inc(&ibytiPacketsWorked);
  741. waiting.set(i, NULL);
  742. queued->Release();
  743. CriticalBlock b(counterCrit);
  744. queueLength--;
  745. if (scanLength > maxScanLength)
  746. maxScanLength = scanLength;
  747. totScanLength += scanLength;
  748. totScans++;
  749. if (totScans)
  750. meanScanLength = totScanLength / totScans;
  751. return true;
  752. }
  753. }
  754. }
  755. return false;
  756. }
  757. void wait()
  758. {
  759. available.wait();
  760. }
  761. void signal(unsigned num)
  762. {
  763. available.signal(num);
  764. }
  765. IRoxieQueryPacket *dequeue()
  766. {
  767. CriticalBlock qc(qcrit);
  768. unsigned lim = waiting.ordinality();
  769. if (lim)
  770. {
  771. if (headRegionSize)
  772. {
  773. if (lim > headRegionSize)
  774. lim = headRegionSize;
  775. return waiting.dequeue(rand() % lim);
  776. }
  777. return waiting.dequeue();
  778. }
  779. else
  780. return NULL;
  781. }
  782. unsigned getHeadRegionSize() const
  783. {
  784. return headRegionSize;
  785. }
  786. unsigned setHeadRegionSize(unsigned newsize)
  787. {
  788. unsigned ret = headRegionSize;
  789. headRegionSize = newsize;
  790. return ret;
  791. }
  792. };
  793. class CRoxieWorker : public CInterface, implements IPooledThread
  794. {
  795. RoxieQueue *queue;
  796. CriticalSection actCrit;
  797. Semaphore ibytiSem;
  798. bool stopped;
  799. bool abortJob;
  800. bool busy;
  801. Owned<IRoxieSlaveActivity> activity;
  802. Owned<IRoxieQueryPacket> packet;
  803. SlaveContextLogger logctx;
  804. public:
  805. IMPLEMENT_IINTERFACE;
  806. CRoxieWorker()
  807. {
  808. queue = NULL;
  809. stopped = false;
  810. busy = false;
  811. abortJob = false;
  812. }
  813. void init(void *_r)
  814. {
  815. queue = (RoxieQueue *) _r;
  816. stopped = false;
  817. busy = false;
  818. abortJob = false;
  819. }
  820. bool canReuse()
  821. {
  822. return true;
  823. }
  824. bool stop()
  825. {
  826. stopped = true;
  827. return true;
  828. }
  829. inline void setActivity(IRoxieSlaveActivity *act)
  830. {
  831. CriticalBlock b(actCrit);
  832. activity.setown(act);
  833. }
  834. inline bool match(RoxiePacketHeader &h)
  835. {
  836. // There is a window between getting packet from queue and being able to match it.
  837. // This could cause some deduping to fail, but it does not matter if it does (so long as it is rare!)
  838. CriticalBlock b(actCrit);
  839. return packet && packet->queryHeader().matchPacket(h);
  840. }
  841. void abortChannel(unsigned channel)
  842. {
  843. CriticalBlock b(actCrit);
  844. if (packet && packet->queryHeader().channel==channel)
  845. {
  846. abortJob = true;
  847. if (doIbytiDelay)
  848. ibytiSem.signal();
  849. if (activity)
  850. activity->abort();
  851. }
  852. }
  853. bool checkAbort(RoxiePacketHeader &h, bool checkRank, bool &queryFound, bool &preActivity)
  854. {
  855. CriticalBlock b(actCrit);
  856. if (packet && packet->queryHeader().matchPacket(h))
  857. {
  858. queryFound = true;
  859. abortJob = true;
  860. if (doIbytiDelay)
  861. ibytiSem.signal();
  862. if (activity)
  863. {
  864. // Try to stop/abort a job after it starts only if IBYTI comes from a higher priority slave
  865. // (more primary in the rank). The slaves with higher rank will hold the lower bits of the retries field in IBYTI packet).
  866. if (!checkRank || ((h.retries & ROXIE_RETRIES_MASK) < h.getSubChannelMask(h.channel)))
  867. {
  868. activity->abort();
  869. return true;
  870. }
  871. else
  872. {
  873. return false;
  874. }
  875. }
  876. if (busy)
  877. {
  878. preActivity = true;
  879. return true;
  880. }
  881. }
  882. return false;
  883. }
  884. void throwRemoteException(IException *E, IRoxieSlaveActivity *activity, IRoxieQueryPacket *packet, bool isUser)
  885. {
  886. try
  887. {
  888. if (activity && (logctx.queryTraceLevel() > 1))
  889. {
  890. StringBuffer act;
  891. activity->toString(act);
  892. logctx.CTXLOG("throwRemoteException, activity %s, isUser=%d", act.str(), (int) isUser);
  893. if (!isUser)
  894. EXCLOG(E, "throwRemoteException");
  895. }
  896. RoxiePacketHeader &header = packet->queryHeader();
  897. // I failed to do the query, but already sent out IBYTI - resend it so someone else can try
  898. if (!isUser)
  899. {
  900. StringBuffer s;
  901. s.append("Exception in slave for packet ");
  902. header.toString(s);
  903. logctx.logOperatorException(E, NULL, 0, "%s", s.str());
  904. header.setException();
  905. if (!header.allChannelsFailed())
  906. {
  907. if (logctx.queryTraceLevel() > 1)
  908. logctx.CTXLOG("resending packet from slave in case others want to try it");
  909. ROQ->sendPacket(packet, logctx);
  910. }
  911. }
  912. RoxiePacketHeader newHeader(header, ROXIE_EXCEPTION);
  913. if (isUser)
  914. newHeader.retries = (unsigned short) -1;
  915. Owned<IMessagePacker> output = ROQ->createOutputStream(newHeader, true, logctx);
  916. StringBuffer message("<Exception>");
  917. message.appendf("<Code>%d</Code><Message>", E->errorCode());
  918. StringBuffer err;
  919. E->errorMessage(err);
  920. encodeXML(err.str(), message);
  921. message.append("</Message></Exception>");
  922. unsigned len = message.length();
  923. void *ret = output->getBuffer(len+1, true);
  924. memcpy(ret, message.str(), len+1);
  925. output->putBuffer(ret, len+1, true);
  926. output->flush(true);
  927. E->Release();
  928. }
  929. catch (IException *EInE)
  930. {
  931. EXCLOG(EInE, "Exception during throwRemoteException");
  932. E->Release();
  933. EInE->Release();
  934. }
  935. catch (...)
  936. {
  937. logctx.CTXLOG("Unknown Exception during throwRemoteException");
  938. E->Release();
  939. }
  940. }
  941. void doActivity()
  942. {
  943. RoxiePacketHeader &header = packet->queryHeader();
  944. unsigned channel = header.channel;
  945. hash64_t queryHash = packet->queryHeader().queryHash;
  946. unsigned activityId = packet->queryHeader().activityId & ~ROXIE_PRIORITY_MASK;
  947. Owned<IQueryFactory> queryFactory = getQueryFactory(queryHash, channel);
  948. if (!queryFactory && logctx.queryWuid())
  949. {
  950. Owned <IRoxieDaliHelper> daliHelper = connectToDali();
  951. Owned<IConstWorkUnit> wu = daliHelper->attachWorkunit(logctx.queryWuid(), NULL);
  952. SCMStringBuffer target;
  953. wu->getClusterName(target);
  954. queryFactory.setown(createSlaveQueryFactoryFromWu(wu, channel));
  955. if (queryFactory)
  956. cacheOnDemandQuery(queryHash, channel, queryFactory);
  957. }
  958. if (!queryFactory)
  959. {
  960. StringBuffer hdr;
  961. IException *E = MakeStringException(MSGAUD_operator, ROXIE_UNKNOWN_QUERY, "Roxie slave received request for unregistered query: %s", packet->queryHeader().toString(hdr).str());
  962. EXCLOG(E, "doActivity");
  963. throwRemoteException(E, activity, packet, false);
  964. return;
  965. }
  966. try
  967. {
  968. if (logctx.queryTraceLevel() > 8)
  969. {
  970. StringBuffer x;
  971. logctx.CTXLOG("IBYTI delay controls : doIbytiDelay=%s numslaves=%u subchnl=%u : %s",
  972. doIbytiDelay?"YES":"NO",
  973. numSlaves[channel], subChannels[channel],
  974. header.toString(x).str());
  975. }
  976. bool debugging = logctx.queryDebuggerActive();
  977. if (debugging)
  978. {
  979. if (subChannels[channel] != 1)
  980. abortJob = true; // when debugging, we always run on primary only...
  981. }
  982. else if (doIbytiDelay && (numSlaves[channel] > 1))
  983. {
  984. bool primChannel = true;
  985. if (subChannels[channel] != 1)
  986. primChannel = false;
  987. bool myTurnToDelayIBYTI = true; // all slaves will delay, except one
  988. unsigned hdrHashVal = header.priorityHash();
  989. if ((((hdrHashVal % numSlaves[channel]) + 1) == subChannels[channel]))
  990. myTurnToDelayIBYTI = false;
  991. if (myTurnToDelayIBYTI)
  992. {
  993. unsigned delay = getIbytiDelay(channel, header);
  994. if (logctx.queryTraceLevel() > 6)
  995. {
  996. StringBuffer x;
  997. logctx.CTXLOG("YES myTurnToDelayIBYTI channel=%s delay=%u hash=%u %s", primChannel?"primary":"secondary", delay, hdrHashVal, header.toString(x).str());
  998. }
  999. // MORE: this code puts the penalty on all slaves on this channel,
  1000. // change it to have one for each slave on every channel.
  1001. // NOT critical for the time being with 2 slaves per channel
  1002. // MORE: if we are dealing with a query that was on channel 0, we may want a longer delay
  1003. // (since the theory about duplicated work not mattering when cluster is idle does not hold up)
  1004. if (delay)
  1005. {
  1006. ibytiSem.wait(delay);
  1007. if (abortJob)
  1008. resetIbytiDelay(channel); // we know there is an active buddy on the channel...
  1009. else
  1010. decIbytiDelay(channel);
  1011. if (logctx.queryTraceLevel() > 8)
  1012. {
  1013. StringBuffer x;
  1014. logctx.CTXLOG("Buddy did%s send IBYTI, updated delay=%u : %s",
  1015. abortJob ? "" : " NOT", IBYTIDelays[channel], header.toString(x).str());
  1016. }
  1017. }
  1018. }
  1019. else {
  1020. #ifndef NO_IBYTI_DELAYS_COUNT
  1021. if (primChannel) atomic_inc(&ibytiNoDelaysPrm);
  1022. else atomic_inc(&ibytiNoDelaysSec);
  1023. #endif
  1024. if (logctx.queryTraceLevel() > 6)
  1025. {
  1026. StringBuffer x;
  1027. logctx.CTXLOG("NOT myTurnToDelayIBYTI channel=%s hash=%u %s", primChannel?"primary":"secondary", hdrHashVal, header.toString(x).str());
  1028. }
  1029. }
  1030. }
  1031. if (abortJob)
  1032. {
  1033. CriticalBlock b(actCrit);
  1034. busy = false; // Keep order - before setActivity below
  1035. if (logctx.queryTraceLevel() > 5)
  1036. {
  1037. StringBuffer x;
  1038. logctx.CTXLOG("Stop before processing - activity aborted %s", header.toString(x).str());
  1039. }
  1040. return;
  1041. }
  1042. if (!debugging)
  1043. ROQ->sendIbyti(header, logctx);
  1044. atomic_inc(&activitiesStarted);
  1045. Owned <ISlaveActivityFactory> factory = queryFactory->getSlaveActivityFactory(activityId);
  1046. assertex(factory);
  1047. setActivity(factory->createActivity(logctx, packet));
  1048. #ifdef TEST_SLAVE_FAILURE
  1049. bool skip = false;
  1050. if (testSlaveFailure)
  1051. {
  1052. // Meaning of each byte in testSlaveFailure
  1053. // bits 1 -> 4 : test cast type (4 bits)
  1054. // bits 5 -> 11 : test case Freq (7 bits)
  1055. // bit 12 : : 1 Dot NOT Send ROXIE_ALIVE message - 0: send it
  1056. // bits 13 -> 32 : test case parameter (20 bits), if any
  1057. unsigned testCaseType = (testSlaveFailure & 0x0000000F);
  1058. unsigned testCaseFreq = (testSlaveFailure & 0x000007F0) >> 4;
  1059. unsigned testCaseParm = (testSlaveFailure & 0xFFFFF000) >> 12;
  1060. if (testCaseFreq && (atomic_read(&activitiesStarted) % testCaseFreq == 0))
  1061. {
  1062. StringBuffer x;
  1063. logctx.CTXLOG("------------ TestSlaveFailure to do the following (testCase=%u freq=%u tot=%u parm=%u ROXIE_ALIVE is %s - val=0x%.8X) for %s",
  1064. testCaseType, testCaseFreq, (unsigned) atomic_read(&activitiesStarted), testCaseParm, (testSlaveFailure & 0x800) ? "OFF" : "ON",
  1065. testSlaveFailure, header.toString(x).str());
  1066. switch (testCaseType)
  1067. {
  1068. case 1:
  1069. if (testCaseParm == 0) testCaseParm = 10000;
  1070. logctx.CTXLOG("--------------- Sleeping for %u ms - testCase=%u", testCaseParm, testCaseType);
  1071. Sleep(testCaseParm);
  1072. break;
  1073. case 2:
  1074. logctx.CTXLOG("--------------- Skip processing - testCase=%u ------", testCaseType);
  1075. skip = true;
  1076. break;
  1077. case 3:
  1078. logctx.CTXLOG("--------------- Throwing Exception String number %u NOW - testCase=%u -----", ROXIE_FILE_ERROR, testCaseType);
  1079. throw MakeStringException(ROXIE_FILE_ERROR, "Simulate File Exception in slave NOW");
  1080. break;
  1081. case 4:
  1082. if (numSlaves[channel] == 1)
  1083. {
  1084. logctx.CTXLOG("--------------- Setting numSlaves[channel=%u] to 2 to force one way to act as two way for ibyti logic testing - testCase=%u ------", channel, testCaseType);
  1085. numSlaves[channel] = 2;
  1086. }
  1087. testSlaveFailure = 0;
  1088. break;
  1089. }
  1090. }
  1091. }
  1092. if (!skip)
  1093. {
  1094. #endif
  1095. Owned<IMessagePacker> output = activity->process();
  1096. if (logctx.queryTraceLevel() > 5)
  1097. {
  1098. StringBuffer x;
  1099. logctx.CTXLOG("done processing %s", header.toString(x).str());
  1100. }
  1101. if (output)
  1102. {
  1103. atomic_inc(&activitiesCompleted);
  1104. busy = false; // Keep order - before setActivity below
  1105. setActivity(NULL); // Ensures all stats are merged from child queries etc
  1106. logctx.flush();
  1107. output->flush(true);
  1108. }
  1109. #ifdef TEST_SLAVE_FAILURE
  1110. }
  1111. #endif
  1112. }
  1113. catch (IUserException *E)
  1114. {
  1115. throwRemoteException(E, activity, packet, true);
  1116. }
  1117. catch (IException *E)
  1118. {
  1119. if (E->errorCode()!=ROXIE_ABORT_ERROR)
  1120. throwRemoteException(E, activity, packet, false);
  1121. }
  1122. catch (...)
  1123. {
  1124. throwRemoteException(MakeStringException(ROXIE_MULTICAST_ERROR, "Unknown exception"), activity, packet, false);
  1125. }
  1126. busy = false; // Keep order - before setActivity below
  1127. setActivity(NULL);
  1128. }
  1129. void main()
  1130. {
  1131. while (!stopped)
  1132. {
  1133. try
  1134. {
  1135. loop
  1136. {
  1137. queue->wait();
  1138. if (stopped)
  1139. break;
  1140. {
  1141. CriticalBlock b(counterCrit);
  1142. slavesActive++;
  1143. if (slavesActive > maxSlavesActive)
  1144. maxSlavesActive = slavesActive;
  1145. }
  1146. abortJob = false;
  1147. busy = true;
  1148. if (doIbytiDelay)
  1149. ibytiSem.reinit(0U); // Make sure sem is is in no-signaled state
  1150. {
  1151. CriticalBlock b(queueCrit);
  1152. packet.setown(queue->dequeue());
  1153. }
  1154. if (packet)
  1155. {
  1156. {
  1157. CriticalBlock b(counterCrit);
  1158. queueLength--;
  1159. }
  1160. RoxiePacketHeader &header = packet->queryHeader();
  1161. logctx.set(packet);
  1162. #ifdef TIME_PACKETS
  1163. {
  1164. unsigned now = msTick();
  1165. unsigned packetWait = now-header.tick;
  1166. header.tick = now;
  1167. CriticalBlock b(counterCrit);
  1168. if (packetWait > packetWaitMax)
  1169. packetWaitMax = packetWait;
  1170. packetWaitElapsed += packetWait;
  1171. atomic_inc(&packetWaitCount);
  1172. }
  1173. #endif
  1174. if (logctx.queryTraceLevel() > 10)
  1175. {
  1176. StringBuffer x;
  1177. logctx.CTXLOG("dequeued %s", header.toString(x).str());
  1178. }
  1179. if (ROQ->checkSuspended(header, logctx))
  1180. {
  1181. StringBuffer s;
  1182. logctx.CTXLOG("Ignoring packet for suspended channel %d: %s", header.channel, header.toString(s).str());
  1183. }
  1184. else if ((header.activityId & ~ROXIE_PRIORITY_MASK) == ROXIE_UNLOAD)
  1185. {
  1186. doUnload(packet, logctx);
  1187. }
  1188. else if ((header.activityId & ~ROXIE_PRIORITY_MASK) == ROXIE_PING)
  1189. {
  1190. doPing(packet, logctx);
  1191. }
  1192. else if ((header.activityId & ~ROXIE_PRIORITY_MASK) == ROXIE_DEBUGREQUEST)
  1193. {
  1194. // MORE - we need to make sure only executed on primary, and that the proxyId (== pointer to DebugGraphManager) is still valid.
  1195. // It may be that there is not a lot of point using the pointer - may as well use an non-reused ID and look it up in a global hash table of active ones
  1196. doDebugRequest(packet, logctx);
  1197. }
  1198. else if (header.channel)
  1199. doActivity();
  1200. else
  1201. throwUnexpected(); // channel 0 requests translated earlier now
  1202. #ifdef TIME_PACKETS
  1203. {
  1204. unsigned now = msTick();
  1205. unsigned packetRun = now-header.tick;
  1206. CriticalBlock b(counterCrit);
  1207. if (packetRun > packetRunMax)
  1208. packetRunMax = packetRun;
  1209. packetRunElapsed += packetRun;
  1210. atomic_inc(&packetRunCount);
  1211. }
  1212. #endif
  1213. }
  1214. busy = false;
  1215. {
  1216. CriticalBlock b(actCrit);
  1217. packet.clear();
  1218. logctx.set(NULL);
  1219. }
  1220. {
  1221. CriticalBlock b(counterCrit);
  1222. slavesActive--;
  1223. }
  1224. }
  1225. }
  1226. catch(...)
  1227. {
  1228. CriticalBlock b(actCrit);
  1229. Owned<IException> E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unexpected exception in Roxie worker thread");
  1230. EXCLOG(E);
  1231. if (packet)
  1232. throwRemoteException(E.getClear(), NULL, packet, false);
  1233. packet.clear();
  1234. }
  1235. }
  1236. }
  1237. };
  1238. //=================================================================================
  1239. class CallbackEntry : public CInterface, implements IPendingCallback
  1240. {
  1241. const RoxiePacketHeader &header;
  1242. StringAttr lfn;
  1243. InterruptableSemaphore ready;
  1244. MemoryBuffer data;
  1245. bool gotData;
  1246. public:
  1247. IMPLEMENT_IINTERFACE;
  1248. CallbackEntry(const RoxiePacketHeader &_header, const char *_lfn) : header(_header), lfn(_lfn)
  1249. {
  1250. gotData = false;
  1251. }
  1252. virtual bool wait(unsigned msecs)
  1253. {
  1254. return ready.wait(msecs);
  1255. }
  1256. virtual MemoryBuffer &queryData()
  1257. {
  1258. return data;
  1259. }
  1260. bool matches(RoxiePacketHeader &cand, const char *_lfn)
  1261. {
  1262. return (cand.matchPacket(header) && (!_lfn|| stricmp(_lfn, lfn)==0));
  1263. }
  1264. void doFileCallback(unsigned _len, const void *_data, bool aborted)
  1265. {
  1266. // MORE - make sure we call this for whole query abort as well as for callback abort
  1267. if (aborted)
  1268. ready.interrupt(MakeStringException(0, "Interrupted"));
  1269. else if (!gotData)
  1270. {
  1271. gotData = true;
  1272. data.append(_len, _data);
  1273. ready.signal();
  1274. }
  1275. }
  1276. };
  1277. class RoxieReceiverBase : public CInterface, implements IThreadFactory, implements IRoxieOutputQueueManager
  1278. {
  1279. protected:
  1280. #ifdef ROXIE_SLA_LOGIC
  1281. RoxieQueue slaQueue;
  1282. Owned <IThreadPool> slaWorkers;
  1283. #endif
  1284. RoxieQueue hiQueue;
  1285. Owned <IThreadPool> hiWorkers;
  1286. RoxieQueue loQueue;
  1287. Owned <IThreadPool> loWorkers;
  1288. unsigned numWorkers;
  1289. void abortChannel(unsigned channel, IThreadPool *workers)
  1290. {
  1291. Owned<IPooledThreadIterator> wi = workers->running();
  1292. ForEach(*wi)
  1293. {
  1294. CRoxieWorker &w = (CRoxieWorker &) wi->query();
  1295. w.abortChannel(channel);
  1296. }
  1297. }
  1298. public:
  1299. IMPLEMENT_IINTERFACE;
  1300. #ifdef ROXIE_SLA_LOGIC
  1301. RoxieReceiverBase(unsigned _numWorkers) : numWorkers(_numWorkers), slaQueue(headRegionSize), hiQueue(headRegionSize), loQueue(headRegionSize)
  1302. #else
  1303. RoxieReceiverBase(unsigned _numWorkers) : numWorkers(_numWorkers), hiQueue(headRegionSize), loQueue(headRegionSize)
  1304. #endif
  1305. {
  1306. loWorkers.setown(createThreadPool("RoxieLoWorkers", this, NULL, numWorkers));
  1307. hiWorkers.setown(createThreadPool("RoxieHiWorkers", this, NULL, numWorkers));
  1308. #ifdef ROXIE_SLA_LOGIC
  1309. slaWorkers.setown(createThreadPool("RoxieSLAWorkers", this, NULL, numWorkers));
  1310. #endif
  1311. CriticalBlock b(ccdChannelsCrit);
  1312. Owned<IPropertyTreeIterator> it = ccdChannels->getElements("RoxieSlaveProcess");
  1313. ForEach(*it)
  1314. {
  1315. unsigned channel = it->query().getPropInt("@channel", 0);
  1316. unsigned subChannel = it->query().getPropInt("@subChannel", 0);
  1317. assertex(channel <= numChannels);
  1318. assertex(subChannels[channel] == 0);
  1319. assertex(subChannel != 0);
  1320. subChannels[channel] = subChannel;
  1321. IBYTIDelays[channel] = initIbytiDelay;
  1322. channels[channelCount++] = channel;
  1323. }
  1324. }
  1325. virtual bool checkSuspended(const RoxiePacketHeader &header, const IRoxieContextLogger &logctx)
  1326. {
  1327. bool suspended;
  1328. {
  1329. SpinBlock b(suspendCrit);
  1330. suspended = suspendedChannels[header.channel];
  1331. }
  1332. if (suspended)
  1333. {
  1334. try
  1335. {
  1336. RoxiePacketHeader newHeader(header, ROXIE_EXCEPTION);
  1337. Owned<IMessagePacker> output = ROQ->createOutputStream(newHeader, true, logctx);
  1338. StringBuffer message;
  1339. message.appendf("<Exception><Code>%d</Code><Message>Channel %d is suspended</Message></Exception>", ROXIE_CHANNEL_SUSPENDED, header.channel);
  1340. unsigned len = message.length();
  1341. void *ret = output->getBuffer(len+1, true);
  1342. memcpy(ret, message.str(), len+1);
  1343. output->putBuffer(ret, len+1, true);
  1344. output->flush(true);
  1345. }
  1346. catch (IException *EInE)
  1347. {
  1348. EXCLOG(EInE, "Exception during checkSuspended");
  1349. EInE->Release();
  1350. }
  1351. catch (...)
  1352. {
  1353. logctx.CTXLOG("Unknown Exception during checkSuspended");
  1354. }
  1355. }
  1356. return suspended;
  1357. }
  1358. virtual bool suspendChannel(unsigned channel, bool suspend, const IRoxieContextLogger &logctx)
  1359. {
  1360. assertex(channel < MAX_CLUSTER_SIZE);
  1361. bool prev;
  1362. {
  1363. SpinBlock b(suspendCrit);
  1364. prev = suspendedChannels[channel];
  1365. suspendedChannels[channel] = suspend;
  1366. }
  1367. if (suspend && subChannels[channel] && !prev)
  1368. {
  1369. logctx.CTXLOG("ERROR: suspending channel %d - aborting active queries", channel);
  1370. #ifdef ROXIE_SLA_LOGIC
  1371. abortChannel(channel, slaWorkers);
  1372. #endif
  1373. abortChannel(channel, hiWorkers);
  1374. abortChannel(channel, loWorkers);
  1375. }
  1376. return prev;
  1377. }
  1378. virtual unsigned getHeadRegionSize() const
  1379. {
  1380. return loQueue.getHeadRegionSize();
  1381. }
  1382. virtual void setHeadRegionSize(unsigned newSize)
  1383. {
  1384. #ifdef ROXIE_SLA_LOGIC
  1385. slaQueue.setHeadRegionSize(newSize);
  1386. #endif
  1387. hiQueue.setHeadRegionSize(newSize);
  1388. loQueue.setHeadRegionSize(newSize);
  1389. }
  1390. virtual void start()
  1391. {
  1392. for (unsigned i = 0; i < numWorkers; i++)
  1393. {
  1394. // MORE - why would we have same number of each?
  1395. // MORE - All workers (hi or low) have same sys priority, same number of workers,
  1396. // and same queue size ... What can make a query marked high priority
  1397. // get prioity of resource over low one ?
  1398. // MORE: I think we may want to have one set of worker threads that gets jobs of 2 (or 3 with SLA)
  1399. // queues (sla, high, and low). These workers will give higher priority for jobs
  1400. // on higher priority queues but without starving low ones... something similar to what
  1401. // I implemented in UDP output queues.
  1402. // For the time being, I will keep as is, and just add SLA queue and workers.
  1403. loWorkers->start(&loQueue);
  1404. hiWorkers->start(&hiQueue);
  1405. #ifdef ROXIE_SLA_LOGIC
  1406. slaWorkers->start(&slaQueue);
  1407. #endif
  1408. }
  1409. }
  1410. virtual void stop()
  1411. {
  1412. loWorkers->stopAll(true);
  1413. loQueue.signal(loWorkers->runningCount()); // MORE - looks like a race here... interruptableSemaphore would be better
  1414. hiWorkers->stopAll(true);
  1415. hiQueue.signal(hiWorkers->runningCount());
  1416. #ifdef ROXIE_SLA_LOGIC
  1417. slaWorkers->stopAll(true);
  1418. slaQueue.signal(slaWorkers->runningCount());
  1419. #endif
  1420. }
  1421. virtual void join()
  1422. {
  1423. #ifdef ROXIE_SLA_LOGIC
  1424. slaWorkers->joinAll(true);
  1425. #endif
  1426. hiWorkers->joinAll(true);
  1427. loWorkers->joinAll(true);
  1428. loWorkers.clear(); // Breaks a cyclic reference count that would stop us from releasing RoxieReceiverThread otherwise
  1429. hiWorkers.clear();
  1430. #ifdef ROXIE_SLA_LOGIC
  1431. slaWorkers.clear();
  1432. #endif
  1433. }
  1434. virtual IPooledThread *createNew()
  1435. {
  1436. return new CRoxieWorker;
  1437. }
  1438. IArrayOf<CallbackEntry> callbacks;
  1439. CriticalSection callbacksCrit;
  1440. virtual IPendingCallback *notePendingCallback(const RoxiePacketHeader &header, const char *lfn)
  1441. {
  1442. CriticalBlock b(callbacksCrit);
  1443. CallbackEntry *callback = new CallbackEntry(header, lfn);
  1444. callbacks.append(*callback);
  1445. return callback;
  1446. }
  1447. virtual void removePendingCallback(IPendingCallback *goer)
  1448. {
  1449. if (goer)
  1450. {
  1451. CriticalBlock b(callbacksCrit);
  1452. callbacks.zap(static_cast<CallbackEntry &>(*goer));
  1453. }
  1454. }
  1455. protected:
  1456. void doFileCallback(IRoxieQueryPacket *packet)
  1457. {
  1458. // This is called on the main slave reader thread so needs to be as fast as possible to avoid lost packets
  1459. const char *lfn;
  1460. const char *data;
  1461. unsigned len;
  1462. RoxiePacketHeader &header = packet->queryHeader();
  1463. if (header.activityId == ROXIE_FILECALLBACK || header.activityId == ROXIE_DEBUGCALLBACK)
  1464. {
  1465. lfn = (const char *) packet->queryContextData();
  1466. unsigned namelen = strlen(lfn) + 1;
  1467. data = lfn + namelen;
  1468. len = packet->getContextLength() - namelen;
  1469. }
  1470. else
  1471. {
  1472. lfn = data = NULL; // used when query aborted
  1473. len = 0;
  1474. }
  1475. CriticalBlock b(callbacksCrit);
  1476. ForEachItemIn(idx, callbacks)
  1477. {
  1478. CallbackEntry &c = callbacks.item(idx);
  1479. if (c.matches(header, lfn))
  1480. {
  1481. if (traceLevel > 10)
  1482. DBGLOG("callback return matched a waiting query");
  1483. c.doFileCallback(len, data, header.retries==QUERY_ABORTED);
  1484. }
  1485. }
  1486. }
  1487. };
  1488. #ifdef _MSC_VER
  1489. #pragma warning ( push )
  1490. #pragma warning ( disable: 4355 )
  1491. #endif
  1492. class RoxieThrottledPacketSender : public Thread
  1493. {
  1494. TokenBucket &bucket;
  1495. InterruptableSemaphore queued;
  1496. Semaphore started;
  1497. unsigned maxPacketSize;
  1498. SafeQueueOf<IRoxieQueryPacket, false> queue;
  1499. class StoppedException: public CInterface, public IException
  1500. {
  1501. public:
  1502. IMPLEMENT_IINTERFACE;
  1503. int errorCode() const { return 0; }
  1504. StringBuffer & errorMessage(StringBuffer &str) const { return str.append("Stopped"); }
  1505. MessageAudience errorAudience() const { return MSGAUD_user; }
  1506. };
  1507. void enqueue(IRoxieQueryPacket *packet)
  1508. {
  1509. packet->Link();
  1510. queue.enqueue(packet);
  1511. queued.signal();
  1512. }
  1513. IRoxieQueryPacket *dequeue()
  1514. {
  1515. queued.wait();
  1516. return queue.dequeue();
  1517. }
  1518. public:
  1519. RoxieThrottledPacketSender(TokenBucket &_bucket, unsigned _maxPacketSize)
  1520. : Thread("RoxieThrottledPacketSender"), bucket(_bucket), maxPacketSize(_maxPacketSize)
  1521. {
  1522. start();
  1523. started.wait();
  1524. }
  1525. ~RoxieThrottledPacketSender()
  1526. {
  1527. stop();
  1528. join();
  1529. }
  1530. virtual int run()
  1531. {
  1532. started.signal();
  1533. loop
  1534. {
  1535. try
  1536. {
  1537. Owned<IRoxieQueryPacket> packet = dequeue();
  1538. RoxiePacketHeader &header = packet->queryHeader();
  1539. unsigned length = packet->queryHeader().packetlength;
  1540. {
  1541. MTIME_SECTION(queryActiveTimer(), "bucket_wait");
  1542. bucket.wait((length / 1024) + 1);
  1543. }
  1544. if (channelWrite(header.channel, &header, length) != length)
  1545. DBGLOG("multicast write wrote too little");
  1546. atomic_inc(&packetsSent);
  1547. }
  1548. catch (StoppedException *E)
  1549. {
  1550. E->Release();
  1551. break;
  1552. }
  1553. catch (IException *E)
  1554. {
  1555. EXCLOG(E);
  1556. E->Release();
  1557. }
  1558. catch (...)
  1559. {
  1560. }
  1561. }
  1562. return 0;
  1563. }
  1564. virtual void sendPacket(IRoxieQueryPacket *x, const IRoxieContextLogger &logctx)
  1565. {
  1566. RoxiePacketHeader &header = x->queryHeader();
  1567. unsigned length = x->queryHeader().packetlength;
  1568. assertex (header.activityId & ~ROXIE_PRIORITY_MASK);
  1569. switch (header.retries & ROXIE_RETRIES_MASK)
  1570. {
  1571. case (QUERY_ABORTED & ROXIE_RETRIES_MASK):
  1572. {
  1573. StringBuffer s;
  1574. logctx.CTXLOG("Aborting packet size=%d: %s", length, header.toString(s).str());
  1575. }
  1576. break;
  1577. default:
  1578. {
  1579. StringBuffer s;
  1580. logctx.CTXLOG("Resending packet size=%d: %s", length, header.toString(s).str());
  1581. }
  1582. break;
  1583. case 0:
  1584. if (logctx.queryTraceLevel() > 8)
  1585. {
  1586. StringBuffer s;
  1587. logctx.CTXLOG("Sending packet size=%d: %s", length, header.toString(s).str());
  1588. }
  1589. break;
  1590. }
  1591. if (length > maxPacketSize)
  1592. {
  1593. StringBuffer s;
  1594. throw MakeStringException(ROXIE_PACKET_ERROR, "Maximum packet length %d exceeded sending packet %s", maxPacketSize, header.toString(s).str());
  1595. }
  1596. enqueue(x);
  1597. }
  1598. void stop()
  1599. {
  1600. // bucket.stop();
  1601. queued.interrupt(new StoppedException);
  1602. }
  1603. };
  1604. class RoxieSocketQueueManager : public RoxieReceiverBase
  1605. {
  1606. unsigned maxPacketSize;
  1607. bool running;
  1608. Linked<ISendManager> sendManager;
  1609. Linked<IReceiveManager> receiveManager;
  1610. Owned<TokenBucket> bucket;
  1611. class ReceiverThread : public Thread
  1612. {
  1613. RoxieSocketQueueManager &parent;
  1614. public:
  1615. ReceiverThread(RoxieSocketQueueManager &_parent) : parent(_parent), Thread("RoxieSocketQueueManager") {}
  1616. int run()
  1617. {
  1618. // Raise the priority so ibyti's get through in a timely fashion
  1619. #ifdef __linux__
  1620. setLinuxThreadPriority(3);
  1621. #else
  1622. adjustPriority(1);
  1623. #endif
  1624. return parent.run();
  1625. }
  1626. } readThread;
  1627. public:
  1628. RoxieSocketQueueManager(unsigned snifferChannel, unsigned _numWorkers) : RoxieReceiverBase(_numWorkers), readThread(*this)
  1629. {
  1630. int udpQueueSize = topology->getPropInt("@udpQueueSize", UDP_QUEUE_SIZE);
  1631. int udpSendQueueSize = topology->getPropInt("@udpSendQueueSize", UDP_SEND_QUEUE_SIZE);
  1632. int udpMaxSlotsPerClient = topology->getPropInt("@udpMaxSlotsPerClient", 0x7fffffff);
  1633. #ifdef _DEBUG
  1634. bool udpResendEnabled = topology->getPropBool("@udpResendEnabled", false);
  1635. #else
  1636. bool udpResendEnabled = false; // As long as it is known to be broken, we don't want it accidentally enabled in any release version
  1637. #endif
  1638. maxPacketSize = multicastSocket->get_max_send_size();
  1639. if ((maxPacketSize==0)||(maxPacketSize>65535))
  1640. maxPacketSize = 65535;
  1641. if (topology->getPropInt("@sendMaxRate", 0))
  1642. {
  1643. unsigned sendMaxRate = topology->getPropInt("@sendMaxRate");
  1644. unsigned sendMaxRatePeriod = topology->getPropInt("@sendMaxRatePeriod", 1);
  1645. bucket.setown(new TokenBucket(sendMaxRate, sendMaxRatePeriod, sendMaxRate));
  1646. throttledPacketSendManager.setown(new RoxieThrottledPacketSender(*bucket, maxPacketSize));
  1647. }
  1648. IpAddress snifferIp;
  1649. getChannelIp(snifferIp, snifferChannel);
  1650. if (udpMaxSlotsPerClient > udpQueueSize)
  1651. udpMaxSlotsPerClient = udpQueueSize;
  1652. unsigned serverFlowPort = topology->getPropInt("@serverFlowPort", CCD_SERVER_FLOW_PORT);
  1653. unsigned dataPort = topology->getPropInt("@dataPort", CCD_DATA_PORT);
  1654. unsigned clientFlowPort = topology->getPropInt("@clientFlowPort", CCD_CLIENT_FLOW_PORT);
  1655. unsigned snifferPort = topology->getPropInt("@snifferPort", CCD_SNIFFER_PORT);
  1656. receiveManager.setown(createReceiveManager(serverFlowPort, dataPort, clientFlowPort, snifferPort, snifferIp, udpQueueSize, udpMaxSlotsPerClient, myNodeIndex));
  1657. sendManager.setown(createSendManager(serverFlowPort, dataPort, clientFlowPort, snifferPort, snifferIp, udpSendQueueSize, fastLaneQueue ? 3 : 2, udpResendEnabled ? udpMaxSlotsPerClient : 0, bucket, myNodeIndex));
  1658. running = false;
  1659. }
  1660. CriticalSection crit;
  1661. Owned<RoxieThrottledPacketSender> throttledPacketSendManager;
  1662. virtual void sendPacket(IRoxieQueryPacket *x, const IRoxieContextLogger &logctx)
  1663. {
  1664. if (throttledPacketSendManager)
  1665. throttledPacketSendManager->sendPacket(x, logctx);
  1666. else
  1667. {
  1668. MTIME_SECTION(queryActiveTimer(), "RoxieSocketQueueManager::sendPacket");
  1669. RoxiePacketHeader &header = x->queryHeader();
  1670. unsigned length = x->queryHeader().packetlength;
  1671. assertex (header.activityId & ~ROXIE_PRIORITY_MASK);
  1672. StringBuffer s;
  1673. switch (header.retries & ROXIE_RETRIES_MASK)
  1674. {
  1675. case (QUERY_ABORTED & ROXIE_RETRIES_MASK):
  1676. logctx.CTXLOG("Aborting packet size=%d: %s", length, header.toString(s).str());
  1677. break;
  1678. default:
  1679. logctx.CTXLOG("Resending packet size=%d: %s", length, header.toString(s).str());
  1680. break;
  1681. case 0:
  1682. if (logctx.queryTraceLevel() > 8)
  1683. logctx.CTXLOG("Sending packet size=%d: %s", length, header.toString(s).str());
  1684. break;
  1685. }
  1686. // MORE - crashes have been observed after exceptions here - mechanism not yet clear nor reproducible
  1687. if (length > maxPacketSize)
  1688. {
  1689. StringBuffer s;
  1690. throw MakeStringException(ROXIE_PACKET_ERROR, "Maximum packet length %d exceeded sending packet %s", maxPacketSize, header.toString(s).str());
  1691. }
  1692. CriticalBlock c(crit); // is this needed or was it just protecting multicast array? prevent interleaving?
  1693. if (channelWrite(header.channel, &header, length) != length)
  1694. logctx.CTXLOG("multicast write wrote too little");
  1695. atomic_inc(&packetsSent);
  1696. }
  1697. }
  1698. virtual void sendIbyti(RoxiePacketHeader &header, const IRoxieContextLogger &logctx)
  1699. {
  1700. MTIME_SECTION(queryActiveTimer(), "RoxieSocketQueueManager::sendIbyti");
  1701. RoxiePacketHeader ibytiHeader(header, header.activityId & ROXIE_PRIORITY_MASK);
  1702. if (logctx.queryTraceLevel() > 8)
  1703. {
  1704. StringBuffer s; logctx.CTXLOG("Sending IBYTI packet %s", ibytiHeader.toString(s).str());
  1705. }
  1706. CriticalBlock c(crit); // Not sure we really need this? Preventing interleave on writes? Should sock manage it?
  1707. if (channelWrite(header.channel, &ibytiHeader, sizeof(RoxiePacketHeader)) != sizeof(RoxiePacketHeader))
  1708. logctx.CTXLOG("sendIbyti wrote too little");
  1709. atomic_inc(&ibytiPacketsSent);
  1710. }
  1711. virtual void sendAbort(RoxiePacketHeader &header, const IRoxieContextLogger &logctx)
  1712. {
  1713. MTIME_SECTION(queryActiveTimer(), "RoxieSocketQueueManager::sendAbort");
  1714. RoxiePacketHeader abortHeader(header, header.activityId & ROXIE_PRIORITY_MASK);
  1715. abortHeader.retries = QUERY_ABORTED;
  1716. if (logctx.queryTraceLevel() > 8)
  1717. {
  1718. StringBuffer s; logctx.CTXLOG("Sending ABORT packet %s", abortHeader.toString(s).str());
  1719. }
  1720. CriticalBlock c(crit); // Not sure we really need this? Preventing interleave on writes? Should sock manage it?
  1721. if (channelWrite(header.channel, &abortHeader, sizeof(RoxiePacketHeader)) != sizeof(RoxiePacketHeader))
  1722. logctx.CTXLOG("sendAbort wrote too little");
  1723. atomic_inc(&abortsSent);
  1724. }
  1725. virtual void sendAbortCallback(const RoxiePacketHeader &header, const char *lfn, const IRoxieContextLogger &logctx)
  1726. {
  1727. MTIME_SECTION(queryActiveTimer(), "RoxieSocketQueueManager::sendAbortCallback");
  1728. RoxiePacketHeader abortHeader(header, ROXIE_FILECALLBACK);
  1729. abortHeader.retries = QUERY_ABORTED;
  1730. MemoryBuffer data;
  1731. data.append(sizeof(abortHeader), &abortHeader).append(lfn);
  1732. if (logctx.queryTraceLevel() > 5)
  1733. {
  1734. StringBuffer s; logctx.CTXLOG("Sending ABORT FILECALLBACK packet %s for file %s", abortHeader.toString(s).str(), lfn);
  1735. }
  1736. CriticalBlock c(crit); // Not sure we really need this? Preventing interleave on writes? Should sock manage it?
  1737. if (channelWrite(header.channel, data.toByteArray(), data.length()) != data.length())
  1738. logctx.CTXLOG("tr->write wrote too little");
  1739. atomic_inc(&abortsSent);
  1740. }
  1741. virtual IMessagePacker *createOutputStream(RoxiePacketHeader &header, bool outOfBand, const IRoxieContextLogger &logctx)
  1742. {
  1743. unsigned qnum = outOfBand ? 0 : ((header.retries & ROXIE_FASTLANE) || !fastLaneQueue) ? 1 : 2;
  1744. if (logctx.queryTraceLevel() > 8)
  1745. {
  1746. StringBuffer s; logctx.CTXLOG("Creating Output Stream for reply packet on Q=%d - %s", qnum, header.toString(s).str());
  1747. }
  1748. return sendManager->createMessagePacker(header.uid, header.getSequenceId(), &header, sizeof(RoxiePacketHeader), header.serverIdx, qnum);
  1749. }
  1750. virtual bool replyPending(RoxiePacketHeader &header)
  1751. {
  1752. return sendManager->dataQueued(header.uid, header.getSequenceId(), header.serverIdx);
  1753. }
  1754. virtual bool abortCompleted(RoxiePacketHeader &header)
  1755. {
  1756. return sendManager->abortData(header.uid, header.getSequenceId(), header.serverIdx);
  1757. }
  1758. bool abortRunning(RoxiePacketHeader &header, IThreadPool *workers, bool checkRank, bool &preActivity)
  1759. {
  1760. bool queryFound = false;
  1761. bool ret = false;
  1762. Owned<IPooledThreadIterator> wi = workers->running();
  1763. ForEach(*wi)
  1764. {
  1765. CRoxieWorker &w = (CRoxieWorker &) wi->query();
  1766. if (w.checkAbort(header, checkRank, queryFound, preActivity))
  1767. {
  1768. ret = true;
  1769. break;
  1770. }
  1771. else if (queryFound)
  1772. {
  1773. ret = false;
  1774. break;
  1775. }
  1776. }
  1777. if (!checkRank)
  1778. {
  1779. if (traceLevel > 8)
  1780. DBGLOG("discarding data for aborted query");
  1781. ROQ->abortCompleted(header);
  1782. }
  1783. return ret;
  1784. }
  1785. void doIbyti(RoxiePacketHeader &header, RoxieQueue &queue, IThreadPool *workers)
  1786. {
  1787. assertex(!localSlave);
  1788. atomic_inc(&ibytiPacketsReceived);
  1789. bool preActivity = false;
  1790. if (traceLevel > 10)
  1791. {
  1792. IpAddress peer;
  1793. StringBuffer s, s1;
  1794. multicastSocket->getPeerAddress(peer).getIpText(s);
  1795. header.toString(s1);
  1796. DBGLOG("doIBYTI %s from %s", s1.str(), s.str());
  1797. DBGLOG("header.retries=%x header.getSubChannelMask(header.channel)=%x", header.retries, header.getSubChannelMask(header.channel));
  1798. }
  1799. if (header.retries == QUERY_ABORTED)
  1800. {
  1801. abortRunning(header, workers, false, preActivity);
  1802. queue.remove(header);
  1803. if (traceLevel > 10)
  1804. {
  1805. StringBuffer s;
  1806. DBGLOG("Abort activity %s", header.toString(s).str());
  1807. }
  1808. }
  1809. else
  1810. {
  1811. if ((header.retries & ROXIE_RETRIES_MASK) == header.getSubChannelMask(header.channel))
  1812. {
  1813. if (traceLevel > 10)
  1814. DBGLOG("doIBYTI packet was from self");
  1815. atomic_inc(&ibytiPacketsFromSelf);
  1816. }
  1817. else
  1818. {
  1819. resetIbytiDelay(header.channel);
  1820. bool foundInQ;
  1821. {
  1822. CriticalBlock b(queueCrit);
  1823. foundInQ = queue.remove(header);
  1824. }
  1825. if (foundInQ) {
  1826. if (traceLevel > 10)
  1827. {
  1828. StringBuffer s;
  1829. DBGLOG("Removed activity from Q : %s", header.toString(s).str());
  1830. }
  1831. atomic_inc(&ibytiPacketsWorked);
  1832. return;
  1833. }
  1834. if (abortRunning(header, workers, true, preActivity))
  1835. {
  1836. if (preActivity)
  1837. atomic_inc(&ibytiPacketsWorked); // MORE - may want to have a diff counter for this (not in queue but in IBYTI wait or before)
  1838. else
  1839. atomic_inc(&ibytiPacketsHalfWorked);
  1840. return;
  1841. }
  1842. if (traceLevel > 10)
  1843. DBGLOG("doIBYTI packet was too late");
  1844. atomic_inc(&ibytiPacketsTooLate); // meaning either I started and reserve the right to finish, or I finished already
  1845. }
  1846. }
  1847. }
  1848. void processMessage(MemoryBuffer &mb, RoxiePacketHeader &header, RoxieQueue &queue, IThreadPool *workers)
  1849. {
  1850. // NOTE - this thread needs to do as little as possible - just read packets and queue them up - otherwise we can get packet loss due to buffer overflow
  1851. // DO NOT put tracing on this thread except at very high tracelevels!
  1852. if (header.activityId == ROXIE_FILECALLBACK || header.activityId == ROXIE_DEBUGCALLBACK )
  1853. {
  1854. Owned<IRoxieQueryPacket> packet = createRoxiePacket(mb);
  1855. if (traceLevel > 10)
  1856. {
  1857. StringBuffer s;
  1858. DBGLOG("ROXIE_CALLBACK %s", header.toString(s).str());
  1859. }
  1860. doFileCallback(packet);
  1861. }
  1862. else if ((header.activityId & ~ROXIE_PRIORITY_MASK) == 0)
  1863. doIbyti(header, queue, workers); // MORE - check how fast this is!
  1864. else
  1865. {
  1866. Owned<IRoxieQueryPacket> packet = createRoxiePacket(mb);
  1867. SlaveContextLogger logctx(packet);
  1868. unsigned retries = header.thisChannelRetries();
  1869. if (retries)
  1870. {
  1871. // MORE - is this fast enough? By the time I am seeing retries I may already be under load. Could move onto a separate thread
  1872. assertex(header.channel); // should never see a retry on channel 0
  1873. if (retries >= SUBCHANNEL_MASK)
  1874. return; // someone sent a failure or something - ignore it
  1875. // Send back an out-of-band immediately, to let Roxie server know that channel is still active
  1876. if (!(testSlaveFailure & 0x800))
  1877. {
  1878. RoxiePacketHeader newHeader(header, ROXIE_ALIVE);
  1879. Owned<IMessagePacker> output = ROQ->createOutputStream(newHeader, true, logctx);
  1880. output->flush(true);
  1881. }
  1882. // If it's a retry, look it up against already running, or output stream, or input queue
  1883. // if found, send an IBYTI and discard retry request
  1884. bool primChannel = true;
  1885. if (subChannels[header.channel] != 1) primChannel = false;
  1886. if (primChannel)
  1887. atomic_inc(&retriesReceivedPrm);
  1888. else
  1889. atomic_inc(&retriesReceivedSec);
  1890. bool alreadyRunning = false;
  1891. Owned<IPooledThreadIterator> wi = workers->running();
  1892. ForEach(*wi)
  1893. {
  1894. CRoxieWorker &w = (CRoxieWorker &) wi->query();
  1895. if (w.match(header))
  1896. {
  1897. alreadyRunning = true;
  1898. if (primChannel)
  1899. atomic_inc(&retriesIgnoredPrm);
  1900. else
  1901. atomic_inc(&retriesIgnoredSec);
  1902. ROQ->sendIbyti(header, logctx);
  1903. if (logctx.queryTraceLevel() > 10)
  1904. {
  1905. StringBuffer xx; logctx.CTXLOG("Ignored retry on %s channel for running activity %s", primChannel?"primary":"secondary", header.toString(xx).str());
  1906. }
  1907. break;
  1908. }
  1909. }
  1910. if (!alreadyRunning && checkCompleted && ROQ->replyPending(header))
  1911. {
  1912. alreadyRunning = true;
  1913. if (primChannel)
  1914. atomic_inc(&retriesIgnoredPrm);
  1915. else
  1916. atomic_inc(&retriesIgnoredSec);
  1917. ROQ->sendIbyti(header, logctx);
  1918. if (logctx.queryTraceLevel() > 10)
  1919. {
  1920. StringBuffer xx; logctx.CTXLOG("Ignored retry on %s channel for completed activity %s", primChannel?"primary":"secondary", header.toString(xx).str());
  1921. }
  1922. }
  1923. if (!alreadyRunning)
  1924. {
  1925. if (logctx.queryTraceLevel() > 10)
  1926. {
  1927. StringBuffer xx; logctx.CTXLOG("Retry %d received on %s channel for %s", retries+1, primChannel?"primary":"secondary", header.toString(xx).str());
  1928. }
  1929. queue.enqueueUnique(packet.getClear());
  1930. }
  1931. }
  1932. else // first time (not a retry).
  1933. {
  1934. if (header.channel)
  1935. {
  1936. queue.enqueue(packet.getClear());
  1937. }
  1938. else
  1939. {
  1940. // Turn broadcast packet (channel 0), as early as possible, into non-0 channel packets.
  1941. // So retries and other communication with Roxie server (which uses non-0 channel numbers) will not cause double work or confusion.
  1942. // Unfortunately this is bad news for dropping packets
  1943. for (unsigned i = 1; i < channelCount; i++)
  1944. queue.enqueue(packet->clonePacket(channels[i]));
  1945. header.channel = channels[0];
  1946. queue.enqueue(packet.getClear());
  1947. }
  1948. }
  1949. }
  1950. }
  1951. int run()
  1952. {
  1953. if (traceLevel)
  1954. DBGLOG("RoxieSocketQueueManager::run() starting: doIbytiDelay=%s minIbytiDelay=%u initIbytiDelay=%u",
  1955. doIbytiDelay?"YES":"NO", minIbytiDelay, initIbytiDelay);
  1956. for (;;)
  1957. {
  1958. MemoryBuffer mb;
  1959. try
  1960. {
  1961. // NOTE - this thread needs to do as little as possible - just read packets and queue them up - otherwise we can get packet loss due to buffer overflow
  1962. // DO NOT put tracing on this thread except at very high tracelevels!
  1963. unsigned l;
  1964. multicastSocket->read(mb.reserve(maxPacketSize), sizeof(RoxiePacketHeader), maxPacketSize, l, 5);
  1965. mb.setLength(l);
  1966. atomic_inc(&packetsReceived);
  1967. RoxiePacketHeader &header = *(RoxiePacketHeader *) mb.toByteArray();
  1968. if (l != header.packetlength)
  1969. DBGLOG("sock->read returned %d but packetlength was %d", l, header.packetlength);
  1970. if (traceLevel > 10)
  1971. {
  1972. StringBuffer s;
  1973. DBGLOG("Read from multicast: %s", header.toString(s).str());
  1974. }
  1975. #ifdef ROXIE_SLA_LOGIC
  1976. if (header.activityId & ROXIE_SLA_PRIORITY)
  1977. processMessage(mb, header, slaQueue, slaWorkers);
  1978. else
  1979. #endif
  1980. if (header.activityId & ROXIE_HIGH_PRIORITY)
  1981. processMessage(mb, header, hiQueue, hiWorkers);
  1982. else
  1983. processMessage(mb, header, loQueue, loWorkers);
  1984. }
  1985. catch (IException *E)
  1986. {
  1987. if (running)
  1988. {
  1989. // MORE: Maybe we should utilize IException::errorCode - not just text ??
  1990. if (E->errorCode()==JSOCKERR_timeout_expired)
  1991. E->Release();
  1992. else if (roxiemem::memPoolExhausted())
  1993. {
  1994. //MORE: I think this should probably be based on the error code instead.
  1995. EXCLOG(E, "Exception reading or processing multicast msg");
  1996. E->Release();
  1997. MilliSleep(1000); // Give a chance for mem free
  1998. }
  1999. else
  2000. {
  2001. EXCLOG(E, "Exception reading or processing multicast msg");
  2002. E->Release();
  2003. // MORE: Protect with try logic, in case udp_create throws exception ?
  2004. // What to do if create fails (ie exception is caught) ?
  2005. if (multicastSocket)
  2006. {
  2007. multicastSocket->close();
  2008. multicastSocket.clear();
  2009. openMulticastSocket();
  2010. }
  2011. }
  2012. }
  2013. else
  2014. {
  2015. E->Release();
  2016. break;
  2017. }
  2018. }
  2019. }
  2020. return 0;
  2021. }
  2022. void start()
  2023. {
  2024. RoxieReceiverBase::start();
  2025. running = true;
  2026. readThread.start();
  2027. }
  2028. void stop()
  2029. {
  2030. if (running)
  2031. {
  2032. running = false;
  2033. multicastSocket->close();
  2034. }
  2035. RoxieReceiverBase::stop();
  2036. }
  2037. void join()
  2038. {
  2039. readThread.join();
  2040. RoxieReceiverBase::join();
  2041. }
  2042. virtual IReceiveManager *queryReceiveManager()
  2043. {
  2044. return receiveManager;
  2045. }
  2046. };
  2047. #ifdef _MSC_VER
  2048. #pragma warning( pop )
  2049. #endif
  2050. //==================================================================================================
  2051. interface ILocalMessageCollator : extends IMessageCollator
  2052. {
  2053. virtual void enqueueMessage(void *data, unsigned datalen, void *meta, unsigned metalen, void *header, unsigned headerlen) = 0;
  2054. };
  2055. interface ILocalReceiveManager : extends IReceiveManager
  2056. {
  2057. virtual ILocalMessageCollator *lookupCollator(ruid_t id) = 0;
  2058. };
  2059. class LocalMessagePacker : public CDummyMessagePacker
  2060. {
  2061. MemoryBuffer meta;
  2062. MemoryBuffer header;
  2063. Linked<ILocalReceiveManager> rm;
  2064. ruid_t id;
  2065. public:
  2066. IMPLEMENT_IINTERFACE;
  2067. LocalMessagePacker(RoxiePacketHeader &_header, ILocalReceiveManager *_rm) : rm(_rm)
  2068. {
  2069. id = _header.uid;
  2070. header.append(sizeof(RoxiePacketHeader), &_header);
  2071. }
  2072. virtual void flush(bool last_message);
  2073. virtual void sendMetaInfo(const void *buf, unsigned len)
  2074. {
  2075. meta.append(len, buf);
  2076. }
  2077. };
  2078. class CLocalMessageUnpackCursor : public CInterface, implements IMessageUnpackCursor
  2079. {
  2080. void *data;
  2081. unsigned datalen;
  2082. unsigned pos;
  2083. Linked<IRowManager> rowManager;
  2084. public:
  2085. IMPLEMENT_IINTERFACE;
  2086. CLocalMessageUnpackCursor(IRowManager *_rowManager, void *_data, unsigned _datalen)
  2087. : rowManager(_rowManager)
  2088. {
  2089. datalen = _datalen;
  2090. data = _data;
  2091. pos = 0;
  2092. }
  2093. ~CLocalMessageUnpackCursor()
  2094. {
  2095. }
  2096. virtual bool atEOF() const
  2097. {
  2098. return datalen==pos;
  2099. }
  2100. virtual bool isSerialized() const
  2101. {
  2102. // NOTE: tempting to think that we could avoid serializing in localSlave case, but have to be careful about the lifespan of the rowManager...
  2103. return true;
  2104. }
  2105. virtual const void * getNext(int length)
  2106. {
  2107. if (pos==datalen)
  2108. return NULL;
  2109. assertex(pos + length <= datalen);
  2110. void * cur = ((char *) data) + pos;
  2111. pos += length;
  2112. void * ret = rowManager->allocate(length, 0);
  2113. memcpy(ret, cur, length);
  2114. //No need for finalize since only contains plain data.
  2115. return ret;
  2116. }
  2117. };
  2118. class CLocalMessageResult : public CInterface, implements IMessageResult
  2119. {
  2120. void *data;
  2121. void *meta;
  2122. void *header;
  2123. unsigned datalen, metalen, headerlen;
  2124. unsigned pos;
  2125. public:
  2126. IMPLEMENT_IINTERFACE;
  2127. CLocalMessageResult(void *_data, unsigned _datalen, void *_meta, unsigned _metalen, void *_header, unsigned _headerlen)
  2128. {
  2129. datalen = _datalen;
  2130. metalen = _metalen;
  2131. headerlen = _headerlen;
  2132. data = _data;
  2133. meta = _meta;
  2134. header = _header;
  2135. pos = 0;
  2136. }
  2137. ~CLocalMessageResult()
  2138. {
  2139. free(data);
  2140. free(meta);
  2141. free(header);
  2142. }
  2143. virtual IMessageUnpackCursor *getCursor(IRowManager *rowMgr) const
  2144. {
  2145. return new CLocalMessageUnpackCursor(rowMgr, data, datalen);
  2146. }
  2147. virtual const void *getMessageHeader(unsigned &length) const
  2148. {
  2149. length = headerlen;
  2150. return header;
  2151. }
  2152. virtual const void *getMessageMetadata(unsigned &length) const
  2153. {
  2154. length = metalen;
  2155. return meta;
  2156. }
  2157. virtual void discard() const
  2158. {
  2159. }
  2160. };
  2161. class CLocalMessageCollator : public CInterface, implements ILocalMessageCollator
  2162. {
  2163. InterruptableSemaphore sem;
  2164. QueueOf<IMessageResult, false> pending;
  2165. CriticalSection crit;
  2166. Linked<IRowManager> rowManager;
  2167. Linked<ILocalReceiveManager> receiveManager;
  2168. ruid_t id;
  2169. unsigned totalBytesReceived;
  2170. public:
  2171. IMPLEMENT_IINTERFACE;
  2172. CLocalMessageCollator(IRowManager *_rowManager, ruid_t _ruid);
  2173. ~CLocalMessageCollator();
  2174. virtual ruid_t queryRUID() const
  2175. {
  2176. return id;
  2177. }
  2178. virtual bool add_package(DataBuffer *dataBuff)
  2179. {
  2180. throwUnexpected(); // internal use in udp layer...
  2181. }
  2182. virtual IMessageResult* getNextResult(unsigned time_out, bool &anyActivity)
  2183. {
  2184. anyActivity = false;
  2185. if (!sem.wait(time_out))
  2186. return NULL;
  2187. anyActivity = true;
  2188. CriticalBlock c(crit);
  2189. return pending.dequeue();
  2190. }
  2191. virtual void interrupt(IException *E)
  2192. {
  2193. sem.interrupt(E);
  2194. }
  2195. virtual void enqueueMessage(void *data, unsigned datalen, void *meta, unsigned metalen, void *header, unsigned headerlen)
  2196. {
  2197. CriticalBlock c(crit);
  2198. pending.enqueue(new CLocalMessageResult(data, datalen, meta, metalen, header, headerlen));
  2199. sem.signal();
  2200. totalBytesReceived += datalen + metalen + headerlen;
  2201. }
  2202. virtual unsigned queryBytesReceived() const
  2203. {
  2204. return totalBytesReceived;
  2205. }
  2206. };
  2207. class RoxieLocalReceiveManager : public CInterface, implements ILocalReceiveManager
  2208. {
  2209. MapXToMyClass<ruid_t, ruid_t, ILocalMessageCollator> collators;
  2210. Owned<IRowManager> rowManager;
  2211. CriticalSection crit;
  2212. Owned<StringContextLogger> logctx;
  2213. Linked<IMessageCollator> defaultCollator;
  2214. public:
  2215. IMPLEMENT_IINTERFACE;
  2216. RoxieLocalReceiveManager() : logctx(new StringContextLogger("RoxieLocalReceiveManager"))
  2217. {
  2218. }
  2219. virtual IMessageCollator *createMessageCollator(IRowManager *manager, ruid_t ruid)
  2220. {
  2221. CriticalBlock b(crit);
  2222. if (!rowManager)
  2223. rowManager.setown(roxiemem::createRowManager(0, NULL, *logctx, NULL, false)); // MORE - should not really use default limits
  2224. IMessageCollator *collator = new CLocalMessageCollator(rowManager, ruid); // MORE - is this right - why two rowManagers and why pass this one (not the other) ?
  2225. collators.setValue(ruid, collator);
  2226. return collator;
  2227. }
  2228. virtual void detachCollator(const IMessageCollator *collator)
  2229. {
  2230. ruid_t id = collator->queryRUID();
  2231. CriticalBlock b(crit);
  2232. collators.setValue(id, NULL);
  2233. }
  2234. virtual void setDefaultCollator(IMessageCollator *collator)
  2235. {
  2236. CriticalBlock b(crit);
  2237. defaultCollator.set(collator);
  2238. }
  2239. virtual ILocalMessageCollator *lookupCollator(ruid_t id)
  2240. {
  2241. CriticalBlock b(crit);
  2242. IMessageCollator *ret = collators.getValue(id);
  2243. if (!ret)
  2244. ret = defaultCollator;
  2245. return QUERYINTERFACE(ret, ILocalMessageCollator);
  2246. }
  2247. };
  2248. void LocalMessagePacker::flush(bool last_message)
  2249. {
  2250. data.setLength(lastput);
  2251. if (last_message)
  2252. {
  2253. ILocalMessageCollator *collator = rm->lookupCollator(id);
  2254. if (collator)
  2255. {
  2256. unsigned datalen = data.length();
  2257. unsigned metalen = meta.length();
  2258. unsigned headerlen = header.length();
  2259. collator->enqueueMessage(data.detach(), datalen, meta.detach(), metalen, header.detach(), headerlen);
  2260. }
  2261. // otherwise Roxie server is no longer interested and we can simply discard
  2262. }
  2263. }
  2264. CLocalMessageCollator::CLocalMessageCollator(IRowManager *_rowManager, ruid_t _ruid)
  2265. : rowManager(_rowManager), id(_ruid)
  2266. {
  2267. id = 0;
  2268. totalBytesReceived = 0;
  2269. }
  2270. CLocalMessageCollator::~CLocalMessageCollator()
  2271. {
  2272. IMessageResult *goer;
  2273. loop
  2274. {
  2275. goer = pending.dequeue();
  2276. if (!goer)
  2277. break;
  2278. goer->Release();
  2279. }
  2280. }
  2281. class RoxieLocalQueueManager : public RoxieReceiverBase
  2282. {
  2283. Linked<ISendManager> sendManager;
  2284. Linked<RoxieLocalReceiveManager> receiveManager;
  2285. public:
  2286. RoxieLocalQueueManager(unsigned snifferChannel, unsigned _numWorkers) : RoxieReceiverBase(_numWorkers)
  2287. {
  2288. receiveManager.setown(new RoxieLocalReceiveManager);
  2289. }
  2290. virtual bool suspendChannel(unsigned channel, bool suspend, const IRoxieContextLogger &logctx)
  2291. {
  2292. if (suspend)
  2293. UNIMPLEMENTED;
  2294. return false;
  2295. }
  2296. virtual void sendPacket(IRoxieQueryPacket *packet, const IRoxieContextLogger &logctx)
  2297. {
  2298. RoxiePacketHeader &header = packet->queryHeader();
  2299. unsigned retries = header.thisChannelRetries();
  2300. if (header.activityId == ROXIE_FILECALLBACK || header.activityId == ROXIE_DEBUGCALLBACK )
  2301. {
  2302. if (traceLevel > 5)
  2303. {
  2304. StringBuffer s;
  2305. DBGLOG("ROXIE_CALLBACK %s", header.toString(s).str());
  2306. }
  2307. doFileCallback(packet);
  2308. }
  2309. else if (retries < SUBCHANNEL_MASK)
  2310. {
  2311. if (retries)
  2312. {
  2313. // Send back an out-of-band immediately, to let Roxie server know that channel is still active
  2314. RoxiePacketHeader newHeader(header, ROXIE_ALIVE);
  2315. Owned<IMessagePacker> output = createOutputStream(newHeader, true, logctx);
  2316. output->flush(true);
  2317. }
  2318. RoxieQueue *targetQueue;
  2319. #ifdef ROXIE_SLA_LOGIC
  2320. if (header.activityId & ROXIE_SLA_PRIORITY)
  2321. targetQueue = &slaQueue;
  2322. else
  2323. #endif
  2324. if (header.activityId & ROXIE_HIGH_PRIORITY)
  2325. targetQueue = &hiQueue;
  2326. else
  2327. targetQueue = &loQueue;
  2328. if (header.channel)
  2329. {
  2330. targetQueue->enqueue(LINK(packet));
  2331. }
  2332. else
  2333. {
  2334. // Turn broadcast packet (channel 0), as early as possible, into non-0 channel packets.
  2335. // So retries and other communication with Roxie server (which uses non-0 channel numbers) will not cause double work or confusion.
  2336. for (unsigned i = 0; i < channelCount; i++)
  2337. {
  2338. targetQueue->enqueue(packet->clonePacket(channels[i]));
  2339. }
  2340. }
  2341. }
  2342. }
  2343. virtual void sendIbyti(RoxiePacketHeader &header, const IRoxieContextLogger &logctx)
  2344. {
  2345. // Don't do IBYTI's when local slave - no buddy to talk to anyway
  2346. }
  2347. virtual void sendAbort(RoxiePacketHeader &header, const IRoxieContextLogger &logctx)
  2348. {
  2349. // MORE - should really have some code here? - no one to alert about the abort
  2350. //UNIMPLEMENTED;
  2351. }
  2352. virtual void sendAbortCallback(const RoxiePacketHeader &header, const char *lfn, const IRoxieContextLogger &logctx)
  2353. {
  2354. // MORE - should really have some code here
  2355. //UNIMPLEMENTED;
  2356. }
  2357. virtual IMessagePacker *createOutputStream(RoxiePacketHeader &header, bool outOfBand, const IRoxieContextLogger &logctx)
  2358. {
  2359. return new LocalMessagePacker(header, receiveManager);
  2360. }
  2361. virtual IReceiveManager *queryReceiveManager()
  2362. {
  2363. return receiveManager;
  2364. }
  2365. virtual bool replyPending(RoxiePacketHeader &header)
  2366. {
  2367. // MORE - should really have some code here!
  2368. return false;
  2369. }
  2370. virtual bool abortCompleted(RoxiePacketHeader &header)
  2371. {
  2372. // MORE - should really have some code here!
  2373. return false;
  2374. }
  2375. };
  2376. IRoxieOutputQueueManager *ROQ;
  2377. extern IRoxieOutputQueueManager *createOutputQueueManager(unsigned snifferChannel, unsigned numWorkers)
  2378. {
  2379. if (localSlave)
  2380. return new RoxieLocalQueueManager(snifferChannel, numWorkers);
  2381. else
  2382. return new RoxieSocketQueueManager(snifferChannel, numWorkers);
  2383. }
  2384. //================================================================================================================================
  2385. class PacketDiscarder : public Thread, implements IPacketDiscarder
  2386. {
  2387. bool aborted;
  2388. Owned<IRowManager> rowManager; // not completely sure I need one... maybe I do
  2389. Owned<IMessageCollator> mc;
  2390. public:
  2391. IMPLEMENT_IINTERFACE;
  2392. PacketDiscarder()
  2393. {
  2394. aborted = false;
  2395. };
  2396. ~PacketDiscarder()
  2397. {
  2398. if (mc)
  2399. ROQ->queryReceiveManager()->detachCollator(mc);
  2400. mc.clear();
  2401. }
  2402. virtual int run()
  2403. {
  2404. Owned<StringContextLogger> logctx = new StringContextLogger("PacketDiscarder");
  2405. rowManager.setown(roxiemem::createRowManager(1, NULL, *logctx, NULL));
  2406. mc.setown(ROQ->queryReceiveManager()->createMessageCollator(rowManager, RUID_DISCARD));
  2407. ROQ->queryReceiveManager()->setDefaultCollator(mc);
  2408. while (!aborted)
  2409. {
  2410. bool anyActivity = false;
  2411. Owned<IMessageResult> mr = mc->getNextResult(5000, anyActivity);
  2412. if (mr)
  2413. {
  2414. if (traceLevel > 4)
  2415. DBGLOG("Discarding unwanted message");
  2416. unsigned headerLen;
  2417. const RoxiePacketHeader &header = *(const RoxiePacketHeader *) mr->getMessageHeader(headerLen);
  2418. if (headerLen)
  2419. {
  2420. switch (header.activityId)
  2421. {
  2422. case ROXIE_FILECALLBACK:
  2423. {
  2424. Owned<IMessageUnpackCursor> callbackData = mr->getCursor(rowManager);
  2425. OwnedConstRoxieRow len = callbackData->getNext(sizeof(RecordLengthType));
  2426. if (len)
  2427. {
  2428. RecordLengthType *rowlen = (RecordLengthType *) len.get();
  2429. OwnedConstRoxieRow row = callbackData->getNext(*rowlen);
  2430. const char *rowdata = (const char *) row.get();
  2431. // bool isOpt = * (bool *) rowdata;
  2432. // bool isLocal = * (bool *) (rowdata+1);
  2433. ROQ->sendAbortCallback(header, rowdata+2, *logctx);
  2434. }
  2435. else
  2436. DBGLOG("Unrecognized format in discarded file callback");
  2437. break;
  2438. }
  2439. // MORE - ROXIE_ALIVE perhaps should go here too? debug callbacks? Actually any standard query results should too (though by the time I see them here it's too late (that may change once start streaming)
  2440. }
  2441. }
  2442. else
  2443. DBGLOG("Unwanted message had no header?!");
  2444. }
  2445. else if (!anyActivity)
  2446. {
  2447. // to avoid leaking partial unwanted packets, we clear out mc periodically...
  2448. ROQ->queryReceiveManager()->detachCollator(mc);
  2449. mc.setown(ROQ->queryReceiveManager()->createMessageCollator(rowManager, RUID_DISCARD));
  2450. ROQ->queryReceiveManager()->setDefaultCollator(mc);
  2451. }
  2452. }
  2453. return 0;
  2454. }
  2455. virtual void start()
  2456. {
  2457. Thread::start();
  2458. }
  2459. virtual void stop()
  2460. {
  2461. if (mc)
  2462. mc->interrupt();
  2463. aborted = true;
  2464. join();
  2465. }
  2466. };
  2467. IPacketDiscarder *createPacketDiscarder()
  2468. {
  2469. IPacketDiscarder *packetDiscarder = new PacketDiscarder;
  2470. packetDiscarder->start();
  2471. return packetDiscarder;
  2472. }
  2473. //================================================================================================================================
  2474. // There are various possibly interesting ways to reply to a ping:
  2475. // Reply as soon as receive, or put it on the queue like other messages?
  2476. // Reply for every channel, or just once for every slave?
  2477. // Should I send on channel 0 or round-robin the channels?
  2478. // My gut feeling is that knowing what channels are responding is useful so should reply on every unsuspended channel,
  2479. // and that the delay caused by queuing system is an interesting part of what we want to measure (though nice to know minimum possible too)
  2480. unsigned pingInterval = 60;
  2481. class PingTimer : public Thread
  2482. {
  2483. bool aborted;
  2484. Owned<IRowManager> rowManager;
  2485. Owned<IMessageCollator> mc;
  2486. StringContextLogger logctx;
  2487. void sendPing(unsigned priorityMask)
  2488. {
  2489. unsigned packetSize = sizeof(RoxiePacketHeader) + sizeof(char) + strlen("PING") + 1 + sizeof(PingRecord);
  2490. void *packetData = malloc(packetSize);
  2491. RoxiePacketHeader *header = (RoxiePacketHeader *) packetData;
  2492. RemoteActivityId pingId(ROXIE_PING | priorityMask, 0);
  2493. header->init(pingId, 0, 0, 0);
  2494. char *finger = (char *) (header + 1);
  2495. *finger++ = (char) LOGGING_FLAGSPRESENT;
  2496. strcpy(finger, "PING");
  2497. finger += strlen("PING")+1;
  2498. if (traceLevel > 1)
  2499. DBGLOG("PING sent");
  2500. PingRecord data;
  2501. data.senderIP.ipset(getNodeAddress(myNodeIndex));
  2502. data.tick = usTick();
  2503. memcpy(finger, &data, sizeof(PingRecord));
  2504. Owned<IRoxieQueryPacket> packet = createRoxiePacket(packetData, packetSize);
  2505. ROQ->sendPacket(packet, logctx);
  2506. }
  2507. public:
  2508. PingTimer() : logctx("PingTimer")
  2509. {
  2510. aborted = false;
  2511. };
  2512. ~PingTimer()
  2513. {
  2514. if (mc)
  2515. ROQ->queryReceiveManager()->detachCollator(mc);
  2516. mc.clear();
  2517. }
  2518. virtual int run()
  2519. {
  2520. rowManager.setown(roxiemem::createRowManager(1, NULL, queryDummyContextLogger(), NULL));
  2521. mc.setown(ROQ->queryReceiveManager()->createMessageCollator(rowManager, RUID_PING));
  2522. unsigned pingsReceived = 0;
  2523. unsigned pingsElapsed = 0;
  2524. sendPing(ROXIE_HIGH_PRIORITY);
  2525. while (!aborted)
  2526. {
  2527. bool anyActivity = false;
  2528. Owned<IMessageResult> mr = mc->getNextResult(pingInterval*1000, anyActivity);
  2529. if (mr)
  2530. {
  2531. unsigned headerLen;
  2532. const RoxiePacketHeader *header = (const RoxiePacketHeader *) mr->getMessageHeader(headerLen);
  2533. Owned<IMessageUnpackCursor> mu = mr->getCursor(rowManager);
  2534. PingRecord *answer = (PingRecord *) mu->getNext(sizeof(PingRecord));
  2535. if (answer && mu->atEOF() && headerLen==sizeof(RoxiePacketHeader))
  2536. {
  2537. unsigned elapsed = usTick() - answer->tick;
  2538. pingsReceived++;
  2539. pingsElapsed += elapsed;
  2540. if (traceLevel > 10)
  2541. DBGLOG("PING reply channel=%d, time %d", header->channel, elapsed); // DBGLOG is slower than the pings so be careful!
  2542. }
  2543. else
  2544. DBGLOG("PING reply, garbled result");
  2545. ReleaseRoxieRow(answer);
  2546. }
  2547. else if (!anyActivity)
  2548. {
  2549. if (traceLevel)
  2550. DBGLOG("PING: %d replies received, average delay %d", pingsReceived, pingsReceived ? pingsElapsed / pingsReceived : 0);
  2551. pingsReceived = 0;
  2552. pingsElapsed = 0;
  2553. sendPing(ROXIE_HIGH_PRIORITY); // MORE - we could think about alternating the priority or sending pings on high and low at the same time...
  2554. }
  2555. }
  2556. return 0;
  2557. }
  2558. void stop()
  2559. {
  2560. if (mc)
  2561. mc->interrupt();
  2562. aborted = true;
  2563. }
  2564. static CriticalSection crit;
  2565. } *pingTimer;
  2566. CriticalSection PingTimer::crit;
  2567. extern void startPingTimer()
  2568. {
  2569. CriticalBlock b(PingTimer::crit);
  2570. if (!pingTimer)
  2571. {
  2572. pingTimer = new PingTimer();
  2573. pingTimer->start();
  2574. }
  2575. }
  2576. extern void stopPingTimer()
  2577. {
  2578. CriticalBlock b(PingTimer::crit);
  2579. if (pingTimer)
  2580. {
  2581. pingTimer->stop();
  2582. pingTimer->join();
  2583. delete pingTimer;
  2584. pingTimer = NULL;
  2585. }
  2586. }