ccdqueue.cpp 120 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550
  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 "jencrypt.hpp"
  21. #include "jsecrets.hpp"
  22. #include "udplib.hpp"
  23. #include "udptopo.hpp"
  24. #include "udpsha.hpp"
  25. #include "ccd.hpp"
  26. #include "ccddebug.hpp"
  27. #include "ccdquery.hpp"
  28. #include "ccdstate.hpp"
  29. #include "ccdqueue.ipp"
  30. #include "ccdsnmp.hpp"
  31. #ifdef _USE_CPPUNIT
  32. #include <cppunit/extensions/HelperMacros.h>
  33. #endif
  34. using roxiemem::OwnedRoxieRow;
  35. using roxiemem::OwnedConstRoxieRow;
  36. using roxiemem::IRowManager;
  37. using roxiemem::DataBuffer;
  38. //============================================================================================
  39. RoxiePacketHeader::RoxiePacketHeader(const RemoteActivityId &_remoteId, ruid_t _uid, unsigned _channel, unsigned _overflowSequence)
  40. {
  41. packetlength = sizeof(RoxiePacketHeader);
  42. #ifdef TIME_PACKETS
  43. tick = 0;
  44. #endif
  45. init(_remoteId, _uid, _channel, _overflowSequence);
  46. }
  47. RoxiePacketHeader::RoxiePacketHeader(const RoxiePacketHeader &source, unsigned _activityId, unsigned subChannel) : serverId(source.serverId)
  48. {
  49. // Used to create the header to send a callback to originating server or an IBYTI to a buddy
  50. activityId = _activityId;
  51. uid = source.uid;
  52. queryHash = source.queryHash;
  53. channel = source.channel;
  54. overflowSequence = source.overflowSequence;
  55. continueSequence = source.continueSequence;
  56. if (_activityId >= ROXIE_ACTIVITY_SPECIAL_FIRST && _activityId <= ROXIE_ACTIVITY_SPECIAL_LAST)
  57. overflowSequence |= OUTOFBAND_SEQUENCE; // Need to make sure it is not treated as dup of actual reply in the udp layer
  58. retries = getSubChannelMask(subChannel) | (source.retries & ~ROXIE_RETRIES_MASK);
  59. #ifdef TIME_PACKETS
  60. tick = source.tick;
  61. #endif
  62. #ifdef SUBCHANNELS_IN_HEADER
  63. memcpy(subChannels, source.subChannels, sizeof(subChannels));
  64. #endif
  65. packetlength = sizeof(RoxiePacketHeader);
  66. }
  67. unsigned RoxiePacketHeader::getSubChannelMask(unsigned subChannel)
  68. {
  69. return SUBCHANNEL_MASK << (SUBCHANNEL_BITS * subChannel);
  70. }
  71. unsigned RoxiePacketHeader::priorityHash() const
  72. {
  73. // Used to determine which agent to act as primary and which as secondary for a given packet (thus spreading the load)
  74. // It's important that we do NOT include channel (since that would result in different values for the different agents responding to a broadcast)
  75. // We also don't include continueSequence since we'd prefer continuations to go the same way as original
  76. unsigned hash = serverId.hash();
  77. hash = hashc((const unsigned char *) &uid, sizeof(uid), hash);
  78. hash += overflowSequence; // MORE - is this better than hashing?
  79. if (traceLevel > 9)
  80. {
  81. StringBuffer s;
  82. DBGLOG("Calculating hash: %s hash was %d", toString(s).str(), hash);
  83. }
  84. return hash;
  85. }
  86. void RoxiePacketHeader::copy(const RoxiePacketHeader &oh)
  87. {
  88. // used for saving away kill packets for later matching by match
  89. uid = oh.uid;
  90. overflowSequence = oh.overflowSequence;
  91. continueSequence = oh.continueSequence;
  92. serverId = oh.serverId;
  93. channel = oh.channel;
  94. // MORE - would it be safer, maybe even faster to copy the rest too?
  95. }
  96. bool RoxiePacketHeader::matchPacket(const RoxiePacketHeader &oh) const
  97. {
  98. // used when matching up a kill packet against a pending one...
  99. // DO NOT compare activityId - they are not supposed to match, since 0 in activityid identifies ibyti!
  100. return
  101. oh.uid==uid &&
  102. (oh.overflowSequence & ~OUTOFBAND_SEQUENCE) == (overflowSequence & ~OUTOFBAND_SEQUENCE) &&
  103. oh.continueSequence == continueSequence &&
  104. oh.serverId==serverId &&
  105. oh.channel==channel;
  106. }
  107. void RoxiePacketHeader::init(const RemoteActivityId &_remoteId, ruid_t _uid, unsigned _channel, unsigned _overflowSequence)
  108. {
  109. retries = 0;
  110. activityId = _remoteId.activityId;
  111. queryHash = _remoteId.queryHash;
  112. uid = _uid;
  113. serverId = myNode;
  114. channel = _channel;
  115. overflowSequence = _overflowSequence;
  116. continueSequence = 0;
  117. #ifdef SUBCHANNELS_IN_HEADER
  118. clearSubChannels();
  119. #endif
  120. #ifdef TIME_PACKETS
  121. tick = 0;
  122. #else
  123. filler = 0; // keeps valgrind happy
  124. #endif
  125. }
  126. #ifdef SUBCHANNELS_IN_HEADER
  127. void RoxiePacketHeader::clearSubChannels()
  128. {
  129. for (unsigned idx = 0; idx < MAX_SUBCHANNEL; idx++)
  130. subChannels[idx].clear();
  131. }
  132. #endif
  133. StringBuffer &RoxiePacketHeader::toString(StringBuffer &ret) const
  134. {
  135. const IpAddress serverIP = serverId.getIpAddress();
  136. ret.append("activityId=");
  137. switch(activityId & ~ROXIE_PRIORITY_MASK)
  138. {
  139. case 0: ret.append("IBYTI"); break;
  140. case ROXIE_UNLOAD: ret.append("ROXIE_UNLOAD"); break;
  141. case ROXIE_PING: ret.append("ROXIE_PING"); break;
  142. case ROXIE_TRACEINFO: ret.append("ROXIE_TRACEINFO"); break;
  143. case ROXIE_DEBUGREQUEST: ret.append("ROXIE_DEBUGREQUEST"); break;
  144. case ROXIE_DEBUGCALLBACK: ret.append("ROXIE_DEBUGCALLBACK"); break;
  145. case ROXIE_FILECALLBACK: ret.append("ROXIE_FILECALLBACK"); break;
  146. case ROXIE_ALIVE: ret.append("ROXIE_ALIVE"); break;
  147. case ROXIE_KEYEDLIMIT_EXCEEDED: ret.append("ROXIE_KEYEDLIMIT_EXCEEDED"); break;
  148. case ROXIE_LIMIT_EXCEEDED: ret.append("ROXIE_LIMIT_EXCEEDED"); break;
  149. case ROXIE_EXCEPTION: ret.append("ROXIE_EXCEPTION"); break;
  150. default:
  151. ret.appendf("%u", (activityId & ~(ROXIE_ACTIVITY_FETCH | ROXIE_PRIORITY_MASK)));
  152. if (activityId & ROXIE_ACTIVITY_FETCH)
  153. ret.appendf(" (fetch part)");
  154. break;
  155. }
  156. ret.appendf(" uid=" RUIDF " pri=", uid);
  157. switch(activityId & ROXIE_PRIORITY_MASK)
  158. {
  159. case ROXIE_SLA_PRIORITY: ret.append("SLA"); break;
  160. case ROXIE_HIGH_PRIORITY: ret.append("HIGH"); break;
  161. case ROXIE_LOW_PRIORITY: ret.append("LOW"); break;
  162. default: ret.append("???"); break;
  163. }
  164. ret.appendf(" queryHash=%" I64F "x ch=%u seq=%d cont=%d server=", queryHash, channel, overflowSequence, continueSequence);
  165. serverIP.getIpText(ret);
  166. if (retries)
  167. {
  168. if (retries==QUERY_ABORTED)
  169. ret.append(" retries=QUERY_ABORTED");
  170. else
  171. {
  172. if (retries & ROXIE_RETRIES_MASK)
  173. ret.appendf(" retries=%04x", retries);
  174. if (retries & ROXIE_FASTLANE)
  175. ret.appendf(" FASTLANE");
  176. if (retries & ROXIE_BROADCAST)
  177. ret.appendf(" BROADCAST");
  178. }
  179. }
  180. #ifdef SUBCHANNELS_IN_HEADER
  181. ret.append(" subchannels=");
  182. for (unsigned idx = 0; idx < MAX_SUBCHANNEL; idx++)
  183. {
  184. if (subChannels[idx].isNull())
  185. break;
  186. if (idx)
  187. ret.append(',');
  188. subChannels[idx].getTraceText(ret);
  189. if (subChannels[idx].isMe())
  190. {
  191. ret.append("(me)");
  192. }
  193. }
  194. #endif
  195. return ret;
  196. }
  197. bool RoxiePacketHeader::allChannelsFailed()
  198. {
  199. unsigned mask = (1 << (getNumAgents(channel) * SUBCHANNEL_BITS)) - 1;
  200. return (retries & mask) == mask;
  201. }
  202. bool RoxiePacketHeader::retry()
  203. {
  204. bool worthRetrying = false;
  205. unsigned mask = SUBCHANNEL_MASK;
  206. unsigned numAgents = getNumAgents(channel);
  207. for (unsigned subChannel = 0; subChannel < numAgents; subChannel++)
  208. {
  209. unsigned subRetries = (retries & mask) >> (subChannel * SUBCHANNEL_BITS);
  210. if (subRetries != SUBCHANNEL_MASK)
  211. subRetries++;
  212. if (subRetries != SUBCHANNEL_MASK)
  213. worthRetrying = true;
  214. retries = (retries & ~mask) | (subRetries << (subChannel * SUBCHANNEL_BITS));
  215. mask <<= SUBCHANNEL_BITS;
  216. }
  217. return worthRetrying;
  218. }
  219. void RoxiePacketHeader::setException(unsigned subChannel)
  220. {
  221. retries |= SUBCHANNEL_MASK << (SUBCHANNEL_BITS * subChannel);
  222. }
  223. unsigned RoxiePacketHeader::thisChannelRetries(unsigned subChannel)
  224. {
  225. unsigned shift = SUBCHANNEL_BITS * subChannel;
  226. unsigned mask = SUBCHANNEL_MASK << shift;
  227. return (retries & mask) >> shift;
  228. }
  229. //============================================================================================
  230. unsigned getReplicationLevel(unsigned channel)
  231. {
  232. if (!channel)
  233. return 0;
  234. Owned<const ITopologyServer> topology = getTopology();
  235. return topology->queryChannelInfo(channel).replicationLevel();
  236. }
  237. //============================================================================================
  238. // This function maps a agent number to the multicast ip used to talk to it.
  239. IpAddress multicastBase("239.1.1.1"); // TBD IPv6 (need IPv6 multicast addresses?
  240. IpAddress multicastLast("239.1.5.254");
  241. const IpAddress &getChannelIp(IpAddress &ip, unsigned _channel)
  242. {
  243. // need to be careful to avoid the .0's and the .255's (not sure why...)
  244. ip = multicastBase;
  245. if (!ip.ipincrement(_channel,1,254,1,0xffff)
  246. ||(ip.ipcompare(multicastLast)>0))
  247. throw MakeStringException(ROXIE_MULTICAST_ERROR, "Out-of-range multicast channel %d", _channel);
  248. return ip;
  249. }
  250. static Owned<ISocket> multicastSocket;
  251. void joinMulticastChannel(unsigned channel)
  252. {
  253. IpAddress multicastIp;
  254. getChannelIp(multicastIp, channel);
  255. SocketEndpoint ep(ccdMulticastPort, multicastIp);
  256. StringBuffer epStr;
  257. ep.getUrlStr(epStr);
  258. if (!multicastSocket->join_multicast_group(ep))
  259. throw MakeStringException(ROXIE_MULTICAST_ERROR, "Failed to join multicast channel %d (%s)", channel, epStr.str());
  260. if (traceLevel)
  261. DBGLOG("Joined multicast channel %d (%s)", channel, epStr.str());
  262. }
  263. static SocketEndpointArray multicastEndpoints; // indexed by channel
  264. void setMulticastEndpoints(unsigned numChannels)
  265. {
  266. for (unsigned channel = 0; channel <= numChannels; channel++) // NOTE - channel 0 is special, and numChannels does not include it
  267. {
  268. IpAddress multicastIp;
  269. getChannelIp(multicastIp, channel);
  270. multicastEndpoints.append(SocketEndpoint(ccdMulticastPort, multicastIp));
  271. }
  272. }
  273. void openMulticastSocket()
  274. {
  275. if (!multicastSocket)
  276. {
  277. multicastSocket.setown(ISocket::udp_create(ccdMulticastPort));
  278. if (multicastTTL)
  279. {
  280. multicastSocket->set_ttl(multicastTTL);
  281. DBGLOG("Roxie: multicastTTL: %u", multicastTTL);
  282. }
  283. else
  284. DBGLOG("Roxie: multicastTTL not set");
  285. multicastSocket->set_receive_buffer_size(udpMulticastBufferSize);
  286. size32_t actualSize = multicastSocket->get_receive_buffer_size();
  287. if (actualSize < udpMulticastBufferSize)
  288. {
  289. DBGLOG("Roxie: multicast socket buffer size could not be set (requested=%d actual %d", udpMulticastBufferSize, actualSize);
  290. throwUnexpected();
  291. }
  292. if (traceLevel)
  293. DBGLOG("Roxie: multicast socket created port=%d sockbuffsize=%d actual %d", ccdMulticastPort, udpMulticastBufferSize, actualSize);
  294. if (roxieMulticastEnabled && !localAgent)
  295. {
  296. Owned<const ITopologyServer> topology = getTopology();
  297. for (unsigned channel : topology->queryChannels())
  298. {
  299. assertex(channel);
  300. joinMulticastChannel(channel);
  301. }
  302. joinMulticastChannel(0); // all agents also listen on channel 0
  303. }
  304. }
  305. }
  306. void closeMulticastSockets()
  307. {
  308. multicastSocket.clear();
  309. }
  310. static bool channelWrite(RoxiePacketHeader &buf, bool includeSelf)
  311. {
  312. size32_t minwrote = 0;
  313. if (roxieMulticastEnabled)
  314. {
  315. return multicastSocket->udp_write_to(multicastEndpoints.item(buf.channel), &buf, buf.packetlength) == buf.packetlength;
  316. }
  317. else
  318. {
  319. #ifdef SUBCHANNELS_IN_HEADER
  320. // In the containerized system, the list of subchannel IPs is captured in the packet header to ensure everyone is using the
  321. // same snapshot of the topology state.
  322. // If the subchannel IPs are not set, fill them in now. If they are set, use them.
  323. if (buf.subChannels[0].isNull())
  324. {
  325. Owned<const ITopologyServer> topo = getTopology();
  326. const SocketEndpointArray &eps = topo->queryAgents(buf.channel);
  327. if (!eps.ordinality())
  328. throw makeStringExceptionV(0, "No agents available for channel %d", buf.channel);
  329. if (buf.channel==0)
  330. {
  331. // Note that we expand any writes on channel 0 here, since we need to capture the server's view of what agents are on each channel
  332. bool allOk = true;
  333. if (traceRoxiePackets)
  334. {
  335. StringBuffer header;
  336. DBGLOG("Translating packet sent to channel 0: %s", buf.toString(header).str());
  337. }
  338. for (unsigned channel = 0; channel < numChannels; channel++)
  339. {
  340. buf.channel = channel+1;
  341. if (!channelWrite(buf, true))
  342. allOk = false;
  343. buf.clearSubChannels();
  344. }
  345. buf.channel = 0;
  346. return allOk;
  347. }
  348. unsigned hdrHashVal = buf.priorityHash();
  349. unsigned numAgents = eps.ordinality();
  350. unsigned subChannel = (hdrHashVal % numAgents);
  351. for (unsigned idx = 0; idx < MAX_SUBCHANNEL; idx++)
  352. {
  353. if (idx == numAgents)
  354. break;
  355. buf.subChannels[idx].setIp(eps.item(subChannel));
  356. subChannel++;
  357. if (subChannel == numAgents)
  358. subChannel = 0;
  359. }
  360. }
  361. else
  362. {
  363. assert(buf.channel != 0);
  364. }
  365. for (unsigned subChannel = 0; subChannel < MAX_SUBCHANNEL; subChannel++)
  366. {
  367. if (buf.subChannels[subChannel].isNull())
  368. break;
  369. if (includeSelf || !buf.subChannels[subChannel].isMe())
  370. {
  371. if (traceRoxiePackets)
  372. {
  373. StringBuffer s, header;
  374. DBGLOG("Writing %d bytes to subchannel %d (%s) %s", buf.packetlength, subChannel, buf.subChannels[subChannel].getTraceText(s).str(), buf.toString(header).str());
  375. }
  376. SocketEndpoint ep(ccdMulticastPort, buf.subChannels[subChannel].getIpAddress());
  377. size32_t wrote = multicastSocket->udp_write_to(ep, &buf, buf.packetlength);
  378. if (!subChannel || wrote < minwrote)
  379. minwrote = wrote;
  380. if (delaySubchannelPackets)
  381. MilliSleep(100);
  382. }
  383. else if (traceRoxiePackets)
  384. {
  385. StringBuffer s, header;
  386. DBGLOG("NOT writing %d bytes to subchannel %d (%s) %s", buf.packetlength, subChannel, buf.subChannels[subChannel].getTraceText(s).str(), buf.toString(header).str());
  387. }
  388. }
  389. #else
  390. Owned<const ITopologyServer> topo = getTopology();
  391. const SocketEndpointArray &eps = topo->queryAgents(buf.channel);
  392. if (!eps.ordinality())
  393. throw makeStringExceptionV(0, "No agents available for channel %d", buf.channel);
  394. ForEachItemIn(idx, eps)
  395. {
  396. size32_t wrote = multicastSocket->udp_write_to(eps.item(idx), &buf, buf.packetlength);
  397. if (!idx || wrote < minwrote)
  398. minwrote = wrote;
  399. }
  400. #endif
  401. }
  402. return minwrote==buf.packetlength;
  403. }
  404. //============================================================================================
  405. class CRoxieQueryPacketBase : public CInterface
  406. {
  407. protected:
  408. RoxiePacketHeader *data;
  409. const byte *traceInfo;
  410. unsigned traceLength;
  411. public:
  412. IMPLEMENT_IINTERFACE;
  413. CRoxieQueryPacketBase(const void *_data, int lengthRemaining) : data((RoxiePacketHeader *) _data)
  414. {
  415. assertex(lengthRemaining >= (int) sizeof(RoxiePacketHeader));
  416. data->packetlength = lengthRemaining;
  417. const byte *finger = (const byte *) (data + 1);
  418. lengthRemaining -= sizeof(RoxiePacketHeader);
  419. if (data->activityId == ROXIE_FILECALLBACK || data->activityId == ROXIE_DEBUGCALLBACK || data->retries == QUERY_ABORTED)
  420. {
  421. traceInfo = NULL;
  422. traceLength = 0;
  423. }
  424. else
  425. {
  426. assertex(lengthRemaining > 1);
  427. traceInfo = finger;
  428. lengthRemaining--;
  429. if (*finger++ & LOGGING_DEBUGGERACTIVE)
  430. {
  431. assertex(lengthRemaining >= (int) sizeof(unsigned short));
  432. unsigned short debugLen = *(unsigned short *) finger;
  433. finger += debugLen + sizeof(unsigned short);
  434. lengthRemaining -= debugLen + sizeof(unsigned short);
  435. }
  436. for (;;)
  437. {
  438. assertex(lengthRemaining>0);
  439. if (!*finger)
  440. {
  441. lengthRemaining--;
  442. finger++;
  443. break;
  444. }
  445. lengthRemaining--;
  446. finger++;
  447. }
  448. traceLength = finger - traceInfo;
  449. }
  450. }
  451. ~CRoxieQueryPacketBase()
  452. {
  453. free(data);
  454. }
  455. };
  456. class CRoxieQueryPacket : public CRoxieQueryPacketBase, implements IRoxieQueryPacket
  457. {
  458. protected:
  459. const byte *continuationData = nullptr;
  460. unsigned continuationLength = 0;
  461. const byte *smartStepInfoData = nullptr;
  462. unsigned smartStepInfoLength = 0;
  463. const byte *contextData = nullptr;
  464. unsigned contextLength = 0;
  465. public:
  466. IMPLEMENT_IINTERFACE;
  467. CRoxieQueryPacket(const void *_data, int length) : CRoxieQueryPacketBase(_data, length)
  468. {
  469. const byte *finger = (const byte *) (data + 1) + traceLength;
  470. int lengthRemaining = length - sizeof(RoxiePacketHeader) - traceLength;
  471. if (data->activityId == ROXIE_FILECALLBACK || data->activityId == ROXIE_DEBUGCALLBACK || data->retries == QUERY_ABORTED)
  472. {
  473. continuationData = NULL;
  474. continuationLength = 0;
  475. smartStepInfoData = NULL;
  476. smartStepInfoLength = 0;
  477. }
  478. else
  479. {
  480. if (data->continueSequence & ~CONTINUE_SEQUENCE_SKIPTO)
  481. {
  482. assertex(lengthRemaining >= (int) sizeof(unsigned));
  483. continuationLength = *(unsigned *) finger;
  484. continuationData = finger + sizeof(unsigned);
  485. finger = continuationData + continuationLength;
  486. lengthRemaining -= continuationLength + sizeof(unsigned);
  487. }
  488. if (data->continueSequence & CONTINUE_SEQUENCE_SKIPTO)
  489. {
  490. assertex(lengthRemaining >= (int) sizeof(unsigned));
  491. smartStepInfoLength = *(unsigned *) finger;
  492. smartStepInfoData = finger + sizeof(unsigned);
  493. finger = smartStepInfoData + smartStepInfoLength;
  494. lengthRemaining -= smartStepInfoLength + sizeof(unsigned);
  495. }
  496. }
  497. assertex(lengthRemaining >= 0);
  498. contextData = finger;
  499. contextLength = lengthRemaining;
  500. }
  501. virtual RoxiePacketHeader &queryHeader() const
  502. {
  503. return *data;
  504. }
  505. virtual const byte *queryTraceInfo() const
  506. {
  507. return traceInfo;
  508. }
  509. virtual unsigned getTraceLength() const
  510. {
  511. return traceLength;
  512. }
  513. virtual const void *queryContinuationData() const
  514. {
  515. return continuationData;
  516. }
  517. virtual unsigned getContinuationLength() const
  518. {
  519. return continuationLength;
  520. }
  521. virtual const byte *querySmartStepInfoData() const
  522. {
  523. return smartStepInfoData;
  524. }
  525. virtual unsigned getSmartStepInfoLength() const
  526. {
  527. return smartStepInfoLength;
  528. }
  529. virtual const void *queryContextData() const
  530. {
  531. return contextData;
  532. }
  533. virtual unsigned getContextLength() const
  534. {
  535. return contextLength;
  536. }
  537. virtual IRoxieQueryPacket *clonePacket(unsigned channel) const
  538. {
  539. unsigned length = data->packetlength;
  540. RoxiePacketHeader *newdata = (RoxiePacketHeader *) malloc(length);
  541. memcpy(newdata, data, length);
  542. newdata->channel = channel;
  543. newdata->retries |= ROXIE_BROADCAST;
  544. return createRoxiePacket(newdata, length);
  545. }
  546. virtual IRoxieQueryPacket *insertSkipData(size32_t skipDataLen, const void *skipData) const
  547. {
  548. assertex((data->continueSequence & CONTINUE_SEQUENCE_SKIPTO) == 0); // Should not already be any skipto info in the source packet
  549. unsigned newDataSize = data->packetlength + sizeof(unsigned) + skipDataLen;
  550. char *newdata = (char *) malloc(newDataSize);
  551. unsigned headSize = sizeof(RoxiePacketHeader);
  552. if (traceLength)
  553. headSize += traceLength;
  554. if (data->continueSequence & ~CONTINUE_SEQUENCE_SKIPTO)
  555. headSize += sizeof(unsigned) + continuationLength;
  556. memcpy(newdata, data, headSize); // copy in leading part of old data
  557. ((RoxiePacketHeader *) newdata)->continueSequence |= CONTINUE_SEQUENCE_SKIPTO; // set flag indicating new data is present
  558. *(unsigned *) (newdata + headSize) = skipDataLen; // add length field for new data
  559. memcpy(newdata + headSize + sizeof(unsigned), skipData, skipDataLen); // copy in new data
  560. memcpy(newdata + headSize + sizeof(unsigned) + skipDataLen, ((char *) data) + headSize, data->packetlength - headSize); // copy in remaining old data
  561. return createRoxiePacket(newdata, newDataSize);
  562. }
  563. virtual ISerializedRoxieQueryPacket *serialize() const override
  564. {
  565. unsigned length = data->packetlength;
  566. MemoryBuffer mb;
  567. if (encryptInTransit)
  568. {
  569. const byte *plainData = (const byte *) (data+1);
  570. plainData += traceLength;
  571. unsigned plainLen = length - sizeof(RoxiePacketHeader) - traceLength;
  572. mb.append(sizeof(RoxiePacketHeader)+traceLength, data); // Header and traceInfo are unencrypted
  573. const MemoryAttr &udpkey = getSecretUdpKey(true);
  574. aesEncrypt(udpkey.get(), udpkey.length(), plainData, plainLen, mb); // Encrypt everything else
  575. RoxiePacketHeader *newHeader = (RoxiePacketHeader *) mb.toByteArray();
  576. newHeader->packetlength = mb.length();
  577. }
  578. else
  579. {
  580. mb.append(length, data);
  581. }
  582. return createSerializedRoxiePacket(mb);
  583. }
  584. };
  585. // CNocryptRoxieQueryPacket implements both serialized and deserialized packet interfaces, to avoid additional copy operations when
  586. // using localAgent mode.
  587. class CNocryptRoxieQueryPacket: public CRoxieQueryPacket, implements ISerializedRoxieQueryPacket
  588. {
  589. public:
  590. IMPLEMENT_IINTERFACE;
  591. CNocryptRoxieQueryPacket(const void *_data, int length) : CRoxieQueryPacket(_data, length)
  592. {
  593. }
  594. virtual RoxiePacketHeader &queryHeader() const
  595. {
  596. return CRoxieQueryPacket::queryHeader();
  597. }
  598. virtual const byte *queryTraceInfo() const
  599. {
  600. return traceInfo;
  601. }
  602. virtual unsigned getTraceLength() const
  603. {
  604. return traceLength;
  605. }
  606. virtual ISerializedRoxieQueryPacket *cloneSerializedPacket(unsigned channel) const
  607. {
  608. unsigned length = data->packetlength;
  609. RoxiePacketHeader *newdata = (RoxiePacketHeader *) malloc(length);
  610. memcpy(newdata, data, length);
  611. newdata->channel = channel;
  612. newdata->retries |= ROXIE_BROADCAST;
  613. return new CNocryptRoxieQueryPacket(newdata, length);
  614. }
  615. virtual ISerializedRoxieQueryPacket *serialize() const override
  616. {
  617. return const_cast<CNocryptRoxieQueryPacket *>(LINK(this));
  618. }
  619. virtual IRoxieQueryPacket *deserialize() const override
  620. {
  621. return const_cast<CNocryptRoxieQueryPacket *>(LINK(this));
  622. }
  623. };
  624. class CSerializedRoxieQueryPacket : public CRoxieQueryPacketBase, implements ISerializedRoxieQueryPacket
  625. {
  626. public:
  627. IMPLEMENT_IINTERFACE;
  628. CSerializedRoxieQueryPacket(const void *_data, int length) : CRoxieQueryPacketBase(_data, length)
  629. {
  630. }
  631. virtual RoxiePacketHeader &queryHeader() const
  632. {
  633. return *data;
  634. }
  635. virtual const byte *queryTraceInfo() const
  636. {
  637. return traceInfo;
  638. }
  639. virtual unsigned getTraceLength() const
  640. {
  641. return traceLength;
  642. }
  643. virtual ISerializedRoxieQueryPacket *cloneSerializedPacket(unsigned channel) const
  644. {
  645. unsigned length = data->packetlength;
  646. RoxiePacketHeader *newdata = (RoxiePacketHeader *) malloc(length);
  647. memcpy(newdata, data, length);
  648. newdata->channel = channel;
  649. newdata->retries |= ROXIE_BROADCAST;
  650. return new CSerializedRoxieQueryPacket(newdata, length);
  651. }
  652. virtual IRoxieQueryPacket *deserialize() const override
  653. {
  654. unsigned length = data->packetlength;
  655. MemoryBuffer mb;
  656. if (encryptInTransit)
  657. {
  658. const byte *encryptedData = (const byte *) (data+1);
  659. encryptedData += traceLength;
  660. unsigned encryptedLen = length - sizeof(RoxiePacketHeader) - traceLength;
  661. mb.append(sizeof(RoxiePacketHeader)+traceLength, data); // Header and traceInfo are unencrypted
  662. const MemoryAttr &udpkey = getSecretUdpKey(true);
  663. aesDecrypt(udpkey.get(), udpkey.length(), encryptedData, encryptedLen, mb); // Decrypt everything else
  664. RoxiePacketHeader *newHeader = (RoxiePacketHeader *) mb.toByteArray();
  665. newHeader->packetlength = mb.length();
  666. }
  667. else
  668. {
  669. mb.append(length, data);
  670. }
  671. return createRoxiePacket(mb);
  672. }
  673. };
  674. extern IRoxieQueryPacket *createRoxiePacket(void *_data, unsigned _len)
  675. {
  676. if (!encryptInTransit)
  677. return new CNocryptRoxieQueryPacket(_data, _len);
  678. if ((unsigned short)_len != _len)
  679. {
  680. StringBuffer s;
  681. RoxiePacketHeader *header = (RoxiePacketHeader *) _data;
  682. header->toString(s);
  683. free(_data);
  684. throw MakeStringException(ROXIE_PACKET_ERROR, "Packet length %d exceeded maximum sending packet %s", _len, s.str());
  685. }
  686. return new CRoxieQueryPacket(_data, _len);
  687. }
  688. extern IRoxieQueryPacket *createRoxiePacket(MemoryBuffer &m)
  689. {
  690. unsigned length = m.length(); // don't make assumptions about evaluation order of parameters...
  691. return createRoxiePacket(m.detachOwn(), length);
  692. }
  693. extern IRoxieQueryPacket *deserializeCallbackPacket(MemoryBuffer &m)
  694. {
  695. // Direct decryption of special packets - others are only decrypted after being dequeued
  696. if (encryptInTransit)
  697. {
  698. RoxiePacketHeader *header = (RoxiePacketHeader *) m.toByteArray();
  699. assertex(header != nullptr);
  700. assertex(header->activityId == ROXIE_FILECALLBACK || header->activityId == ROXIE_DEBUGCALLBACK);
  701. assertex(m.length() >= header->packetlength);
  702. unsigned encryptedLen = header->packetlength - sizeof(RoxiePacketHeader);
  703. const void *encryptedData = (const void *)(header+1);
  704. MemoryBuffer decrypted;
  705. decrypted.append(sizeof(RoxiePacketHeader), header);
  706. decrypted.ensureCapacity(encryptedLen); // May be up to 16 bytes smaller...
  707. const MemoryAttr &udpkey = getSecretUdpKey(true);
  708. aesDecrypt(udpkey.get(), udpkey.length(), encryptedData, encryptedLen, decrypted);
  709. unsigned length = decrypted.length();
  710. RoxiePacketHeader *newHeader = (RoxiePacketHeader *) decrypted.detachOwn();
  711. newHeader->packetlength = length;
  712. return createRoxiePacket(newHeader, length);
  713. }
  714. else
  715. {
  716. unsigned length = m.length(); // don't make assumptions about evaluation order of parameters...
  717. return createRoxiePacket(m.detachOwn(), length);
  718. }
  719. }
  720. extern ISerializedRoxieQueryPacket *createSerializedRoxiePacket(MemoryBuffer &m)
  721. {
  722. unsigned length = m.length(); // don't make assumptions about evaluation order of parameters...
  723. return new CSerializedRoxieQueryPacket(m.detachOwn(), length);
  724. }
  725. //=================================================================================
  726. AgentContextLogger::AgentContextLogger()
  727. {
  728. GetHostIp(ip);
  729. set(NULL);
  730. }
  731. AgentContextLogger::AgentContextLogger(ISerializedRoxieQueryPacket *packet)
  732. {
  733. GetHostIp(ip);
  734. set(packet);
  735. }
  736. void AgentContextLogger::set(ISerializedRoxieQueryPacket *packet)
  737. {
  738. anyOutput = false;
  739. intercept = false;
  740. debuggerActive = false;
  741. checkingHeap = false;
  742. aborted = false;
  743. stats.reset();
  744. start = msTick();
  745. if (packet)
  746. {
  747. CriticalBlock b(crit); // Why?
  748. RoxiePacketHeader &header = packet->queryHeader();
  749. const byte *traceInfo = packet->queryTraceInfo();
  750. StringBuffer s;
  751. if (traceInfo)
  752. {
  753. unsigned traceLength = packet->getTraceLength();
  754. unsigned char loggingFlags = *traceInfo;
  755. if (loggingFlags & LOGGING_FLAGSPRESENT) // should always be true.... but this flag is handy to avoid flags byte ever being NULL
  756. {
  757. traceInfo++;
  758. traceLength--;
  759. if (loggingFlags & LOGGING_INTERCEPTED)
  760. intercept = true;
  761. if (loggingFlags & LOGGING_TRACELEVELSET)
  762. {
  763. ctxTraceLevel = (*traceInfo++ - 1); // avoid null byte here in case anyone still thinks there's just a null-terminated string
  764. traceLength--;
  765. }
  766. if (loggingFlags & LOGGING_BLIND)
  767. blind = true;
  768. if (loggingFlags & LOGGING_CHECKINGHEAP)
  769. checkingHeap = true;
  770. if (loggingFlags & LOGGING_DEBUGGERACTIVE)
  771. {
  772. assertex(traceLength > sizeof(unsigned short));
  773. debuggerActive = true;
  774. unsigned short debugLen = *(unsigned short *) traceInfo;
  775. traceInfo += debugLen + sizeof(unsigned short);
  776. traceLength -= debugLen + sizeof(unsigned short);
  777. }
  778. // Passing the wuid via the logging context prefix is a lot of a hack...
  779. if (loggingFlags & LOGGING_WUID)
  780. {
  781. unsigned wuidLen = 0;
  782. while (wuidLen < traceLength)
  783. {
  784. if (traceInfo[wuidLen]=='@'||traceInfo[wuidLen]==':')
  785. break;
  786. wuidLen++;
  787. }
  788. wuid.set((const char *) traceInfo, wuidLen);
  789. }
  790. }
  791. s.append(traceLength, (const char *) traceInfo);
  792. s.append("|");
  793. }
  794. channel = header.channel;
  795. ip.getIpText(s);
  796. s.append(':').append(channel);
  797. StringContextLogger::set(s.str());
  798. if (intercept || mergeAgentStatistics)
  799. {
  800. RoxiePacketHeader newHeader(header, ROXIE_TRACEINFO, 0); // subchannel not relevant
  801. output.setown(ROQ->createOutputStream(newHeader, false, *this));
  802. }
  803. }
  804. else
  805. {
  806. StringContextLogger::set("");
  807. channel = 0;
  808. }
  809. }
  810. void AgentContextLogger::putStatProcessed(unsigned subGraphId, unsigned actId, unsigned idx, unsigned processed, unsigned strands) const
  811. {
  812. if (output && mergeAgentStatistics)
  813. {
  814. MemoryBuffer buf;
  815. buf.append((char) LOG_CHILDCOUNT); // A special log entry for the stats
  816. buf.append(subGraphId);
  817. buf.append(actId);
  818. buf.append(idx);
  819. buf.append(processed);
  820. buf.append(strands);
  821. }
  822. }
  823. void AgentContextLogger::putStats(unsigned subGraphId, unsigned actId, const CRuntimeStatisticCollection &stats) const
  824. {
  825. if (output && mergeAgentStatistics)
  826. {
  827. MemoryBuffer buf;
  828. buf.append((char) LOG_CHILDSTATS); // A special log entry for the stats
  829. buf.append(subGraphId);
  830. buf.append(actId);
  831. if (stats.serialize(buf))
  832. {
  833. unsigned len = buf.length();
  834. void *ret = output->getBuffer(len, true);
  835. memcpy(ret, buf.toByteArray(), len);
  836. output->putBuffer(ret, len, true);
  837. anyOutput = true;
  838. }
  839. }
  840. }
  841. void AgentContextLogger::flush()
  842. {
  843. if (output)
  844. {
  845. CriticalBlock b(crit);
  846. if (mergeAgentStatistics)
  847. {
  848. MemoryBuffer buf;
  849. buf.append((char) LOG_STATVALUES); // A special log entry for the stats
  850. if (stats.serialize(buf))
  851. {
  852. unsigned len = buf.length();
  853. void *ret = output->getBuffer(len, true);
  854. memcpy(ret, buf.toByteArray(), len);
  855. output->putBuffer(ret, len, true);
  856. anyOutput = true;
  857. }
  858. }
  859. ForEachItemIn(idx, log)
  860. {
  861. MemoryBuffer buf;
  862. LogItem &logItem = log.item(idx);
  863. logItem.serialize(buf);
  864. unsigned len = buf.length();
  865. void *ret = output->getBuffer(len, true);
  866. memcpy(ret, buf.toByteArray(), len);
  867. output->putBuffer(ret, len, true);
  868. anyOutput = true;
  869. }
  870. log.kill();
  871. if (anyOutput)
  872. output->flush();
  873. output.clear();
  874. }
  875. }
  876. //=================================================================================
  877. static SpinLock onDemandQueriesCrit;
  878. static MapXToMyClass<hash64_t, hash64_t, IQueryFactory> onDemandQueryCache;
  879. void sendUnloadMessage(hash64_t hash, const char *id, const IRoxieContextLogger &logctx)
  880. {
  881. RemoteActivityId unloadId(ROXIE_UNLOAD, hash);
  882. RoxiePacketHeader header(unloadId, 0, 0, 0);
  883. MemoryBuffer mb;
  884. mb.append(sizeof(RoxiePacketHeader), &header);
  885. mb.append((char) LOGGING_FLAGSPRESENT);
  886. mb.append(id);
  887. if (traceLevel > 1)
  888. DBGLOG("UNLOAD sent for query %s", id);
  889. Owned<IRoxieQueryPacket> packet = createRoxiePacket(mb);
  890. ROQ->sendPacket(packet, logctx);
  891. }
  892. void doUnload(IRoxieQueryPacket *packet, const IRoxieContextLogger &logctx)
  893. {
  894. const RoxiePacketHeader &header = packet->queryHeader();
  895. unsigned channelNo = header.channel;
  896. if (logctx.queryTraceLevel())
  897. logctx.CTXLOG("Unload received for channel %d", channelNo);
  898. hash64_t hashValue = header.queryHash;
  899. hashValue = rtlHash64Data(sizeof(channelNo), &channelNo, hashValue);
  900. SpinBlock b(onDemandQueriesCrit);
  901. onDemandQueryCache.remove(hashValue);
  902. }
  903. void cacheOnDemandQuery(hash64_t hashValue, unsigned channelNo, IQueryFactory *query)
  904. {
  905. hashValue = rtlHash64Data(sizeof(channelNo), &channelNo, hashValue);
  906. SpinBlock b(onDemandQueriesCrit);
  907. onDemandQueryCache.setValue(hashValue, query);
  908. }
  909. //=================================================================================
  910. struct PingRecord
  911. {
  912. unsigned tick;
  913. IpAddress senderIP;
  914. };
  915. void doPing(IRoxieQueryPacket *packet, const IRoxieContextLogger &logctx)
  916. {
  917. const RoxiePacketHeader &header = packet->queryHeader();
  918. const IpAddress serverIP = header.serverId.getIpAddress();
  919. unsigned contextLength = packet->getContextLength();
  920. if (contextLength != sizeof(PingRecord))
  921. {
  922. StringBuffer s;
  923. throw MakeStringException(ROXIE_UNKNOWN_SERVER, "Unexpected data size %d (expected %d) in PING: %s", contextLength, (unsigned) sizeof(PingRecord), header.toString(s).str());
  924. }
  925. const PingRecord *data = (const PingRecord *) packet->queryContextData();
  926. if (!serverIP.ipequals(data->senderIP))
  927. {
  928. StringBuffer s;
  929. throw MakeStringException(ROXIE_UNKNOWN_SERVER, "Message received from unknown Roxie server %s", header.toString(s).str());
  930. }
  931. RoxiePacketHeader newHeader(header, ROXIE_PING, 0); // subchannel not relevant
  932. Owned<IMessagePacker> output = ROQ->createOutputStream(newHeader, true, logctx);
  933. void *ret = output->getBuffer(contextLength, false);
  934. memcpy(ret, data, contextLength);
  935. output->putBuffer(ret, contextLength, false);
  936. output->flush();
  937. }
  938. //=================================================================================
  939. static ThreadId roxiePacketReaderThread = 0;
  940. class IBYTIbuffer
  941. {
  942. // This class is used to track a finite set of recently-received IBYTI messages, that may have arrived before the messages they refer to
  943. // It is accessed ONLY from the main reader thread and as such does not need to be threadsafe (but does need to be fast).
  944. // We use a circular buffer, and don't bother removing anything (just treat old items as expired). If the buffer overflows we will end up
  945. // discarding the oldest tracked orphaned IBYTI - but that's ok, no worse than if we hadn't tracked them at all.
  946. public:
  947. IBYTIbuffer(unsigned _numOrphans) : numOrphans(_numOrphans)
  948. {
  949. assertex(numOrphans);
  950. orphans = new RoxiePacketHeader[numOrphans];
  951. tail = 0;
  952. }
  953. ~IBYTIbuffer()
  954. {
  955. delete [] orphans;
  956. }
  957. void noteOrphan(const RoxiePacketHeader &hdr)
  958. {
  959. assert(GetCurrentThreadId()==roxiePacketReaderThread);
  960. unsigned now = msTick();
  961. // We could trace that the buffer may be too small, if (orphans[tail].activityId >= now)
  962. orphans[tail].copy(hdr);
  963. orphans[tail].activityId = now + IBYTIbufferLifetime;
  964. tail++;
  965. if (tail == numOrphans)
  966. tail = 0;
  967. }
  968. bool lookup(const RoxiePacketHeader &hdr) const
  969. {
  970. assert(GetCurrentThreadId()==roxiePacketReaderThread);
  971. unsigned now = msTick();
  972. unsigned lookat = tail;
  973. do
  974. {
  975. if (!lookat)
  976. lookat = numOrphans;
  977. lookat--;
  978. if ((int) (orphans[lookat].activityId - now) < 0) // Watch out for wrapping
  979. break; // expired;
  980. if (orphans[lookat].matchPacket(hdr))
  981. return true;
  982. } while (lookat != tail);
  983. return false;
  984. }
  985. private:
  986. RoxiePacketHeader *orphans = nullptr;
  987. unsigned tail = 0;
  988. unsigned numOrphans = 0;
  989. };
  990. //=================================================================================
  991. //
  992. // RoxieQueue - holds pending transactions on a roxie agent
  993. class RoxieQueue : public CInterface, implements IThreadFactory
  994. {
  995. Owned <IThreadPool> workers;
  996. QueueOf<ISerializedRoxieQueryPacket, true> waiting;
  997. Semaphore available;
  998. CriticalSection qcrit;
  999. unsigned headRegionSize;
  1000. unsigned numWorkers;
  1001. RelaxedAtomic<unsigned> started;
  1002. std::atomic<unsigned> idle;
  1003. IBYTIbuffer *myIBYTIbuffer = nullptr;
  1004. void noteQueued()
  1005. {
  1006. maxQueueLength.store_max(++queueLength);
  1007. // NOTE - there is a small race condition here - if idle is 1 but two enqueue's happen
  1008. // close enough together that the signal has not yet caused idle to come back down to zero, then the
  1009. // desired new thread may not be created. It's unlikely, and it's benign in that the query is still
  1010. // processed and the thread will be created next time the HWM is reached.
  1011. if (started < numWorkers && idle==0)
  1012. {
  1013. workers->start(this);
  1014. started++;
  1015. }
  1016. }
  1017. public:
  1018. IMPLEMENT_IINTERFACE;
  1019. RoxieQueue(unsigned _headRegionSize, unsigned _numWorkers)
  1020. {
  1021. headRegionSize = _headRegionSize;
  1022. numWorkers = _numWorkers;
  1023. workers.setown(createThreadPool("RoxieWorkers", this, NULL, numWorkers));
  1024. started = 0;
  1025. idle = 0;
  1026. if (IBYTIbufferSize)
  1027. myIBYTIbuffer = new IBYTIbuffer(IBYTIbufferSize);
  1028. }
  1029. ~RoxieQueue()
  1030. {
  1031. delete myIBYTIbuffer;
  1032. }
  1033. virtual IPooledThread *createNew();
  1034. void abortChannel(unsigned channel);
  1035. void start()
  1036. {
  1037. if (prestartAgentThreads)
  1038. {
  1039. while (started < numWorkers)
  1040. {
  1041. workers->start(this);
  1042. started++;
  1043. }
  1044. }
  1045. }
  1046. IPooledThreadIterator *running()
  1047. {
  1048. return workers->running();
  1049. }
  1050. void stopAll()
  1051. {
  1052. workers->stopAll(true);
  1053. signal(workers->runningCount());
  1054. }
  1055. void join()
  1056. {
  1057. workers->joinAll(true);
  1058. workers.clear(); // Breaks a cyclic reference count that would stop us from releasing RoxieReceiverThread otherwise
  1059. }
  1060. void enqueue(ISerializedRoxieQueryPacket *x)
  1061. {
  1062. {
  1063. #ifdef TIME_PACKETS
  1064. x->queryHeader().tick = msTick();
  1065. #endif
  1066. CriticalBlock qc(qcrit);
  1067. waiting.enqueue(x);
  1068. noteQueued();
  1069. }
  1070. available.signal();
  1071. }
  1072. void enqueueUnique(ISerializedRoxieQueryPacket *x, unsigned subChannel)
  1073. {
  1074. RoxiePacketHeader &header = x->queryHeader();
  1075. #ifdef TIME_PACKETS
  1076. header.tick = msTick();
  1077. #endif
  1078. bool found = false;
  1079. {
  1080. CriticalBlock qc(qcrit);
  1081. unsigned len = waiting.ordinality();
  1082. unsigned i;
  1083. for (i = 0; i < len; i++)
  1084. {
  1085. ISerializedRoxieQueryPacket *queued = waiting.item(i);
  1086. if (queued && queued->queryHeader().matchPacket(header))
  1087. {
  1088. found = true;
  1089. break;
  1090. }
  1091. }
  1092. if (!found)
  1093. waiting.enqueue(x);
  1094. }
  1095. if (found)
  1096. {
  1097. if (traceLevel > 0)
  1098. {
  1099. StringBuffer xx;
  1100. AgentContextLogger l(x);
  1101. l.CTXLOG("Ignored retry on subchannel %u for queued activity %s", subChannel, header.toString(xx).str());
  1102. }
  1103. if (!subChannel)
  1104. retriesIgnoredPrm++;
  1105. else
  1106. retriesIgnoredSec++;
  1107. x->Release();
  1108. }
  1109. else
  1110. {
  1111. available.signal();
  1112. noteQueued();
  1113. if (traceLevel > 10)
  1114. {
  1115. AgentContextLogger l(x);
  1116. StringBuffer xx;
  1117. l.CTXLOG("enqueued %s", header.toString(xx).str());
  1118. }
  1119. }
  1120. }
  1121. bool remove(RoxiePacketHeader &x)
  1122. {
  1123. unsigned scanLength = 0;
  1124. ISerializedRoxieQueryPacket *found = nullptr;
  1125. {
  1126. CriticalBlock qc(qcrit);
  1127. unsigned len = waiting.ordinality();
  1128. unsigned i;
  1129. for (i = 0; i < len; i++)
  1130. {
  1131. ISerializedRoxieQueryPacket *queued = waiting.item(i);
  1132. if (queued)
  1133. {
  1134. scanLength++;
  1135. if (queued->queryHeader().matchPacket(x))
  1136. {
  1137. waiting.set(i, NULL);
  1138. found = queued;
  1139. break;
  1140. }
  1141. }
  1142. }
  1143. }
  1144. if (found)
  1145. {
  1146. #ifdef _DEBUG
  1147. RoxiePacketHeader &header = found->queryHeader();
  1148. AgentContextLogger l(found);
  1149. StringBuffer xx;
  1150. l.CTXLOG("discarded %s", header.toString(xx).str());
  1151. #endif
  1152. found->Release();
  1153. queueLength--;
  1154. if (scanLength > maxScanLength)
  1155. maxScanLength = scanLength;
  1156. totScanLength += scanLength;
  1157. totScans++;
  1158. return true;
  1159. }
  1160. else
  1161. return false;
  1162. }
  1163. void wait()
  1164. {
  1165. idle++;
  1166. available.wait();
  1167. idle--;
  1168. }
  1169. void signal(unsigned num)
  1170. {
  1171. available.signal(num);
  1172. }
  1173. ISerializedRoxieQueryPacket *dequeue()
  1174. {
  1175. CriticalBlock qc(qcrit);
  1176. unsigned lim = waiting.ordinality();
  1177. if (lim)
  1178. {
  1179. if (headRegionSize)
  1180. {
  1181. if (lim > headRegionSize)
  1182. lim = headRegionSize;
  1183. return waiting.dequeue(fastRand() % lim);
  1184. }
  1185. return waiting.dequeue();
  1186. }
  1187. else
  1188. return NULL;
  1189. }
  1190. unsigned getHeadRegionSize() const
  1191. {
  1192. return headRegionSize;
  1193. }
  1194. unsigned setHeadRegionSize(unsigned newsize)
  1195. {
  1196. unsigned ret = headRegionSize;
  1197. headRegionSize = newsize;
  1198. return ret;
  1199. }
  1200. void noteOrphanIBYTI(const RoxiePacketHeader &hdr)
  1201. {
  1202. if (myIBYTIbuffer)
  1203. myIBYTIbuffer->noteOrphan(hdr);
  1204. }
  1205. bool lookupOrphanIBYTI(const RoxiePacketHeader &hdr) const
  1206. {
  1207. if (myIBYTIbuffer)
  1208. return myIBYTIbuffer->lookup(hdr);
  1209. else
  1210. return false;
  1211. }
  1212. };
  1213. class CRoxieWorker : public CInterface, implements IPooledThread
  1214. {
  1215. RoxieQueue *queue;
  1216. CriticalSection actCrit;
  1217. #ifndef NEW_IBYTI
  1218. Semaphore ibytiSem;
  1219. #endif
  1220. bool stopped;
  1221. bool abortJob;
  1222. bool busy;
  1223. Owned<IRoxieAgentActivity> activity;
  1224. Owned<IRoxieQueryPacket> packet;
  1225. Owned<const ITopologyServer> topology;
  1226. AgentContextLogger logctx;
  1227. public:
  1228. IMPLEMENT_IINTERFACE;
  1229. CRoxieWorker()
  1230. {
  1231. queue = NULL;
  1232. stopped = false;
  1233. busy = false;
  1234. abortJob = false;
  1235. }
  1236. virtual void init(void *_r) override
  1237. {
  1238. queue = (RoxieQueue *) _r;
  1239. stopped = false;
  1240. busy = false;
  1241. abortJob = false;
  1242. }
  1243. virtual bool canReuse() const override
  1244. {
  1245. return true;
  1246. }
  1247. virtual bool stop() override
  1248. {
  1249. stopped = true;
  1250. return true;
  1251. }
  1252. inline void setActivity(IRoxieAgentActivity *act)
  1253. {
  1254. CriticalBlock b(actCrit);
  1255. activity.setown(act);
  1256. }
  1257. inline bool match(RoxiePacketHeader &h)
  1258. {
  1259. // There is a window between getting packet from queue and being able to match it.
  1260. // This could cause some deduping to fail, but it does not matter if it does (so long as it is rare!)
  1261. CriticalBlock b(actCrit);
  1262. return packet && packet->queryHeader().matchPacket(h);
  1263. }
  1264. void abortChannel(unsigned channel)
  1265. {
  1266. CriticalBlock b(actCrit);
  1267. if (packet && packet->queryHeader().channel==channel)
  1268. {
  1269. abortJob = true;
  1270. #ifndef NEW_IBYTI
  1271. if (doIbytiDelay)
  1272. ibytiSem.signal();
  1273. #endif
  1274. if (activity)
  1275. activity->abort();
  1276. }
  1277. }
  1278. bool checkAbort(RoxiePacketHeader &h, bool checkRank, bool &queryFound, bool &preActivity)
  1279. {
  1280. CriticalBlock b(actCrit);
  1281. if (packet && packet->queryHeader().matchPacket(h))
  1282. {
  1283. queryFound = true;
  1284. abortJob = true;
  1285. #ifndef NEW_IBYTI
  1286. if (doIbytiDelay)
  1287. ibytiSem.signal();
  1288. #endif
  1289. if (activity)
  1290. {
  1291. // Try to stop/abort a job after it starts only if IBYTI comes from a higher priority agent
  1292. // (more primary in the rank). The agents with higher rank will hold the lower bits of the retries field in IBYTI packet).
  1293. #ifdef SUBCHANNELS_IN_HEADER
  1294. if (!checkRank || h.getRespondingSubChannel() < h.mySubChannel())
  1295. #else
  1296. if (!checkRank || topology->queryChannelInfo(h.channel).otherAgentHasPriority(h.priorityHash(), h.getRespondingSubChannel()))
  1297. #endif
  1298. {
  1299. activity->abort();
  1300. return true;
  1301. }
  1302. else
  1303. {
  1304. return false;
  1305. }
  1306. }
  1307. if (busy)
  1308. {
  1309. preActivity = true;
  1310. return true;
  1311. }
  1312. }
  1313. return false;
  1314. }
  1315. void throwRemoteException(IException *E, IRoxieAgentActivity *activity, IRoxieQueryPacket *packet, bool isUser)
  1316. {
  1317. try
  1318. {
  1319. if (activity && (logctx.queryTraceLevel() > 1))
  1320. {
  1321. StringBuffer act;
  1322. activity->toString(act);
  1323. logctx.CTXLOG("throwRemoteException, activity %s, isUser=%d", act.str(), (int) isUser);
  1324. if (!isUser)
  1325. EXCLOG(E, "throwRemoteException");
  1326. }
  1327. RoxiePacketHeader &header = packet->queryHeader();
  1328. #ifdef SUBCHANNELS_IN_HEADER
  1329. unsigned mySubChannel = header.mySubChannel();
  1330. #else
  1331. unsigned mySubChannel = topology->queryChannelInfo(header.channel).subChannel();
  1332. #endif
  1333. // I failed to do the query, but already sent out IBYTI - resend it so someone else can try
  1334. if (!isUser)
  1335. {
  1336. StringBuffer s;
  1337. s.append("Exception in agent for packet ");
  1338. header.toString(s);
  1339. logctx.logOperatorException(E, NULL, 0, "%s", s.str());
  1340. header.setException(mySubChannel);
  1341. if (!header.allChannelsFailed() && !localAgent)
  1342. {
  1343. if (logctx.queryTraceLevel() > 1)
  1344. logctx.CTXLOG("resending packet from agent in case others want to try it");
  1345. ROQ->sendPacket(packet, logctx);
  1346. }
  1347. }
  1348. RoxiePacketHeader newHeader(header, ROXIE_EXCEPTION, mySubChannel);
  1349. if (isUser)
  1350. newHeader.retries = (unsigned short) -1;
  1351. Owned<IMessagePacker> output = ROQ->createOutputStream(newHeader, true, logctx);
  1352. StringBuffer message("<Exception>");
  1353. message.appendf("<Code>%d</Code><Message>", E->errorCode());
  1354. StringBuffer err;
  1355. E->errorMessage(err);
  1356. encodeXML(err.str(), message);
  1357. message.append("</Message></Exception>");
  1358. unsigned len = message.length();
  1359. void *ret = output->getBuffer(len+1, true);
  1360. memcpy(ret, message.str(), len+1);
  1361. output->putBuffer(ret, len+1, true);
  1362. output->flush();
  1363. E->Release();
  1364. }
  1365. catch (IException *EInE)
  1366. {
  1367. EXCLOG(EInE, "Exception during throwRemoteException");
  1368. E->Release();
  1369. EInE->Release();
  1370. }
  1371. catch (...)
  1372. {
  1373. logctx.CTXLOG("Unknown Exception during throwRemoteException");
  1374. E->Release();
  1375. }
  1376. }
  1377. void doActivity()
  1378. {
  1379. RoxiePacketHeader &header = packet->queryHeader();
  1380. unsigned channel = header.channel;
  1381. hash64_t queryHash = packet->queryHeader().queryHash;
  1382. unsigned activityId = packet->queryHeader().activityId & ~ROXIE_PRIORITY_MASK;
  1383. Owned<IQueryFactory> queryFactory = getQueryFactory(queryHash, channel);
  1384. #ifdef SUBCHANNELS_IN_HEADER
  1385. unsigned mySubChannel = header.mySubChannel();
  1386. #else
  1387. unsigned numAgents = topology->queryAgents(channel).ordinality();
  1388. unsigned mySubChannel = topology->queryChannelInfo(channel).subChannel();
  1389. #endif
  1390. if (!queryFactory && logctx.queryWuid())
  1391. {
  1392. Owned <IRoxieDaliHelper> daliHelper = connectToDali();
  1393. Owned<IConstWorkUnit> wu = daliHelper->attachWorkunit(logctx.queryWuid());
  1394. queryFactory.setown(createAgentQueryFactoryFromWu(wu, channel));
  1395. if (queryFactory)
  1396. cacheOnDemandQuery(queryHash, channel, queryFactory);
  1397. }
  1398. if (!queryFactory)
  1399. {
  1400. StringBuffer hdr;
  1401. IException *E = MakeStringException(MSGAUD_operator, ROXIE_UNKNOWN_QUERY, "Roxie agent received request for unregistered query: %s", packet->queryHeader().toString(hdr).str());
  1402. EXCLOG(E, "doActivity");
  1403. throwRemoteException(E, activity, packet, false);
  1404. return;
  1405. }
  1406. try
  1407. {
  1408. bool debugging = logctx.queryDebuggerActive();
  1409. if (debugging)
  1410. {
  1411. if (mySubChannel)
  1412. abortJob = true; // when debugging, we always run on primary only...
  1413. }
  1414. #ifndef NEW_IBYTI
  1415. #ifdef SUBCHANNELS_IN_HEADER
  1416. else if (doIbytiDelay && mySubChannel)
  1417. {
  1418. unsigned delay = 0;
  1419. for (unsigned subChannel = 0; subChannel < mySubChannel; subChannel++)
  1420. delay += getIbytiDelay(header.subChannels[subChannel].getIpAddress());
  1421. unsigned start = 0;
  1422. if (traceRoxiePackets)
  1423. {
  1424. StringBuffer x;
  1425. DBGLOG("YES myTurnToDelay subchannel=%u delay=%u %s", mySubChannel, delay, header.toString(x).str());
  1426. start = msTick();
  1427. }
  1428. if (delay)
  1429. ibytiSem.wait(delay);
  1430. if (traceRoxiePackets)
  1431. {
  1432. StringBuffer x;
  1433. DBGLOG("Delay done, abortJob=%d, elapsed=%d", (int) abortJob, msTick()-start);
  1434. }
  1435. if (!abortJob)
  1436. {
  1437. for (unsigned subChannel = 0; subChannel < mySubChannel; subChannel++)
  1438. noteNodeSick(header.subChannels[subChannel]);
  1439. }
  1440. }
  1441. #else
  1442. else if (doIbytiDelay && (numAgents > 1))
  1443. {
  1444. unsigned hdrHashVal = header.priorityHash();
  1445. unsigned primarySubChannel = (hdrHashVal % numAgents);
  1446. if (primarySubChannel != mySubChannel)
  1447. {
  1448. unsigned delay = topology->queryChannelInfo(channel).getIbytiDelay(primarySubChannel);
  1449. if (logctx.queryTraceLevel() > 6)
  1450. {
  1451. StringBuffer x;
  1452. logctx.CTXLOG("YES myTurnToDelayIBYTI subchannel=%u delay=%u hash=%u %s", mySubChannel, delay, hdrHashVal, header.toString(x).str());
  1453. }
  1454. // MORE: if we are dealing with a query that was on channel 0, we may want a longer delay
  1455. // (since the theory about duplicated work not mattering when cluster is idle does not hold up)
  1456. if (delay)
  1457. {
  1458. ibytiSem.wait(delay);
  1459. if (!abortJob)
  1460. topology->queryChannelInfo(channel).noteChannelsSick(primarySubChannel);
  1461. if (logctx.queryTraceLevel() > 8)
  1462. {
  1463. StringBuffer x;
  1464. logctx.CTXLOG("Buddy did%s send IBYTI, updated delay : %s",
  1465. abortJob ? "" : " NOT", header.toString(x).str());
  1466. }
  1467. }
  1468. }
  1469. else
  1470. {
  1471. #ifndef NO_IBYTI_DELAYS_COUNT
  1472. if (!mySubChannel)
  1473. ibytiNoDelaysPrm++;
  1474. else
  1475. ibytiNoDelaysSec++;
  1476. #endif
  1477. if (logctx.queryTraceLevel() > 6)
  1478. {
  1479. StringBuffer x;
  1480. logctx.CTXLOG("NOT myTurnToDelayIBYTI subchannel=%u hash=%u %s", mySubChannel, hdrHashVal, header.toString(x).str());
  1481. }
  1482. }
  1483. }
  1484. #endif
  1485. #endif
  1486. if (abortJob)
  1487. {
  1488. CriticalBlock b(actCrit);
  1489. busy = false; // Keep order - before setActivity below
  1490. if (logctx.queryTraceLevel() > 5)
  1491. {
  1492. StringBuffer x;
  1493. logctx.CTXLOG("Stop before processing - activity aborted %s", header.toString(x).str());
  1494. }
  1495. return;
  1496. }
  1497. if (!debugging)
  1498. ROQ->sendIbyti(header, logctx, mySubChannel);
  1499. activitiesStarted++;
  1500. Owned <IAgentActivityFactory> factory = queryFactory->getAgentActivityFactory(activityId);
  1501. assertex(factory);
  1502. setActivity(factory->createActivity(logctx, packet));
  1503. Owned<IMessagePacker> output = activity->process();
  1504. if (logctx.queryTraceLevel() > 5)
  1505. {
  1506. StringBuffer x;
  1507. logctx.CTXLOG("done processing %s", header.toString(x).str());
  1508. }
  1509. if (output)
  1510. {
  1511. activitiesCompleted++;
  1512. busy = false; // Keep order - before setActivity below
  1513. setActivity(NULL); // Ensures all stats are merged from child queries etc
  1514. logctx.flush();
  1515. output->flush();
  1516. }
  1517. }
  1518. catch (IUserException *E)
  1519. {
  1520. throwRemoteException(E, activity, packet, true);
  1521. }
  1522. catch (IException *E)
  1523. {
  1524. if (E->errorCode()!=ROXIE_ABORT_ERROR)
  1525. throwRemoteException(E, activity, packet, false);
  1526. else
  1527. E->Release();
  1528. }
  1529. catch (...)
  1530. {
  1531. throwRemoteException(MakeStringException(ROXIE_MULTICAST_ERROR, "Unknown exception"), activity, packet, false);
  1532. }
  1533. busy = false; // Keep order - before setActivity below
  1534. setActivity(NULL);
  1535. }
  1536. virtual void threadmain() override
  1537. {
  1538. while (!stopped)
  1539. {
  1540. try
  1541. {
  1542. for (;;)
  1543. {
  1544. queue->wait();
  1545. if (stopped)
  1546. break;
  1547. agentsActive++;
  1548. maxAgentsActive.store_max(agentsActive);
  1549. abortJob = false;
  1550. busy = true;
  1551. #ifndef NEW_IBYTI
  1552. if (doIbytiDelay)
  1553. ibytiSem.reinit(0U); // Make sure sem is is in no-signaled state
  1554. #endif
  1555. Owned<ISerializedRoxieQueryPacket> next = queue->dequeue();
  1556. if (next)
  1557. {
  1558. logctx.set(next);
  1559. packet.setown(next->deserialize());
  1560. next.clear();
  1561. queueLength--;
  1562. RoxiePacketHeader &header = packet->queryHeader();
  1563. #ifdef TIME_PACKETS
  1564. {
  1565. unsigned now = msTick();
  1566. unsigned packetWait = now-header.tick;
  1567. header.tick = now;
  1568. packetWaitMax.store_max(packetWait);
  1569. packetWaitElapsed += packetWait;
  1570. packetWaitCount++;
  1571. }
  1572. #endif
  1573. topology.setown(getTopology());
  1574. if (logctx.queryTraceLevel() > 10)
  1575. {
  1576. StringBuffer x;
  1577. logctx.CTXLOG("dequeued %s", header.toString(x).str());
  1578. }
  1579. if ((header.activityId & ~ROXIE_PRIORITY_MASK) == ROXIE_UNLOAD)
  1580. {
  1581. doUnload(packet, logctx);
  1582. }
  1583. else if ((header.activityId & ~ROXIE_PRIORITY_MASK) == ROXIE_PING)
  1584. {
  1585. doPing(packet, logctx);
  1586. }
  1587. else if ((header.activityId & ~ROXIE_PRIORITY_MASK) == ROXIE_DEBUGREQUEST)
  1588. {
  1589. // MORE - we need to make sure only executed on primary, and that the proxyId (== pointer to DebugGraphManager) is still valid.
  1590. // 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
  1591. doDebugRequest(packet, logctx);
  1592. }
  1593. else if (header.channel)
  1594. doActivity();
  1595. else
  1596. throwUnexpected(); // channel 0 requests translated earlier now
  1597. #ifdef TIME_PACKETS
  1598. {
  1599. unsigned now = msTick();
  1600. unsigned packetRun = now-header.tick;
  1601. packetRunMax.store_max(packetRun);
  1602. packetRunElapsed += packetRun;
  1603. packetRunCount++;
  1604. }
  1605. #endif
  1606. }
  1607. busy = false;
  1608. {
  1609. CriticalBlock b(actCrit);
  1610. packet.clear();
  1611. topology.clear();
  1612. logctx.set(NULL);
  1613. }
  1614. agentsActive--;
  1615. }
  1616. }
  1617. catch(IException *E)
  1618. {
  1619. CriticalBlock b(actCrit);
  1620. EXCLOG(E);
  1621. if (packet)
  1622. {
  1623. throwRemoteException(E, NULL, packet, false);
  1624. packet.clear();
  1625. }
  1626. else
  1627. E->Release();
  1628. topology.clear();
  1629. }
  1630. catch(...)
  1631. {
  1632. CriticalBlock b(actCrit);
  1633. Owned<IException> E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unexpected exception in Roxie worker thread");
  1634. EXCLOG(E);
  1635. if (packet)
  1636. {
  1637. throwRemoteException(E.getClear(), NULL, packet, false);
  1638. packet.clear();
  1639. }
  1640. topology.clear();
  1641. }
  1642. }
  1643. }
  1644. };
  1645. IPooledThread *RoxieQueue::createNew()
  1646. {
  1647. return new CRoxieWorker;
  1648. }
  1649. void RoxieQueue::abortChannel(unsigned channel)
  1650. {
  1651. Owned<IPooledThreadIterator> wi = workers->running();
  1652. ForEach(*wi)
  1653. {
  1654. CRoxieWorker &w = (CRoxieWorker &) wi->query();
  1655. w.abortChannel(channel);
  1656. }
  1657. }
  1658. //=================================================================================
  1659. class CallbackEntry : implements IPendingCallback, public CInterface
  1660. {
  1661. const RoxiePacketHeader &header;
  1662. StringAttr lfn;
  1663. InterruptableSemaphore ready;
  1664. MemoryBuffer data;
  1665. bool gotData;
  1666. public:
  1667. IMPLEMENT_IINTERFACE;
  1668. CallbackEntry(const RoxiePacketHeader &_header, const char *_lfn) : header(_header), lfn(_lfn)
  1669. {
  1670. gotData = false;
  1671. }
  1672. virtual bool wait(unsigned msecs)
  1673. {
  1674. return ready.wait(msecs);
  1675. }
  1676. virtual MemoryBuffer &queryData()
  1677. {
  1678. return data;
  1679. }
  1680. bool matches(RoxiePacketHeader &cand, const char *_lfn)
  1681. {
  1682. return (cand.matchPacket(header) && (!_lfn|| stricmp(_lfn, lfn)==0));
  1683. }
  1684. void doFileCallback(unsigned _len, const void *_data, bool aborted)
  1685. {
  1686. // MORE - make sure we call this for whole query abort as well as for callback abort
  1687. if (aborted)
  1688. ready.interrupt(MakeStringException(0, "Interrupted"));
  1689. else if (!gotData)
  1690. {
  1691. gotData = true;
  1692. data.append(_len, _data);
  1693. ready.signal();
  1694. }
  1695. }
  1696. };
  1697. class RoxieReceiverBase : implements IRoxieOutputQueueManager, public CInterface
  1698. {
  1699. protected:
  1700. RoxieQueue slaQueue;
  1701. RoxieQueue hiQueue;
  1702. RoxieQueue loQueue;
  1703. unsigned numWorkers;
  1704. public:
  1705. IMPLEMENT_IINTERFACE;
  1706. RoxieReceiverBase(unsigned _numWorkers) : slaQueue(headRegionSize, _numWorkers), hiQueue(headRegionSize, _numWorkers), loQueue(headRegionSize, _numWorkers), numWorkers(_numWorkers)
  1707. {
  1708. }
  1709. virtual unsigned getHeadRegionSize() const
  1710. {
  1711. return loQueue.getHeadRegionSize();
  1712. }
  1713. virtual void setHeadRegionSize(unsigned newSize)
  1714. {
  1715. slaQueue.setHeadRegionSize(newSize);
  1716. hiQueue.setHeadRegionSize(newSize);
  1717. loQueue.setHeadRegionSize(newSize);
  1718. }
  1719. virtual void start()
  1720. {
  1721. loQueue.start();
  1722. hiQueue.start();
  1723. slaQueue.start();
  1724. }
  1725. virtual void stop()
  1726. {
  1727. loQueue.stopAll();
  1728. hiQueue.stopAll();
  1729. slaQueue.stopAll();
  1730. }
  1731. virtual void join()
  1732. {
  1733. loQueue.join();
  1734. hiQueue.join();
  1735. slaQueue.join();
  1736. }
  1737. IArrayOf<CallbackEntry> callbacks;
  1738. CriticalSection callbacksCrit;
  1739. virtual IPendingCallback *notePendingCallback(const RoxiePacketHeader &header, const char *lfn)
  1740. {
  1741. CriticalBlock b(callbacksCrit);
  1742. CallbackEntry *callback = new CallbackEntry(header, lfn);
  1743. callbacks.append(*callback);
  1744. return callback;
  1745. }
  1746. virtual void removePendingCallback(IPendingCallback *goer)
  1747. {
  1748. if (goer)
  1749. {
  1750. CriticalBlock b(callbacksCrit);
  1751. callbacks.zap(static_cast<CallbackEntry &>(*goer));
  1752. }
  1753. }
  1754. protected:
  1755. void doFileCallback(IRoxieQueryPacket *packet)
  1756. {
  1757. // This is called on the main agent reader thread so needs to be as fast as possible to avoid lost packets
  1758. const char *lfn;
  1759. const char *data;
  1760. unsigned len;
  1761. RoxiePacketHeader &header = packet->queryHeader();
  1762. if (header.activityId == ROXIE_FILECALLBACK || header.activityId == ROXIE_DEBUGCALLBACK)
  1763. {
  1764. lfn = (const char *) packet->queryContextData();
  1765. unsigned namelen = strlen(lfn) + 1;
  1766. data = lfn + namelen;
  1767. len = packet->getContextLength() - namelen;
  1768. }
  1769. else
  1770. {
  1771. lfn = data = NULL; // used when query aborted
  1772. len = 0;
  1773. }
  1774. CriticalBlock b(callbacksCrit);
  1775. ForEachItemIn(idx, callbacks)
  1776. {
  1777. CallbackEntry &c = callbacks.item(idx);
  1778. if (c.matches(header, lfn))
  1779. {
  1780. if (traceLevel > 10)
  1781. DBGLOG("callback return matched a waiting query");
  1782. c.doFileCallback(len, data, header.retries==QUERY_ABORTED);
  1783. }
  1784. }
  1785. }
  1786. };
  1787. #ifdef _MSC_VER
  1788. #pragma warning ( push )
  1789. #pragma warning ( disable: 4355 )
  1790. #endif
  1791. class RoxieThrottledPacketSender : public Thread
  1792. {
  1793. TokenBucket &bucket;
  1794. InterruptableSemaphore queued;
  1795. Semaphore started;
  1796. unsigned maxPacketSize;
  1797. SafeQueueOf<IRoxieQueryPacket, false> queue;
  1798. class DECL_EXCEPTION StoppedException: public IException, public CInterface
  1799. {
  1800. public:
  1801. IMPLEMENT_IINTERFACE;
  1802. int errorCode() const { return 0; }
  1803. StringBuffer & errorMessage(StringBuffer &str) const { return str.append("Stopped"); }
  1804. MessageAudience errorAudience() const { return MSGAUD_user; }
  1805. };
  1806. void enqueue(IRoxieQueryPacket *packet)
  1807. {
  1808. packet->Link();
  1809. queue.enqueue(packet);
  1810. queued.signal();
  1811. }
  1812. IRoxieQueryPacket *dequeue()
  1813. {
  1814. queued.wait();
  1815. return queue.dequeue();
  1816. }
  1817. public:
  1818. RoxieThrottledPacketSender(TokenBucket &_bucket, unsigned _maxPacketSize)
  1819. : Thread("RoxieThrottledPacketSender"), bucket(_bucket), maxPacketSize(_maxPacketSize)
  1820. {
  1821. start();
  1822. started.wait();
  1823. }
  1824. ~RoxieThrottledPacketSender()
  1825. {
  1826. stop();
  1827. join();
  1828. }
  1829. virtual int run()
  1830. {
  1831. started.signal();
  1832. for (;;)
  1833. {
  1834. try
  1835. {
  1836. Owned<IRoxieQueryPacket> packet = dequeue();
  1837. unsigned length = packet->queryHeader().packetlength;
  1838. {
  1839. MTIME_SECTION(queryActiveTimer(), "bucket_wait");
  1840. bucket.wait((length / 1024) + 1);
  1841. }
  1842. Owned<ISerializedRoxieQueryPacket> serialized = packet->serialize();
  1843. if (!channelWrite(serialized->queryHeader(), true))
  1844. DBGLOG("Roxie packet write wrote too little");
  1845. packetsSent++;
  1846. }
  1847. catch (StoppedException *E)
  1848. {
  1849. E->Release();
  1850. break;
  1851. }
  1852. catch (IException *E)
  1853. {
  1854. EXCLOG(E);
  1855. E->Release();
  1856. }
  1857. catch (...)
  1858. {
  1859. }
  1860. }
  1861. return 0;
  1862. }
  1863. void sendPacket(IRoxieQueryPacket *x, const IRoxieContextLogger &logctx)
  1864. {
  1865. RoxiePacketHeader &header = x->queryHeader();
  1866. unsigned length = x->queryHeader().packetlength;
  1867. assertex (header.activityId & ~ROXIE_PRIORITY_MASK);
  1868. switch (header.retries & ROXIE_RETRIES_MASK)
  1869. {
  1870. case (QUERY_ABORTED & ROXIE_RETRIES_MASK):
  1871. {
  1872. StringBuffer s;
  1873. logctx.CTXLOG("Aborting packet size=%d: %s", length, header.toString(s).str());
  1874. }
  1875. break;
  1876. default:
  1877. {
  1878. StringBuffer s;
  1879. logctx.CTXLOG("Resending packet size=%d: %s", length, header.toString(s).str());
  1880. }
  1881. break;
  1882. case 0:
  1883. if (logctx.queryTraceLevel() > 8)
  1884. {
  1885. StringBuffer s;
  1886. logctx.CTXLOG("Sending packet size=%d: %s", length, header.toString(s).str());
  1887. }
  1888. break;
  1889. }
  1890. if (length > maxPacketSize)
  1891. {
  1892. StringBuffer s;
  1893. throw MakeStringException(ROXIE_PACKET_ERROR, "Maximum packet length %d exceeded sending packet %s", maxPacketSize, header.toString(s).str());
  1894. }
  1895. enqueue(x);
  1896. }
  1897. void stop()
  1898. {
  1899. // bucket.stop();
  1900. queued.interrupt(new StoppedException);
  1901. }
  1902. };
  1903. //------------------------------------------------------------------------------------------------------------
  1904. #ifdef NEW_IBYTI
  1905. class DelayedPacketQueue
  1906. {
  1907. // Used to keep a list of all recently-received packets where we are not primary subchannel. There is one queue per subchannel level
  1908. // It is accessed ONLY from the main reader thread and does not need to be threadsafe (but does need to be fast)
  1909. // We use a doubly-linked list (not std::list as not quite flexible enough).
  1910. class DelayedPacketEntry
  1911. {
  1912. DelayedPacketEntry() = delete;
  1913. DelayedPacketEntry(const DelayedPacketEntry&) = delete;
  1914. public:
  1915. DelayedPacketEntry(ISerializedRoxieQueryPacket *_packet, unsigned _waitExpires)
  1916. : packet(_packet), waitExpires(_waitExpires)
  1917. {
  1918. }
  1919. ~DelayedPacketEntry()
  1920. {
  1921. if (prev)
  1922. prev->next = next;
  1923. if (next)
  1924. next->prev = prev;
  1925. }
  1926. bool matches(const RoxiePacketHeader &ibyti) const
  1927. {
  1928. return packet->queryHeader().matchPacket(ibyti);
  1929. }
  1930. ISerializedRoxieQueryPacket *getClear()
  1931. {
  1932. return packet.getClear();
  1933. }
  1934. StringBuffer & describe(StringBuffer &ret) const
  1935. {
  1936. return packet->queryHeader().toString(ret);
  1937. }
  1938. Owned<ISerializedRoxieQueryPacket> packet;
  1939. DelayedPacketEntry *next = nullptr;
  1940. DelayedPacketEntry *prev = nullptr;
  1941. unsigned waitExpires = 0;
  1942. };
  1943. public:
  1944. DelayedPacketQueue() = default;
  1945. DelayedPacketQueue(const DelayedPacketQueue&) = delete;
  1946. ~DelayedPacketQueue()
  1947. {
  1948. while (head)
  1949. removeEntry(head);
  1950. }
  1951. bool doIBYTI(const RoxiePacketHeader &ibyti)
  1952. {
  1953. assert(GetCurrentThreadId()==roxiePacketReaderThread);
  1954. DelayedPacketEntry *finger = head;
  1955. while (finger)
  1956. {
  1957. if (finger->matches(ibyti))
  1958. {
  1959. if (traceRoxiePackets)
  1960. {
  1961. StringBuffer s;
  1962. DBGLOG("IBYTI removing delayed packet %s", finger->describe(s).str());
  1963. }
  1964. removeEntry(finger);
  1965. return true;
  1966. }
  1967. finger = finger->next;
  1968. }
  1969. return false;
  1970. }
  1971. void append(ISerializedRoxieQueryPacket *packet, unsigned expires)
  1972. {
  1973. // Goes on the end. But percolate the expiry time backwards
  1974. assert(GetCurrentThreadId()==roxiePacketReaderThread);
  1975. DelayedPacketEntry *newEntry = new DelayedPacketEntry(packet, expires);
  1976. if (traceRoxiePackets)
  1977. {
  1978. StringBuffer s;
  1979. DBGLOG("Adding delayed packet %s", packet->queryHeader().toString(s).str());
  1980. }
  1981. newEntry->prev = tail;
  1982. if (tail)
  1983. {
  1984. tail->next = newEntry;
  1985. for (DelayedPacketEntry *finger = tail; finger != nullptr; finger = finger->prev)
  1986. {
  1987. if ((int) (finger->waitExpires - expires) <= 0)
  1988. break;
  1989. finger->waitExpires = expires;
  1990. finger = finger->prev;
  1991. }
  1992. }
  1993. else
  1994. head = newEntry;
  1995. tail = newEntry;
  1996. }
  1997. // Move any that we are done waiting for our buddy onto the active queue
  1998. void checkExpired(unsigned now, RoxieQueue &slaQueue, RoxieQueue &hiQueue, RoxieQueue &loQueue)
  1999. {
  2000. assert(GetCurrentThreadId()==roxiePacketReaderThread);
  2001. DelayedPacketEntry *finger = head;
  2002. while (finger)
  2003. {
  2004. if (((int) (finger->waitExpires - now)) <= 0) // Oddly coded to handle wrapping
  2005. {
  2006. ISerializedRoxieQueryPacket *packet = finger->getClear();
  2007. const RoxiePacketHeader &header = packet->queryHeader();
  2008. if (traceRoxiePackets)
  2009. {
  2010. StringBuffer s;
  2011. DBGLOG("No IBYTI received yet for delayed packet %s", header.toString(s).str());
  2012. }
  2013. if (header.activityId & ROXIE_SLA_PRIORITY)
  2014. slaQueue.enqueue(packet);
  2015. else if (header.activityId & ROXIE_HIGH_PRIORITY)
  2016. hiQueue.enqueue(packet);
  2017. else
  2018. loQueue.enqueue(packet);
  2019. for (unsigned subChannel = 0; subChannel < MAX_SUBCHANNEL; subChannel++)
  2020. {
  2021. if (header.subChannels[subChannel].isMe() || header.subChannels[subChannel].isNull())
  2022. break;
  2023. noteNodeSick(header.subChannels[subChannel]);
  2024. }
  2025. DelayedPacketEntry *goer = finger;
  2026. finger = finger->next;
  2027. removeEntry(goer);
  2028. }
  2029. else
  2030. break;
  2031. }
  2032. }
  2033. // How long until the next time we want to call checkExpires() ?
  2034. unsigned timeout(unsigned now) const
  2035. {
  2036. assert(GetCurrentThreadId()==roxiePacketReaderThread);
  2037. if (head)
  2038. {
  2039. int delay = (int) (head->waitExpires - now);
  2040. if (delay <= 0)
  2041. return 0;
  2042. else
  2043. return (unsigned) delay;
  2044. }
  2045. else
  2046. return (unsigned) -1;
  2047. }
  2048. private:
  2049. void removeEntry(DelayedPacketEntry *goer)
  2050. {
  2051. if (goer==head)
  2052. head = goer->next;
  2053. if (goer==tail)
  2054. tail = goer->prev;
  2055. delete goer;
  2056. }
  2057. DelayedPacketEntry *head = nullptr;
  2058. DelayedPacketEntry *tail = nullptr;
  2059. };
  2060. //------------------------------------------------------------------------------------------------------------
  2061. class DelayedPacketQueueChannel : public CInterface
  2062. {
  2063. // Manages a set of DelayedPacketQueues, one for each supported subchannel level.
  2064. DelayedPacketQueueChannel() = delete;
  2065. DelayedPacketQueueChannel(const DelayedPacketQueueChannel&) = delete;
  2066. public:
  2067. DelayedPacketQueueChannel(unsigned _channel) : channel(_channel)
  2068. {
  2069. }
  2070. inline unsigned queryChannel() const { return channel; }
  2071. inline DelayedPacketQueue &queryQueue(unsigned subchannel)
  2072. {
  2073. assertex(subchannel); // Subchannel 0 means primary and is never delayed
  2074. subchannel -= 1;
  2075. if (subchannel > maxSeen)
  2076. maxSeen = subchannel;
  2077. return queues[subchannel];
  2078. }
  2079. unsigned timeout(unsigned now) const
  2080. {
  2081. unsigned min = (unsigned) -1;
  2082. for (unsigned queue = 0; queue <= maxSeen; queue++)
  2083. {
  2084. unsigned t = queues[queue].timeout(now);
  2085. if (t < min)
  2086. min = t;
  2087. }
  2088. return min;
  2089. }
  2090. void checkExpired(unsigned now, RoxieQueue &slaQueue, RoxieQueue &hiQueue, RoxieQueue &loQueue)
  2091. {
  2092. for (unsigned queue = 0; queue <= maxSeen; queue++)
  2093. {
  2094. queues[queue].checkExpired(now, slaQueue, hiQueue, loQueue);
  2095. }
  2096. }
  2097. private:
  2098. DelayedPacketQueue queues[MAX_SUBCHANNEL-1]; // Note - primary subchannel is not included
  2099. unsigned channel = 0;
  2100. unsigned maxSeen = 0;
  2101. };
  2102. class DelayedPacketQueueManager
  2103. {
  2104. public:
  2105. DelayedPacketQueueManager() = default;
  2106. DelayedPacketQueueManager(const DelayedPacketQueueManager&) = delete;
  2107. inline DelayedPacketQueue &queryQueue(unsigned channel, unsigned subchannel)
  2108. {
  2109. // Note - there are normally no more than a couple of channels on a single agent.
  2110. // If that were to change we could make this a fixed size array
  2111. assert(GetCurrentThreadId()==roxiePacketReaderThread);
  2112. ForEachItemIn(idx, channels)
  2113. {
  2114. DelayedPacketQueueChannel &i = channels.item(idx);
  2115. if (i.queryChannel() == channel)
  2116. return i.queryQueue(subchannel);
  2117. }
  2118. channels.append(*new DelayedPacketQueueChannel(channel));
  2119. return channels.tos().queryQueue(subchannel);
  2120. }
  2121. unsigned timeout(unsigned now) const
  2122. {
  2123. unsigned ret = (unsigned) -1;
  2124. ForEachItemIn(idx, channels)
  2125. {
  2126. unsigned t = channels.item(idx).timeout(now);
  2127. if (t < ret)
  2128. ret = t;
  2129. }
  2130. return ret;
  2131. }
  2132. void checkExpired(unsigned now, RoxieQueue &slaQueue, RoxieQueue &hiQueue, RoxieQueue &loQueue)
  2133. {
  2134. ForEachItemIn(idx, channels)
  2135. {
  2136. channels.item(idx).checkExpired(now, slaQueue, hiQueue, loQueue);
  2137. }
  2138. }
  2139. private:
  2140. CIArrayOf<DelayedPacketQueueChannel> channels;
  2141. };
  2142. #endif
  2143. //------------------------------------------------------------------------------------------------------------
  2144. class RoxieSocketQueueManager : public RoxieReceiverBase
  2145. {
  2146. protected:
  2147. Linked<ISendManager> sendManager;
  2148. Linked<IReceiveManager> receiveManager;
  2149. Owned<RoxieThrottledPacketSender> throttledPacketSendManager;
  2150. Owned<TokenBucket> bucket;
  2151. unsigned maxPacketSize = 0;
  2152. std::atomic<bool> running = { false };
  2153. #ifdef NEW_IBYTI
  2154. DelayedPacketQueueManager delayed;
  2155. #endif
  2156. class ReceiverThread : public Thread
  2157. {
  2158. RoxieSocketQueueManager &parent;
  2159. public:
  2160. ReceiverThread(RoxieSocketQueueManager &_parent) : Thread("RoxieSocketQueueManager"), parent(_parent) {}
  2161. int run()
  2162. {
  2163. // Raise the priority so ibyti's get through in a timely fashion
  2164. #if defined( __linux__) || defined(__APPLE__)
  2165. setLinuxThreadPriority(3);
  2166. #else
  2167. adjustPriority(1);
  2168. #endif
  2169. roxiePacketReaderThread = GetCurrentThreadId();
  2170. return parent.run();
  2171. }
  2172. } readThread;
  2173. public:
  2174. RoxieSocketQueueManager(unsigned _numWorkers) : RoxieReceiverBase(_numWorkers), readThread(*this)
  2175. {
  2176. maxPacketSize = multicastSocket->get_max_send_size();
  2177. if ((maxPacketSize==0)||(maxPacketSize>65535))
  2178. maxPacketSize = 65535;
  2179. }
  2180. virtual void sendPacket(IRoxieQueryPacket *x, const IRoxieContextLogger &logctx)
  2181. {
  2182. if (throttledPacketSendManager)
  2183. throttledPacketSendManager->sendPacket(x, logctx);
  2184. else
  2185. {
  2186. MTIME_SECTION(queryActiveTimer(), "RoxieSocketQueueManager::sendPacket");
  2187. RoxiePacketHeader &header = x->queryHeader();
  2188. unsigned length = x->queryHeader().packetlength;
  2189. assertex (header.activityId & ~ROXIE_PRIORITY_MASK);
  2190. StringBuffer s;
  2191. switch (header.retries & ROXIE_RETRIES_MASK)
  2192. {
  2193. case (QUERY_ABORTED & ROXIE_RETRIES_MASK):
  2194. logctx.CTXLOG("Aborting packet size=%d: %s", length, header.toString(s).str());
  2195. break;
  2196. default:
  2197. logctx.CTXLOG("Resending packet size=%d: %s", length, header.toString(s).str());
  2198. break;
  2199. case 0:
  2200. if (logctx.queryTraceLevel() > 8)
  2201. logctx.CTXLOG("Sending packet size=%d: %s", length, header.toString(s).str());
  2202. break;
  2203. }
  2204. if (length > maxPacketSize)
  2205. {
  2206. StringBuffer s;
  2207. throw MakeStringException(ROXIE_PACKET_ERROR, "Maximum packet length %d exceeded sending packet %s", maxPacketSize, header.toString(s).str());
  2208. }
  2209. Owned <ISerializedRoxieQueryPacket> serialized = x->serialize();
  2210. if (!channelWrite(serialized->queryHeader(), true))
  2211. logctx.CTXLOG("Roxie packet write wrote too little");
  2212. packetsSent++;
  2213. }
  2214. }
  2215. virtual void sendIbyti(RoxiePacketHeader &header, const IRoxieContextLogger &logctx, unsigned subChannel) override
  2216. {
  2217. #ifdef SUBCHANNELS_IN_HEADER
  2218. if (!header.hasBuddies())
  2219. return;
  2220. #endif
  2221. MTIME_SECTION(queryActiveTimer(), "RoxieSocketQueueManager::sendIbyti");
  2222. RoxiePacketHeader ibytiHeader(header, header.activityId & ROXIE_PRIORITY_MASK, subChannel);
  2223. if (logctx.queryTraceLevel() > 8)
  2224. {
  2225. StringBuffer s; logctx.CTXLOG("Sending IBYTI packet %s", ibytiHeader.toString(s).str());
  2226. }
  2227. channelWrite(ibytiHeader, false); // don't send to self
  2228. ibytiPacketsSent++;
  2229. }
  2230. virtual void sendAbort(RoxiePacketHeader &header, const IRoxieContextLogger &logctx) override
  2231. {
  2232. MTIME_SECTION(queryActiveTimer(), "RoxieSocketQueueManager::sendAbort");
  2233. RoxiePacketHeader abortHeader(header, header.activityId & ROXIE_PRIORITY_MASK, 0); // subChannel irrelevant - we are about to overwrite retries anyway
  2234. abortHeader.retries = QUERY_ABORTED;
  2235. if (logctx.queryTraceLevel() > 8)
  2236. {
  2237. StringBuffer s; logctx.CTXLOG("Sending ABORT packet %s", abortHeader.toString(s).str());
  2238. }
  2239. try
  2240. {
  2241. if (!channelWrite(abortHeader, true))
  2242. logctx.CTXLOG("sendAbort wrote too little");
  2243. }
  2244. catch (IException *E)
  2245. {
  2246. EXCLOG(E);
  2247. E->Release();
  2248. }
  2249. abortsSent++;
  2250. }
  2251. virtual void sendAbortCallback(const RoxiePacketHeader &header, const char *lfn, const IRoxieContextLogger &logctx) override
  2252. {
  2253. MTIME_SECTION(queryActiveTimer(), "RoxieSocketQueueManager::sendAbortCallback");
  2254. RoxiePacketHeader abortHeader(header, ROXIE_FILECALLBACK, 0); // subChannel irrelevant - we are about to overwrite retries anyway
  2255. abortHeader.retries = QUERY_ABORTED;
  2256. abortHeader.packetlength += strlen(lfn)+1;
  2257. MemoryBuffer data;
  2258. data.append(sizeof(abortHeader), &abortHeader).append(lfn);
  2259. if (logctx.queryTraceLevel() > 5)
  2260. {
  2261. StringBuffer s; logctx.CTXLOG("Sending ABORT FILECALLBACK packet %s for file %s", abortHeader.toString(s).str(), lfn);
  2262. }
  2263. Owned<IRoxieQueryPacket> packet = createRoxiePacket(data);
  2264. Owned<ISerializedRoxieQueryPacket> serialized = packet->serialize();
  2265. if (!channelWrite(serialized->queryHeader(), true))
  2266. logctx.CTXLOG("sendAbortCallback wrote too little");
  2267. abortsSent++;
  2268. }
  2269. virtual IMessagePacker *createOutputStream(RoxiePacketHeader &header, bool outOfBand, const IRoxieContextLogger &logctx)
  2270. {
  2271. unsigned qnum = outOfBand ? 0 : ((header.retries & ROXIE_FASTLANE) || !fastLaneQueue) ? 1 : 2;
  2272. if (logctx.queryTraceLevel() > 8)
  2273. {
  2274. StringBuffer s; logctx.CTXLOG("Creating Output Stream for reply packet on Q=%d - %s", qnum, header.toString(s).str());
  2275. }
  2276. return sendManager->createMessagePacker(header.uid, header.getSequenceId(), &header, sizeof(RoxiePacketHeader), header.serverId, qnum);
  2277. }
  2278. virtual bool replyPending(RoxiePacketHeader &header)
  2279. {
  2280. return sendManager->dataQueued(header.uid, header.getSequenceId(), header.serverId);
  2281. }
  2282. virtual bool abortCompleted(RoxiePacketHeader &header)
  2283. {
  2284. return sendManager->abortData(header.uid, header.getSequenceId(), header.serverId);
  2285. }
  2286. bool abortRunning(RoxiePacketHeader &header, RoxieQueue &queue, bool checkRank, bool &preActivity)
  2287. {
  2288. bool queryFound = false;
  2289. bool ret = false;
  2290. Owned<IPooledThreadIterator> wi = queue.running();
  2291. ForEach(*wi)
  2292. {
  2293. CRoxieWorker &w = (CRoxieWorker &) wi->query();
  2294. if (w.checkAbort(header, checkRank, queryFound, preActivity))
  2295. {
  2296. ret = true;
  2297. break;
  2298. }
  2299. else if (queryFound)
  2300. {
  2301. ret = false;
  2302. break;
  2303. }
  2304. }
  2305. if (!checkRank)
  2306. {
  2307. if (traceLevel > 8)
  2308. DBGLOG("discarding data for aborted query");
  2309. ROQ->abortCompleted(header);
  2310. }
  2311. return ret;
  2312. }
  2313. void doIbyti(RoxiePacketHeader &header, RoxieQueue &queue)
  2314. {
  2315. assert(!localAgent);
  2316. bool preActivity = false;
  2317. #ifdef SUBCHANNELS_IN_HEADER
  2318. unsigned mySubChannel = header.mySubChannel();
  2319. #else
  2320. Owned<const ITopologyServer> topology = getTopology();
  2321. const ChannelInfo &channelInfo = topology->queryChannelInfo(header.channel);
  2322. unsigned mySubChannel = channelInfo.subChannel();
  2323. #endif
  2324. if (header.retries == QUERY_ABORTED)
  2325. {
  2326. bool foundInQ = false;
  2327. #ifdef NEW_IBYTI
  2328. foundInQ = mySubChannel != 0 && delayed.queryQueue(header.channel, mySubChannel).doIBYTI(header);
  2329. #endif
  2330. if (!foundInQ)
  2331. foundInQ = queue.remove(header);
  2332. if (!foundInQ)
  2333. abortRunning(header, queue, false, preActivity);
  2334. if (traceRoxiePackets || traceLevel > 10)
  2335. {
  2336. StringBuffer s;
  2337. DBGLOG("Abort activity %s", header.toString(s).str());
  2338. }
  2339. }
  2340. else
  2341. {
  2342. ibytiPacketsReceived++;
  2343. unsigned subChannel = header.getRespondingSubChannel();
  2344. if (subChannel == mySubChannel)
  2345. {
  2346. if (traceRoxiePackets || traceLevel > 10)
  2347. DBGLOG("doIBYTI packet was from self");
  2348. ibytiPacketsFromSelf++;
  2349. }
  2350. else
  2351. {
  2352. #ifndef SUBCHANNELS_IN_HEADER
  2353. channelInfo.noteChannelHealthy(subChannel);
  2354. #else
  2355. noteNodeHealthy(header.subChannels[subChannel]);
  2356. #endif
  2357. bool foundInQ = false;
  2358. #ifdef NEW_IBYTI
  2359. foundInQ = mySubChannel != 0 && delayed.queryQueue(header.channel, mySubChannel).doIBYTI(header);
  2360. #endif
  2361. if (!foundInQ)
  2362. foundInQ = queue.remove(header);
  2363. if (foundInQ)
  2364. {
  2365. if (traceRoxiePackets || traceLevel > 10)
  2366. {
  2367. StringBuffer s;
  2368. DBGLOG("Removed activity from Q : %s", header.toString(s).str());
  2369. }
  2370. ibytiPacketsWorked++;
  2371. return;
  2372. }
  2373. if (abortRunning(header, queue, true, preActivity))
  2374. {
  2375. if (traceRoxiePackets || traceLevel > 10)
  2376. {
  2377. StringBuffer s;
  2378. DBGLOG("Aborted running activity : %s", header.toString(s).str());
  2379. }
  2380. if (preActivity)
  2381. ibytiPacketsWorked++;
  2382. else
  2383. ibytiPacketsHalfWorked++;
  2384. return;
  2385. }
  2386. if (traceRoxiePackets || traceLevel > 10)
  2387. {
  2388. StringBuffer s;
  2389. DBGLOG("doIBYTI packet was too late (or too early) : %s", header.toString(s).str());
  2390. }
  2391. ibytiPacketsTooLate++; // meaning either I started and reserve the right to finish, or I finished already
  2392. if (IBYTIbufferSize)
  2393. queue.noteOrphanIBYTI(header);
  2394. }
  2395. }
  2396. }
  2397. void processMessage(MemoryBuffer &mb, RoxiePacketHeader &header, RoxieQueue &queue)
  2398. {
  2399. // 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
  2400. // DO NOT put tracing on this thread except at very high tracelevels!
  2401. if ((header.activityId & ~ROXIE_PRIORITY_MASK) == 0)
  2402. doIbyti(header, queue);
  2403. else
  2404. {
  2405. if (!header.channel)
  2406. {
  2407. // Turn broadcast packet (channel 0), as early as possible, into non-0 channel packets.
  2408. // So retries and other communication with Roxie server (which uses non-0 channel numbers) will not cause double work or confusion.
  2409. // Unfortunately this is bad news for dropping packets
  2410. // In SUBCHANNELS_IN_HEADER mode this translation has been done on server before sending, except for some control messages like PING or UNLOAD
  2411. Owned<const ITopologyServer> topology = getTopology();
  2412. const std::vector<unsigned> channels = topology->queryChannels();
  2413. Owned<ISerializedRoxieQueryPacket> packet = createSerializedRoxiePacket(mb);
  2414. for (unsigned i = 1; i < channels.size(); i++)
  2415. queue.enqueue(packet->cloneSerializedPacket(channels[i]));
  2416. header.channel = channels[0];
  2417. queue.enqueue(packet.getClear());
  2418. return;
  2419. }
  2420. #ifdef SUBCHANNELS_IN_HEADER
  2421. unsigned mySubchannel = header.mySubChannel();
  2422. #else
  2423. Owned<const ITopologyServer> topology = getTopology();
  2424. unsigned mySubchannel = topology->queryChannelInfo(header.channel).subChannel();
  2425. #endif
  2426. if (header.activityId == ROXIE_FILECALLBACK || header.activityId == ROXIE_DEBUGCALLBACK )
  2427. {
  2428. Owned<IRoxieQueryPacket> packet = deserializeCallbackPacket(mb);
  2429. if (traceLevel > 10)
  2430. {
  2431. StringBuffer s;
  2432. DBGLOG("ROXIE_CALLBACK %s", header.toString(s).str());
  2433. }
  2434. doFileCallback(packet);
  2435. }
  2436. else if (IBYTIbufferSize && queue.lookupOrphanIBYTI(header))
  2437. {
  2438. if (traceRoxiePackets || traceLevel > 10)
  2439. {
  2440. StringBuffer s;
  2441. DBGLOG("doIBYTI packet was too early : %s", header.toString(s).str());
  2442. }
  2443. ibytiPacketsTooLate--;
  2444. ibytiPacketsTooEarly++;
  2445. }
  2446. else
  2447. {
  2448. Owned<ISerializedRoxieQueryPacket> packet = createSerializedRoxiePacket(mb);
  2449. AgentContextLogger logctx(packet);
  2450. unsigned retries = header.thisChannelRetries(mySubchannel);
  2451. if (retries)
  2452. {
  2453. // MORE - is this fast enough? By the time I am seeing retries I may already be under load. Could move onto a separate thread
  2454. assertex(header.channel); // should never see a retry on channel 0
  2455. if (retries >= SUBCHANNEL_MASK)
  2456. return; // someone sent a failure or something - ignore it
  2457. // Send back an out-of-band immediately, to let Roxie server know that channel is still active
  2458. if (!(testAgentFailure & 0x800))
  2459. {
  2460. RoxiePacketHeader newHeader(header, ROXIE_ALIVE, mySubchannel);
  2461. Owned<IMessagePacker> output = ROQ->createOutputStream(newHeader, true, logctx);
  2462. output->flush();
  2463. }
  2464. // If it's a retry, look it up against already running, or output stream, or input queue
  2465. // if found, send an IBYTI and discard retry request
  2466. if (!mySubchannel)
  2467. retriesReceivedPrm++;
  2468. else
  2469. retriesReceivedSec++;
  2470. bool alreadyRunning = false;
  2471. Owned<IPooledThreadIterator> wi = queue.running();
  2472. ForEach(*wi)
  2473. {
  2474. CRoxieWorker &w = (CRoxieWorker &) wi->query();
  2475. if (w.match(header))
  2476. {
  2477. alreadyRunning = true;
  2478. if (!mySubchannel)
  2479. retriesIgnoredPrm++;
  2480. else
  2481. retriesIgnoredSec++;
  2482. ROQ->sendIbyti(header, logctx, mySubchannel);
  2483. if (logctx.queryTraceLevel() > 10)
  2484. {
  2485. StringBuffer xx; logctx.CTXLOG("Ignored retry on subchannel %u for running activity %s", mySubchannel, header.toString(xx).str());
  2486. }
  2487. break;
  2488. }
  2489. }
  2490. if (!alreadyRunning && checkCompleted && ROQ->replyPending(header))
  2491. {
  2492. alreadyRunning = true;
  2493. if (!mySubchannel)
  2494. retriesIgnoredPrm++;
  2495. else
  2496. retriesIgnoredSec++;
  2497. ROQ->sendIbyti(header, logctx, mySubchannel);
  2498. if (logctx.queryTraceLevel() > 10)
  2499. {
  2500. StringBuffer xx; logctx.CTXLOG("Ignored retry on subchannel %u for completed activity %s", mySubchannel, header.toString(xx).str());
  2501. }
  2502. }
  2503. if (!alreadyRunning)
  2504. {
  2505. if (logctx.queryTraceLevel() > 10)
  2506. {
  2507. StringBuffer xx; logctx.CTXLOG("Retry %d received on subchannel %u for %s", retries+1, mySubchannel, header.toString(xx).str());
  2508. }
  2509. queue.enqueueUnique(packet.getClear(), mySubchannel);
  2510. }
  2511. }
  2512. else // first time (not a retry).
  2513. {
  2514. #ifdef NEW_IBYTI
  2515. if (mySubchannel != 0) // i.e. I am not the primary here
  2516. {
  2517. unsigned delay = 0;
  2518. for (unsigned subChannel = 0; subChannel < mySubchannel; subChannel++)
  2519. delay += getIbytiDelay(header.subChannels[subChannel]);
  2520. delayed.queryQueue(header.channel, mySubchannel).append(packet.getClear(), msTick()+delay);
  2521. }
  2522. else
  2523. #endif
  2524. queue.enqueue(packet.getClear());
  2525. }
  2526. }
  2527. }
  2528. }
  2529. int run()
  2530. {
  2531. if (traceLevel)
  2532. DBGLOG("RoxieSocketQueueManager::run() starting: doIbytiDelay=%s minIbytiDelay=%u initIbytiDelay=%u",
  2533. doIbytiDelay?"YES":"NO", minIbytiDelay, initIbytiDelay);
  2534. for (;;)
  2535. {
  2536. MemoryBuffer mb;
  2537. try
  2538. {
  2539. // 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
  2540. // DO NOT put tracing on this thread except at very high tracelevels!
  2541. #ifdef NEW_IBYTI
  2542. unsigned timeout = delayed.timeout(msTick());
  2543. if (timeout>5000)
  2544. timeout = 5000;
  2545. #else
  2546. unsigned timeout = 5000;
  2547. #endif
  2548. unsigned l;
  2549. multicastSocket->readtms(mb.reserve(maxPacketSize), sizeof(RoxiePacketHeader), maxPacketSize, l, timeout);
  2550. mb.setLength(l);
  2551. packetsReceived++;
  2552. RoxiePacketHeader &header = *(RoxiePacketHeader *) mb.toByteArray();
  2553. if (l != header.packetlength)
  2554. DBGLOG("sock->read returned %d but packetlength was %d", l, header.packetlength);
  2555. if (traceRoxiePackets || traceLevel > 10)
  2556. {
  2557. StringBuffer s;
  2558. DBGLOG("Read roxie packet: %s", header.toString(s).str());
  2559. }
  2560. if (header.activityId & ROXIE_SLA_PRIORITY)
  2561. processMessage(mb, header, slaQueue);
  2562. else if (header.activityId & ROXIE_HIGH_PRIORITY)
  2563. processMessage(mb, header, hiQueue);
  2564. else
  2565. processMessage(mb, header, loQueue);
  2566. }
  2567. catch (IException *E)
  2568. {
  2569. if (running)
  2570. {
  2571. // MORE: Maybe we should utilize IException::errorCode - not just text ??
  2572. if (E->errorCode()==JSOCKERR_timeout_expired)
  2573. E->Release();
  2574. else if (roxiemem::memPoolExhausted())
  2575. {
  2576. //MORE: I think this should probably be based on the error code instead.
  2577. EXCLOG(E, "Exception reading or processing roxie packet");
  2578. E->Release();
  2579. MilliSleep(1000); // Give a chance for mem free
  2580. }
  2581. else
  2582. {
  2583. EXCLOG(E, "Exception reading or processing roxie packet");
  2584. E->Release();
  2585. // MORE: Protect with try logic, in case udp_create throws exception ?
  2586. // What to do if create fails (ie exception is caught) ?
  2587. if (multicastSocket)
  2588. {
  2589. multicastSocket->close();
  2590. multicastSocket.clear();
  2591. openMulticastSocket();
  2592. }
  2593. }
  2594. }
  2595. else
  2596. {
  2597. E->Release();
  2598. break;
  2599. }
  2600. }
  2601. #ifdef NEW_IBYTI
  2602. delayed.checkExpired(msTick(), slaQueue, hiQueue, loQueue);
  2603. #endif
  2604. }
  2605. return 0;
  2606. }
  2607. void start()
  2608. {
  2609. RoxieReceiverBase::start();
  2610. running = true;
  2611. readThread.start();
  2612. }
  2613. void stop()
  2614. {
  2615. if (running)
  2616. {
  2617. running = false;
  2618. multicastSocket->close();
  2619. }
  2620. RoxieReceiverBase::stop();
  2621. }
  2622. void join()
  2623. {
  2624. readThread.join();
  2625. RoxieReceiverBase::join();
  2626. }
  2627. virtual IReceiveManager *queryReceiveManager()
  2628. {
  2629. return receiveManager;
  2630. }
  2631. };
  2632. class RoxieUdpSocketQueueManager : public RoxieSocketQueueManager
  2633. {
  2634. public:
  2635. RoxieUdpSocketQueueManager(unsigned _numWorkers, bool encryptionInTransit) : RoxieSocketQueueManager(_numWorkers)
  2636. {
  2637. unsigned udpQueueSize = topology->getPropInt("@udpQueueSize", UDP_QUEUE_SIZE);
  2638. unsigned udpSendQueueSize = topology->getPropInt("@udpSendQueueSize", UDP_SEND_QUEUE_SIZE);
  2639. unsigned udpMaxSlotsPerClient = topology->getPropInt("@udpMaxSlotsPerClient", 0x7fffffff);
  2640. if (topology->getPropInt("@sendMaxRate", 0))
  2641. {
  2642. unsigned sendMaxRate = topology->getPropInt("@sendMaxRate");
  2643. unsigned sendMaxRatePeriod = topology->getPropInt("@sendMaxRatePeriod", 1);
  2644. bucket.setown(new TokenBucket(sendMaxRate, sendMaxRatePeriod, sendMaxRate));
  2645. throttledPacketSendManager.setown(new RoxieThrottledPacketSender(*bucket, maxPacketSize));
  2646. }
  2647. if (udpMaxSlotsPerClient > udpQueueSize)
  2648. udpMaxSlotsPerClient = udpQueueSize;
  2649. if (udpResendLostPackets && udpMaxSlotsPerClient > TRACKER_BITS)
  2650. udpMaxSlotsPerClient = TRACKER_BITS;
  2651. unsigned serverFlowPort = topology->getPropInt("@serverFlowPort", CCD_SERVER_FLOW_PORT);
  2652. bool sendFlowOnDataPort = topology->getPropBool("@sendFlowOnDataPort", true);
  2653. unsigned dataPort = topology->getPropInt("@dataPort", CCD_DATA_PORT);
  2654. unsigned clientFlowPort = topology->getPropInt("@clientFlowPort", CCD_CLIENT_FLOW_PORT);
  2655. receiveManager.setown(createReceiveManager(serverFlowPort, dataPort, clientFlowPort, udpQueueSize, udpMaxSlotsPerClient, encryptionInTransit));
  2656. sendManager.setown(createSendManager(sendFlowOnDataPort ? dataPort : serverFlowPort, dataPort, clientFlowPort, udpSendQueueSize, fastLaneQueue ? 3 : 2, bucket, encryptionInTransit));
  2657. }
  2658. virtual void abortPendingData(const SocketEndpoint &ep) override
  2659. {
  2660. sendManager->abortAll(ep);
  2661. }
  2662. };
  2663. class RoxieAeronSocketQueueManager : public RoxieSocketQueueManager
  2664. {
  2665. public:
  2666. RoxieAeronSocketQueueManager(unsigned _numWorkers, bool encryptionInTransit) : RoxieSocketQueueManager(_numWorkers)
  2667. {
  2668. unsigned dataPort = topology->getPropInt("@dataPort", CCD_DATA_PORT);
  2669. SocketEndpoint ep(dataPort, myNode.getIpAddress());
  2670. receiveManager.setown(createAeronReceiveManager(ep, encryptionInTransit));
  2671. assertex(!myNode.getIpAddress().isNull());
  2672. sendManager.setown(createAeronSendManager(dataPort, fastLaneQueue ? 3 : 2, myNode.getIpAddress(), encryptionInTransit));
  2673. }
  2674. virtual void abortPendingData(const SocketEndpoint &ep) override
  2675. {
  2676. }
  2677. };
  2678. #ifdef _MSC_VER
  2679. #pragma warning( pop )
  2680. #endif
  2681. //==================================================================================================
  2682. interface ILocalMessageCollator : extends IMessageCollator
  2683. {
  2684. virtual void enqueueMessage(bool outOfBand, void *data, unsigned datalen, void *meta, unsigned metalen, void *header, unsigned headerlen) = 0;
  2685. };
  2686. interface ILocalReceiveManager : extends IReceiveManager
  2687. {
  2688. virtual ILocalMessageCollator *lookupCollator(ruid_t id) = 0;
  2689. };
  2690. class LocalMessagePacker : public CDummyMessagePacker
  2691. {
  2692. MemoryBuffer meta;
  2693. MemoryBuffer header;
  2694. Linked<ILocalReceiveManager> rm;
  2695. ruid_t id;
  2696. bool outOfBand;
  2697. public:
  2698. IMPLEMENT_IINTERFACE;
  2699. LocalMessagePacker(RoxiePacketHeader &_header, bool _outOfBand, ILocalReceiveManager *_rm) : rm(_rm), outOfBand(_outOfBand)
  2700. {
  2701. id = _header.uid;
  2702. header.append(sizeof(RoxiePacketHeader), &_header);
  2703. }
  2704. virtual void flush() override;
  2705. virtual void sendMetaInfo(const void *buf, unsigned len) override
  2706. {
  2707. meta.append(len, buf);
  2708. }
  2709. };
  2710. class CLocalMessageUnpackCursor : implements IMessageUnpackCursor, public CInterface
  2711. {
  2712. void *data;
  2713. unsigned datalen;
  2714. unsigned pos;
  2715. Linked<IRowManager> rowManager;
  2716. public:
  2717. IMPLEMENT_IINTERFACE;
  2718. CLocalMessageUnpackCursor(IRowManager *_rowManager, void *_data, unsigned _datalen)
  2719. : rowManager(_rowManager)
  2720. {
  2721. datalen = _datalen;
  2722. data = _data;
  2723. pos = 0;
  2724. }
  2725. ~CLocalMessageUnpackCursor()
  2726. {
  2727. }
  2728. virtual bool atEOF() const
  2729. {
  2730. return datalen==pos;
  2731. }
  2732. virtual bool isSerialized() const
  2733. {
  2734. // NOTE: tempting to think that we could avoid serializing in localAgent case, but have to be careful about the lifespan of the rowManager...
  2735. return true;
  2736. }
  2737. virtual const void * getNext(int length)
  2738. {
  2739. if (pos==datalen)
  2740. return NULL;
  2741. assertex(pos + length <= datalen);
  2742. void * cur = ((char *) data) + pos;
  2743. pos += length;
  2744. void * ret = rowManager->allocate(length, 0);
  2745. memcpy(ret, cur, length);
  2746. //No need for finalize since only contains plain data.
  2747. return ret;
  2748. }
  2749. };
  2750. class CLocalMessageResult : implements IMessageResult, public CInterface
  2751. {
  2752. void *data;
  2753. void *meta;
  2754. void *header;
  2755. unsigned datalen, metalen, headerlen;
  2756. unsigned pos;
  2757. public:
  2758. IMPLEMENT_IINTERFACE;
  2759. CLocalMessageResult(void *_data, unsigned _datalen, void *_meta, unsigned _metalen, void *_header, unsigned _headerlen)
  2760. {
  2761. datalen = _datalen;
  2762. metalen = _metalen;
  2763. headerlen = _headerlen;
  2764. data = _data;
  2765. meta = _meta;
  2766. header = _header;
  2767. pos = 0;
  2768. }
  2769. ~CLocalMessageResult()
  2770. {
  2771. free(data);
  2772. free(meta);
  2773. free(header);
  2774. }
  2775. virtual IMessageUnpackCursor *getCursor(IRowManager *rowMgr) const
  2776. {
  2777. return new CLocalMessageUnpackCursor(rowMgr, data, datalen);
  2778. }
  2779. virtual const void *getMessageHeader(unsigned &length) const
  2780. {
  2781. length = headerlen;
  2782. return header;
  2783. }
  2784. virtual const void *getMessageMetadata(unsigned &length) const
  2785. {
  2786. length = metalen;
  2787. return meta;
  2788. }
  2789. virtual void discard() const
  2790. {
  2791. }
  2792. };
  2793. class CLocalMessageCollator : implements ILocalMessageCollator, public CInterface
  2794. {
  2795. InterruptableSemaphore sem;
  2796. QueueOf<IMessageResult, false> pending;
  2797. CriticalSection crit;
  2798. Linked<IRowManager> rowManager; // Linked to ensure it lives longer than me
  2799. Linked<ILocalReceiveManager> receiveManager;
  2800. ruid_t id;
  2801. unsigned totalBytesReceived;
  2802. public:
  2803. IMPLEMENT_IINTERFACE;
  2804. CLocalMessageCollator(IRowManager *_rowManager, ruid_t _ruid);
  2805. ~CLocalMessageCollator();
  2806. virtual ruid_t queryRUID() const
  2807. {
  2808. return id;
  2809. }
  2810. virtual IMessageResult* getNextResult(unsigned time_out, bool &anyActivity)
  2811. {
  2812. anyActivity = false;
  2813. if (!sem.wait(time_out))
  2814. return NULL;
  2815. anyActivity = true;
  2816. CriticalBlock c(crit);
  2817. return pending.dequeue();
  2818. }
  2819. virtual void interrupt(IException *E)
  2820. {
  2821. sem.interrupt(E);
  2822. }
  2823. virtual void enqueueMessage(bool outOfBand, void *data, unsigned datalen, void *meta, unsigned metalen, void *header, unsigned headerlen)
  2824. {
  2825. CriticalBlock c(crit);
  2826. if (outOfBand)
  2827. pending.enqueueHead(new CLocalMessageResult(data, datalen, meta, metalen, header, headerlen));
  2828. else
  2829. pending.enqueue(new CLocalMessageResult(data, datalen, meta, metalen, header, headerlen));
  2830. sem.signal();
  2831. totalBytesReceived += datalen + metalen + headerlen;
  2832. }
  2833. virtual unsigned queryBytesReceived() const
  2834. {
  2835. return totalBytesReceived;
  2836. }
  2837. virtual unsigned queryDuplicates() const
  2838. {
  2839. return 0;
  2840. }
  2841. virtual unsigned queryResends() const
  2842. {
  2843. return 0;
  2844. }
  2845. };
  2846. class RoxieLocalReceiveManager : implements ILocalReceiveManager, public CInterface
  2847. {
  2848. MapXToMyClass<ruid_t, ruid_t, ILocalMessageCollator> collators;
  2849. CriticalSection crit;
  2850. Owned<StringContextLogger> logctx;
  2851. public:
  2852. IMPLEMENT_IINTERFACE;
  2853. RoxieLocalReceiveManager() : logctx(new StringContextLogger("RoxieLocalReceiveManager"))
  2854. {
  2855. }
  2856. virtual IMessageCollator *createMessageCollator(IRowManager *manager, ruid_t ruid)
  2857. {
  2858. ILocalMessageCollator *collator = new CLocalMessageCollator(manager, ruid);
  2859. CriticalBlock b(crit);
  2860. collators.setValue(ruid, collator);
  2861. return collator;
  2862. }
  2863. virtual void detachCollator(const IMessageCollator *collator)
  2864. {
  2865. ruid_t id = collator->queryRUID();
  2866. CriticalBlock b(crit);
  2867. collators.setValue(id, NULL);
  2868. }
  2869. virtual ILocalMessageCollator *lookupCollator(ruid_t id)
  2870. {
  2871. CriticalBlock b(crit);
  2872. ILocalMessageCollator *ret = collators.getValue(id);
  2873. if (!ret)
  2874. ret = collators.getValue(RUID_DISCARD);
  2875. return LINK(ret);
  2876. }
  2877. };
  2878. void LocalMessagePacker::flush()
  2879. {
  2880. // MORE - I think this means we don't send anything until whole message available in localAgent mode, which
  2881. // may not be optimal.
  2882. data.setLength(lastput);
  2883. Owned<ILocalMessageCollator> collator = rm->lookupCollator(id);
  2884. if (collator)
  2885. {
  2886. unsigned datalen = data.length();
  2887. unsigned metalen = meta.length();
  2888. unsigned headerlen = header.length();
  2889. collator->enqueueMessage(outOfBand, data.detach(), datalen, meta.detach(), metalen, header.detach(), headerlen);
  2890. }
  2891. // otherwise Roxie server is no longer interested and we can simply discard
  2892. }
  2893. CLocalMessageCollator::CLocalMessageCollator(IRowManager *_rowManager, ruid_t _ruid)
  2894. : rowManager(_rowManager), id(_ruid)
  2895. {
  2896. totalBytesReceived = 0;
  2897. }
  2898. CLocalMessageCollator::~CLocalMessageCollator()
  2899. {
  2900. IMessageResult *goer;
  2901. for (;;)
  2902. {
  2903. goer = pending.dequeue();
  2904. if (!goer)
  2905. break;
  2906. goer->Release();
  2907. }
  2908. }
  2909. class RoxieLocalQueueManager : public RoxieReceiverBase
  2910. {
  2911. Linked<RoxieLocalReceiveManager> receiveManager;
  2912. public:
  2913. RoxieLocalQueueManager(unsigned _numWorkers) : RoxieReceiverBase(_numWorkers)
  2914. {
  2915. receiveManager.setown(new RoxieLocalReceiveManager);
  2916. }
  2917. virtual void sendPacket(IRoxieQueryPacket *packet, const IRoxieContextLogger &logctx) override
  2918. {
  2919. RoxiePacketHeader &header = packet->queryHeader();
  2920. unsigned retries = header.thisChannelRetries(0);
  2921. if (header.activityId == ROXIE_FILECALLBACK || header.activityId == ROXIE_DEBUGCALLBACK )
  2922. {
  2923. if (traceLevel > 5)
  2924. {
  2925. StringBuffer s;
  2926. DBGLOG("ROXIE_CALLBACK %s", header.toString(s).str());
  2927. }
  2928. // MORE - do we need to encrypt these?
  2929. doFileCallback(packet);
  2930. }
  2931. else if (retries < SUBCHANNEL_MASK)
  2932. {
  2933. if (retries)
  2934. {
  2935. // Send back an out-of-band immediately, to let Roxie server know that channel is still active
  2936. RoxiePacketHeader newHeader(header, ROXIE_ALIVE, 0);
  2937. Owned<IMessagePacker> output = createOutputStream(newHeader, true, logctx);
  2938. output->flush();
  2939. return; // No point sending the retry in localAgent mode
  2940. }
  2941. RoxieQueue *targetQueue;
  2942. if (header.activityId & ROXIE_SLA_PRIORITY)
  2943. targetQueue = &slaQueue;
  2944. else if (header.activityId & ROXIE_HIGH_PRIORITY)
  2945. targetQueue = &hiQueue;
  2946. else
  2947. targetQueue = &loQueue;
  2948. Owned<ISerializedRoxieQueryPacket> serialized = packet->serialize();
  2949. if (header.channel)
  2950. {
  2951. targetQueue->enqueue(serialized.getClear());
  2952. }
  2953. else
  2954. {
  2955. // Turn broadcast packet (channel 0), as early as possible, into non-0 channel packets.
  2956. // So retries and other communication with Roxie server (which uses non-0 channel numbers) will not cause double work or confusion.
  2957. for (unsigned i = 1; i < numChannels; i++)
  2958. targetQueue->enqueue(serialized->cloneSerializedPacket(i+1));
  2959. header.channel = 1;
  2960. targetQueue->enqueue(serialized.getClear());
  2961. }
  2962. }
  2963. }
  2964. virtual void sendIbyti(RoxiePacketHeader &header, const IRoxieContextLogger &logctx, unsigned subChannel) override
  2965. {
  2966. // Don't do IBYTI's when local agent - no buddy to talk to anyway
  2967. }
  2968. virtual void sendAbort(RoxiePacketHeader &header, const IRoxieContextLogger &logctx) override
  2969. {
  2970. MTIME_SECTION(queryActiveTimer(), "RoxieLocalQueueManager::sendAbort");
  2971. RoxiePacketHeader abortHeader(header, header.activityId & ROXIE_PRIORITY_MASK, 0);
  2972. abortHeader.retries = QUERY_ABORTED;
  2973. if (logctx.queryTraceLevel() > 8)
  2974. {
  2975. StringBuffer s; logctx.CTXLOG("Sending ABORT packet %s", abortHeader.toString(s).str());
  2976. }
  2977. MemoryBuffer data;
  2978. data.append(sizeof(abortHeader), &abortHeader);
  2979. Owned<IRoxieQueryPacket> packet = createRoxiePacket(data);
  2980. sendPacket(packet, logctx);
  2981. abortsSent++;
  2982. }
  2983. virtual void sendAbortCallback(const RoxiePacketHeader &header, const char *lfn, const IRoxieContextLogger &logctx) override
  2984. {
  2985. MTIME_SECTION(queryActiveTimer(), "RoxieLocalQueueManager::sendAbortCallback");
  2986. RoxiePacketHeader abortHeader(header, ROXIE_FILECALLBACK, 0);
  2987. abortHeader.retries = QUERY_ABORTED;
  2988. MemoryBuffer data;
  2989. data.append(sizeof(abortHeader), &abortHeader).append(lfn);
  2990. if (logctx.queryTraceLevel() > 5)
  2991. {
  2992. StringBuffer s; logctx.CTXLOG("Sending ABORT FILECALLBACK packet %s for file %s", abortHeader.toString(s).str(), lfn);
  2993. }
  2994. Owned<IRoxieQueryPacket> packet = createRoxiePacket(data);
  2995. sendPacket(packet, logctx);
  2996. abortsSent++;
  2997. }
  2998. virtual IMessagePacker *createOutputStream(RoxiePacketHeader &header, bool outOfBand, const IRoxieContextLogger &logctx) override
  2999. {
  3000. return new LocalMessagePacker(header, outOfBand, receiveManager);
  3001. }
  3002. virtual IReceiveManager *queryReceiveManager() override
  3003. {
  3004. return receiveManager;
  3005. }
  3006. virtual bool replyPending(RoxiePacketHeader &header) override
  3007. {
  3008. // MORE - should really have some code here! But returning true is a reasonable approximation.
  3009. return true;
  3010. }
  3011. virtual bool abortCompleted(RoxiePacketHeader &header) override
  3012. {
  3013. // MORE - should really have some code here!
  3014. return false;
  3015. }
  3016. virtual void abortPendingData(const SocketEndpoint &ep) override
  3017. {
  3018. // Shouldn't ever happen, I think
  3019. }
  3020. };
  3021. extern IRoxieOutputQueueManager *createOutputQueueManager(unsigned numWorkers, bool encrypted)
  3022. {
  3023. if (localAgent)
  3024. return new RoxieLocalQueueManager(numWorkers);
  3025. else if (useAeron)
  3026. return new RoxieAeronSocketQueueManager(numWorkers, encrypted);
  3027. else
  3028. return new RoxieUdpSocketQueueManager(numWorkers, encrypted);
  3029. }
  3030. //================================================================================================================================
  3031. class PacketDiscarder : public Thread, implements IPacketDiscarder
  3032. {
  3033. bool aborted;
  3034. Owned<IRowManager> rowManager; // not completely sure I need one... maybe I do
  3035. Owned<IMessageCollator> mc;
  3036. public:
  3037. IMPLEMENT_IINTERFACE;
  3038. PacketDiscarder()
  3039. {
  3040. aborted = false;
  3041. };
  3042. ~PacketDiscarder()
  3043. {
  3044. if (mc)
  3045. ROQ->queryReceiveManager()->detachCollator(mc);
  3046. mc.clear();
  3047. }
  3048. virtual int run()
  3049. {
  3050. Owned<StringContextLogger> logctx = new StringContextLogger("PacketDiscarder");
  3051. rowManager.setown(roxiemem::createRowManager(0, NULL, *logctx, NULL, false));
  3052. mc.setown(ROQ->queryReceiveManager()->createMessageCollator(rowManager, RUID_DISCARD));
  3053. try
  3054. {
  3055. while (!aborted)
  3056. {
  3057. bool anyActivity = false;
  3058. Owned<IMessageResult> mr = mc->getNextResult(5000, anyActivity);
  3059. if (mr)
  3060. {
  3061. if (traceLevel > 4)
  3062. DBGLOG("Discarding unwanted message");
  3063. unsigned headerLen;
  3064. const RoxiePacketHeader &header = *(const RoxiePacketHeader *) mr->getMessageHeader(headerLen);
  3065. if (headerLen)
  3066. {
  3067. switch (header.activityId)
  3068. {
  3069. case ROXIE_FILECALLBACK:
  3070. {
  3071. Owned<IMessageUnpackCursor> callbackData = mr->getCursor(rowManager);
  3072. OwnedConstRoxieRow len = callbackData->getNext(sizeof(RecordLengthType));
  3073. if (len)
  3074. {
  3075. RecordLengthType *rowlen = (RecordLengthType *) len.get();
  3076. OwnedConstRoxieRow row = callbackData->getNext(*rowlen);
  3077. const char *rowdata = (const char *) row.get();
  3078. // bool isOpt = * (bool *) rowdata;
  3079. // bool isLocal = * (bool *) (rowdata+1);
  3080. ROQ->sendAbortCallback(header, rowdata+2, *logctx);
  3081. }
  3082. else
  3083. DBGLOG("Unrecognized format in discarded file callback");
  3084. break;
  3085. }
  3086. // 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)
  3087. }
  3088. }
  3089. else
  3090. DBGLOG("Unwanted message had no header?!");
  3091. }
  3092. else if (!anyActivity)
  3093. {
  3094. // to avoid leaking partial unwanted packets, we clear out mc periodically...
  3095. ROQ->queryReceiveManager()->detachCollator(mc);
  3096. mc.setown(ROQ->queryReceiveManager()->createMessageCollator(rowManager, RUID_DISCARD));
  3097. }
  3098. }
  3099. }
  3100. catch (IException * E)
  3101. {
  3102. if (!aborted || QUERYINTERFACE(E, InterruptedSemaphoreException) == NULL)
  3103. EXCLOG(E);
  3104. ::Release(E);
  3105. }
  3106. return 0;
  3107. }
  3108. virtual void start()
  3109. {
  3110. Thread::start();
  3111. }
  3112. virtual void stop()
  3113. {
  3114. if (mc)
  3115. mc->interrupt();
  3116. aborted = true;
  3117. join();
  3118. }
  3119. };
  3120. IPacketDiscarder *createPacketDiscarder()
  3121. {
  3122. IPacketDiscarder *packetDiscarder = new PacketDiscarder;
  3123. packetDiscarder->start();
  3124. return packetDiscarder;
  3125. }
  3126. //================================================================================================================================
  3127. // There are various possibly interesting ways to reply to a ping:
  3128. // Reply as soon as receive, or put it on the queue like other messages?
  3129. // Reply for every channel, or just once for every agent?
  3130. // Should I send on channel 0 or round-robin the channels?
  3131. // My gut feeling is that knowing what channels are responding is useful so should reply on every unsuspended channel,
  3132. // 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)
  3133. unsigned pingInterval = 60;
  3134. class PingTimer : public Thread
  3135. {
  3136. bool aborted;
  3137. Owned<IRowManager> rowManager;
  3138. Owned<IMessageCollator> mc;
  3139. StringContextLogger logctx;
  3140. void sendPing(unsigned priorityMask)
  3141. {
  3142. try
  3143. {
  3144. RemoteActivityId pingId(ROXIE_PING | priorityMask, 0);
  3145. RoxiePacketHeader header(pingId, 0, 0, 0);
  3146. MemoryBuffer mb;
  3147. mb.append(sizeof(RoxiePacketHeader), &header);
  3148. mb.append((char) LOGGING_FLAGSPRESENT);
  3149. mb.append("PING");
  3150. PingRecord data;
  3151. data.senderIP.ipset(myNode.getIpAddress());
  3152. data.tick = usTick();
  3153. mb.append(sizeof(PingRecord), &data);
  3154. if (traceLevel > 1)
  3155. DBGLOG("PING sent");
  3156. Owned<IRoxieQueryPacket> packet = createRoxiePacket(mb);
  3157. ROQ->sendPacket(packet, logctx);
  3158. }
  3159. catch (IException *E)
  3160. {
  3161. EXCLOG(E);
  3162. E->Release();
  3163. }
  3164. }
  3165. public:
  3166. PingTimer() : logctx("PingTimer")
  3167. {
  3168. aborted = false;
  3169. };
  3170. ~PingTimer()
  3171. {
  3172. if (mc)
  3173. ROQ->queryReceiveManager()->detachCollator(mc);
  3174. mc.clear();
  3175. }
  3176. virtual int run()
  3177. {
  3178. rowManager.setown(roxiemem::createRowManager(1, NULL, queryDummyContextLogger(), NULL, false));
  3179. mc.setown(ROQ->queryReceiveManager()->createMessageCollator(rowManager, RUID_PING));
  3180. unsigned pingsReceived = 0;
  3181. unsigned pingsElapsed = 0;
  3182. sendPing(ROXIE_HIGH_PRIORITY);
  3183. while (!aborted)
  3184. {
  3185. bool anyActivity = false;
  3186. Owned<IMessageResult> mr = mc->getNextResult(pingInterval*1000, anyActivity);
  3187. if (mr)
  3188. {
  3189. unsigned headerLen;
  3190. const RoxiePacketHeader *header = (const RoxiePacketHeader *) mr->getMessageHeader(headerLen);
  3191. Owned<IMessageUnpackCursor> mu = mr->getCursor(rowManager);
  3192. PingRecord *answer = (PingRecord *) mu->getNext(sizeof(PingRecord));
  3193. if (answer && mu->atEOF() && headerLen==sizeof(RoxiePacketHeader))
  3194. {
  3195. unsigned elapsed = usTick() - answer->tick;
  3196. pingsReceived++;
  3197. pingsElapsed += elapsed;
  3198. if (traceLevel > 10)
  3199. DBGLOG("PING reply channel=%d, time %d", header->channel, elapsed); // DBGLOG is slower than the pings so be careful!
  3200. }
  3201. else
  3202. DBGLOG("PING reply, garbled result");
  3203. ReleaseRoxieRow(answer);
  3204. }
  3205. else if (!anyActivity)
  3206. {
  3207. if (!pingsReceived && roxieMulticastEnabled)
  3208. DBGLOG("PING: NO replies received! Please check multicast settings, and that your network supports multicast.");
  3209. else if (traceLevel)
  3210. DBGLOG("PING: %d replies received, average delay %uus", pingsReceived, pingsReceived ? pingsElapsed / pingsReceived : 0);
  3211. pingsReceived = 0;
  3212. pingsElapsed = 0;
  3213. sendPing(ROXIE_HIGH_PRIORITY); // MORE - we could think about alternating the priority or sending pings on high and low at the same time...
  3214. }
  3215. }
  3216. return 0;
  3217. }
  3218. void stop()
  3219. {
  3220. if (mc)
  3221. mc->interrupt();
  3222. aborted = true;
  3223. }
  3224. static CriticalSection crit;
  3225. } *pingTimer;
  3226. CriticalSection PingTimer::crit;
  3227. extern void startPingTimer()
  3228. {
  3229. CriticalBlock b(PingTimer::crit);
  3230. if (!pingTimer)
  3231. {
  3232. pingTimer = new PingTimer();
  3233. pingTimer->start();
  3234. }
  3235. }
  3236. extern void stopPingTimer()
  3237. {
  3238. CriticalBlock b(PingTimer::crit);
  3239. if (pingTimer)
  3240. {
  3241. pingTimer->stop();
  3242. pingTimer->join();
  3243. delete pingTimer;
  3244. pingTimer = NULL;
  3245. }
  3246. }