ccdserver.cpp 1.1 MB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578255792558025581255822558325584255852558625587255882558925590255912559225593255942559525596255972559825599256002560125602256032560425605256062560725608256092561025611256122561325614256152561625617256182561925620256212562225623256242562525626256272562825629256302563125632256332563425635256362563725638256392564025641256422564325644256452564625647256482564925650256512565225653256542565525656256572565825659256602566125662256632566425665256662566725668256692567025671256722567325674256752567625677256782567925680256812568225683256842568525686256872568825689256902569125692256932569425695256962569725698256992570025701257022570325704257052570625707257082570925710257112571225713257142571525716257172571825719257202572125722257232572425725257262572725728257292573025731257322573325734257352573625737257382573925740257412574225743257442574525746257472574825749257502575125752257532575425755257562575725758257592576025761257622576325764257652576625767257682576925770257712577225773257742577525776257772577825779257802578125782257832578425785257862578725788257892579025791257922579325794257952579625797257982579925800258012580225803258042580525806258072580825809258102581125812258132581425815258162581725818258192582025821258222582325824258252582625827258282582925830258312583225833258342583525836258372583825839258402584125842258432584425845258462584725848258492585025851258522585325854258552585625857258582585925860258612586225863258642586525866258672586825869258702587125872258732587425875258762587725878258792588025881258822588325884258852588625887258882588925890258912589225893258942589525896258972589825899259002590125902259032590425905259062590725908259092591025911259122591325914259152591625917259182591925920259212592225923259242592525926259272592825929259302593125932259332593425935259362593725938259392594025941259422594325944259452594625947259482594925950259512595225953259542595525956259572595825959259602596125962259632596425965259662596725968259692597025971259722597325974259752597625977259782597925980259812598225983259842598525986259872598825989259902599125992259932599425995259962599725998259992600026001260022600326004260052600626007260082600926010260112601226013260142601526016260172601826019260202602126022260232602426025260262602726028260292603026031260322603326034260352603626037260382603926040260412604226043260442604526046260472604826049260502605126052260532605426055260562605726058260592606026061260622606326064260652606626067260682606926070260712607226073260742607526076260772607826079260802608126082260832608426085260862608726088260892609026091260922609326094260952609626097260982609926100261012610226103261042610526106261072610826109261102611126112261132611426115261162611726118261192612026121261222612326124261252612626127261282612926130261312613226133261342613526136261372613826139261402614126142261432614426145261462614726148261492615026151261522615326154261552615626157261582615926160261612616226163261642616526166261672616826169261702617126172261732617426175261762617726178261792618026181261822618326184261852618626187261882618926190261912619226193261942619526196261972619826199262002620126202262032620426205262062620726208262092621026211262122621326214262152621626217262182621926220262212622226223262242622526226262272622826229262302623126232262332623426235262362623726238262392624026241262422624326244262452624626247262482624926250262512625226253262542625526256262572625826259262602626126262262632626426265262662626726268262692627026271262722627326274262752627626277262782627926280262812628226283262842628526286262872628826289262902629126292262932629426295262962629726298262992630026301263022630326304263052630626307263082630926310263112631226313263142631526316263172631826319263202632126322263232632426325263262632726328263292633026331263322633326334263352633626337263382633926340263412634226343263442634526346263472634826349263502635126352263532635426355263562635726358263592636026361263622636326364263652636626367263682636926370263712637226373263742637526376263772637826379263802638126382263832638426385263862638726388263892639026391263922639326394263952639626397263982639926400264012640226403264042640526406264072640826409264102641126412264132641426415264162641726418264192642026421264222642326424264252642626427264282642926430264312643226433264342643526436264372643826439264402644126442264432644426445264462644726448264492645026451264522645326454264552645626457264582645926460264612646226463264642646526466264672646826469264702647126472264732647426475264762647726478264792648026481264822648326484264852648626487264882648926490264912649226493264942649526496264972649826499265002650126502265032650426505265062650726508265092651026511265122651326514265152651626517265182651926520265212652226523265242652526526265272652826529265302653126532265332653426535265362653726538265392654026541265422654326544265452654626547265482654926550265512655226553265542655526556265572655826559265602656126562265632656426565265662656726568265692657026571265722657326574265752657626577265782657926580265812658226583265842658526586265872658826589265902659126592265932659426595265962659726598265992660026601266022660326604266052660626607266082660926610266112661226613266142661526616266172661826619266202662126622266232662426625266262662726628266292663026631266322663326634266352663626637266382663926640266412664226643266442664526646266472664826649266502665126652266532665426655266562665726658266592666026661266622666326664266652666626667266682666926670266712667226673266742667526676266772667826679266802668126682266832668426685266862668726688266892669026691266922669326694266952669626697266982669926700267012670226703267042670526706267072670826709267102671126712267132671426715267162671726718267192672026721267222672326724267252672626727267282672926730267312673226733267342673526736267372673826739267402674126742267432674426745267462674726748267492675026751267522675326754267552675626757267582675926760267612676226763267642676526766267672676826769267702677126772267732677426775267762677726778267792678026781267822678326784267852678626787267882678926790267912679226793267942679526796267972679826799268002680126802268032680426805268062680726808268092681026811268122681326814268152681626817268182681926820268212682226823268242682526826268272682826829268302683126832268332683426835268362683726838268392684026841268422684326844268452684626847268482684926850268512685226853268542685526856268572685826859268602686126862268632686426865268662686726868268692687026871268722687326874268752687626877268782687926880268812688226883268842688526886268872688826889268902689126892268932689426895268962689726898268992690026901269022690326904269052690626907269082690926910269112691226913269142691526916269172691826919269202692126922269232692426925269262692726928269292693026931269322693326934269352693626937269382693926940269412694226943269442694526946269472694826949269502695126952269532695426955269562695726958269592696026961269622696326964269652696626967269682696926970269712697226973269742697526976269772697826979269802698126982269832698426985269862698726988269892699026991269922699326994269952699626997269982699927000270012700227003270042700527006270072700827009270102701127012270132701427015270162701727018270192702027021270222702327024270252702627027270282702927030270312703227033270342703527036270372703827039270402704127042270432704427045270462704727048270492705027051270522705327054270552705627057270582705927060270612706227063270642706527066270672706827069270702707127072270732707427075270762707727078270792708027081270822708327084270852708627087270882708927090270912709227093270942709527096270972709827099271002710127102271032710427105271062710727108271092711027111271122711327114271152711627117271182711927120271212712227123271242712527126271272712827129271302713127132271332713427135271362713727138271392714027141271422714327144271452714627147271482714927150271512715227153271542715527156271572715827159271602716127162271632716427165271662716727168271692717027171271722717327174271752717627177271782717927180271812718227183271842718527186271872718827189271902719127192271932719427195271962719727198271992720027201272022720327204272052720627207272082720927210272112721227213272142721527216272172721827219272202722127222272232722427225272262722727228272292723027231272322723327234272352723627237272382723927240272412724227243272442724527246272472724827249272502725127252272532725427255272562725727258272592726027261272622726327264272652726627267272682726927270272712727227273272742727527276272772727827279272802728127282272832728427285272862728727288272892729027291272922729327294272952729627297272982729927300273012730227303273042730527306273072730827309273102731127312273132731427315273162731727318273192732027321273222732327324273252732627327273282732927330273312733227333273342733527336273372733827339273402734127342273432734427345273462734727348273492735027351273522735327354273552735627357273582735927360273612736227363273642736527366273672736827369273702737127372273732737427375273762737727378273792738027381273822738327384273852738627387273882738927390273912739227393273942739527396273972739827399274002740127402274032740427405274062740727408274092741027411274122741327414274152741627417274182741927420274212742227423274242742527426274272742827429274302743127432274332743427435274362743727438274392744027441274422744327444274452744627447274482744927450274512745227453274542745527456274572745827459274602746127462274632746427465274662746727468274692747027471274722747327474274752747627477274782747927480274812748227483274842748527486274872748827489274902749127492274932749427495274962749727498274992750027501275022750327504275052750627507275082750927510275112751227513275142751527516275172751827519275202752127522275232752427525275262752727528275292753027531275322753327534275352753627537275382753927540275412754227543275442754527546275472754827549275502755127552275532755427555275562755727558275592756027561275622756327564275652756627567275682756927570275712757227573275742757527576275772757827579275802758127582275832758427585275862758727588275892759027591275922759327594275952759627597275982759927600276012760227603276042760527606276072760827609276102761127612276132761427615276162761727618276192762027621276222762327624276252762627627276282762927630276312763227633276342763527636276372763827639276402764127642276432764427645276462764727648276492765027651276522765327654276552765627657276582765927660276612766227663276642766527666276672766827669276702767127672276732767427675276762767727678276792768027681276822768327684276852768627687276882768927690276912769227693276942769527696276972769827699277002770127702277032770427705277062770727708277092771027711277122771327714277152771627717277182771927720277212772227723277242772527726277272772827729277302773127732277332773427735277362773727738277392774027741277422774327744277452774627747277482774927750277512775227753277542775527756277572775827759277602776127762277632776427765277662776727768277692777027771277722777327774277752777627777277782777927780277812778227783277842778527786277872778827789277902779127792277932779427795277962779727798277992780027801278022780327804278052780627807278082780927810278112781227813278142781527816278172781827819278202782127822278232782427825278262782727828278292783027831278322783327834278352783627837278382783927840278412784227843278442784527846278472784827849278502785127852278532785427855278562785727858278592786027861278622786327864278652786627867278682786927870278712787227873278742787527876278772787827879278802788127882278832788427885278862788727888278892789027891278922789327894278952789627897278982789927900279012790227903279042790527906279072790827909279102791127912279132791427915279162791727918279192792027921279222792327924279252792627927279282792927930279312793227933279342793527936279372793827939279402794127942279432794427945279462794727948279492795027951279522795327954279552795627957279582795927960279612796227963279642796527966279672796827969279702797127972279732797427975279762797727978279792798027981279822798327984279852798627987279882798927990279912799227993279942799527996279972799827999280002800128002280032800428005280062800728008280092801028011280122801328014280152801628017280182801928020280212802228023280242802528026280272802828029280302803128032280332803428035280362803728038280392804028041280422804328044280452804628047280482804928050280512805228053280542805528056280572805828059280602806128062280632806428065280662806728068280692807028071280722807328074280752807628077280782807928080280812808228083280842808528086280872808828089280902809128092280932809428095280962809728098280992810028101281022810328104281052810628107281082810928110281112811228113281142811528116281172811828119281202812128122281232812428125281262812728128281292813028131281322813328134281352813628137281382813928140281412814228143281442814528146281472814828149281502815128152281532815428155281562815728158281592816028161281622816328164281652816628167281682816928170281712817228173281742817528176281772817828179281802818128182281832818428185281862818728188281892819028191281922819328194281952819628197281982819928200282012820228203282042820528206282072820828209282102821128212282132821428215282162821728218282192822028221282222822328224282252822628227282282822928230282312823228233282342823528236282372823828239282402824128242282432824428245282462824728248282492825028251282522825328254282552825628257282582825928260282612826228263282642826528266282672826828269282702827128272282732827428275282762827728278282792828028281282822828328284282852828628287282882828928290282912829228293282942829528296282972829828299283002830128302283032830428305283062830728308283092831028311283122831328314283152831628317283182831928320283212832228323283242832528326283272832828329283302833128332283332833428335283362833728338283392834028341283422834328344283452834628347283482834928350283512835228353283542835528356283572835828359283602836128362283632836428365283662836728368283692837028371283722837328374283752837628377283782837928380283812838228383283842838528386283872838828389283902839128392283932839428395283962839728398283992840028401284022840328404284052840628407284082840928410284112841228413284142841528416284172841828419284202842128422284232842428425284262842728428284292843028431284322843328434284352843628437284382843928440284412844228443284442844528446284472844828449284502845128452284532845428455284562845728458284592846028461284622846328464284652846628467284682846928470284712847228473284742847528476284772847828479284802848128482284832848428485284862848728488284892849028491284922849328494284952849628497284982849928500285012850228503285042850528506285072850828509285102851128512285132851428515285162851728518285192852028521285222852328524285252852628527285282852928530285312853228533285342853528536285372853828539285402854128542285432854428545285462854728548285492855028551285522855328554285552855628557285582855928560285612856228563285642856528566285672856828569285702857128572285732857428575285762857728578285792858028581285822858328584285852858628587285882858928590285912859228593285942859528596285972859828599286002860128602286032860428605286062860728608286092861028611286122861328614286152861628617286182861928620286212862228623286242862528626286272862828629286302863128632286332863428635286362863728638286392864028641286422864328644286452864628647286482864928650286512865228653286542865528656286572865828659286602866128662286632866428665286662866728668286692867028671286722867328674286752867628677286782867928680286812868228683286842868528686286872868828689286902869128692286932869428695286962869728698286992870028701287022870328704287052870628707287082870928710287112871228713287142871528716287172871828719287202872128722287232872428725287262872728728287292873028731287322873328734287352873628737287382873928740287412874228743287442874528746287472874828749287502875128752287532875428755287562875728758287592876028761287622876328764287652876628767287682876928770287712877228773287742877528776287772877828779287802878128782287832878428785287862878728788287892879028791287922879328794287952879628797287982879928800288012880228803288042880528806288072880828809288102881128812288132881428815288162881728818288192882028821288222882328824288252882628827288282882928830288312883228833288342883528836288372883828839288402884128842288432884428845288462884728848288492885028851288522885328854288552885628857288582885928860288612886228863288642886528866288672886828869288702887128872288732887428875288762887728878288792888028881288822888328884288852888628887288882888928890288912889228893288942889528896288972889828899289002890128902289032890428905289062890728908289092891028911289122891328914289152891628917289182891928920289212892228923289242892528926289272892828929289302893128932289332893428935289362893728938289392894028941289422894328944289452894628947289482894928950289512895228953289542895528956289572895828959289602896128962289632896428965289662896728968289692897028971289722897328974289752897628977289782897928980289812898228983289842898528986289872898828989289902899128992289932899428995289962899728998289992900029001290022900329004290052900629007290082900929010290112901229013290142901529016290172901829019290202902129022290232902429025290262902729028290292903029031290322903329034290352903629037290382903929040290412904229043290442904529046290472904829049290502905129052290532905429055290562905729058290592906029061290622906329064290652906629067290682906929070290712907229073290742907529076290772907829079290802908129082290832908429085290862908729088290892909029091290922909329094290952909629097290982909929100291012910229103291042910529106291072910829109291102911129112291132911429115291162911729118291192912029121291222912329124291252912629127291282912929130291312913229133291342913529136291372913829139291402914129142291432914429145291462914729148291492915029151291522915329154291552915629157291582915929160291612916229163291642916529166291672916829169291702917129172291732917429175291762917729178291792918029181291822918329184291852918629187291882918929190291912919229193291942919529196291972919829199292002920129202292032920429205292062920729208292092921029211292122921329214292152921629217292182921929220292212922229223292242922529226292272922829229292302923129232292332923429235292362923729238292392924029241292422924329244292452924629247292482924929250292512925229253292542925529256292572925829259292602926129262292632926429265292662926729268292692927029271292722927329274292752927629277292782927929280292812928229283292842928529286292872928829289292902929129292292932929429295292962929729298292992930029301293022930329304293052930629307293082930929310293112931229313293142931529316293172931829319293202932129322293232932429325293262932729328293292933029331293322933329334293352933629337293382933929340293412934229343293442934529346293472934829349293502935129352293532935429355293562935729358293592936029361293622936329364293652936629367293682936929370293712937229373293742937529376293772937829379293802938129382293832938429385293862938729388293892939029391293922939329394293952939629397293982939929400294012940229403294042940529406294072940829409294102941129412294132941429415294162941729418294192942029421294222942329424294252942629427294282942929430294312943229433294342943529436294372943829439294402944129442294432944429445294462944729448294492945029451294522945329454294552945629457294582945929460294612946229463294642946529466294672946829469294702947129472294732947429475294762947729478294792948029481294822948329484294852948629487294882948929490294912949229493294942949529496294972949829499295002950129502295032950429505295062950729508295092951029511295122951329514295152951629517295182951929520295212952229523295242952529526295272952829529295302953129532295332953429535295362953729538295392954029541295422954329544295452954629547295482954929550295512955229553295542955529556295572955829559295602956129562295632956429565295662956729568295692957029571295722957329574295752957629577295782957929580295812958229583295842958529586295872958829589295902959129592295932959429595295962959729598295992960029601296022960329604296052960629607296082960929610296112961229613296142961529616296172961829619296202962129622296232962429625296262962729628296292963029631296322963329634296352963629637296382963929640296412964229643296442964529646296472964829649296502965129652296532965429655296562965729658296592966029661296622966329664296652966629667296682966929670296712967229673296742967529676296772967829679296802968129682296832968429685296862968729688296892969029691296922969329694296952969629697296982969929700297012970229703297042970529706297072970829709297102971129712297132971429715297162971729718297192972029721297222972329724297252972629727297282972929730297312973229733297342973529736297372973829739297402974129742297432974429745297462974729748297492975029751297522975329754297552975629757297582975929760297612976229763297642976529766297672976829769297702977129772297732977429775297762977729778297792978029781297822978329784297852978629787297882978929790297912979229793297942979529796297972979829799298002980129802298032980429805298062980729808298092981029811298122981329814298152981629817298182981929820298212982229823298242982529826298272982829829298302983129832298332983429835298362983729838298392984029841298422984329844298452984629847298482984929850298512985229853298542985529856298572985829859298602986129862298632986429865298662986729868298692987029871298722987329874298752987629877298782987929880298812988229883298842988529886298872988829889298902989129892298932989429895298962989729898298992990029901299022990329904299052990629907299082990929910299112991229913299142991529916299172991829919299202992129922299232992429925299262992729928299292993029931299322993329934299352993629937299382993929940299412994229943299442994529946299472994829949299502995129952299532995429955299562995729958299592996029961299622996329964299652996629967299682996929970299712997229973299742997529976299772997829979299802998129982299832998429985299862998729988299892999029991299922999329994299952999629997299982999930000300013000230003300043000530006300073000830009300103001130012300133001430015300163001730018300193002030021300223002330024300253002630027300283002930030300313003230033300343003530036300373003830039300403004130042300433004430045300463004730048300493005030051300523005330054300553005630057300583005930060300613006230063300643006530066300673006830069300703007130072300733007430075300763007730078300793008030081300823008330084300853008630087300883008930090300913009230093300943009530096300973009830099301003010130102301033010430105301063010730108301093011030111301123011330114301153011630117301183011930120301213012230123301243012530126301273012830129301303013130132301333013430135301363013730138301393014030141301423014330144301453014630147301483014930150301513015230153301543015530156301573015830159301603016130162301633016430165301663016730168301693017030171301723017330174301753017630177301783017930180301813018230183301843018530186301873018830189301903019130192301933019430195301963019730198301993020030201302023020330204302053020630207302083020930210302113021230213302143021530216302173021830219302203022130222302233022430225302263022730228302293023030231302323023330234302353023630237302383023930240302413024230243302443024530246302473024830249302503025130252302533025430255302563025730258302593026030261302623026330264302653026630267302683026930270302713027230273302743027530276302773027830279302803028130282302833028430285302863028730288302893029030291302923029330294302953029630297302983029930300303013030230303303043030530306303073030830309303103031130312303133031430315303163031730318303193032030321303223032330324303253032630327303283032930330303313033230333303343033530336303373033830339303403034130342303433034430345303463034730348303493035030351303523035330354303553035630357303583035930360303613036230363303643036530366303673036830369303703037130372303733037430375303763037730378303793038030381303823038330384303853038630387303883038930390303913039230393303943039530396303973039830399304003040130402304033040430405304063040730408304093041030411304123041330414304153041630417304183041930420304213042230423304243042530426304273042830429304303043130432304333043430435304363043730438304393044030441304423044330444304453044630447304483044930450304513045230453304543045530456304573045830459304603046130462304633046430465304663046730468304693047030471304723047330474304753047630477304783047930480304813048230483304843048530486304873048830489304903049130492304933049430495304963049730498304993050030501305023050330504305053050630507305083050930510305113051230513305143051530516305173051830519305203052130522305233052430525305263052730528305293053030531305323053330534305353053630537305383053930540305413054230543305443054530546305473054830549305503055130552305533055430555305563055730558305593056030561305623056330564305653056630567305683056930570305713057230573305743057530576305773057830579305803058130582305833058430585305863058730588305893059030591305923059330594305953059630597305983059930600306013060230603306043060530606306073060830609306103061130612306133061430615306163061730618306193062030621306223062330624306253062630627306283062930630306313063230633306343063530636306373063830639306403064130642306433064430645306463064730648306493065030651306523065330654306553065630657306583065930660306613066230663306643066530666306673066830669306703067130672306733067430675306763067730678306793068030681306823068330684306853068630687306883068930690306913069230693306943069530696306973069830699307003070130702307033070430705307063070730708307093071030711307123071330714307153071630717307183071930720307213072230723307243072530726307273072830729307303073130732307333073430735307363073730738307393074030741307423074330744307453074630747307483074930750307513075230753307543075530756307573075830759307603076130762307633076430765307663076730768307693077030771307723077330774307753077630777307783077930780307813078230783307843078530786307873078830789307903079130792307933079430795307963079730798307993080030801308023080330804308053080630807308083080930810308113081230813308143081530816308173081830819308203082130822308233082430825308263082730828308293083030831308323083330834308353083630837308383083930840308413084230843308443084530846308473084830849308503085130852308533085430855308563085730858308593086030861308623086330864308653086630867308683086930870308713087230873308743087530876308773087830879308803088130882308833088430885308863088730888308893089030891308923089330894308953089630897308983089930900309013090230903309043090530906309073090830909309103091130912309133091430915309163091730918309193092030921309223092330924309253092630927309283092930930309313093230933309343093530936309373093830939309403094130942309433094430945309463094730948309493095030951309523095330954309553095630957309583095930960309613096230963309643096530966309673096830969309703097130972309733097430975309763097730978309793098030981309823098330984309853098630987309883098930990309913099230993309943099530996309973099830999310003100131002310033100431005310063100731008310093101031011310123101331014310153101631017310183101931020310213102231023310243102531026310273102831029310303103131032310333103431035310363103731038310393104031041310423104331044310453104631047310483104931050310513105231053310543105531056310573105831059310603106131062310633106431065310663106731068310693107031071310723107331074310753107631077310783107931080310813108231083310843108531086310873108831089310903109131092310933109431095310963109731098310993110031101311023110331104311053110631107311083110931110311113111231113311143111531116311173111831119311203112131122311233112431125311263112731128311293113031131311323113331134311353113631137311383113931140311413114231143311443114531146311473114831149311503115131152311533115431155311563115731158311593116031161311623116331164311653116631167311683116931170311713117231173311743117531176311773117831179311803118131182311833118431185311863118731188311893119031191311923119331194311953119631197311983119931200312013120231203312043120531206312073120831209312103121131212312133121431215312163121731218312193122031221312223122331224312253122631227312283122931230312313123231233312343123531236312373123831239312403124131242312433124431245312463124731248312493125031251312523125331254312553125631257312583125931260312613126231263312643126531266312673126831269312703127131272312733127431275312763127731278312793128031281312823128331284312853128631287312883128931290312913129231293312943129531296312973129831299313003130131302313033130431305313063130731308313093131031311313123131331314313153131631317313183131931320313213132231323313243132531326313273132831329313303133131332313333133431335313363133731338313393134031341313423134331344313453134631347313483134931350313513135231353313543135531356313573135831359313603136131362313633136431365313663136731368313693137031371313723137331374313753137631377313783137931380313813138231383313843138531386313873138831389313903139131392313933139431395313963139731398313993140031401314023140331404314053140631407314083140931410314113141231413314143141531416314173141831419314203142131422314233142431425314263142731428314293143031431314323143331434314353143631437314383143931440314413144231443314443144531446314473144831449314503145131452314533145431455314563145731458314593146031461314623146331464314653146631467314683146931470314713147231473314743147531476314773147831479314803148131482314833148431485314863148731488314893149031491314923149331494314953149631497314983149931500315013150231503315043150531506315073150831509315103151131512315133151431515315163151731518315193152031521315223152331524315253152631527315283152931530315313153231533315343153531536315373153831539315403154131542315433154431545315463154731548315493155031551315523155331554315553155631557315583155931560315613156231563315643156531566315673156831569315703157131572315733157431575315763157731578315793158031581315823158331584315853158631587315883158931590315913159231593315943159531596315973159831599316003160131602316033160431605316063160731608316093161031611316123161331614316153161631617316183161931620316213162231623316243162531626316273162831629316303163131632316333163431635316363163731638316393164031641316423164331644316453164631647316483164931650316513165231653316543165531656316573165831659316603166131662316633166431665316663166731668316693167031671316723167331674316753167631677316783167931680316813168231683316843168531686316873168831689316903169131692316933169431695316963169731698316993170031701317023170331704317053170631707317083170931710317113171231713317143171531716317173171831719317203172131722317233172431725317263172731728317293173031731317323173331734317353173631737317383173931740317413174231743317443174531746317473174831749317503175131752317533175431755317563175731758317593176031761317623176331764317653176631767317683176931770317713177231773317743177531776317773177831779317803178131782317833178431785317863178731788317893179031791317923179331794317953179631797317983179931800318013180231803318043180531806318073180831809318103181131812318133181431815318163181731818318193182031821318223182331824318253182631827318283182931830318313183231833318343183531836318373183831839318403184131842318433184431845318463184731848318493185031851318523185331854318553185631857318583185931860318613186231863318643186531866318673186831869318703187131872318733187431875318763187731878318793188031881318823188331884318853188631887318883188931890318913189231893318943189531896318973189831899319003190131902319033190431905319063190731908319093191031911319123191331914319153191631917319183191931920319213192231923319243192531926319273192831929319303193131932319333193431935319363193731938319393194031941319423194331944319453194631947319483194931950319513195231953319543195531956319573195831959319603196131962319633196431965319663196731968319693197031971319723197331974319753197631977319783197931980319813198231983319843198531986319873198831989319903199131992319933199431995319963199731998319993200032001320023200332004320053200632007320083200932010320113201232013320143201532016320173201832019320203202132022320233202432025320263202732028320293203032031320323203332034320353203632037320383203932040320413204232043320443204532046320473204832049320503205132052320533205432055320563205732058320593206032061320623206332064320653206632067320683206932070320713207232073320743207532076320773207832079320803208132082320833208432085320863208732088320893209032091320923209332094320953209632097320983209932100321013210232103321043210532106321073210832109321103211132112321133211432115321163211732118321193212032121321223212332124321253212632127321283212932130321313213232133321343213532136321373213832139321403214132142321433214432145321463214732148321493215032151321523215332154321553215632157321583215932160321613216232163321643216532166321673216832169321703217132172321733217432175321763217732178321793218032181321823218332184321853218632187321883218932190321913219232193321943219532196321973219832199322003220132202322033220432205322063220732208322093221032211322123221332214322153221632217322183221932220322213222232223322243222532226322273222832229322303223132232322333223432235322363223732238322393224032241322423224332244322453224632247322483224932250322513225232253322543225532256322573225832259322603226132262322633226432265322663226732268322693227032271322723227332274322753227632277322783227932280322813228232283322843228532286322873228832289322903229132292322933229432295322963229732298322993230032301323023230332304323053230632307323083230932310323113231232313323143231532316323173231832319323203232132322323233232432325323263232732328323293233032331323323233332334323353233632337323383233932340323413234232343323443234532346323473234832349323503235132352323533235432355323563235732358323593236032361323623236332364323653236632367323683236932370323713237232373323743237532376323773237832379323803238132382323833238432385323863238732388323893239032391323923239332394323953239632397323983239932400324013240232403324043240532406324073240832409324103241132412324133241432415324163241732418324193242032421324223242332424324253242632427324283242932430324313243232433324343243532436324373243832439324403244132442324433244432445324463244732448324493245032451324523245332454324553245632457324583245932460324613246232463324643246532466324673246832469324703247132472324733247432475324763247732478324793248032481324823248332484324853248632487324883248932490324913249232493324943249532496324973249832499325003250132502325033250432505325063250732508325093251032511325123251332514325153251632517325183251932520325213252232523325243252532526325273252832529325303253132532325333253432535325363253732538325393254032541325423254332544325453254632547325483254932550325513255232553325543255532556325573255832559325603256132562325633256432565325663256732568325693257032571325723257332574325753257632577325783257932580325813258232583325843258532586325873258832589325903259132592325933259432595325963259732598325993260032601326023260332604326053260632607326083260932610326113261232613326143261532616326173261832619326203262132622326233262432625326263262732628326293263032631326323263332634326353263632637326383263932640326413264232643326443264532646326473264832649326503265132652326533265432655326563265732658326593266032661
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. #include "jmisc.hpp"
  15. #include "jdebug.hpp"
  16. #include "jptree.hpp"
  17. #include "rtlkey.hpp"
  18. #include "jsort.hpp"
  19. #include "jhtree.hpp"
  20. #include "jqueue.tpp"
  21. #include "jisem.hpp"
  22. #include "thorxmlread.hpp"
  23. #include "thorrparse.ipp"
  24. #include "thorxmlwrite.hpp"
  25. #include "thorsoapcall.hpp"
  26. #include "thorcommon.ipp"
  27. #include "jlzw.hpp"
  28. #include "jregexp.hpp"
  29. #include "javahash.hpp"
  30. #include "javahash.tpp"
  31. #include "thorstep.ipp"
  32. #include "thorpipe.hpp"
  33. #include "thorfile.hpp"
  34. #include "eclhelper.hpp"
  35. #include "eclrtl_imp.hpp"
  36. #include "rtlfield_imp.hpp"
  37. #include "rtlds_imp.hpp"
  38. #include "rtlread_imp.hpp"
  39. #include "dafdesc.hpp"
  40. #include "dautils.hpp"
  41. #include "wujobq.hpp"
  42. namespace ccdserver_hqlhelper
  43. {
  44. #include "eclhelper_base.hpp"
  45. }
  46. #include "ccd.hpp"
  47. #include "ccdserver.hpp"
  48. #include "ccdactivities.hpp"
  49. #include "ccdquery.hpp"
  50. #include "ccdstate.hpp"
  51. #include "ccdqueue.ipp"
  52. #include "ccdsnmp.hpp"
  53. #include "ccddali.hpp"
  54. #include "jsmartsock.hpp"
  55. #include "dllserver.hpp"
  56. #include "workflow.hpp"
  57. #include "nbcd.hpp"
  58. #include "roxiemem.hpp"
  59. #include "roxierowbuff.hpp"
  60. #include "roxiehelper.hpp"
  61. #include "roxielmj.hpp"
  62. #include "roxierow.hpp"
  63. #include "thorplugin.hpp"
  64. #include "keybuild.hpp"
  65. #define MAX_HTTP_HEADERSIZE 8000
  66. #define MIN_PAYLOAD_SIZE 800
  67. #pragma warning(disable : 4355)
  68. #define DEFAULT_PARALLEL_LOOP_THREADS 1
  69. #define PROBE
  70. #ifdef _DEBUG
  71. //#define FAKE_EXCEPTIONS
  72. //#define TRACE_JOINGROUPS
  73. //#define TRACE_SPLIT
  74. //#define _CHECK_HEAPSORT
  75. //#undef PARALLEL_EXECUTE
  76. //#define TRACE_SEEK_REQUESTS
  77. #endif
  78. using roxiemem::OwnedRoxieRow;
  79. using roxiemem::OwnedConstRoxieRow;
  80. using roxiemem::IRowManager;
  81. // There is a bug in VC6 implemetation of protected which prevents nested classes from accessing owner's data. It can be tricky to work around - hence...
  82. #if _MSC_VER==1200
  83. #define protected public
  84. #endif
  85. #define TRACE_STARTSTOP // This determines if it is available - it is enabled/disabled by a configuration option
  86. static const SmartStepExtra dummySmartStepExtra(SSEFreadAhead, NULL);
  87. typedef IEclProcess* (* EclProcessFactory)();
  88. inline void ReleaseRoxieRowSet(ConstPointerArray &data)
  89. {
  90. ForEachItemIn(idx, data)
  91. ReleaseRoxieRow(data.item(idx));
  92. data.kill();
  93. }
  94. //=================================================================================
  95. class RestartableThread : public CInterface
  96. {
  97. class MyThread : public Thread
  98. {
  99. Linked<RestartableThread> owner;
  100. public:
  101. MyThread(RestartableThread *_owner, const char *name) : Thread(name), owner(_owner)
  102. {
  103. }
  104. virtual int run()
  105. {
  106. owner->started.signal();
  107. return owner->run();
  108. }
  109. };
  110. friend class MyThread;
  111. Semaphore started;
  112. Owned<MyThread> thread;
  113. CriticalSection crit;
  114. StringAttr name;
  115. public:
  116. RestartableThread(const char *_name) : name(_name)
  117. {
  118. }
  119. virtual void start(const char *namePrefix)
  120. {
  121. StringBuffer s(namePrefix);
  122. s.append(name);
  123. {
  124. CriticalBlock b(crit);
  125. assertex(!thread);
  126. thread.setown(new MyThread(this, s));
  127. thread->start();
  128. }
  129. started.wait();
  130. }
  131. virtual void join()
  132. {
  133. {
  134. Owned<Thread> tthread;
  135. {
  136. CriticalBlock b(crit);
  137. tthread.setown(thread.getClear());
  138. }
  139. if (tthread)
  140. tthread->join();
  141. }
  142. }
  143. virtual int run() = 0;
  144. };
  145. //================================================================================
  146. // default implementation - can be overridden for efficiency...
  147. bool IRoxieInput::nextGroup(ConstPointerArray & group)
  148. {
  149. const void * next;
  150. while ((next = nextInGroup()) != NULL)
  151. group.append(next);
  152. if (group.ordinality())
  153. return true;
  154. return false;
  155. }
  156. inline const void * nextUngrouped(IRoxieInput * input)
  157. {
  158. const void * ret = input->nextInGroup();
  159. if (!ret)
  160. ret = input->nextInGroup();
  161. return ret;
  162. };
  163. //=================================================================================
  164. //The following don't link their arguments because that creates a circular reference
  165. //But I wish there was a better way
  166. class IndirectSlaveContext : public CInterface, implements IRoxieSlaveContext
  167. {
  168. public:
  169. IndirectSlaveContext(IRoxieSlaveContext * _ctx = NULL) : ctx(_ctx) {}
  170. IMPLEMENT_IINTERFACE
  171. void set(IRoxieSlaveContext * _ctx) { ctx = _ctx; }
  172. virtual ICodeContext *queryCodeContext()
  173. {
  174. return ctx->queryCodeContext();
  175. }
  176. virtual void checkAbort()
  177. {
  178. ctx->checkAbort();
  179. }
  180. virtual void notifyAbort(IException *E)
  181. {
  182. ctx->notifyAbort(E);
  183. }
  184. virtual IActivityGraph * queryChildGraph(unsigned id)
  185. {
  186. return ctx->queryChildGraph(id);
  187. }
  188. virtual void noteChildGraph(unsigned id, IActivityGraph *childGraph)
  189. {
  190. ctx->noteChildGraph(id, childGraph) ;
  191. }
  192. virtual IRowManager &queryRowManager()
  193. {
  194. return ctx->queryRowManager();
  195. }
  196. virtual void noteStatistic(unsigned statCode, unsigned __int64 value, unsigned count) const
  197. {
  198. ctx->noteStatistic(statCode, value, count);
  199. }
  200. virtual void CTXLOG(const char *format, ...) const
  201. {
  202. va_list args;
  203. va_start(args, format);
  204. ctx->CTXLOGva(format, args);
  205. va_end(args);
  206. }
  207. virtual void CTXLOGva(const char *format, va_list args) const
  208. {
  209. ctx->CTXLOGva(format, args);
  210. }
  211. virtual void CTXLOGa(TracingCategory category, const char *prefix, const char *text) const
  212. {
  213. ctx->CTXLOGa(category, prefix, text);
  214. }
  215. virtual void logOperatorException(IException *E, const char *file, unsigned line, const char *format, ...) const
  216. {
  217. va_list args;
  218. va_start(args, format);
  219. ctx->logOperatorExceptionVA(E, file, line, format, args);
  220. va_end(args);
  221. }
  222. virtual void logOperatorExceptionVA(IException *E, const char *file, unsigned line, const char *format, va_list args) const
  223. {
  224. ctx->logOperatorExceptionVA(E, file, line, format, args);
  225. }
  226. virtual void CTXLOGae(IException *E, const char *file, unsigned line, const char *prefix, const char *format, ...) const
  227. {
  228. va_list args;
  229. va_start(args, format);
  230. ctx->CTXLOGaeva(E, file, line, prefix, format, args);
  231. va_end(args);
  232. }
  233. virtual void CTXLOGaeva(IException *E, const char *file, unsigned line, const char *prefix, const char *format, va_list args) const
  234. {
  235. ctx->CTXLOGaeva(E, file, line, prefix, format, args);
  236. }
  237. virtual void CTXLOGl(LogItem *log) const
  238. {
  239. ctx->CTXLOGl(log);
  240. }
  241. virtual StringBuffer &getLogPrefix(StringBuffer &ret) const
  242. {
  243. return ctx->getLogPrefix(ret);
  244. }
  245. virtual unsigned queryTraceLevel() const
  246. {
  247. return ctx->queryTraceLevel();
  248. }
  249. virtual bool isIntercepted() const
  250. {
  251. return ctx->isIntercepted();
  252. }
  253. virtual bool isBlind() const
  254. {
  255. return ctx->isBlind();
  256. }
  257. virtual unsigned parallelJoinPreload()
  258. {
  259. return ctx->parallelJoinPreload();
  260. }
  261. virtual unsigned concatPreload()
  262. {
  263. return ctx->concatPreload();
  264. }
  265. virtual unsigned fetchPreload()
  266. {
  267. return ctx->fetchPreload();
  268. }
  269. virtual unsigned fullKeyedJoinPreload()
  270. {
  271. return ctx->fullKeyedJoinPreload();
  272. }
  273. virtual unsigned keyedJoinPreload()
  274. {
  275. return ctx->keyedJoinPreload();
  276. }
  277. virtual unsigned prefetchProjectPreload()
  278. {
  279. return ctx->prefetchProjectPreload();
  280. }
  281. virtual void addSlavesReplyLen(unsigned len)
  282. {
  283. ctx->addSlavesReplyLen(len);
  284. }
  285. virtual const char *queryAuthToken()
  286. {
  287. return ctx->queryAuthToken();
  288. }
  289. virtual const IResolvedFile *resolveLFN(const char *filename, bool isOpt)
  290. {
  291. return ctx->resolveLFN(filename, isOpt);
  292. }
  293. virtual IRoxieWriteHandler *createLFN(const char *filename, bool overwrite, bool extend, const StringArray &clusters)
  294. {
  295. return ctx->createLFN(filename, overwrite, extend, clusters);
  296. }
  297. virtual void onFileCallback(const RoxiePacketHeader &header, const char *lfn, bool isOpt, bool isLocal)
  298. {
  299. ctx->onFileCallback(header, lfn, isOpt, isLocal);
  300. }
  301. virtual IActivityGraph *getLibraryGraph(const LibraryCallFactoryExtra &extra, IRoxieServerActivity *parentActivity)
  302. {
  303. return ctx->getLibraryGraph(extra, parentActivity);
  304. }
  305. virtual void noteProcessed(const IRoxieContextLogger &_activityContext, const IRoxieServerActivity *_activity, unsigned _idx, unsigned _processed, unsigned __int64 _totalCycles, unsigned __int64 _localCycles) const
  306. {
  307. ctx->noteProcessed(_activityContext, _activity, _idx, _processed, _totalCycles, _localCycles);
  308. }
  309. virtual IProbeManager *queryProbeManager() const
  310. {
  311. return ctx->queryProbeManager();
  312. }
  313. virtual IDebuggableContext *queryDebugContext() const
  314. {
  315. return ctx->queryDebugContext();
  316. }
  317. virtual bool queryTimeActivities() const
  318. {
  319. return ctx->queryTimeActivities();
  320. }
  321. virtual void printResults(IXmlWriter *output, const char *name, unsigned sequence)
  322. {
  323. ctx->printResults(output, name, sequence);
  324. }
  325. virtual void setWUState(WUState state)
  326. {
  327. ctx->setWUState(state);
  328. }
  329. virtual bool checkWuAborted()
  330. {
  331. return ctx->checkWuAborted();
  332. }
  333. virtual IWorkUnit *updateWorkUnit() const
  334. {
  335. return ctx->updateWorkUnit();
  336. }
  337. virtual IConstWorkUnit *queryWorkUnit() const
  338. {
  339. return ctx->queryWorkUnit();
  340. }
  341. virtual IRoxieServerContext *queryServerContext()
  342. {
  343. return ctx->queryServerContext();
  344. }
  345. protected:
  346. IRoxieSlaveContext * ctx;
  347. };
  348. //=================================================================================
  349. #define RESULT_FLUSH_THRESHOLD 10000u
  350. #ifdef _DEBUG
  351. #define SOAP_SPLIT_THRESHOLD 100u
  352. #define SOAP_SPLIT_RESERVE 200u
  353. #else
  354. #define SOAP_SPLIT_THRESHOLD 64000u
  355. #define SOAP_SPLIT_RESERVE 65535u
  356. #endif
  357. //=================================================================================
  358. class CRoxieServerActivityFactoryBase : public CActivityFactory, implements IRoxieServerActivityFactory
  359. {
  360. protected:
  361. IntArray dependencies; // things I am dependent on
  362. IntArray dependencyIndexes; // things I am dependent on
  363. IntArray dependencyControlIds; // things I am dependent on
  364. StringArray dependencyEdgeIds; // How to describe them to the debugger
  365. unsigned dependentCount; // things dependent on me
  366. mutable CriticalSection statsCrit;
  367. mutable __int64 processed;
  368. mutable __int64 started;
  369. mutable __int64 totalCycles;
  370. mutable __int64 localCycles;
  371. public:
  372. IMPLEMENT_IINTERFACE;
  373. CRoxieServerActivityFactoryBase(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  374. : CActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  375. {
  376. processed = 0;
  377. started = 0;
  378. totalCycles = 0;
  379. localCycles = 0;
  380. dependentCount = 0;
  381. }
  382. ~CRoxieServerActivityFactoryBase()
  383. {
  384. }
  385. StringBuffer &toString(StringBuffer &ret) const
  386. {
  387. return ret.appendf("%p", this);
  388. }
  389. virtual void addDependency(unsigned _source, ThorActivityKind _kind, unsigned _sourceIdx, int controlId, const char *edgeId)
  390. {
  391. dependencies.append(_source);
  392. dependencyIndexes.append(_sourceIdx);
  393. dependencyControlIds.append(controlId);
  394. dependencyEdgeIds.append(edgeId);
  395. }
  396. virtual void noteDependent(unsigned target)
  397. {
  398. dependentCount++;
  399. }
  400. virtual IntArray &queryDependencies() { return dependencies; }
  401. virtual IntArray &queryDependencyIndexes() { return dependencyIndexes; }
  402. virtual IntArray &queryDependencyControlIds() { return dependencyControlIds; }
  403. virtual StringArray &queryDependencyEdgeIds() { return dependencyEdgeIds; }
  404. virtual unsigned queryId() const { return id; }
  405. virtual unsigned querySubgraphId() const { return subgraphId; }
  406. virtual ThorActivityKind getKind() const { return kind; }
  407. virtual IOutputMetaData * queryOutputMeta() const
  408. {
  409. return meta;
  410. }
  411. virtual bool isSink() const
  412. {
  413. return false;
  414. }
  415. virtual bool isFunction() const
  416. {
  417. return false;
  418. }
  419. virtual bool isGraphInvariant() const
  420. {
  421. return false;
  422. }
  423. virtual IHThorArg &getHelper() const
  424. {
  425. return *helperFactory();
  426. }
  427. virtual IRoxieServerActivity *createFunction(IHThorArg &arg, IProbeManager *_probeManager) const
  428. {
  429. arg.Release();
  430. throwUnexpected();
  431. }
  432. virtual void noteProcessed(unsigned idx, unsigned _processed, unsigned __int64 _totalCycles, unsigned __int64 _localCycles) const
  433. {
  434. if (_processed || _totalCycles || _localCycles)
  435. {
  436. CriticalBlock b(statsCrit);
  437. #ifdef _DEBUG
  438. assertex(_totalCycles >= _localCycles);
  439. #endif
  440. processed += _processed;
  441. totalCycles += _totalCycles;
  442. localCycles += _localCycles;
  443. }
  444. }
  445. virtual void noteStarted() const
  446. {
  447. CriticalBlock b(statsCrit);
  448. started ++;
  449. }
  450. virtual void noteStarted(unsigned idx) const
  451. {
  452. throwUnexpected(); // should be implemented/required by multiOutput cases only
  453. }
  454. virtual void getEdgeProgressInfo(unsigned output, IPropertyTree &edge) const
  455. {
  456. CriticalBlock b(statsCrit);
  457. if (output == 0)
  458. {
  459. putStatsValue(&edge, "count", "sum", processed);
  460. if (started)
  461. putStatsValue(&edge, "started", "sum", started);
  462. }
  463. else
  464. ERRLOG("unexpected call to getEdgeProcessInfo for output %d in activity %d", output, queryId());
  465. }
  466. virtual void getNodeProgressInfo(IPropertyTree &node) const
  467. {
  468. CActivityFactory::getNodeProgressInfo(node);
  469. CriticalBlock b(statsCrit);
  470. if (started)
  471. putStatsValue(&node, "_roxieStarted", "sum", started);
  472. if (totalCycles)
  473. putStatsValue(&node, "totalTime", "sum", (unsigned) (cycle_to_nanosec(totalCycles)/1000));
  474. if (localCycles)
  475. putStatsValue(&node, "localTime", "sum", (unsigned) (cycle_to_nanosec(localCycles)/1000));
  476. }
  477. virtual void resetNodeProgressInfo()
  478. {
  479. CActivityFactory::resetNodeProgressInfo();
  480. CriticalBlock b(statsCrit);
  481. started = 0;
  482. totalCycles = 0;
  483. localCycles = 0;
  484. }
  485. virtual void getActivityMetrics(StringBuffer &reply) const
  486. {
  487. CActivityFactory::getActivityMetrics(reply);
  488. CriticalBlock b(statsCrit);
  489. putStatsValue(reply, "_roxieStarted", "sum", started);
  490. putStatsValue(reply, "totalTime", "sum", (unsigned) (cycle_to_nanosec(totalCycles)/1000));
  491. putStatsValue(reply, "localTime", "sum", (unsigned) (cycle_to_nanosec(localCycles)/1000));
  492. }
  493. virtual unsigned __int64 queryLocalCycles() const
  494. {
  495. return localCycles;
  496. }
  497. virtual IQueryFactory &queryQueryFactory() const
  498. {
  499. return CActivityFactory::queryQueryFactory();
  500. }
  501. virtual ActivityArray *queryChildQuery(unsigned idx, unsigned &id)
  502. {
  503. return CActivityFactory::queryChildQuery(idx, id);
  504. }
  505. virtual void addChildQuery(unsigned id, ActivityArray *childQuery)
  506. {
  507. CActivityFactory::addChildQuery(id, childQuery);
  508. }
  509. virtual void createChildQueries(IArrayOf<IActivityGraph> &childGraphs, IRoxieServerActivity *parentActivity, IProbeManager *_probeManager, const IRoxieContextLogger &_logctx) const
  510. {
  511. ForEachItemIn(idx, childQueries)
  512. {
  513. childGraphs.append(*createActivityGraph(NULL, childQueryIndexes.item(idx), childQueries.item(idx), parentActivity, _probeManager, _logctx));
  514. }
  515. }
  516. virtual void onCreateChildQueries(IRoxieSlaveContext *ctx, IHThorArg *colocalArg, IArrayOf<IActivityGraph> &childGraphs) const
  517. {
  518. ForEachItemIn(idx, childGraphs)
  519. {
  520. ctx->noteChildGraph(childQueryIndexes.item(idx), &childGraphs.item(idx));
  521. childGraphs.item(idx).onCreate(ctx, colocalArg);
  522. }
  523. }
  524. IActivityGraph * createChildGraph(IRoxieSlaveContext * ctx, IHThorArg *colocalArg, unsigned childId, IRoxieServerActivity *parentActivity, IProbeManager * _probeManager, const IRoxieContextLogger &_logctx) const
  525. {
  526. unsigned match = childQueryIndexes.find(childId);
  527. assertex(match != NotFound);
  528. Owned<IActivityGraph> graph = createActivityGraph(NULL, childQueryIndexes.item(match), childQueries.item(match), parentActivity, _probeManager, _logctx);
  529. graph->onCreate(ctx, colocalArg);
  530. return graph.getClear();
  531. }
  532. virtual IRoxieServerSideCache *queryServerSideCache() const
  533. {
  534. return NULL; // Activities that wish to support server-side caching will need to do better....
  535. }
  536. virtual bool getEnableFieldTranslation() const
  537. {
  538. throwUnexpected(); // only implemented by index-related subclasses
  539. }
  540. virtual IDefRecordMeta *queryActivityMeta() const
  541. {
  542. throwUnexpected(); // only implemented by index-related subclasses
  543. }
  544. virtual void noteStatistic(unsigned statCode, unsigned __int64 value, unsigned count) const
  545. {
  546. mystats.noteStatistic(statCode, value, count);
  547. }
  548. };
  549. class CRoxieServerMultiInputInfo
  550. {
  551. private:
  552. UnsignedArray inputs;
  553. UnsignedArray inputIndexes;
  554. public:
  555. void set(unsigned idx, unsigned source, unsigned sourceidx)
  556. {
  557. if (idx==inputs.length())
  558. {
  559. inputs.append(source);
  560. inputIndexes.append(sourceidx);
  561. }
  562. else
  563. {
  564. while (!inputs.isItem(idx))
  565. {
  566. inputs.append(0);
  567. inputIndexes.append(0);
  568. }
  569. inputs.replace(source, idx);
  570. inputIndexes.replace(sourceidx, idx);
  571. }
  572. }
  573. unsigned get(unsigned idx, unsigned &sourceidx) const
  574. {
  575. if (inputs.isItem(idx))
  576. {
  577. sourceidx = inputIndexes.item(idx);
  578. return inputs.item(idx);
  579. }
  580. else
  581. return (unsigned) -1;
  582. }
  583. inline unsigned ordinality() const { return inputs.ordinality(); }
  584. };
  585. class CRoxieServerMultiInputFactory : public CRoxieServerActivityFactoryBase
  586. {
  587. private:
  588. CRoxieServerMultiInputInfo inputs;
  589. public:
  590. IMPLEMENT_IINTERFACE;
  591. CRoxieServerMultiInputFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  592. : CRoxieServerActivityFactoryBase(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  593. {
  594. }
  595. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  596. {
  597. inputs.set(idx, source, sourceidx);
  598. }
  599. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  600. {
  601. return inputs.get(idx, sourceidx);
  602. }
  603. inline unsigned numInputs() const { return inputs.ordinality(); }
  604. };
  605. class CWrappedException : public CInterface, implements IException
  606. {
  607. Owned<IException> wrapped;
  608. ThorActivityKind kind;
  609. unsigned queryId;
  610. public:
  611. IMPLEMENT_IINTERFACE;
  612. CWrappedException(IException *_wrapped, ThorActivityKind _kind, unsigned _queryId)
  613. : wrapped(_wrapped), kind(_kind), queryId(_queryId)
  614. {
  615. }
  616. virtual int errorCode() const { return wrapped->errorCode(); }
  617. virtual StringBuffer & errorMessage(StringBuffer &msg) const { return wrapped->errorMessage(msg).appendf(" (in %s %d)", getActivityText(kind), queryId); }
  618. virtual MessageAudience errorAudience() const { return wrapped->errorAudience(); }
  619. };
  620. class CRoxieServerActivityFactory : public CRoxieServerActivityFactoryBase
  621. {
  622. protected:
  623. unsigned input;
  624. unsigned inputidx;
  625. public:
  626. IMPLEMENT_IINTERFACE;
  627. CRoxieServerActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  628. : CRoxieServerActivityFactoryBase(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  629. {
  630. input = (unsigned) -1;
  631. inputidx = 0;
  632. }
  633. inline void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  634. {
  635. if (idx != 0)
  636. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: id = %d : setInput() parameter out of bounds idx = %d at %s(%d)", id, idx, __FILE__, __LINE__);
  637. if (input != -1)
  638. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: id = %d : setInput() called twice for input = %d source = %d inputidx = %d sourceidx = %d at %s(%d)", id, input, source, inputidx, sourceidx, __FILE__, __LINE__);
  639. input = source;
  640. inputidx = sourceidx;
  641. }
  642. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  643. {
  644. if (!idx)
  645. {
  646. sourceidx = inputidx;
  647. return input;
  648. }
  649. return (unsigned) -1;
  650. }
  651. };
  652. class CRoxieServerMultiOutputFactory : public CRoxieServerActivityFactory
  653. {
  654. protected:
  655. unsigned numOutputs;
  656. unsigned __int64 *processedArray;
  657. bool *startedArray;
  658. CRoxieServerMultiOutputFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  659. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  660. {
  661. numOutputs = 0;
  662. processedArray = NULL;
  663. startedArray = NULL;
  664. }
  665. ~CRoxieServerMultiOutputFactory()
  666. {
  667. delete [] processedArray;
  668. delete [] startedArray;
  669. }
  670. void setNumOutputs(unsigned num)
  671. {
  672. numOutputs = num;
  673. if (!num)
  674. num = 1; // Even sink activities like to track how many records they process
  675. processedArray = new unsigned __int64[num];
  676. startedArray = new bool[num];
  677. for (unsigned i = 0; i < num; i++)
  678. {
  679. processedArray[i] = 0;
  680. startedArray[i] = 0;
  681. }
  682. }
  683. virtual void getEdgeProgressInfo(unsigned idx, IPropertyTree &edge) const
  684. {
  685. assertex(numOutputs ? idx < numOutputs : idx==0);
  686. CriticalBlock b(statsCrit);
  687. putStatsValue(&edge, "count", "sum", processedArray[idx]);
  688. putStatsValue(&edge, "started", "sum", startedArray[idx]);
  689. }
  690. virtual void noteProcessed(unsigned idx, unsigned _processed, unsigned __int64 _totalCycles, unsigned __int64 _localCycles) const
  691. {
  692. assertex(numOutputs ? idx < numOutputs : idx==0);
  693. CriticalBlock b(statsCrit);
  694. processedArray[idx] += _processed;
  695. totalCycles += _totalCycles;
  696. localCycles += _localCycles;
  697. }
  698. virtual void noteStarted(unsigned idx) const
  699. {
  700. assertex(numOutputs ? idx < numOutputs : idx==0);
  701. CriticalBlock b(statsCrit);
  702. startedArray[idx] = true;
  703. }
  704. };
  705. class CRoxieServerInternalSinkFactory : public CRoxieServerActivityFactory
  706. {
  707. protected:
  708. bool isInternal;
  709. bool isRoot;
  710. unsigned usageCount;
  711. public:
  712. CRoxieServerInternalSinkFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  713. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  714. {
  715. usageCount = _usageCount;
  716. isRoot = _isRoot;
  717. isInternal = false; // filled in by derived class constructor
  718. }
  719. virtual bool isSink() const
  720. {
  721. //only a sink if a root activity
  722. return isRoot && !(isInternal && dependentCount && dependentCount==usageCount); // MORE - it's possible for this to get the answer wrong still, since usageCount does not include references from main procedure. Gavin?
  723. }
  724. virtual void getEdgeProgressInfo(unsigned idx, IPropertyTree &edge) const
  725. {
  726. // There is no meaningful info to return along the dependency edge - we don't detect how many times the value has been read from the context
  727. // Just leave it blank is safest.
  728. }
  729. };
  730. typedef enum { STATEreset, STATEstarted, STATEstopped, STATEstarting } activityState;
  731. const char *queryStateText(activityState state)
  732. {
  733. switch (state)
  734. {
  735. case STATEreset: return "reset";
  736. case STATEstarted: return "started";
  737. case STATEstopped: return "stopped";
  738. case STATEstarting: return "starting";
  739. default: return "unknown";
  740. }
  741. }
  742. typedef ICopyArrayOf<IRoxieServerActivity> IRoxieServerActivityCopyArray;
  743. class CParallelActivityExecutor : public CAsyncFor
  744. {
  745. public:
  746. unsigned parentExtractSize;
  747. const byte * parentExtract;
  748. CParallelActivityExecutor(IRoxieServerActivityCopyArray & _activities, unsigned _parentExtractSize, const byte * _parentExtract) :
  749. activities(_activities), parentExtractSize(_parentExtractSize), parentExtract(_parentExtract) { }
  750. void Do(unsigned i)
  751. {
  752. activities.item(i).execute(parentExtractSize, parentExtract);
  753. }
  754. private:
  755. IRoxieServerActivityCopyArray & activities;
  756. };
  757. class CRoxieServerActivity : public CInterface, implements IRoxieServerActivity, implements IRoxieInput, implements IRoxieContextLogger
  758. {
  759. protected:
  760. IRoxieInput *input;
  761. IHThorArg &basehelper;
  762. IRoxieSlaveContext *ctx;
  763. const IRoxieServerActivityFactory *factory;
  764. IRoxieServerActivityCopyArray dependencies;
  765. IntArray dependencyControlIds;
  766. IArrayOf<IActivityGraph> childGraphs;
  767. CachedOutputMetaData meta;
  768. IHThorArg *colocalParent;
  769. IEngineRowAllocator *rowAllocator;
  770. CriticalSection statecrit;
  771. mutable StatsCollector stats;
  772. unsigned processed;
  773. unsigned __int64 totalCycles;
  774. unsigned activityId;
  775. activityState state;
  776. bool createPending;
  777. bool debugging;
  778. public:
  779. IMPLEMENT_IINTERFACE;
  780. CRoxieServerActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  781. : factory(_factory),
  782. basehelper(_factory->getHelper()),
  783. activityId(_factory->queryId())
  784. {
  785. input = NULL;
  786. ctx = NULL;
  787. meta.set(basehelper.queryOutputMeta());
  788. processed = 0;
  789. totalCycles = 0;
  790. if (factory)
  791. factory->createChildQueries(childGraphs, this, _probeManager, *this);
  792. state=STATEreset;
  793. rowAllocator = NULL;
  794. debugging = _probeManager != NULL; // Don't want to collect timing stats from debug sessions
  795. colocalParent = NULL;
  796. createPending = true;
  797. }
  798. CRoxieServerActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, IHThorArg &_helper)
  799. : factory(_factory), basehelper(_helper)
  800. {
  801. input = NULL;
  802. ctx = NULL;
  803. meta.set(basehelper.queryOutputMeta());
  804. processed = 0;
  805. totalCycles = 0;
  806. if (factory)
  807. factory->createChildQueries(childGraphs, this, _probeManager, *this);
  808. state=STATEreset;
  809. rowAllocator = NULL;
  810. debugging = _probeManager != NULL; // Don't want to collect timing stats from debug sessions
  811. colocalParent = NULL;
  812. createPending = true;
  813. }
  814. CRoxieServerActivity(IHThorArg & _helper) : factory(NULL), basehelper(_helper)
  815. {
  816. activityId = 0;
  817. input = NULL;
  818. ctx = NULL;
  819. meta.set(basehelper.queryOutputMeta());
  820. processed = 0;
  821. totalCycles = 0;
  822. state=STATEreset;
  823. rowAllocator = NULL;
  824. debugging = false;
  825. colocalParent = NULL;
  826. createPending = true;
  827. }
  828. inline ~CRoxieServerActivity()
  829. {
  830. CriticalBlock cb(statecrit);
  831. if (traceStartStop)
  832. DBGLOG("%p destroy state=%s", this, queryStateText(state)); // Note- CTXLOG may not be safe
  833. if (state!=STATEreset)
  834. {
  835. DBGLOG("STATE: Activity %d destroyed but not reset", activityId);
  836. state = STATEreset; // bit pointless but there you go...
  837. }
  838. basehelper.Release();
  839. ::Release(rowAllocator);
  840. }
  841. virtual const IRoxieContextLogger &queryLogCtx()const
  842. {
  843. return *this;
  844. }
  845. inline void createRowAllocator()
  846. {
  847. if (!rowAllocator)
  848. rowAllocator = ctx->queryCodeContext()->getRowAllocator(meta.queryOriginal(), activityId);
  849. }
  850. // MORE - most of this is copied from ccd.hpp - can't we refactor?
  851. virtual void CTXLOG(const char *format, ...) const
  852. {
  853. va_list args;
  854. va_start(args, format);
  855. CTXLOGva(format, args);
  856. va_end(args);
  857. }
  858. virtual void CTXLOGva(const char *format, va_list args) const
  859. {
  860. StringBuffer text, prefix;
  861. getLogPrefix(prefix);
  862. text.valist_appendf(format, args);
  863. CTXLOGa(LOG_TRACING, prefix.str(), text.str());
  864. }
  865. virtual void CTXLOGa(TracingCategory category, const char *prefix, const char *text) const
  866. {
  867. if (ctx)
  868. ctx->CTXLOGa(category, prefix, text);
  869. else
  870. DBGLOG("[%s] %s", prefix, text);
  871. }
  872. virtual void logOperatorException(IException *E, const char *file, unsigned line, const char *format, ...) const
  873. {
  874. va_list args;
  875. va_start(args, format);
  876. StringBuffer prefix;
  877. getLogPrefix(prefix);
  878. CTXLOGaeva(E, file, line, prefix.str(), format, args);
  879. va_end(args);
  880. }
  881. virtual void logOperatorExceptionVA(IException *E, const char *file, unsigned line, const char *format, va_list args) const
  882. {
  883. StringBuffer prefix;
  884. getLogPrefix(prefix);
  885. CTXLOGaeva(E, file, line, prefix.str(), format, args);
  886. }
  887. virtual void CTXLOGae(IException *E, const char *file, unsigned line, const char *prefix, const char *format, ...) const
  888. {
  889. va_list args;
  890. va_start(args, format);
  891. CTXLOGaeva(E, file, line, prefix, format, args);
  892. va_end(args);
  893. }
  894. virtual void CTXLOGaeva(IException *E, const char *file, unsigned line, const char *prefix, const char *format, va_list args) const
  895. {
  896. if (ctx)
  897. ctx->CTXLOGaeva(E, file, line, prefix, format, args);
  898. else
  899. {
  900. StringBuffer ss;
  901. ss.appendf("[%s] ERROR", prefix);
  902. if (E)
  903. ss.append(": ").append(E->errorCode());
  904. if (file)
  905. ss.appendf(": %s(%d) ", file, line);
  906. if (E)
  907. E->errorMessage(ss.append(": "));
  908. if (format)
  909. {
  910. ss.append(": ").valist_appendf(format, args);
  911. }
  912. LOG(MCoperatorProgress, unknownJob, "%s", ss.str());
  913. }
  914. }
  915. virtual void CTXLOGl(LogItem *log) const
  916. {
  917. if (ctx)
  918. ctx->CTXLOGl(log);
  919. else
  920. {
  921. assert(ctx);
  922. log->Release(); // Should never happen
  923. }
  924. }
  925. virtual void noteStatistic(unsigned statCode, unsigned __int64 value, unsigned count) const
  926. {
  927. if (factory)
  928. factory->noteStatistic(statCode, value, count);
  929. if (ctx)
  930. ctx->noteStatistic(statCode, value, count);
  931. stats.noteStatistic(statCode, value, count);
  932. }
  933. virtual StringBuffer &getLogPrefix(StringBuffer &ret) const
  934. {
  935. if (ctx)
  936. ctx->getLogPrefix(ret);
  937. return ret.append('@').append(activityId);
  938. }
  939. virtual bool isIntercepted() const
  940. {
  941. return ctx ? ctx->isIntercepted() : false;
  942. }
  943. virtual bool isBlind() const
  944. {
  945. return ctx ? ctx->isBlind() : blindLogging;
  946. }
  947. virtual unsigned queryTraceLevel() const
  948. {
  949. if (ctx)
  950. return ctx->queryTraceLevel();
  951. else
  952. return traceLevel;
  953. }
  954. virtual bool isPassThrough()
  955. {
  956. return false;
  957. }
  958. virtual const IResolvedFile *resolveLFN(const char *filename, bool isOpt)
  959. {
  960. return ctx->resolveLFN(filename, isOpt);
  961. }
  962. virtual const IResolvedFile *queryVarFileInfo() const
  963. {
  964. throwUnexpected(); // should be implemented in more derived class by anyone that has a remote adaptor
  965. return NULL;
  966. }
  967. virtual void serializeSkipInfo(MemoryBuffer &out, unsigned seekLen, const void *rawSeek, unsigned numFields, const void * seek, const SmartStepExtra &stepExtra) const
  968. {
  969. throwUnexpected(); // should be implemented in more derived class wherever needed
  970. }
  971. virtual IRoxieSlaveContext *queryContext()
  972. {
  973. return ctx;
  974. }
  975. virtual IRoxieServerActivity *queryActivity() { return this; }
  976. virtual IIndexReadActivityInfo *queryIndexReadActivity() { return NULL; }
  977. virtual bool needsAllocator() const { return false; }
  978. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  979. {
  980. ctx = _ctx;
  981. colocalParent = _colocalParent;
  982. createPending = true;
  983. if (needsAllocator())
  984. createRowAllocator();
  985. processed = 0;
  986. totalCycles = 0;
  987. if (factory)
  988. factory->onCreateChildQueries(_ctx, &basehelper, childGraphs);
  989. }
  990. virtual void serializeCreateStartContext(MemoryBuffer &out)
  991. {
  992. //This should only be called after onStart has been called on the helper
  993. assertex(!createPending);
  994. assertex(state==STATEstarted);
  995. unsigned startlen = out.length();
  996. basehelper.serializeCreateContext(out);
  997. basehelper.serializeStartContext(out);
  998. if (queryTraceLevel() > 10)
  999. CTXLOG("serializeCreateStartContext for %d added %d bytes", activityId, out.length()-startlen);
  1000. }
  1001. virtual void serializeExtra(MemoryBuffer &out) {}
  1002. inline void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  1003. {
  1004. CriticalBlock cb(statecrit);
  1005. if (state != STATEreset && state != STATEstarting)
  1006. {
  1007. CTXLOG("STATE: Expected state to be reset, but was %s, in activity %d", queryStateText(state), activityId);
  1008. }
  1009. state=STATEstarted;
  1010. #ifdef TRACE_STARTSTOP
  1011. if (traceStartStop)
  1012. {
  1013. CTXLOG("start %d", activityId);
  1014. if (watchActivityId && watchActivityId==activityId)
  1015. {
  1016. CTXLOG("WATCH: start %d", activityId);
  1017. }
  1018. }
  1019. #endif
  1020. executeDependencies(parentExtractSize, parentExtract, 0);
  1021. if (input)
  1022. input->start(parentExtractSize, parentExtract, paused);
  1023. ensureCreated();
  1024. basehelper.onStart(parentExtract, NULL);
  1025. if (factory)
  1026. factory->noteStarted();
  1027. }
  1028. void executeDependencies(unsigned parentExtractSize, const byte *parentExtract, unsigned controlId)
  1029. {
  1030. //MORE: Create a filtered list and then use asyncfor
  1031. ForEachItemIn(idx, dependencies)
  1032. {
  1033. if (dependencyControlIds.item(idx) == controlId)
  1034. dependencies.item(idx).execute(parentExtractSize, parentExtract);
  1035. }
  1036. }
  1037. virtual unsigned __int64 queryTotalCycles() const
  1038. {
  1039. return totalCycles;
  1040. }
  1041. virtual unsigned __int64 queryLocalCycles() const
  1042. {
  1043. __int64 ret = totalCycles;
  1044. if (input) ret -= input->queryTotalCycles();
  1045. if (ret < 0)
  1046. ret = 0;
  1047. return ret;
  1048. }
  1049. virtual IRoxieInput *queryInput(unsigned idx) const
  1050. {
  1051. if (idx==0)
  1052. return input;
  1053. else
  1054. return NULL;
  1055. }
  1056. void noteProcessed(unsigned _idx, unsigned _processed, unsigned __int64 _totalCycles, unsigned __int64 _localCycles) const
  1057. {
  1058. if (factory)
  1059. {
  1060. if (!debugging)
  1061. factory->noteProcessed(_idx, _processed, _totalCycles, _localCycles);
  1062. if (ctx)
  1063. ctx->noteProcessed(*this, this, _idx, _processed, _totalCycles, _localCycles);
  1064. }
  1065. }
  1066. inline void ensureCreated()
  1067. {
  1068. if (createPending)
  1069. {
  1070. createPending = false;
  1071. basehelper.onCreate(ctx->queryCodeContext(), colocalParent, NULL);
  1072. }
  1073. }
  1074. inline void stop(bool aborting)
  1075. {
  1076. if (state != STATEstopped)
  1077. {
  1078. CriticalBlock cb(statecrit);
  1079. if (state != STATEstopped)
  1080. {
  1081. state=STATEstopped;
  1082. #ifdef TRACE_STARTSTOP
  1083. if (traceStartStop)
  1084. {
  1085. CTXLOG("stop %d", activityId);
  1086. if (watchActivityId && watchActivityId==activityId)
  1087. {
  1088. CTXLOG("WATCH: stop %d", activityId);
  1089. }
  1090. }
  1091. #endif
  1092. if (input)
  1093. input->stop(aborting);
  1094. }
  1095. }
  1096. }
  1097. inline void reset()
  1098. {
  1099. if (state != STATEreset)
  1100. {
  1101. CriticalBlock cb(statecrit);
  1102. if (state != STATEreset)
  1103. {
  1104. if (state==STATEstarted || state==STATEstarting)
  1105. {
  1106. CTXLOG("STATE: activity %d reset without stop", activityId);
  1107. stop(false);
  1108. }
  1109. if (ctx->queryTimeActivities())
  1110. {
  1111. stats.dumpStats(*this);
  1112. StringBuffer prefix, text;
  1113. getLogPrefix(prefix);
  1114. text.appendf("records processed - %d", processed);
  1115. CTXLOGa(LOG_STATISTICS, prefix.str(), text.str());
  1116. text.clear().appendf("total time - %d us", (unsigned) (cycle_to_nanosec(totalCycles)/1000));
  1117. CTXLOGa(LOG_STATISTICS, prefix.str(), text.str());
  1118. text.clear().appendf("local time - %d us", (unsigned) (cycle_to_nanosec(queryLocalCycles())/1000));
  1119. CTXLOGa(LOG_STATISTICS, prefix.str(), text.str());
  1120. }
  1121. state = STATEreset;
  1122. #ifdef TRACE_STARTSTOP
  1123. if (traceStartStop)
  1124. {
  1125. CTXLOG("reset %d", activityId);
  1126. if (watchActivityId && watchActivityId==activityId)
  1127. {
  1128. CTXLOG("WATCH: reset %d", activityId);
  1129. }
  1130. }
  1131. #endif
  1132. ForEachItemIn(idx, dependencies)
  1133. dependencies.item(idx).reset();
  1134. noteProcessed(0, processed, totalCycles, queryLocalCycles());
  1135. if (input)
  1136. input->reset();
  1137. processed = 0;
  1138. totalCycles = 0;
  1139. }
  1140. }
  1141. }
  1142. virtual void addDependency(IRoxieServerActivity &source, unsigned sourceIdx, int controlId)
  1143. {
  1144. dependencies.append(source);
  1145. dependencyControlIds.append(controlId);
  1146. }
  1147. virtual void resetEOF()
  1148. {
  1149. //would make more sense if the default implementation (and eof member) were in the base class
  1150. }
  1151. // Sink activities should override this....
  1152. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  1153. {
  1154. throw MakeStringException(ROXIE_SINK, "Internal error: execute() requires a sink");
  1155. }
  1156. virtual void executeChild(size32_t & retSize, void * & ret, unsigned parentExtractSize, const byte * parentExtract)
  1157. {
  1158. throw MakeStringException(ROXIE_SINK, "Internal error: executeChild() requires a suitable sink");
  1159. }
  1160. virtual __int64 evaluate()
  1161. {
  1162. throw MakeStringException(ROXIE_SINK, "Internal error: evaluate() requires a function");
  1163. }
  1164. virtual IRoxieInput * querySelectOutput(unsigned id)
  1165. {
  1166. return NULL;
  1167. }
  1168. virtual bool querySetStreamInput(unsigned id, IRoxieInput * _input)
  1169. {
  1170. return false;
  1171. }
  1172. virtual void setInput(unsigned idx, IRoxieInput *_in)
  1173. {
  1174. assertex(!idx);
  1175. input = _in;
  1176. }
  1177. virtual IRoxieInput *queryOutput(unsigned idx)
  1178. {
  1179. if (idx == (unsigned) -1)
  1180. idx = 0;
  1181. return idx ? NULL : this;
  1182. }
  1183. virtual IOutputMetaData *queryOutputMeta() const
  1184. {
  1185. return meta.queryOriginal();
  1186. }
  1187. virtual unsigned queryId() const
  1188. {
  1189. return activityId;
  1190. }
  1191. virtual unsigned querySubgraphId() const
  1192. {
  1193. return factory->querySubgraphId();
  1194. }
  1195. virtual void checkAbort()
  1196. {
  1197. ctx->checkAbort();
  1198. }
  1199. IException *makeWrappedException(IException *e)
  1200. {
  1201. StringBuffer msg;
  1202. ThorActivityKind activityKind = factory ? factory->getKind() : TAKnone;
  1203. CTXLOG("makeWrappedException - %s (in %s %d)", e->errorMessage(msg).str(), getActivityText(activityKind), activityId);
  1204. if (QUERYINTERFACE(e, CWrappedException) || QUERYINTERFACE(e, IUserException))
  1205. return e;
  1206. else
  1207. return new CWrappedException(e, activityKind, activityId);
  1208. }
  1209. virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract)
  1210. {
  1211. }
  1212. virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract, IProbeManager *probeManager, IArrayOf<IRoxieInput> &probes)
  1213. {
  1214. }
  1215. virtual void resetOutputsUsed()
  1216. {
  1217. }
  1218. virtual void noteOutputUsed()
  1219. {
  1220. }
  1221. virtual IRoxieServerSideCache *queryServerSideCache() const
  1222. {
  1223. return factory->queryServerSideCache();
  1224. }
  1225. virtual const IRoxieServerActivityFactory *queryFactory() const
  1226. {
  1227. return factory;
  1228. }
  1229. inline ThorActivityKind getKind() const
  1230. {
  1231. return factory->getKind();
  1232. }
  1233. inline bool isSink() const
  1234. {
  1235. return (factory != NULL) && factory->isSink();
  1236. }
  1237. };
  1238. //=====================================================================================================
  1239. class CRoxieServerLateStartActivity : public CRoxieServerActivity
  1240. {
  1241. protected:
  1242. IRoxieInput *input; // Don't use base class input field as we want to delay starts
  1243. bool prefiltered;
  1244. bool eof;
  1245. void lateStart(unsigned parentExtractSize, const byte *parentExtract, bool any)
  1246. {
  1247. prefiltered = !any;
  1248. eof = prefiltered;
  1249. if (!prefiltered)
  1250. input->start(parentExtractSize, parentExtract, false);
  1251. else
  1252. {
  1253. if (traceStartStop)
  1254. CTXLOG("lateStart activity stopping input early as prefiltered");
  1255. input->stop(false);
  1256. }
  1257. }
  1258. public:
  1259. CRoxieServerLateStartActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  1260. : CRoxieServerActivity(_factory, _probeManager)
  1261. {
  1262. prefiltered = false;
  1263. eof = false;
  1264. }
  1265. virtual void stop(bool aborting)
  1266. {
  1267. if (!prefiltered)
  1268. {
  1269. input->stop(aborting);
  1270. }
  1271. else if (traceStartStop)
  1272. CTXLOG("lateStart activity NOT stopping input late as prefiltered");
  1273. CRoxieServerActivity::stop(aborting);
  1274. }
  1275. virtual unsigned __int64 queryLocalCycles() const
  1276. {
  1277. __int64 localCycles = totalCycles - input->queryTotalCycles();
  1278. if (localCycles < 0)
  1279. localCycles = 0;
  1280. return localCycles;
  1281. }
  1282. virtual IRoxieInput *queryInput(unsigned idx) const
  1283. {
  1284. if (idx==0)
  1285. return input;
  1286. else
  1287. return NULL;
  1288. }
  1289. virtual void reset()
  1290. {
  1291. CRoxieServerActivity::reset();
  1292. input->reset();
  1293. prefiltered = false;
  1294. }
  1295. virtual void setInput(unsigned idx, IRoxieInput *_in)
  1296. {
  1297. assertex(!idx);
  1298. input = _in;
  1299. }
  1300. };
  1301. //=====================================================================================================
  1302. atomic_t nextInstanceId;
  1303. extern unsigned getNextInstanceId()
  1304. {
  1305. return atomic_add_exchange(&nextInstanceId, 1)+1;
  1306. }
  1307. atomic_t nextRuid;
  1308. ruid_t getNextRuid()
  1309. {
  1310. ruid_t ret = atomic_add_exchange(&nextRuid, 1)+1;
  1311. while (ret < RUID_FIRST)
  1312. ret = atomic_add_exchange(&nextRuid, 1)+1; // ruids 0 and 1 are reserved for pings/unwanted discarder.
  1313. return ret;
  1314. }
  1315. void setStartRuid(unsigned restarts)
  1316. {
  1317. atomic_set(&nextRuid, restarts * 0x10000);
  1318. atomic_set(&nextInstanceId, restarts * 10000);
  1319. }
  1320. enum { LimitSkipErrorCode = 0, KeyedLimitSkipErrorCode = 1 };
  1321. class LimitSkipException : public CInterface, public IException
  1322. {
  1323. int code;
  1324. public:
  1325. LimitSkipException(int _code) { code = _code; }
  1326. IMPLEMENT_IINTERFACE;
  1327. virtual int errorCode() const { return code; }
  1328. virtual StringBuffer & errorMessage(StringBuffer &msg) const { return msg.append("LimitSkipException"); }
  1329. virtual MessageAudience errorAudience() const { return MSGAUD_internal; }
  1330. };
  1331. IException *makeLimitSkipException(bool isKeyed)
  1332. {
  1333. // We need to make sure what we throw is IException not something derived from it....
  1334. return new LimitSkipException(isKeyed ? KeyedLimitSkipErrorCode : LimitSkipErrorCode);
  1335. }
  1336. //=================================================================================
  1337. interface IRecordPullerCallback : extends IExceptionHandler
  1338. {
  1339. virtual void processRow(const void *row) = 0;
  1340. virtual void processEOG() = 0;
  1341. virtual void processGroup(const ConstPointerArray &rows) = 0;
  1342. virtual void processDone() = 0;
  1343. };
  1344. class RecordPullerThread : public RestartableThread
  1345. {
  1346. protected:
  1347. IRoxieInput *input;
  1348. IRecordPullerCallback *helper;
  1349. Semaphore started; // MORE: GH->RKC I'm pretty sure this can be deleted, since handled by RestartableThread
  1350. bool groupAtOnce, eof, eog;
  1351. CriticalSection crit;
  1352. public:
  1353. RecordPullerThread(bool _groupAtOnce)
  1354. : RestartableThread("RecordPullerThread"), groupAtOnce(_groupAtOnce)
  1355. {
  1356. input = NULL;
  1357. helper = NULL;
  1358. eof = eog = FALSE;
  1359. }
  1360. inline unsigned __int64 queryTotalCycles() const
  1361. {
  1362. return input->queryTotalCycles();
  1363. }
  1364. void setInput(IRecordPullerCallback *_helper, IRoxieInput *_input)
  1365. {
  1366. helper = _helper;
  1367. input = _input;
  1368. }
  1369. IRoxieInput *queryInput() const
  1370. {
  1371. return input;
  1372. }
  1373. void start(unsigned parentExtractSize, const byte *parentExtract, bool paused, unsigned preload, bool noThread, IRoxieSlaveContext *ctx)
  1374. {
  1375. eof = false;
  1376. eog = false;
  1377. input->start(parentExtractSize, parentExtract, paused);
  1378. try
  1379. {
  1380. if (preload && !paused)
  1381. {
  1382. if (traceLevel > 4)
  1383. DBGLOG("Preload fetching first %d records", preload);
  1384. if (groupAtOnce)
  1385. pullGroups(preload);
  1386. else
  1387. pullRecords(preload);
  1388. }
  1389. if (eof)
  1390. {
  1391. if (traceLevel > 4)
  1392. DBGLOG("No need to start puller after preload");
  1393. helper->processDone();
  1394. }
  1395. else
  1396. {
  1397. if (!noThread)
  1398. {
  1399. StringBuffer logPrefix("[");
  1400. if (ctx) ctx->getLogPrefix(logPrefix);
  1401. logPrefix.append("] ");
  1402. RestartableThread::start(logPrefix);
  1403. started.wait();
  1404. }
  1405. }
  1406. }
  1407. catch (IException *e)
  1408. {
  1409. helper->fireException(e);
  1410. }
  1411. catch (...)
  1412. {
  1413. helper->fireException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unexpected exception caught in RecordPullerThread::start"));
  1414. }
  1415. }
  1416. void stop(bool aborting)
  1417. {
  1418. if (traceStartStop)
  1419. DBGLOG("RecordPullerThread::stop");
  1420. {
  1421. CriticalBlock c(crit); // stop is called on our consumer's thread. We need to take care calling stop for our input to make sure it is not in mid-nextInGroup etc etc.
  1422. input->stop(aborting);
  1423. }
  1424. RestartableThread::join();
  1425. }
  1426. void reset()
  1427. {
  1428. input->reset();
  1429. }
  1430. virtual int run()
  1431. {
  1432. started.signal();
  1433. try
  1434. {
  1435. if (groupAtOnce)
  1436. pullGroups((unsigned) -1);
  1437. else
  1438. pullRecords((unsigned) -1);
  1439. helper->processDone();
  1440. }
  1441. catch (IException *e)
  1442. {
  1443. helper->fireException(e);
  1444. }
  1445. catch (...)
  1446. {
  1447. helper->fireException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unexpected exception caught in RecordPullerThread::run"));
  1448. }
  1449. return 0;
  1450. }
  1451. void done()
  1452. {
  1453. helper->processDone();
  1454. }
  1455. bool pullRecords(unsigned preload)
  1456. {
  1457. if (eof)
  1458. return false;
  1459. while (preload)
  1460. {
  1461. const void * row;
  1462. {
  1463. CriticalBlock c(crit); // See comments in stop for why this is needed
  1464. row = input->nextInGroup();
  1465. }
  1466. if (row)
  1467. {
  1468. eog = false;
  1469. helper->processRow(row);
  1470. }
  1471. else if (!eog)
  1472. {
  1473. helper->processEOG();
  1474. eog = true;
  1475. }
  1476. else
  1477. {
  1478. eof = true;
  1479. return false;
  1480. }
  1481. if (preload != (unsigned) -1)
  1482. preload--;
  1483. }
  1484. return true;
  1485. }
  1486. void pullGroups(unsigned preload)
  1487. {
  1488. ConstPointerArray thisGroup;
  1489. unsigned rowsDone = 0;
  1490. while (preload && !eof)
  1491. {
  1492. const void *row;
  1493. {
  1494. CriticalBlock c(crit);
  1495. row = input->nextInGroup();
  1496. }
  1497. if (row)
  1498. {
  1499. thisGroup.append(row);
  1500. rowsDone++;
  1501. }
  1502. else if (thisGroup.length())
  1503. {
  1504. helper->processGroup(thisGroup);
  1505. thisGroup.kill();
  1506. if (preload != (unsigned) -1)
  1507. {
  1508. if (preload > rowsDone)
  1509. preload -= rowsDone;
  1510. else
  1511. break;
  1512. }
  1513. rowsDone = 0;
  1514. }
  1515. else
  1516. {
  1517. eof = true;
  1518. break;
  1519. }
  1520. }
  1521. }
  1522. };
  1523. //=================================================================================
  1524. #define READAHEAD_SIZE 1000
  1525. // MORE - this code copied from ThreadedConcat code - may be able to common up some.
  1526. class CRoxieServerReadAheadInput : public CInterface, implements IRoxieInput, implements IRecordPullerCallback
  1527. {
  1528. QueueOf<const void, true> buffer;
  1529. InterruptableSemaphore ready;
  1530. InterruptableSemaphore space;
  1531. CriticalSection crit;
  1532. bool eof;
  1533. bool disabled;
  1534. RecordPullerThread puller;
  1535. unsigned preload;
  1536. unsigned __int64 totalCycles;
  1537. IRoxieSlaveContext *ctx;
  1538. public:
  1539. IMPLEMENT_IINTERFACE;
  1540. CRoxieServerReadAheadInput(unsigned _preload) : puller(true), preload(_preload)
  1541. {
  1542. eof = false;
  1543. disabled = false;
  1544. totalCycles = 0;
  1545. ctx = NULL;
  1546. }
  1547. void onCreate(IRoxieSlaveContext *_ctx)
  1548. {
  1549. ctx = _ctx;
  1550. disabled = (ctx->queryDebugContext() != NULL);
  1551. }
  1552. virtual IRoxieServerActivity *queryActivity()
  1553. {
  1554. return puller.queryInput()->queryActivity();
  1555. }
  1556. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  1557. {
  1558. return puller.queryInput()->queryIndexReadActivity();
  1559. }
  1560. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  1561. {
  1562. eof = false;
  1563. totalCycles = 0;
  1564. if (disabled)
  1565. puller.queryInput()->start(parentExtractSize, parentExtract, paused);
  1566. else
  1567. {
  1568. space.reinit(READAHEAD_SIZE);
  1569. ready.reinit();
  1570. puller.start(parentExtractSize, parentExtract, paused, preload, false, ctx);
  1571. }
  1572. }
  1573. virtual void stop(bool aborting)
  1574. {
  1575. if (disabled)
  1576. puller.queryInput()->stop(aborting);
  1577. else
  1578. {
  1579. space.interrupt();
  1580. ready.interrupt();
  1581. puller.stop(aborting);
  1582. }
  1583. }
  1584. virtual void reset()
  1585. {
  1586. if (disabled)
  1587. puller.queryInput()->reset();
  1588. else
  1589. {
  1590. puller.reset();
  1591. ForEachItemIn(idx1, buffer)
  1592. ReleaseRoxieRow(buffer.item(idx1));
  1593. buffer.clear();
  1594. }
  1595. }
  1596. virtual void resetEOF()
  1597. {
  1598. throwUnexpected();
  1599. }
  1600. virtual IOutputMetaData * queryOutputMeta() const
  1601. {
  1602. return puller.queryInput()->queryOutputMeta();
  1603. }
  1604. virtual void checkAbort()
  1605. {
  1606. puller.queryInput()->checkAbort();
  1607. }
  1608. void setInput(unsigned idx, IRoxieInput *_in)
  1609. {
  1610. assertex(!idx);
  1611. puller.setInput(this, _in);
  1612. }
  1613. virtual unsigned __int64 queryTotalCycles() const
  1614. {
  1615. return totalCycles;
  1616. }
  1617. virtual unsigned __int64 queryLocalCycles() const
  1618. {
  1619. __int64 ret = totalCycles - puller.queryInput()->queryTotalCycles();
  1620. if (ret < 0) ret = 0;
  1621. return ret;
  1622. }
  1623. virtual IRoxieInput *queryInput(unsigned idx) const
  1624. {
  1625. return puller.queryInput()->queryInput(idx);
  1626. }
  1627. virtual const void * nextInGroup()
  1628. {
  1629. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  1630. if (disabled)
  1631. return puller.queryInput()->nextInGroup();
  1632. else
  1633. {
  1634. loop
  1635. {
  1636. {
  1637. CriticalBlock b(crit);
  1638. if (eof && !buffer.ordinality())
  1639. return NULL; // eof
  1640. }
  1641. ready.wait();
  1642. const void *ret;
  1643. {
  1644. CriticalBlock b(crit);
  1645. ret = buffer.dequeue();
  1646. }
  1647. space.signal();
  1648. return ret;
  1649. }
  1650. }
  1651. }
  1652. virtual unsigned queryId() const { throwUnexpected(); }
  1653. virtual bool fireException(IException *e)
  1654. {
  1655. // called from puller thread on failure
  1656. ready.interrupt(LINK(e));
  1657. space.interrupt(e);
  1658. return true;
  1659. }
  1660. virtual void processRow(const void *row)
  1661. {
  1662. {
  1663. CriticalBlock b(crit);
  1664. buffer.enqueue(row);
  1665. }
  1666. ready.signal();
  1667. space.wait();
  1668. }
  1669. virtual void processGroup(const ConstPointerArray &rows)
  1670. {
  1671. // NOTE - a bit bizarre in that it waits for the space AFTER using it.
  1672. // But the space semaphore is only there to stop infinite readahead. And otherwise it would deadlock
  1673. // if group was larger than max(space)
  1674. {
  1675. CriticalBlock b(crit);
  1676. ForEachItemIn(idx, rows)
  1677. buffer.enqueue(rows.item(idx));
  1678. buffer.enqueue(NULL);
  1679. }
  1680. for (unsigned i2 = 0; i2 <= rows.length(); i2++) // note - does 1 extra for the null
  1681. {
  1682. ready.signal();
  1683. space.wait();
  1684. }
  1685. }
  1686. virtual void processEOG()
  1687. {
  1688. // Used when output is not grouped - just ignore
  1689. }
  1690. virtual void processDone()
  1691. {
  1692. CriticalBlock b(crit);
  1693. eof = true;
  1694. ready.signal();
  1695. }
  1696. };
  1697. //=================================================================================
  1698. class CRoxieServerTwoInputActivity : public CRoxieServerActivity
  1699. {
  1700. protected:
  1701. IRoxieInput *input1;
  1702. Owned<CRoxieServerReadAheadInput> puller;
  1703. public:
  1704. CRoxieServerTwoInputActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  1705. : CRoxieServerActivity(_factory, _probeManager)
  1706. {
  1707. input1 = NULL;
  1708. }
  1709. ~CRoxieServerTwoInputActivity()
  1710. {
  1711. }
  1712. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  1713. {
  1714. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  1715. input1->start(parentExtractSize, parentExtract, paused);
  1716. }
  1717. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  1718. {
  1719. if (puller)
  1720. puller->onCreate(_ctx);
  1721. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  1722. }
  1723. virtual void stop(bool aborting)
  1724. {
  1725. input1->stop(aborting);
  1726. CRoxieServerActivity::stop(aborting);
  1727. }
  1728. virtual unsigned __int64 queryLocalCycles() const
  1729. {
  1730. __int64 ret;
  1731. __int64 inputCycles = input->queryTotalCycles();
  1732. __int64 input1Cycles = input1->queryTotalCycles();
  1733. if (puller)
  1734. ret = totalCycles - (inputCycles > input1Cycles ? inputCycles : input1Cycles);
  1735. else
  1736. ret = totalCycles - (inputCycles + input1Cycles);
  1737. if (ret < 0)
  1738. ret = 0;
  1739. return ret;
  1740. }
  1741. virtual IRoxieInput *queryInput(unsigned idx) const
  1742. {
  1743. switch (idx)
  1744. {
  1745. case 0:
  1746. return input;
  1747. case 1:
  1748. return input1;
  1749. default:
  1750. return NULL;
  1751. }
  1752. }
  1753. virtual void reset()
  1754. {
  1755. CRoxieServerActivity::reset();
  1756. if (input1)
  1757. input1->reset();
  1758. }
  1759. virtual void setInput(unsigned idx, IRoxieInput *_in)
  1760. {
  1761. switch(idx)
  1762. {
  1763. case 0:
  1764. input = _in;
  1765. break;
  1766. case 1:
  1767. input1 = _in;
  1768. break;
  1769. default:
  1770. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  1771. }
  1772. }
  1773. };
  1774. //=================================================================================
  1775. class CRoxieServerMultiInputBaseActivity : public CRoxieServerActivity
  1776. {
  1777. protected:
  1778. unsigned numInputs;
  1779. IRoxieInput **inputArray;
  1780. public:
  1781. CRoxieServerMultiInputBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  1782. : CRoxieServerActivity(_factory, _probeManager), numInputs(_numInputs)
  1783. {
  1784. inputArray = new IRoxieInput*[numInputs];
  1785. for (unsigned i = 0; i < numInputs; i++)
  1786. inputArray[i] = NULL;
  1787. }
  1788. ~CRoxieServerMultiInputBaseActivity()
  1789. {
  1790. delete [] inputArray;
  1791. }
  1792. virtual unsigned __int64 queryLocalCycles() const
  1793. {
  1794. __int64 localCycles = totalCycles;
  1795. for (unsigned i = 0; i < numInputs; i++)
  1796. localCycles -= inputArray[i]->queryTotalCycles();
  1797. if (localCycles < 0)
  1798. localCycles = 0;
  1799. return localCycles;
  1800. }
  1801. virtual IRoxieInput *queryInput(unsigned idx) const
  1802. {
  1803. if (idx < numInputs)
  1804. return inputArray[idx];
  1805. else
  1806. return NULL;
  1807. }
  1808. virtual void reset()
  1809. {
  1810. for (unsigned i = 0; i < numInputs; i++)
  1811. inputArray[i]->reset();
  1812. CRoxieServerActivity::reset();
  1813. }
  1814. virtual void setInput(unsigned idx, IRoxieInput *_in)
  1815. {
  1816. inputArray[idx] = _in;
  1817. }
  1818. };
  1819. //=================================================================================
  1820. class CRoxieServerMultiInputActivity : public CRoxieServerMultiInputBaseActivity
  1821. {
  1822. public:
  1823. CRoxieServerMultiInputActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  1824. : CRoxieServerMultiInputBaseActivity(_factory, _probeManager, _numInputs)
  1825. {
  1826. }
  1827. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  1828. {
  1829. CRoxieServerMultiInputBaseActivity::start(parentExtractSize, parentExtract, paused);
  1830. for (unsigned i = 0; i < numInputs; i++)
  1831. {
  1832. inputArray[i]->start(parentExtractSize, parentExtract, paused);
  1833. }
  1834. }
  1835. virtual void stop(bool aborting)
  1836. {
  1837. for (unsigned i = 0; i < numInputs; i++)
  1838. {
  1839. inputArray[i]->stop(aborting);
  1840. }
  1841. CRoxieServerMultiInputBaseActivity::stop(aborting);
  1842. }
  1843. };
  1844. //=====================================================================================================
  1845. class CRoxieServerInternalSinkActivity : public CRoxieServerActivity
  1846. {
  1847. protected:
  1848. bool executed;
  1849. CriticalSection ecrit;
  1850. Owned<IException> exception;
  1851. public:
  1852. CRoxieServerInternalSinkActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  1853. : CRoxieServerActivity(_factory, _probeManager)
  1854. {
  1855. executed = false;
  1856. }
  1857. virtual void reset()
  1858. {
  1859. executed = false;
  1860. exception.clear();
  1861. CRoxieServerActivity::reset();
  1862. }
  1863. virtual IRoxieInput *queryOutput(unsigned idx)
  1864. {
  1865. return NULL;
  1866. }
  1867. virtual const void *nextInGroup()
  1868. {
  1869. throwUnexpected(); // I am nobody's input
  1870. }
  1871. virtual void onExecute() = 0;
  1872. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  1873. {
  1874. CriticalBlock b(ecrit);
  1875. if (exception)
  1876. throw exception.getLink();
  1877. if (!executed)
  1878. {
  1879. try
  1880. {
  1881. start(parentExtractSize, parentExtract, false);
  1882. {
  1883. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext()); // unfortunately this is not really best place for seeing in debugger.
  1884. onExecute();
  1885. }
  1886. stop(false);
  1887. executed = true;
  1888. }
  1889. catch (IException *E)
  1890. {
  1891. exception.set(E); // (or maybe makeWrappedException?)
  1892. stop(true);
  1893. throw;
  1894. }
  1895. catch (...)
  1896. {
  1897. exception.set(MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught at %s:%d", __FILE__, __LINE__));
  1898. stop(true);
  1899. throw;
  1900. }
  1901. }
  1902. }
  1903. };
  1904. //=================================================================================
  1905. class CRoxieServerQueryPacket : public CInterface, implements IRoxieServerQueryPacket
  1906. {
  1907. protected:
  1908. Owned<IMessageResult> result;
  1909. Owned<IRoxieQueryPacket> packet;
  1910. Linked<IRoxieServerQueryPacket> continuation;
  1911. unsigned hash;
  1912. unsigned seq;
  1913. unsigned lastDebugSequence;
  1914. Owned<IRoxieQueryPacket> lastDebugResponse;
  1915. ILRUChain *prev;
  1916. ILRUChain *next;
  1917. bool delayed;
  1918. public:
  1919. IMPLEMENT_IINTERFACE;
  1920. CRoxieServerQueryPacket(IRoxieQueryPacket *p) : packet(p)
  1921. {
  1922. hash = 0;
  1923. seq = 0;
  1924. prev = NULL;
  1925. next = NULL;
  1926. delayed = false;
  1927. lastDebugSequence = 0;
  1928. }
  1929. virtual IRoxieQueryPacket *queryPacket() const
  1930. {
  1931. return packet;
  1932. }
  1933. virtual bool isContinuation() const
  1934. {
  1935. return packet && (packet->queryHeader().continueSequence & ~CONTINUE_SEQUENCE_SKIPTO) != 0;
  1936. }
  1937. virtual bool isDelayed() const
  1938. {
  1939. return delayed;
  1940. }
  1941. virtual bool isEnd() const
  1942. {
  1943. return false;
  1944. }
  1945. virtual bool isLimit(unsigned __int64 &_rowLimit, unsigned __int64 &_keyedLimit, unsigned __int64 &_stopAfter) const
  1946. {
  1947. return false;
  1948. }
  1949. virtual bool hasResult() const
  1950. {
  1951. return result != NULL;
  1952. }
  1953. virtual bool hasContinuation() const
  1954. {
  1955. return continuation != NULL;
  1956. }
  1957. virtual void setDelayed(bool _delayed)
  1958. {
  1959. delayed = _delayed;
  1960. }
  1961. virtual void setPacket(IRoxieQueryPacket *_packet)
  1962. {
  1963. packet.setown(_packet);
  1964. }
  1965. virtual void setSequence(unsigned _seq)
  1966. {
  1967. assertex(!IsShared());
  1968. seq = _seq;
  1969. }
  1970. virtual unsigned getSequence() const
  1971. {
  1972. return seq;
  1973. }
  1974. IMessageResult *getResult()
  1975. {
  1976. return result.getLink();
  1977. }
  1978. IMessageResult *queryResult()
  1979. {
  1980. return result;
  1981. }
  1982. void setResult(IMessageResult *r)
  1983. {
  1984. result.setown(r);
  1985. }
  1986. IRoxieServerQueryPacket *queryContinuation()
  1987. {
  1988. return continuation;
  1989. }
  1990. void setContinuation(IRoxieServerQueryPacket *c)
  1991. {
  1992. continuation.setown(c);
  1993. }
  1994. virtual unsigned queryHash() const
  1995. {
  1996. return hash;
  1997. }
  1998. virtual void setHash(unsigned _hash)
  1999. {
  2000. hash = _hash;
  2001. }
  2002. virtual ILRUChain *queryPrev() const { return prev; }
  2003. virtual ILRUChain *queryNext() const { return next; }
  2004. virtual void setPrev(ILRUChain *p) { prev = p; }
  2005. virtual void setNext(ILRUChain *n) { next = n; }
  2006. virtual void unchain()
  2007. {
  2008. if (prev && next)
  2009. {
  2010. prev->setNext(next);
  2011. next->setPrev(prev);
  2012. }
  2013. next = NULL;
  2014. prev = NULL;
  2015. }
  2016. virtual IRoxieQueryPacket *getDebugResponse(unsigned sequence)
  2017. {
  2018. if (sequence == lastDebugSequence)
  2019. return lastDebugResponse.getLink();
  2020. else if (sequence > lastDebugSequence)
  2021. {
  2022. lastDebugResponse.clear();
  2023. return NULL;
  2024. }
  2025. else
  2026. throwUnexpected();
  2027. }
  2028. virtual void setDebugResponse(unsigned sequence, IRoxieQueryPacket *response)
  2029. {
  2030. lastDebugSequence = sequence;
  2031. lastDebugResponse.set(response);
  2032. }
  2033. };
  2034. class CRoxieServerQueryPacketEndMarker : public CRoxieServerQueryPacket
  2035. {
  2036. public:
  2037. CRoxieServerQueryPacketEndMarker() : CRoxieServerQueryPacket(NULL)
  2038. {
  2039. }
  2040. virtual bool isEnd() const
  2041. {
  2042. return true;
  2043. }
  2044. };
  2045. class CRoxieServerQueryPacketLimitMarker : public CRoxieServerQueryPacket
  2046. {
  2047. unsigned __int64 rowLimit;
  2048. unsigned __int64 keyedLimit;
  2049. unsigned __int64 stopAfter;
  2050. public:
  2051. CRoxieServerQueryPacketLimitMarker(unsigned __int64 _rowLimit, unsigned __int64 _keyedLimit, unsigned __int64 _stopAfter) : CRoxieServerQueryPacket(NULL)
  2052. {
  2053. rowLimit = _rowLimit;
  2054. keyedLimit = _keyedLimit;
  2055. stopAfter = _stopAfter;
  2056. }
  2057. virtual bool isLimit(unsigned __int64 &_rowLimit, unsigned __int64 &_keyedLimit, unsigned __int64 &_stopAfter) const
  2058. {
  2059. _rowLimit = rowLimit;
  2060. _keyedLimit = keyedLimit;
  2061. _stopAfter = stopAfter;
  2062. return true;
  2063. }
  2064. };
  2065. class CRoxieServerSideCache : implements IRoxieServerSideCache, implements ILRUChain
  2066. {
  2067. protected:
  2068. unsigned cacheTableSize;
  2069. unsigned cacheTableSpace;
  2070. IRoxieServerQueryPacket **cacheTable;
  2071. mutable ILRUChain *prev;
  2072. mutable ILRUChain *next;
  2073. mutable CriticalSection crit;
  2074. virtual ILRUChain *queryPrev() const { return prev; }
  2075. virtual ILRUChain *queryNext() const { return next; }
  2076. virtual void setPrev(ILRUChain *p) { prev = p; }
  2077. virtual void setNext(ILRUChain *n) { next = n; }
  2078. virtual void unchain()
  2079. {
  2080. prev->setNext(next);
  2081. next->setPrev(prev);
  2082. next = NULL;
  2083. prev = NULL;
  2084. }
  2085. void moveToHead(IRoxieServerQueryPacket *mru)
  2086. {
  2087. mru->unchain();
  2088. mru->setNext(next);
  2089. next->setPrev(mru);
  2090. mru->setPrev(this);
  2091. next = mru;
  2092. }
  2093. IRoxieServerQueryPacket *removeLRU()
  2094. {
  2095. if (next==this)
  2096. assertex(next != this);
  2097. IRoxieServerQueryPacket *goer = (IRoxieServerQueryPacket *) next;
  2098. goer->unchain(); // NOTE - this will modify the value of next
  2099. return goer;
  2100. }
  2101. void removeEntry(IRoxieServerQueryPacket *goer)
  2102. {
  2103. unsigned v = goer->queryHash() % cacheTableSize;
  2104. loop
  2105. {
  2106. IRoxieServerQueryPacket *found = cacheTable[v];
  2107. assertex(found);
  2108. if (found == goer)
  2109. {
  2110. cacheTable[v] = NULL;
  2111. unsigned vn = v;
  2112. loop
  2113. {
  2114. vn++;
  2115. if (vn==cacheTableSize) vn = 0;
  2116. IRoxieServerQueryPacket *found2 = cacheTable[vn];
  2117. if (!found2)
  2118. break;
  2119. unsigned vm = found2->queryHash() % cacheTableSize;
  2120. if (((vn+cacheTableSize-vm) % cacheTableSize)>=((vn+cacheTableSize-v) % cacheTableSize)) // diff(vn,vm)>=diff(vn,v)
  2121. {
  2122. cacheTable[v] = found2;
  2123. v = vn;
  2124. cacheTable[v] = NULL;
  2125. }
  2126. }
  2127. cacheTableSpace++;
  2128. break;
  2129. }
  2130. v++;
  2131. if (v==cacheTableSize)
  2132. v = 0;
  2133. }
  2134. goer->Release();
  2135. }
  2136. public:
  2137. CRoxieServerSideCache(unsigned _cacheSize)
  2138. {
  2139. cacheTableSize = (_cacheSize*4)/3;
  2140. cacheTable = new IRoxieServerQueryPacket *[cacheTableSize];
  2141. memset(cacheTable, 0, cacheTableSize * sizeof(IRoxieServerQueryPacket *));
  2142. cacheTableSpace = _cacheSize;
  2143. prev = this;
  2144. next = this;
  2145. }
  2146. ~CRoxieServerSideCache()
  2147. {
  2148. for (unsigned i = 0; i < cacheTableSize; i++)
  2149. {
  2150. ::Release(cacheTable[i]);
  2151. }
  2152. delete [] cacheTable;
  2153. }
  2154. virtual IRoxieServerQueryPacket *findCachedResult(const IRoxieContextLogger &logctx, IRoxieQueryPacket *p) const
  2155. {
  2156. unsigned hash = p->hash();
  2157. unsigned et = hash % cacheTableSize;
  2158. if (traceServerSideCache)
  2159. {
  2160. StringBuffer s;
  2161. logctx.CTXLOG("CRoxieServerSideCache::findCachedResult hash %x slot %d %s", hash, et, p->queryHeader().toString(s).str());
  2162. }
  2163. CriticalBlock b(crit);
  2164. loop
  2165. {
  2166. IRoxieServerQueryPacket *found = cacheTable[et];
  2167. if (!found)
  2168. return NULL;
  2169. if (found->queryHash() == hash && found->queryPacket()->cacheMatch(p))
  2170. {
  2171. const_cast<CRoxieServerSideCache *>(this)->moveToHead(found);
  2172. if (traceServerSideCache)
  2173. logctx.CTXLOG("CRoxieServerSideCache::findCachedResult cache hit");
  2174. logctx.noteStatistic(STATS_SERVERCACHEHIT, 1, 1);
  2175. return NULL;
  2176. // Because IMessageResult cannot be replayed, this echeme is flawed. I'm leaving the code here just as a stats gatherer to see how useful it would have been....
  2177. //IRoxieServerQueryPacket *ret = new CRoxieServerQueryPacket(p);
  2178. //ret->setResult(found->getResult());
  2179. //return ret;
  2180. }
  2181. et++;
  2182. if (et == cacheTableSize)
  2183. et = 0;
  2184. }
  2185. }
  2186. virtual void noteCachedResult(IRoxieServerQueryPacket *out, IMessageResult *in)
  2187. {
  2188. if (true) //!in->getLength()) // MORE - separate caches for hits and nohits
  2189. {
  2190. unsigned hash = out->queryPacket()->hash();
  2191. out->setHash(hash);
  2192. unsigned et = hash % cacheTableSize;
  2193. if (traceServerSideCache)
  2194. {
  2195. StringBuffer s;
  2196. DBGLOG("CRoxieServerSideCache::noteCachedResult hash %x slot %d %s", hash, et, out->queryPacket()->queryHeader().toString(s).str());
  2197. }
  2198. CriticalBlock b(crit);
  2199. loop
  2200. {
  2201. IRoxieServerQueryPacket *found = cacheTable[et];
  2202. if (!found)
  2203. {
  2204. if (cacheTableSpace)
  2205. {
  2206. out->setResult(LINK(in));
  2207. cacheTable[et] = LINK(out);
  2208. cacheTableSpace--;
  2209. moveToHead(out);
  2210. break;
  2211. }
  2212. else
  2213. {
  2214. IRoxieServerQueryPacket *goer = removeLRU();
  2215. removeEntry(goer);
  2216. et = hash % cacheTableSize;
  2217. continue;
  2218. }
  2219. }
  2220. else if (found->queryHash()==hash && found->queryPacket()->cacheMatch(out->queryPacket()))
  2221. {
  2222. moveToHead(found);
  2223. return; // already in the cache. Because we don't cache until we have result, this can happen where
  2224. // multiple copies of a slave query are in-flight at once.
  2225. }
  2226. et++;
  2227. if (et == cacheTableSize)
  2228. et = 0;
  2229. }
  2230. }
  2231. // MORE - do we need to worry about the attachment between the MessageUnpacker and the current row manager. May all fall out ok...
  2232. // Can I easily spot a null result? Do I want to cache null results separately? only?
  2233. }
  2234. // Note that this caching mechanism (unlike the old keyed-join specific one) does not common up cases where multiple
  2235. // identical queries are in-flight at the same time. But if we can make it persistant between queries that will
  2236. // more than make up for it
  2237. };
  2238. class CRowArrayMessageUnpackCursor : public CInterface, implements IMessageUnpackCursor
  2239. {
  2240. ConstPointerArray &data;
  2241. Linked<IMessageResult> result;
  2242. public:
  2243. IMPLEMENT_IINTERFACE;
  2244. CRowArrayMessageUnpackCursor(ConstPointerArray &_data, IMessageResult *_result)
  2245. : data(_data), result(_result)
  2246. {
  2247. }
  2248. virtual bool atEOF() const
  2249. {
  2250. return data.length()==0;
  2251. }
  2252. virtual bool isSerialized() const
  2253. {
  2254. return false;
  2255. }
  2256. virtual const void * getNext(int length)
  2257. {
  2258. if (!data.length())
  2259. return NULL;
  2260. const void *ret = data.item(0);
  2261. data.remove(0);
  2262. return ret;
  2263. }
  2264. };
  2265. // MORE - should possibly move more over to the lazy version used in indexread?
  2266. class CRowArrayMessageResult : public CInterface, implements IMessageResult
  2267. {
  2268. ConstPointerArray data;
  2269. IRowManager &rowManager;
  2270. bool variableSize;
  2271. public:
  2272. IMPLEMENT_IINTERFACE;
  2273. CRowArrayMessageResult(IRowManager &_rowManager, bool _variableSize) : rowManager(_rowManager), variableSize(_variableSize)
  2274. {
  2275. }
  2276. ~CRowArrayMessageResult()
  2277. {
  2278. ReleaseRoxieRowSet(data);
  2279. }
  2280. virtual IMessageUnpackCursor *getCursor(IRowManager *rowMgr) const
  2281. {
  2282. CRowArrayMessageResult *_this = (CRowArrayMessageResult *) this;
  2283. return new CRowArrayMessageUnpackCursor(_this->data, _this);
  2284. }
  2285. virtual const void *getMessageHeader(unsigned &length) const
  2286. {
  2287. throwUnexpected(); // should never get called - I don't have a header available
  2288. length = 0;
  2289. return NULL;
  2290. }
  2291. virtual const void *getMessageMetadata(unsigned &length) const
  2292. {
  2293. length = 0;
  2294. return NULL;
  2295. }
  2296. virtual void discard() const
  2297. {
  2298. throwUnexpected();
  2299. }
  2300. void append(const void *row)
  2301. {
  2302. data.append(row);
  2303. }
  2304. };
  2305. void throwRemoteException(IMessageUnpackCursor *extra)
  2306. {
  2307. RecordLengthType *rowlen = (RecordLengthType *) extra->getNext(sizeof(RecordLengthType));
  2308. if (rowlen)
  2309. {
  2310. char *xml = (char *) extra->getNext(*rowlen);
  2311. ReleaseRoxieRow(rowlen);
  2312. Owned<IPropertyTree> p = createPTreeFromXMLString(xml);
  2313. ReleaseRoxieRow(xml);
  2314. unsigned code = p->getPropInt("Code", 0);
  2315. const char *msg = p->queryProp("Message");
  2316. if (!msg)
  2317. msg = xml;
  2318. throw MakeStringException(code, "%s", msg);
  2319. }
  2320. throwUnexpected();
  2321. }
  2322. class CRemoteResultAdaptor :public CInterface, implements IRoxieInput, implements IExceptionHandler
  2323. {
  2324. friend class CRemoteResultMerger;
  2325. class CRemoteResultMerger
  2326. {
  2327. class HeapEntry : public CInterface
  2328. {
  2329. private:
  2330. CRemoteResultAdaptor &adaptor;
  2331. IMessageUnpackCursor *cursor;
  2332. public:
  2333. const void *current;
  2334. bool isLast;
  2335. bool lastIsComplete;
  2336. IRoxieServerQueryPacket *packet;
  2337. unsigned seq;
  2338. public:
  2339. inline const void *noteResult(IMessageUnpackCursor *_cursor, bool _lastIsComplete)
  2340. {
  2341. cursor = _cursor;
  2342. lastIsComplete = _lastIsComplete;
  2343. return next();
  2344. }
  2345. public:
  2346. HeapEntry(CRemoteResultAdaptor &_adaptor, IRoxieServerQueryPacket *_packet, unsigned _seq) : adaptor(_adaptor), packet(_packet), seq(_seq)
  2347. {
  2348. cursor = NULL;
  2349. current = NULL;
  2350. isLast = false;
  2351. lastIsComplete = true;
  2352. }
  2353. ~HeapEntry()
  2354. {
  2355. ::Release(packet);
  2356. ::Release(cursor);
  2357. ReleaseRoxieRow(current);
  2358. }
  2359. bool isCompleteMatch() const
  2360. {
  2361. if (!isLast || lastIsComplete)
  2362. return true;
  2363. else
  2364. return false;
  2365. }
  2366. const void *next()
  2367. {
  2368. if (cursor)
  2369. {
  2370. ReleaseClearRoxieRow(current);
  2371. current = adaptor.getRow(cursor);
  2372. isLast = cursor->atEOF();
  2373. if (!current)
  2374. {
  2375. cursor->Release();
  2376. cursor = NULL;
  2377. }
  2378. }
  2379. return current;
  2380. }
  2381. unsigned skipTo(IRangeCompare *compare, const void *seek, unsigned numFields, bool requireExactMatch)
  2382. {
  2383. // MORE - This loop should possibly be a binchop... though it's not absolutely clear that is true (depends on term frequencies)
  2384. unsigned skipped = 0;
  2385. loop
  2386. {
  2387. int c = compare->docompare(current, seek, numFields);
  2388. //If larger than the seek values, then we may be allowed to return an inexact match,
  2389. //if equal then it is required to be an exact match,
  2390. if (c > 0)
  2391. {
  2392. if (!requireExactMatch || isCompleteMatch())
  2393. break;
  2394. }
  2395. else if ((c == 0) && isCompleteMatch())
  2396. break;
  2397. skipped++;
  2398. if (!next())
  2399. break;
  2400. }
  2401. return skipped;
  2402. }
  2403. };
  2404. CRemoteResultAdaptor &adaptor;
  2405. CIArrayOf<HeapEntry> heapEntries;
  2406. UnsignedArray heap;
  2407. IRowManager *rowManager;
  2408. unsigned numPending;
  2409. unsigned numFields;
  2410. bool endSeen;
  2411. bool remakePending;
  2412. IRangeCompare *compare;
  2413. bool deferredContinuation;
  2414. inline int doCompare(unsigned l, unsigned r)
  2415. {
  2416. int ret = compare->docompare(heapEntries.item(l).current, heapEntries.item(r).current, numFields);
  2417. if (!ret) ret = heapEntries.item(l).seq - heapEntries.item(r).seq;
  2418. return ret;
  2419. }
  2420. void makeHeap()
  2421. {
  2422. /* Permute blocks to establish the heap property
  2423. For each element p, the children are p*2+1 and p*2+2 (provided these are in range)
  2424. The children of p must both be greater than or equal to p
  2425. The parent of a child c is given by p = (c-1)/2
  2426. */
  2427. unsigned i;
  2428. unsigned n = heap.length();
  2429. unsigned *s = heap.getArray();
  2430. for (i=1; i<n; i++)
  2431. {
  2432. unsigned r = s[i];
  2433. int c = i; /* child */
  2434. while (c > 0)
  2435. {
  2436. int p = (c-1)/2; /* parent */
  2437. if ( doCompare( s[c], s[p] ) >= 0 )
  2438. break;
  2439. s[c] = s[p];
  2440. s[p] = r;
  2441. c = p;
  2442. }
  2443. }
  2444. remakePending = false;
  2445. }
  2446. void remakeHeap()
  2447. {
  2448. /* The row associated with block[0] will have changed
  2449. This code restores the heap property
  2450. */
  2451. unsigned p = 0; /* parent */
  2452. unsigned n = heap.length();
  2453. unsigned *s = heap.getArray();
  2454. while (1)
  2455. {
  2456. unsigned c = p*2 + 1; /* child */
  2457. if ( c >= n )
  2458. break;
  2459. /* Select smaller child */
  2460. if ( c+1 < n && doCompare( s[c+1], s[c] ) < 0 ) c += 1;
  2461. /* If child is greater or equal than parent then we are done */
  2462. if ( doCompare( s[c], s[p] ) >= 0 )
  2463. break;
  2464. /* Swap parent and child */
  2465. unsigned r = s[c];
  2466. s[c] = s[p];
  2467. s[p] = r;
  2468. /* child becomes parent */
  2469. p = c;
  2470. }
  2471. remakePending = false;
  2472. }
  2473. void append(IRoxieServerQueryPacket *p, unsigned seq)
  2474. {
  2475. HeapEntry &h = *new HeapEntry(adaptor, LINK(p), seq);
  2476. IMessageResult *result = p->queryResult();
  2477. assertex(result);
  2478. if (h.noteResult(result->getCursor(rowManager), isCompleteMatchFlag(result)))
  2479. {
  2480. heapEntries.append(h);
  2481. heap.append(heap.ordinality());
  2482. }
  2483. else
  2484. h.Release();
  2485. }
  2486. void removeHeap(unsigned idx)
  2487. {
  2488. heapEntries.remove(idx);
  2489. ForEachItemIn(i, heap)
  2490. {
  2491. unsigned v = heap.item(i);
  2492. assertex(v != idx);
  2493. if (v > idx)
  2494. heap.replace(v-1, i);
  2495. }
  2496. }
  2497. bool isCompleteMatchFlag(IMessageResult *result)
  2498. {
  2499. unsigned metaLen;
  2500. const byte *metaInfo = (const byte *) result->getMessageMetadata(metaLen);
  2501. if (metaLen)
  2502. {
  2503. unsigned short continuationLen = *(unsigned short *) metaInfo;
  2504. if (continuationLen >= sizeof(bool))
  2505. {
  2506. metaInfo += sizeof(unsigned short);
  2507. return *(bool *) metaInfo;
  2508. }
  2509. }
  2510. return true; // if no continuation info, last row was complete.
  2511. }
  2512. public:
  2513. CRemoteResultMerger(CRemoteResultAdaptor &_adaptor) : adaptor(_adaptor)
  2514. {
  2515. init(NULL, NULL);
  2516. }
  2517. void init(ISteppingMeta *meta, IRowManager *_rowManager)
  2518. {
  2519. if (meta)
  2520. {
  2521. numFields = meta->getNumFields();
  2522. compare = meta->queryCompare();
  2523. }
  2524. else
  2525. {
  2526. numFields = 0;
  2527. compare = NULL;
  2528. }
  2529. rowManager = _rowManager;
  2530. numPending = 0;
  2531. endSeen = false;
  2532. remakePending = false;
  2533. deferredContinuation = false;
  2534. }
  2535. void reset()
  2536. {
  2537. heapEntries.kill();
  2538. heap.kill();
  2539. numPending = 0;
  2540. endSeen = false;
  2541. remakePending = false;
  2542. deferredContinuation = false;
  2543. }
  2544. inline bool noteEndSeen()
  2545. {
  2546. bool hadSeen = endSeen;
  2547. if (!endSeen)
  2548. makeHeap();
  2549. endSeen = true;
  2550. return !hadSeen;
  2551. }
  2552. void noteResult(IRoxieServerQueryPacket *p, unsigned seq)
  2553. {
  2554. if (!p->isContinuation())
  2555. append(p, seq);
  2556. else
  2557. {
  2558. ForEachItemIn(idx, heapEntries)
  2559. {
  2560. HeapEntry &h = heapEntries.item(idx);
  2561. if (h.packet == p)
  2562. {
  2563. IMessageResult *result = p->queryResult();
  2564. if (!h.noteResult(result->getCursor(rowManager), isCompleteMatchFlag(result)))
  2565. {
  2566. heap.zap(idx);
  2567. removeHeap(idx);
  2568. }
  2569. numPending--;
  2570. if (!numPending)
  2571. makeHeap();
  2572. return;
  2573. }
  2574. }
  2575. }
  2576. // If we get here it must be a continuation for one that I have not yet consumed... we don't need to do anything.
  2577. return;
  2578. }
  2579. unsigned skipRows(unsigned &idx, const void *seek, const void *rawSeek, unsigned numFields, unsigned seekLen, const SmartStepExtra & stepExtra)
  2580. {
  2581. HeapEntry &entry = heapEntries.item(idx);
  2582. unsigned skipped = entry.current ? entry.skipTo(compare, seek, numFields, !stepExtra.returnMismatches()) : 0;
  2583. if (!entry.current)
  2584. {
  2585. IRoxieServerQueryPacket *continuation = entry.packet->queryContinuation();
  2586. if (continuation)
  2587. {
  2588. continuation->Link();
  2589. entry.packet->Release();
  2590. entry.packet = continuation;
  2591. if (continuation->hasResult())
  2592. {
  2593. IMessageResult *result = continuation->queryResult();
  2594. bool lastIsCompleteMatch = isCompleteMatchFlag(result);
  2595. entry.noteResult(result->getCursor(rowManager), lastIsCompleteMatch);
  2596. }
  2597. else
  2598. {
  2599. if (continuation->isDelayed())
  2600. {
  2601. continuation->setDelayed(false);
  2602. MemoryBuffer serializedSkip;
  2603. adaptor.activity.serializeSkipInfo(serializedSkip, seekLen, rawSeek, numFields, seek, stepExtra);
  2604. continuation->setPacket(continuation->queryPacket()->insertSkipData(serializedSkip.length(), serializedSkip.toByteArray()));
  2605. ROQ->sendPacket(continuation->queryPacket(), adaptor.activity.queryLogCtx());
  2606. adaptor.sentsome.signal();
  2607. }
  2608. numPending++;
  2609. }
  2610. }
  2611. else
  2612. {
  2613. heap.zap(idx);
  2614. removeHeap(idx);
  2615. idx--;
  2616. }
  2617. }
  2618. return skipped;
  2619. }
  2620. const void * nextSteppedGE(const void * seek, const void *rawSeek, unsigned numFields, unsigned seeklen, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  2621. {
  2622. // We discard all rows < seekval from all entries in heap
  2623. // If this results in additional slave requests, we return NULL so that we can wait for them
  2624. // If not, we rebuild the heap (if any were skipped) and return the first row
  2625. deferredContinuation = false;
  2626. if (heap.length())
  2627. {
  2628. unsigned skipped = 0;
  2629. unsigned idx = 0;
  2630. while(heapEntries.isItem(idx))
  2631. {
  2632. skipped += skipRows(idx, seek, rawSeek, numFields, seeklen, stepExtra);
  2633. idx++;
  2634. }
  2635. if (numPending)
  2636. return NULL; // can't answer yet, need more results from slaves
  2637. else
  2638. {
  2639. if (skipped)
  2640. makeHeap();
  2641. return next(wasCompleteMatch, stepExtra);
  2642. }
  2643. }
  2644. else
  2645. return NULL;
  2646. }
  2647. bool doContinuation(HeapEntry &topEntry, bool canDefer)
  2648. {
  2649. IRoxieServerQueryPacket *continuation = topEntry.packet->queryContinuation();
  2650. if (continuation)
  2651. {
  2652. if (continuation->isDelayed() && canDefer)
  2653. {
  2654. if (adaptor.activity.queryLogCtx().queryTraceLevel() > 10)
  2655. adaptor.activity.queryLogCtx().CTXLOG("Deferring continuation");
  2656. deferredContinuation = true;
  2657. }
  2658. else
  2659. {
  2660. deferredContinuation = false;
  2661. continuation->Link();
  2662. topEntry.packet->Release();
  2663. topEntry.packet = continuation;
  2664. if (continuation->hasResult())
  2665. {
  2666. IMessageResult *result = continuation->queryResult();
  2667. bool lastIsCompleteMatch = isCompleteMatchFlag(result);
  2668. topEntry.noteResult(result->getCursor(rowManager), lastIsCompleteMatch);
  2669. }
  2670. else
  2671. {
  2672. if (continuation->isDelayed()) // has the continuation been requested yet?
  2673. {
  2674. continuation->Link();
  2675. topEntry.packet->Release();
  2676. topEntry.packet = continuation;
  2677. continuation->setDelayed(false);
  2678. if (adaptor.activity.queryLogCtx().queryTraceLevel() > 10)
  2679. adaptor.activity.queryLogCtx().CTXLOG("About to send continuation, from doContinuation");
  2680. ROQ->sendPacket(continuation->queryPacket(), adaptor.activity.queryLogCtx());
  2681. adaptor.sentsome.signal();
  2682. }
  2683. numPending++; // we are waiting for one that is already in flight
  2684. }
  2685. }
  2686. return true; // next not known yet
  2687. }
  2688. else
  2689. return false;
  2690. }
  2691. const void *next(bool & wasCompleteMatch, const SmartStepExtra & stepExtra)
  2692. {
  2693. OwnedConstRoxieRow ret;
  2694. if (heap.length())
  2695. {
  2696. if (deferredContinuation)
  2697. {
  2698. unsigned top = heap.item(0);
  2699. HeapEntry &topEntry = heapEntries.item(top);
  2700. doContinuation(topEntry, false);
  2701. return NULL;
  2702. }
  2703. if (remakePending)
  2704. remakeHeap();
  2705. unsigned top = heap.item(0);
  2706. HeapEntry &topEntry = heapEntries.item(top);
  2707. ret.set(topEntry.current);
  2708. wasCompleteMatch = topEntry.isCompleteMatch();
  2709. const void *next = topEntry.next();
  2710. if (!next)
  2711. {
  2712. if (!doContinuation(topEntry, stepExtra.returnMismatches()))
  2713. {
  2714. unsigned last = heap.pop();
  2715. if (heap.length())
  2716. heap.replace(last, 0);
  2717. removeHeap(top);
  2718. }
  2719. }
  2720. remakePending = true;
  2721. }
  2722. return ret.getClear();
  2723. }
  2724. bool ready()
  2725. {
  2726. return endSeen && numPending == 0;
  2727. }
  2728. };
  2729. IRoxieServerQueryPacket *createRoxieServerQueryPacket(IRoxieQueryPacket *p, bool &cached)
  2730. {
  2731. if (serverSideCache && !debugContext)
  2732. {
  2733. IRoxieServerQueryPacket *ret = serverSideCache->findCachedResult(activity.queryLogCtx(), p);
  2734. if (ret)
  2735. {
  2736. p->Release();
  2737. cached = true;
  2738. return ret;
  2739. }
  2740. }
  2741. cached = false;
  2742. return new CRoxieServerQueryPacket(p);
  2743. }
  2744. #ifdef _DEBUG
  2745. void dumpPending()
  2746. {
  2747. CriticalBlock b(pendingCrit);
  2748. ForEachItemIn(idx, pending)
  2749. {
  2750. IRoxieServerQueryPacket &p = pending.item(idx);
  2751. StringBuffer s;
  2752. unsigned __int64 dummy;
  2753. if (p.isEnd())
  2754. s.append("END");
  2755. else if (p.isLimit(dummy, dummy, dummy))
  2756. s.append("LIMIT");
  2757. else
  2758. {
  2759. IRoxieQueryPacket *i = p.queryPacket();
  2760. s.appendf("%s", p.hasResult() ? "COMPLETE " : "PENDING ");
  2761. if (i)
  2762. {
  2763. RoxiePacketHeader &header = i->queryHeader();
  2764. header.toString(s);
  2765. }
  2766. }
  2767. DBGLOG("Pending %d %s", idx, s.str());
  2768. }
  2769. }
  2770. #endif
  2771. void abortPending()
  2772. {
  2773. CriticalBlock b(pendingCrit);
  2774. ForEachItemIn(idx, pending)
  2775. {
  2776. IRoxieServerQueryPacket &p = pending.item(idx);
  2777. if (!p.hasResult())
  2778. {
  2779. IRoxieQueryPacket *i = p.queryPacket();
  2780. if (i)
  2781. {
  2782. RoxiePacketHeader &header = i->queryHeader();
  2783. ROQ->sendAbort(header, activity.queryLogCtx());
  2784. }
  2785. }
  2786. }
  2787. pending.kill();
  2788. }
  2789. void checkDelayed()
  2790. {
  2791. if (ctx->queryDebugContext() && ctx->queryDebugContext()->getExecuteSequentially())
  2792. {
  2793. bool allDelayed = true;
  2794. CriticalBlock b(pendingCrit);
  2795. unsigned sendIdx = (unsigned) -1;
  2796. ForEachItemIn(idx, pending)
  2797. {
  2798. IRoxieServerQueryPacket &p = pending.item(idx);
  2799. if (p.queryPacket())
  2800. {
  2801. if (p.isDelayed())
  2802. {
  2803. if (sendIdx == (unsigned) -1)
  2804. sendIdx = idx;
  2805. }
  2806. else if (!p.hasResult())
  2807. {
  2808. allDelayed = false;
  2809. break;
  2810. }
  2811. }
  2812. }
  2813. if (allDelayed && sendIdx != (unsigned) -1)
  2814. {
  2815. if (activity.queryLogCtx().queryTraceLevel() > 10)
  2816. activity.queryLogCtx().CTXLOG("About to send debug-deferred from next");
  2817. pending.item(sendIdx).setDelayed(false);
  2818. ROQ->sendPacket(pending.item(sendIdx).queryPacket(), activity.queryLogCtx());
  2819. sentsome.signal();
  2820. }
  2821. }
  2822. else if (deferredStart)
  2823. {
  2824. CriticalBlock b(pendingCrit);
  2825. ForEachItemIn(idx, pending)
  2826. {
  2827. IRoxieServerQueryPacket &p = pending.item(idx);
  2828. if (p.isDelayed())
  2829. {
  2830. if (activity.queryLogCtx().queryTraceLevel() > 10)
  2831. activity.queryLogCtx().CTXLOG("About to send deferred start from next");
  2832. p.setDelayed(false);
  2833. ROQ->sendPacket(p.queryPacket(), activity.queryLogCtx());
  2834. sentsome.signal();
  2835. }
  2836. }
  2837. deferredStart = false;
  2838. }
  2839. }
  2840. void retryPending()
  2841. {
  2842. CriticalBlock b(pendingCrit);
  2843. checkDelayed();
  2844. ForEachItemIn(idx, pending)
  2845. {
  2846. IRoxieServerQueryPacket &p = pending.item(idx);
  2847. if (!p.hasResult() && !p.isDelayed())
  2848. {
  2849. IRoxieQueryPacket *i = p.queryPacket();
  2850. if (i)
  2851. {
  2852. if (!i->queryHeader().retry())
  2853. {
  2854. StringBuffer s;
  2855. IException *E = MakeStringException(ROXIE_MULTICAST_ERROR, "Failed to get response from slave(s) for %s in activity %d", i->queryHeader().toString(s).str(), queryId());
  2856. activity.queryLogCtx().logOperatorException(E, __FILE__, __LINE__, "CRemoteResultAdaptor::retry");
  2857. throw E;
  2858. }
  2859. if (!localSlave)
  2860. {
  2861. ROQ->sendPacket(i, activity.queryLogCtx());
  2862. atomic_inc(&retriesSent);
  2863. }
  2864. }
  2865. }
  2866. }
  2867. }
  2868. class ChannelBuffer
  2869. {
  2870. protected:
  2871. unsigned bufferLeft;
  2872. MemoryBuffer buffer;
  2873. char *nextBuf;
  2874. unsigned overflowSequence;
  2875. unsigned channel; // == bonded channel
  2876. bool needsFlush;
  2877. InterruptableSemaphore flowController;
  2878. const CRemoteResultAdaptor &owner;
  2879. CriticalSection crit;
  2880. public:
  2881. ChannelBuffer(const CRemoteResultAdaptor &_owner, unsigned _channel) : owner(_owner), channel(_channel), flowController(perChannelFlowLimit)
  2882. {
  2883. overflowSequence = 0;
  2884. needsFlush = false;
  2885. bufferLeft = 0;
  2886. nextBuf = NULL;
  2887. }
  2888. void init(unsigned minSize)
  2889. {
  2890. assertex(!buffer.length());
  2891. if (minSize < MIN_PAYLOAD_SIZE)
  2892. minSize = MIN_PAYLOAD_SIZE;
  2893. unsigned headerSize = sizeof(RoxiePacketHeader)+owner.headerLength();
  2894. unsigned bufferSize = headerSize+minSize;
  2895. if (bufferSize < mtu_size)
  2896. bufferSize = mtu_size;
  2897. buffer.reserveTruncate(bufferSize);
  2898. bufferLeft = bufferSize - headerSize;
  2899. assertex(buffer.toByteArray());
  2900. nextBuf = (char *) buffer.toByteArray() + headerSize;
  2901. needsFlush = false;
  2902. }
  2903. inline IRoxieQueryPacket *flush()
  2904. {
  2905. CriticalBlock cb(crit);
  2906. Owned<IRoxieQueryPacket> ret;
  2907. if (needsFlush)
  2908. {
  2909. buffer.setLength(nextBuf - buffer.toByteArray());
  2910. RoxiePacketHeader *h = (RoxiePacketHeader *) buffer.toByteArray();
  2911. h->init(owner.remoteId, owner.ruid, channel, overflowSequence);
  2912. //patch logPrefix, cachedContext and parent extract into the place reserved in the message buffer
  2913. byte * tgt = (byte*)(h+1);
  2914. owner.copyHeader(tgt, channel);
  2915. ret.setown(createRoxiePacket(buffer));
  2916. if (overflowSequence == OVERFLOWSEQUENCE_MAX)
  2917. overflowSequence = 1; // don't wrap to 0 - that is a bit special
  2918. else
  2919. overflowSequence++;
  2920. needsFlush = false;
  2921. bufferLeft = 0;
  2922. if (owner.flowControlled)
  2923. {
  2924. CriticalUnblock cub(crit);
  2925. while (!flowController.wait(1000))
  2926. {
  2927. StringBuffer s;
  2928. owner.activity.queryLogCtx().CTXLOG("Channel %d blocked by flow control: %s", channel, h->toString(s).str());
  2929. }
  2930. }
  2931. }
  2932. return ret.getClear();
  2933. }
  2934. inline void signal()
  2935. {
  2936. if (owner.flowControlled)
  2937. flowController.signal();
  2938. }
  2939. inline void interrupt(IException *e)
  2940. {
  2941. flowController.interrupt(e);
  2942. }
  2943. inline void *getBuffer(unsigned size)
  2944. {
  2945. CriticalBlock cb(crit);
  2946. if (bufferLeft >= size)
  2947. {
  2948. needsFlush = true;
  2949. void * ret = nextBuf;
  2950. nextBuf += size;
  2951. bufferLeft -= size;
  2952. return ret;
  2953. }
  2954. else if (!needsFlush)
  2955. {
  2956. init(size);
  2957. return getBuffer(size);
  2958. }
  2959. else if (owner.mergeOrder)
  2960. {
  2961. return buffer.reserve(size); // whole query needs to go as single packet if we are to merge
  2962. }
  2963. else
  2964. return NULL; // will force it to flush and start a new packet
  2965. }
  2966. };
  2967. private:
  2968. friend class CRemoteResultMerger;
  2969. bool allread;
  2970. bool contextCached;
  2971. bool preserveOrder;
  2972. InterruptableSemaphore sentsome;
  2973. Owned <IMessageCollator> mc;
  2974. Owned<IMessageUnpackCursor> mu;
  2975. Owned<IMessageResult> mr;
  2976. ChannelBuffer **buffers;
  2977. IHThorArg &helper;
  2978. unsigned __int64 stopAfter;
  2979. unsigned resendSequence;
  2980. IHThorArg *colocalArg;
  2981. IArrayOf<IRoxieServerQueryPacket> pending;
  2982. CriticalSection pendingCrit;
  2983. IRoxieServerSideCache *serverSideCache;
  2984. unsigned sentSequence;
  2985. Owned<IOutputRowDeserializer> deserializer;
  2986. Owned<IEngineRowAllocator> rowAllocator;
  2987. CRemoteResultMerger merger;
  2988. // this is only used to avoid recreating a bufferStream for each row. A better solution may be needed
  2989. MemoryBuffer tempRowBuffer;
  2990. Owned<ISerialStream> bufferStream;
  2991. CThorStreamDeserializerSource rowSource;
  2992. protected:
  2993. IRowManager *rowManager;
  2994. IRoxieInput *owner;
  2995. unsigned __int64 rowLimit;
  2996. unsigned __int64 keyedLimit;
  2997. IRoxieServerErrorHandler *errorHandler;
  2998. CachedOutputMetaData meta;
  2999. public:
  3000. ISteppingMeta *mergeOrder;
  3001. IRoxieSlaveContext *ctx;
  3002. IDebuggableContext *debugContext;
  3003. IRoxieServerActivity &activity;
  3004. unsigned parentExtractSize;
  3005. const byte * parentExtract;
  3006. bool flowControlled;
  3007. bool deferredStart;
  3008. MemoryBuffer logInfo;
  3009. MemoryBuffer cachedContext;
  3010. const RemoteActivityId &remoteId;
  3011. ruid_t ruid;
  3012. mutable CriticalSection buffersCrit;
  3013. unsigned processed;
  3014. unsigned __int64 totalCycles;
  3015. //private: //vc6 doesn't like this being private yet accessed by nested class...
  3016. const void *getRow(IMessageUnpackCursor *mu)
  3017. {
  3018. if (!mu->isSerialized() || (meta.isFixedSize() && !deserializer))
  3019. return mu->getNext(meta.getFixedSize());
  3020. else
  3021. {
  3022. RecordLengthType *rowlen = (RecordLengthType *) mu->getNext(sizeof(RecordLengthType));
  3023. if (rowlen)
  3024. {
  3025. RecordLengthType len = *rowlen;
  3026. ReleaseRoxieRow(rowlen);
  3027. const void *slaveRec = mu->getNext(len);
  3028. if (deserializer && mu->isSerialized())
  3029. {
  3030. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  3031. tempRowBuffer.setBuffer(len, const_cast<void *>(slaveRec), false);
  3032. size_t outsize = deserializer->deserialize(rowBuilder, rowSource);
  3033. ReleaseRoxieRow(slaveRec);
  3034. return rowBuilder.finalizeRowClear(outsize);
  3035. }
  3036. else
  3037. return slaveRec;
  3038. }
  3039. else
  3040. return NULL;
  3041. }
  3042. }
  3043. private:
  3044. ChannelBuffer *queryChannelBuffer(unsigned channel, bool force=false)
  3045. {
  3046. CriticalBlock cb(buffersCrit);
  3047. ChannelBuffer *b = buffers[channel];
  3048. if (!b && force)
  3049. {
  3050. if (!contextCached)
  3051. {
  3052. logInfo.clear();
  3053. unsigned char loggingFlags = LOGGING_FLAGSPRESENT | LOGGING_TRACELEVELSET;
  3054. unsigned char ctxTraceLevel = activity.queryLogCtx().queryTraceLevel() + 1; // Avoid passing a 0
  3055. if (activity.queryLogCtx().isIntercepted())
  3056. loggingFlags |= LOGGING_INTERCEPTED;
  3057. if (ctx->queryTimeActivities())
  3058. loggingFlags |= LOGGING_TIMEACTIVITIES;
  3059. if (activity.queryLogCtx().isBlind())
  3060. loggingFlags |= LOGGING_BLIND;
  3061. if (debugContext)
  3062. {
  3063. loggingFlags |= LOGGING_DEBUGGERACTIVE;
  3064. logInfo.append(loggingFlags).append(ctxTraceLevel);
  3065. MemoryBuffer bpInfo;
  3066. debugContext->serialize(bpInfo);
  3067. bpInfo.append((__uint64)(memsize_t) &activity);
  3068. logInfo.append((unsigned short) bpInfo.length());
  3069. logInfo.append(bpInfo.length(), bpInfo.toByteArray());
  3070. }
  3071. else
  3072. logInfo.append(loggingFlags).append(ctxTraceLevel);
  3073. StringBuffer logPrefix;
  3074. activity.queryLogCtx().getLogPrefix(logPrefix);
  3075. logInfo.append(logPrefix);
  3076. activity.serializeCreateStartContext(cachedContext.clear());
  3077. activity.serializeExtra(cachedContext);
  3078. if (activity.queryVarFileInfo())
  3079. activity.queryVarFileInfo()->queryTimeStamp().serialize(cachedContext);
  3080. contextCached = true;
  3081. }
  3082. b = buffers[channel] = new ChannelBuffer(*this, channel);
  3083. }
  3084. return b;
  3085. }
  3086. void processRow(const void *got)
  3087. {
  3088. processed++;
  3089. if (processed > rowLimit)
  3090. {
  3091. ReleaseRoxieRow(got);
  3092. errorHandler->onLimitExceeded(false); // NOTE - should throw exception
  3093. throwUnexpected();
  3094. }
  3095. else if (processed > keyedLimit)
  3096. {
  3097. ReleaseRoxieRow(got);
  3098. errorHandler->onLimitExceeded(true); // NOTE - should throw exception
  3099. throwUnexpected();
  3100. }
  3101. }
  3102. public:
  3103. IMPLEMENT_IINTERFACE;
  3104. CRemoteResultAdaptor(const RemoteActivityId &_remoteId, IOutputMetaData *_meta, IHThorArg &_helper, IRoxieServerActivity &_activity, bool _preserveOrder, bool _flowControlled)
  3105. : remoteId(_remoteId), meta(_meta), activity(_activity), helper(_helper), preserveOrder(_preserveOrder), flowControlled(_flowControlled), merger(*this)
  3106. {
  3107. rowLimit = (unsigned __int64) -1;
  3108. keyedLimit = (unsigned __int64) -1;
  3109. contextCached = false;
  3110. stopAfter = I64C(0x7FFFFFFFFFFFFFFF);
  3111. buffers = new ChannelBuffer*[numChannels+1];
  3112. memset(buffers, 0, (numChannels+1)*sizeof(ChannelBuffer *));
  3113. parentExtractSize = 0;
  3114. parentExtract = NULL;
  3115. owner = NULL;
  3116. mergeOrder = NULL;
  3117. deferredStart = false;
  3118. processed = 0;
  3119. totalCycles = 0;
  3120. sentSequence = 0;
  3121. serverSideCache = activity.queryServerSideCache();
  3122. bufferStream.setown(createMemoryBufferSerialStream(tempRowBuffer));
  3123. rowSource.setStream(bufferStream);
  3124. }
  3125. ~CRemoteResultAdaptor()
  3126. {
  3127. if (mc)
  3128. {
  3129. ROQ->queryReceiveManager()->detachCollator(mc);
  3130. mc.clear();
  3131. }
  3132. for (unsigned channel = 0; channel <= numChannels; channel++)
  3133. {
  3134. delete(buffers[channel]);
  3135. }
  3136. delete [] buffers;
  3137. }
  3138. void setMeta(IOutputMetaData *newmeta)
  3139. {
  3140. meta.set(newmeta);
  3141. }
  3142. virtual IRoxieServerActivity *queryActivity()
  3143. {
  3144. return &activity;
  3145. }
  3146. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  3147. {
  3148. return NULL;
  3149. }
  3150. void setMergeInfo(ISteppingMeta *_mergeOrder)
  3151. {
  3152. mergeOrder = _mergeOrder;
  3153. deferredStart = true;
  3154. }
  3155. void send(IRoxieQueryPacket *p)
  3156. {
  3157. if (p)
  3158. {
  3159. Linked<IRoxieQueryPacket> saver(p); // avoids a race with abortPending, without keeping pendingCrit locked over the send which we might prefer not to
  3160. assertex(p->queryHeader().uid==ruid);
  3161. // MORE: Maybe we should base the fastlane flag on some other
  3162. // criteria !! (i.e A Roxie server prediction based on the
  3163. // activity type/activity behaviour/expected reply size .. etc).
  3164. //
  3165. // Currently (code below) based on high priority, seq=0, and none-child activity.
  3166. // But this could still cause too many reply packets on the fatlane
  3167. // (higher priority output Q), which may cause the activities on the
  3168. // low priority output Q to not get service on time.
  3169. if ((colocalArg == 0) && // not a child query activity??
  3170. (p->queryHeader().activityId & (ROXIE_SLA_PRIORITY | ROXIE_HIGH_PRIORITY)) &&
  3171. (p->queryHeader().overflowSequence == 0) &&
  3172. (p->queryHeader().continueSequence & ~CONTINUE_SEQUENCE_SKIPTO)==0)
  3173. p->queryHeader().retries |= ROXIE_FASTLANE;
  3174. if (p->queryHeader().channel)
  3175. {
  3176. bool cached = false;
  3177. IRoxieServerQueryPacket *rsqp = createRoxieServerQueryPacket(p, cached);
  3178. if (deferredStart)
  3179. rsqp->setDelayed(true);
  3180. rsqp->setSequence(sentSequence++);
  3181. {
  3182. CriticalBlock b(pendingCrit);
  3183. pending.append(*rsqp);
  3184. }
  3185. if (!deferredStart)
  3186. {
  3187. if (!cached)
  3188. ROQ->sendPacket(p, activity.queryLogCtx());
  3189. sentsome.signal();
  3190. }
  3191. }
  3192. else
  3193. {
  3194. // Care is needed here. If I send the packet before I add to the pending there is a danger that I'll get results that I discard
  3195. // Need to add first, then send
  3196. unsigned i;
  3197. bool allCached = true;
  3198. for (i = 1; i <= numActiveChannels; i++)
  3199. {
  3200. IRoxieQueryPacket *q = p->clonePacket(i);
  3201. bool thisChannelCached;
  3202. IRoxieServerQueryPacket *rsqp = createRoxieServerQueryPacket(q, thisChannelCached);
  3203. if (!thisChannelCached)
  3204. allCached = false;
  3205. rsqp->setSequence(sentSequence++);
  3206. if (deferredStart)
  3207. {
  3208. rsqp->setDelayed(true);
  3209. }
  3210. {
  3211. CriticalBlock b(pendingCrit);
  3212. pending.append(*rsqp);
  3213. }
  3214. if (!deferredStart)
  3215. sentsome.signal();
  3216. }
  3217. if (!allCached && !deferredStart)
  3218. ROQ->sendPacket(p, activity.queryLogCtx());
  3219. buffers[0]->signal(); // since replies won't come back on that channel...
  3220. p->Release();
  3221. }
  3222. }
  3223. }
  3224. void *getMem(unsigned partNo, unsigned fileNo, unsigned size)
  3225. {
  3226. unsigned channel = partNo ? getBondedChannel(partNo) : 0;
  3227. size += sizeof(PartNoType);
  3228. ChannelBuffer *b = queryChannelBuffer(channel, true);
  3229. char *buffer = (char *) b->getBuffer(size);
  3230. if (!buffer)
  3231. {
  3232. send(b->flush());
  3233. buffer = (char *) b->getBuffer(size);
  3234. }
  3235. PartNoType sp;
  3236. sp.partNo = partNo;
  3237. sp.fileNo = fileNo;
  3238. memcpy(buffer, &sp, sizeof(sp));
  3239. buffer += sizeof(sp);
  3240. return buffer;
  3241. }
  3242. void injectResult(IMessageResult *result)
  3243. {
  3244. IRoxieServerQueryPacket *f = new CRoxieServerQueryPacket(NULL);
  3245. f->setSequence(sentSequence++);
  3246. f->setResult(result);
  3247. CriticalBlock b(pendingCrit);
  3248. pending.append(*f);
  3249. sentsome.signal(); // MORE - arguably should only send if there is any point waking up the listener thread, to save context swicth
  3250. }
  3251. void flush()
  3252. {
  3253. for (unsigned channel = 0; channel <= numChannels; channel++)
  3254. {
  3255. ChannelBuffer *b = queryChannelBuffer(channel, false);
  3256. if (b)
  3257. send(b->flush());
  3258. }
  3259. }
  3260. void interruptBuffers(IException *e)
  3261. {
  3262. for (unsigned channel = 0; channel <= numChannels; channel++)
  3263. {
  3264. ChannelBuffer *b = queryChannelBuffer(channel, false);
  3265. if (b)
  3266. b->interrupt(LINK(e));
  3267. }
  3268. }
  3269. void senddone()
  3270. {
  3271. CriticalBlock b(pendingCrit);
  3272. pending.append(*new CRoxieServerQueryPacketEndMarker);
  3273. sentsome.signal();
  3274. }
  3275. bool fireException(IException *e)
  3276. {
  3277. {
  3278. CriticalBlock b(pendingCrit);
  3279. pending.append(*new CRoxieServerQueryPacketEndMarker);
  3280. }
  3281. interruptBuffers(e);
  3282. if (mc)
  3283. mc->interrupt(LINK(e));
  3284. sentsome.interrupt(e);
  3285. return true;
  3286. }
  3287. virtual void onCreate(IRoxieInput *_owner, IRoxieServerErrorHandler *_errorHandler, IRoxieSlaveContext *_ctx, IHThorArg *_colocalArg)
  3288. {
  3289. owner = _owner;
  3290. errorHandler = _errorHandler;
  3291. ctx = _ctx;
  3292. debugContext = ctx->queryDebugContext();
  3293. colocalArg = _colocalArg;
  3294. if (meta.needsSerialize())
  3295. {
  3296. deserializer.setown(meta.createRowDeserializer(_ctx->queryCodeContext(), activity.queryId()));
  3297. rowAllocator.setown(ctx->queryCodeContext()->getRowAllocator(meta.queryOriginal(), activity.queryId()));
  3298. }
  3299. if (ctx->queryDebugContext() && ctx->queryDebugContext()->getExecuteSequentially())
  3300. deferredStart = true;
  3301. }
  3302. virtual unsigned queryId() const
  3303. {
  3304. return owner->queryId();
  3305. }
  3306. virtual void onStart(unsigned _parentExtractSize, const byte * _parentExtract)
  3307. {
  3308. #ifdef TRACE_STARTSTOP
  3309. if (traceStartStop)
  3310. activity.queryLogCtx().CTXLOG("RRAonstart");
  3311. #endif
  3312. sentsome.reinit();
  3313. ruid = getNextRuid();
  3314. rowManager = &ctx->queryRowManager();
  3315. if (mergeOrder)
  3316. merger.init(mergeOrder, rowManager);
  3317. if (mc)
  3318. {
  3319. ROQ->queryReceiveManager()->detachCollator(mc); // Should never happen - implies someone forgot to call onReset!
  3320. }
  3321. mc.setown(ROQ->queryReceiveManager()->createMessageCollator(rowManager, ruid));
  3322. allread = false;
  3323. mu.clear();
  3324. contextCached = false;
  3325. processed = 0;
  3326. totalCycles = 0;
  3327. resendSequence = 0;
  3328. sentSequence = 0;
  3329. for (unsigned channel = 0; channel <= numChannels; channel++)
  3330. {
  3331. delete(buffers[channel]);
  3332. buffers[channel] = NULL;
  3333. }
  3334. flush();
  3335. parentExtractSize = _parentExtractSize;
  3336. parentExtract = _parentExtract;
  3337. }
  3338. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  3339. {
  3340. #ifdef TRACE_STARTSTOP
  3341. if (traceStartStop)
  3342. activity.queryLogCtx().CTXLOG("RRAstart");
  3343. #endif
  3344. owner->start(parentExtractSize, parentExtract, paused);
  3345. totalCycles = 0;
  3346. }
  3347. void checkAbort()
  3348. {
  3349. owner->checkAbort();
  3350. }
  3351. void setLimits(unsigned __int64 _rowLimit, unsigned __int64 _keyedLimit, unsigned __int64 _stopAfter)
  3352. {
  3353. if (ctx->queryProbeManager())
  3354. {
  3355. if (_rowLimit != (unsigned __int64) -1) ctx->queryProbeManager()->setNodePropertyInt(&activity, "rowLimit", _rowLimit);
  3356. if (_keyedLimit != (unsigned __int64) -1) ctx->queryProbeManager()->setNodePropertyInt(&activity, "keyedLimit", _keyedLimit);
  3357. if (_stopAfter != I64C(0x7FFFFFFFFFFFFFFF)) ctx->queryProbeManager()->setNodePropertyInt(&activity, "choosenLimit", _stopAfter);
  3358. }
  3359. {
  3360. CriticalBlock b(pendingCrit);
  3361. if (pending.length())
  3362. {
  3363. #ifdef _DEBUG
  3364. dumpPending(); // MORE - only defined in debug build - could have put the ifdef inside the dumpPending method
  3365. #endif
  3366. assertex(pending.length()==0);
  3367. }
  3368. pending.append(*new CRoxieServerQueryPacketLimitMarker(_rowLimit, _keyedLimit, _stopAfter));
  3369. }
  3370. sentsome.signal();
  3371. rowLimit = _rowLimit;
  3372. keyedLimit = _keyedLimit;
  3373. stopAfter = _stopAfter;
  3374. }
  3375. virtual void stop(bool aborting)
  3376. {
  3377. #ifdef TRACE_STARTSTOP
  3378. if (traceStartStop)
  3379. activity.queryLogCtx().CTXLOG("RRAstop");
  3380. #endif
  3381. onStop(aborting);
  3382. owner->stop(aborting);
  3383. }
  3384. void onStop(bool aborting)
  3385. {
  3386. #ifdef TRACE_STARTSTOP
  3387. if (traceStartStop)
  3388. activity.queryLogCtx().CTXLOG("RRAonstop");
  3389. #endif
  3390. abortPending();
  3391. interruptBuffers(NULL);
  3392. sentsome.interrupt();
  3393. if (mc) // May not be set if start() chain threw exception
  3394. mc->interrupt();
  3395. }
  3396. virtual void reset()
  3397. {
  3398. #ifdef TRACE_STARTSTOP
  3399. if (traceStartStop)
  3400. activity.queryLogCtx().CTXLOG("RRAreset");
  3401. #endif
  3402. owner->reset();
  3403. onReset();
  3404. }
  3405. virtual void resetEOF()
  3406. {
  3407. throwUnexpected();
  3408. }
  3409. virtual void onReset()
  3410. {
  3411. #ifdef TRACE_STARTSTOP
  3412. if (traceStartStop)
  3413. activity.queryLogCtx().CTXLOG("RRAonreset");
  3414. #endif
  3415. if (mc)
  3416. ROQ->queryReceiveManager()->detachCollator(mc);
  3417. merger.reset();
  3418. pending.kill();
  3419. if (mc && ctx)
  3420. ctx->addSlavesReplyLen(mc->queryBytesReceived());
  3421. mc.clear(); // Or we won't free memory for graphs that get recreated
  3422. mu.clear(); //ditto
  3423. mergeOrder = NULL; // MORE - is that needed?
  3424. deferredStart = false;
  3425. }
  3426. virtual IOutputMetaData * queryOutputMeta() const
  3427. {
  3428. return helper.queryOutputMeta();
  3429. }
  3430. virtual unsigned __int64 queryTotalCycles() const
  3431. {
  3432. return totalCycles;
  3433. }
  3434. virtual unsigned __int64 queryLocalCycles() const
  3435. {
  3436. return owner->queryLocalCycles();
  3437. }
  3438. virtual IRoxieInput *queryInput(unsigned idx) const
  3439. {
  3440. return owner->queryInput(idx);
  3441. }
  3442. const void * nextSteppedGE(const void *seek, const void *rawSeek, unsigned numFields, unsigned seekLen, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  3443. {
  3444. if (activity.queryLogCtx().queryTraceLevel() > 10)
  3445. {
  3446. StringBuffer recstr;
  3447. unsigned i;
  3448. for (i = 0; i < seekLen; i++)
  3449. {
  3450. recstr.appendf("%02x ", ((unsigned char *) rawSeek)[i]);
  3451. }
  3452. activity.queryLogCtx().CTXLOG("CRemoteResultAdaptor::nextSteppedGE(rawSeek=%s numFields=%d, seeklen=%d, returnMismatches=%d)", recstr.str(), numFields, seekLen, stepExtra.returnMismatches());
  3453. }
  3454. assertex(mergeOrder);
  3455. if (deferredStart)
  3456. {
  3457. CriticalBlock b(pendingCrit);
  3458. ForEachItemIn(idx, pending)
  3459. {
  3460. IRoxieServerQueryPacket &p = pending.item(idx);
  3461. if (p.isDelayed())
  3462. {
  3463. p.setDelayed(false);
  3464. if (activity.queryLogCtx().queryTraceLevel() > 10)
  3465. activity.queryLogCtx().CTXLOG("About to send deferred start from nextSteppedGE, setting requireExact to %d", !stepExtra.returnMismatches());
  3466. MemoryBuffer serializedSkip;
  3467. activity.serializeSkipInfo(serializedSkip, seekLen, rawSeek, numFields, seek, stepExtra);
  3468. p.setPacket(p.queryPacket()->insertSkipData(serializedSkip.length(), serializedSkip.toByteArray()));
  3469. ROQ->sendPacket(p.queryPacket(), activity.queryLogCtx());
  3470. sentsome.signal();
  3471. }
  3472. }
  3473. deferredStart = false;
  3474. }
  3475. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  3476. if (processed==stopAfter)
  3477. return NULL;
  3478. if (allread)
  3479. return NULL;
  3480. loop
  3481. {
  3482. if (merger.ready())
  3483. {
  3484. const void *got = merger.nextSteppedGE(seek, rawSeek, numFields, seekLen, wasCompleteMatch, stepExtra);
  3485. if (got)
  3486. {
  3487. processRow(got);
  3488. return got;
  3489. }
  3490. }
  3491. if (!reload()) // MORE - should pass the seek info here...
  3492. return NULL;
  3493. }
  3494. }
  3495. virtual const void *nextInGroup()
  3496. {
  3497. // If we are merging then we need to do a heapsort on all
  3498. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  3499. if (activity.queryLogCtx().queryTraceLevel() > 10)
  3500. {
  3501. activity.queryLogCtx().CTXLOG("CRemoteResultAdaptor::nextInGroup()");
  3502. }
  3503. loop
  3504. {
  3505. checkDelayed();
  3506. if (processed==stopAfter)
  3507. return NULL;
  3508. if (allread)
  3509. return NULL;
  3510. // If we can still consume from the merger or the most recently retrieved mu, do so.
  3511. const void *got = NULL;
  3512. if (mergeOrder && merger.ready())
  3513. {
  3514. bool matched = true;
  3515. got = merger.next(matched, dummySmartStepExtra);
  3516. }
  3517. else if (mu)
  3518. got = getRow(mu);
  3519. if (got)
  3520. {
  3521. processRow(got);
  3522. return got;
  3523. }
  3524. if (!reload())
  3525. return NULL;
  3526. }
  3527. }
  3528. bool reload()
  3529. {
  3530. // Wait for something to be returned from a slave....
  3531. mu.clear();
  3532. sentsome.wait();
  3533. // must be at least an endMarker on the queue since sentsome was signalled
  3534. {
  3535. CriticalBlock b(pendingCrit);
  3536. IRoxieServerQueryPacket &top = pending.item(0);
  3537. if (top.isLimit(rowLimit, keyedLimit, stopAfter)) // This is really a start marker...
  3538. {
  3539. pending.remove(0);
  3540. return true;
  3541. }
  3542. else if (top.isEnd())
  3543. {
  3544. pending.remove(0);
  3545. allread = true;
  3546. if (activity.queryLogCtx().queryTraceLevel() > 5)
  3547. activity.queryLogCtx().CTXLOG("All read on ruid %x", ruid);
  3548. return false;
  3549. }
  3550. else if (mergeOrder)
  3551. {
  3552. unsigned idx = 0;
  3553. bool added = false;
  3554. while (pending.isItem(idx))
  3555. {
  3556. IRoxieServerQueryPacket &item = pending.item(idx);
  3557. if (item.isEnd())
  3558. {
  3559. if (merger.noteEndSeen())
  3560. {
  3561. sentsome.signal(); // Because we waited, yet didn't actually consume anything
  3562. added = true;
  3563. }
  3564. break;
  3565. }
  3566. else if (item.hasResult())
  3567. {
  3568. merger.noteResult(&item, item.getSequence());
  3569. pending.remove(idx);
  3570. added = true;
  3571. }
  3572. else if (item.isContinuation())
  3573. idx++;
  3574. else
  3575. break;
  3576. }
  3577. if (added)
  3578. return true;
  3579. }
  3580. else if (top.hasResult())
  3581. {
  3582. mr.setown(pending.item(0).getResult());
  3583. mu.setown(mr->getCursor(rowManager));
  3584. pending.remove(0);
  3585. return true;
  3586. }
  3587. }
  3588. getNextUnpacker();
  3589. return true;
  3590. }
  3591. void getNextUnpacker()
  3592. {
  3593. mu.clear();
  3594. unsigned ctxTraceLevel = activity.queryLogCtx().queryTraceLevel();
  3595. loop
  3596. {
  3597. checkDelayed();
  3598. unsigned timeout = remoteId.isSLAPriority() ? slaTimeout : (remoteId.isHighPriority() ? highTimeout : lowTimeout);
  3599. owner->checkAbort();
  3600. bool anyActivity;
  3601. if (ctxTraceLevel > 5)
  3602. activity.queryLogCtx().CTXLOG("Calling getNextUnpacker(%d)", timeout);
  3603. mr.setown(mc->getNextResult(timeout, anyActivity));
  3604. if (ctxTraceLevel > 6)
  3605. activity.queryLogCtx().CTXLOG("Called getNextUnpacker(%d), activity=%d", timeout, anyActivity);
  3606. owner->checkAbort();
  3607. if (mr)
  3608. {
  3609. unsigned roxieHeaderLen;
  3610. const RoxiePacketHeader &header = *(const RoxiePacketHeader *) mr->getMessageHeader(roxieHeaderLen);
  3611. #ifdef _DEBUG
  3612. assertex(roxieHeaderLen == sizeof(RoxiePacketHeader));
  3613. #endif
  3614. if (ctxTraceLevel > 5)
  3615. {
  3616. StringBuffer s;
  3617. activity.queryLogCtx().CTXLOG("getNextUnpacker got packet %s", header.toString(s).str());
  3618. }
  3619. CriticalBlock b(pendingCrit);
  3620. unsigned idx = 0;
  3621. IRoxieServerQueryPacket *original = NULL;
  3622. IRoxieQueryPacket *op;
  3623. while (pending.isItem(idx))
  3624. {
  3625. original = &pending.item(idx);
  3626. op = original->queryPacket();
  3627. if (op && header.matchPacket(op->queryHeader()))
  3628. break;
  3629. original = NULL;
  3630. idx++;
  3631. }
  3632. if (!original || original->hasResult())
  3633. {
  3634. switch (header.activityId)
  3635. {
  3636. case ROXIE_FILECALLBACK:
  3637. {
  3638. // tell slave to abort
  3639. //if (ctxTraceLevel > 5)
  3640. {
  3641. StringBuffer s;
  3642. activity.queryLogCtx().CTXLOG("Redundant callback on query %s", header.toString(s).str());
  3643. }
  3644. Owned<IMessageUnpackCursor> callbackData = mr->getCursor(rowManager);
  3645. OwnedConstRoxieRow len = callbackData->getNext(sizeof(RecordLengthType));
  3646. if (len)
  3647. {
  3648. RecordLengthType *rowlen = (RecordLengthType *) len.get();
  3649. OwnedConstRoxieRow row = callbackData->getNext(*rowlen);
  3650. const char *rowdata = (const char *) row.get();
  3651. // bool isOpt = * (bool *) rowdata;
  3652. // bool isLocal = * (bool *) (rowdata+1);
  3653. ROQ->sendAbortCallback(header, rowdata+2, activity.queryLogCtx());
  3654. }
  3655. else
  3656. throwUnexpected();
  3657. break;
  3658. }
  3659. // MORE - ROXIE_ALIVE perhaps should go here too
  3660. case ROXIE_TRACEINFO:
  3661. {
  3662. Owned<IMessageUnpackCursor> extra = mr->getCursor(rowManager);
  3663. loop
  3664. {
  3665. RecordLengthType *rowlen = (RecordLengthType *) extra->getNext(sizeof(RecordLengthType));
  3666. if (rowlen)
  3667. {
  3668. char *logInfo = (char *) extra->getNext(*rowlen);
  3669. MemoryBuffer buf;
  3670. buf.setBuffer(*rowlen, logInfo, false);
  3671. activity.queryLogCtx().CTXLOGl(new LogItem(buf));
  3672. ReleaseRoxieRow(rowlen);
  3673. ReleaseRoxieRow(logInfo);
  3674. }
  3675. else
  3676. break;
  3677. }
  3678. break;
  3679. }
  3680. default:
  3681. if (ctxTraceLevel > 3)
  3682. activity.queryLogCtx().CTXLOG("Discarding packet %p - original %p is NULL or has result already", mr.get(), original);
  3683. mr->discard();
  3684. break;
  3685. }
  3686. mr.clear();
  3687. }
  3688. else
  3689. {
  3690. atomic_inc(&resultsReceived);
  3691. switch (header.activityId)
  3692. {
  3693. case ROXIE_DEBUGCALLBACK:
  3694. {
  3695. Owned<IMessageUnpackCursor> callbackData = mr->getCursor(rowManager);
  3696. OwnedConstRoxieRow len = callbackData->getNext(sizeof(RecordLengthType));
  3697. if (len)
  3698. {
  3699. RecordLengthType *rowlen = (RecordLengthType *) len.get();
  3700. OwnedConstRoxieRow row = callbackData->getNext(*rowlen);
  3701. char *rowdata = (char *) row.get();
  3702. //if (ctxTraceLevel > 5)
  3703. {
  3704. StringBuffer s;
  3705. activity.queryLogCtx().CTXLOG("Callback on query %s for debug", header.toString(s).str());
  3706. }
  3707. MemoryBuffer slaveInfo;
  3708. slaveInfo.setBuffer(*rowlen, rowdata, false);
  3709. unsigned debugSequence;
  3710. slaveInfo.read(debugSequence);
  3711. Owned<IRoxieQueryPacket> reply = original->getDebugResponse(debugSequence);
  3712. if (!reply)
  3713. reply.setown(activity.queryContext()->queryDebugContext()->onDebugCallback(header, *rowlen, rowdata));
  3714. if (reply)
  3715. {
  3716. original->setDebugResponse(debugSequence, reply);
  3717. ROQ->sendPacket(reply, activity.queryLogCtx());
  3718. }
  3719. }
  3720. else
  3721. throwUnexpected();
  3722. // MORE - somehow we need to make sure slave gets a reply even if I'm not waiting (in udp layer)
  3723. // Leave original message on pending queue in original location - this is not a reply to it.
  3724. break;
  3725. }
  3726. case ROXIE_FILECALLBACK:
  3727. {
  3728. // we need to send back to the slave a message containing the file info requested.
  3729. Owned<IMessageUnpackCursor> callbackData = mr->getCursor(rowManager);
  3730. OwnedConstRoxieRow len = callbackData->getNext(sizeof(RecordLengthType));
  3731. if (len)
  3732. {
  3733. RecordLengthType *rowlen = (RecordLengthType *) len.get();
  3734. OwnedConstRoxieRow row = callbackData->getNext(*rowlen);
  3735. const char *rowdata = (const char *) row.get();
  3736. bool isOpt = * (bool *) rowdata;
  3737. bool isLocal = * (bool *) (rowdata+1);
  3738. const char *lfn = rowdata+2;
  3739. //if (ctxTraceLevel > 5)
  3740. {
  3741. StringBuffer s;
  3742. activity.queryLogCtx().CTXLOG("Callback on query %s file %s", header.toString(s).str(),(const char *) lfn);
  3743. }
  3744. activity.queryContext()->onFileCallback(header, lfn, isOpt, isLocal);
  3745. }
  3746. else
  3747. throwUnexpected();
  3748. // MORE - somehow we need to make sure slave gets a reply even if I'm not waiting (in udp layer)
  3749. // Leave original message on pending queue in original location - this is not a reply to it.
  3750. break;
  3751. }
  3752. case ROXIE_KEYEDLIMIT_EXCEEDED:
  3753. activity.queryLogCtx().CTXLOG("ROXIE_KEYEDLIMIT_EXCEEDED");
  3754. errorHandler->onLimitExceeded(true); // NOTE - should throw exception!
  3755. throwUnexpected();
  3756. case ROXIE_LIMIT_EXCEEDED:
  3757. activity.queryLogCtx().CTXLOG("ROXIE_LIMIT_EXCEEDED");
  3758. errorHandler->onLimitExceeded(false); // NOTE - should throw exception!
  3759. throwUnexpected();
  3760. case ROXIE_TRACEINFO:
  3761. {
  3762. Owned<IMessageUnpackCursor> extra = mr->getCursor(rowManager);
  3763. loop
  3764. {
  3765. RecordLengthType *rowlen = (RecordLengthType *) extra->getNext(sizeof(RecordLengthType));
  3766. if (rowlen)
  3767. {
  3768. char *logInfo = (char *) extra->getNext(*rowlen);
  3769. MemoryBuffer buf;
  3770. buf.setBuffer(*rowlen, logInfo, false);
  3771. activity.queryLogCtx().CTXLOGl(new LogItem(buf));
  3772. ReleaseRoxieRow(rowlen);
  3773. ReleaseRoxieRow(logInfo);
  3774. }
  3775. else
  3776. break;
  3777. }
  3778. break;
  3779. }
  3780. case ROXIE_EXCEPTION:
  3781. if (ctxTraceLevel > 1)
  3782. {
  3783. StringBuffer s;
  3784. activity.queryLogCtx().CTXLOG("Exception on query %s", header.toString(s).str());
  3785. }
  3786. op->queryHeader().noteException(header.retries);
  3787. if (op->queryHeader().allChannelsFailed())
  3788. {
  3789. activity.queryLogCtx().CTXLOG("Multiple exceptions on query - aborting");
  3790. Owned<IMessageUnpackCursor> exceptionData = mr->getCursor(rowManager);
  3791. throwRemoteException(exceptionData);
  3792. }
  3793. // Leave it on pending queue in original location
  3794. break;
  3795. case ROXIE_ALIVE:
  3796. if (ctxTraceLevel > 4)
  3797. {
  3798. StringBuffer s;
  3799. activity.queryLogCtx().CTXLOG("ROXIE_ALIVE: %s", header.toString(s).str());
  3800. }
  3801. op->queryHeader().noteAlive(header.retries & ROXIE_RETRIES_MASK);
  3802. // Leave it on pending queue in original location
  3803. break;
  3804. default:
  3805. if (header.retries & ROXIE_RETRIES_MASK)
  3806. atomic_inc(&retriesNeeded);
  3807. unsigned metaLen;
  3808. const void *metaData = mr->getMessageMetadata(metaLen);
  3809. if (metaLen)
  3810. {
  3811. // We got back first chunk but there is more.
  3812. // resend the packet, with the cursor info provided.
  3813. // MORE - if smart-stepping, we don't want to send the continuation immediately. Other cases it's not clear that we do.
  3814. if (ctxTraceLevel > 1)
  3815. {
  3816. StringBuffer s;
  3817. activity.queryLogCtx().CTXLOG("Additional data size %d on query %s mergeOrder %p", metaLen, header.toString(s).str(), mergeOrder);
  3818. }
  3819. if (*((unsigned short *) metaData) + sizeof(unsigned short) != metaLen)
  3820. {
  3821. StringBuffer s;
  3822. activity.queryLogCtx().CTXLOG("Additional data size %d on query %s mergeOrder %p", metaLen, header.toString(s).str(), mergeOrder);
  3823. activity.queryLogCtx().CTXLOG("Additional data is corrupt");
  3824. throwUnexpected();
  3825. }
  3826. MemoryBuffer nextQuery;
  3827. nextQuery.append(sizeof(RoxiePacketHeader), &header);
  3828. nextQuery.append(metaLen, metaData);
  3829. nextQuery.append(op->getTraceLength(), op->queryTraceInfo());
  3830. nextQuery.append(op->getContextLength(), op->queryContextData());
  3831. if (resendSequence == CONTINUESEQUENCE_MAX)
  3832. {
  3833. activity.queryLogCtx().CTXLOG("ERROR: Continuation sequence wrapped"); // shouldn't actually matter.... but suggests a very iffy query!
  3834. resendSequence = 1;
  3835. }
  3836. else
  3837. resendSequence++;
  3838. RoxiePacketHeader *newHeader = (RoxiePacketHeader *) nextQuery.toByteArray();
  3839. newHeader->continueSequence = resendSequence; // NOTE - we clear the skipTo flag since continuation of a skip is NOT a skip...
  3840. newHeader->retries &= ~ROXIE_RETRIES_MASK;
  3841. IRoxieQueryPacket *resend = createRoxiePacket(nextQuery);
  3842. CRoxieServerQueryPacket *fqp = new CRoxieServerQueryPacket(resend);
  3843. fqp->setSequence(original->getSequence());
  3844. pending.add(*fqp, idx+1); // note that pending takes ownership. sendPacket does not release.
  3845. original->setContinuation(LINK(fqp));
  3846. if (mergeOrder)
  3847. fqp->setDelayed(true);
  3848. else
  3849. {
  3850. ROQ->sendPacket(resend, activity.queryLogCtx());
  3851. sentsome.signal();
  3852. }
  3853. // Note that we don't attempt to cache results that have continuation records - too tricky !
  3854. }
  3855. else
  3856. {
  3857. if (serverSideCache)
  3858. serverSideCache->noteCachedResult(original, mr);
  3859. }
  3860. unsigned channel = header.channel;
  3861. {
  3862. ChannelBuffer *b = queryChannelBuffer(channel); // If not something is wrong, or we sent out on channel 0?
  3863. if (b)
  3864. b->signal();
  3865. }
  3866. original->setResult(mr.getClear());
  3867. sentsome.signal();
  3868. return;
  3869. }
  3870. }
  3871. }
  3872. else
  3873. {
  3874. if (!anyActivity)
  3875. {
  3876. activity.queryLogCtx().CTXLOG("Input has stalled - retry required?");
  3877. retryPending();
  3878. }
  3879. }
  3880. }
  3881. }
  3882. inline unsigned headerLength() const
  3883. {
  3884. return logInfo.length() + cachedContext.length() + sizeof(unsigned) + parentExtractSize;
  3885. }
  3886. void copyHeader(byte *tgt, unsigned channel) const
  3887. {
  3888. unsigned len = logInfo.length();
  3889. memcpy(tgt, logInfo.toByteArray(), len);
  3890. tgt += len;
  3891. *(unsigned *) tgt = parentExtractSize;
  3892. tgt += sizeof(unsigned);
  3893. memcpy(tgt, parentExtract, parentExtractSize);
  3894. tgt += parentExtractSize;
  3895. memcpy(tgt, cachedContext.toByteArray(), cachedContext.length());
  3896. tgt += cachedContext.length();
  3897. }
  3898. };
  3899. class CSkippableRemoteResultAdaptor : public CRemoteResultAdaptor
  3900. {
  3901. Owned <IException> exception;
  3902. bool skipping;
  3903. ConstPointerArray buff;
  3904. unsigned index;
  3905. bool pulled;
  3906. void pullInput()
  3907. {
  3908. try
  3909. {
  3910. if (exception)
  3911. throw exception.getClear();
  3912. unsigned __int64 count = 0;
  3913. loop
  3914. {
  3915. const void * next = CRemoteResultAdaptor::nextInGroup();
  3916. if (next == NULL)
  3917. {
  3918. next = CRemoteResultAdaptor::nextInGroup();
  3919. if(next == NULL)
  3920. break;
  3921. buff.append(NULL);
  3922. }
  3923. count++;
  3924. if (count > rowLimit)
  3925. {
  3926. ReleaseRoxieRow(next);
  3927. ReleaseRoxieRowSet(buff);
  3928. errorHandler->onLimitExceeded(false); // throws an exception - user or LimitSkipException
  3929. throwUnexpected();
  3930. }
  3931. else if (count > keyedLimit)
  3932. {
  3933. ReleaseRoxieRow(next);
  3934. ReleaseRoxieRowSet(buff);
  3935. errorHandler->onLimitExceeded(true); // throws an exception - user or LimitSkipException
  3936. throwUnexpected();
  3937. }
  3938. buff.append(next);
  3939. }
  3940. }
  3941. catch (IException *E)
  3942. {
  3943. if (QUERYINTERFACE(E, LimitSkipException))
  3944. {
  3945. Owned<IException> cleanup = E;
  3946. ReleaseRoxieRowSet(buff);
  3947. const void *onfail = errorHandler->createLimitFailRow(E->errorCode() == KeyedLimitSkipErrorCode);
  3948. if (onfail)
  3949. buff.append(onfail);
  3950. }
  3951. else
  3952. throw;
  3953. }
  3954. pulled = true;
  3955. }
  3956. public:
  3957. CSkippableRemoteResultAdaptor(const RemoteActivityId &_remoteId, IOutputMetaData *_meta, IHThorArg &_helper, IRoxieServerActivity &_activity, bool _preserveOrder, bool _flowControlled, bool _skipping) :
  3958. CRemoteResultAdaptor(_remoteId, _meta, _helper, _activity, _preserveOrder, _flowControlled)
  3959. {
  3960. skipping = _skipping;
  3961. index = 0;
  3962. pulled = false;
  3963. }
  3964. void setException(IException *E)
  3965. {
  3966. exception.setown(E);
  3967. }
  3968. virtual void onReset()
  3969. {
  3970. while (buff.isItem(index))
  3971. ReleaseRoxieRow(buff.item(index++));
  3972. buff.kill();
  3973. pulled = false;
  3974. exception.clear();
  3975. CRemoteResultAdaptor::onReset();
  3976. }
  3977. void onStart(unsigned _parentExtractSize, const byte * _parentExtract)
  3978. {
  3979. index = 0;
  3980. pulled = false;
  3981. CRemoteResultAdaptor::onStart(_parentExtractSize, _parentExtract);
  3982. }
  3983. virtual const void * nextSteppedGE(const void *seek, const void *rawSeek, unsigned numFields, unsigned seeklen, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  3984. {
  3985. // MORE - not sure what we need to do about the skip case... but we need at least this to prevent issues with exception getting lost
  3986. if (exception)
  3987. throw exception.getClear();
  3988. return CRemoteResultAdaptor::nextSteppedGE(seek, rawSeek, numFields, seeklen, wasCompleteMatch, stepExtra);
  3989. }
  3990. virtual const void *nextInGroup()
  3991. {
  3992. if (skipping)
  3993. {
  3994. if(!pulled)
  3995. pullInput();
  3996. if(buff.isItem(index))
  3997. {
  3998. const void * next = buff.item(index++);
  3999. if(next)
  4000. processed++;
  4001. return next;
  4002. }
  4003. return NULL;
  4004. }
  4005. else
  4006. {
  4007. if (exception)
  4008. throw exception.getClear();
  4009. return CRemoteResultAdaptor::nextInGroup();
  4010. }
  4011. }
  4012. };
  4013. //=================================================================================
  4014. class CRoxieServerApplyActivity : public CRoxieServerInternalSinkActivity
  4015. {
  4016. IHThorApplyArg &helper;
  4017. public:
  4018. CRoxieServerApplyActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4019. : CRoxieServerInternalSinkActivity(_factory, _probeManager), helper((IHThorApplyArg &) basehelper)
  4020. {
  4021. }
  4022. virtual void onExecute()
  4023. {
  4024. helper.start();
  4025. loop
  4026. {
  4027. const void * next = input->nextInGroup();
  4028. if (!next)
  4029. {
  4030. next = input->nextInGroup();
  4031. if (!next)
  4032. break;
  4033. }
  4034. helper.apply(next);
  4035. ReleaseRoxieRow(next);
  4036. }
  4037. helper.end();
  4038. }
  4039. };
  4040. class CRoxieServerApplyActivityFactory : public CRoxieServerActivityFactory
  4041. {
  4042. bool isRoot;
  4043. public:
  4044. CRoxieServerApplyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  4045. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  4046. {
  4047. }
  4048. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4049. {
  4050. return new CRoxieServerApplyActivity(this, _probeManager);
  4051. }
  4052. virtual bool isSink() const
  4053. {
  4054. return isRoot;
  4055. }
  4056. };
  4057. IRoxieServerActivityFactory *createRoxieServerApplyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  4058. {
  4059. return new CRoxieServerApplyActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  4060. }
  4061. //=================================================================================
  4062. class CRoxieServerNullActivity : public CRoxieServerActivity
  4063. {
  4064. public:
  4065. CRoxieServerNullActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4066. : CRoxieServerActivity(_factory, _probeManager)
  4067. {
  4068. }
  4069. virtual const void *nextInGroup()
  4070. {
  4071. return NULL;
  4072. }
  4073. };
  4074. IRoxieServerActivity * createRoxieServerNullActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4075. {
  4076. return new CRoxieServerNullActivity(_factory, _probeManager);
  4077. }
  4078. class CRoxieServerNullActivityFactory : public CRoxieServerActivityFactory
  4079. {
  4080. public:
  4081. CRoxieServerNullActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4082. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4083. {
  4084. }
  4085. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4086. {
  4087. return new CRoxieServerNullActivity(this, _probeManager);
  4088. }
  4089. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  4090. {
  4091. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for null activity");
  4092. }
  4093. };
  4094. IRoxieServerActivityFactory *createRoxieServerNullActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4095. {
  4096. return new CRoxieServerNullActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4097. }
  4098. //=================================================================================
  4099. class CRoxieServerPassThroughActivity : public CRoxieServerActivity
  4100. {
  4101. public:
  4102. CRoxieServerPassThroughActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4103. : CRoxieServerActivity(_factory, _probeManager)
  4104. {
  4105. }
  4106. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  4107. {
  4108. return input->gatherConjunctions(collector);
  4109. }
  4110. virtual void resetEOF()
  4111. {
  4112. input->resetEOF();
  4113. }
  4114. virtual const void *nextInGroup()
  4115. {
  4116. const void * next = input->nextInGroup();
  4117. if (next)
  4118. processed++;
  4119. return next;
  4120. }
  4121. virtual bool isPassThrough()
  4122. {
  4123. return true;
  4124. }
  4125. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  4126. {
  4127. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4128. const void * next = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  4129. if (next)
  4130. processed++;
  4131. return next;
  4132. }
  4133. IInputSteppingMeta * querySteppingMeta()
  4134. {
  4135. return input->querySteppingMeta();
  4136. }
  4137. };
  4138. IRoxieServerActivity * createRoxieServerPassThroughActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4139. {
  4140. return new CRoxieServerPassThroughActivity(_factory, _probeManager);
  4141. }
  4142. //=================================================================================
  4143. class CRoxieServerChildBaseActivity : public CRoxieServerActivity
  4144. {
  4145. protected:
  4146. bool eof;
  4147. bool first;
  4148. public:
  4149. CRoxieServerChildBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4150. : CRoxieServerActivity(_factory, _probeManager)
  4151. {
  4152. eof = false;
  4153. first = true;
  4154. }
  4155. ~CRoxieServerChildBaseActivity()
  4156. {
  4157. }
  4158. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  4159. {
  4160. eof = false;
  4161. first = true;
  4162. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  4163. }
  4164. };
  4165. class CRoxieServerChildBaseActivityFactory : public CRoxieServerActivityFactory
  4166. {
  4167. public:
  4168. CRoxieServerChildBaseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4169. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4170. {
  4171. }
  4172. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  4173. {
  4174. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for %s activity", getActivityText(kind));
  4175. }
  4176. };
  4177. //=================================================================================
  4178. class CRoxieServerChildIteratorActivity : public CRoxieServerChildBaseActivity
  4179. {
  4180. IHThorChildIteratorArg &helper;
  4181. public:
  4182. CRoxieServerChildIteratorActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4183. : CRoxieServerChildBaseActivity(_factory, _probeManager), helper((IHThorChildIteratorArg &) basehelper)
  4184. {
  4185. }
  4186. virtual bool needsAllocator() const { return true; }
  4187. virtual const void *nextInGroup()
  4188. {
  4189. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4190. if (eof)
  4191. return NULL;
  4192. bool ok;
  4193. if (first)
  4194. {
  4195. ok = helper.first();
  4196. first = false;
  4197. }
  4198. else
  4199. ok = helper.next();
  4200. try
  4201. {
  4202. while (ok)
  4203. {
  4204. processed++;
  4205. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  4206. unsigned outSize = helper.transform(rowBuilder);
  4207. if (outSize)
  4208. return rowBuilder.finalizeRowClear(outSize);
  4209. ok = helper.next();
  4210. }
  4211. }
  4212. catch (IException *E)
  4213. {
  4214. throw makeWrappedException(E);
  4215. }
  4216. eof = true;
  4217. return NULL;
  4218. }
  4219. };
  4220. class CRoxieServerChildIteratorActivityFactory : public CRoxieServerChildBaseActivityFactory
  4221. {
  4222. public:
  4223. CRoxieServerChildIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4224. : CRoxieServerChildBaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4225. {
  4226. }
  4227. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4228. {
  4229. return new CRoxieServerChildIteratorActivity(this, _probeManager);
  4230. }
  4231. };
  4232. IRoxieServerActivityFactory *createRoxieServerChildIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4233. {
  4234. return new CRoxieServerChildIteratorActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4235. }
  4236. //=================================================================================
  4237. class CRoxieServerChildNormalizeActivity : public CRoxieServerChildBaseActivity
  4238. {
  4239. IHThorChildNormalizeArg &helper;
  4240. public:
  4241. CRoxieServerChildNormalizeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4242. : CRoxieServerChildBaseActivity(_factory, _probeManager), helper((IHThorChildNormalizeArg &) basehelper)
  4243. {
  4244. }
  4245. virtual bool needsAllocator() const { return true; }
  4246. virtual const void *nextInGroup()
  4247. {
  4248. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4249. if (eof)
  4250. return NULL;
  4251. bool ok;
  4252. if (first)
  4253. {
  4254. ok = helper.first();
  4255. first = false;
  4256. }
  4257. else
  4258. ok = helper.next();
  4259. if (ok)
  4260. {
  4261. try
  4262. {
  4263. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  4264. do {
  4265. unsigned outSize = helper.transform(rowBuilder);
  4266. if (outSize)
  4267. {
  4268. processed++;
  4269. return rowBuilder.finalizeRowClear(outSize);
  4270. }
  4271. ok = helper.next();
  4272. }
  4273. while (ok);
  4274. }
  4275. catch (IException *E)
  4276. {
  4277. throw makeWrappedException(E);
  4278. }
  4279. }
  4280. eof = true;
  4281. return NULL;
  4282. }
  4283. };
  4284. class CRoxieServerChildNormalizeActivityFactory : public CRoxieServerChildBaseActivityFactory
  4285. {
  4286. public:
  4287. CRoxieServerChildNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4288. : CRoxieServerChildBaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4289. {
  4290. }
  4291. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4292. {
  4293. return new CRoxieServerChildNormalizeActivity(this, _probeManager);
  4294. }
  4295. };
  4296. IRoxieServerActivityFactory *createRoxieServerNewChildNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4297. {
  4298. return new CRoxieServerChildNormalizeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4299. }
  4300. //=================================================================================
  4301. class CRoxieServerChildAggregateActivity : public CRoxieServerChildBaseActivity
  4302. {
  4303. IHThorChildAggregateArg &helper;
  4304. public:
  4305. CRoxieServerChildAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4306. : CRoxieServerChildBaseActivity(_factory, _probeManager), helper((IHThorChildAggregateArg &) basehelper)
  4307. {
  4308. }
  4309. virtual bool needsAllocator() const { return true; }
  4310. virtual const void *nextInGroup()
  4311. {
  4312. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4313. if (eof)
  4314. return NULL;
  4315. eof = true;
  4316. processed++;
  4317. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  4318. helper.clearAggregate(rowBuilder);
  4319. helper.processRows(rowBuilder);
  4320. size32_t finalSize = meta.getRecordSize(rowBuilder.getSelf());
  4321. return rowBuilder.finalizeRowClear(finalSize);
  4322. }
  4323. };
  4324. class CRoxieServerChildAggregateActivityFactory : public CRoxieServerChildBaseActivityFactory
  4325. {
  4326. public:
  4327. CRoxieServerChildAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4328. : CRoxieServerChildBaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4329. {
  4330. }
  4331. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4332. {
  4333. return new CRoxieServerChildAggregateActivity(this, _probeManager);
  4334. }
  4335. };
  4336. IRoxieServerActivityFactory *createRoxieServerNewChildAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4337. {
  4338. return new CRoxieServerChildAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4339. }
  4340. //=================================================================================
  4341. class CRoxieServerChildGroupAggregateActivity : public CRoxieServerChildBaseActivity, public IHThorGroupAggregateCallback
  4342. {
  4343. IHThorChildGroupAggregateArg &helper;
  4344. RowAggregator aggregated;
  4345. public:
  4346. IMPLEMENT_IINTERFACE
  4347. CRoxieServerChildGroupAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4348. : CRoxieServerChildBaseActivity(_factory, _probeManager), helper((IHThorChildGroupAggregateArg &) basehelper),
  4349. aggregated(helper, helper)
  4350. {
  4351. }
  4352. void processRow(const void * next)
  4353. {
  4354. aggregated.addRow(next);
  4355. }
  4356. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  4357. {
  4358. CRoxieServerChildBaseActivity::start(parentExtractSize, parentExtract, paused);
  4359. aggregated.start(rowAllocator);
  4360. }
  4361. virtual void reset()
  4362. {
  4363. aggregated.reset();
  4364. CRoxieServerChildBaseActivity::reset();
  4365. }
  4366. virtual bool needsAllocator() const { return true; }
  4367. virtual const void *nextInGroup()
  4368. {
  4369. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4370. if (eof)
  4371. return NULL;
  4372. if (first)
  4373. {
  4374. helper.processRows(this);
  4375. first = false;
  4376. }
  4377. Owned<AggregateRowBuilder> next = aggregated.nextResult();
  4378. if (next)
  4379. {
  4380. processed++;
  4381. return next->finalizeRowClear();
  4382. }
  4383. eof = true;
  4384. return NULL;
  4385. }
  4386. };
  4387. class CRoxieServerChildGroupAggregateActivityFactory : public CRoxieServerChildBaseActivityFactory
  4388. {
  4389. public:
  4390. CRoxieServerChildGroupAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4391. : CRoxieServerChildBaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4392. {
  4393. }
  4394. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4395. {
  4396. return new CRoxieServerChildGroupAggregateActivity(this, _probeManager);
  4397. }
  4398. };
  4399. IRoxieServerActivityFactory *createRoxieServerNewChildGroupAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4400. {
  4401. return new CRoxieServerChildGroupAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4402. }
  4403. //=================================================================================
  4404. class CRoxieServerChildThroughNormalizeActivity : public CRoxieServerChildBaseActivity
  4405. {
  4406. IHThorChildThroughNormalizeArg &helper;
  4407. const void * lastInput;
  4408. unsigned numProcessedLastGroup;
  4409. bool ok;
  4410. public:
  4411. CRoxieServerChildThroughNormalizeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4412. : CRoxieServerChildBaseActivity(_factory, _probeManager), helper((IHThorChildThroughNormalizeArg &) basehelper)
  4413. {
  4414. lastInput = NULL;
  4415. numProcessedLastGroup = 0;
  4416. ok = false;
  4417. }
  4418. virtual void stop(bool aborting)
  4419. {
  4420. CRoxieServerChildBaseActivity::stop(aborting);
  4421. ReleaseRoxieRow(lastInput);
  4422. lastInput = NULL;
  4423. }
  4424. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  4425. {
  4426. CRoxieServerChildBaseActivity::start(parentExtractSize, parentExtract, paused);
  4427. numProcessedLastGroup = processed;
  4428. ok = false;
  4429. }
  4430. virtual bool needsAllocator() const { return true; }
  4431. virtual const void *nextInGroup()
  4432. {
  4433. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4434. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  4435. loop
  4436. {
  4437. if (ok)
  4438. ok = helper.next();
  4439. while (!ok)
  4440. {
  4441. ReleaseRoxieRow(lastInput);
  4442. lastInput = input->nextInGroup();
  4443. if (!lastInput)
  4444. {
  4445. if (numProcessedLastGroup != processed)
  4446. {
  4447. numProcessedLastGroup = processed;
  4448. return NULL;
  4449. }
  4450. lastInput = input->nextInGroup();
  4451. if (!lastInput)
  4452. return NULL;
  4453. }
  4454. ok = helper.first(lastInput);
  4455. }
  4456. try
  4457. {
  4458. do
  4459. {
  4460. unsigned outSize = helper.transform(rowBuilder);
  4461. if (outSize)
  4462. {
  4463. processed++;
  4464. return rowBuilder.finalizeRowClear(outSize);
  4465. }
  4466. ok = helper.next();
  4467. } while (ok);
  4468. }
  4469. catch (IException *E)
  4470. {
  4471. throw makeWrappedException(E);
  4472. }
  4473. }
  4474. }
  4475. };
  4476. class CRoxieServerChildThroughNormalizeActivityFactory : public CRoxieServerActivityFactory
  4477. {
  4478. public:
  4479. CRoxieServerChildThroughNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4480. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4481. {
  4482. }
  4483. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4484. {
  4485. return new CRoxieServerChildThroughNormalizeActivity(this, _probeManager);
  4486. }
  4487. };
  4488. IRoxieServerActivityFactory *createRoxieServerNewChildThroughNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4489. {
  4490. return new CRoxieServerChildThroughNormalizeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4491. }
  4492. //=================================================================================
  4493. class CRoxieServerRawIteratorActivity : public CRoxieServerActivity
  4494. {
  4495. IHThorRawIteratorArg &helper;
  4496. bool eogPending;
  4497. bool eof;
  4498. Owned<IOutputRowDeserializer> rowDeserializer;
  4499. MemoryBuffer tempRowBuffer;
  4500. Owned<ISerialStream> bufferStream;
  4501. CThorStreamDeserializerSource rowSource;
  4502. public:
  4503. CRoxieServerRawIteratorActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4504. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorRawIteratorArg &) basehelper)
  4505. {
  4506. bufferStream.setown(createMemoryBufferSerialStream(tempRowBuffer));
  4507. rowSource.setStream(bufferStream);
  4508. eogPending = false;
  4509. eof = false;
  4510. }
  4511. virtual bool needsAllocator() const { return true; }
  4512. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  4513. {
  4514. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  4515. rowDeserializer.setown(rowAllocator->createRowDeserializer(ctx->queryCodeContext()));
  4516. }
  4517. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  4518. {
  4519. eogPending = false;
  4520. eof = false;
  4521. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  4522. size32_t lenData = 0;
  4523. const void * data = NULL;
  4524. helper.queryDataset(lenData, data);
  4525. tempRowBuffer.setBuffer(lenData, const_cast<void *>(data), false);
  4526. }
  4527. virtual void reset()
  4528. {
  4529. tempRowBuffer.resetBuffer();
  4530. CRoxieServerActivity::reset();
  4531. }
  4532. virtual const void *nextInGroup()
  4533. {
  4534. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4535. if (eof)
  4536. return NULL;
  4537. if (rowSource.eos())
  4538. {
  4539. eof = true;
  4540. return NULL;
  4541. }
  4542. if (eogPending)
  4543. {
  4544. eogPending = false;
  4545. return NULL;
  4546. }
  4547. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  4548. size32_t size = rowDeserializer->deserialize(rowBuilder, rowSource);
  4549. if (meta.isGrouped())
  4550. rowSource.read(sizeof(bool), &eogPending);
  4551. processed++;
  4552. return rowBuilder.finalizeRowClear(size);
  4553. }
  4554. };
  4555. class CRoxieServerRawIteratorActivityFactory : public CRoxieServerActivityFactory
  4556. {
  4557. public:
  4558. CRoxieServerRawIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4559. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4560. {
  4561. }
  4562. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4563. {
  4564. return new CRoxieServerRawIteratorActivity(this, _probeManager);
  4565. }
  4566. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  4567. {
  4568. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for %s activity", getActivityText(kind));
  4569. }
  4570. };
  4571. IRoxieServerActivityFactory *createRoxieServerRawIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4572. {
  4573. return new CRoxieServerRawIteratorActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4574. }
  4575. //=================================================================================
  4576. class CRoxieServerLinkedRawIteratorActivity : public CRoxieServerActivity
  4577. {
  4578. IHThorLinkedRawIteratorArg &helper;
  4579. public:
  4580. CRoxieServerLinkedRawIteratorActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4581. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorLinkedRawIteratorArg &) basehelper)
  4582. {
  4583. }
  4584. virtual const void *nextInGroup()
  4585. {
  4586. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4587. const void *ret =helper.next();
  4588. if (ret)
  4589. {
  4590. LinkRoxieRow(ret);
  4591. processed++;
  4592. }
  4593. return ret;
  4594. }
  4595. };
  4596. class CRoxieServerLinkedRawIteratorActivityFactory : public CRoxieServerActivityFactory
  4597. {
  4598. public:
  4599. CRoxieServerLinkedRawIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4600. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4601. {
  4602. }
  4603. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4604. {
  4605. return new CRoxieServerLinkedRawIteratorActivity(this, _probeManager);
  4606. }
  4607. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  4608. {
  4609. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for %s activity", getActivityText(kind));
  4610. }
  4611. };
  4612. IRoxieServerActivityFactory *createRoxieServerLinkedRawIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4613. {
  4614. return new CRoxieServerLinkedRawIteratorActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4615. }
  4616. //=================================================================================
  4617. class CRoxieServerDatasetResultActivity : public CRoxieServerActivity
  4618. {
  4619. public:
  4620. CRoxieServerDatasetResultActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4621. : CRoxieServerActivity(_factory, _probeManager)
  4622. {
  4623. }
  4624. virtual const void *nextInGroup()
  4625. {
  4626. throwUnexpected();
  4627. }
  4628. virtual void executeChild(size32_t & retSize, void * & ret, unsigned parentExtractSize, const byte * parentExtract)
  4629. {
  4630. try
  4631. {
  4632. start(parentExtractSize, parentExtract, false);
  4633. {
  4634. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4635. MemoryBuffer result;
  4636. IRecordSize * inputMeta = input->queryOutputMeta();
  4637. loop
  4638. {
  4639. const void *nextrec = input->nextInGroup();
  4640. if (!nextrec)
  4641. {
  4642. nextrec = input->nextInGroup();
  4643. if (!nextrec)
  4644. break;
  4645. }
  4646. result.append(inputMeta->getRecordSize(nextrec), nextrec);
  4647. ReleaseRoxieRow(nextrec);
  4648. }
  4649. retSize = result.length();
  4650. ret = result.detach();
  4651. }
  4652. stop(false);
  4653. reset();
  4654. }
  4655. catch(IException *E)
  4656. {
  4657. ctx->notifyAbort(E);
  4658. stop(true);
  4659. reset();
  4660. throw;
  4661. }
  4662. catch(...)
  4663. {
  4664. Owned<IException> E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught at %s:%d", __FILE__, __LINE__);
  4665. ctx->notifyAbort(E);
  4666. stop(true);
  4667. reset();
  4668. throw;
  4669. }
  4670. }
  4671. };
  4672. class CRoxieServerDatasetResultActivityFactory : public CRoxieServerActivityFactory
  4673. {
  4674. bool isRoot;
  4675. public:
  4676. CRoxieServerDatasetResultActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  4677. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  4678. {
  4679. }
  4680. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4681. {
  4682. return new CRoxieServerDatasetResultActivity(this, _probeManager);
  4683. }
  4684. virtual bool isSink() const
  4685. {
  4686. return isRoot;
  4687. }
  4688. };
  4689. IRoxieServerActivityFactory *createRoxieServerDatasetResultActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  4690. {
  4691. return new CRoxieServerDatasetResultActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  4692. }
  4693. //=================================================================================
  4694. /*
  4695. * Deprecated in 3.8, this class is being kept for backward compatibility,
  4696. * since now the code generator is using InlineTables (below) for all
  4697. * temporary tables and rows.
  4698. */
  4699. class CRoxieServerTempTableActivity : public CRoxieServerActivity
  4700. {
  4701. IHThorTempTableArg &helper;
  4702. unsigned curRow;
  4703. unsigned numRows;
  4704. public:
  4705. CRoxieServerTempTableActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4706. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorTempTableArg &) basehelper)
  4707. {
  4708. curRow = 0;
  4709. }
  4710. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  4711. {
  4712. curRow = 0;
  4713. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  4714. numRows = helper.numRows();
  4715. }
  4716. virtual bool needsAllocator() const { return true; }
  4717. virtual const void *nextInGroup()
  4718. {
  4719. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4720. // Filtering empty rows, returns the next valid row
  4721. while (curRow < numRows)
  4722. {
  4723. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  4724. unsigned outSize = helper.getRow(rowBuilder, curRow++);
  4725. if (outSize)
  4726. {
  4727. processed++;
  4728. return rowBuilder.finalizeRowClear(outSize);
  4729. }
  4730. }
  4731. return NULL;
  4732. }
  4733. virtual void setInput(unsigned idx, IRoxieInput *_in)
  4734. {
  4735. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  4736. }
  4737. };
  4738. class CRoxieServerTempTableActivityFactory : public CRoxieServerActivityFactory
  4739. {
  4740. public:
  4741. CRoxieServerTempTableActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4742. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4743. {
  4744. }
  4745. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4746. {
  4747. return new CRoxieServerTempTableActivity(this, _probeManager);
  4748. }
  4749. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  4750. {
  4751. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for TempTable activity");
  4752. }
  4753. };
  4754. IRoxieServerActivityFactory *createRoxieServerTempTableActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4755. {
  4756. return new CRoxieServerTempTableActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4757. }
  4758. //=================================================================================
  4759. class CRoxieServerInlineTableActivity : public CRoxieServerActivity
  4760. {
  4761. IHThorInlineTableArg &helper;
  4762. __uint64 curRow;
  4763. __uint64 numRows;
  4764. public:
  4765. CRoxieServerInlineTableActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4766. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorInlineTableArg &) basehelper)
  4767. {
  4768. }
  4769. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  4770. {
  4771. curRow = 0;
  4772. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  4773. numRows = helper.numRows();
  4774. }
  4775. virtual bool needsAllocator() const { return true; }
  4776. virtual const void *nextInGroup()
  4777. {
  4778. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4779. // Filtering empty rows, returns the next valid row
  4780. while (curRow < numRows)
  4781. {
  4782. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  4783. unsigned outSize = helper.getRow(rowBuilder, curRow++);
  4784. if (outSize)
  4785. {
  4786. processed++;
  4787. return rowBuilder.finalizeRowClear(outSize);
  4788. }
  4789. }
  4790. return NULL;
  4791. }
  4792. virtual void setInput(unsigned idx, IRoxieInput *_in)
  4793. {
  4794. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  4795. }
  4796. };
  4797. class CRoxieServerInlineTableActivityFactory : public CRoxieServerActivityFactory
  4798. {
  4799. public:
  4800. CRoxieServerInlineTableActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4801. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4802. {
  4803. }
  4804. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4805. {
  4806. return new CRoxieServerInlineTableActivity(this, _probeManager);
  4807. }
  4808. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  4809. {
  4810. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for InlineTable activity");
  4811. }
  4812. };
  4813. IRoxieServerActivityFactory *createRoxieServerInlineTableActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4814. {
  4815. return new CRoxieServerInlineTableActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4816. }
  4817. //=================================================================================
  4818. class CRoxieServerWorkUnitReadActivity : public CRoxieServerActivity
  4819. {
  4820. IHThorWorkunitReadArg &helper;
  4821. Owned<IWorkUnitRowReader> wuReader; // MORE - can we use IRoxieInput instead?
  4822. IRoxieServerContext *serverContext;
  4823. public:
  4824. CRoxieServerWorkUnitReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  4825. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorWorkunitReadArg &)basehelper)
  4826. {
  4827. serverContext = NULL;
  4828. }
  4829. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  4830. {
  4831. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  4832. serverContext = ctx->queryServerContext();
  4833. if (!serverContext)
  4834. {
  4835. throw MakeStringException(ROXIE_INTERNAL_ERROR, "Workunit read activity cannot be executed in slave context");
  4836. }
  4837. }
  4838. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  4839. {
  4840. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  4841. IXmlToRowTransformer * xmlTransformer = helper.queryXmlTransformer();
  4842. wuReader.setown(serverContext->getWorkunitRowReader(helper.queryName(), helper.querySequence(), xmlTransformer, rowAllocator, meta.isGrouped()));
  4843. // MORE _ should that be in onCreate?
  4844. }
  4845. virtual void reset()
  4846. {
  4847. wuReader.clear();
  4848. CRoxieServerActivity::reset();
  4849. };
  4850. virtual bool needsAllocator() const { return true; }
  4851. virtual const void *nextInGroup()
  4852. {
  4853. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  4854. const void *ret = wuReader->nextInGroup();
  4855. if (ret)
  4856. processed++;
  4857. return ret;
  4858. }
  4859. virtual void setInput(unsigned idx, IRoxieInput *_in)
  4860. {
  4861. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  4862. }
  4863. };
  4864. class CRoxieServerWorkUnitReadActivityFactory : public CRoxieServerActivityFactory
  4865. {
  4866. public:
  4867. CRoxieServerWorkUnitReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4868. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  4869. {
  4870. }
  4871. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  4872. {
  4873. return new CRoxieServerWorkUnitReadActivity(this, _probeManager);
  4874. }
  4875. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  4876. {
  4877. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for WorkUnitRead activity");
  4878. }
  4879. };
  4880. IRoxieServerActivityFactory *createRoxieServerWorkUnitReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  4881. {
  4882. return new CRoxieServerWorkUnitReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  4883. }
  4884. //=================================================================================
  4885. interface ILocalGraphEx : public ILocalGraph
  4886. {
  4887. public:
  4888. virtual void setResult(unsigned id, IGraphResult * result) = 0;
  4889. virtual IRoxieInput * createResultIterator(unsigned id) = 0;
  4890. virtual void setGraphLoopResult(IGraphResult * result) = 0;
  4891. virtual IRoxieInput * createGraphLoopResultIterator(unsigned id) = 0;
  4892. };
  4893. class CSafeRoxieInput : public CInterface, implements IRoxieInput
  4894. {
  4895. public:
  4896. CSafeRoxieInput(IRoxieInput * _input) : input(_input) {}
  4897. IMPLEMENT_IINTERFACE
  4898. virtual IOutputMetaData * queryOutputMeta() const
  4899. {
  4900. return input->queryOutputMeta();
  4901. }
  4902. virtual unsigned queryId() const
  4903. {
  4904. return input->queryId();
  4905. }
  4906. virtual unsigned __int64 queryTotalCycles() const
  4907. {
  4908. return input->queryTotalCycles();
  4909. }
  4910. virtual unsigned __int64 queryLocalCycles() const
  4911. {
  4912. return input->queryLocalCycles();
  4913. }
  4914. virtual IRoxieInput *queryInput(unsigned idx) const
  4915. {
  4916. return input->queryInput(idx);
  4917. }
  4918. virtual IRoxieServerActivity *queryActivity()
  4919. {
  4920. return input->queryActivity();
  4921. }
  4922. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  4923. {
  4924. return input->queryIndexReadActivity();
  4925. }
  4926. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  4927. {
  4928. CriticalBlock procedure(cs);
  4929. input->start(parentExtractSize, parentExtract, paused);
  4930. }
  4931. virtual void stop(bool aborting)
  4932. {
  4933. CriticalBlock procedure(cs);
  4934. input->stop(aborting);
  4935. }
  4936. virtual void reset()
  4937. {
  4938. CriticalBlock procedure(cs);
  4939. input->reset();
  4940. }
  4941. virtual void resetEOF()
  4942. {
  4943. CriticalBlock procedure(cs);
  4944. input->resetEOF();
  4945. }
  4946. virtual void checkAbort()
  4947. {
  4948. CriticalBlock procedure(cs);
  4949. input->checkAbort();
  4950. }
  4951. virtual const void *nextInGroup()
  4952. {
  4953. CriticalBlock procedure(cs);
  4954. return input->nextInGroup();
  4955. }
  4956. virtual bool nextGroup(ConstPointerArray & group)
  4957. {
  4958. CriticalBlock procedure(cs);
  4959. return input->nextGroup(group);
  4960. }
  4961. private:
  4962. CriticalSection cs;
  4963. Linked<IRoxieInput> input;
  4964. };
  4965. //=================================================================================
  4966. class CPseudoRoxieInput : public CInterface, implements IRoxieInput
  4967. {
  4968. protected:
  4969. unsigned __int64 totalCycles;
  4970. public:
  4971. IMPLEMENT_IINTERFACE;
  4972. CPseudoRoxieInput()
  4973. {
  4974. totalCycles = 0;
  4975. }
  4976. virtual unsigned __int64 queryTotalCycles() const
  4977. {
  4978. return totalCycles;
  4979. }
  4980. virtual unsigned __int64 queryLocalCycles() const
  4981. {
  4982. return totalCycles;
  4983. }
  4984. virtual IRoxieInput *queryInput(unsigned idx) const
  4985. {
  4986. return NULL;
  4987. }
  4988. virtual IRoxieServerActivity *queryActivity()
  4989. {
  4990. throwUnexpected();
  4991. }
  4992. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  4993. {
  4994. throwUnexpected();
  4995. }
  4996. virtual IOutputMetaData * queryOutputMeta() const { throwUnexpected(); }
  4997. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused) { }
  4998. virtual void stop(bool aborting) { }
  4999. virtual void reset() { totalCycles = 0; }
  5000. virtual void checkAbort() { }
  5001. virtual unsigned queryId() const { throwUnexpected(); }
  5002. virtual void resetEOF() { }
  5003. };
  5004. class CIndirectRoxieInput : public CPseudoRoxieInput
  5005. {
  5006. public:
  5007. CIndirectRoxieInput(IRoxieInput * _input = NULL) : input(_input)
  5008. {
  5009. }
  5010. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5011. {
  5012. input->start(parentExtractSize, parentExtract, paused);
  5013. }
  5014. virtual void stop(bool aborting)
  5015. {
  5016. input->stop(aborting);
  5017. }
  5018. virtual void reset()
  5019. {
  5020. input->reset();
  5021. totalCycles = 0;
  5022. }
  5023. virtual void checkAbort()
  5024. {
  5025. input->checkAbort();
  5026. }
  5027. virtual const void * nextInGroup()
  5028. {
  5029. return input->nextInGroup();
  5030. }
  5031. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  5032. {
  5033. return input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  5034. }
  5035. virtual unsigned __int64 queryLocalCycles() const
  5036. {
  5037. __int64 ret = totalCycles - input->queryTotalCycles();
  5038. if (ret < 0)
  5039. ret = 0;
  5040. return ret;
  5041. }
  5042. virtual IRoxieInput *queryInput(unsigned idx) const
  5043. {
  5044. return input->queryInput(idx);
  5045. }
  5046. virtual unsigned queryId() const
  5047. {
  5048. return input->queryId();
  5049. }
  5050. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  5051. {
  5052. return input->gatherConjunctions(collector);
  5053. }
  5054. virtual void resetEOF()
  5055. {
  5056. input->resetEOF();
  5057. }
  5058. virtual unsigned numConcreteOutputs() const
  5059. {
  5060. return input->numConcreteOutputs();
  5061. }
  5062. virtual IRoxieInput * queryConcreteInput(unsigned idx)
  5063. {
  5064. return input->queryConcreteInput(idx);
  5065. }
  5066. virtual IOutputMetaData * queryOutputMeta() const
  5067. {
  5068. return input->queryOutputMeta();
  5069. }
  5070. virtual IRoxieServerActivity *queryActivity()
  5071. {
  5072. return input->queryActivity();
  5073. }
  5074. void setInput(IRoxieInput * _input)
  5075. {
  5076. input = _input;
  5077. }
  5078. protected:
  5079. IRoxieInput * input;
  5080. };
  5081. class CExtractMapperInput : public CIndirectRoxieInput
  5082. {
  5083. unsigned savedParentExtractSize;
  5084. const byte * savedParentExtract;
  5085. public:
  5086. CExtractMapperInput(IRoxieInput * _input = NULL) : CIndirectRoxieInput(_input)
  5087. {
  5088. savedParentExtractSize = 0;
  5089. savedParentExtract = NULL;
  5090. }
  5091. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5092. {
  5093. input->start(savedParentExtractSize, savedParentExtract, paused);
  5094. }
  5095. void setParentExtract(unsigned _savedParentExtractSize, const byte * _savedParentExtract)
  5096. {
  5097. savedParentExtractSize = _savedParentExtractSize;
  5098. savedParentExtract = _savedParentExtract;
  5099. }
  5100. };
  5101. class CGraphResult : public CInterface, implements IGraphResult
  5102. {
  5103. CriticalSection cs;
  5104. CachedOutputMetaData meta;
  5105. ConstPointerArray data;
  5106. Owned<IEngineRowAllocator> rowsetAllocator;
  5107. bool complete;
  5108. void clear()
  5109. {
  5110. CriticalBlock func(cs);
  5111. ReleaseRoxieRowSet(data);
  5112. complete = false;
  5113. }
  5114. public:
  5115. CGraphResult()
  5116. {
  5117. complete = false; // dummy result is not supposed to be used...
  5118. }
  5119. CGraphResult(IEngineRowAllocator * _ownedRowsetAllocator, ConstPointerArray & input, bool own) : rowsetAllocator(_ownedRowsetAllocator)
  5120. {
  5121. meta.set(rowsetAllocator->queryOutputMeta());
  5122. ForEachItemIn(i, input)
  5123. {
  5124. const void * cur = input.item(i);
  5125. if (!own && cur)
  5126. LinkRoxieRow(cur);
  5127. data.append(cur);
  5128. }
  5129. if (own)
  5130. input.kill();
  5131. complete = true;
  5132. }
  5133. CGraphResult(IEngineRowAllocator * _ownedRowsetAllocator, void * row, bool own) : rowsetAllocator(_ownedRowsetAllocator)
  5134. {
  5135. meta.set(rowsetAllocator->queryOutputMeta());
  5136. data.append(row);
  5137. if (!own)
  5138. LinkRoxieRow(row);
  5139. complete = true;
  5140. }
  5141. ~CGraphResult() { clear(); }
  5142. IMPLEMENT_IINTERFACE
  5143. // interface IGraphResult
  5144. virtual IRoxieInput * createIterator()
  5145. {
  5146. if (!complete)
  5147. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Internal Error: Reading uninitialised graph result");
  5148. return new CGraphResultIterator(this);
  5149. }
  5150. virtual void getResult(unsigned & lenResult, void * & result)
  5151. {
  5152. if (!complete)
  5153. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Internal Error: Reading uninitialised graph result");
  5154. bool grouped = meta.isGrouped();
  5155. MemoryBuffer rowdata;
  5156. unsigned max = data.ordinality();
  5157. unsigned i;
  5158. for (i = 0; i < max; i++)
  5159. {
  5160. const void * nextrec = data.item(i);
  5161. size32_t thisSize = meta.getRecordSize(nextrec);
  5162. rowdata.append(thisSize, nextrec);
  5163. if (grouped)
  5164. {
  5165. bool eog = false;
  5166. if (data.isItem(i+1))
  5167. {
  5168. if (!data.item(i+1))
  5169. {
  5170. eog = true;
  5171. i++;
  5172. }
  5173. }
  5174. else
  5175. eog = true;
  5176. rowdata.append(eog);
  5177. }
  5178. }
  5179. lenResult = rowdata.length();
  5180. result = rowdata.detach();
  5181. }
  5182. virtual void getLinkedResult(unsigned & countResult, byte * * & result)
  5183. {
  5184. if (!complete)
  5185. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Internal Error: Reading uninitialised graph result");
  5186. byte * * rowset = rowsetAllocator->createRowset(data.ordinality());
  5187. unsigned max = data.ordinality();
  5188. unsigned i;
  5189. for (i = 0; i < max; i++)
  5190. {
  5191. const void * next = data.item(i);
  5192. if (next) LinkRoxieRow(next);
  5193. rowset[i] = (byte *)next;
  5194. }
  5195. countResult = max;
  5196. result = rowset;
  5197. }
  5198. //other
  5199. const void * getRow(unsigned i)
  5200. {
  5201. CriticalBlock func(cs);
  5202. if (!data.isItem(i))
  5203. return NULL;
  5204. const void * ret = data.item(i);
  5205. if (ret) LinkRoxieRow(ret);
  5206. return ret;
  5207. }
  5208. protected:
  5209. class CGraphResultIterator : public CPseudoRoxieInput
  5210. {
  5211. unsigned i;
  5212. Linked<CGraphResult> result;
  5213. public:
  5214. CGraphResultIterator(CGraphResult * _result) : result(_result) { i = 0; }
  5215. IMPLEMENT_IINTERFACE
  5216. public:
  5217. virtual const void * nextInGroup()
  5218. {
  5219. return result->getRow(i++);
  5220. }
  5221. };
  5222. };
  5223. //=================================================================================
  5224. class CRoxieServerLocalResultReadActivity : public CRoxieServerActivity
  5225. {
  5226. IHThorLocalResultReadArg &helper;
  5227. Owned<IRoxieInput> iter;
  5228. ILocalGraphEx * graph;
  5229. unsigned graphId;
  5230. unsigned sequence;
  5231. public:
  5232. CRoxieServerLocalResultReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId)
  5233. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorLocalResultReadArg &)basehelper), graphId(_graphId)
  5234. {
  5235. graph = NULL;
  5236. sequence = 0;
  5237. }
  5238. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  5239. {
  5240. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  5241. graph = static_cast<ILocalGraphEx *>(_ctx->queryCodeContext()->resolveLocalQuery(graphId));
  5242. sequence = helper.querySequence();
  5243. }
  5244. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5245. {
  5246. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  5247. iter.setown(graph->createResultIterator(sequence));
  5248. }
  5249. virtual void reset()
  5250. {
  5251. iter.clear();
  5252. CRoxieServerActivity::reset();
  5253. };
  5254. virtual const void *nextInGroup()
  5255. {
  5256. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  5257. const void * next = iter->nextInGroup();
  5258. if (next)
  5259. {
  5260. processed++;
  5261. atomic_inc(&rowsIn);
  5262. }
  5263. return next;
  5264. }
  5265. virtual void setInput(unsigned idx, IRoxieInput *_in)
  5266. {
  5267. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  5268. }
  5269. };
  5270. class CRoxieServerLocalResultReadActivityFactory : public CRoxieServerActivityFactory
  5271. {
  5272. unsigned graphId;
  5273. public:
  5274. CRoxieServerLocalResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _graphId)
  5275. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), graphId(_graphId)
  5276. {
  5277. }
  5278. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  5279. {
  5280. return new CRoxieServerLocalResultReadActivity(this, _probeManager, graphId);
  5281. }
  5282. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  5283. {
  5284. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for LocalResultRead activity");
  5285. }
  5286. };
  5287. IRoxieServerActivityFactory *createRoxieServerLocalResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned graphId)
  5288. {
  5289. return new CRoxieServerLocalResultReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, graphId);
  5290. }
  5291. //=================================================================================
  5292. class CRoxieServerLocalResultStreamReadActivity : public CRoxieServerActivity
  5293. {
  5294. IHThorLocalResultReadArg &helper;
  5295. Owned<IRoxieInput> streamInput;
  5296. unsigned sequence;
  5297. public:
  5298. CRoxieServerLocalResultStreamReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  5299. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorLocalResultReadArg &)basehelper)
  5300. {
  5301. sequence = 0;
  5302. }
  5303. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  5304. {
  5305. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  5306. sequence = helper.querySequence();
  5307. }
  5308. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5309. {
  5310. assertex(streamInput != NULL);
  5311. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  5312. streamInput->start(parentExtractSize, parentExtract, paused);
  5313. }
  5314. virtual void stop(bool aborting)
  5315. {
  5316. CRoxieServerActivity::stop(aborting);
  5317. streamInput->stop(aborting);
  5318. }
  5319. virtual void reset()
  5320. {
  5321. streamInput->reset();
  5322. CRoxieServerActivity::reset();
  5323. };
  5324. virtual const void *nextInGroup()
  5325. {
  5326. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  5327. const void * next = streamInput->nextInGroup();
  5328. if (next)
  5329. {
  5330. processed++;
  5331. atomic_inc(&rowsIn);
  5332. }
  5333. return next;
  5334. }
  5335. virtual bool querySetStreamInput(unsigned id, IRoxieInput * _input)
  5336. {
  5337. if (id == sequence)
  5338. {
  5339. streamInput.set(_input);
  5340. return true;
  5341. }
  5342. return false;
  5343. }
  5344. virtual void setInput(unsigned idx, IRoxieInput *_in)
  5345. {
  5346. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  5347. }
  5348. };
  5349. class CRoxieServerLocalResultStreamReadActivityFactory : public CRoxieServerActivityFactory
  5350. {
  5351. public:
  5352. CRoxieServerLocalResultStreamReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  5353. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  5354. {
  5355. }
  5356. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  5357. {
  5358. return new CRoxieServerLocalResultStreamReadActivity(this, _probeManager);
  5359. }
  5360. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  5361. {
  5362. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for LocalResultRead activity");
  5363. }
  5364. };
  5365. IRoxieServerActivityFactory *createRoxieServerLocalResultStreamReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  5366. {
  5367. return new CRoxieServerLocalResultStreamReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  5368. }
  5369. //=====================================================================================================
  5370. class CRoxieServerLocalResultWriteActivity : public CRoxieServerInternalSinkActivity
  5371. {
  5372. IHThorLocalResultWriteArg &helper;
  5373. ILocalGraphEx * graph;
  5374. unsigned graphId;
  5375. public:
  5376. CRoxieServerLocalResultWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId)
  5377. : CRoxieServerInternalSinkActivity(_factory, _probeManager), helper((IHThorLocalResultWriteArg &)basehelper), graphId(_graphId)
  5378. {
  5379. graph = NULL;
  5380. }
  5381. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  5382. {
  5383. CRoxieServerInternalSinkActivity::onCreate(_ctx, _colocalParent);
  5384. graph = static_cast<ILocalGraphEx *>(_ctx->queryCodeContext()->resolveLocalQuery(graphId));
  5385. }
  5386. virtual void onExecute()
  5387. {
  5388. ConstPointerArray rows;
  5389. try
  5390. {
  5391. loop
  5392. {
  5393. const void *nextrec = input->nextInGroup();
  5394. if (!nextrec)
  5395. {
  5396. nextrec = input->nextInGroup();
  5397. if (!nextrec)
  5398. break;
  5399. rows.append(NULL);
  5400. }
  5401. rows.append(nextrec);
  5402. }
  5403. IOutputMetaData *outputMeta = input->queryOutputMeta();
  5404. Owned<CGraphResult> result = new CGraphResult(ctx->queryCodeContext()->getRowAllocator(outputMeta, activityId), rows, true);
  5405. graph->setResult(helper.querySequence(), result);
  5406. }
  5407. catch(...)
  5408. {
  5409. ReleaseRoxieRowSet(rows);
  5410. throw;
  5411. }
  5412. }
  5413. IRoxieInput * querySelectOutput(unsigned id)
  5414. {
  5415. if (id == helper.querySequence())
  5416. {
  5417. executed = true;
  5418. return LINK(input);
  5419. }
  5420. return NULL;
  5421. }
  5422. };
  5423. class CRoxieServerLocalResultWriteActivityFactory : public CRoxieServerInternalSinkFactory
  5424. {
  5425. unsigned graphId;
  5426. public:
  5427. CRoxieServerLocalResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, unsigned _graphId, bool _isRoot)
  5428. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot), graphId(_graphId)
  5429. {
  5430. isInternal = true;
  5431. Owned<IHThorLocalResultWriteArg> helper = (IHThorLocalResultWriteArg *) helperFactory();
  5432. }
  5433. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  5434. {
  5435. return new CRoxieServerLocalResultWriteActivity(this, _probeManager, graphId);
  5436. }
  5437. };
  5438. IRoxieServerActivityFactory *createRoxieServerLocalResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, unsigned _graphId, bool _isRoot)
  5439. {
  5440. return new CRoxieServerLocalResultWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _graphId, _isRoot);
  5441. }
  5442. //=================================================================================
  5443. class CRoxieServerGraphLoopResultReadActivity : public CRoxieServerActivity
  5444. {
  5445. protected:
  5446. IHThorGraphLoopResultReadArg &helper;
  5447. Owned<IRoxieInput> iter;
  5448. ILocalGraphEx * graph;
  5449. unsigned graphId;
  5450. unsigned sequence;
  5451. public:
  5452. CRoxieServerGraphLoopResultReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId)
  5453. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorGraphLoopResultReadArg &)basehelper), graphId(_graphId)
  5454. {
  5455. graph = NULL;
  5456. sequence = 0;
  5457. }
  5458. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  5459. {
  5460. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  5461. graph = static_cast<ILocalGraphEx *>(_ctx->queryCodeContext()->resolveLocalQuery(graphId));
  5462. }
  5463. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5464. {
  5465. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  5466. if (iter)
  5467. iter->start(parentExtractSize, parentExtract, paused);
  5468. else
  5469. {
  5470. sequence = helper.querySequence();
  5471. if ((int)sequence >= 0)
  5472. {
  5473. try
  5474. {
  5475. iter.setown(graph->createGraphLoopResultIterator(sequence));
  5476. }
  5477. catch (IException * E)
  5478. {
  5479. throw makeWrappedException(E);
  5480. }
  5481. }
  5482. }
  5483. }
  5484. virtual void stop(bool aborting)
  5485. {
  5486. if (iter)
  5487. iter->stop(aborting);
  5488. CRoxieServerActivity::stop(aborting);
  5489. }
  5490. virtual void reset()
  5491. {
  5492. if (iter)
  5493. iter->reset();
  5494. iter.clear();
  5495. CRoxieServerActivity::reset();
  5496. };
  5497. virtual const void *nextInGroup()
  5498. {
  5499. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  5500. const void * next = iter ? iter->nextInGroup() : NULL;
  5501. if (next)
  5502. {
  5503. processed++;
  5504. atomic_inc(&rowsIn);
  5505. }
  5506. return next;
  5507. }
  5508. virtual void setInput(unsigned idx, IRoxieInput *_in)
  5509. {
  5510. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  5511. }
  5512. virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract)
  5513. {
  5514. ensureCreated();
  5515. basehelper.onStart(parentExtract, NULL);
  5516. processor.noteUseIteration(helper.querySequence());
  5517. }
  5518. virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract, IProbeManager *probeManager, IArrayOf<IRoxieInput> &probes)
  5519. {
  5520. //helper already initialised from the gratherIterationUsage() call.
  5521. iter.set(processor.connectIterationOutput(helper.querySequence(), probeManager, probes, this, 0));
  5522. }
  5523. };
  5524. //variety of CRoxieServerGraphLoopResultReadActivity created internally with a predefined sequence number
  5525. class CRoxieServerInternalGraphLoopResultReadActivity : public CRoxieServerGraphLoopResultReadActivity
  5526. {
  5527. public:
  5528. CRoxieServerInternalGraphLoopResultReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId, unsigned _sequence)
  5529. : CRoxieServerGraphLoopResultReadActivity(_factory, _probeManager, _graphId)
  5530. {
  5531. sequence = _sequence;
  5532. }
  5533. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5534. {
  5535. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  5536. if ((int)sequence >= 0)
  5537. {
  5538. try
  5539. {
  5540. iter.setown(graph->createGraphLoopResultIterator(sequence));
  5541. }
  5542. catch (IException * E)
  5543. {
  5544. throw makeWrappedException(E);
  5545. }
  5546. }
  5547. }
  5548. };
  5549. class CRoxieServerGraphLoopResultReadActivityFactory : public CRoxieServerActivityFactory
  5550. {
  5551. unsigned graphId;
  5552. public:
  5553. CRoxieServerGraphLoopResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _graphId)
  5554. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), graphId(_graphId)
  5555. {
  5556. }
  5557. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  5558. {
  5559. return new CRoxieServerGraphLoopResultReadActivity(this, _probeManager, graphId);
  5560. }
  5561. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  5562. {
  5563. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for GraphLoopResultRead activity");
  5564. }
  5565. };
  5566. IRoxieServerActivityFactory *createRoxieServerGraphLoopResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned graphId)
  5567. {
  5568. return new CRoxieServerGraphLoopResultReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, graphId);
  5569. }
  5570. //=====================================================================================================
  5571. class CRoxieServerGraphLoopResultWriteActivity : public CRoxieServerInternalSinkActivity
  5572. {
  5573. IHThorGraphLoopResultWriteArg &helper;
  5574. ILocalGraphEx * graph;
  5575. unsigned graphId;
  5576. public:
  5577. CRoxieServerGraphLoopResultWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId)
  5578. : CRoxieServerInternalSinkActivity(_factory, _probeManager), helper((IHThorGraphLoopResultWriteArg &)basehelper), graphId(_graphId)
  5579. {
  5580. graph = NULL;
  5581. }
  5582. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  5583. {
  5584. CRoxieServerInternalSinkActivity::onCreate(_ctx, _colocalParent);
  5585. graph = static_cast<ILocalGraphEx *>(_ctx->queryCodeContext()->resolveLocalQuery(graphId));
  5586. }
  5587. virtual void onExecute()
  5588. {
  5589. ConstPointerArray rows;
  5590. try
  5591. {
  5592. loop
  5593. {
  5594. const void *nextrec = input->nextInGroup();
  5595. if (!nextrec)
  5596. {
  5597. nextrec = input->nextInGroup();
  5598. if (!nextrec)
  5599. break;
  5600. rows.append(NULL);
  5601. }
  5602. rows.append(nextrec);
  5603. }
  5604. IOutputMetaData *outputMeta = input->queryOutputMeta();
  5605. Owned<CGraphResult> result = new CGraphResult(ctx->queryCodeContext()->getRowAllocator(outputMeta, activityId), rows, true);
  5606. graph->setGraphLoopResult(result);
  5607. }
  5608. catch(...)
  5609. {
  5610. ReleaseRoxieRowSet(rows);
  5611. throw;
  5612. }
  5613. }
  5614. virtual IRoxieInput *queryOutput(unsigned idx)
  5615. {
  5616. if (idx==0)
  5617. return this;
  5618. else
  5619. return NULL;
  5620. }
  5621. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  5622. {
  5623. return input->gatherConjunctions(collector);
  5624. }
  5625. virtual void resetEOF()
  5626. {
  5627. input->resetEOF();
  5628. }
  5629. virtual const void *nextInGroup()
  5630. {
  5631. const void * next = input->nextInGroup();
  5632. if (next)
  5633. processed++;
  5634. return next;
  5635. }
  5636. virtual bool isPassThrough()
  5637. {
  5638. return true;
  5639. }
  5640. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  5641. {
  5642. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  5643. const void * next = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  5644. if (next)
  5645. processed++;
  5646. return next;
  5647. }
  5648. IInputSteppingMeta * querySteppingMeta()
  5649. {
  5650. return input->querySteppingMeta();
  5651. }
  5652. virtual IOutputMetaData * queryOutputMeta() const
  5653. {
  5654. return input->queryOutputMeta();
  5655. }
  5656. };
  5657. class CRoxieServerGraphLoopResultWriteActivityFactory : public CRoxieServerInternalSinkFactory
  5658. {
  5659. unsigned graphId;
  5660. public:
  5661. CRoxieServerGraphLoopResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, unsigned _graphId)
  5662. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, true), graphId(_graphId)
  5663. {
  5664. isInternal = true;
  5665. Owned<IHThorGraphLoopResultWriteArg> helper = (IHThorGraphLoopResultWriteArg *) helperFactory();
  5666. }
  5667. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  5668. {
  5669. return new CRoxieServerGraphLoopResultWriteActivity(this, _probeManager, graphId);
  5670. }
  5671. };
  5672. IRoxieServerActivityFactory *createRoxieServerGraphLoopResultWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, unsigned _graphId)
  5673. {
  5674. return new CRoxieServerGraphLoopResultWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _graphId);
  5675. }
  5676. #if 0
  5677. //=====================================================================================================
  5678. CHThorLocalResultSpillActivity::CHThorLocalResultSpillActivity(IAgentContext &_agent, ActivityId const & _id, IHThorLocalResultSpillArg &_arg)
  5679. : CHThorSimpleActivityBase(_agent, _id, _arg), helper(_arg)
  5680. {
  5681. next = NULL;
  5682. }
  5683. void CHThorLocalResultSpillActivity::ready()
  5684. {
  5685. CHThorSimpleActivityBase::ready();
  5686. next = input->nextInGroup();
  5687. grouped = input->isGrouped();
  5688. rowdata.clear();
  5689. }
  5690. const void * CHThorLocalResultSpillActivity::nextInGroup()
  5691. {
  5692. const void * ret = next;
  5693. next = input->nextInGroup();
  5694. if (!ret && !next)
  5695. return NULL;
  5696. if (ret)
  5697. {
  5698. size32_t thisSize = outputMeta->getRecordSize(ret);
  5699. rowdata.append(thisSize, ret);
  5700. if (grouped)
  5701. rowdata.append(next == NULL);
  5702. }
  5703. return ret;
  5704. }
  5705. void CHThorLocalResultSpillActivity::done()
  5706. {
  5707. loop
  5708. {
  5709. const void * ret = nextInGroup();
  5710. if (!ret)
  5711. {
  5712. ret = nextInGroup();
  5713. if (!ret)
  5714. break;
  5715. }
  5716. ReleaseRoxieRow(ret);
  5717. }
  5718. agent.setLocalResult(helper.querySequence(), rowdata.length(), rowdata.toByteArray());
  5719. CHThorSimpleActivityBase::done();
  5720. }
  5721. #endif
  5722. //=================================================================================
  5723. class CRoxieServerDedupActivity : public CRoxieServerActivity
  5724. {
  5725. IHThorDedupArg &helper;
  5726. bool keepLeft;
  5727. bool first;
  5728. unsigned numKept;
  5729. unsigned numToKeep;
  5730. const void *kept;
  5731. public:
  5732. CRoxieServerDedupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _keepLeft)
  5733. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorDedupArg &)basehelper)
  5734. {
  5735. keepLeft = _keepLeft;
  5736. kept = NULL;
  5737. numKept = 0;
  5738. first = true;
  5739. numToKeep = 0;
  5740. }
  5741. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5742. {
  5743. numKept = 0;
  5744. first = true;
  5745. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  5746. numToKeep = helper.numToKeep();
  5747. }
  5748. virtual void reset()
  5749. {
  5750. ReleaseClearRoxieRow(kept);
  5751. CRoxieServerActivity::reset();
  5752. }
  5753. virtual const void * nextInGroup()
  5754. {
  5755. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  5756. if (first)
  5757. {
  5758. kept = input->nextInGroup();
  5759. first = false;
  5760. }
  5761. const void * next;
  5762. loop
  5763. {
  5764. next = input->nextInGroup();
  5765. if (!kept || !next || !helper.matches(kept,next))
  5766. {
  5767. numKept = 0;
  5768. break;
  5769. }
  5770. if (numKept < numToKeep-1)
  5771. {
  5772. numKept++;
  5773. break;
  5774. }
  5775. if (keepLeft)
  5776. {
  5777. ReleaseRoxieRow(next);
  5778. }
  5779. else
  5780. {
  5781. ReleaseRoxieRow(kept);
  5782. kept = next;
  5783. }
  5784. }
  5785. const void * ret = kept;
  5786. kept = next;
  5787. // CTXLOG("dedup returns %p", ret);
  5788. if (ret) processed++;
  5789. return ret;
  5790. }
  5791. };
  5792. class CRoxieServerDedupAllActivity : public CRoxieServerActivity
  5793. {
  5794. IHThorDedupArg &helper;
  5795. unsigned survivorIndex;
  5796. ConstPointerArray survivors;
  5797. bool keepLeft;
  5798. bool eof;
  5799. bool first;
  5800. ICompare *primaryCompare;
  5801. public:
  5802. CRoxieServerDedupAllActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _keepLeft)
  5803. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorDedupArg &)basehelper)
  5804. {
  5805. keepLeft = _keepLeft;
  5806. primaryCompare = helper.queryComparePrimary();
  5807. eof = false;
  5808. first = true;
  5809. survivorIndex = 0;
  5810. }
  5811. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  5812. {
  5813. eof = false;
  5814. first = true;
  5815. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  5816. }
  5817. virtual void reset()
  5818. {
  5819. #ifdef _DEBUG
  5820. while (survivors.isItem(survivorIndex))
  5821. {
  5822. ReleaseRoxieRow(survivors.item(survivorIndex++));
  5823. }
  5824. #endif
  5825. survivors.kill();
  5826. eof = false;
  5827. first = true;
  5828. CRoxieServerActivity::reset();
  5829. }
  5830. void dedupRange(unsigned first, unsigned last, ConstPointerArray & group)
  5831. {
  5832. for (unsigned idxL = first; idxL < last; idxL++)
  5833. {
  5834. const void * left = group.item(idxL);
  5835. if (left)
  5836. {
  5837. for (unsigned idxR = first; idxR < last; idxR++)
  5838. {
  5839. const void * right = group.item(idxR);
  5840. if ((idxL != idxR) && right)
  5841. {
  5842. if (helper.matches(left, right))
  5843. {
  5844. if (keepLeft)
  5845. {
  5846. group.replace(NULL, idxR);
  5847. ReleaseRoxieRow(right);
  5848. }
  5849. else
  5850. {
  5851. group.replace(NULL, idxL);
  5852. ReleaseRoxieRow(left);
  5853. break;
  5854. }
  5855. }
  5856. }
  5857. }
  5858. }
  5859. }
  5860. }
  5861. void dedupRangeIndirect(unsigned first, unsigned last, void *** index)
  5862. {
  5863. for (unsigned idxL = first; idxL < last; idxL++)
  5864. {
  5865. void * left = *(index[idxL]);
  5866. if (left)
  5867. {
  5868. for (unsigned idxR = first; idxR < last; idxR++)
  5869. {
  5870. void * right = *(index[idxR]);
  5871. if ((idxL != idxR) && right)
  5872. {
  5873. if (helper.matches(left, right))
  5874. {
  5875. if (keepLeft)
  5876. {
  5877. *(index[idxR]) = NULL;
  5878. ReleaseRoxieRow(right);
  5879. }
  5880. else
  5881. {
  5882. *(index[idxL]) = NULL;
  5883. ReleaseRoxieRow(left);
  5884. break;
  5885. }
  5886. }
  5887. }
  5888. }
  5889. }
  5890. }
  5891. }
  5892. bool calcNextDedupAll()
  5893. {
  5894. survivors.kill();
  5895. survivorIndex = 0;
  5896. ConstPointerArray group;
  5897. if (eof || !input->nextGroup(group))
  5898. {
  5899. eof = true;
  5900. return false;
  5901. }
  5902. unsigned max = group.ordinality();
  5903. if (primaryCompare)
  5904. {
  5905. //hard, if not impossible, to hit this code once optimisations in place
  5906. MemoryAttr indexbuff(max*sizeof(void **));
  5907. void *** index = (void ***)indexbuff.bufferBase();
  5908. qsortvecstable(const_cast<void * *>(group.getArray()), max, *primaryCompare, index);
  5909. unsigned first = 0;
  5910. for (unsigned idx = 1; idx < max; idx++)
  5911. {
  5912. if (primaryCompare->docompare(*(index[first]), *(index[idx])) != 0)
  5913. {
  5914. dedupRangeIndirect(first, idx, index);
  5915. first = idx;
  5916. }
  5917. }
  5918. dedupRangeIndirect(first, max, index);
  5919. for(unsigned idx2=0; idx2<max; ++idx2)
  5920. {
  5921. void * cur = *(index[idx2]);
  5922. if(cur)
  5923. survivors.append(cur);
  5924. }
  5925. }
  5926. else
  5927. {
  5928. dedupRange(0, max, group);
  5929. for(unsigned idx=0; idx<max; ++idx)
  5930. {
  5931. const void * cur = group.item(idx);
  5932. if(cur)
  5933. survivors.append(cur);
  5934. }
  5935. }
  5936. return true;
  5937. }
  5938. virtual const void *nextInGroup()
  5939. {
  5940. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  5941. if (first)
  5942. {
  5943. calcNextDedupAll();
  5944. first = false;
  5945. }
  5946. while (survivors.isItem(survivorIndex))
  5947. {
  5948. const void *ret = survivors.item(survivorIndex++);
  5949. if (ret)
  5950. {
  5951. processed++;
  5952. return ret;
  5953. }
  5954. }
  5955. calcNextDedupAll();
  5956. return NULL;
  5957. }
  5958. };
  5959. class CRoxieServerDedupActivityFactory : public CRoxieServerActivityFactory
  5960. {
  5961. bool compareAll;
  5962. bool keepLeft;
  5963. public:
  5964. CRoxieServerDedupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  5965. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  5966. {
  5967. Owned<IHThorDedupArg> helper = (IHThorDedupArg *) helperFactory();
  5968. compareAll = helper->compareAll();
  5969. keepLeft = helper->keepLeft();
  5970. }
  5971. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  5972. {
  5973. if (compareAll)
  5974. return new CRoxieServerDedupAllActivity(this, _probeManager, keepLeft);
  5975. else
  5976. return new CRoxieServerDedupActivity(this, _probeManager, keepLeft);
  5977. }
  5978. };
  5979. IRoxieServerActivityFactory *createRoxieServerDedupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  5980. {
  5981. return new CRoxieServerDedupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  5982. }
  5983. //=================================================================================
  5984. class CRoxieServerHashDedupActivity : public CRoxieServerActivity
  5985. {
  5986. bool eof;
  5987. IHThorHashDedupArg &helper;
  5988. class HashDedupElement
  5989. {
  5990. public:
  5991. HashDedupElement(unsigned _hash, const void *_keyRow)
  5992. : hash(_hash), keyRow(_keyRow)
  5993. {
  5994. }
  5995. ~HashDedupElement()
  5996. {
  5997. ReleaseRoxieRow(keyRow);
  5998. }
  5999. inline unsigned queryHash() const
  6000. {
  6001. return hash;
  6002. }
  6003. inline const void *queryRow() const
  6004. {
  6005. return keyRow;
  6006. }
  6007. private:
  6008. unsigned hash;
  6009. const void *keyRow;
  6010. };
  6011. class HashDedupTable : public SuperHashTable
  6012. {
  6013. public:
  6014. HashDedupTable(IHThorHashDedupArg & _helper, unsigned _activityId)
  6015. : helper(_helper),
  6016. activityId(_activityId),
  6017. keySize(helper.queryKeySize())
  6018. {
  6019. }
  6020. virtual ~HashDedupTable() { releaseAll(); }
  6021. virtual unsigned getHashFromElement(const void *et) const
  6022. {
  6023. const HashDedupElement *element = reinterpret_cast<const HashDedupElement *>(et);
  6024. return element->queryHash();
  6025. }
  6026. virtual unsigned getHashFromFindParam(const void *fp) const { throwUnexpected(); }
  6027. virtual const void * getFindParam(const void *et) const { throwUnexpected(); }
  6028. virtual bool matchesElement(const void *et, const void *searchET) const { throwUnexpected(); }
  6029. virtual bool matchesFindParam(const void *et, const void *key, unsigned fphash) const
  6030. {
  6031. const HashDedupElement *element = reinterpret_cast<const HashDedupElement *>(et);
  6032. if (fphash != element->queryHash())
  6033. return false;
  6034. return (helper.queryKeyCompare()->docompare(element->queryRow(), key) == 0);
  6035. }
  6036. virtual void onAdd(void *et) {}
  6037. virtual void onRemove(void *et)
  6038. {
  6039. const HashDedupElement *element = reinterpret_cast<const HashDedupElement *>(et);
  6040. delete element;
  6041. }
  6042. void onCreate(IRoxieSlaveContext *ctx)
  6043. {
  6044. keyRowAllocator.setown(ctx->queryCodeContext()->getRowAllocator(keySize.queryOriginal(), activityId));
  6045. }
  6046. void reset()
  6047. {
  6048. kill();
  6049. }
  6050. bool insert(const void * row)
  6051. {
  6052. unsigned hash = helper.queryHash()->hash(row);
  6053. RtlDynamicRowBuilder keyRowBuilder(keyRowAllocator, true);
  6054. size32_t thisKeySize = helper.recordToKey(keyRowBuilder, row);
  6055. OwnedConstRoxieRow keyRow = keyRowBuilder.finalizeRowClear(thisKeySize);
  6056. if (find(hash, keyRow.get()))
  6057. return false;
  6058. addNew(new HashDedupElement(hash, keyRow.getClear()), hash);
  6059. return true;
  6060. }
  6061. private:
  6062. IHThorHashDedupArg & helper;
  6063. CachedOutputMetaData keySize;
  6064. Owned<IEngineRowAllocator> keyRowAllocator;
  6065. unsigned activityId;
  6066. } table;
  6067. public:
  6068. CRoxieServerHashDedupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  6069. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorHashDedupArg &)basehelper), table(helper, activityId)
  6070. {
  6071. eof = false;
  6072. }
  6073. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6074. {
  6075. eof = false;
  6076. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  6077. }
  6078. virtual void onCreate(IRoxieSlaveContext *ctx, IHThorArg *_colocalParent)
  6079. {
  6080. CRoxieServerActivity::onCreate(ctx, colocalParent);
  6081. table.onCreate(ctx);
  6082. }
  6083. virtual void reset()
  6084. {
  6085. table.reset();
  6086. eof = false;
  6087. CRoxieServerActivity::reset();
  6088. }
  6089. virtual const void *nextInGroup()
  6090. {
  6091. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  6092. while(!eof)
  6093. {
  6094. const void * next = input->nextInGroup();
  6095. if(!next)
  6096. next = input->nextInGroup();
  6097. if(!next)
  6098. {
  6099. eof = true;
  6100. break;
  6101. }
  6102. if(table.insert(next))
  6103. return next;
  6104. else
  6105. ReleaseRoxieRow(next);
  6106. }
  6107. return NULL;
  6108. }
  6109. };
  6110. class CRoxieServerHashDedupActivityFactory : public CRoxieServerActivityFactory
  6111. {
  6112. public:
  6113. CRoxieServerHashDedupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6114. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  6115. {
  6116. }
  6117. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  6118. {
  6119. return new CRoxieServerHashDedupActivity(this, _probeManager);
  6120. }
  6121. };
  6122. IRoxieServerActivityFactory *createRoxieServerHashDedupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6123. {
  6124. return new CRoxieServerHashDedupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  6125. }
  6126. //=================================================================================
  6127. class CRoxieServerRollupActivity : public CRoxieServerActivity
  6128. {
  6129. IHThorRollupArg &helper;
  6130. OwnedConstRoxieRow left;
  6131. OwnedConstRoxieRow prev;
  6132. OwnedConstRoxieRow right;
  6133. bool readFirstRow;
  6134. public:
  6135. CRoxieServerRollupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  6136. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorRollupArg &)basehelper)
  6137. {
  6138. readFirstRow = false;
  6139. }
  6140. ~CRoxieServerRollupActivity()
  6141. {
  6142. }
  6143. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6144. {
  6145. readFirstRow = false;
  6146. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  6147. }
  6148. virtual void reset()
  6149. {
  6150. left.clear();
  6151. prev.clear();
  6152. right.clear();
  6153. CRoxieServerActivity::reset();
  6154. }
  6155. virtual bool needsAllocator() const { return true; }
  6156. virtual const void * nextInGroup()
  6157. {
  6158. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  6159. if (!readFirstRow)
  6160. {
  6161. left.setown(input->nextInGroup());
  6162. prev.set(left);
  6163. readFirstRow = true;
  6164. }
  6165. loop
  6166. {
  6167. right.setown(input->nextInGroup());
  6168. if(!prev || !right || !helper.matches(prev,right))
  6169. {
  6170. const void * ret = left.getClear();
  6171. if(ret)
  6172. processed++;
  6173. left.setown(right.getClear());
  6174. prev.set(left);
  6175. return ret;
  6176. }
  6177. try
  6178. {
  6179. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  6180. unsigned outSize = helper.transform(rowBuilder, left, right);
  6181. if (outSize)
  6182. left.setown(rowBuilder.finalizeRowClear(outSize));
  6183. prev.set(right);
  6184. }
  6185. catch(IException * E)
  6186. {
  6187. throw makeWrappedException(E);
  6188. }
  6189. }
  6190. }
  6191. };
  6192. class CRoxieServerRollupActivityFactory : public CRoxieServerActivityFactory
  6193. {
  6194. public:
  6195. CRoxieServerRollupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6196. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  6197. {
  6198. }
  6199. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  6200. {
  6201. return new CRoxieServerRollupActivity(this, _probeManager);
  6202. }
  6203. };
  6204. IRoxieServerActivityFactory *createRoxieServerRollupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6205. {
  6206. return new CRoxieServerRollupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  6207. }
  6208. //=================================================================================
  6209. class CRoxieServerNormalizeActivity : public CRoxieServerActivity
  6210. {
  6211. IHThorNormalizeArg &helper;
  6212. unsigned numThisRow;
  6213. unsigned curRow;
  6214. const void *buffer;
  6215. unsigned numProcessedLastGroup;
  6216. public:
  6217. CRoxieServerNormalizeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  6218. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorNormalizeArg &)basehelper)
  6219. {
  6220. buffer = NULL;
  6221. numThisRow = 0;
  6222. curRow = 0;
  6223. numProcessedLastGroup = 0;
  6224. }
  6225. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6226. {
  6227. numThisRow = 0;
  6228. curRow = 0;
  6229. numProcessedLastGroup = 0;
  6230. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  6231. }
  6232. virtual void reset()
  6233. {
  6234. ReleaseClearRoxieRow(buffer);
  6235. CRoxieServerActivity::reset();
  6236. }
  6237. virtual bool needsAllocator() const { return true; }
  6238. virtual const void * nextInGroup()
  6239. {
  6240. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  6241. loop
  6242. {
  6243. while (curRow == numThisRow)
  6244. {
  6245. if (buffer)
  6246. ReleaseClearRoxieRow(buffer);
  6247. buffer = input->nextInGroup();
  6248. if (!buffer && (processed == numProcessedLastGroup))
  6249. buffer = input->nextInGroup();
  6250. if (!buffer)
  6251. {
  6252. numProcessedLastGroup = processed;
  6253. return NULL;
  6254. }
  6255. curRow = 0;
  6256. numThisRow = helper.numExpandedRows(buffer);
  6257. }
  6258. try
  6259. {
  6260. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  6261. unsigned actualSize = helper.transform(rowBuilder, buffer, ++curRow);
  6262. if (actualSize != 0)
  6263. {
  6264. processed++;
  6265. return rowBuilder.finalizeRowClear(actualSize);
  6266. }
  6267. }
  6268. catch (IException *E)
  6269. {
  6270. throw makeWrappedException(E);
  6271. }
  6272. }
  6273. }
  6274. };
  6275. class CRoxieServerNormalizeActivityFactory : public CRoxieServerActivityFactory
  6276. {
  6277. public:
  6278. CRoxieServerNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6279. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  6280. {
  6281. }
  6282. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  6283. {
  6284. return new CRoxieServerNormalizeActivity(this, _probeManager);
  6285. }
  6286. };
  6287. IRoxieServerActivityFactory *createRoxieServerNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6288. {
  6289. return new CRoxieServerNormalizeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  6290. }
  6291. //=================================================================================
  6292. class CRoxieServerNormalizeChildActivity : public CRoxieServerActivity
  6293. {
  6294. IHThorNormalizeChildArg &helper;
  6295. unsigned numThisRow;
  6296. unsigned curRow;
  6297. const void *buffer;
  6298. unsigned numProcessedLastGroup;
  6299. INormalizeChildIterator * cursor;
  6300. const void * curChildRow;
  6301. bool advanceInput()
  6302. {
  6303. loop
  6304. {
  6305. ReleaseClearRoxieRow(buffer);
  6306. buffer = input->nextInGroup();
  6307. if (!buffer && (processed == numProcessedLastGroup))
  6308. buffer = input->nextInGroup();
  6309. if (!buffer)
  6310. {
  6311. numProcessedLastGroup = processed;
  6312. return false;
  6313. }
  6314. curChildRow = cursor->first(buffer);
  6315. if (curChildRow)
  6316. {
  6317. curRow = 0;
  6318. return true;
  6319. }
  6320. }
  6321. }
  6322. public:
  6323. CRoxieServerNormalizeChildActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  6324. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorNormalizeChildArg &)basehelper)
  6325. {
  6326. buffer = NULL;
  6327. cursor = NULL;
  6328. numThisRow = 0;
  6329. curRow = 0;
  6330. numProcessedLastGroup = 0;
  6331. curChildRow = NULL;
  6332. }
  6333. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6334. {
  6335. numThisRow = 0;
  6336. curRow = 0;
  6337. numProcessedLastGroup = 0;
  6338. curChildRow = NULL;
  6339. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  6340. cursor = helper.queryIterator();
  6341. }
  6342. virtual void stop(bool aborting)
  6343. {
  6344. CRoxieServerActivity::stop(aborting);
  6345. }
  6346. virtual void reset()
  6347. {
  6348. cursor = NULL;
  6349. ReleaseClearRoxieRow(buffer);
  6350. CRoxieServerActivity::reset();
  6351. }
  6352. virtual bool needsAllocator() const { return true; }
  6353. const void *nextInGroup()
  6354. {
  6355. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  6356. loop
  6357. {
  6358. if (!buffer)
  6359. {
  6360. if (!advanceInput())
  6361. return NULL;
  6362. }
  6363. try
  6364. {
  6365. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  6366. size32_t outSize = helper.transform(rowBuilder, buffer, curChildRow, ++curRow);
  6367. curChildRow = cursor->next();
  6368. if (!curChildRow)
  6369. ReleaseClearRoxieRow(buffer);
  6370. if (outSize != 0)
  6371. {
  6372. processed++;
  6373. return rowBuilder.finalizeRowClear(outSize);
  6374. }
  6375. }
  6376. catch (IException *E)
  6377. {
  6378. throw makeWrappedException(E);
  6379. }
  6380. }
  6381. }
  6382. };
  6383. class CRoxieServerNormalizeChildActivityFactory : public CRoxieServerActivityFactory
  6384. {
  6385. public:
  6386. CRoxieServerNormalizeChildActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6387. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  6388. {
  6389. }
  6390. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  6391. {
  6392. return new CRoxieServerNormalizeChildActivity(this, _probeManager);
  6393. }
  6394. };
  6395. IRoxieServerActivityFactory *createRoxieServerNormalizeChildActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6396. {
  6397. return new CRoxieServerNormalizeChildActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  6398. }
  6399. //=================================================================================
  6400. class CRoxieServerNormalizeLinkedChildActivity : public CRoxieServerActivity
  6401. {
  6402. IHThorNormalizeLinkedChildArg &helper;
  6403. OwnedConstRoxieRow curParent;
  6404. OwnedConstRoxieRow curChild;
  6405. unsigned numProcessedLastGroup;
  6406. bool advanceInput()
  6407. {
  6408. loop
  6409. {
  6410. curParent.setown(input->nextInGroup());
  6411. if (!curParent && (processed == numProcessedLastGroup))
  6412. curParent.setown(input->nextInGroup());
  6413. if (!curParent)
  6414. {
  6415. numProcessedLastGroup = processed;
  6416. return false;
  6417. }
  6418. curChild.set(helper.first(curParent));
  6419. if (curChild)
  6420. return true;
  6421. }
  6422. }
  6423. public:
  6424. CRoxieServerNormalizeLinkedChildActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  6425. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorNormalizeLinkedChildArg &)basehelper)
  6426. {
  6427. numProcessedLastGroup = 0;
  6428. }
  6429. ~CRoxieServerNormalizeLinkedChildActivity()
  6430. {
  6431. }
  6432. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  6433. {
  6434. numProcessedLastGroup = 0;
  6435. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  6436. }
  6437. virtual void reset()
  6438. {
  6439. curParent.clear();
  6440. curChild.clear();
  6441. CRoxieServerActivity::reset();
  6442. }
  6443. const void *nextInGroup()
  6444. {
  6445. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  6446. loop
  6447. {
  6448. if (!curParent)
  6449. {
  6450. if (!advanceInput())
  6451. return NULL;
  6452. }
  6453. try
  6454. {
  6455. const void *ret = curChild.getClear();
  6456. curChild.set(helper.next());
  6457. if (!curChild)
  6458. curParent.clear();
  6459. if (ret)
  6460. {
  6461. processed++;
  6462. return ret;
  6463. }
  6464. }
  6465. catch (IException *E)
  6466. {
  6467. throw makeWrappedException(E);
  6468. }
  6469. }
  6470. }
  6471. };
  6472. class CRoxieServerNormalizeLinkedChildActivityFactory : public CRoxieServerActivityFactory
  6473. {
  6474. public:
  6475. CRoxieServerNormalizeLinkedChildActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6476. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  6477. {
  6478. }
  6479. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  6480. {
  6481. return new CRoxieServerNormalizeLinkedChildActivity(this, _probeManager);
  6482. }
  6483. };
  6484. IRoxieServerActivityFactory *createRoxieServerNormalizeLinkedChildActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  6485. {
  6486. return new CRoxieServerNormalizeLinkedChildActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  6487. }
  6488. //=================================================================================
  6489. interface ISortAlgorithm
  6490. {
  6491. virtual void prepare(IRoxieInput *input) = 0;
  6492. virtual const void *next() = 0;
  6493. virtual void reset() = 0;
  6494. };
  6495. class CQuickSortAlgorithm : implements ISortAlgorithm
  6496. {
  6497. unsigned curIndex;
  6498. ConstPointerArray sorted;
  6499. ICompare *compare;
  6500. public:
  6501. CQuickSortAlgorithm(ICompare *_compare) : compare(_compare)
  6502. {
  6503. curIndex = 0;
  6504. }
  6505. virtual void prepare(IRoxieInput *input)
  6506. {
  6507. curIndex = 0;
  6508. if (input->nextGroup(sorted))
  6509. qsortvec(const_cast<void * *>(sorted.getArray()), sorted.ordinality(), *compare);
  6510. }
  6511. virtual const void *next()
  6512. {
  6513. if (sorted.isItem(curIndex))
  6514. return sorted.item(curIndex++);
  6515. return NULL;
  6516. }
  6517. virtual void reset()
  6518. {
  6519. while (sorted.isItem(curIndex))
  6520. ReleaseRoxieRow(sorted.item(curIndex++));
  6521. curIndex = 0;
  6522. sorted.kill();
  6523. }
  6524. };
  6525. class CSpillingQuickSortAlgorithm : implements ISortAlgorithm, implements roxiemem::IBufferedRowCallback
  6526. {
  6527. enum {
  6528. InitialSortElements = 0,
  6529. //The number of rows that can be added without entering a critical section, and therefore also the number
  6530. //of rows that might not get freed when memory gets tight.
  6531. CommitStep=32
  6532. };
  6533. roxiemem::DynamicRoxieOutputRowArray rowsToSort;
  6534. roxiemem::RoxieSimpleInputRowArray sorted;
  6535. ICompare *compare;
  6536. IRoxieSlaveContext * ctx;
  6537. Owned<IDiskMerger> diskMerger;
  6538. Owned<IRowStream> diskReader;
  6539. Owned<IOutputMetaData> rowMeta;
  6540. unsigned activityId;
  6541. public:
  6542. CSpillingQuickSortAlgorithm(ICompare *_compare, IRoxieSlaveContext * _ctx, IOutputMetaData * _rowMeta, unsigned _activityId)
  6543. : rowsToSort(&_ctx->queryRowManager(), InitialSortElements, CommitStep), ctx(_ctx), compare(_compare), rowMeta(_rowMeta), activityId(_activityId)
  6544. {
  6545. ctx->queryRowManager().addRowBuffer(this);
  6546. }
  6547. ~CSpillingQuickSortAlgorithm()
  6548. {
  6549. ctx->queryRowManager().removeRowBuffer(this);
  6550. diskReader.clear();
  6551. }
  6552. virtual void prepare(IRoxieInput *input)
  6553. {
  6554. loop
  6555. {
  6556. const void * next = input->nextInGroup();
  6557. if (!next)
  6558. break;
  6559. if (!rowsToSort.append(next))
  6560. {
  6561. {
  6562. roxiemem::RoxieOutputRowArrayLock block(rowsToSort);
  6563. //We should have been called back to free any committed rows, but occasionally it may not (e.g., if
  6564. //the problem is global memory is exhausted) - in which case force a spill here (but add any pending
  6565. //rows first).
  6566. if (rowsToSort.numCommitted() != 0)
  6567. {
  6568. rowsToSort.flush();
  6569. spillRows();
  6570. }
  6571. //Ensure new rows are written to the head of the array. It needs to be a separate call because
  6572. //spillRows() cannot shift active row pointer since it can be called from any thread
  6573. rowsToSort.flush();
  6574. }
  6575. if (!rowsToSort.append(next))
  6576. {
  6577. ReleaseRoxieRow(next);
  6578. throw MakeStringException(ROXIEMM_MEMORY_LIMIT_EXCEEDED, "Insufficient memory to append sort row");
  6579. }
  6580. }
  6581. }
  6582. rowsToSort.flush();
  6583. roxiemem::RoxieOutputRowArrayLock block(rowsToSort);
  6584. if (diskMerger)
  6585. {
  6586. spillRows();
  6587. rowsToSort.kill();
  6588. diskReader.setown(diskMerger->merge(compare));
  6589. }
  6590. else
  6591. {
  6592. unsigned numRows = rowsToSort.numCommitted();
  6593. if (numRows)
  6594. {
  6595. const void * * rows = rowsToSort.getBlock(numRows);
  6596. //MORE: Should this be parallel? Should that be dependent on whether it is grouped? Should be a hint.
  6597. qsortvec(const_cast<void * *>(rows), numRows, *compare);
  6598. }
  6599. sorted.transferFrom(rowsToSort);
  6600. }
  6601. }
  6602. virtual const void *next()
  6603. {
  6604. if(diskReader)
  6605. return diskReader->nextRow();
  6606. return sorted.dequeue();
  6607. }
  6608. virtual void reset()
  6609. {
  6610. //MORE: This could transfer any row pointer from sorted back to rowsToSort. It would trade
  6611. //fewer heap allocations with not freeing up the memory from large group sorts.
  6612. rowsToSort.clearRows();
  6613. sorted.kill();
  6614. //Disk reader must be cleared before the merger - or the files may still be locked.
  6615. diskReader.clear();
  6616. diskMerger.clear();
  6617. }
  6618. //interface roxiemem::IBufferedRowCallback
  6619. virtual unsigned getPriority() const
  6620. {
  6621. //Spill global sorts before grouped sorts
  6622. if (rowMeta->isGrouped())
  6623. return 20;
  6624. return 10;
  6625. }
  6626. virtual bool freeBufferedRows(bool critical)
  6627. {
  6628. roxiemem::RoxieOutputRowArrayLock block(rowsToSort);
  6629. return spillRows();
  6630. }
  6631. protected:
  6632. bool spillRows()
  6633. {
  6634. unsigned numRows = rowsToSort.numCommitted();
  6635. if (numRows == 0)
  6636. return false;
  6637. const void * * rows = rowsToSort.getBlock(numRows);
  6638. qsortvec(const_cast<void * *>(rows), numRows, *compare);
  6639. Owned<IRowWriter> out = queryMerger()->createWriteBlock();
  6640. for (unsigned i= 0; i < numRows; i++)
  6641. {
  6642. out->putRow(rows[i]);
  6643. }
  6644. rowsToSort.noteSpilled(numRows);
  6645. return true;
  6646. }
  6647. IDiskMerger * queryMerger()
  6648. {
  6649. if (!diskMerger)
  6650. {
  6651. unsigned __int64 seq = (memsize_t)this ^ get_cycles_now();
  6652. StringBuffer spillBasename;
  6653. spillBasename.append(tempDirectory).append(PATHSEPCHAR).appendf("spill_sort_%"I64F"u", seq);
  6654. Owned<IRowLinkCounter> linker = new RoxieRowLinkCounter();
  6655. Owned<IRowInterfaces> rowInterfaces = createRowInterfaces(rowMeta, activityId, ctx->queryCodeContext());
  6656. diskMerger.setown(createDiskMerger(rowInterfaces, linker, spillBasename));
  6657. }
  6658. return diskMerger;
  6659. }
  6660. };
  6661. #define INSERTION_SORT_BLOCKSIZE 1024
  6662. class SortedBlock : public CInterface, implements IInterface
  6663. {
  6664. unsigned sequence;
  6665. const void **rows;
  6666. unsigned length;
  6667. unsigned pos;
  6668. SortedBlock(const SortedBlock &);
  6669. public:
  6670. IMPLEMENT_IINTERFACE;
  6671. SortedBlock(unsigned _sequence, IRowManager *rowManager, unsigned activityId) : sequence(_sequence)
  6672. {
  6673. rows = (const void **) rowManager->allocate(INSERTION_SORT_BLOCKSIZE * sizeof(void *), activityId);
  6674. length = 0;
  6675. pos = 0;
  6676. }
  6677. ~SortedBlock()
  6678. {
  6679. while (pos < length)
  6680. ReleaseRoxieRow(rows[pos++]);
  6681. ReleaseRoxieRow(rows);
  6682. }
  6683. int compareTo(SortedBlock *r, ICompare *compare)
  6684. {
  6685. int rc = compare->docompare(rows[pos], r->rows[r->pos]);
  6686. if (!rc)
  6687. rc = sequence - r->sequence;
  6688. return rc;
  6689. }
  6690. const void *next()
  6691. {
  6692. if (pos < length)
  6693. return rows[pos++];
  6694. else
  6695. return NULL;
  6696. }
  6697. inline bool eof()
  6698. {
  6699. return pos==length;
  6700. }
  6701. bool insert(const void *next, ICompare *_compare )
  6702. {
  6703. unsigned b = length;
  6704. if (b == INSERTION_SORT_BLOCKSIZE)
  6705. return false;
  6706. else if (b < 7)
  6707. {
  6708. while (b)
  6709. {
  6710. if (_compare->docompare(next, rows[b-1]) >= 0)
  6711. break;
  6712. b--;
  6713. }
  6714. if (b != length)
  6715. memmove(&rows[b+1], &rows[b], (length - b) * sizeof(void *));
  6716. rows[b] = next;
  6717. length++;
  6718. return true;
  6719. }
  6720. else
  6721. {
  6722. unsigned int a = 0;
  6723. while ((int)a<b)
  6724. {
  6725. int i = (a+b)/2;
  6726. int rc = _compare->docompare(next, rows[i]);
  6727. if (rc>=0)
  6728. a = i+1;
  6729. else
  6730. b = i;
  6731. }
  6732. if (a != length)
  6733. memmove(&rows[a+1], &rows[a], (length - a) * sizeof(void *));
  6734. rows[a] = next;
  6735. length++;
  6736. return true;
  6737. }
  6738. }
  6739. };
  6740. class CInsertionSortAlgorithm : implements ISortAlgorithm
  6741. {
  6742. SortedBlock *curBlock;
  6743. unsigned blockNo;
  6744. IArrayOf<SortedBlock> blocks;
  6745. unsigned activityId;
  6746. IRowManager *rowManager;
  6747. ICompare *compare;
  6748. void newBlock()
  6749. {
  6750. blocks.append(*curBlock);
  6751. curBlock = new SortedBlock(blockNo++, rowManager, activityId);
  6752. }
  6753. inline static int doCompare(SortedBlock &l, SortedBlock &r, ICompare *compare)
  6754. {
  6755. return l.compareTo(&r, compare);
  6756. }
  6757. void makeHeap()
  6758. {
  6759. /* Permute blocks to establish the heap property
  6760. For each element p, the children are p*2+1 and p*2+2 (provided these are in range)
  6761. The children of p must both be greater than or equal to p
  6762. The parent of a child c is given by p = (c-1)/2
  6763. */
  6764. unsigned i;
  6765. unsigned n = blocks.length();
  6766. SortedBlock **s = blocks.getArray();
  6767. for (i=1; i<n; i++)
  6768. {
  6769. SortedBlock * r = s[i];
  6770. int c = i; /* child */
  6771. while (c > 0)
  6772. {
  6773. int p = (c-1)/2; /* parent */
  6774. if ( doCompare( blocks.item(c), blocks.item(p), compare ) >= 0 )
  6775. break;
  6776. s[c] = s[p];
  6777. s[p] = r;
  6778. c = p;
  6779. }
  6780. }
  6781. }
  6782. void remakeHeap()
  6783. {
  6784. /* The row associated with block[0] will have changed
  6785. This code restores the heap property
  6786. */
  6787. unsigned p = 0; /* parent */
  6788. unsigned n = blocks.length();
  6789. SortedBlock **s = blocks.getArray();
  6790. while (1)
  6791. {
  6792. unsigned c = p*2 + 1; /* child */
  6793. if ( c >= n )
  6794. break;
  6795. /* Select smaller child */
  6796. if ( c+1 < n && doCompare( blocks.item(c+1), blocks.item(c), compare ) < 0 ) c += 1;
  6797. /* If child is greater or equal than parent then we are done */
  6798. if ( doCompare( blocks.item(c), blocks.item(p), compare ) >= 0 )
  6799. break;
  6800. /* Swap parent and child */
  6801. SortedBlock *r = s[c];
  6802. s[c] = s[p];
  6803. s[p] = r;
  6804. /* child becomes parent */
  6805. p = c;
  6806. }
  6807. }
  6808. public:
  6809. CInsertionSortAlgorithm(ICompare *_compare, IRowManager *_rowManager, unsigned _activityId)
  6810. : compare(_compare)
  6811. {
  6812. rowManager = _rowManager;
  6813. activityId = _activityId;
  6814. curBlock = NULL;
  6815. blockNo = 0;
  6816. }
  6817. virtual void reset()
  6818. {
  6819. blocks.kill();
  6820. delete curBlock;
  6821. curBlock = NULL;
  6822. blockNo = 0;
  6823. }
  6824. virtual void prepare(IRoxieInput *input)
  6825. {
  6826. blockNo = 0;
  6827. curBlock = new SortedBlock(blockNo++, rowManager, activityId);
  6828. loop
  6829. {
  6830. const void *next = input->nextInGroup();
  6831. if (!next)
  6832. break;
  6833. if (!curBlock->insert(next, compare))
  6834. {
  6835. newBlock();
  6836. curBlock->insert(next, compare);
  6837. }
  6838. }
  6839. if (blockNo > 1)
  6840. {
  6841. blocks.append(*curBlock);
  6842. curBlock = NULL;
  6843. makeHeap();
  6844. }
  6845. }
  6846. virtual const void * next()
  6847. {
  6848. const void *ret;
  6849. if (blockNo==1) // single block case..
  6850. {
  6851. ret = curBlock->next();
  6852. }
  6853. else if (blocks.length())
  6854. {
  6855. SortedBlock &top = blocks.item(0);
  6856. ret = top.next();
  6857. if (top.eof())
  6858. blocks.replace(blocks.popGet(), 0);
  6859. remakeHeap();
  6860. }
  6861. else
  6862. ret = NULL;
  6863. return ret;
  6864. }
  6865. };
  6866. class CHeapSortAlgorithm : implements ISortAlgorithm
  6867. {
  6868. unsigned curIndex;
  6869. ConstPointerArray sorted;
  6870. bool inputAlreadySorted;
  6871. IntArray sequences;
  6872. bool eof;
  6873. ICompare *compare;
  6874. #ifdef _CHECK_HEAPSORT
  6875. void checkHeap() const
  6876. {
  6877. unsigned n = sorted.ordinality();
  6878. if (n)
  6879. {
  6880. ICompare *_compare = compare;
  6881. void **s = sorted.getArray();
  6882. int *sq = sequences.getArray();
  6883. unsigned p;
  6884. #if 0
  6885. CTXLOG("------------------------%d entries-----------------", n);
  6886. for (p = 0; p < n; p++)
  6887. {
  6888. CTXLOG("HEAP %d: %d %.10s", p, sq[p], s[p] ? s[p] : "..");
  6889. }
  6890. #endif
  6891. for (p = 0; p < n; p++)
  6892. {
  6893. unsigned c = p*2+1;
  6894. if (c<n)
  6895. assertex(!s[c] || (docompare(p, c, _compare, s, sq) <= 0));
  6896. c++;
  6897. if (c<n)
  6898. assertex(!s[c] || (docompare(p, c, _compare, s, sq) <= 0));
  6899. }
  6900. }
  6901. }
  6902. #else
  6903. inline void checkHeap() const {}
  6904. #endif
  6905. const void *removeHeap()
  6906. {
  6907. unsigned n = sorted.ordinality();
  6908. if (n)
  6909. {
  6910. const void *ret = sorted.item(0);
  6911. if (n > 1 && ret)
  6912. {
  6913. ICompare *_compare = compare;
  6914. const void **s = sorted.getArray();
  6915. int *sq = sequences.getArray();
  6916. unsigned v = 0; // vacancy
  6917. loop
  6918. {
  6919. unsigned c = 2*v + 1;
  6920. if (c < n)
  6921. {
  6922. unsigned f = c; // favourite to fill it
  6923. c++;
  6924. if (c < n && s[c] && (!s[f] || (docompare(f, c, _compare, s, sq) > 0))) // is the smaller of the children
  6925. f = c;
  6926. sq[v] = sq[f];
  6927. if ((s[v] = s[f]) != NULL)
  6928. v = f;
  6929. else
  6930. break;
  6931. }
  6932. else
  6933. {
  6934. s[v] = NULL;
  6935. break;
  6936. }
  6937. }
  6938. }
  6939. checkHeap();
  6940. return ret;
  6941. }
  6942. else
  6943. return NULL;
  6944. }
  6945. static inline int docompare(unsigned l, unsigned r, ICompare *_compare, const void **s, int *sq)
  6946. {
  6947. int rc = _compare->docompare(s[l], s[r]);
  6948. if (!rc)
  6949. rc = sq[l] - sq[r];
  6950. return rc;
  6951. }
  6952. void insertHeap(const void *next)
  6953. {
  6954. // Upside-down heap sort
  6955. // Maintain a heap where every parent is lower than each of its children
  6956. // Root (at node 0) is lowest record seen, nodes 2n+1, 2n+2 are the children
  6957. // To insert a row, add it at end then keep swapping with parent as long as parent is greater
  6958. // To remove a row, take row 0, then recreate heap by replacing it with smaller of two children and so on down the tree
  6959. // Nice features:
  6960. // 1. Deterministic
  6961. // 2. Sort time can be overlapped with upstream/downstream processes - there is no delay between receiving last record from input and deliveriing first to output
  6962. // 3. Already sorted case can be spotted at zero cost while reading.
  6963. // 4. If you don't read all the results, you don't have to complete the sort
  6964. // BUT it is NOT stable, so we have to use a parallel array of sequence numbers
  6965. unsigned n = sorted.ordinality();
  6966. sorted.append(next);
  6967. sequences.append(n);
  6968. if (!n)
  6969. return;
  6970. ICompare *_compare = compare;
  6971. const void **s = sorted.getArray();
  6972. if (inputAlreadySorted)
  6973. {
  6974. if (_compare->docompare(next, s[n-1]) >= 0)
  6975. return;
  6976. else
  6977. {
  6978. // MORE - could delay creating sequences until now...
  6979. inputAlreadySorted = false;
  6980. }
  6981. }
  6982. int *sq = sequences.getArray();
  6983. unsigned q = n;
  6984. while (n)
  6985. {
  6986. unsigned parent = (n-1) / 2;
  6987. const void *p = s[parent];
  6988. if (_compare->docompare(p, next) <= 0)
  6989. break;
  6990. s[n] = p;
  6991. sq[n] = sq[parent];
  6992. s[parent] = next;
  6993. sq[parent] = q;
  6994. n = parent;
  6995. }
  6996. }
  6997. public:
  6998. CHeapSortAlgorithm(ICompare *_compare) : compare(_compare)
  6999. {
  7000. inputAlreadySorted = true;
  7001. curIndex = 0;
  7002. eof = false;
  7003. }
  7004. virtual void reset()
  7005. {
  7006. eof = false;
  7007. if (inputAlreadySorted)
  7008. {
  7009. while (sorted.isItem(curIndex))
  7010. ReleaseRoxieRow(sorted.item(curIndex++));
  7011. sorted.kill();
  7012. }
  7013. else
  7014. {
  7015. ReleaseRoxieRowSet(sorted);
  7016. }
  7017. inputAlreadySorted = true;
  7018. sequences.kill();
  7019. }
  7020. virtual void prepare(IRoxieInput *input)
  7021. {
  7022. inputAlreadySorted = true;
  7023. curIndex = 0;
  7024. eof = false;
  7025. assertex(sorted.ordinality()==0);
  7026. const void *next = input->nextInGroup();
  7027. if (!next)
  7028. {
  7029. eof = true;
  7030. return;
  7031. }
  7032. loop
  7033. {
  7034. insertHeap(next);
  7035. next = input->nextInGroup();
  7036. if (!next)
  7037. break;
  7038. }
  7039. checkHeap();
  7040. }
  7041. virtual const void * next()
  7042. {
  7043. if (inputAlreadySorted)
  7044. {
  7045. if (sorted.isItem(curIndex))
  7046. {
  7047. return sorted.item(curIndex++);
  7048. }
  7049. else
  7050. return NULL;
  7051. }
  7052. else
  7053. return removeHeap();
  7054. }
  7055. };
  7056. typedef enum {heapSort, insertionSort, quickSort, spillingQuickSort, unknownSort } RoxieSortAlgorithm;
  7057. class CRoxieServerSortActivity : public CRoxieServerActivity
  7058. {
  7059. protected:
  7060. IHThorSortArg &helper;
  7061. ICompare *compare;
  7062. ISortAlgorithm *sorter;
  7063. bool readInput;
  7064. RoxieSortAlgorithm sortAlgorithm;
  7065. unsigned sortFlags;
  7066. public:
  7067. CRoxieServerSortActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, RoxieSortAlgorithm _sortAlgorithm, unsigned _sortFlags)
  7068. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSortArg &)basehelper), sortAlgorithm(_sortAlgorithm), sortFlags(_sortFlags)
  7069. {
  7070. compare = helper.queryCompare();
  7071. readInput = false;
  7072. sorter = NULL;
  7073. }
  7074. ~CRoxieServerSortActivity()
  7075. {
  7076. delete sorter;
  7077. }
  7078. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  7079. {
  7080. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  7081. switch (sortAlgorithm)
  7082. {
  7083. case heapSort:
  7084. sorter = new CHeapSortAlgorithm(compare);
  7085. break;
  7086. case insertionSort:
  7087. sorter = new CInsertionSortAlgorithm(compare, &ctx->queryRowManager(), activityId);
  7088. break;
  7089. case quickSort:
  7090. sorter = new CQuickSortAlgorithm(compare);
  7091. break;
  7092. case spillingQuickSort:
  7093. sorter = new CSpillingQuickSortAlgorithm(compare, ctx, meta, activityId);
  7094. break;
  7095. case unknownSort:
  7096. sorter = NULL; // create it later....
  7097. break;
  7098. default:
  7099. throwUnexpected();
  7100. break;
  7101. }
  7102. }
  7103. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7104. {
  7105. assertex(!readInput);
  7106. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  7107. }
  7108. virtual void reset()
  7109. {
  7110. if (sorter)
  7111. sorter->reset();
  7112. readInput = false;
  7113. CRoxieServerActivity::reset();
  7114. }
  7115. virtual const void * nextInGroup()
  7116. {
  7117. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  7118. if (!readInput)
  7119. {
  7120. if (sortAlgorithm == unknownSort)
  7121. {
  7122. delete sorter;
  7123. sorter = NULL;
  7124. IHThorAlgorithm *sortMethod = static_cast<IHThorAlgorithm *>(helper.selectInterface(TAIalgorithm_1));
  7125. const char *useAlgorithm = sortMethod->queryAlgorithm();
  7126. if (useAlgorithm)
  7127. {
  7128. if (stricmp(useAlgorithm, "quicksort")==0)
  7129. {
  7130. if (sortFlags & TAFstable)
  7131. throw MakeStringException(ROXIE_UNKNOWN_ALGORITHM, "Invalid stable sort algorithm %s requested", useAlgorithm);
  7132. sorter = new CQuickSortAlgorithm(compare);
  7133. }
  7134. else if (stricmp(useAlgorithm, "heapsort")==0)
  7135. sorter = new CHeapSortAlgorithm(compare);
  7136. else if (stricmp(useAlgorithm, "insertionsort")==0)
  7137. sorter = new CInsertionSortAlgorithm(compare, &ctx->queryRowManager(), activityId);
  7138. else
  7139. {
  7140. WARNLOG(ROXIE_UNKNOWN_ALGORITHM, "Ignoring unsupported sort order algorithm '%s', using default", useAlgorithm);
  7141. if (sortFlags & TAFunstable)
  7142. sorter = new CQuickSortAlgorithm(compare);
  7143. else
  7144. sorter = new CHeapSortAlgorithm(compare);
  7145. }
  7146. }
  7147. else
  7148. sorter = new CHeapSortAlgorithm(compare); // shouldn't really happen but there was a vintage of codegen that did not set the flag when algorithm not specified...
  7149. }
  7150. sorter->prepare(input);
  7151. readInput = true;
  7152. }
  7153. const void *ret = sorter->next();
  7154. if (ret)
  7155. processed++;
  7156. else
  7157. {
  7158. sorter->reset();
  7159. readInput = false; // ready for next group
  7160. }
  7161. return ret;
  7162. }
  7163. };
  7164. class CRoxieServerSortActivityFactory : public CRoxieServerActivityFactory
  7165. {
  7166. RoxieSortAlgorithm sortAlgorithm;
  7167. unsigned sortFlags;
  7168. public:
  7169. CRoxieServerSortActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  7170. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  7171. {
  7172. sortAlgorithm = heapSort;
  7173. sortFlags = TAFstable;
  7174. Owned<IHThorSortArg> sortHelper = (IHThorSortArg *) helperFactory();
  7175. IHThorAlgorithm *sortMethod = static_cast<IHThorAlgorithm *>(sortHelper->selectInterface(TAIalgorithm_1));
  7176. if (sortMethod)
  7177. {
  7178. sortFlags = sortMethod->getAlgorithmFlags();
  7179. if (sortFlags & TAFunstable)
  7180. sortAlgorithm = quickSort;
  7181. if (!(sortFlags & TAFconstant))
  7182. sortAlgorithm = unknownSort;
  7183. else
  7184. {
  7185. const char *useAlgorithm = sortMethod->queryAlgorithm();
  7186. if (useAlgorithm)
  7187. {
  7188. if (stricmp(useAlgorithm, "quicksort")==0)
  7189. {
  7190. if (sortFlags & TAFstable)
  7191. throw MakeStringException(ROXIE_UNKNOWN_ALGORITHM, "Invalid stable sort algorithm %s requested", useAlgorithm);
  7192. sortAlgorithm = quickSort;
  7193. }
  7194. else if (stricmp(useAlgorithm, "spillingquicksort")==0)
  7195. {
  7196. if (sortFlags & TAFstable)
  7197. throw MakeStringException(ROXIE_UNKNOWN_ALGORITHM, "Invalid stable sort algorithm %s requested", useAlgorithm);
  7198. sortAlgorithm = spillingQuickSort;
  7199. }
  7200. else if (stricmp(useAlgorithm, "heapsort")==0)
  7201. sortAlgorithm = heapSort; // NOTE - we do allow UNSTABLE('heapsort') in order to facilitate runtime selection
  7202. else if (stricmp(useAlgorithm, "insertionsort")==0)
  7203. sortAlgorithm = insertionSort;
  7204. else
  7205. {
  7206. WARNLOG(ROXIE_UNKNOWN_ALGORITHM, "Ignoring unsupported sort order algorithm '%s', using default", useAlgorithm);
  7207. if (sortFlags & TAFunstable)
  7208. sortAlgorithm = quickSort;
  7209. else
  7210. sortAlgorithm = heapSort;
  7211. }
  7212. }
  7213. }
  7214. }
  7215. }
  7216. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  7217. {
  7218. return new CRoxieServerSortActivity(this, _probeManager, sortAlgorithm, sortFlags);
  7219. }
  7220. };
  7221. IRoxieServerActivityFactory *createRoxieServerSortActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  7222. {
  7223. return new CRoxieServerSortActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  7224. }
  7225. //=====================================================================================================
  7226. class CRoxieServerSortedActivity : public CRoxieServerActivity
  7227. {
  7228. IHThorSortedArg &helper;
  7229. ICompare * compare;
  7230. const void *prev;
  7231. IRangeCompare * stepCompare;
  7232. public:
  7233. CRoxieServerSortedActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  7234. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSortedArg &)basehelper)
  7235. {
  7236. prev = NULL;
  7237. compare = helper.queryCompare();
  7238. stepCompare = NULL;
  7239. }
  7240. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7241. {
  7242. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  7243. IInputSteppingMeta * stepMeta = input->querySteppingMeta();
  7244. if (stepMeta)
  7245. stepCompare = stepMeta->queryCompare();
  7246. prev = NULL;
  7247. }
  7248. virtual void reset()
  7249. {
  7250. ReleaseClearRoxieRow(prev);
  7251. CRoxieServerActivity::reset();
  7252. }
  7253. virtual const void * nextInGroup()
  7254. {
  7255. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  7256. const void *ret = input->nextInGroup();
  7257. if (ret && prev && compare->docompare(prev, ret) > 0)
  7258. {
  7259. // MORE - better to give mismatching rows that indexes?
  7260. throw MakeStringException(ROXIE_NOT_SORTED, "SORTED(%u) detected incorrectly sorted rows (row %d, %d))", activityId, processed, processed+1);
  7261. }
  7262. ReleaseRoxieRow(prev);
  7263. prev = ret;
  7264. if (ret)
  7265. {
  7266. LinkRoxieRow(prev);
  7267. processed++;
  7268. }
  7269. return ret;
  7270. }
  7271. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  7272. {
  7273. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  7274. const void *ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  7275. if (ret && prev && compare->docompare(prev, ret) > 0)
  7276. {
  7277. // MORE - better to give mismatching rows that indexes?
  7278. throw MakeStringException(ROXIE_NOT_SORTED, "SORTED(%u) detected incorrectly sorted rows (row %d, %d))", activityId, processed, processed+1);
  7279. }
  7280. ReleaseRoxieRow(prev);
  7281. prev = ret;
  7282. if (ret)
  7283. {
  7284. LinkRoxieRow(prev);
  7285. processed++;
  7286. }
  7287. return ret;
  7288. }
  7289. IInputSteppingMeta * querySteppingMeta()
  7290. {
  7291. return input->querySteppingMeta();
  7292. }
  7293. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  7294. {
  7295. return input->gatherConjunctions(collector);
  7296. }
  7297. virtual void resetEOF()
  7298. {
  7299. input->resetEOF();
  7300. }
  7301. };
  7302. class CRoxieServerSortedActivityFactory : public CRoxieServerActivityFactory
  7303. {
  7304. public:
  7305. CRoxieServerSortedActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  7306. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  7307. {
  7308. }
  7309. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  7310. {
  7311. return new CRoxieServerSortedActivity(this, _probeManager);
  7312. }
  7313. };
  7314. IRoxieServerActivityFactory *createRoxieServerSortedActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  7315. {
  7316. return new CRoxieServerSortedActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  7317. }
  7318. //=====================================================================================================
  7319. class CRoxieServerThroughSpillActivity : public CRoxieServerActivity
  7320. {
  7321. /*
  7322. BE VERY CAREFUL - this code is tricky.
  7323. Note that starts and stops (and resets) can occur in strange orders
  7324. The FIRST start OR stop must initialize the activity but only the first START should call the upstream start.
  7325. The last stop should call the upstream stop.
  7326. The first reset should call the upstream reset.
  7327. The calculation of whether a row is needed for other (yet to come) outputs needs to work correctly even if the output in question has
  7328. not yet had start or stop called - for this to happen init() is called on all outputs on the first start or stop.
  7329. Some outputs may be completely pruned away when used in a GRAPH - these outputs should not receive any start/stop/reset and should be
  7330. ignored in the minIndex calculation
  7331. */
  7332. public:
  7333. IHThorArg &helper;
  7334. unsigned activeOutputs;
  7335. unsigned numOutputs;
  7336. unsigned numOriginalOutputs;
  7337. QueueOf<const void, true> buffer;
  7338. CriticalSection crit;
  7339. CriticalSection crit2;
  7340. unsigned tailIdx;
  7341. unsigned headIdx;
  7342. Owned<IException> error;
  7343. class OutputAdaptor : public CInterface, implements IRoxieInput
  7344. {
  7345. bool eof, eofpending, stopped;
  7346. public:
  7347. CRoxieServerThroughSpillActivity *parent;
  7348. unsigned idx;
  7349. unsigned oid;
  7350. unsigned processed;
  7351. unsigned __int64 totalCycles;
  7352. public:
  7353. IMPLEMENT_IINTERFACE;
  7354. OutputAdaptor()
  7355. {
  7356. parent = NULL;
  7357. oid = 0;
  7358. idx = 0;
  7359. processed = 0;
  7360. totalCycles = 0;
  7361. eofpending = false;
  7362. eof = false;
  7363. stopped = false;
  7364. }
  7365. ~OutputAdaptor()
  7366. {
  7367. if (traceStartStop)
  7368. DBGLOG("%p ~OutputAdaptor %d", this, oid);
  7369. }
  7370. void init()
  7371. {
  7372. if (traceStartStop)
  7373. DBGLOG("%p init Input adaptor %d", this, oid);
  7374. idx = 0;
  7375. processed = 0;
  7376. totalCycles = 0;
  7377. eofpending = false;
  7378. eof = false;
  7379. stopped = false;
  7380. }
  7381. virtual unsigned queryId() const
  7382. {
  7383. return parent->queryId();
  7384. }
  7385. virtual IRoxieServerActivity *queryActivity()
  7386. {
  7387. return parent;
  7388. }
  7389. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  7390. {
  7391. return parent->queryIndexReadActivity();
  7392. }
  7393. virtual unsigned __int64 queryTotalCycles() const
  7394. {
  7395. return totalCycles;
  7396. }
  7397. virtual unsigned __int64 queryLocalCycles() const
  7398. {
  7399. return 0;
  7400. }
  7401. virtual IRoxieInput *queryInput(unsigned idx) const
  7402. {
  7403. return parent->queryInput(idx);
  7404. }
  7405. virtual const void * nextInGroup()
  7406. {
  7407. ActivityTimer t(totalCycles, timeActivities, parent->ctx->queryDebugContext());
  7408. if (eof)
  7409. return NULL;
  7410. const void *ret = parent->readBuffered(idx, oid);
  7411. #ifdef TRACE_SPLIT
  7412. parent->CTXLOG("Adaptor %d got back %p for record %d", oid, ret, idx);
  7413. #endif
  7414. idx++;
  7415. if (ret)
  7416. {
  7417. processed++;
  7418. eofpending = false;
  7419. }
  7420. else if (eofpending)
  7421. eof = true;
  7422. else
  7423. eofpending = true;
  7424. return ret;
  7425. }
  7426. virtual IOutputMetaData * queryOutputMeta() const
  7427. {
  7428. return parent->queryOutputMeta();
  7429. }
  7430. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7431. {
  7432. // NOTE: it is tempting to move the init() of all output adaptors here. However that is not a good idea,
  7433. // since adaptors that have not yet started or stoppped (but are going to) still need to have been init()'ed
  7434. // for minIndex to give the correct answers
  7435. // therefore, we call init() on all adaptors on receipt of the first start() or stop()
  7436. if (traceStartStop)
  7437. parent->CTXLOG("%p start Input adaptor %d stopped = %d", this, oid, stopped);
  7438. parent->start(oid, parentExtractSize, parentExtract, paused);
  7439. }
  7440. virtual void stop(bool aborting)
  7441. {
  7442. if (traceStartStop)
  7443. parent->CTXLOG("%p stop Input adaptor %d stopped = %d", this, oid, stopped);
  7444. if (!stopped)
  7445. {
  7446. parent->stop(oid, idx, aborting); // NOTE - may call init()
  7447. stopped = true; // parent code relies on stop being called exactly once per adaptor, so make sure it is!
  7448. idx = (unsigned) -1; // causes minIndex not to save rows for me...
  7449. }
  7450. };
  7451. virtual void reset()
  7452. {
  7453. if (traceStartStop)
  7454. parent->CTXLOG("%p reset Input adaptor %d stopped = %d", this, oid, stopped);
  7455. parent->reset(oid, processed);
  7456. processed = 0;
  7457. idx = 0; // value should not be relevant really but this is the safest...
  7458. stopped = false;
  7459. };
  7460. virtual void resetEOF()
  7461. {
  7462. parent->resetEOF();
  7463. }
  7464. virtual void checkAbort()
  7465. {
  7466. parent->checkAbort();
  7467. }
  7468. } *adaptors;
  7469. bool *used;
  7470. unsigned nextFreeOutput()
  7471. {
  7472. unsigned i = numOutputs;
  7473. while (i)
  7474. {
  7475. i--;
  7476. if (!used[i])
  7477. return i;
  7478. }
  7479. throwUnexpected();
  7480. }
  7481. unsigned minIndex(unsigned exceptOid)
  7482. {
  7483. // MORE - yukky code (and slow). Could keep them heapsorted by idx or something
  7484. // this is trying to determine whethwe any of the adaptors will in the future read a given record
  7485. unsigned minIdx = (unsigned) -1;
  7486. for (unsigned i = 0; i < numOutputs; i++)
  7487. {
  7488. if (i != exceptOid && used[i] && adaptors[i].idx < minIdx)
  7489. minIdx = adaptors[i].idx;
  7490. }
  7491. return minIdx;
  7492. }
  7493. void initOutputs()
  7494. {
  7495. activeOutputs = numOutputs;
  7496. for (unsigned i = 0; i < numOriginalOutputs; i++)
  7497. if (used[i])
  7498. adaptors[i].init();
  7499. state = STATEstarting;
  7500. }
  7501. public:
  7502. CRoxieServerThroughSpillActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numOutputs)
  7503. : CRoxieServerActivity(_factory, _probeManager), helper(basehelper), numOutputs(_numOutputs)
  7504. {
  7505. numOriginalOutputs = numOutputs;
  7506. adaptors = new OutputAdaptor[numOutputs];
  7507. used = new bool[numOutputs];
  7508. for (unsigned i = 0; i < numOutputs; i++)
  7509. {
  7510. adaptors[i].parent = this;
  7511. adaptors[i].oid = i;
  7512. used[i] = false;
  7513. }
  7514. tailIdx = 0;
  7515. headIdx = 0;
  7516. activeOutputs = numOutputs;
  7517. }
  7518. ~CRoxieServerThroughSpillActivity()
  7519. {
  7520. delete [] adaptors;
  7521. delete [] used;
  7522. }
  7523. const void *readBuffered(unsigned idx, unsigned oid)
  7524. {
  7525. CriticalBlock b(crit);
  7526. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext()); // NOTE - time spent waiting for crit not included here. Is that right?
  7527. if (idx == headIdx) // test once without getting the crit2 sec
  7528. {
  7529. CriticalUnblock b1(crit);
  7530. CriticalBlock b2(crit2);
  7531. if (error)
  7532. {
  7533. throw error.getLink();
  7534. }
  7535. if (idx == headIdx) // test again now that we have it
  7536. {
  7537. try
  7538. {
  7539. const void *row = input->nextInGroup();
  7540. CriticalBlock b3(crit);
  7541. headIdx++;
  7542. if (row) processed++;
  7543. if (activeOutputs==1)
  7544. {
  7545. #ifdef TRACE_SPLIT
  7546. CTXLOG("spill %d optimised return of %p", activityId, row);
  7547. #endif
  7548. return row; // optimization for the case where only one output still active.
  7549. }
  7550. buffer.enqueue(row);
  7551. }
  7552. catch (IException *E)
  7553. {
  7554. #ifdef TRACE_SPLIT
  7555. CTXLOG("spill %d caught exception", activityId);
  7556. #endif
  7557. error.set(E);
  7558. throw;
  7559. }
  7560. catch (...)
  7561. {
  7562. IException *E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught in CRoxieServerThroughSpillActivity::readBuffered");
  7563. error.set(E);
  7564. throw E;
  7565. }
  7566. }
  7567. }
  7568. idx -= tailIdx;
  7569. if (!idx)
  7570. {
  7571. unsigned min = minIndex(oid);
  7572. if (min > tailIdx)
  7573. {
  7574. tailIdx++;
  7575. const void *ret = buffer.dequeue(); // no need to link - last puller
  7576. #ifdef TRACE_SPLIT
  7577. CTXLOG("last puller return of %p", ret);
  7578. #endif
  7579. return ret;
  7580. }
  7581. }
  7582. const void *ret = buffer.item(idx);
  7583. if (ret) LinkRoxieRow(ret);
  7584. #ifdef TRACE_SPLIT
  7585. CTXLOG("standard return of %p", ret);
  7586. #endif
  7587. return ret;
  7588. }
  7589. virtual void start(unsigned oid, unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7590. {
  7591. CriticalBlock b(crit);
  7592. if (error)
  7593. throw error.getLink();
  7594. if (factory)
  7595. factory->noteStarted(oid);
  7596. if (traceStartStop)
  7597. CTXLOG("SPLIT %p: start %d child %d activeOutputs %d numOutputs %d numOriginalOutputs %d state %s", this, activityId, oid, activeOutputs, numOutputs, numOriginalOutputs, queryStateText(state));
  7598. if (state != STATEstarted)
  7599. {
  7600. if (state != STATEstarting)
  7601. initOutputs();
  7602. tailIdx = 0;
  7603. headIdx = 0;
  7604. error.clear();
  7605. try
  7606. {
  7607. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  7608. }
  7609. catch (IException *E)
  7610. {
  7611. #ifdef TRACE_SPLIT
  7612. CTXLOG("spill %d caught exception in start", activityId);
  7613. #endif
  7614. error.set(E);
  7615. throw;
  7616. }
  7617. catch (...)
  7618. {
  7619. IException *E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught in CRoxieServerThroughSpillActivity::start");
  7620. error.set(E);
  7621. throw E;
  7622. }
  7623. }
  7624. }
  7625. void stop(unsigned oid, unsigned idx, bool aborting)
  7626. {
  7627. // Note that OutputAdaptor code ensures that stop is not called more than once per adaptor
  7628. CriticalBlock b(crit);
  7629. #ifdef TRACE_STARTSTOP
  7630. if (traceStartStop)
  7631. {
  7632. CTXLOG("SPLIT %p: stop %d child %d activeOutputs %d numOutputs %d numOriginalOutputs %d state %s", this, activityId, oid, activeOutputs, numOutputs, numOriginalOutputs, queryStateText(state));
  7633. if (watchActivityId && watchActivityId==activityId)
  7634. {
  7635. CTXLOG("WATCH: stop %d", activityId);
  7636. }
  7637. }
  7638. #endif
  7639. if (state != STATEstarting && state != STATEstarted)
  7640. initOutputs();
  7641. if (activeOutputs > 1)
  7642. {
  7643. if (tailIdx==idx)
  7644. {
  7645. // Discard all buffered rows that are there purely for this adaptor to read them
  7646. unsigned min = minIndex(oid);
  7647. if (min != (unsigned) -1)
  7648. // what does -1 signify?? No-one wants anything? In which case can't we kill all rows??
  7649. // Should never happen though if there are still some active.
  7650. // there may be a small window where adaptors are blocked on the semaphore...
  7651. {
  7652. #ifdef TRACE_SPLIT
  7653. CTXLOG("%p: Discarding buffered rows from %d to %d for oid %x (%d outputs active)", this, idx, min, oid, activeOutputs);
  7654. #endif
  7655. while (tailIdx < min)
  7656. {
  7657. ReleaseRoxieRow(buffer.dequeue());
  7658. tailIdx++;
  7659. }
  7660. }
  7661. }
  7662. activeOutputs--;
  7663. return;
  7664. }
  7665. #ifdef TRACE_SPLIT
  7666. CTXLOG("%p: All outputs done", this);
  7667. #endif
  7668. activeOutputs = numOutputs;
  7669. CRoxieServerActivity::stop(aborting);
  7670. };
  7671. void reset(unsigned oid, unsigned _processed)
  7672. {
  7673. if (traceStartStop)
  7674. CTXLOG("SPLIT %p: reset %d child %d activeOutputs %d numOutputs %d numOriginalOutputs %d state %s", this, activityId, oid, activeOutputs, numOutputs, numOriginalOutputs, queryStateText(state));
  7675. activeOutputs = numOutputs;
  7676. while (buffer.ordinality())
  7677. ReleaseRoxieRow(buffer.dequeue());
  7678. error.clear();
  7679. if (state != STATEreset) // make sure input is only reset once
  7680. CRoxieServerActivity::reset();
  7681. };
  7682. virtual unsigned __int64 queryLocalCycles() const
  7683. {
  7684. return 0;
  7685. }
  7686. virtual const void *nextInGroup()
  7687. {
  7688. throwUnexpected(); // Internal logic error - we are not anybody's input
  7689. }
  7690. virtual IOutputMetaData * queryOutputMeta() const
  7691. {
  7692. // if (outputMeta)
  7693. // return outputMeta;
  7694. // else
  7695. return input->queryOutputMeta(); // not always known (e.g. disk write - though Gavin _could_ fill it in)
  7696. }
  7697. virtual IRoxieInput *queryOutput(unsigned idx)
  7698. {
  7699. if (idx==(unsigned)-1)
  7700. idx = nextFreeOutput(); // MORE - what is this used for?
  7701. assertex(idx < numOriginalOutputs);
  7702. assertex(!used[idx]);
  7703. used[idx] = true;
  7704. return &adaptors[idx];
  7705. }
  7706. virtual void resetOutputsUsed()
  7707. {
  7708. numOutputs = 1;
  7709. activeOutputs = 1;
  7710. // MORE RKC->GH should we be clearing the used array here? anywhere?
  7711. }
  7712. virtual void noteOutputUsed()
  7713. {
  7714. assertex(numOutputs < numOriginalOutputs);
  7715. numOutputs++;
  7716. activeOutputs = numOutputs;
  7717. }
  7718. virtual bool isPassThrough()
  7719. {
  7720. return numOutputs==1;
  7721. }
  7722. };
  7723. class CRoxieServerThroughSpillActivityFactory : public CRoxieServerMultiOutputFactory
  7724. {
  7725. public:
  7726. CRoxieServerThroughSpillActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  7727. : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  7728. {
  7729. Owned<IHThorSpillArg> helper = (IHThorSpillArg *) helperFactory();
  7730. setNumOutputs(helper->getTempUsageCount() + 1);
  7731. }
  7732. CRoxieServerThroughSpillActivityFactory(IQueryFactory &_queryFactory, HelperFactory *_helperFactory, unsigned _numOutputs)
  7733. : CRoxieServerMultiOutputFactory(0, 0, _queryFactory, _helperFactory, TAKsplit)
  7734. {
  7735. setNumOutputs(_numOutputs);
  7736. }
  7737. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  7738. {
  7739. return new CRoxieServerThroughSpillActivity(this, _probeManager, numOutputs);
  7740. }
  7741. };
  7742. IRoxieServerActivityFactory *createRoxieServerThroughSpillActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  7743. {
  7744. return new CRoxieServerThroughSpillActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  7745. }
  7746. IRoxieServerActivityFactory *createRoxieServerThroughSpillActivityFactory(IQueryFactory &_queryFactory, HelperFactory *_factory, unsigned _numOutputs)
  7747. {
  7748. return new CRoxieServerThroughSpillActivityFactory(_queryFactory, _factory, _numOutputs);
  7749. }
  7750. //----------------------------------------------------------------------------------------------
  7751. class CRoxieServerSplitActivityFactory : public CRoxieServerMultiOutputFactory
  7752. {
  7753. public:
  7754. CRoxieServerSplitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  7755. : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  7756. {
  7757. Owned<IHThorSplitArg> helper = (IHThorSplitArg *) helperFactory();
  7758. setNumOutputs(helper->numBranches());
  7759. }
  7760. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  7761. {
  7762. return new CRoxieServerThroughSpillActivity(this, _probeManager, numOutputs);
  7763. }
  7764. };
  7765. IRoxieServerActivityFactory *createRoxieServerSplitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  7766. {
  7767. return new CRoxieServerSplitActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  7768. }
  7769. //=====================================================================================================
  7770. #define PIPE_BUFSIZE 0x8000
  7771. static IException *createPipeFailureException(const char *cmd, unsigned retcode, IPipeProcess *pipe)
  7772. {
  7773. StringBuffer msg;
  7774. if(pipe->hasError())
  7775. {
  7776. try
  7777. {
  7778. char error[512];
  7779. size32_t sz = pipe->readError(sizeof(error), error);
  7780. if(sz && sz!=(size32_t)-1)
  7781. msg.append(", stderr: '").append(sz, error).append("'");
  7782. }
  7783. catch (IException *e)
  7784. {
  7785. EXCLOG(e, "Error reading pipe stderr");
  7786. e->Release();
  7787. }
  7788. }
  7789. return MakeStringException(ROXIE_PIPE_ERROR, "Pipe process %s returned error %u%s", cmd, retcode, msg.str());
  7790. }
  7791. class CRoxieServerPipeReadActivity : public CRoxieServerActivity
  7792. {
  7793. IHThorPipeReadArg &helper;
  7794. Owned<IPipeProcess> pipe;
  7795. StringAttr pipeCommand;
  7796. Owned<IOutputRowDeserializer> rowDeserializer;
  7797. Owned<IReadRowStream> readTransformer;
  7798. bool groupSignalled;
  7799. public:
  7800. CRoxieServerPipeReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  7801. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorPipeReadArg &)basehelper)
  7802. {
  7803. groupSignalled = true;
  7804. }
  7805. virtual bool needsAllocator() const { return true; }
  7806. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  7807. {
  7808. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  7809. rowDeserializer.setown(rowAllocator->createRowDeserializer(ctx->queryCodeContext()));
  7810. }
  7811. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7812. {
  7813. groupSignalled = true; // i.e. don't start with a NULL row
  7814. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  7815. if (!readTransformer)
  7816. readTransformer.setown(createReadRowStream(rowAllocator, rowDeserializer, helper.queryXmlTransformer(), helper.queryCsvTransformer(), helper.queryXmlIteratorPath(), helper.getPipeFlags()));
  7817. openPipe(helper.getPipeProgram());
  7818. }
  7819. virtual void stop(bool aborting)
  7820. {
  7821. CRoxieServerActivity::stop(aborting);
  7822. pipe.clear();
  7823. readTransformer->setStream(NULL);
  7824. }
  7825. virtual const void *nextInGroup()
  7826. {
  7827. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  7828. while (!waitForPipe())
  7829. {
  7830. if (!pipe)
  7831. return NULL;
  7832. if (helper.getPipeFlags() & TPFgroupeachrow)
  7833. {
  7834. if (!groupSignalled)
  7835. {
  7836. groupSignalled = true;
  7837. return NULL;
  7838. }
  7839. }
  7840. }
  7841. const void *ret = readTransformer->next();
  7842. assertex(ret != NULL); // if ret can ever be NULL then we need to recode this logic
  7843. processed++;
  7844. groupSignalled = false;
  7845. return ret;
  7846. }
  7847. protected:
  7848. bool waitForPipe()
  7849. {
  7850. if (!pipe)
  7851. return false; // done
  7852. if (!readTransformer->eos())
  7853. return true;
  7854. verifyPipe();
  7855. return false;
  7856. }
  7857. void openPipe(char const * cmd)
  7858. {
  7859. pipeCommand.setown(cmd);
  7860. pipe.setown(createPipeProcess());
  7861. if(!pipe->run(NULL, cmd, ".", false, true, true, 0x10000))
  7862. throw MakeStringException(ROXIE_PIPE_ERROR, "Could not run pipe process %s", cmd);
  7863. Owned<ISimpleReadStream> pipeReader = pipe->getOutputStream();
  7864. readTransformer->setStream(pipeReader.get());
  7865. }
  7866. void verifyPipe()
  7867. {
  7868. if (pipe)
  7869. {
  7870. unsigned err = pipe->wait();
  7871. if(err && !(helper.getPipeFlags() & TPFnofail))
  7872. {
  7873. throw createPipeFailureException(pipeCommand.get(), err, pipe);
  7874. }
  7875. pipe.clear();
  7876. }
  7877. }
  7878. };
  7879. class CRoxieServerPipeThroughActivity : public CRoxieServerActivity, implements IRecordPullerCallback
  7880. {
  7881. IHThorPipeThroughArg &helper;
  7882. RecordPullerThread puller;
  7883. Owned<IPipeProcess> pipe;
  7884. StringAttr pipeCommand;
  7885. InterruptableSemaphore pipeVerified;
  7886. InterruptableSemaphore pipeOpened;
  7887. CachedOutputMetaData inputMeta;
  7888. Owned<IOutputRowSerializer> rowSerializer;
  7889. Owned<IOutputRowDeserializer> rowDeserializer;
  7890. Owned<IPipeWriteXformHelper> writeTransformer;
  7891. Owned<IReadRowStream> readTransformer;
  7892. bool firstRead;
  7893. bool recreate;
  7894. bool inputExhausted;
  7895. bool groupSignalled;
  7896. public:
  7897. CRoxieServerPipeThroughActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  7898. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorPipeThroughArg &)basehelper), puller(false)
  7899. {
  7900. recreate = helper.recreateEachRow();
  7901. groupSignalled = true;
  7902. firstRead = false;
  7903. inputExhausted = false;
  7904. }
  7905. virtual bool needsAllocator() const { return true; }
  7906. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  7907. {
  7908. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  7909. rowSerializer.setown(inputMeta.createRowSerializer(ctx->queryCodeContext(), activityId));
  7910. rowDeserializer.setown(rowAllocator->createRowDeserializer(ctx->queryCodeContext()));
  7911. writeTransformer.setown(createPipeWriteXformHelper(helper.getPipeFlags(), helper.queryXmlOutput(), helper.queryCsvOutput(), rowSerializer));
  7912. }
  7913. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  7914. {
  7915. firstRead = true;
  7916. inputExhausted = false;
  7917. groupSignalled = true; // i.e. don't start with a NULL row
  7918. pipeVerified.reinit();
  7919. pipeOpened.reinit();
  7920. writeTransformer->ready();
  7921. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  7922. if (!readTransformer)
  7923. readTransformer.setown(createReadRowStream(rowAllocator, rowDeserializer, helper.queryXmlTransformer(), helper.queryCsvTransformer(), helper.queryXmlIteratorPath(), helper.getPipeFlags()));
  7924. if(!recreate)
  7925. openPipe(helper.getPipeProgram());
  7926. puller.start(parentExtractSize, parentExtract, paused, 0, false, ctx); // Pipe does not support preload presently - locks up
  7927. }
  7928. virtual void setInput(unsigned idx, IRoxieInput *_in)
  7929. {
  7930. if (idx)
  7931. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  7932. puller.setInput(this, _in);
  7933. inputMeta.set(_in->queryOutputMeta());
  7934. }
  7935. virtual void stop(bool aborting)
  7936. {
  7937. pipeVerified.interrupt(NULL);
  7938. pipeOpened.interrupt(NULL);
  7939. puller.stop(aborting);
  7940. CRoxieServerActivity::stop(aborting);
  7941. pipe.clear();
  7942. readTransformer->setStream(NULL);
  7943. }
  7944. virtual void reset()
  7945. {
  7946. puller.reset();
  7947. CRoxieServerActivity::reset();
  7948. }
  7949. virtual const void *nextInGroup()
  7950. {
  7951. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  7952. while (!waitForPipe())
  7953. {
  7954. if (!pipe)
  7955. return NULL;
  7956. if (helper.getPipeFlags() & TPFgroupeachrow)
  7957. {
  7958. if (!groupSignalled)
  7959. {
  7960. groupSignalled = true;
  7961. return NULL;
  7962. }
  7963. }
  7964. }
  7965. const void *ret = readTransformer->next();
  7966. assertex(ret != NULL); // if ret can ever be NULL then we need to recode this logic
  7967. processed++;
  7968. groupSignalled = false;
  7969. return ret;
  7970. }
  7971. virtual void processRow(const void *row)
  7972. {
  7973. // called from puller thread
  7974. if(recreate)
  7975. openPipe(helper.getNameFromRow(row));
  7976. writeTransformer->writeTranslatedText(row, pipe);
  7977. ReleaseRoxieRow(row);
  7978. if(recreate)
  7979. {
  7980. closePipe();
  7981. pipeVerified.wait();
  7982. }
  7983. }
  7984. virtual void processDone()
  7985. {
  7986. // called from puller thread
  7987. if(recreate)
  7988. {
  7989. inputExhausted = true;
  7990. pipeOpened.signal();
  7991. }
  7992. else
  7993. {
  7994. closePipe();
  7995. pipeVerified.wait();
  7996. }
  7997. }
  7998. virtual void processEOG()
  7999. {
  8000. }
  8001. void processGroup(const ConstPointerArray &)
  8002. {
  8003. throwUnexpected();
  8004. }
  8005. virtual bool fireException(IException *e)
  8006. {
  8007. pipeOpened.interrupt(LINK(e));
  8008. pipeVerified.interrupt(e);
  8009. return true;
  8010. }
  8011. private:
  8012. bool waitForPipe()
  8013. {
  8014. if (firstRead)
  8015. {
  8016. pipeOpened.wait();
  8017. firstRead = false;
  8018. }
  8019. if (!pipe)
  8020. return false; // done
  8021. if (!readTransformer->eos())
  8022. return true;
  8023. verifyPipe();
  8024. if (recreate && !inputExhausted)
  8025. pipeOpened.wait();
  8026. return false;
  8027. }
  8028. void openPipe(char const * cmd)
  8029. {
  8030. pipeCommand.setown(cmd);
  8031. pipe.setown(createPipeProcess());
  8032. if(!pipe->run(NULL, cmd, ".", true, true, true, 0x10000))
  8033. throw MakeStringException(ROXIE_PIPE_ERROR, "Could not run pipe process %s", cmd);
  8034. writeTransformer->writeHeader(pipe);
  8035. Owned<ISimpleReadStream> pipeReader = pipe->getOutputStream();
  8036. readTransformer->setStream(pipeReader.get());
  8037. pipeOpened.signal();
  8038. }
  8039. void closePipe()
  8040. {
  8041. writeTransformer->writeFooter(pipe);
  8042. pipe->closeInput();
  8043. }
  8044. void verifyPipe()
  8045. {
  8046. if (pipe)
  8047. {
  8048. unsigned err = pipe->wait();
  8049. if(err && !(helper.getPipeFlags() & TPFnofail))
  8050. {
  8051. throw createPipeFailureException(pipeCommand.get(), err, pipe);
  8052. }
  8053. pipe.clear();
  8054. pipeVerified.signal();
  8055. }
  8056. }
  8057. };
  8058. class CRoxieServerPipeWriteActivity : public CRoxieServerInternalSinkActivity
  8059. {
  8060. IHThorPipeWriteArg &helper;
  8061. Owned<IPipeProcess> pipe;
  8062. StringAttr pipeCommand;
  8063. CachedOutputMetaData inputMeta;
  8064. Owned<IOutputRowSerializer> rowSerializer;
  8065. Owned<IPipeWriteXformHelper> writeTransformer;
  8066. bool firstRead;
  8067. bool recreate;
  8068. bool inputExhausted;
  8069. public:
  8070. CRoxieServerPipeWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8071. : CRoxieServerInternalSinkActivity(_factory, _probeManager), helper((IHThorPipeWriteArg &)basehelper)
  8072. {
  8073. recreate = helper.recreateEachRow();
  8074. firstRead = false;
  8075. inputExhausted = false;
  8076. }
  8077. virtual bool needsAllocator() const { return true; }
  8078. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  8079. {
  8080. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  8081. inputMeta.set(input->queryOutputMeta());
  8082. rowSerializer.setown(inputMeta.createRowSerializer(ctx->queryCodeContext(), activityId));
  8083. writeTransformer.setown(createPipeWriteXformHelper(helper.getPipeFlags(), helper.queryXmlOutput(), helper.queryCsvOutput(), rowSerializer));
  8084. }
  8085. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8086. {
  8087. firstRead = true;
  8088. inputExhausted = false;
  8089. writeTransformer->ready();
  8090. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  8091. if(!recreate)
  8092. openPipe(helper.getPipeProgram());
  8093. }
  8094. virtual void stop(bool aborting)
  8095. {
  8096. CRoxieServerActivity::stop(aborting);
  8097. pipe.clear();
  8098. }
  8099. virtual void onExecute()
  8100. {
  8101. loop
  8102. {
  8103. const void *row = input->nextInGroup();
  8104. if (!row)
  8105. {
  8106. row = input->nextInGroup();
  8107. if (!row)
  8108. break;
  8109. }
  8110. processed++;
  8111. if(recreate)
  8112. openPipe(helper.getNameFromRow(row));
  8113. writeTransformer->writeTranslatedText(row, pipe);
  8114. ReleaseRoxieRow(row);
  8115. if(recreate)
  8116. closePipe();
  8117. }
  8118. closePipe();
  8119. }
  8120. private:
  8121. void openPipe(char const * cmd)
  8122. {
  8123. pipeCommand.setown(cmd);
  8124. pipe.setown(createPipeProcess());
  8125. if(!pipe->run(NULL, cmd, ".", true, false, true, 0x10000))
  8126. throw MakeStringException(ROXIE_PIPE_ERROR, "Could not run pipe process %s", cmd);
  8127. writeTransformer->writeHeader(pipe);
  8128. }
  8129. void closePipe()
  8130. {
  8131. writeTransformer->writeFooter(pipe);
  8132. pipe->closeInput();
  8133. unsigned err = pipe->wait();
  8134. if(err && !(helper.getPipeFlags() & TPFnofail))
  8135. {
  8136. throw createPipeFailureException(pipeCommand.get(), err, pipe);
  8137. }
  8138. pipe.clear();
  8139. }
  8140. };
  8141. class CRoxieServerPipeReadActivityFactory : public CRoxieServerActivityFactory
  8142. {
  8143. public:
  8144. CRoxieServerPipeReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8145. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  8146. {
  8147. }
  8148. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8149. {
  8150. return new CRoxieServerPipeReadActivity(this, _probeManager);
  8151. }
  8152. };
  8153. class CRoxieServerPipeThroughActivityFactory : public CRoxieServerActivityFactory
  8154. {
  8155. public:
  8156. CRoxieServerPipeThroughActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8157. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  8158. {
  8159. }
  8160. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8161. {
  8162. return new CRoxieServerPipeThroughActivity(this, _probeManager);
  8163. }
  8164. };
  8165. class CRoxieServerPipeWriteActivityFactory : public CRoxieServerInternalSinkFactory
  8166. {
  8167. public:
  8168. CRoxieServerPipeWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  8169. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot)
  8170. {
  8171. }
  8172. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8173. {
  8174. return new CRoxieServerPipeWriteActivity(this, _probeManager);
  8175. }
  8176. };
  8177. IRoxieServerActivityFactory *createRoxieServerPipeReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8178. {
  8179. return new CRoxieServerPipeReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  8180. }
  8181. IRoxieServerActivityFactory *createRoxieServerPipeThroughActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8182. {
  8183. return new CRoxieServerPipeThroughActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  8184. }
  8185. IRoxieServerActivityFactory *createRoxieServerPipeWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  8186. {
  8187. return new CRoxieServerPipeWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot);
  8188. }
  8189. //=====================================================================================================
  8190. class CRoxieServerStreamedIteratorActivity : public CRoxieServerActivity
  8191. {
  8192. IHThorStreamedIteratorArg &helper;
  8193. Owned<IRowStream> rows;
  8194. public:
  8195. CRoxieServerStreamedIteratorActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8196. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorStreamedIteratorArg &)basehelper)
  8197. {
  8198. }
  8199. ~CRoxieServerStreamedIteratorActivity()
  8200. {
  8201. }
  8202. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8203. {
  8204. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  8205. rows.setown(helper.createInput());
  8206. }
  8207. virtual void stop(bool aborting)
  8208. {
  8209. if (rows)
  8210. {
  8211. rows->stop();
  8212. rows.clear();
  8213. }
  8214. CRoxieServerActivity::stop(aborting);
  8215. }
  8216. virtual const void *nextInGroup()
  8217. {
  8218. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8219. assertex(rows != NULL);
  8220. const void * next = rows->nextRow();
  8221. if (next)
  8222. processed++;
  8223. return next;
  8224. }
  8225. };
  8226. class CRoxieServerStreamedIteratorActivityFactory : public CRoxieServerActivityFactory
  8227. {
  8228. public:
  8229. CRoxieServerStreamedIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8230. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  8231. {
  8232. }
  8233. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8234. {
  8235. return new CRoxieServerStreamedIteratorActivity(this, _probeManager);
  8236. }
  8237. };
  8238. IRoxieServerActivityFactory *createRoxieServerStreamedIteratorActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8239. {
  8240. return new CRoxieServerStreamedIteratorActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  8241. }
  8242. //=====================================================================================================
  8243. class CRoxieServerFilterActivity : public CRoxieServerLateStartActivity
  8244. {
  8245. IHThorFilterArg &helper;
  8246. bool anyThisGroup;
  8247. IRangeCompare * stepCompare;
  8248. public:
  8249. CRoxieServerFilterActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8250. : CRoxieServerLateStartActivity(_factory, _probeManager), helper((IHThorFilterArg &)basehelper)
  8251. {
  8252. anyThisGroup = false;
  8253. stepCompare = NULL;
  8254. }
  8255. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8256. {
  8257. anyThisGroup = false;
  8258. CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
  8259. lateStart(parentExtractSize, parentExtract, helper.canMatchAny());
  8260. stepCompare = NULL;
  8261. if (!eof)
  8262. {
  8263. IInputSteppingMeta * stepMeta = input->querySteppingMeta();
  8264. if (stepMeta)
  8265. stepCompare = stepMeta->queryCompare();
  8266. }
  8267. }
  8268. virtual const void * nextInGroup()
  8269. {
  8270. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8271. if (eof)
  8272. return NULL;
  8273. loop
  8274. {
  8275. const void * ret = input->nextInGroup();
  8276. if (!ret)
  8277. {
  8278. //stop returning two NULLs in a row.
  8279. if (anyThisGroup)
  8280. {
  8281. anyThisGroup = false;
  8282. return NULL;
  8283. }
  8284. ret = input->nextInGroup();
  8285. if (!ret)
  8286. {
  8287. eof = true;
  8288. return NULL; // eof...
  8289. }
  8290. }
  8291. if (helper.isValid(ret))
  8292. {
  8293. anyThisGroup = true;
  8294. processed++;
  8295. return ret;
  8296. }
  8297. ReleaseRoxieRow(ret);
  8298. }
  8299. }
  8300. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  8301. {
  8302. //Could assert that this isn't grouped
  8303. // MORE - will need rethinking once we rethink the nextSteppedGE interface for global smart-stepping.
  8304. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8305. if (eof)
  8306. return NULL;
  8307. loop
  8308. {
  8309. const void * ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  8310. if (!ret)
  8311. {
  8312. eof = true;
  8313. return NULL;
  8314. }
  8315. if (!wasCompleteMatch)
  8316. {
  8317. anyThisGroup = false; // RKC->GH - is this right??
  8318. return ret;
  8319. }
  8320. if (helper.isValid(ret))
  8321. {
  8322. anyThisGroup = true;
  8323. processed++;
  8324. return ret;
  8325. }
  8326. if (!stepExtra.returnMismatches())
  8327. {
  8328. ReleaseRoxieRow(ret);
  8329. return nextInGroup();
  8330. }
  8331. if (stepCompare->docompare(ret, seek, numFields) != 0)
  8332. {
  8333. wasCompleteMatch = false;
  8334. anyThisGroup = false; // WHY?
  8335. return ret;
  8336. }
  8337. ReleaseRoxieRow(ret);
  8338. }
  8339. }
  8340. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  8341. {
  8342. return input->gatherConjunctions(collector);
  8343. }
  8344. virtual void resetEOF()
  8345. {
  8346. eof = prefiltered;
  8347. anyThisGroup = false;
  8348. input->resetEOF();
  8349. }
  8350. IInputSteppingMeta * querySteppingMeta()
  8351. {
  8352. return input->querySteppingMeta();
  8353. }
  8354. };
  8355. class CRoxieServerFilterActivityFactory : public CRoxieServerActivityFactory
  8356. {
  8357. public:
  8358. CRoxieServerFilterActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8359. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  8360. {
  8361. }
  8362. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8363. {
  8364. return new CRoxieServerFilterActivity(this, _probeManager);
  8365. }
  8366. };
  8367. IRoxieServerActivityFactory *createRoxieServerFilterActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8368. {
  8369. return new CRoxieServerFilterActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  8370. }
  8371. //=====================================================================================================
  8372. class CRoxieServerFilterGroupActivity : public CRoxieServerLateStartActivity
  8373. {
  8374. IHThorFilterGroupArg &helper;
  8375. unsigned curIndex;
  8376. ConstPointerArray gathered;
  8377. IRangeCompare * stepCompare;
  8378. public:
  8379. CRoxieServerFilterGroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8380. : CRoxieServerLateStartActivity(_factory, _probeManager), helper((IHThorFilterGroupArg &)basehelper)
  8381. {
  8382. curIndex = 0;
  8383. stepCompare = NULL;
  8384. }
  8385. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8386. {
  8387. CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
  8388. lateStart(parentExtractSize, parentExtract, helper.canMatchAny());//sets eof
  8389. assertex(eof == !helper.canMatchAny());
  8390. curIndex = 0;
  8391. stepCompare = NULL;
  8392. if (!eof)
  8393. {
  8394. IInputSteppingMeta * inputStepping = input->querySteppingMeta();
  8395. if (inputStepping)
  8396. stepCompare = inputStepping->queryCompare();
  8397. }
  8398. }
  8399. virtual void reset()
  8400. {
  8401. releaseGathered();
  8402. CRoxieServerLateStartActivity::reset();
  8403. }
  8404. inline void releaseGathered()
  8405. {
  8406. while (gathered.isItem(curIndex))
  8407. ReleaseRoxieRow(gathered.item(curIndex++));
  8408. gathered.kill();
  8409. }
  8410. virtual const void * nextInGroup()
  8411. {
  8412. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8413. loop
  8414. {
  8415. if (eof)
  8416. return NULL;
  8417. if (gathered.ordinality())
  8418. {
  8419. if (gathered.isItem(curIndex))
  8420. {
  8421. const void * ret = gathered.item(curIndex++);
  8422. processed++;
  8423. return ret;
  8424. }
  8425. curIndex = 0;
  8426. gathered.kill();
  8427. return NULL;
  8428. }
  8429. const void * ret = input->nextInGroup();
  8430. while (ret)
  8431. {
  8432. gathered.append(ret);
  8433. ret = input->nextInGroup();
  8434. }
  8435. unsigned num = gathered.ordinality();
  8436. if (num != 0)
  8437. {
  8438. if (!helper.isValid(num, (const void * *)gathered.getArray()))
  8439. ReleaseRoxieRowSet(gathered); // read next group
  8440. }
  8441. else
  8442. eof = true;
  8443. }
  8444. }
  8445. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  8446. {
  8447. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8448. if (eof)
  8449. return NULL;
  8450. if (gathered.ordinality())
  8451. {
  8452. while (gathered.isItem(curIndex))
  8453. {
  8454. const void * ret = gathered.item(curIndex++);
  8455. if (stepCompare->docompare(ret, seek, numFields) >= 0)
  8456. {
  8457. processed++;
  8458. return ret;
  8459. }
  8460. ReleaseRoxieRow(ret);
  8461. }
  8462. curIndex = 0;
  8463. gathered.kill();
  8464. //nextSteppedGE never returns an end of group marker.
  8465. }
  8466. //Not completely sure about this - it could lead the the start of a group being skipped,
  8467. //so the group filter could potentially work on a different group. If so, we'd need to check the
  8468. //next fields were a subset of the grouping fields - more an issue for the group activity.
  8469. //MORE: What do we do with wasCompleteMatch? something like the following????
  8470. #if 0
  8471. loop
  8472. {
  8473. const void * ret;
  8474. if (stepExtra.returnMismatches())
  8475. {
  8476. bool matchedCompletely = true;
  8477. ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  8478. if (!wasCompleteMatch)
  8479. return ret;
  8480. }
  8481. else
  8482. ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  8483. #endif
  8484. const void * ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  8485. while (ret)
  8486. {
  8487. gathered.append(ret);
  8488. ret = input->nextInGroup();
  8489. }
  8490. unsigned num = gathered.ordinality();
  8491. if (num != 0)
  8492. {
  8493. if (!helper.isValid(num, (const void * *)gathered.getArray()))
  8494. ReleaseRoxieRowSet(gathered); // read next group
  8495. }
  8496. else
  8497. eof = true;
  8498. return nextUngrouped(this);
  8499. }
  8500. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  8501. {
  8502. return input->gatherConjunctions(collector);
  8503. }
  8504. virtual void resetEOF()
  8505. {
  8506. eof = false;
  8507. releaseGathered();
  8508. input->resetEOF();
  8509. }
  8510. IInputSteppingMeta * querySteppingMeta()
  8511. {
  8512. return input->querySteppingMeta();
  8513. }
  8514. };
  8515. class CRoxieServerFilterGroupActivityFactory : public CRoxieServerActivityFactory
  8516. {
  8517. public:
  8518. CRoxieServerFilterGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8519. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  8520. {
  8521. }
  8522. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8523. {
  8524. return new CRoxieServerFilterGroupActivity(this, _probeManager);
  8525. }
  8526. };
  8527. IRoxieServerActivityFactory *createRoxieServerFilterGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8528. {
  8529. return new CRoxieServerFilterGroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  8530. }
  8531. //=================================================================================
  8532. class CRoxieServerSideEffectActivity : public CRoxieServerActivity
  8533. {
  8534. IHThorSideEffectArg &helper;
  8535. CriticalSection ecrit;
  8536. Owned<IException> exception;
  8537. bool executed;
  8538. public:
  8539. CRoxieServerSideEffectActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8540. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSideEffectArg &)basehelper)
  8541. {
  8542. executed = false;
  8543. }
  8544. virtual const void * nextInGroup()
  8545. {
  8546. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8547. CriticalBlock b(ecrit);
  8548. if (exception)
  8549. throw(exception.getLink());
  8550. if (!executed)
  8551. {
  8552. try
  8553. {
  8554. executed = true;
  8555. helper.action();
  8556. }
  8557. catch(IException *E)
  8558. {
  8559. exception.set(E);
  8560. throw;
  8561. }
  8562. }
  8563. return NULL;
  8564. }
  8565. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  8566. {
  8567. CriticalBlock b(ecrit);
  8568. if (exception)
  8569. throw(exception.getLink());
  8570. if (!executed)
  8571. {
  8572. try
  8573. {
  8574. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8575. executed = true;
  8576. start(parentExtractSize, parentExtract, false);
  8577. helper.action();
  8578. stop(false);
  8579. }
  8580. catch(IException *E)
  8581. {
  8582. ctx->notifyAbort(E);
  8583. stop(true);
  8584. exception.set(E);
  8585. throw;
  8586. }
  8587. }
  8588. }
  8589. virtual void reset()
  8590. {
  8591. executed = false;
  8592. exception.clear();
  8593. CRoxieServerActivity::reset();
  8594. }
  8595. };
  8596. class CRoxieServerSideEffectActivityFactory : public CRoxieServerActivityFactory
  8597. {
  8598. bool isRoot;
  8599. public:
  8600. CRoxieServerSideEffectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  8601. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  8602. {
  8603. }
  8604. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8605. {
  8606. return new CRoxieServerSideEffectActivity(this, _probeManager);
  8607. }
  8608. virtual bool isSink() const
  8609. {
  8610. return isRoot && !meta.queryOriginal();
  8611. }
  8612. };
  8613. IRoxieServerActivityFactory *createRoxieServerSideEffectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  8614. {
  8615. return new CRoxieServerSideEffectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  8616. }
  8617. //=================================================================================
  8618. class CRoxieServerActionActivity : public CRoxieServerInternalSinkActivity
  8619. {
  8620. IHThorActionArg &helper;
  8621. public:
  8622. CRoxieServerActionActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8623. : CRoxieServerInternalSinkActivity(_factory, _probeManager), helper((IHThorActionArg &)basehelper)
  8624. {
  8625. }
  8626. virtual void onExecute()
  8627. {
  8628. helper.action();
  8629. }
  8630. };
  8631. class CRoxieServerActionActivityFactory : public CRoxieServerInternalSinkFactory
  8632. {
  8633. public:
  8634. CRoxieServerActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  8635. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot)
  8636. {
  8637. }
  8638. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8639. {
  8640. return new CRoxieServerActionActivity(this, _probeManager);
  8641. }
  8642. };
  8643. IRoxieServerActivityFactory *createRoxieServerActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  8644. {
  8645. return new CRoxieServerActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot);
  8646. }
  8647. //=================================================================================
  8648. class CRoxieServerSampleActivity : public CRoxieServerActivity
  8649. {
  8650. IHThorSampleArg &helper;
  8651. unsigned numSamples;
  8652. unsigned numToSkip;
  8653. unsigned whichSample;
  8654. bool anyThisGroup;
  8655. bool eof;
  8656. public:
  8657. CRoxieServerSampleActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8658. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSampleArg &)basehelper)
  8659. {
  8660. numSamples = 0;
  8661. numToSkip = 0;
  8662. whichSample = 0;
  8663. anyThisGroup = false;
  8664. eof = false;
  8665. }
  8666. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8667. {
  8668. anyThisGroup = false;
  8669. eof = false;
  8670. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  8671. numSamples = helper.getProportion();
  8672. whichSample = helper.getSampleNumber();
  8673. numToSkip = (whichSample ? whichSample-1 : 0);
  8674. }
  8675. virtual const void * nextInGroup()
  8676. {
  8677. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8678. if (eof)
  8679. return NULL;
  8680. loop
  8681. {
  8682. const void * ret = input->nextInGroup();
  8683. if (!ret)
  8684. {
  8685. //this does work with groups - may or may not be useful...
  8686. //reset the sample for each group.... probably best.
  8687. numToSkip = (whichSample ? whichSample-1 : 0);
  8688. if (anyThisGroup)
  8689. {
  8690. anyThisGroup = false;
  8691. return NULL;
  8692. }
  8693. ret = input->nextInGroup();
  8694. if (!ret)
  8695. {
  8696. eof = true;
  8697. return NULL; // eof...
  8698. }
  8699. }
  8700. if (numToSkip == 0)
  8701. {
  8702. anyThisGroup = true;
  8703. numToSkip = numSamples-1;
  8704. processed++;
  8705. return ret;
  8706. }
  8707. numToSkip--;
  8708. ReleaseRoxieRow(ret);
  8709. }
  8710. }
  8711. };
  8712. class CRoxieServerSampleActivityFactory : public CRoxieServerActivityFactory
  8713. {
  8714. public:
  8715. CRoxieServerSampleActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8716. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  8717. {
  8718. }
  8719. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8720. {
  8721. return new CRoxieServerSampleActivity(this, _probeManager);
  8722. }
  8723. };
  8724. IRoxieServerActivityFactory *createRoxieServerSampleActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8725. {
  8726. return new CRoxieServerSampleActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  8727. }
  8728. //=================================================================================
  8729. class CRoxieServerChooseSetsActivity : public CRoxieServerActivity
  8730. {
  8731. IHThorChooseSetsArg &helper;
  8732. unsigned numSets;
  8733. unsigned * setCounts;
  8734. bool done;
  8735. public:
  8736. CRoxieServerChooseSetsActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8737. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorChooseSetsArg &)basehelper)
  8738. {
  8739. setCounts = NULL;
  8740. numSets = 0;
  8741. done = false;
  8742. }
  8743. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8744. {
  8745. done = false;
  8746. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  8747. numSets = helper.getNumSets();
  8748. setCounts = new unsigned[numSets];
  8749. memset(setCounts, 0, sizeof(unsigned)*numSets);
  8750. helper.setCounts(setCounts);
  8751. }
  8752. virtual void reset()
  8753. {
  8754. delete [] setCounts;
  8755. setCounts = NULL;
  8756. CRoxieServerActivity::reset();
  8757. }
  8758. virtual const void * nextInGroup()
  8759. {
  8760. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8761. if (done)
  8762. return NULL;
  8763. loop
  8764. {
  8765. const void * ret = input->nextInGroup();
  8766. if (!ret)
  8767. {
  8768. ret = input->nextInGroup();
  8769. if (!ret)
  8770. {
  8771. done = true;
  8772. return NULL;
  8773. }
  8774. }
  8775. processed++;
  8776. switch (helper.getRecordAction(ret))
  8777. {
  8778. case 2:
  8779. done = true;
  8780. return ret;
  8781. case 1:
  8782. return ret;
  8783. }
  8784. ReleaseRoxieRow(ret);
  8785. }
  8786. }
  8787. };
  8788. class CRoxieServerChooseSetsActivityFactory : public CRoxieServerActivityFactory
  8789. {
  8790. public:
  8791. CRoxieServerChooseSetsActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8792. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  8793. {
  8794. }
  8795. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8796. {
  8797. return new CRoxieServerChooseSetsActivity(this, _probeManager);
  8798. }
  8799. };
  8800. IRoxieServerActivityFactory *createRoxieServerChooseSetsActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8801. {
  8802. return new CRoxieServerChooseSetsActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  8803. }
  8804. //=================================================================================
  8805. class CRoxieServerChooseSetsExActivity : public CRoxieServerActivity
  8806. {
  8807. protected:
  8808. IHThorChooseSetsExArg &helper;
  8809. unsigned numSets;
  8810. unsigned curIndex;
  8811. unsigned * setCounts;
  8812. count_t * limits;
  8813. bool done;
  8814. ConstPointerArray gathered;
  8815. virtual bool includeRow(const void * row) = 0;
  8816. virtual void calculateSelection() = 0;
  8817. public:
  8818. CRoxieServerChooseSetsExActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  8819. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorChooseSetsExArg &)basehelper)
  8820. {
  8821. setCounts = NULL;
  8822. limits = NULL;
  8823. done = false;
  8824. curIndex = 0;
  8825. numSets = 0;
  8826. }
  8827. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8828. {
  8829. done = false;
  8830. curIndex = 0;
  8831. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  8832. numSets = helper.getNumSets();
  8833. setCounts = new unsigned[numSets];
  8834. memset(setCounts, 0, sizeof(unsigned)*numSets);
  8835. limits = (count_t *)calloc(sizeof(count_t), numSets);
  8836. helper.getLimits(limits);
  8837. }
  8838. virtual void reset()
  8839. {
  8840. delete [] setCounts;
  8841. setCounts = NULL;
  8842. free(limits);
  8843. limits = NULL;
  8844. while (gathered.isItem(curIndex))
  8845. ReleaseRoxieRow(gathered.item(curIndex++));
  8846. gathered.kill();
  8847. CRoxieServerActivity::reset();
  8848. }
  8849. virtual const void * nextInGroup()
  8850. {
  8851. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  8852. if (gathered.ordinality() == 0)
  8853. {
  8854. curIndex = 0;
  8855. if (!input->nextGroup(gathered))
  8856. {
  8857. done = true;
  8858. return NULL;
  8859. }
  8860. ForEachItemIn(idx1, gathered)
  8861. {
  8862. unsigned category = helper.getCategory(gathered.item(idx1));
  8863. if (category)
  8864. setCounts[category-1]++;
  8865. }
  8866. calculateSelection();
  8867. }
  8868. while (gathered.isItem(curIndex))
  8869. {
  8870. const void * row = gathered.item(curIndex);
  8871. gathered.replace(NULL, curIndex);
  8872. curIndex++;
  8873. if (includeRow(row))
  8874. {
  8875. processed++;
  8876. return row;
  8877. }
  8878. ReleaseRoxieRow(row);
  8879. }
  8880. gathered.kill();
  8881. return NULL;
  8882. }
  8883. };
  8884. class CRoxieServerChooseSetsLastActivity : public CRoxieServerChooseSetsExActivity
  8885. {
  8886. unsigned * numToSkip;
  8887. public:
  8888. CRoxieServerChooseSetsLastActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager) : CRoxieServerChooseSetsExActivity(_factory, _probeManager)
  8889. {
  8890. numToSkip = NULL;
  8891. }
  8892. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8893. {
  8894. CRoxieServerChooseSetsExActivity::start(parentExtractSize, parentExtract, paused);
  8895. numToSkip = (unsigned *)calloc(sizeof(unsigned), numSets);
  8896. }
  8897. virtual void reset()
  8898. {
  8899. free(numToSkip);
  8900. numToSkip = NULL;
  8901. CRoxieServerChooseSetsExActivity::reset();
  8902. }
  8903. protected:
  8904. virtual void calculateSelection()
  8905. {
  8906. for (unsigned idx=0; idx < numSets; idx++)
  8907. {
  8908. if (setCounts[idx] < limits[idx])
  8909. numToSkip[idx] = 0;
  8910. else
  8911. numToSkip[idx] = (unsigned)(setCounts[idx] - limits[idx]);
  8912. }
  8913. }
  8914. virtual bool includeRow(const void * row)
  8915. {
  8916. unsigned category = helper.getCategory(row);
  8917. if (category)
  8918. {
  8919. if (numToSkip[category-1] == 0)
  8920. return true;
  8921. numToSkip[category-1]--;
  8922. }
  8923. return false;
  8924. }
  8925. };
  8926. class CRoxieServerChooseSetsEnthActivity : public CRoxieServerChooseSetsExActivity
  8927. {
  8928. count_t * counter;
  8929. public:
  8930. CRoxieServerChooseSetsEnthActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager) : CRoxieServerChooseSetsExActivity(_factory, _probeManager)
  8931. {
  8932. counter = NULL;
  8933. }
  8934. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  8935. {
  8936. CRoxieServerChooseSetsExActivity::start(parentExtractSize, parentExtract, paused);
  8937. counter = (count_t *)calloc(sizeof(count_t), numSets);
  8938. }
  8939. virtual void reset()
  8940. {
  8941. free(counter);
  8942. counter = NULL;
  8943. CRoxieServerChooseSetsExActivity::reset();
  8944. }
  8945. protected:
  8946. virtual void calculateSelection()
  8947. {
  8948. }
  8949. virtual bool includeRow(const void * row)
  8950. {
  8951. unsigned category = helper.getCategory(row);
  8952. if (category)
  8953. {
  8954. assertex(category <= numSets);
  8955. counter[category-1] += limits[category-1];
  8956. if(counter[category-1] >= setCounts[category-1])
  8957. {
  8958. counter[category-1] -= setCounts[category-1];
  8959. return true;
  8960. }
  8961. }
  8962. return false;
  8963. }
  8964. };
  8965. class CRoxieServerChooseSetsEnthActivityFactory : public CRoxieServerActivityFactory
  8966. {
  8967. public:
  8968. CRoxieServerChooseSetsEnthActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8969. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  8970. {
  8971. }
  8972. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8973. {
  8974. return new CRoxieServerChooseSetsEnthActivity(this, _probeManager);
  8975. }
  8976. };
  8977. IRoxieServerActivityFactory *createRoxieServerChooseSetsEnthActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8978. {
  8979. return new CRoxieServerChooseSetsEnthActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  8980. }
  8981. class CRoxieServerChooseSetsLastActivityFactory : public CRoxieServerActivityFactory
  8982. {
  8983. public:
  8984. CRoxieServerChooseSetsLastActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8985. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  8986. {
  8987. }
  8988. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  8989. {
  8990. return new CRoxieServerChooseSetsLastActivity(this, _probeManager);
  8991. }
  8992. };
  8993. IRoxieServerActivityFactory *createRoxieServerChooseSetsLastActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  8994. {
  8995. return new CRoxieServerChooseSetsLastActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  8996. }
  8997. //=================================================================================
  8998. class CRoxieServerEnthActivity : public CRoxieServerActivity
  8999. {
  9000. IHThorEnthArg &helper;
  9001. unsigned __int64 numerator;
  9002. unsigned __int64 denominator;
  9003. unsigned __int64 counter;
  9004. bool eof;
  9005. public:
  9006. CRoxieServerEnthActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9007. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorEnthArg &)basehelper)
  9008. {
  9009. eof = false;
  9010. numerator = denominator = counter = 0;
  9011. }
  9012. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9013. {
  9014. eof = false;
  9015. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9016. numerator = helper.getProportionNumerator();
  9017. denominator = helper.getProportionDenominator();
  9018. if(denominator == 0) denominator = 1; //MORE: simplest way to avoid disaster in this case
  9019. counter = (helper.getSampleNumber()-1) * greatestCommonDivisor(numerator, denominator);
  9020. if (counter >= denominator)
  9021. counter %= denominator;
  9022. }
  9023. inline bool wanted()
  9024. {
  9025. counter += numerator;
  9026. if(counter >= denominator)
  9027. {
  9028. counter -= denominator;
  9029. return true;
  9030. }
  9031. return false;
  9032. }
  9033. virtual const void * nextInGroup()
  9034. {
  9035. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  9036. if (eof)
  9037. return NULL;
  9038. const void * ret;
  9039. loop
  9040. {
  9041. ret = input->nextInGroup();
  9042. if(!ret) //end of group
  9043. ret = input->nextInGroup();
  9044. if(!ret) //eof
  9045. {
  9046. eof = true;
  9047. return ret;
  9048. }
  9049. if (wanted())
  9050. return ret;
  9051. ReleaseRoxieRow(ret);
  9052. }
  9053. }
  9054. };
  9055. class CRoxieServerEnthActivityFactory : public CRoxieServerActivityFactory
  9056. {
  9057. public:
  9058. CRoxieServerEnthActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9059. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  9060. {
  9061. }
  9062. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  9063. {
  9064. return new CRoxieServerEnthActivity(this, _probeManager);
  9065. }
  9066. };
  9067. IRoxieServerActivityFactory *createRoxieServerEnthActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9068. {
  9069. return new CRoxieServerEnthActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  9070. }
  9071. //=================================================================================
  9072. class CRoxieServerAggregateActivity : public CRoxieServerActivity
  9073. {
  9074. IHThorAggregateArg &helper;
  9075. bool eof;
  9076. bool isInputGrouped;
  9077. bool abortEarly;
  9078. public:
  9079. CRoxieServerAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9080. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorAggregateArg &)basehelper)
  9081. {
  9082. eof = false;
  9083. isInputGrouped = false;
  9084. abortEarly = false;
  9085. }
  9086. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9087. {
  9088. eof = false;
  9089. isInputGrouped = input->queryOutputMeta()->isGrouped(); // could be done earlier, in setInput?
  9090. abortEarly = !isInputGrouped && (factory->getKind() == TAKexistsaggregate); // ditto
  9091. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9092. }
  9093. virtual bool needsAllocator() const { return true; }
  9094. virtual const void * nextInGroup()
  9095. {
  9096. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  9097. if (eof)
  9098. return NULL;
  9099. const void * next = input->nextInGroup();
  9100. if (!next && isInputGrouped)
  9101. {
  9102. eof = true;
  9103. return NULL;
  9104. }
  9105. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  9106. size32_t finalSize = helper.clearAggregate(rowBuilder);
  9107. if (next)
  9108. {
  9109. finalSize = helper.processFirst(rowBuilder, next);
  9110. ReleaseRoxieRow(next);
  9111. if (!abortEarly)
  9112. {
  9113. loop
  9114. {
  9115. next = input->nextInGroup();
  9116. if (!next)
  9117. break;
  9118. finalSize = helper.processNext(rowBuilder, next);
  9119. ReleaseRoxieRow(next);
  9120. }
  9121. }
  9122. }
  9123. if (!isInputGrouped) // either read all, or aborted early
  9124. eof = true;
  9125. processed++;
  9126. return rowBuilder.finalizeRowClear(finalSize);
  9127. }
  9128. };
  9129. class CRoxieServerAggregateActivityFactory : public CRoxieServerActivityFactory
  9130. {
  9131. public:
  9132. CRoxieServerAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9133. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  9134. {
  9135. }
  9136. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  9137. {
  9138. return new CRoxieServerAggregateActivity(this, _probeManager);
  9139. }
  9140. };
  9141. IRoxieServerActivityFactory *createRoxieServerAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9142. {
  9143. return new CRoxieServerAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  9144. }
  9145. //=================================================================================
  9146. typedef unsigned t_hashPrefix;
  9147. class CRoxieServerHashAggregateActivity : public CRoxieServerActivity
  9148. {
  9149. IHThorHashAggregateArg &helper;
  9150. RowAggregator aggregated;
  9151. bool eof;
  9152. bool gathered;
  9153. public:
  9154. CRoxieServerHashAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9155. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorHashAggregateArg &)basehelper), aggregated(helper, helper)
  9156. {
  9157. eof = false;
  9158. gathered = false;
  9159. }
  9160. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9161. {
  9162. eof = false;
  9163. gathered = false;
  9164. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9165. aggregated.start(rowAllocator);
  9166. }
  9167. virtual void reset()
  9168. {
  9169. aggregated.reset();
  9170. CRoxieServerActivity::reset();
  9171. }
  9172. virtual bool needsAllocator() const { return true; }
  9173. virtual const void * nextInGroup()
  9174. {
  9175. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  9176. if (eof)
  9177. return NULL;
  9178. if (!gathered)
  9179. {
  9180. loop
  9181. {
  9182. const void * next = input->nextInGroup();
  9183. if (!next)
  9184. {
  9185. next = input->nextInGroup();
  9186. if (!next)
  9187. break;
  9188. }
  9189. aggregated.addRow(next);
  9190. ReleaseRoxieRow(next);
  9191. }
  9192. gathered = true;
  9193. }
  9194. Owned<AggregateRowBuilder> next = aggregated.nextResult();
  9195. if (next)
  9196. {
  9197. processed++;
  9198. return next->finalizeRowClear();
  9199. }
  9200. eof = true;
  9201. return NULL;
  9202. }
  9203. };
  9204. class CRoxieServerHashAggregateActivityFactory : public CRoxieServerActivityFactory
  9205. {
  9206. public:
  9207. CRoxieServerHashAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9208. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  9209. {
  9210. }
  9211. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  9212. {
  9213. return new CRoxieServerHashAggregateActivity(this, _probeManager);
  9214. }
  9215. };
  9216. IRoxieServerActivityFactory *createRoxieServerHashAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9217. {
  9218. return new CRoxieServerHashAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  9219. }
  9220. //=================================================================================
  9221. class CRoxieServerDegroupActivity : public CRoxieServerActivity
  9222. {
  9223. IHThorDegroupArg &helper;
  9224. bool eof;
  9225. public:
  9226. CRoxieServerDegroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9227. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorDegroupArg &)basehelper)
  9228. {
  9229. eof = false;
  9230. }
  9231. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9232. {
  9233. eof = false;
  9234. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9235. }
  9236. virtual const void * nextInGroup()
  9237. {
  9238. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  9239. if (eof)
  9240. return NULL;
  9241. const void * ret = input->nextInGroup();
  9242. if (!ret)
  9243. ret = input->nextInGroup();
  9244. if (ret)
  9245. processed++;
  9246. else
  9247. eof = true;
  9248. return ret;
  9249. }
  9250. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  9251. {
  9252. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  9253. if (eof)
  9254. return NULL;
  9255. const void * ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  9256. if (ret)
  9257. processed++;
  9258. else
  9259. eof = true;
  9260. return ret;
  9261. }
  9262. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  9263. {
  9264. return input->gatherConjunctions(collector);
  9265. }
  9266. virtual void resetEOF()
  9267. {
  9268. eof = false;
  9269. input->resetEOF();
  9270. }
  9271. IInputSteppingMeta * querySteppingMeta()
  9272. {
  9273. return input->querySteppingMeta();
  9274. }
  9275. };
  9276. class CRoxieServerDegroupActivityFactory : public CRoxieServerActivityFactory
  9277. {
  9278. public:
  9279. CRoxieServerDegroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9280. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  9281. {
  9282. }
  9283. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  9284. {
  9285. return new CRoxieServerDegroupActivity(this, _probeManager);
  9286. }
  9287. };
  9288. IRoxieServerActivityFactory *createRoxieServerDegroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9289. {
  9290. return new CRoxieServerDegroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  9291. }
  9292. //=================================================================================
  9293. class CRoxieServerSpillReadActivity : public CRoxieServerActivity
  9294. {
  9295. IHThorDiskReadArg &helper;
  9296. bool needTransform;
  9297. bool eof;
  9298. bool anyThisGroup;
  9299. unsigned __int64 rowLimit;
  9300. unsigned __int64 choosenLimit;
  9301. public:
  9302. CRoxieServerSpillReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9303. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorDiskReadArg &)basehelper)
  9304. {
  9305. needTransform = helper.needTransform();
  9306. rowLimit = (unsigned __int64) -1;
  9307. choosenLimit = 0;
  9308. eof = false;
  9309. anyThisGroup = false;
  9310. }
  9311. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9312. {
  9313. anyThisGroup = false;
  9314. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9315. if (helper.canMatchAny())
  9316. eof = false;
  9317. else
  9318. eof = true;
  9319. choosenLimit = helper.getChooseNLimit();
  9320. rowLimit = helper.getRowLimit();
  9321. helper.setCallback(NULL); // members should not be called - change if they are
  9322. }
  9323. virtual bool needsAllocator() const { return true; }
  9324. virtual const void * nextInGroup()
  9325. {
  9326. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  9327. if (eof)
  9328. return NULL;
  9329. if (processed==choosenLimit)
  9330. {
  9331. eof = true;
  9332. return NULL;
  9333. }
  9334. if (needTransform)
  9335. {
  9336. loop
  9337. {
  9338. const void *in = input->nextInGroup();
  9339. if (!in)
  9340. {
  9341. if (anyThisGroup)
  9342. {
  9343. anyThisGroup = false;
  9344. return NULL;
  9345. }
  9346. in = input->nextInGroup();
  9347. if (!in)
  9348. {
  9349. eof = true;
  9350. return NULL; // eof...
  9351. }
  9352. }
  9353. unsigned outSize;
  9354. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  9355. try
  9356. {
  9357. outSize = helper.transform(rowBuilder, in);
  9358. ReleaseRoxieRow(in);
  9359. }
  9360. catch (IException *E)
  9361. {
  9362. throw makeWrappedException(E);
  9363. }
  9364. if (outSize)
  9365. {
  9366. anyThisGroup = true;
  9367. processed++;
  9368. if (processed==rowLimit)
  9369. {
  9370. if (traceLevel > 4)
  9371. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  9372. helper.onLimitExceeded();
  9373. }
  9374. return rowBuilder.finalizeRowClear(outSize);
  9375. }
  9376. }
  9377. }
  9378. else
  9379. {
  9380. const void *ret = input->nextInGroup();
  9381. if (ret)
  9382. {
  9383. processed++;
  9384. if (processed==rowLimit)
  9385. {
  9386. if (traceLevel > 4)
  9387. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  9388. ReleaseClearRoxieRow(ret);
  9389. helper.onLimitExceeded(); // should not return
  9390. throwUnexpected();
  9391. }
  9392. }
  9393. return ret;
  9394. }
  9395. }
  9396. };
  9397. class CRoxieServerSpillReadActivityFactory : public CRoxieServerActivityFactory
  9398. {
  9399. public:
  9400. CRoxieServerSpillReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9401. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  9402. {
  9403. }
  9404. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  9405. {
  9406. return new CRoxieServerSpillReadActivity(this, _probeManager);
  9407. }
  9408. virtual void addDependency(unsigned source, ThorActivityKind sourceKind, unsigned sourceIdx, int controlId, const char *edgeId)
  9409. {
  9410. if (sourceKind==TAKspill || sourceKind==TAKdiskwrite) // Bit of a hack - codegen probably should differentiate
  9411. setInput(0, source, sourceIdx);
  9412. else
  9413. CRoxieServerActivityFactory::addDependency(source, kind, sourceIdx, controlId, edgeId);
  9414. }
  9415. };
  9416. IRoxieServerActivityFactory *createRoxieServerSpillReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  9417. {
  9418. return new CRoxieServerSpillReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  9419. }
  9420. //=================================================================================
  9421. class CRoxieServerSpillWriteActivity : public CRoxieServerActivity
  9422. {
  9423. public:
  9424. CRoxieServerSpillWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9425. : CRoxieServerActivity(_factory, _probeManager)
  9426. {
  9427. }
  9428. ~CRoxieServerSpillWriteActivity()
  9429. {
  9430. }
  9431. virtual const void *nextInGroup()
  9432. {
  9433. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  9434. return input->nextInGroup();
  9435. }
  9436. };
  9437. //==================================================================================
  9438. class CRoxieServerDiskWriteActivity : public CRoxieServerInternalSinkActivity, implements IRoxiePublishCallback
  9439. {
  9440. protected:
  9441. Owned<IExtRowWriter> outSeq;
  9442. Owned<IOutputRowSerializer> rowSerializer;
  9443. Linked<IFileIOStream> diskout;
  9444. bool blockcompressed;
  9445. bool extend;
  9446. bool overwrite;
  9447. bool encrypted;
  9448. bool grouped;
  9449. IHThorDiskWriteArg &helper;
  9450. StringBuffer lfn; // logical filename
  9451. CachedOutputMetaData diskmeta;
  9452. Owned<IRoxieWriteHandler> writer;
  9453. unsigned __int64 uncompressedBytesWritten;
  9454. void updateWorkUnitResult(unsigned __int64 reccount)
  9455. {
  9456. assertex(writer);
  9457. // MORE - a lot of this is common with hthor
  9458. if(lfn.length()) //this is required as long as temp files don't get a name which can be stored in the WU and automatically deleted by the WU
  9459. {
  9460. WorkunitUpdate wu = ctx->updateWorkUnit();
  9461. if (wu)
  9462. {
  9463. unsigned flags = helper.getFlags();
  9464. WUFileKind fileKind;
  9465. if (TDXtemporary & flags)
  9466. fileKind = WUFileTemporary;
  9467. else if(TDXjobtemp & flags)
  9468. fileKind = WUFileJobOwned;
  9469. else if(TDWowned & flags)
  9470. fileKind = WUFileOwned;
  9471. else
  9472. fileKind = WUFileStandard;
  9473. StringArray clusters;
  9474. writer->getClusters(clusters);
  9475. wu->addFile(lfn.str(), &clusters, helper.getTempUsageCount(), fileKind, NULL);
  9476. if (!(flags & TDXtemporary) && helper.getSequence() >= 0)
  9477. {
  9478. Owned<IWUResult> result = wu->updateResultBySequence(helper.getSequence());
  9479. if (result)
  9480. {
  9481. result->setResultTotalRowCount(reccount);
  9482. result->setResultStatus(ResultStatusCalculated);
  9483. if (helper.getFlags() & TDWresult)
  9484. result->setResultFilename(lfn.str());
  9485. else
  9486. result->setResultLogicalName(lfn.str());
  9487. }
  9488. }
  9489. }
  9490. }
  9491. }
  9492. void resolve()
  9493. {
  9494. const char * rawLogicalName = helper.getFileName();
  9495. assertex(rawLogicalName);
  9496. assertex((helper.getFlags() & TDXtemporary) == 0);
  9497. StringArray clusters;
  9498. unsigned clusterIdx = 0;
  9499. while(true)
  9500. {
  9501. char const * cluster = helper.queryCluster(clusterIdx);
  9502. if(!cluster)
  9503. break;
  9504. clusters.append(cluster);
  9505. clusterIdx++;
  9506. }
  9507. if (clusters.length())
  9508. {
  9509. if (extend)
  9510. throw MakeStringException(0, "Cannot combine EXTEND and CLUSTER flags on disk write of file %s", rawLogicalName);
  9511. }
  9512. else
  9513. {
  9514. if (roxieName.length())
  9515. clusters.append(roxieName.str());
  9516. else
  9517. clusters.append(".");
  9518. }
  9519. writer.setown(ctx->createLFN(rawLogicalName, overwrite, extend, clusters)); // MORE - if there's a workunit, use if for scope.
  9520. // MORE - need to check somewhere that single part if it's an existing file or an external one...
  9521. }
  9522. public:
  9523. CRoxieServerDiskWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9524. : CRoxieServerInternalSinkActivity(_factory, _probeManager), helper((IHThorDiskWriteArg &)basehelper)
  9525. {
  9526. extend = ((helper.getFlags() & TDWextend) != 0);
  9527. overwrite = ((helper.getFlags() & TDWoverwrite) != 0);
  9528. grouped = false; // don't think we need to support it...
  9529. diskmeta.set(helper.queryDiskRecordSize());
  9530. blockcompressed = (((helper.getFlags() & TDWnewcompress) != 0) || (((helper.getFlags() & TDXcompress) != 0) && (diskmeta.getFixedSize() >= MIN_ROWCOMPRESS_RECSIZE))); //always use new compression
  9531. encrypted = false; // set later
  9532. uncompressedBytesWritten = 0;
  9533. }
  9534. ~CRoxieServerDiskWriteActivity()
  9535. {
  9536. }
  9537. virtual bool needsAllocator() const
  9538. {
  9539. return true;
  9540. }
  9541. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9542. {
  9543. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9544. resolve();
  9545. Owned<IFileIO> io;
  9546. void *ekey;
  9547. size32_t ekeylen;
  9548. helper.getEncryptKey(ekeylen, ekey);
  9549. Owned<ICompressor> ecomp;
  9550. if (ekeylen!=0)
  9551. {
  9552. ecomp.setown(createAESCompressor256(ekeylen,ekey));
  9553. memset(ekey,0,ekeylen);
  9554. rtlFree(ekey);
  9555. encrypted = true;
  9556. blockcompressed = true;
  9557. }
  9558. if(blockcompressed)
  9559. io.setown(createCompressedFileWriter(writer->queryFile(), (diskmeta.isFixedSize() ? diskmeta.getFixedSize() : 0), extend, true, ecomp));
  9560. else
  9561. io.setown(writer->queryFile()->open(extend ? IFOwrite : IFOcreate));
  9562. if(!io)
  9563. throw MakeStringException(errno, "Failed to create%s file %s for writing", (encrypted ? " encrypted" : (blockcompressed ? " compressed" : "")), writer->queryFile()->queryFilename());
  9564. diskout.setown(createBufferedIOStream(io));
  9565. if(extend)
  9566. diskout->seek(0, IFSend);
  9567. rowSerializer.setown(input->queryOutputMeta()->createRowSerializer(ctx->queryCodeContext(), activityId));
  9568. bool tallycrc = !factory->queryQueryFactory().getDebugValueBool("skipFileFormatCrcCheck", false) && !(helper.getFlags() & TDRnocrccheck);
  9569. outSeq.setown(createRowWriter(diskout, rowSerializer, rowAllocator, grouped, tallycrc, true ));
  9570. }
  9571. virtual void stop(bool aborting)
  9572. {
  9573. if (aborting)
  9574. {
  9575. if (writer)
  9576. writer->finish(false, this);
  9577. }
  9578. else
  9579. {
  9580. outSeq->flush();
  9581. updateWorkUnitResult(processed);
  9582. uncompressedBytesWritten = outSeq->getPosition();
  9583. writer->finish(true, this);
  9584. }
  9585. writer.clear();
  9586. CRoxieServerActivity::stop(aborting);
  9587. }
  9588. virtual void reset()
  9589. {
  9590. CRoxieServerActivity::reset();
  9591. diskout.clear();
  9592. outSeq.clear();
  9593. writer.clear();
  9594. uncompressedBytesWritten = 0;
  9595. }
  9596. virtual void onExecute()
  9597. {
  9598. loop
  9599. {
  9600. const void *nextrec = input->nextInGroup();
  9601. if (!nextrec)
  9602. {
  9603. nextrec = input->nextInGroup();
  9604. if (!nextrec)
  9605. break;
  9606. }
  9607. processed++;
  9608. outSeq->putRow(nextrec);
  9609. }
  9610. }
  9611. virtual void setFileProperties(IFileDescriptor *desc) const
  9612. {
  9613. IPropertyTree &partProps = desc->queryPart(0)->queryProperties(); //properties of the first file part.
  9614. IPropertyTree &fileProps = desc->queryProperties(); // properties of the logical file
  9615. if (blockcompressed)
  9616. {
  9617. // caller has already set @size from file size...
  9618. fileProps.setPropBool("@blockCompressed", true);
  9619. partProps.setPropInt64("@compressedSize", partProps.getPropInt64("@size", 0)); // MORE should this be on logical too?
  9620. fileProps.setPropInt64("@size", uncompressedBytesWritten);
  9621. partProps.setPropInt64("@size", uncompressedBytesWritten);
  9622. }
  9623. if (encrypted)
  9624. fileProps.setPropBool("@encrypted", true);
  9625. fileProps.setPropInt64("@recordCount", processed);
  9626. unsigned flags = helper.getFlags();
  9627. if (flags & TDWpersist)
  9628. fileProps.setPropBool("@persistent", true);
  9629. if (grouped)
  9630. fileProps.setPropBool("@grouped", true);
  9631. if (flags & (TDWowned|TDXjobtemp|TDXtemporary))
  9632. fileProps.setPropBool("@owned", true);
  9633. if (flags & TDWresult)
  9634. fileProps.setPropBool("@result", true);
  9635. IConstWorkUnit *workUnit = ctx->queryWorkUnit();
  9636. if (workUnit)
  9637. {
  9638. SCMStringBuffer owner, wuid, job;
  9639. fileProps.setProp("@owner", workUnit->getUser(owner).str());
  9640. fileProps.setProp("@workunit", workUnit->getWuid(wuid).str());
  9641. fileProps.setProp("@job", workUnit->getJobName(job).str());
  9642. }
  9643. setExpiryTime(fileProps, helper.getExpiryDays());
  9644. if (flags & TDWupdate)
  9645. {
  9646. unsigned eclCRC;
  9647. unsigned __int64 totalCRC;
  9648. helper.getUpdateCRCs(eclCRC, totalCRC);
  9649. fileProps.setPropInt("@eclCRC", eclCRC);
  9650. fileProps.setPropInt64("@totalCRC", totalCRC);
  9651. }
  9652. fileProps.setPropInt("@formatCrc", helper.getFormatCrc());
  9653. IRecordSize * inputMeta = input->queryOutputMeta();
  9654. if ((inputMeta->isFixedSize()) && !isOutputTransformed())
  9655. fileProps.setPropInt("@recordSize", inputMeta->getFixedSize() + (grouped ? 1 : 0));
  9656. const char *recordECL = helper.queryRecordECL();
  9657. if (recordECL && *recordECL)
  9658. fileProps.setProp("ECL", recordECL);
  9659. }
  9660. virtual IUserDescriptor *queryUserDescriptor() const
  9661. {
  9662. IConstWorkUnit *workUnit = ctx->queryWorkUnit();
  9663. if (workUnit)
  9664. return workUnit->queryUserDescriptor();
  9665. else
  9666. return NULL;
  9667. }
  9668. virtual bool isOutputTransformed() const { return false; }
  9669. };
  9670. //=================================================================================
  9671. class CRoxieServerCsvWriteActivity : public CRoxieServerDiskWriteActivity
  9672. {
  9673. IHThorCsvWriteArg &csvHelper;
  9674. CSVOutputStream csvOutput;
  9675. public:
  9676. CRoxieServerCsvWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9677. : CRoxieServerDiskWriteActivity(_factory, _probeManager), csvHelper(static_cast<IHThorCsvWriteArg &>(helper))
  9678. {
  9679. csvOutput.init(csvHelper.queryCsvParameters(), false);
  9680. }
  9681. virtual void onExecute()
  9682. {
  9683. const char * header = csvHelper.queryCsvParameters()->queryHeader();
  9684. if (header)
  9685. {
  9686. csvOutput.beginLine();
  9687. csvOutput.writeHeaderLn(strlen(header), header);
  9688. diskout->write(csvOutput.length(), csvOutput.str());
  9689. }
  9690. loop
  9691. {
  9692. const void *nextrec = input->nextInGroup();
  9693. if (!nextrec)
  9694. {
  9695. nextrec = input->nextInGroup();
  9696. if (!nextrec)
  9697. break;
  9698. }
  9699. processed++;
  9700. csvOutput.beginLine();
  9701. csvHelper.writeRow((const byte *)nextrec, &csvOutput);
  9702. csvOutput.endLine();
  9703. diskout->write(csvOutput.length(), csvOutput.str());
  9704. ReleaseRoxieRow(nextrec);
  9705. }
  9706. const char * footer = csvHelper.queryCsvParameters()->queryFooter();
  9707. if (footer)
  9708. {
  9709. csvOutput.beginLine();
  9710. csvOutput.writeHeaderLn(strlen(footer), footer);
  9711. diskout->write(csvOutput.length(), csvOutput.str());
  9712. }
  9713. }
  9714. virtual void setFileProperties(IFileDescriptor *desc) const
  9715. {
  9716. CRoxieServerDiskWriteActivity::setFileProperties(desc);
  9717. IPropertyTree &props = desc->queryProperties();
  9718. props.setProp("@format","utf8n");
  9719. ICsvParameters *csvParameters = csvHelper.queryCsvParameters();
  9720. StringBuffer separator;
  9721. const char *s = csvParameters->querySeparator(0);
  9722. while (*s)
  9723. {
  9724. if (',' == *s)
  9725. separator.append("\\,");
  9726. else
  9727. separator.append(*s);
  9728. ++s;
  9729. }
  9730. props.setProp("@csvSeparate", separator.str());
  9731. props.setProp("@csvQuote", csvParameters->queryQuote(0));
  9732. props.setProp("@csvTerminate", csvParameters->queryTerminator(0));
  9733. }
  9734. virtual bool isOutputTransformed() const { return true; }
  9735. };
  9736. class CRoxieServerXmlWriteActivity : public CRoxieServerDiskWriteActivity
  9737. {
  9738. IHThorXmlWriteArg &xmlHelper;
  9739. StringAttr rowTag;
  9740. public:
  9741. CRoxieServerXmlWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9742. : CRoxieServerDiskWriteActivity(_factory, _probeManager), xmlHelper(static_cast<IHThorXmlWriteArg &>(helper))
  9743. {
  9744. }
  9745. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9746. {
  9747. CRoxieServerDiskWriteActivity::start(parentExtractSize, parentExtract, paused);
  9748. const char * path = xmlHelper.queryIteratorPath();
  9749. if (!path)
  9750. rowTag.set("Row");
  9751. else
  9752. {
  9753. if (*path == '/') path++;
  9754. if (strchr(path, '/')) UNIMPLEMENTED; // more what do we do with /mydata/row
  9755. rowTag.set(path);
  9756. }
  9757. }
  9758. virtual void onExecute()
  9759. {
  9760. const char * header = xmlHelper.queryHeader();
  9761. if (!header) header = "<Dataset>\n";
  9762. diskout->write(strlen(header), header);
  9763. CommonXmlWriter xmlOutput(xmlHelper.getXmlFlags());
  9764. loop
  9765. {
  9766. OwnedConstRoxieRow nextrec = input->nextInGroup();
  9767. if (!nextrec)
  9768. {
  9769. nextrec.setown(input->nextInGroup());
  9770. if (!nextrec)
  9771. break;
  9772. }
  9773. processed++;
  9774. xmlOutput.clear().outputBeginNested(rowTag, false);
  9775. xmlHelper.toXML((const byte *)nextrec.get(), xmlOutput);
  9776. xmlOutput.outputEndNested(rowTag);
  9777. diskout->write(xmlOutput.length(), xmlOutput.str());
  9778. }
  9779. const char * footer = xmlHelper.queryFooter();
  9780. if (!footer) footer = "</Dataset>\n";
  9781. diskout->write(strlen(footer), footer);
  9782. }
  9783. virtual void reset()
  9784. {
  9785. CRoxieServerDiskWriteActivity::reset();
  9786. rowTag.clear();
  9787. }
  9788. virtual void setFileProperties(IFileDescriptor *desc) const
  9789. {
  9790. CRoxieServerDiskWriteActivity::setFileProperties(desc);
  9791. desc->queryProperties().setProp("@format","utf8n");
  9792. desc->queryProperties().setProp("@rowTag",rowTag.get());
  9793. }
  9794. virtual bool isOutputTransformed() const { return true; }
  9795. };
  9796. class CRoxieServerDiskWriteActivityFactory : public CRoxieServerMultiOutputFactory
  9797. {
  9798. bool isRoot;
  9799. public:
  9800. CRoxieServerDiskWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  9801. : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  9802. {
  9803. Owned<IHThorDiskWriteArg> helper = (IHThorDiskWriteArg *) helperFactory();
  9804. setNumOutputs(helper->getTempUsageCount());
  9805. if (_kind!=TAKdiskwrite)
  9806. assertex(numOutputs == 0);
  9807. }
  9808. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  9809. {
  9810. switch (numOutputs)
  9811. {
  9812. case 0:
  9813. switch (kind)
  9814. {
  9815. case TAKdiskwrite: return new CRoxieServerDiskWriteActivity(this, _probeManager);
  9816. case TAKcsvwrite: return new CRoxieServerCsvWriteActivity(this, _probeManager);
  9817. case TAKxmlwrite: return new CRoxieServerXmlWriteActivity(this, _probeManager);
  9818. };
  9819. throwUnexpected();
  9820. case 1:
  9821. return new CRoxieServerSpillWriteActivity(this, _probeManager);
  9822. default:
  9823. return new CRoxieServerThroughSpillActivity(this, _probeManager, numOutputs);
  9824. }
  9825. }
  9826. virtual bool isSink() const
  9827. {
  9828. return numOutputs == 0; // MORE - check with Gavin if this is right if not a temp but reread in same job...
  9829. }
  9830. };
  9831. IRoxieServerActivityFactory *createRoxieServerDiskWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  9832. {
  9833. return new CRoxieServerDiskWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  9834. }
  9835. //=================================================================================
  9836. class CRoxieServerIndexWriteActivity : public CRoxieServerInternalSinkActivity, implements IRoxiePublishCallback
  9837. {
  9838. IHThorIndexWriteArg &helper;
  9839. bool overwrite;
  9840. Owned<ClusterWriteHandler> clusterHandler;
  9841. Owned<IRoxieWriteHandler> writer;
  9842. unsigned __int64 reccount;
  9843. unsigned int fileCrc;
  9844. StringBuffer filename;
  9845. void updateWorkUnitResult()
  9846. {
  9847. if(filename.length()) //this is required as long as temp files don't get a name which can be stored in the WU and automatically deleted by the WU
  9848. {
  9849. WorkunitUpdate wu = ctx->updateWorkUnit();
  9850. if (wu)
  9851. {
  9852. if (!(helper.getFlags() & TDXtemporary) && helper.getSequence() >= 0)
  9853. {
  9854. Owned<IWUResult> result = wu->updateResultBySequence(helper.getSequence());
  9855. if (result)
  9856. {
  9857. result->setResultTotalRowCount(reccount);
  9858. result->setResultStatus(ResultStatusCalculated);
  9859. result->setResultLogicalName(filename.str());
  9860. }
  9861. }
  9862. if(clusterHandler)
  9863. clusterHandler->finish(writer->queryFile());
  9864. }
  9865. CTXLOG("Created roxie index file %s", filename.str());
  9866. }
  9867. }
  9868. virtual void resolve()
  9869. {
  9870. StringArray clusters;
  9871. unsigned clusterIdx = 0;
  9872. while(true)
  9873. {
  9874. char const * cluster = helper.queryCluster(clusterIdx);
  9875. if(!cluster)
  9876. break;
  9877. clusters.append(cluster);
  9878. clusterIdx++;
  9879. }
  9880. if (roxieName.length())
  9881. clusters.append(roxieName.str());
  9882. else
  9883. clusters.append(".");
  9884. writer.setown(ctx->createLFN(helper.getFileName(), overwrite, false, clusters)); // MORE - if there's a workunit, use if for scope.
  9885. filename.set(writer->queryFile()->queryFilename());
  9886. if (writer->queryFile()->exists())
  9887. {
  9888. if (overwrite)
  9889. {
  9890. CTXLOG("Removing existing %s from DFS",filename.str());
  9891. writer->queryFile()->remove();
  9892. }
  9893. else
  9894. throw MakeStringException(99, "Cannot write index file %s, file already exists (missing OVERWRITE attribute?)", filename.str());
  9895. }
  9896. }
  9897. void buildUserMetadata(Owned<IPropertyTree> & metadata)
  9898. {
  9899. size32_t nameLen;
  9900. char * nameBuff;
  9901. size32_t valueLen;
  9902. char * valueBuff;
  9903. unsigned idx = 0;
  9904. while(helper.getIndexMeta(nameLen, nameBuff, valueLen, valueBuff, idx++))
  9905. {
  9906. StringBuffer name(nameLen, nameBuff);
  9907. StringBuffer value(valueLen, valueBuff);
  9908. if(*nameBuff == '_' && strcmp(name, "_nodeSize") != 0)
  9909. throw MakeStringException(0, "Invalid name %s in user metadata for index %s (names beginning with underscore are reserved)", name.str(), helper.getFileName());
  9910. if(!validateXMLTag(name.str()))
  9911. throw MakeStringException(0, "Invalid name %s in user metadata for index %s (not legal XML element name)", name.str(), helper.getFileName());
  9912. if(!metadata)
  9913. metadata.setown(createPTree("metadata"));
  9914. metadata->setProp(name.str(), value.str());
  9915. }
  9916. }
  9917. void buildLayoutMetadata(Owned<IPropertyTree> & metadata)
  9918. {
  9919. if(!metadata)
  9920. metadata.setown(createPTree("metadata"));
  9921. metadata->setProp("_record_ECL", helper.queryRecordECL());
  9922. void * layoutMetaBuff;
  9923. size32_t layoutMetaSize;
  9924. if(helper.getIndexLayout(layoutMetaSize, layoutMetaBuff))
  9925. {
  9926. metadata->setPropBin("_record_layout", layoutMetaSize, layoutMetaBuff);
  9927. rtlFree(layoutMetaBuff);
  9928. }
  9929. }
  9930. public:
  9931. CRoxieServerIndexWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  9932. : CRoxieServerInternalSinkActivity(_factory, _probeManager), helper(static_cast<IHThorIndexWriteArg &>(basehelper))
  9933. {
  9934. overwrite = ((helper.getFlags() & TIWoverwrite) != 0);
  9935. reccount = 0;
  9936. }
  9937. ~CRoxieServerIndexWriteActivity()
  9938. {
  9939. }
  9940. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  9941. {
  9942. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  9943. resolve();
  9944. }
  9945. virtual void onExecute()
  9946. {
  9947. bool isVariable = helper.queryDiskRecordSize()->isVariableSize();
  9948. size32_t maxDiskRecordSize;
  9949. if (isVariable)
  9950. maxDiskRecordSize = 0x8000;
  9951. else
  9952. {
  9953. maxDiskRecordSize = helper.queryDiskRecordSize()->getFixedSize();
  9954. if (maxDiskRecordSize > 0x8000)
  9955. throw MakeStringException(99, "Index minimum record length (%d) exceeds 32k internal limit", maxDiskRecordSize);
  9956. }
  9957. OwnedMalloc<char> rowBuffer(maxDiskRecordSize, true);
  9958. unsigned __int64 fileSize = 0;
  9959. fileCrc = -1;
  9960. if (helper.getDatasetName())
  9961. {
  9962. Owned<const IResolvedFile> dsFileInfo = resolveLFN(helper.getFileName(), false);
  9963. if (dsFileInfo)
  9964. {
  9965. fileSize = dsFileInfo->getFileSize();
  9966. }
  9967. }
  9968. {
  9969. Owned<IFileIO> io;
  9970. try
  9971. {
  9972. io.setown(writer->queryFile()->open(IFOcreate));
  9973. }
  9974. catch(IException * e)
  9975. {
  9976. e->Release();
  9977. clearKeyStoreCache(false);
  9978. io.setown(writer->queryFile()->open(IFOcreate));
  9979. }
  9980. if(!io)
  9981. throw MakeStringException(errno, "Failed to create file %s for writing", filename.str());
  9982. Owned<IFileIOStream> out = createIOStream(io);
  9983. unsigned flags = COL_PREFIX | HTREE_FULLSORT_KEY;
  9984. if (helper.getFlags() & TIWrowcompress)
  9985. flags |= HTREE_COMPRESSED_KEY|HTREE_QUICK_COMPRESSED_KEY;
  9986. else if (!(helper.getFlags() & TIWnolzwcompress))
  9987. flags |= HTREE_COMPRESSED_KEY;
  9988. if (isVariable)
  9989. flags |= HTREE_VARSIZE;
  9990. Owned<IPropertyTree> metadata;
  9991. buildUserMetadata(metadata);
  9992. buildLayoutMetadata(metadata);
  9993. unsigned nodeSize = metadata ? metadata->getPropInt("_nodeSize", NODESIZE) : NODESIZE;
  9994. Owned<IKeyBuilder> builder = createKeyBuilder(out, flags, maxDiskRecordSize, fileSize, nodeSize, helper.getKeyedSize(), 0);
  9995. class BcWrapper : implements IBlobCreator
  9996. {
  9997. IKeyBuilder *builder;
  9998. public:
  9999. BcWrapper(IKeyBuilder *_builder) : builder(_builder) {}
  10000. virtual unsigned __int64 createBlob(size32_t size, const void * ptr)
  10001. {
  10002. return builder->createBlob(size, (const char *) ptr);
  10003. }
  10004. } bc(builder);
  10005. // Loop thru the results
  10006. loop
  10007. {
  10008. OwnedConstRoxieRow nextrec(input->nextInGroup());
  10009. if (!nextrec)
  10010. {
  10011. nextrec.setown(input->nextInGroup());
  10012. if (!nextrec)
  10013. break;
  10014. }
  10015. try
  10016. {
  10017. unsigned __int64 fpos;
  10018. RtlStaticRowBuilder rowBuilder(rowBuffer, maxDiskRecordSize);
  10019. size32_t thisSize = helper.transform(rowBuilder, nextrec, &bc, fpos);
  10020. builder->processKeyData(rowBuffer, fpos, thisSize);
  10021. }
  10022. catch(IException * e)
  10023. {
  10024. throw makeWrappedException(e);
  10025. }
  10026. reccount++;
  10027. }
  10028. if(metadata)
  10029. builder->finish(metadata,&fileCrc);
  10030. else
  10031. builder->finish(&fileCrc);
  10032. }
  10033. }
  10034. virtual void stop(bool aborting)
  10035. {
  10036. if (writer)
  10037. {
  10038. if (!aborting)
  10039. updateWorkUnitResult();
  10040. writer->finish(!aborting, this);
  10041. writer.clear();
  10042. }
  10043. CRoxieServerActivity::stop(aborting);
  10044. }
  10045. virtual void reset()
  10046. {
  10047. CRoxieServerActivity::reset();
  10048. writer.clear();
  10049. }
  10050. //interface IRoxiePublishCallback
  10051. virtual void setFileProperties(IFileDescriptor *desc) const
  10052. {
  10053. IPropertyTree &partProps = desc->queryPart(0)->queryProperties(); //properties of the first file part.
  10054. IPropertyTree &fileProps = desc->queryProperties(); // properties of the logical file
  10055. // Now publish to name services
  10056. StringBuffer dir,base;
  10057. offset_t indexFileSize = writer->queryFile()->size();
  10058. if(clusterHandler)
  10059. clusterHandler->splitPhysicalFilename(dir, base);
  10060. else
  10061. splitFilename(filename.str(), &dir, &dir, &base, &base);
  10062. desc->setDefaultDir(dir.str());
  10063. //properties of the first file part.
  10064. Owned<IPropertyTree> attrs;
  10065. if(clusterHandler)
  10066. attrs.setown(createPTree("Part")); // clusterHandler is going to set attributes
  10067. else
  10068. {
  10069. // add cluster
  10070. StringBuffer mygroupname;
  10071. desc->setNumParts(1);
  10072. desc->setPartMask(base.str());
  10073. attrs.set(&desc->queryPart(0)->queryProperties());
  10074. }
  10075. attrs->setPropInt64("@size", indexFileSize);
  10076. CDateTime createTime, modifiedTime, accessedTime;
  10077. writer->queryFile()->getTime(&createTime, &modifiedTime, &accessedTime);
  10078. // round file time down to nearest sec. Nanosec accurancy is not preserved elsewhere and can lead to mismatch later.
  10079. unsigned hour, min, sec, nanosec;
  10080. modifiedTime.getTime(hour, min, sec, nanosec);
  10081. modifiedTime.setTime(hour, min, sec, 0);
  10082. StringBuffer timestr;
  10083. modifiedTime.getString(timestr);
  10084. if(timestr.length())
  10085. attrs->setProp("@modified", timestr.str());
  10086. if(clusterHandler)
  10087. clusterHandler->setDescriptorParts(desc, base.str(), attrs);
  10088. // properties of the logical file
  10089. IPropertyTree & properties = desc->queryProperties();
  10090. properties.setProp("@kind", "key");
  10091. properties.setPropInt64("@size", indexFileSize);
  10092. properties.setPropInt64("@recordCount", reccount);
  10093. SCMStringBuffer info;
  10094. WorkunitUpdate workUnit = ctx->updateWorkUnit();
  10095. properties.setProp("@owner", workUnit->getUser(info).str());
  10096. info.clear();
  10097. properties.setProp("@workunit", workUnit->getWuid(info).str());
  10098. info.clear();
  10099. properties.setProp("@job", workUnit->getJobName(info).str());
  10100. char const * rececl = helper.queryRecordECL();
  10101. if(rececl && *rececl)
  10102. properties.setProp("ECL", rececl);
  10103. setExpiryTime(properties, helper.getExpiryDays());
  10104. if (helper.getFlags() & TIWupdate)
  10105. {
  10106. unsigned eclCRC;
  10107. unsigned __int64 totalCRC;
  10108. helper.getUpdateCRCs(eclCRC, totalCRC);
  10109. properties.setPropInt("@eclCRC", eclCRC);
  10110. properties.setPropInt64("@totalCRC", totalCRC);
  10111. }
  10112. properties.setPropInt("@fileCrc", fileCrc);
  10113. properties.setPropInt("@formatCrc", helper.getFormatCrc());
  10114. void * layoutMetaBuff;
  10115. size32_t layoutMetaSize;
  10116. if(helper.getIndexLayout(layoutMetaSize, layoutMetaBuff))
  10117. {
  10118. properties.setPropBin("_record_layout", layoutMetaSize, layoutMetaBuff);
  10119. rtlFree(layoutMetaBuff);
  10120. }
  10121. }
  10122. IUserDescriptor *queryUserDescriptor() const
  10123. {
  10124. IConstWorkUnit *workUnit = ctx->queryWorkUnit();
  10125. if (workUnit)
  10126. return workUnit->queryUserDescriptor();
  10127. else
  10128. return NULL;
  10129. }
  10130. };
  10131. //=================================================================================
  10132. class CRoxieServerIndexWriteActivityFactory : public CRoxieServerMultiOutputFactory
  10133. {
  10134. public:
  10135. CRoxieServerIndexWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  10136. : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  10137. {
  10138. setNumOutputs(0);
  10139. }
  10140. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  10141. {
  10142. return new CRoxieServerIndexWriteActivity(this, _probeManager);
  10143. }
  10144. virtual bool isSink() const
  10145. {
  10146. return true;
  10147. }
  10148. };
  10149. IRoxieServerActivityFactory *createRoxieServerIndexWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  10150. {
  10151. return new CRoxieServerIndexWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  10152. }
  10153. //=================================================================================
  10154. static inline void getLimitType(unsigned flags, bool & limitFail, bool & limitOnFail)
  10155. {
  10156. if((flags & JFmatchAbortLimitSkips) != 0)
  10157. {
  10158. limitFail = false;
  10159. limitOnFail = false;
  10160. }
  10161. else
  10162. {
  10163. limitOnFail = ((flags & JFonfail) != 0);
  10164. limitFail = !limitOnFail;
  10165. }
  10166. }
  10167. class CRoxieServerJoinActivity : public CRoxieServerTwoInputActivity
  10168. {
  10169. enum { JSfill, JSfillleft, JSfillright, JScollate, JScompare, JSleftonly, JSrightonly } state;
  10170. IHThorJoinArg &helper;
  10171. ICompare * collate;
  10172. ICompare * collateupper;
  10173. ThorActivityKind activityKind;
  10174. bool leftOuterJoin;
  10175. bool rightOuterJoin;
  10176. bool exclude;
  10177. bool limitFail;
  10178. bool limitOnFail;
  10179. unsigned keepLimit;
  10180. unsigned joinLimit;
  10181. unsigned atmostLimit;
  10182. unsigned abortLimit;
  10183. bool betweenjoin;
  10184. OwnedRowArray right;
  10185. const void * left;
  10186. const void * pendingRight;
  10187. unsigned rightIndex;
  10188. BoolArray matchedRight;
  10189. bool matchedLeft;
  10190. Owned<IException> failingLimit;
  10191. ConstPointerArray filteredRight;
  10192. Owned<IRHLimitedCompareHelper> limitedhelper;
  10193. OwnedConstRoxieRow defaultLeft;
  10194. OwnedConstRoxieRow defaultRight;
  10195. Owned<IEngineRowAllocator> defaultLeftAllocator;
  10196. Owned<IEngineRowAllocator> defaultRightAllocator;
  10197. bool cloneLeft;
  10198. void createDefaultLeft()
  10199. {
  10200. if (!defaultLeft)
  10201. {
  10202. if (!defaultLeftAllocator)
  10203. defaultLeftAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input->queryOutputMeta(), activityId));
  10204. RtlDynamicRowBuilder rowBuilder(defaultLeftAllocator);
  10205. size32_t thisSize = helper.createDefaultLeft(rowBuilder);
  10206. defaultLeft.setown(rowBuilder.finalizeRowClear(thisSize));
  10207. }
  10208. }
  10209. void createDefaultRight()
  10210. {
  10211. if (!defaultRight)
  10212. {
  10213. if (!defaultRightAllocator)
  10214. defaultRightAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input1->queryOutputMeta(), activityId));
  10215. RtlDynamicRowBuilder rowBuilder(defaultRightAllocator);
  10216. size32_t thisSize = helper.createDefaultRight(rowBuilder);
  10217. defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
  10218. }
  10219. }
  10220. public:
  10221. CRoxieServerJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  10222. : CRoxieServerTwoInputActivity(_factory, _probeManager), helper((IHThorJoinArg &)basehelper)
  10223. {
  10224. // MORE - some of this should be done in factory
  10225. unsigned joinFlags = helper.getJoinFlags();
  10226. leftOuterJoin = (joinFlags & JFleftouter) != 0;
  10227. rightOuterJoin = (joinFlags & JFrightouter) != 0;
  10228. exclude = (joinFlags & JFexclude) != 0;
  10229. cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
  10230. getLimitType(joinFlags, limitFail, limitOnFail);
  10231. if (joinFlags & JFslidingmatch)
  10232. {
  10233. betweenjoin = true;
  10234. collate = helper.queryCompareLeftRightLower();
  10235. collateupper = helper.queryCompareLeftRightUpper();
  10236. }
  10237. else
  10238. {
  10239. betweenjoin = false;
  10240. collate = collateupper = helper.queryCompareLeftRight();
  10241. }
  10242. rightIndex = 0;
  10243. state = JSfill;
  10244. matchedLeft = false;
  10245. joinLimit = 0;
  10246. keepLimit = 0; // wait until ctx available
  10247. atmostLimit = 0; // wait until ctx available
  10248. abortLimit = 0; // wait until ctx available
  10249. assertex((joinFlags & (JFfirst | JFfirstleft | JFfirstright)) == 0);
  10250. left = NULL;
  10251. pendingRight = NULL;
  10252. activityKind = _factory->getKind();
  10253. }
  10254. virtual bool needsAllocator() const { return true; }
  10255. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  10256. {
  10257. left = NULL;
  10258. rightIndex = 0;
  10259. state = JSfill;
  10260. matchedLeft = false;
  10261. CRoxieServerTwoInputActivity::start(parentExtractSize, parentExtract, paused);
  10262. keepLimit = helper.getKeepLimit();
  10263. if (keepLimit == 0)
  10264. keepLimit = (unsigned)-1;
  10265. atmostLimit = helper.getJoinLimit();
  10266. if(atmostLimit == 0)
  10267. atmostLimit = (unsigned)-1;
  10268. else
  10269. assertex(!rightOuterJoin && !betweenjoin);
  10270. abortLimit = helper.getMatchAbortLimit();
  10271. if (abortLimit == 0)
  10272. abortLimit = (unsigned)-1;
  10273. if (rightOuterJoin)
  10274. createDefaultLeft();
  10275. if ((leftOuterJoin && (activityKind==TAKjoin || activityKind==TAKjoinlight || activityKind==TAKdenormalizegroup)) || limitOnFail)
  10276. createDefaultRight();
  10277. if ((helper.getJoinFlags() & JFlimitedprefixjoin) && helper.getJoinLimit())
  10278. { //limited match join (s[1..n])
  10279. limitedhelper.setown(createRHLimitedCompareHelper());
  10280. limitedhelper->init( helper.getJoinLimit(), input1, collate, helper.queryPrefixCompare() );
  10281. }
  10282. }
  10283. virtual void reset()
  10284. {
  10285. right.clear();
  10286. ReleaseClearRoxieRow(left);
  10287. ReleaseClearRoxieRow(pendingRight);
  10288. defaultRight.clear();
  10289. defaultLeft.clear();
  10290. CRoxieServerTwoInputActivity::reset();
  10291. }
  10292. virtual void setInput(unsigned idx, IRoxieInput *_in)
  10293. {
  10294. switch(idx)
  10295. {
  10296. case 0:
  10297. if ((helper.getJoinFlags() & JFparallel) != 0)
  10298. {
  10299. puller.setown(new CRoxieServerReadAheadInput(0)); // MORE - cant ask context for parallelJoinPreload as context is not yet set up.
  10300. puller->setInput(0, _in);
  10301. _in = puller;
  10302. }
  10303. input = _in;
  10304. break;
  10305. case 1:
  10306. input1 = _in;
  10307. break;
  10308. default:
  10309. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  10310. }
  10311. }
  10312. virtual IRoxieInput *queryOutput(unsigned idx)
  10313. {
  10314. if (idx==(unsigned)-1)
  10315. idx = 0;
  10316. return idx ? NULL : this;
  10317. }
  10318. void fillLeft()
  10319. {
  10320. matchedLeft = false;
  10321. left = input->nextInGroup();
  10322. if (!left)
  10323. left = input->nextInGroup();
  10324. if(betweenjoin && left && pendingRight && (collate->docompare(left, pendingRight) >= 0))
  10325. fillRight();
  10326. if (limitedhelper && 0==rightIndex)
  10327. {
  10328. rightIndex = 0;
  10329. right.clear();
  10330. matchedRight.kill();
  10331. if (left)
  10332. {
  10333. limitedhelper->getGroup(right,left);
  10334. ForEachItemIn(idx, right)
  10335. matchedRight.append(false);
  10336. }
  10337. }
  10338. }
  10339. void fillRight()
  10340. {
  10341. if (limitedhelper)
  10342. return;
  10343. failingLimit.clear();
  10344. if(betweenjoin && left)
  10345. {
  10346. aindex_t start = 0;
  10347. while(right.isItem(start) && (collateupper->docompare(left, right.item(start)) > 0))
  10348. start++;
  10349. if(start>0)
  10350. right.clearPart(0, start);
  10351. }
  10352. else
  10353. right.clear();
  10354. rightIndex = 0;
  10355. unsigned groupCount = 0;
  10356. const void * next;
  10357. while(true)
  10358. {
  10359. if(pendingRight)
  10360. {
  10361. next = pendingRight;
  10362. pendingRight = NULL;
  10363. }
  10364. else
  10365. {
  10366. next = input1->nextInGroup();
  10367. }
  10368. if(!rightOuterJoin && next && (!left || (collateupper->docompare(left, next) > 0))) // if right is less than left, and not right outer, can skip group
  10369. {
  10370. while(next)
  10371. {
  10372. ReleaseClearRoxieRow(next);
  10373. next = input1->nextInGroup();
  10374. }
  10375. continue;
  10376. }
  10377. while(next)
  10378. {
  10379. if(groupCount==abortLimit)
  10380. {
  10381. if(limitFail)
  10382. failLimit();
  10383. if (ctx->queryDebugContext())
  10384. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  10385. if(limitOnFail)
  10386. {
  10387. assertex(!failingLimit);
  10388. try
  10389. {
  10390. failLimit();
  10391. }
  10392. catch(IException * except)
  10393. {
  10394. failingLimit.setown(except);
  10395. }
  10396. assertex(failingLimit != NULL);
  10397. }
  10398. right.append(next);
  10399. do
  10400. {
  10401. next = input1->nextInGroup();
  10402. ReleaseRoxieRow(next);
  10403. } while(next);
  10404. break;
  10405. }
  10406. else if(groupCount==atmostLimit)
  10407. {
  10408. right.clear();
  10409. groupCount = 0;
  10410. while(next)
  10411. {
  10412. ReleaseRoxieRow(next);
  10413. next = input1->nextInGroup();
  10414. }
  10415. }
  10416. else
  10417. {
  10418. right.append(next);
  10419. groupCount++;
  10420. }
  10421. next = input1->nextInGroup();
  10422. }
  10423. // normally only want to read one right group, but if is between join and next right group is in window for left, need to continue
  10424. if(betweenjoin && left)
  10425. {
  10426. pendingRight = input1->nextInGroup();
  10427. if(!pendingRight || (collate->docompare(left, pendingRight) < 0))
  10428. break;
  10429. }
  10430. else
  10431. break;
  10432. }
  10433. matchedRight.kill();
  10434. ForEachItemIn(idx, right)
  10435. matchedRight.append(false);
  10436. }
  10437. const void * joinRecords(const void * curLeft, const void * curRight)
  10438. {
  10439. if (cloneLeft)
  10440. {
  10441. LinkRoxieRow(curLeft);
  10442. return curLeft;
  10443. }
  10444. try
  10445. {
  10446. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  10447. size32_t thisSize = helper.transform(rowBuilder, curLeft, curRight);
  10448. if (thisSize)
  10449. return rowBuilder.finalizeRowClear(thisSize);
  10450. else
  10451. return NULL;
  10452. }
  10453. catch (IException *E)
  10454. {
  10455. throw makeWrappedException(E);
  10456. }
  10457. }
  10458. const void * denormalizeRecords(const void * curLeft, ConstPointerArray & rows)
  10459. {
  10460. try
  10461. {
  10462. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  10463. unsigned numRows = rows.ordinality();
  10464. const void * right = numRows ? rows.item(0) : defaultRight.get();
  10465. size32_t thisSize = helper.transform(rowBuilder, curLeft, right, numRows, (const void * *)rows.getArray());
  10466. if (thisSize)
  10467. return rowBuilder.finalizeRowClear(thisSize);
  10468. else
  10469. return NULL;
  10470. }
  10471. catch (IException *E)
  10472. {
  10473. throw makeWrappedException(E);
  10474. }
  10475. }
  10476. const void * joinException(const void * curLeft, IException * except)
  10477. {
  10478. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  10479. size32_t thisSize = helper.onFailTransform(rowBuilder, curLeft, defaultRight, except);
  10480. return rowBuilder.finalizeRowClear(thisSize);
  10481. }
  10482. void failLimit()
  10483. {
  10484. helper.onMatchAbortLimitExceeded();
  10485. CommonXmlWriter xmlwrite(0);
  10486. if (input->queryOutputMeta() && input->queryOutputMeta()->hasXML())
  10487. {
  10488. input->queryOutputMeta()->toXML((byte *) left, xmlwrite);
  10489. }
  10490. throw MakeStringException(ROXIE_TOO_MANY_RESULTS, "More than %d match candidates in join %d for row %s", abortLimit, queryId(), xmlwrite.str());
  10491. }
  10492. virtual const void * nextInGroup()
  10493. {
  10494. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  10495. loop
  10496. {
  10497. switch (state)
  10498. {
  10499. case JSfill:
  10500. fillLeft();
  10501. state = JSfillright;
  10502. break;
  10503. case JSfillright:
  10504. fillRight();
  10505. state = JScollate;
  10506. break;
  10507. case JSfillleft:
  10508. fillLeft();
  10509. state = JScollate;
  10510. break;
  10511. case JScollate:
  10512. if (right.ordinality() == 0)
  10513. {
  10514. if (left == NULL)
  10515. return NULL;
  10516. state = JSleftonly;
  10517. }
  10518. else
  10519. {
  10520. if (!left)
  10521. state = JSrightonly;
  10522. else
  10523. {
  10524. int diff;
  10525. if(betweenjoin)
  10526. diff = ((collate->docompare(left, right.item(0)) < 0) ? -1 : ((collateupper->docompare(left, right.item(right.ordinality()-1)) > 0) ? +1 : 0));
  10527. else
  10528. diff = collate->docompare(left, right.item(0));
  10529. bool limitExceeded = right.ordinality()>abortLimit;
  10530. if (diff == 0)
  10531. {
  10532. if (limitExceeded)
  10533. {
  10534. const void * ret = NULL;
  10535. if(failingLimit)
  10536. ret = joinException(left, failingLimit);
  10537. ReleaseRoxieRow(left);
  10538. left = NULL;
  10539. state = JSfillleft;
  10540. ForEachItemIn(idx, right)
  10541. matchedRight.replace(true, idx);
  10542. if(ret)
  10543. {
  10544. processed++;
  10545. return ret;
  10546. }
  10547. }
  10548. else
  10549. {
  10550. state = JScompare;
  10551. joinLimit = keepLimit;
  10552. }
  10553. }
  10554. else if (diff < 0)
  10555. state = JSleftonly;
  10556. else if (limitExceeded)
  10557. {
  10558. // MORE - Roxie code seems to think there should be a destroyRowset(right) here....
  10559. state = JSfillright;
  10560. }
  10561. else
  10562. state = JSrightonly;
  10563. }
  10564. }
  10565. break;
  10566. case JSrightonly:
  10567. if (rightOuterJoin)
  10568. {
  10569. switch (activityKind)
  10570. {
  10571. case TAKjoin:
  10572. {
  10573. while (right.isItem(rightIndex))
  10574. {
  10575. if (!matchedRight.item(rightIndex))
  10576. {
  10577. const void * rhs = right.item(rightIndex++);
  10578. const void *ret = joinRecords(defaultLeft, rhs);
  10579. if (ret)
  10580. {
  10581. processed++;
  10582. return ret;
  10583. }
  10584. }
  10585. rightIndex++;
  10586. }
  10587. break;
  10588. }
  10589. //Probably excessive to implement the following, but possibly useful
  10590. case TAKdenormalize:
  10591. {
  10592. OwnedConstRoxieRow newLeft;
  10593. newLeft.set(defaultLeft);
  10594. unsigned rowSize = 0;
  10595. unsigned leftCount = 0;
  10596. while (right.isItem(rightIndex))
  10597. {
  10598. if (!matchedRight.item(rightIndex))
  10599. {
  10600. const void * rhs = right.item(rightIndex);
  10601. try
  10602. {
  10603. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  10604. unsigned thisSize = helper.transform(rowBuilder, newLeft, rhs, ++leftCount);
  10605. if (thisSize)
  10606. {
  10607. rowSize = thisSize;
  10608. newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
  10609. }
  10610. }
  10611. catch (IException *E)
  10612. {
  10613. throw makeWrappedException(E);
  10614. }
  10615. }
  10616. rightIndex++;
  10617. }
  10618. state = JSfillright;
  10619. if (rowSize)
  10620. {
  10621. processed++;
  10622. return newLeft.getClear();
  10623. }
  10624. break;
  10625. }
  10626. case TAKdenormalizegroup:
  10627. {
  10628. filteredRight.kill();
  10629. while (right.isItem(rightIndex))
  10630. {
  10631. if (!matchedRight.item(rightIndex))
  10632. filteredRight.append(right.item(rightIndex));
  10633. rightIndex++;
  10634. }
  10635. state = JSfillright;
  10636. if (filteredRight.ordinality())
  10637. {
  10638. const void * ret = denormalizeRecords(defaultLeft, filteredRight);
  10639. filteredRight.kill();
  10640. if (ret)
  10641. {
  10642. processed++;
  10643. return ret;
  10644. }
  10645. }
  10646. break;
  10647. }
  10648. }
  10649. }
  10650. state = JSfillright;
  10651. break;
  10652. case JSleftonly:
  10653. {
  10654. const void * ret = NULL;
  10655. if (!matchedLeft && leftOuterJoin)
  10656. {
  10657. switch (activityKind)
  10658. {
  10659. case TAKjoin:
  10660. ret = joinRecords(left, defaultRight);
  10661. break;
  10662. case TAKdenormalize:
  10663. ret = left;
  10664. left = NULL;
  10665. break;
  10666. case TAKdenormalizegroup:
  10667. filteredRight.kill();
  10668. ret = denormalizeRecords(left, filteredRight);
  10669. break;
  10670. }
  10671. }
  10672. ReleaseRoxieRow(left);
  10673. left = NULL;
  10674. state = JSfillleft;
  10675. if (ret)
  10676. {
  10677. processed++;
  10678. return ret;
  10679. }
  10680. break;
  10681. }
  10682. case JScompare:
  10683. if (joinLimit != 0)
  10684. {
  10685. switch (activityKind)
  10686. {
  10687. case TAKjoin:
  10688. {
  10689. while (right.isItem(rightIndex))
  10690. {
  10691. const void * rhs = right.item(rightIndex++);
  10692. if (helper.match(left, rhs))
  10693. {
  10694. matchedRight.replace(true, rightIndex-1);
  10695. matchedLeft = true;
  10696. if (!exclude)
  10697. {
  10698. const void *ret = joinRecords(left, rhs);
  10699. if (ret)
  10700. {
  10701. processed++;
  10702. joinLimit--;
  10703. return ret;
  10704. }
  10705. }
  10706. }
  10707. }
  10708. break;
  10709. }
  10710. case TAKdenormalize:
  10711. {
  10712. OwnedConstRoxieRow newLeft;
  10713. newLeft.set(left);
  10714. unsigned rowSize = 0;
  10715. unsigned leftCount = 0;
  10716. while (right.isItem(rightIndex) && joinLimit)
  10717. {
  10718. try
  10719. {
  10720. const void * rhs = right.item(rightIndex++);
  10721. if (helper.match(left, rhs))
  10722. {
  10723. matchedRight.replace(true, rightIndex-1);
  10724. matchedLeft = true;
  10725. if (!exclude)
  10726. {
  10727. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  10728. unsigned thisSize = helper.transform(rowBuilder, newLeft, rhs, ++leftCount);
  10729. if (thisSize)
  10730. {
  10731. rowSize = thisSize;
  10732. newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
  10733. joinLimit--;
  10734. }
  10735. }
  10736. }
  10737. }
  10738. catch (IException *E)
  10739. {
  10740. throw makeWrappedException(E);
  10741. }
  10742. }
  10743. state = JSleftonly;
  10744. rightIndex = 0;
  10745. if (rowSize)
  10746. {
  10747. processed++;
  10748. return newLeft.getClear();
  10749. }
  10750. break;
  10751. }
  10752. case TAKdenormalizegroup:
  10753. {
  10754. filteredRight.kill();
  10755. while (right.isItem(rightIndex))
  10756. {
  10757. const void * rhs = right.item(rightIndex++);
  10758. if (helper.match(left, rhs))
  10759. {
  10760. matchedRight.replace(true, rightIndex-1);
  10761. filteredRight.append(rhs);
  10762. matchedLeft = true;
  10763. if (filteredRight.ordinality()==joinLimit)
  10764. break;
  10765. }
  10766. }
  10767. state = JSleftonly;
  10768. rightIndex = 0;
  10769. if (!exclude && filteredRight.ordinality())
  10770. {
  10771. const void * ret = denormalizeRecords(left, filteredRight);
  10772. filteredRight.kill();
  10773. if (ret)
  10774. {
  10775. processed++;
  10776. return ret;
  10777. }
  10778. }
  10779. break;
  10780. }
  10781. }
  10782. }
  10783. state = JSleftonly;
  10784. rightIndex = 0;
  10785. break;
  10786. }
  10787. }
  10788. }
  10789. };
  10790. class CRoxieServerJoinActivityFactory : public CRoxieServerActivityFactory
  10791. {
  10792. unsigned input2;
  10793. unsigned input2idx;
  10794. public:
  10795. CRoxieServerJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  10796. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  10797. {
  10798. input2 = 0;
  10799. input2idx = 0;
  10800. }
  10801. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  10802. {
  10803. return new CRoxieServerJoinActivity(this, _probeManager);
  10804. }
  10805. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  10806. {
  10807. if (idx==1)
  10808. {
  10809. input2 = source;
  10810. input2idx = sourceidx;
  10811. }
  10812. else
  10813. CRoxieServerActivityFactory::setInput(idx, source, sourceidx);
  10814. }
  10815. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  10816. {
  10817. switch (idx)
  10818. {
  10819. case 1:
  10820. sourceidx = input2idx;
  10821. return input2;
  10822. case 0:
  10823. return CRoxieServerActivityFactory::getInput(idx, sourceidx);
  10824. default:
  10825. return (unsigned) -1;
  10826. }
  10827. }
  10828. };
  10829. IRoxieServerActivityFactory *createRoxieServerJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  10830. {
  10831. return new CRoxieServerJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  10832. }
  10833. //=================================================================================
  10834. #define CONCAT_READAHEAD 1000
  10835. MAKEPointerArray(RecordPullerThread, RecordPullerArray);
  10836. class CRoxieServerThreadedConcatActivity : public CRoxieServerActivity, implements IRecordPullerCallback
  10837. {
  10838. QueueOf<const void, true> buffer;
  10839. InterruptableSemaphore ready;
  10840. InterruptableSemaphore space;
  10841. CriticalSection crit;
  10842. unsigned eofs;
  10843. RecordPullerArray pullers;
  10844. unsigned numInputs;
  10845. public:
  10846. CRoxieServerThreadedConcatActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _grouped, unsigned _numInputs)
  10847. : CRoxieServerActivity(_factory, _probeManager)
  10848. {
  10849. eofs = 0;
  10850. numInputs = _numInputs;
  10851. for (unsigned i = 0; i < numInputs; i++)
  10852. pullers.append(*new RecordPullerThread(_grouped));
  10853. }
  10854. ~CRoxieServerThreadedConcatActivity()
  10855. {
  10856. ForEachItemIn(idx, pullers)
  10857. delete &pullers.item(idx);
  10858. }
  10859. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  10860. {
  10861. space.reinit(CONCAT_READAHEAD);
  10862. ready.reinit();
  10863. eofs = 0;
  10864. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  10865. ForEachItemIn(idx, pullers)
  10866. {
  10867. pullers.item(idx).start(parentExtractSize, parentExtract, paused, ctx->concatPreload(), false, ctx);
  10868. // NOTE - it is ok to start the thread running while parts of the subgraph are still being started, since everything
  10869. // in the part of the subgraph that the thread uses has been started.
  10870. // Note that splitters are supposed to cope with being used when only some outputs have been started.
  10871. }
  10872. }
  10873. virtual void stop(bool aborting)
  10874. {
  10875. space.interrupt();
  10876. ready.interrupt();
  10877. ForEachItemIn(idx, pullers)
  10878. pullers.item(idx).stop(aborting);
  10879. CRoxieServerActivity::stop(aborting);
  10880. }
  10881. virtual unsigned __int64 queryLocalCycles() const
  10882. {
  10883. return 0;
  10884. }
  10885. virtual IRoxieInput *queryInput(unsigned idx) const
  10886. {
  10887. if (pullers.isItem(idx))
  10888. return pullers.item(idx).queryInput();
  10889. else
  10890. return NULL;
  10891. }
  10892. virtual void reset()
  10893. {
  10894. CRoxieServerActivity::reset();
  10895. ForEachItemIn(idx, pullers)
  10896. pullers.item(idx).reset();
  10897. ForEachItemIn(idx1, buffer)
  10898. ReleaseRoxieRow(buffer.item(idx1));
  10899. buffer.clear();
  10900. }
  10901. virtual void setInput(unsigned idx, IRoxieInput *_in)
  10902. {
  10903. if (pullers.isItem(idx))
  10904. pullers.item(idx).setInput(this, _in);
  10905. else
  10906. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  10907. }
  10908. virtual const void * nextInGroup()
  10909. {
  10910. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  10911. loop
  10912. {
  10913. {
  10914. CriticalBlock b(crit);
  10915. if (eofs==numInputs && !buffer.ordinality())
  10916. return NULL; // eof
  10917. }
  10918. ready.wait();
  10919. const void *ret;
  10920. {
  10921. CriticalBlock b(crit);
  10922. ret = buffer.dequeue();
  10923. }
  10924. if (ret)
  10925. processed++;
  10926. space.signal();
  10927. return ret;
  10928. }
  10929. }
  10930. virtual bool fireException(IException *e)
  10931. {
  10932. // called from puller thread on failure
  10933. ready.interrupt(LINK(e));
  10934. space.interrupt(e);
  10935. return true;
  10936. }
  10937. virtual void processRow(const void *row)
  10938. {
  10939. {
  10940. CriticalBlock b(crit);
  10941. buffer.enqueue(row);
  10942. }
  10943. ready.signal();
  10944. space.wait();
  10945. }
  10946. virtual void processGroup(const ConstPointerArray &rows)
  10947. {
  10948. // NOTE - a bit bizzare in that it waits for the space AFTER using it.
  10949. // But the space semaphore is only there to stop infinite readahead. And otherwise it would deadlock
  10950. // if group was larger than max(space)
  10951. {
  10952. CriticalBlock b(crit);
  10953. ForEachItemIn(idx, rows)
  10954. buffer.enqueue(rows.item(idx));
  10955. buffer.enqueue(NULL);
  10956. }
  10957. for (unsigned i2 = 0; i2 <= rows.length(); i2++) // note - does 1 extra for the null
  10958. {
  10959. ready.signal();
  10960. space.wait();
  10961. }
  10962. }
  10963. virtual void processEOG()
  10964. {
  10965. // Used when output is not grouped - just ignore
  10966. }
  10967. virtual void processDone()
  10968. {
  10969. CriticalBlock b(crit);
  10970. eofs++;
  10971. if (eofs == numInputs)
  10972. ready.signal();
  10973. }
  10974. };
  10975. class CRoxieServerOrderedConcatActivity : public CRoxieServerActivity
  10976. {
  10977. IRoxieInput *curInput;
  10978. bool eogSeen;
  10979. bool anyThisGroup;
  10980. bool grouped;
  10981. unsigned numInputs;
  10982. unsigned inputIdx;
  10983. IRoxieInput **inputArray;
  10984. public:
  10985. CRoxieServerOrderedConcatActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _grouped, unsigned _numInputs)
  10986. : CRoxieServerActivity(_factory, _probeManager)
  10987. {
  10988. eogSeen = false;
  10989. anyThisGroup = false;
  10990. grouped = _grouped;
  10991. numInputs = _numInputs;
  10992. inputIdx = 0;
  10993. inputArray = new IRoxieInput*[numInputs];
  10994. for (unsigned i = 0; i < numInputs; i++)
  10995. inputArray[i] = NULL;
  10996. }
  10997. ~CRoxieServerOrderedConcatActivity()
  10998. {
  10999. delete [] inputArray;
  11000. }
  11001. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11002. {
  11003. inputIdx = 0;
  11004. curInput = inputArray[inputIdx];
  11005. eogSeen = false;
  11006. anyThisGroup = false;
  11007. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  11008. for (unsigned i = 0; i < numInputs; i++)
  11009. inputArray[i]->start(parentExtractSize, parentExtract, paused);
  11010. }
  11011. virtual void stop(bool aborting)
  11012. {
  11013. for (unsigned i = 0; i < numInputs; i++)
  11014. inputArray[i]->stop(aborting);
  11015. CRoxieServerActivity::stop(aborting);
  11016. }
  11017. virtual unsigned __int64 queryLocalCycles() const
  11018. {
  11019. return 0;
  11020. }
  11021. virtual IRoxieInput *queryInput(unsigned idx) const
  11022. {
  11023. if (idx < numInputs)
  11024. return inputArray[idx];
  11025. else
  11026. return NULL;
  11027. }
  11028. virtual void reset()
  11029. {
  11030. CRoxieServerActivity::reset();
  11031. for (unsigned i = 0; i < numInputs; i++)
  11032. inputArray[i]->reset();
  11033. }
  11034. virtual void setInput(unsigned idx, IRoxieInput *_in)
  11035. {
  11036. inputArray[idx] = _in;
  11037. }
  11038. virtual const void * nextInGroup()
  11039. {
  11040. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  11041. if (!curInput)
  11042. return NULL; // eof
  11043. const void * next = curInput->nextInGroup();
  11044. if (next)
  11045. {
  11046. anyThisGroup = true;
  11047. eogSeen = false;
  11048. processed++;
  11049. return next;
  11050. }
  11051. else if (!eogSeen)
  11052. {
  11053. eogSeen = true;
  11054. if (grouped)
  11055. {
  11056. if (anyThisGroup)
  11057. {
  11058. anyThisGroup = false;
  11059. return NULL;
  11060. }
  11061. else
  11062. return nextInGroup();
  11063. }
  11064. else
  11065. return nextInGroup();
  11066. }
  11067. else if (inputIdx < numInputs-1)
  11068. {
  11069. inputIdx++;
  11070. curInput = inputArray[inputIdx];
  11071. eogSeen = false;
  11072. return nextInGroup();
  11073. }
  11074. else
  11075. {
  11076. curInput = NULL;
  11077. return NULL;
  11078. }
  11079. }
  11080. };
  11081. class CRoxieServerConcatActivityFactory : public CRoxieServerMultiInputFactory
  11082. {
  11083. bool ordered;
  11084. bool grouped;
  11085. public:
  11086. CRoxieServerConcatActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11087. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  11088. {
  11089. Owned <IHThorFunnelArg> helper = (IHThorFunnelArg *) helperFactory();
  11090. ordered = helper->isOrdered();
  11091. grouped = helper->queryOutputMeta()->isGrouped();
  11092. }
  11093. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  11094. {
  11095. if (ordered || (_probeManager && _probeManager->queryDebugManager()))
  11096. return new CRoxieServerOrderedConcatActivity(this, _probeManager, grouped, numInputs());
  11097. else
  11098. return new CRoxieServerThreadedConcatActivity(this, _probeManager, grouped, numInputs());
  11099. }
  11100. };
  11101. IRoxieServerActivityFactory *createRoxieServerConcatActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11102. {
  11103. return new CRoxieServerConcatActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  11104. }
  11105. //=================================================================================
  11106. class CRoxieServerNonEmptyActivity : public CRoxieServerMultiInputBaseActivity
  11107. {
  11108. IRoxieInput * selectedInput;
  11109. unsigned savedParentExtractSize;
  11110. const byte * savedParentExtract;
  11111. bool foundInput;
  11112. public:
  11113. CRoxieServerNonEmptyActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  11114. : CRoxieServerMultiInputBaseActivity(_factory, _probeManager, _numInputs)
  11115. {
  11116. foundInput = false;
  11117. selectedInput = NULL;
  11118. savedParentExtractSize = 0;;
  11119. savedParentExtract = NULL;
  11120. }
  11121. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11122. {
  11123. //Don't start the inputs yet so we can short-circuit...
  11124. CRoxieServerMultiInputBaseActivity::start(parentExtractSize, parentExtract, paused);
  11125. savedParentExtractSize = parentExtractSize;
  11126. savedParentExtract = parentExtract;
  11127. }
  11128. virtual void stop(bool aborting)
  11129. {
  11130. if (foundInput)
  11131. {
  11132. if (selectedInput)
  11133. selectedInput->stop(aborting);
  11134. }
  11135. else
  11136. {
  11137. for (unsigned i = 0; i < numInputs; i++)
  11138. inputArray[i]->stop(aborting);
  11139. }
  11140. CRoxieServerMultiInputBaseActivity::stop(aborting);
  11141. }
  11142. virtual void reset()
  11143. {
  11144. CRoxieServerMultiInputBaseActivity::reset();
  11145. foundInput = false;
  11146. selectedInput = NULL;
  11147. }
  11148. virtual unsigned __int64 queryLocalCycles() const
  11149. {
  11150. return 0; // Can't easily calcuate anything reliable but local processing is negligible
  11151. }
  11152. virtual const void * nextInGroup()
  11153. {
  11154. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  11155. if (!foundInput)
  11156. {
  11157. foundInput = true;
  11158. //If we get an exception in this loop then stop() will stop any started inputs
  11159. for (unsigned i=0; i < numInputs; i++)
  11160. {
  11161. selectedInput = inputArray[i];
  11162. selectedInput->start(savedParentExtractSize, savedParentExtract, false);
  11163. const void * next = selectedInput->nextInGroup();
  11164. if (next)
  11165. {
  11166. //Found a row so stop remaining
  11167. for (unsigned j=i+1; j < numInputs; j++)
  11168. inputArray[j]->stop(false);
  11169. processed++;
  11170. return next;
  11171. }
  11172. selectedInput->stop(false);
  11173. }
  11174. selectedInput = NULL;
  11175. return NULL;
  11176. }
  11177. if (!selectedInput)
  11178. return NULL;
  11179. const void * next = selectedInput->nextInGroup();
  11180. if (next)
  11181. processed++;
  11182. return next;
  11183. }
  11184. };
  11185. class CRoxieServerNonEmptyActivityFactory : public CRoxieServerMultiInputFactory
  11186. {
  11187. public:
  11188. CRoxieServerNonEmptyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11189. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  11190. {
  11191. }
  11192. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  11193. {
  11194. return new CRoxieServerNonEmptyActivity(this, _probeManager, numInputs());
  11195. }
  11196. };
  11197. IRoxieServerActivityFactory *createRoxieServerNonEmptyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11198. {
  11199. return new CRoxieServerNonEmptyActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  11200. }
  11201. //=================================================================================
  11202. class CRoxieServerMergeActivity : public CRoxieServerActivity
  11203. {
  11204. IHThorMergeArg &helper;
  11205. unsigned *mergeheap;
  11206. unsigned activeInputs;
  11207. unsigned numInputs;
  11208. IRoxieInput **inputArray;
  11209. const void **pending;
  11210. bool first;
  11211. ICompare *compare;
  11212. bool dedup;
  11213. void permute()
  11214. {
  11215. assertex(activeInputs == 0);
  11216. for(unsigned i = 0; i < numInputs; i++)
  11217. if(pullInput(i))
  11218. mergeheap[activeInputs++] = i;
  11219. // the tree structure: element p has children p*2+1 and p*2+2, or element c has parent (unsigned)(c-1)/2
  11220. // the heap property: no element should be smaller than its parent
  11221. // the dedup variant: if(dedup), the top of the heap should also not be equal to either child
  11222. // the method: establish this by starting with the parent of the bottom element and working up to the top element, sifting each down to its correct place
  11223. if (activeInputs >= 2)
  11224. for(unsigned p = (activeInputs-2)/2; p > 0; --p)
  11225. siftDown(p);
  11226. if(dedup)
  11227. siftDownDedupTop();
  11228. else
  11229. siftDown(0);
  11230. }
  11231. void readNext()
  11232. {
  11233. if(!pullInput(mergeheap[0]))
  11234. if(!promote(0))
  11235. return;
  11236. // we have changed the element at the top of the heap, so need to sift it down to maintain the heap property
  11237. if(dedup)
  11238. siftDownDedupTop();
  11239. else
  11240. siftDown(0);
  11241. }
  11242. bool pullInput(unsigned i)
  11243. {
  11244. const void *next = inputArray[i]->nextInGroup();
  11245. if (!next)
  11246. next = inputArray[i]->nextInGroup();
  11247. pending[i] = next;
  11248. return (next != NULL);
  11249. }
  11250. bool promote(unsigned p)
  11251. {
  11252. activeInputs--;
  11253. if(activeInputs == p)
  11254. return false;
  11255. mergeheap[p] = mergeheap[activeInputs];
  11256. return true;
  11257. }
  11258. bool siftDown(unsigned p)
  11259. {
  11260. // assumimg that all descendents of p form a heap, sift p down to its correct position, and so include it in the heap
  11261. bool nochange = true;
  11262. while(1)
  11263. {
  11264. unsigned c = p*2 + 1;
  11265. if(c >= activeInputs)
  11266. return nochange;
  11267. if(c+1 < activeInputs)
  11268. {
  11269. int childcmp = BuffCompare(c+1, c);
  11270. if((childcmp < 0) || ((childcmp == 0) && (mergeheap[c+1] < mergeheap[c])))
  11271. ++c;
  11272. }
  11273. int cmp = BuffCompare(c, p);
  11274. if((cmp > 0) || ((cmp == 0) && (mergeheap[c] > mergeheap[p])))
  11275. return nochange;
  11276. nochange = false;
  11277. unsigned r = mergeheap[c];
  11278. mergeheap[c] = mergeheap[p];
  11279. mergeheap[p] = r;
  11280. p = c;
  11281. }
  11282. }
  11283. void siftDownDedupTop()
  11284. {
  11285. // same as siftDown(0), except that it also ensures that the top of the heap is not equal to either of its children
  11286. if(activeInputs < 2)
  11287. return;
  11288. unsigned c = 1;
  11289. int childcmp = 1;
  11290. if(activeInputs >= 3)
  11291. {
  11292. childcmp = BuffCompare(2, 1);
  11293. if(childcmp < 0)
  11294. c = 2;
  11295. }
  11296. int cmp = BuffCompare(c, 0);
  11297. if(cmp > 0)
  11298. return;
  11299. // the following loop ensures the correct property holds on the smaller branch, and that childcmp==0 iff the top matches the other branch
  11300. while(cmp <= 0)
  11301. {
  11302. if(cmp == 0)
  11303. {
  11304. if(mergeheap[c] < mergeheap[0])
  11305. {
  11306. unsigned r = mergeheap[c];
  11307. mergeheap[c] = mergeheap[0];
  11308. mergeheap[0] = r;
  11309. }
  11310. ReleaseClearRoxieRow(pending[mergeheap[c]]);
  11311. if(!pullInput(mergeheap[c]))
  11312. if(!promote(c))
  11313. break;
  11314. siftDown(c);
  11315. }
  11316. else
  11317. {
  11318. unsigned r = mergeheap[c];
  11319. mergeheap[c] = mergeheap[0];
  11320. mergeheap[0] = r;
  11321. if(siftDown(c))
  11322. break;
  11323. }
  11324. cmp = BuffCompare(c, 0);
  11325. }
  11326. // the following loop ensures the uniqueness property holds on the other branch too
  11327. c = 3-c;
  11328. if(activeInputs <= c)
  11329. return;
  11330. while(childcmp == 0)
  11331. {
  11332. if(mergeheap[c] < mergeheap[0])
  11333. {
  11334. unsigned r = mergeheap[c];
  11335. mergeheap[c] = mergeheap[0];
  11336. mergeheap[0] = r;
  11337. }
  11338. ReleaseClearRoxieRow(pending[mergeheap[c]]);
  11339. if(!pullInput(mergeheap[c]))
  11340. if(!promote(c))
  11341. break;
  11342. siftDown(c);
  11343. childcmp = BuffCompare(c, 0);
  11344. }
  11345. }
  11346. inline int BuffCompare(unsigned a, unsigned b)
  11347. {
  11348. return compare->docompare(pending[mergeheap[a]], pending[mergeheap[b]]);
  11349. }
  11350. public:
  11351. CRoxieServerMergeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  11352. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorMergeArg &)basehelper), numInputs(_numInputs)
  11353. {
  11354. activeInputs = 0;
  11355. first = true;
  11356. mergeheap = new unsigned[numInputs];
  11357. inputArray = new IRoxieInput*[numInputs];
  11358. pending = new const void *[numInputs];
  11359. compare = helper.queryCompare();
  11360. dedup = helper.dedup();
  11361. for (unsigned i = 0; i < numInputs; i++)
  11362. {
  11363. inputArray[i] = NULL;
  11364. pending[i] = NULL;
  11365. }
  11366. }
  11367. ~CRoxieServerMergeActivity()
  11368. {
  11369. delete [] mergeheap;
  11370. delete [] inputArray;
  11371. delete [] pending;
  11372. }
  11373. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11374. {
  11375. activeInputs = 0;
  11376. first = true;
  11377. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  11378. for (unsigned i = 0; i < numInputs; i++)
  11379. {
  11380. inputArray[i]->start(parentExtractSize, parentExtract, paused);
  11381. }
  11382. }
  11383. virtual void stop(bool aborting)
  11384. {
  11385. for (unsigned i = 0; i < numInputs; i++)
  11386. {
  11387. inputArray[i]->stop(aborting);
  11388. }
  11389. CRoxieServerActivity::stop(aborting);
  11390. }
  11391. virtual void reset()
  11392. {
  11393. for (unsigned i = 0; i < numInputs; i++)
  11394. {
  11395. ReleaseClearRoxieRow(pending[i]);
  11396. inputArray[i]->reset();
  11397. }
  11398. CRoxieServerActivity::reset();
  11399. }
  11400. virtual void setInput(unsigned idx, IRoxieInput *_in)
  11401. {
  11402. inputArray[idx] = _in;
  11403. }
  11404. virtual const void * nextInGroup()
  11405. {
  11406. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  11407. if (first)
  11408. {
  11409. permute();
  11410. first = false;
  11411. }
  11412. if (activeInputs)
  11413. {
  11414. const void *next = pending[mergeheap[0]];
  11415. readNext();
  11416. if (next)
  11417. processed++;
  11418. return next;
  11419. }
  11420. else
  11421. return NULL;
  11422. }
  11423. };
  11424. class CRoxieServerMergeActivityFactory : public CRoxieServerMultiInputFactory
  11425. {
  11426. public:
  11427. CRoxieServerMergeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11428. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  11429. {
  11430. }
  11431. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  11432. {
  11433. return new CRoxieServerMergeActivity(this, _probeManager, numInputs());
  11434. }
  11435. };
  11436. IRoxieServerActivityFactory *createRoxieServerMergeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11437. {
  11438. return new CRoxieServerMergeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  11439. }
  11440. //=================================================================================
  11441. class CRoxieServerRegroupActivity : public CRoxieServerMultiInputActivity
  11442. {
  11443. IHThorRegroupArg &helper;
  11444. unsigned inputIndex;
  11445. bool eof;
  11446. unsigned __int64 numProcessedLastGroup;
  11447. public:
  11448. CRoxieServerRegroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  11449. : CRoxieServerMultiInputActivity(_factory, _probeManager, _numInputs), helper((IHThorRegroupArg &)basehelper)
  11450. {
  11451. inputIndex = 0;
  11452. eof = false;
  11453. numProcessedLastGroup = 0;
  11454. }
  11455. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11456. {
  11457. inputIndex = 0;
  11458. eof = false;
  11459. numProcessedLastGroup = processed;
  11460. CRoxieServerMultiInputActivity::start(parentExtractSize, parentExtract, paused);
  11461. }
  11462. const void * nextFromInputs()
  11463. {
  11464. unsigned initialInput = inputIndex;
  11465. while (inputIndex < numInputs)
  11466. {
  11467. const void * next = inputArray[inputIndex]->nextInGroup();
  11468. if (next)
  11469. {
  11470. if ((inputIndex != initialInput) && (inputIndex != initialInput+1))
  11471. {
  11472. ReleaseRoxieRow(next);
  11473. throw MakeStringException(ROXIE_MISMATCH_GROUP_ERROR, "Mismatched groups supplied to Regroup (%d)", factory->queryId());
  11474. }
  11475. return next;
  11476. }
  11477. inputIndex++;
  11478. }
  11479. if ((initialInput != 0) && (initialInput+1 != numInputs))
  11480. throw MakeStringException(ROXIE_MISMATCH_GROUP_ERROR, "Mismatched groups supplied to Regroup (%d)", factory->queryId());
  11481. inputIndex = 0;
  11482. return NULL;
  11483. }
  11484. virtual const void * nextInGroup()
  11485. {
  11486. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  11487. if (eof)
  11488. return NULL;
  11489. const void * ret = nextFromInputs();
  11490. if (ret)
  11491. {
  11492. processed++;
  11493. return ret;
  11494. }
  11495. if (numProcessedLastGroup != processed)
  11496. {
  11497. numProcessedLastGroup = processed;
  11498. return NULL;
  11499. }
  11500. eof = true;
  11501. return NULL;
  11502. }
  11503. #if 0
  11504. virtual void setInput(unsigned idx, IRoxieInput *_in)
  11505. {
  11506. //MORE: RKC: Do we want to do this i) always ii) conditionally iii) never
  11507. if (idx)
  11508. {
  11509. puller.setown(new CRoxieServerReadAheadInput(0)); // MORE - cant ask context for parallelJoinPreload as context is not yet set up.
  11510. puller->setInput(0, _in);
  11511. CRoxieServerMultiInputActivity::setInput(idx, puller);
  11512. }
  11513. else
  11514. CRoxieServerMultiInputActivity::setInput(idx, _in);
  11515. }
  11516. #endif
  11517. };
  11518. class CRoxieServerRegroupActivityFactory : public CRoxieServerMultiInputFactory
  11519. {
  11520. public:
  11521. CRoxieServerRegroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11522. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  11523. {
  11524. }
  11525. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  11526. {
  11527. return new CRoxieServerRegroupActivity(this, _probeManager, numInputs());
  11528. }
  11529. };
  11530. IRoxieServerActivityFactory *createRoxieServerRegroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11531. {
  11532. return new CRoxieServerRegroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  11533. }
  11534. //=================================================================================
  11535. class CRoxieServerCombineActivity : public CRoxieServerMultiInputActivity
  11536. {
  11537. IHThorCombineArg &helper;
  11538. unsigned __int64 numProcessedLastGroup;
  11539. public:
  11540. CRoxieServerCombineActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  11541. : CRoxieServerMultiInputActivity(_factory, _probeManager, _numInputs), helper((IHThorCombineArg &)basehelper)
  11542. {
  11543. numProcessedLastGroup = 0;
  11544. }
  11545. ~CRoxieServerCombineActivity()
  11546. {
  11547. }
  11548. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11549. {
  11550. numProcessedLastGroup = processed;
  11551. CRoxieServerMultiInputActivity::start(parentExtractSize, parentExtract, paused);
  11552. }
  11553. void nextInputs(ConstPointerArray & out)
  11554. {
  11555. for (unsigned i=0; i < numInputs; i++)
  11556. {
  11557. const void * next = inputArray[i]->nextInGroup();
  11558. if (next)
  11559. out.append(next);
  11560. }
  11561. }
  11562. virtual bool needsAllocator() const { return true; }
  11563. virtual const void * nextInGroup()
  11564. {
  11565. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  11566. loop
  11567. {
  11568. ConstPointerArray group;
  11569. nextInputs(group);
  11570. if ((group.ordinality() == 0) && (numProcessedLastGroup == processed))
  11571. nextInputs(group);
  11572. if (group.ordinality() == 0)
  11573. {
  11574. numProcessedLastGroup = processed;
  11575. return NULL;
  11576. }
  11577. else if (group.ordinality() != numInputs)
  11578. {
  11579. ReleaseRoxieRowSet(group);
  11580. throw MakeStringException(ROXIE_MISMATCH_GROUP_ERROR, "Mismatched group input for Combine Activity(%d)", factory->queryId());
  11581. }
  11582. try
  11583. {
  11584. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  11585. size32_t outSize = helper.transform(rowBuilder, group.ordinality(), group.getArray());
  11586. ReleaseRoxieRowSet(group);
  11587. if (outSize)
  11588. {
  11589. processed++;
  11590. return rowBuilder.finalizeRowClear(outSize);
  11591. }
  11592. }
  11593. catch (IException *E)
  11594. {
  11595. ReleaseRoxieRowSet(group);
  11596. throw makeWrappedException(E);
  11597. }
  11598. }
  11599. }
  11600. };
  11601. class CRoxieServerCombineActivityFactory : public CRoxieServerMultiInputFactory
  11602. {
  11603. public:
  11604. CRoxieServerCombineActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11605. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  11606. {
  11607. }
  11608. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  11609. {
  11610. return new CRoxieServerCombineActivity(this, _probeManager, numInputs());
  11611. }
  11612. };
  11613. IRoxieServerActivityFactory *createRoxieServerCombineActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11614. {
  11615. return new CRoxieServerCombineActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  11616. }
  11617. //=================================================================================
  11618. class CRoxieServerCombineGroupActivity : public CRoxieServerTwoInputActivity
  11619. {
  11620. IHThorCombineGroupArg &helper;
  11621. unsigned __int64 numProcessedLastGroup;
  11622. public:
  11623. CRoxieServerCombineGroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  11624. : CRoxieServerTwoInputActivity(_factory, _probeManager), helper((IHThorCombineGroupArg &)basehelper)
  11625. {
  11626. numProcessedLastGroup = 0;
  11627. }
  11628. ~CRoxieServerCombineGroupActivity()
  11629. {
  11630. }
  11631. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11632. {
  11633. numProcessedLastGroup = processed;
  11634. CRoxieServerTwoInputActivity::start(parentExtractSize, parentExtract, paused);
  11635. }
  11636. virtual void setInput(unsigned idx, IRoxieInput *_in)
  11637. {
  11638. switch(idx)
  11639. {
  11640. case 0:
  11641. #if 0
  11642. //MORE: RKC: Do we want to do this i) always ii) conditionally iii) never
  11643. puller.setown(new CRoxieServerReadAheadInput(0)); // MORE - cant ask context for parallelJoinPreload as context is not yet set up.
  11644. puller->setInput(0, _in);
  11645. _in = puller;
  11646. #endif
  11647. input = _in;
  11648. break;
  11649. case 1:
  11650. input1 = _in;
  11651. break;
  11652. default:
  11653. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  11654. }
  11655. }
  11656. virtual IRoxieInput *queryOutput(unsigned idx)
  11657. {
  11658. if (idx==(unsigned)-1)
  11659. idx = 0;
  11660. return idx ? NULL : this;
  11661. }
  11662. virtual bool needsAllocator() const { return true; }
  11663. virtual const void * nextInGroup()
  11664. {
  11665. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  11666. loop
  11667. {
  11668. const void * left = input->nextInGroup();
  11669. if (!left && (numProcessedLastGroup == processed))
  11670. left = input->nextInGroup();
  11671. if (!left)
  11672. {
  11673. if (numProcessedLastGroup == processed)
  11674. {
  11675. const void * nextRight = input1->nextInGroup();
  11676. if (nextRight)
  11677. {
  11678. ReleaseRoxieRow(nextRight);
  11679. throw MakeStringException(ROXIE_MISSING_GROUP_ERROR, "Missing LEFT record for Combine Group (%d)", factory->queryId());
  11680. }
  11681. }
  11682. else
  11683. numProcessedLastGroup = processed;
  11684. return NULL;
  11685. }
  11686. ConstPointerArray group;
  11687. loop
  11688. {
  11689. const void * in = input1->nextInGroup();
  11690. if (!in)
  11691. break;
  11692. group.append(in);
  11693. }
  11694. if (group.ordinality() == 0)
  11695. {
  11696. ReleaseRoxieRow(left);
  11697. ReleaseRoxieRowSet(group);
  11698. throw MakeStringException(ROXIE_MISSING_GROUP_ERROR, "Missing RIGHT group for Combine Group (%d)", factory->queryId());
  11699. }
  11700. try
  11701. {
  11702. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  11703. size32_t outSize = helper.transform(rowBuilder, left, group.ordinality(), (const void * *)group.getArray());
  11704. ReleaseRoxieRow(left);
  11705. ReleaseRoxieRowSet(group);
  11706. if (outSize)
  11707. {
  11708. processed++;
  11709. return rowBuilder.finalizeRowClear(outSize);
  11710. }
  11711. }
  11712. catch (IException *E)
  11713. {
  11714. ReleaseRoxieRow(left);
  11715. ReleaseRoxieRowSet(group);
  11716. throw makeWrappedException(E);
  11717. }
  11718. }
  11719. }
  11720. };
  11721. class CRoxieServerCombineGroupActivityFactory : public CRoxieServerActivityFactory
  11722. {
  11723. unsigned input2;
  11724. unsigned input2idx;
  11725. public:
  11726. CRoxieServerCombineGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11727. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  11728. {
  11729. input2 = 0;
  11730. input2idx = 0;
  11731. }
  11732. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  11733. {
  11734. return new CRoxieServerCombineGroupActivity(this, _probeManager);
  11735. }
  11736. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  11737. {
  11738. if (idx==1)
  11739. {
  11740. input2 = source;
  11741. input2idx = sourceidx;
  11742. }
  11743. else
  11744. CRoxieServerActivityFactory::setInput(idx, source, sourceidx);
  11745. }
  11746. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  11747. {
  11748. switch (idx)
  11749. {
  11750. case 1:
  11751. sourceidx = input2idx;
  11752. return input2;
  11753. case 0:
  11754. return CRoxieServerActivityFactory::getInput(idx, sourceidx);
  11755. default:
  11756. return (unsigned) -1;
  11757. }
  11758. }
  11759. };
  11760. IRoxieServerActivityFactory *createRoxieServerCombineGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11761. {
  11762. return new CRoxieServerCombineGroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  11763. }
  11764. //=================================================================================
  11765. class CRoxieServerRollupGroupActivity : public CRoxieServerActivity
  11766. {
  11767. IHThorRollupGroupArg &helper;
  11768. bool eof;
  11769. public:
  11770. CRoxieServerRollupGroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  11771. : CRoxieServerActivity(_factory, _probeManager),
  11772. helper((IHThorRollupGroupArg &)basehelper)
  11773. {
  11774. eof = false;
  11775. }
  11776. ~CRoxieServerRollupGroupActivity()
  11777. {
  11778. }
  11779. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11780. {
  11781. eof = false;
  11782. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  11783. }
  11784. virtual bool needsAllocator() const { return true; }
  11785. virtual const void * nextInGroup()
  11786. {
  11787. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  11788. if (eof)
  11789. return NULL;
  11790. loop
  11791. {
  11792. ConstPointerArray group;
  11793. loop
  11794. {
  11795. const void * in = input->nextInGroup();
  11796. if (!in)
  11797. break;
  11798. group.append(in);
  11799. }
  11800. if (group.ordinality() == 0)
  11801. {
  11802. eof = true;
  11803. return NULL;
  11804. }
  11805. try
  11806. {
  11807. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  11808. size32_t outSize = helper.transform(rowBuilder, group.ordinality(), (const void * *)group.getArray());
  11809. ReleaseRoxieRowSet(group);
  11810. if (outSize)
  11811. {
  11812. processed++;
  11813. return rowBuilder.finalizeRowClear(outSize);
  11814. }
  11815. }
  11816. catch (IException * E)
  11817. {
  11818. ReleaseRoxieRowSet(group);
  11819. throw makeWrappedException(E);
  11820. }
  11821. }
  11822. }
  11823. };
  11824. class CRoxieServerRollupGroupActivityFactory : public CRoxieServerActivityFactory
  11825. {
  11826. public:
  11827. CRoxieServerRollupGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11828. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  11829. {
  11830. }
  11831. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  11832. {
  11833. return new CRoxieServerRollupGroupActivity(this, _probeManager);
  11834. }
  11835. };
  11836. IRoxieServerActivityFactory *createRoxieServerRollupGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11837. {
  11838. return new CRoxieServerRollupGroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  11839. }
  11840. //=================================================================================
  11841. class CRoxieServerFilterProjectActivity : public CRoxieServerLateStartActivity
  11842. {
  11843. IHThorFilterProjectArg &helper;
  11844. unsigned numProcessedLastGroup;
  11845. unsigned __int64 recordCount;
  11846. public:
  11847. CRoxieServerFilterProjectActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  11848. : CRoxieServerLateStartActivity(_factory, _probeManager), helper((IHThorFilterProjectArg &)basehelper)
  11849. {
  11850. numProcessedLastGroup = 0;
  11851. recordCount = 0;
  11852. }
  11853. ~CRoxieServerFilterProjectActivity()
  11854. {
  11855. }
  11856. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11857. {
  11858. numProcessedLastGroup = 0;
  11859. recordCount = 0;
  11860. CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
  11861. lateStart(parentExtractSize, parentExtract, helper.canMatchAny()); //sets eof
  11862. }
  11863. virtual bool needsAllocator() const { return true; }
  11864. virtual const void * nextInGroup()
  11865. {
  11866. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  11867. if (eof)
  11868. return NULL;
  11869. loop
  11870. {
  11871. const void * in = input->nextInGroup();
  11872. if (!in)
  11873. {
  11874. recordCount = 0;
  11875. if (numProcessedLastGroup == processed)
  11876. in = input->nextInGroup();
  11877. if (!in)
  11878. {
  11879. numProcessedLastGroup = processed;
  11880. return NULL;
  11881. }
  11882. }
  11883. try
  11884. {
  11885. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  11886. size32_t outSize = helper.transform(rowBuilder, in, ++recordCount);
  11887. ReleaseRoxieRow(in);
  11888. if (outSize)
  11889. {
  11890. processed++;
  11891. return rowBuilder.finalizeRowClear(outSize);
  11892. }
  11893. }
  11894. catch (IException *E)
  11895. {
  11896. throw makeWrappedException(E);
  11897. }
  11898. }
  11899. }
  11900. };
  11901. class CRoxieServerFilterProjectActivityFactory : public CRoxieServerActivityFactory
  11902. {
  11903. public:
  11904. CRoxieServerFilterProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11905. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  11906. {
  11907. }
  11908. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  11909. {
  11910. return new CRoxieServerFilterProjectActivity(this, _probeManager);
  11911. }
  11912. };
  11913. IRoxieServerActivityFactory *createRoxieServerFilterProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11914. {
  11915. return new CRoxieServerFilterProjectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  11916. }
  11917. //=================================================================================
  11918. class CRoxieServerProjectActivity : public CRoxieServerActivity
  11919. {
  11920. unsigned numProcessedLastGroup;
  11921. bool count;
  11922. unsigned __int64 recordCount;
  11923. public:
  11924. CRoxieServerProjectActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _count)
  11925. : CRoxieServerActivity(_factory, _probeManager),
  11926. count(_count)
  11927. {
  11928. numProcessedLastGroup = 0;
  11929. recordCount = 0;
  11930. }
  11931. ~CRoxieServerProjectActivity()
  11932. {
  11933. }
  11934. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  11935. {
  11936. numProcessedLastGroup = 0;
  11937. recordCount = 0;
  11938. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  11939. }
  11940. virtual bool needsAllocator() const { return true; }
  11941. virtual const void * nextInGroup()
  11942. {
  11943. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  11944. loop
  11945. {
  11946. const void * in = input->nextInGroup();
  11947. if (!in)
  11948. {
  11949. recordCount = 0;
  11950. if (numProcessedLastGroup == processed)
  11951. in = input->nextInGroup();
  11952. if (!in)
  11953. {
  11954. numProcessedLastGroup = processed;
  11955. return NULL;
  11956. }
  11957. }
  11958. try
  11959. {
  11960. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  11961. size32_t outSize;
  11962. if (count)
  11963. outSize = ((IHThorCountProjectArg &) basehelper).transform(rowBuilder, in, ++recordCount);
  11964. else
  11965. outSize = ((IHThorProjectArg &) basehelper).transform(rowBuilder, in);
  11966. ReleaseRoxieRow(in);
  11967. if (outSize)
  11968. {
  11969. processed++;
  11970. return rowBuilder.finalizeRowClear(outSize);
  11971. }
  11972. }
  11973. catch (IException *E)
  11974. {
  11975. throw makeWrappedException(E);
  11976. }
  11977. }
  11978. }
  11979. };
  11980. class CRoxieServerProjectActivityFactory : public CRoxieServerActivityFactory
  11981. {
  11982. protected:
  11983. bool count;
  11984. public:
  11985. CRoxieServerProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11986. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  11987. {
  11988. count = (_kind==TAKcountproject || _kind==TAKprefetchcountproject);
  11989. }
  11990. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  11991. {
  11992. return new CRoxieServerProjectActivity(this, _probeManager, count);
  11993. }
  11994. };
  11995. IRoxieServerActivityFactory *createRoxieServerProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  11996. {
  11997. return new CRoxieServerProjectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  11998. }
  11999. //=================================================================================
  12000. class CRoxieServerPrefetchProjectActivity : public CRoxieServerActivity, implements IRecordPullerCallback
  12001. {
  12002. unsigned numProcessedLastGroup;
  12003. bool count;
  12004. bool eof;
  12005. bool allPulled;
  12006. bool isThreaded;
  12007. unsigned preload;
  12008. unsigned __int64 recordCount;
  12009. IHThorPrefetchProjectArg &helper;
  12010. RecordPullerThread puller;
  12011. InterruptableSemaphore ready;
  12012. InterruptableSemaphore space;
  12013. class PrefetchInfo : public CInterface
  12014. {
  12015. public:
  12016. inline PrefetchInfo(IHThorPrefetchProjectArg &helper, const void *_in, unsigned __int64 _recordCount)
  12017. {
  12018. if (helper.preTransform(extract, _in, _recordCount))
  12019. {
  12020. in.setown(_in);
  12021. recordCount = _recordCount;
  12022. }
  12023. else
  12024. ReleaseRoxieRow(_in);
  12025. }
  12026. OwnedConstRoxieRow in;
  12027. unsigned __int64 recordCount;
  12028. rtlRowBuilder extract;
  12029. };
  12030. QueueOf<PrefetchInfo, true> pulled;
  12031. CriticalSection pulledCrit;
  12032. public:
  12033. CRoxieServerPrefetchProjectActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _count)
  12034. : CRoxieServerActivity(_factory, _probeManager),
  12035. helper((IHThorPrefetchProjectArg &) basehelper),
  12036. puller(false),
  12037. count(_count)
  12038. {
  12039. numProcessedLastGroup = 0;
  12040. recordCount = 0;
  12041. eof = false;
  12042. allPulled = false;
  12043. isThreaded = (helper.getFlags() & PPFparallel) != 0;
  12044. preload = 0;
  12045. }
  12046. ~CRoxieServerPrefetchProjectActivity()
  12047. {
  12048. while (pulled.ordinality())
  12049. ::Release(pulled.dequeue());
  12050. }
  12051. virtual void setInput(unsigned idx, IRoxieInput *_in)
  12052. {
  12053. if (idx)
  12054. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  12055. puller.setInput(this, _in);
  12056. }
  12057. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12058. {
  12059. numProcessedLastGroup = 0;
  12060. recordCount = 0;
  12061. eof = false;
  12062. allPulled = false;
  12063. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  12064. preload = helper.getLookahead();
  12065. if (!preload)
  12066. preload = ctx->prefetchProjectPreload();
  12067. space.reinit(preload);
  12068. ready.reinit();
  12069. puller.start(parentExtractSize, parentExtract, paused, preload, !isThreaded, ctx);
  12070. }
  12071. virtual void stop(bool aborting)
  12072. {
  12073. space.interrupt();
  12074. ready.interrupt();
  12075. CRoxieServerActivity::stop(aborting);
  12076. puller.stop(aborting);
  12077. }
  12078. virtual void reset()
  12079. {
  12080. CRoxieServerActivity::reset();
  12081. puller.reset();
  12082. allPulled = false;
  12083. while (pulled.ordinality())
  12084. ::Release(pulled.dequeue());
  12085. }
  12086. virtual PrefetchInfo *readNextRecord()
  12087. {
  12088. if (!isThreaded)
  12089. {
  12090. if (!allPulled) // This looks like it's thread unsafe but we are inside the if(!isThreaded) so should be ok
  12091. puller.pullRecords(1);
  12092. }
  12093. else
  12094. ready.wait();
  12095. CriticalBlock b(pulledCrit);
  12096. PrefetchInfo *ret = pulled.ordinality() ? pulled.dequeue() : NULL;
  12097. space.signal();
  12098. return ret;
  12099. }
  12100. virtual bool needsAllocator() const { return true; }
  12101. virtual const void * nextInGroup()
  12102. {
  12103. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  12104. if (eof)
  12105. return NULL;
  12106. loop
  12107. {
  12108. Owned<PrefetchInfo> in = readNextRecord();
  12109. if (!in)
  12110. {
  12111. recordCount = 0;
  12112. if (numProcessedLastGroup == processed)
  12113. in.setown(readNextRecord());
  12114. if (!in)
  12115. {
  12116. numProcessedLastGroup = processed;
  12117. eof = true;
  12118. return NULL;
  12119. }
  12120. }
  12121. try
  12122. {
  12123. if (in->in)
  12124. {
  12125. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  12126. size32_t outSize;
  12127. IThorChildGraph *child = helper.queryChild();
  12128. Owned<IEclGraphResults> results;
  12129. if (child)
  12130. results.setown(child->evaluate(in->extract.size(), in->extract.getbytes()));
  12131. outSize = helper.transform(rowBuilder, in->in, results, in->recordCount);
  12132. if (outSize)
  12133. {
  12134. processed++;
  12135. return rowBuilder.finalizeRowClear(outSize);
  12136. }
  12137. }
  12138. }
  12139. catch (IException *E)
  12140. {
  12141. throw makeWrappedException(E);
  12142. }
  12143. }
  12144. }
  12145. // interface IExceptionHandler
  12146. virtual bool fireException(IException *e)
  12147. {
  12148. // called from puller thread on failure
  12149. ready.interrupt(LINK(e));
  12150. space.interrupt(e);
  12151. return true;
  12152. }
  12153. // interface IRecordPullerCallback
  12154. virtual void processRow(const void *row)
  12155. {
  12156. {
  12157. CriticalBlock b(pulledCrit);
  12158. pulled.enqueue(new PrefetchInfo(helper, row, ++recordCount));
  12159. }
  12160. if (isThreaded)
  12161. {
  12162. ready.signal();
  12163. space.wait();
  12164. }
  12165. }
  12166. virtual void processEOG()
  12167. {
  12168. {
  12169. CriticalBlock b(pulledCrit);
  12170. pulled.enqueue(NULL);
  12171. }
  12172. if (isThreaded)
  12173. {
  12174. ready.signal();
  12175. space.wait();
  12176. }
  12177. }
  12178. virtual void processGroup(const ConstPointerArray &rows)
  12179. {
  12180. throwUnexpected();
  12181. }
  12182. virtual void processDone()
  12183. {
  12184. CriticalBlock b(pulledCrit);
  12185. allPulled = true;
  12186. if (isThreaded)
  12187. ready.signal();
  12188. }
  12189. };
  12190. class CRoxieServerPrefetchProjectActivityFactory : public CRoxieServerProjectActivityFactory
  12191. {
  12192. public:
  12193. CRoxieServerPrefetchProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  12194. : CRoxieServerProjectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  12195. {
  12196. }
  12197. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  12198. {
  12199. return new CRoxieServerPrefetchProjectActivity(this, _probeManager, count);
  12200. }
  12201. };
  12202. extern IRoxieServerActivityFactory *createRoxieServerPrefetchProjectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  12203. {
  12204. return new CRoxieServerPrefetchProjectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  12205. }
  12206. //=================================================================================
  12207. class CPointerArrayRoxieInput : public CPseudoRoxieInput
  12208. {
  12209. public:
  12210. CPointerArrayRoxieInput()
  12211. {
  12212. array = NULL;
  12213. curRow = 0;
  12214. }
  12215. void init(ConstPointerArray * _array)
  12216. {
  12217. array = _array;
  12218. curRow = 0;
  12219. }
  12220. virtual const void * nextInGroup()
  12221. {
  12222. if (array->isItem(curRow))
  12223. {
  12224. const void * ret = array->item(curRow);
  12225. array->replace(NULL, curRow);
  12226. curRow++;
  12227. return ret;
  12228. }
  12229. return NULL;
  12230. }
  12231. protected:
  12232. ConstPointerArray * array;
  12233. unsigned curRow;
  12234. };
  12235. class CRoxieServerLoopActivity : public CRoxieServerActivity
  12236. {
  12237. protected:
  12238. IHThorLoopArg &helper;
  12239. ThorActivityKind activityKind;
  12240. unsigned maxIterations;
  12241. bool finishedLooping;
  12242. unsigned flags;
  12243. bool eof;
  12244. rtlRowBuilder loopExtractBuilder;
  12245. unsigned loopGraphId;
  12246. Linked<IOutputMetaData> counterMeta;
  12247. public:
  12248. CRoxieServerLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _loopGraphId, IOutputMetaData * _counterMeta)
  12249. : CRoxieServerActivity(_factory, _probeManager),
  12250. helper((IHThorLoopArg &)basehelper), loopGraphId(_loopGraphId), counterMeta(_counterMeta)
  12251. {
  12252. eof = false;
  12253. finishedLooping = false;
  12254. activityKind = factory->getKind();
  12255. flags = helper.getFlags();
  12256. maxIterations = 0;
  12257. }
  12258. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12259. {
  12260. eof = false;
  12261. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  12262. int iterations = (int) helper.numIterations();
  12263. maxIterations = (iterations >= 0) ? iterations : 0;
  12264. finishedLooping = ((activityKind == TAKloopcount) && (maxIterations == 0));
  12265. if ((flags & IHThorLoopArg::LFnewloopagain) && !helper.loopFirstTime())
  12266. finishedLooping = true;
  12267. loopExtractBuilder.clear();
  12268. helper.createParentExtract(loopExtractBuilder); // could possibly delay this until execution actually happens
  12269. }
  12270. virtual void stop(bool aborting)
  12271. {
  12272. CRoxieServerActivity::stop(aborting);
  12273. loopExtractBuilder.clear();
  12274. }
  12275. void createCounterResult(IRoxieServerChildGraph * graph, unsigned counter)
  12276. {
  12277. if (flags & IHThorLoopArg::LFcounter)
  12278. {
  12279. void * counterRow = ctx->queryRowManager().allocate(sizeof(thor_loop_counter_t), activityId);
  12280. *((thor_loop_counter_t *)counterRow) = counter;
  12281. Owned<IGraphResult> counterResult = new CGraphResult(ctx->queryCodeContext()->getRowAllocator(counterMeta, activityId), counterRow, true);
  12282. graph->setInputResult(2, counterResult);
  12283. }
  12284. }
  12285. };
  12286. //=================================================================================
  12287. class CRoxieServerSequentialLoopActivity : public CRoxieServerLoopActivity
  12288. {
  12289. Owned<IActivityGraph> loopQuery;
  12290. Owned<IRoxieServerChildGraph> loopGraph;
  12291. IRoxieInput * curInput;
  12292. ConstPointerArray loopPending;
  12293. CPointerArrayRoxieInput arrayInput;
  12294. Linked<IRoxieInput> resultInput;
  12295. unsigned loopCounter;
  12296. public:
  12297. CRoxieServerSequentialLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _loopGraphId, IOutputMetaData * _counterMeta)
  12298. : CRoxieServerLoopActivity(_factory, _probeManager, _loopGraphId, _counterMeta)
  12299. {
  12300. curInput = NULL;
  12301. loopCounter = 0;
  12302. }
  12303. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  12304. {
  12305. CRoxieServerLoopActivity::onCreate(_ctx, _colocalParent);
  12306. loopQuery.set(_ctx->queryChildGraph(loopGraphId));
  12307. }
  12308. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12309. {
  12310. curInput = input;
  12311. loopCounter = 1;
  12312. CRoxieServerLoopActivity::start(parentExtractSize, parentExtract, paused);
  12313. //MORE: Not sure about this, should IRoxieServerChildGraph be combined with IActivityGraph?
  12314. loopGraph.set(loopQuery->queryLoopGraph());
  12315. }
  12316. virtual void stop(bool aborting)
  12317. {
  12318. ReleaseRoxieRowSet(loopPending);
  12319. CRoxieServerLoopActivity::stop(aborting);
  12320. }
  12321. virtual const void * nextInGroup()
  12322. {
  12323. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  12324. if (eof)
  12325. return NULL;
  12326. unsigned emptyIterations = 0;
  12327. loop
  12328. {
  12329. loop
  12330. {
  12331. const void * ret = curInput->nextInGroup();
  12332. if (!ret)
  12333. {
  12334. ret = curInput->nextInGroup(); // more cope with groups somehow....
  12335. if (!ret)
  12336. {
  12337. if (finishedLooping)
  12338. {
  12339. eof = true;
  12340. return NULL;
  12341. }
  12342. break;
  12343. }
  12344. }
  12345. if (finishedLooping ||
  12346. ((flags & IHThorLoopArg::LFfiltered) && !helper.sendToLoop(loopCounter, ret)))
  12347. {
  12348. processed++;
  12349. return ret;
  12350. }
  12351. loopPending.append(ret);
  12352. }
  12353. switch (activityKind)
  12354. {
  12355. case TAKloopdataset:
  12356. {
  12357. if (!(flags & IHThorLoopArg::LFnewloopagain))
  12358. {
  12359. if (!helper.loopAgain(loopCounter, loopPending.ordinality(), (const void * *)loopPending.getArray()))
  12360. {
  12361. if (loopPending.ordinality() == 0)
  12362. {
  12363. eof = true;
  12364. return NULL;
  12365. }
  12366. arrayInput.init(&loopPending);
  12367. curInput = &arrayInput;
  12368. finishedLooping = true;
  12369. continue; // back to the input loop again
  12370. }
  12371. }
  12372. break;
  12373. }
  12374. case TAKlooprow:
  12375. if (loopPending.empty())
  12376. {
  12377. finishedLooping = true;
  12378. eof = true;
  12379. return NULL;
  12380. }
  12381. break;
  12382. }
  12383. if (loopPending.ordinality())
  12384. emptyIterations = 0;
  12385. else
  12386. {
  12387. //note: any outputs which didn't go around the loop again, would return the record, reinitializing emptyIterations
  12388. emptyIterations++;
  12389. if (emptyIterations > maxEmptyLoopIterations)
  12390. throw MakeStringException(ROXIE_TOO_MANY_EMPTY_LOOP, "Executed LOOP with empty input and output %u times", emptyIterations);
  12391. if (emptyIterations % 32 == 0)
  12392. CTXLOG("Executing LOOP with empty input and output %u times", emptyIterations);
  12393. }
  12394. checkAbort();
  12395. try
  12396. {
  12397. Owned<IRoxieGraphResults> results = executeIteration(loopExtractBuilder.size(), loopExtractBuilder.getbytes(), loopCounter, loopPending);
  12398. resultInput.setown(results->createIterator(0));
  12399. if (flags & IHThorLoopArg::LFnewloopagain)
  12400. {
  12401. Owned<IRoxieInput> againResult = results->createIterator(helper.loopAgainResult());
  12402. OwnedConstRoxieRow row = againResult->nextInGroup();
  12403. assertex(row);
  12404. //Result is a row which contains a single boolean field.
  12405. if (!((const bool *)row.get())[0])
  12406. finishedLooping = true;
  12407. }
  12408. }
  12409. catch (IException *E)
  12410. {
  12411. throw makeWrappedException(E);
  12412. }
  12413. curInput = resultInput.get();
  12414. loopCounter++;
  12415. if ((activityKind == TAKloopcount) && (loopCounter > maxIterations))
  12416. finishedLooping = true;
  12417. }
  12418. }
  12419. IRoxieGraphResults * executeIteration(unsigned parentExtractSize, const byte *parentExtract, unsigned counter, ConstPointerArray & rows)
  12420. {
  12421. try
  12422. {
  12423. loopGraph->beforeExecute();
  12424. Owned<IGraphResult> inputRowsResult = new CGraphResult(ctx->queryCodeContext()->getRowAllocator(meta.queryOriginal(), activityId), rows, true);
  12425. loopGraph->setInputResult(1, inputRowsResult);
  12426. createCounterResult(loopGraph, counter);
  12427. Owned<IRoxieGraphResults> ret = loopGraph->execute(parentExtractSize, parentExtract);
  12428. loopGraph->afterExecute();
  12429. return ret.getClear();
  12430. }
  12431. catch (...)
  12432. {
  12433. CTXLOG("Exception thrown in loop body - cleaning up");
  12434. loopGraph->afterExecute();
  12435. throw;
  12436. }
  12437. }
  12438. };
  12439. //=================================================================================
  12440. typedef SafeQueueOf<const void, true> SafeRowQueue;
  12441. typedef SimpleInterThreadQueueOf<const void, true> InterThreadRowQueue;
  12442. class CRowQueuePseudoInput : public CPseudoRoxieInput
  12443. {
  12444. public:
  12445. CRowQueuePseudoInput(SafeRowQueue & _input) :
  12446. input(_input)
  12447. {
  12448. eof = false;
  12449. }
  12450. virtual const void * nextInGroup()
  12451. {
  12452. if (eof)
  12453. return NULL;
  12454. const void * ret = input.dequeue();
  12455. if (!ret)
  12456. eof = true;
  12457. return ret;
  12458. }
  12459. protected:
  12460. SafeRowQueue & input;
  12461. bool eof;
  12462. };
  12463. class CRoxieServerParallelLoopActivity;
  12464. class LoopFilterPseudoInput : public CIndirectRoxieInput
  12465. {
  12466. public:
  12467. LoopFilterPseudoInput(CRoxieServerParallelLoopActivity * _activity, IRoxieInput * _input, unsigned _counter) :
  12468. CIndirectRoxieInput(_input), activity(_activity), counter(_counter)
  12469. {
  12470. }
  12471. virtual const void * nextInGroup();
  12472. protected:
  12473. CRoxieServerParallelLoopActivity * activity;
  12474. unsigned counter;
  12475. };
  12476. class LoopExecutorThread : public RestartableThread
  12477. {
  12478. protected:
  12479. Owned<IRoxieInput> safeInput;
  12480. CRoxieServerParallelLoopActivity * activity;
  12481. bool eof;
  12482. CriticalSection crit;
  12483. unsigned flags;
  12484. SafeRowQueue tempResults[2];
  12485. unsigned savedParentExtractSize;
  12486. const byte * savedParentExtract;
  12487. IArrayOf<IActivityGraph> cachedGraphs;
  12488. IRoxieSlaveContext *ctx;
  12489. public:
  12490. LoopExecutorThread()
  12491. : RestartableThread("LoopExecutorThread")
  12492. {
  12493. activity = NULL;
  12494. eof = false;
  12495. flags = 0;
  12496. ctx = NULL;
  12497. savedParentExtract = NULL;
  12498. savedParentExtractSize = 0;
  12499. }
  12500. virtual IRoxieInput *queryInput(unsigned idx) const
  12501. {
  12502. return safeInput->queryInput(idx);
  12503. }
  12504. void setInput(CRoxieServerParallelLoopActivity * _activity, IRoxieInput *_input, unsigned _flags)
  12505. {
  12506. activity = _activity;
  12507. flags = _flags;
  12508. // stop is called on our consumer's thread. We need to take care calling stop for our input to make sure it is not in mid-nextInGroup etc etc.
  12509. safeInput.setown(new CSafeRoxieInput(_input));
  12510. }
  12511. IRoxieInput *queryInput() const
  12512. {
  12513. return safeInput;
  12514. }
  12515. void onCreate(IRoxieSlaveContext * _ctx);
  12516. void start(unsigned parentExtractSize, const byte *parentExtract, bool paused);
  12517. void stop(bool aborting);
  12518. void reset();
  12519. virtual int run();
  12520. protected:
  12521. void executeLoop();
  12522. void executeLoopInstance(unsigned counter, unsigned numIterations, IRoxieInput * input, SafeRowQueue * spillOutput);
  12523. IRoxieInput * createLoopIterationGraph(unsigned i, IRoxieInput * input, unsigned counter);
  12524. };
  12525. class CRoxieServerParallelLoopActivity : public CRoxieServerLoopActivity
  12526. {
  12527. friend class LoopFilterPseudoInput;
  12528. friend class LoopExecutorThread;
  12529. QueueOf<const void, true> ready;
  12530. CriticalSection helperCS;
  12531. CriticalSection cs;
  12532. size32_t sizeNumParallel;
  12533. rtlDataAttr listNumParallel;
  12534. unsigned defaultNumParallel;
  12535. LoopExecutorThread executor;
  12536. IProbeManager* probeManager;
  12537. CriticalSection canAccess;
  12538. CriticalSection scrit;
  12539. InterruptableSemaphore readySpace;
  12540. InterruptableSemaphore recordsReady;
  12541. protected:
  12542. bool includeInLoop(unsigned counter, const void * row)
  12543. {
  12544. CriticalBlock b(helperCS);
  12545. return helper.sendToLoop(counter, row);
  12546. }
  12547. public:
  12548. CRoxieServerParallelLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _loopGraphId, IOutputMetaData * _counterMeta)
  12549. : CRoxieServerLoopActivity(_factory, _probeManager, _loopGraphId, _counterMeta),
  12550. readySpace(parallelLoopFlowLimit)
  12551. {
  12552. probeManager = _probeManager;
  12553. defaultNumParallel = 0;
  12554. }
  12555. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  12556. {
  12557. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  12558. executor.onCreate(_ctx);
  12559. }
  12560. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12561. {
  12562. CriticalBlock b(scrit); // can stop while still starting, if unlucky...
  12563. readySpace.reinit(parallelLoopFlowLimit);
  12564. recordsReady.reinit();
  12565. CRoxieServerLoopActivity::start(parentExtractSize, parentExtract, paused);
  12566. defaultNumParallel = helper.defaultParallelIterations();
  12567. if (!defaultNumParallel)
  12568. defaultNumParallel = DEFAULT_PARALLEL_LOOP_THREADS;
  12569. helper.numParallelIterations(sizeNumParallel, listNumParallel.refdata());
  12570. //MORE: If numIterations <= number of parallel iterations[1],
  12571. //then we don't need to create a separate thread to do the processing, and the results will also avoid
  12572. //being transferred via a queue
  12573. executor.start(parentExtractSize, parentExtract, paused);
  12574. }
  12575. virtual void setInput(unsigned idx, IRoxieInput *_in)
  12576. {
  12577. if (idx)
  12578. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  12579. executor.setInput(this, _in, flags);
  12580. }
  12581. virtual void stop(bool aborting)
  12582. {
  12583. CriticalBlock b(scrit); // can stop while still starting, if unlucky...
  12584. readySpace.interrupt();
  12585. recordsReady.interrupt();
  12586. executor.join(); // MORE - may not be needed given stop/reset split
  12587. CRoxieServerLoopActivity::stop(aborting);
  12588. }
  12589. virtual void reset()
  12590. {
  12591. while (ready.ordinality())
  12592. ReleaseRoxieRow(ready.dequeue());
  12593. executor.reset();
  12594. CRoxieServerActivity::reset();
  12595. }
  12596. virtual const void * nextInGroup()
  12597. {
  12598. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  12599. loop
  12600. {
  12601. if (eof)
  12602. return NULL;
  12603. recordsReady.wait();
  12604. CriticalBlock procedure(canAccess);
  12605. if (ready.ordinality())
  12606. {
  12607. const void *result = ready.dequeue();
  12608. readySpace.signal();
  12609. if (result)
  12610. processed++;
  12611. return result;
  12612. }
  12613. else
  12614. eof = true;
  12615. }
  12616. }
  12617. unsigned getNumParallel(unsigned iter)
  12618. {
  12619. if (iter * sizeof(unsigned) >= sizeNumParallel)
  12620. return defaultNumParallel;
  12621. return ((unsigned *)listNumParallel.getdata())[iter];
  12622. }
  12623. inline void enqueueResult(const void * row)
  12624. {
  12625. try
  12626. {
  12627. while(!readySpace.wait(1000))
  12628. {
  12629. CTXLOG("Blocked waiting for space in loop %p activity id: %d output queue: %d records in queue", this, queryId(), ready.ordinality());
  12630. }
  12631. }
  12632. catch (...)
  12633. {
  12634. ReleaseRoxieRow(row);
  12635. throw;
  12636. }
  12637. CriticalBlock b2(canAccess);
  12638. ready.enqueue(row);
  12639. recordsReady.signal();
  12640. }
  12641. inline void finishResults()
  12642. {
  12643. recordsReady.signal();
  12644. }
  12645. virtual bool fireException(IException *e)
  12646. {
  12647. readySpace.interrupt(LINK(e));
  12648. recordsReady.interrupt(e);
  12649. return true;
  12650. }
  12651. IActivityGraph * createChildGraphInstance()
  12652. {
  12653. return factory->createChildGraph(ctx, &helper, loopGraphId, this, probeManager, *this);
  12654. }
  12655. IActivityGraph * queryChildGraph()
  12656. {
  12657. return ctx->queryChildGraph(loopGraphId);
  12658. }
  12659. };
  12660. //=================================================================================
  12661. const void * LoopFilterPseudoInput::nextInGroup()
  12662. {
  12663. loop
  12664. {
  12665. const void * next = input->nextInGroup();
  12666. if (!next || activity->includeInLoop(counter, next))
  12667. return next;
  12668. activity->enqueueResult(next);
  12669. }
  12670. }
  12671. void LoopExecutorThread::onCreate(IRoxieSlaveContext * _ctx)
  12672. {
  12673. //Initialise the cached graph list with the child instance that will always be created. Other iterations will be created on demand.
  12674. ctx = _ctx;
  12675. cachedGraphs.append(*LINK(activity->queryChildGraph()));
  12676. }
  12677. void LoopExecutorThread::start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12678. {
  12679. savedParentExtractSize = parentExtractSize;
  12680. savedParentExtract = parentExtract;
  12681. eof = false;
  12682. StringBuffer logPrefix("[");
  12683. ctx->getLogPrefix(logPrefix).append("] ");
  12684. RestartableThread::start(logPrefix);
  12685. }
  12686. int LoopExecutorThread::run()
  12687. {
  12688. try
  12689. {
  12690. executeLoop();
  12691. }
  12692. catch (IException *e)
  12693. {
  12694. activity->fireException(e);
  12695. }
  12696. catch (...)
  12697. {
  12698. activity->fireException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unexpected exception caught in LoopExecutorThread::run"));
  12699. }
  12700. return 0;
  12701. }
  12702. void LoopExecutorThread::stop(bool aborting)
  12703. {
  12704. safeInput->stop(aborting);
  12705. RestartableThread::join();
  12706. }
  12707. void LoopExecutorThread::reset()
  12708. {
  12709. safeInput->reset();
  12710. }
  12711. void LoopExecutorThread::executeLoop()
  12712. {
  12713. unsigned iterations = 0;
  12714. unsigned counter = 0;
  12715. unsigned outputIndex = 0;
  12716. //Note, activities don't link inputs, so need to be careful that special inputs remain linked while the activity is executing.
  12717. loop
  12718. {
  12719. if (activity->activityKind == TAKloopcount)
  12720. {
  12721. if (counter == activity->maxIterations)
  12722. break;
  12723. }
  12724. else
  12725. {
  12726. //This condition isn't quite right because it needs to be whether the filtered
  12727. //input is empty. May be ok if we include that in the semantics,
  12728. if (tempResults[1-outputIndex].ordinality() == 0)
  12729. break;
  12730. }
  12731. unsigned numParallel = activity->getNumParallel(iterations);
  12732. Linked<IRoxieInput> curInput;
  12733. if (iterations == 0)
  12734. curInput.set(safeInput);
  12735. else
  12736. {
  12737. SafeRowQueue & inputQueue = tempResults[1-outputIndex];
  12738. inputQueue.enqueue(NULL);
  12739. curInput.setown(new CRowQueuePseudoInput(inputQueue));
  12740. }
  12741. SafeRowQueue * curOutput = NULL;
  12742. if (counter+numParallel > activity->maxIterations)
  12743. numParallel = activity->maxIterations - counter;
  12744. else if (counter+numParallel < activity->maxIterations)
  12745. curOutput = &tempResults[outputIndex];
  12746. executeLoopInstance(counter, numParallel, curInput, curOutput);
  12747. outputIndex = 1-outputIndex;
  12748. counter += numParallel;
  12749. iterations++;
  12750. }
  12751. //Check for TAKlooprow, where end of loop couldn't be determined ahead of time
  12752. SafeRowQueue & inputQueue = tempResults[1-outputIndex];
  12753. while (inputQueue.ordinality())
  12754. {
  12755. const void * next = inputQueue.dequeue();
  12756. activity->enqueueResult(next);
  12757. }
  12758. activity->finishResults();
  12759. }
  12760. void LoopExecutorThread::executeLoopInstance(unsigned counter, unsigned numIterations, IRoxieInput * input, SafeRowQueue * spillOutput)
  12761. {
  12762. IArrayOf<IRoxieInput> savedInputs; // activities don't link their inputs, so this list keeps filters alive.
  12763. Linked<IRoxieInput> curInput = input;
  12764. unsigned i;
  12765. for (i= 0; i != numIterations; i++)
  12766. {
  12767. unsigned thisCounter = counter+i+1;
  12768. IRoxieInput * filtered = curInput;
  12769. if (flags & IHThorLoopArg::LFfiltered)
  12770. {
  12771. filtered = new LoopFilterPseudoInput(activity, curInput, thisCounter);
  12772. savedInputs.append(*filtered);
  12773. }
  12774. //graph is kept, so new curInput will be guaranteed to exist
  12775. curInput.setown(createLoopIterationGraph(i, filtered, thisCounter));
  12776. }
  12777. try
  12778. {
  12779. curInput->start(savedParentExtractSize, savedParentExtract, false);
  12780. if (spillOutput)
  12781. {
  12782. loop
  12783. {
  12784. const void * next = curInput->nextInGroup();
  12785. if (!next)
  12786. break;
  12787. spillOutput->enqueue(next);
  12788. }
  12789. }
  12790. else
  12791. {
  12792. loop
  12793. {
  12794. const void * next = curInput->nextInGroup();
  12795. if (!next)
  12796. break;
  12797. activity->enqueueResult(next);
  12798. }
  12799. }
  12800. }
  12801. catch (IException *E)
  12802. {
  12803. ctx->notifyAbort(E);
  12804. for (i= 0; i != numIterations; i++)
  12805. {
  12806. cachedGraphs.item(i).queryLoopGraph()->afterExecute();
  12807. }
  12808. curInput->stop(true);
  12809. curInput->reset();
  12810. throw;
  12811. }
  12812. for (i= 0; i != numIterations; i++)
  12813. {
  12814. cachedGraphs.item(i).queryLoopGraph()->afterExecute();
  12815. }
  12816. curInput->stop(false);
  12817. curInput->reset();
  12818. }
  12819. IRoxieInput * LoopExecutorThread::createLoopIterationGraph(unsigned i, IRoxieInput * input, unsigned counter)
  12820. {
  12821. if (!cachedGraphs.isItem(i))
  12822. cachedGraphs.append(*activity->createChildGraphInstance());
  12823. Linked<IRoxieServerChildGraph> loopGraph = cachedGraphs.item(i).queryLoopGraph();
  12824. loopGraph->beforeExecute();
  12825. if (!loopGraph->querySetInputResult(1, input))
  12826. throwUnexpected(); // a loop which doesn't use the value from the previous iteration. Should probably handle even if daft.
  12827. activity->createCounterResult(loopGraph, counter);
  12828. return loopGraph->selectOutput(0);
  12829. }
  12830. //=================================================================================
  12831. class CCounterRowMetaData : public CInterface, implements IOutputMetaData
  12832. {
  12833. public:
  12834. IMPLEMENT_IINTERFACE
  12835. virtual size32_t getRecordSize(const void *) { return sizeof(thor_loop_counter_t); }
  12836. virtual size32_t getMinRecordSize() const { return sizeof(thor_loop_counter_t); }
  12837. virtual size32_t getFixedSize() const { return sizeof(thor_loop_counter_t); }
  12838. virtual void toXML(const byte * self, IXmlWriter & out) { }
  12839. virtual unsigned getVersion() const { return OUTPUTMETADATA_VERSION; }
  12840. virtual unsigned getMetaFlags() { return 0; }
  12841. virtual void destruct(byte * self) {}
  12842. virtual IOutputRowSerializer * createRowSerializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  12843. virtual IOutputRowDeserializer * createRowDeserializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  12844. virtual ISourceRowPrefetcher * createRowPrefetcher(ICodeContext * ctx, unsigned activityId) { return NULL; }
  12845. virtual IOutputMetaData * querySerializedMeta() { return this; }
  12846. virtual void walkIndirectMembers(const byte * self, IIndirectMemberVisitor & visitor) {}
  12847. };
  12848. class CRoxieServerLoopActivityFactory : public CRoxieServerActivityFactory
  12849. {
  12850. unsigned loopGraphId;
  12851. unsigned flags;
  12852. Linked<IOutputMetaData> counterMeta;
  12853. public:
  12854. CRoxieServerLoopActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _loopGraphId)
  12855. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), loopGraphId(_loopGraphId)
  12856. {
  12857. Owned<IHThorLoopArg> helper = (IHThorLoopArg *) helperFactory();
  12858. flags = helper->getFlags();
  12859. counterMeta.setown(new CCounterRowMetaData);
  12860. }
  12861. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  12862. {
  12863. if (flags & IHThorLoopArg::LFparallel)
  12864. return new CRoxieServerParallelLoopActivity(this, _probeManager, loopGraphId, counterMeta);
  12865. else
  12866. return new CRoxieServerSequentialLoopActivity(this, _probeManager, loopGraphId, counterMeta);
  12867. }
  12868. };
  12869. IRoxieServerActivityFactory *createRoxieServerLoopActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _loopGraphId)
  12870. {
  12871. return new CRoxieServerLoopActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _loopGraphId);
  12872. }
  12873. //=================================================================================
  12874. class CRoxieServerGraphLoopActivity : public CRoxieServerActivity
  12875. {
  12876. protected:
  12877. IHThorGraphLoopArg &helper;
  12878. unsigned maxIterations;
  12879. unsigned flags;
  12880. rtlRowBuilder GraphExtractBuilder;
  12881. unsigned loopGraphId;
  12882. Linked<IOutputMetaData> counterMeta;
  12883. public:
  12884. CRoxieServerGraphLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _GraphGraphId, IOutputMetaData * _counterMeta)
  12885. : CRoxieServerActivity(_factory, _probeManager),
  12886. helper((IHThorGraphLoopArg &)basehelper), loopGraphId(_GraphGraphId), counterMeta(_counterMeta)
  12887. {
  12888. flags = helper.getFlags();
  12889. maxIterations = 0;
  12890. }
  12891. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12892. {
  12893. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  12894. int iterations = (int) helper.numIterations();
  12895. maxIterations = (iterations >= 0) ? iterations : 0;
  12896. if (maxIterations > maxGraphLoopIterations)
  12897. throw MakeStringException(ROXIE_TOO_MANY_GRAPH_LOOP, "Attempt to execute graph %u times", maxIterations);
  12898. if (maxIterations != 0)
  12899. {
  12900. GraphExtractBuilder.clear();
  12901. helper.createParentExtract(GraphExtractBuilder);
  12902. }
  12903. }
  12904. virtual void stop(bool aborting)
  12905. {
  12906. CRoxieServerActivity::stop(aborting);
  12907. GraphExtractBuilder.clear();
  12908. }
  12909. virtual bool needsAllocator() const { return true; }
  12910. void createCounterResult(IRoxieServerChildGraph * graph, unsigned counter)
  12911. {
  12912. if (flags & IHThorGraphLoopArg::GLFcounter)
  12913. {
  12914. void * counterRow = ctx->queryRowManager().allocate(sizeof(thor_loop_counter_t), activityId);
  12915. *((thor_loop_counter_t *)counterRow) = counter;
  12916. Owned<IGraphResult> counterResult = new CGraphResult(ctx->queryCodeContext()->getRowAllocator(counterMeta, activityId), counterRow, true);
  12917. graph->setInputResult(0, counterResult);
  12918. }
  12919. }
  12920. };
  12921. //=================================================================================
  12922. class CRoxieServerSequentialGraphLoopActivity : public CRoxieServerGraphLoopActivity
  12923. {
  12924. Owned<IActivityGraph> GraphQuery;
  12925. Owned<IRoxieServerChildGraph> loopGraph;
  12926. Linked<IRoxieInput> resultInput;
  12927. bool evaluated;
  12928. public:
  12929. CRoxieServerSequentialGraphLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _GraphGraphId, IOutputMetaData * _counterMeta)
  12930. : CRoxieServerGraphLoopActivity(_factory, _probeManager, _GraphGraphId, _counterMeta)
  12931. {
  12932. evaluated = false;
  12933. }
  12934. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  12935. {
  12936. CRoxieServerGraphLoopActivity::onCreate(_ctx, _colocalParent);
  12937. GraphQuery.set(_ctx->queryChildGraph(loopGraphId));
  12938. }
  12939. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  12940. {
  12941. CRoxieServerGraphLoopActivity::start(parentExtractSize, parentExtract, paused);
  12942. //MORE: Not sure about this, should IRoxieServerChildGraph be combined with IActivityGraph?
  12943. loopGraph.set(GraphQuery->queryLoopGraph());
  12944. evaluated = false;
  12945. }
  12946. virtual void stop(bool aborting)
  12947. {
  12948. if (loopGraph)
  12949. loopGraph->clearGraphLoopResults();
  12950. CRoxieServerGraphLoopActivity::stop(aborting);
  12951. }
  12952. virtual const void * nextInGroup()
  12953. {
  12954. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  12955. if (!evaluated)
  12956. {
  12957. executeEntireGraph();
  12958. evaluated = true;
  12959. }
  12960. const void * ret = resultInput->nextInGroup();
  12961. if (ret)
  12962. processed++;
  12963. return ret;
  12964. }
  12965. void executeIteration(unsigned parentExtractSize, const byte *parentExtract, unsigned counter)
  12966. {
  12967. try
  12968. {
  12969. loopGraph->beforeExecute();
  12970. createCounterResult(loopGraph, counter);
  12971. loopGraph->executeGraphLoop(parentExtractSize, parentExtract);
  12972. loopGraph->afterExecute();
  12973. }
  12974. catch (...)
  12975. {
  12976. CTXLOG("Exception thrown in graph body - cleaning up");
  12977. loopGraph->afterExecute();
  12978. throw;
  12979. }
  12980. }
  12981. void createInitialGraphInput()
  12982. {
  12983. loopGraph->clearGraphLoopResults();
  12984. ConstPointerArray rows;
  12985. try
  12986. {
  12987. loop
  12988. {
  12989. const void *nextrec = input->nextInGroup();
  12990. if (!nextrec)
  12991. {
  12992. nextrec = input->nextInGroup();
  12993. if (!nextrec)
  12994. break;
  12995. rows.append(NULL);
  12996. }
  12997. rows.append(nextrec);
  12998. }
  12999. }
  13000. catch(IException *)
  13001. {
  13002. ReleaseRoxieRowSet(rows);
  13003. throw;
  13004. }
  13005. IOutputMetaData *outputMeta = input->queryOutputMeta();
  13006. Owned<CGraphResult> result = new CGraphResult(ctx->queryCodeContext()->getRowAllocator(outputMeta, activityId), rows, true);
  13007. loopGraph->setGraphLoopResult(0, result);
  13008. }
  13009. void executeEntireGraph()
  13010. {
  13011. createInitialGraphInput();
  13012. for (unsigned loopCounter=1; loopCounter <= maxIterations; loopCounter++)
  13013. {
  13014. executeIteration(GraphExtractBuilder.size(), GraphExtractBuilder.getbytes(), loopCounter);
  13015. }
  13016. resultInput.setown(loopGraph->getGraphLoopResult(maxIterations));
  13017. }
  13018. };
  13019. //=================================================================================
  13020. struct GraphOutputSplitterArg : public ccdserver_hqlhelper::CThorSplitArg
  13021. {
  13022. public:
  13023. virtual unsigned numBranches()
  13024. {
  13025. return 0;
  13026. }
  13027. virtual IOutputMetaData * queryOutputMeta()
  13028. {
  13029. return NULL;// get it from the parent..
  13030. }
  13031. };
  13032. extern "C" IHThorArg * createGraphOutputSplitter() { return new GraphOutputSplitterArg; }
  13033. class CGraphIterationInfo : public CInterface
  13034. {
  13035. private:
  13036. Owned<IRoxieServerActivityFactory> factory; // Note - before sourceAct, so destroyed last
  13037. unsigned sourceIdx;
  13038. Linked<IRoxieServerActivity> sourceAct;
  13039. Linked<IRoxieInput> sourceInput;
  13040. unsigned numUses;
  13041. unsigned iteration;
  13042. public:
  13043. CGraphIterationInfo(IRoxieServerActivity * _sourceAct, IRoxieInput *_input, unsigned _sourceIdx, unsigned _iteration)
  13044. : sourceAct(_sourceAct), sourceInput(_input), sourceIdx(_sourceIdx), iteration(_iteration)
  13045. {
  13046. numUses = 0;
  13047. }
  13048. inline void noteUsed()
  13049. {
  13050. numUses++;
  13051. }
  13052. void createSplitter(IRoxieSlaveContext *ctx, IProbeManager *probeManager)
  13053. {
  13054. if (numUses > 1)
  13055. {
  13056. factory.setown(createRoxieServerThroughSpillActivityFactory(sourceAct->queryFactory()->queryQueryFactory(), createGraphOutputSplitter, numUses));
  13057. IRoxieServerActivity *splitter = factory->createActivity(NULL);
  13058. splitter->onCreate(ctx, NULL);
  13059. IRoxieInput *input = sourceAct->queryOutput(sourceIdx);
  13060. if (probeManager)
  13061. {
  13062. IInputBase * inputBase = probeManager->createProbe(static_cast<IInputBase*>(input), sourceAct, splitter, sourceIdx, 0, iteration);
  13063. input = static_cast<IRoxieInput*>(inputBase);
  13064. // MORE - shouldn't this be added to probes?
  13065. }
  13066. sourceAct.setown(splitter);
  13067. sourceAct->setInput(0, input);
  13068. sourceIdx = 0;
  13069. sourceInput.clear();
  13070. }
  13071. }
  13072. IRoxieInput *connectOutput(IProbeManager *probeManager, IArrayOf<IRoxieInput> &probes, IRoxieServerActivity *targetAct, unsigned targetIdx)
  13073. {
  13074. // MORE - not really necessary to create splitters in separate pass, is it?
  13075. if (factory) // we created a splitter....
  13076. sourceInput.set(sourceAct->queryOutput(sourceIdx));
  13077. IRoxieInput *ret = sourceInput;
  13078. if (probeManager)
  13079. {
  13080. IInputBase *inputBase = probeManager->createProbe(ret, sourceAct, targetAct, sourceIdx, targetIdx, iteration);
  13081. ret = static_cast<IRoxieInput *>(inputBase);
  13082. probes.append(*LINK(ret));
  13083. }
  13084. if (factory) // we created a splitter....
  13085. sourceIdx++;
  13086. return ret;
  13087. }
  13088. };
  13089. class CRoxieServerParallelGraphLoopActivity : public CRoxieServerGraphLoopActivity, implements IRoxieServerLoopResultProcessor
  13090. {
  13091. Owned<IActivityGraph> childGraph;
  13092. IRoxieInput * resultInput;
  13093. CIArrayOf<CGraphIterationInfo> outputs;
  13094. IArrayOf<IRoxieServerChildGraph> iterationGraphs;
  13095. Owned<CExtractMapperInput> inputExtractMapper;
  13096. IProbeManager *probeManager;
  13097. unsigned createLoopCounter;
  13098. IArrayOf<IRoxieInput> probes;
  13099. public:
  13100. CRoxieServerParallelGraphLoopActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _GraphGraphId, IOutputMetaData * _counterMeta)
  13101. : CRoxieServerGraphLoopActivity(_factory, _probeManager, _GraphGraphId, _counterMeta), probeManager(_probeManager)
  13102. {
  13103. inputExtractMapper.setown(new CExtractMapperInput);
  13104. resultInput = NULL;
  13105. createLoopCounter = 0;
  13106. }
  13107. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  13108. {
  13109. CRoxieServerGraphLoopActivity::onCreate(_ctx, _colocalParent);
  13110. childGraph.set(_ctx->queryChildGraph(loopGraphId));
  13111. }
  13112. virtual void setInput(unsigned idx, IRoxieInput *_in)
  13113. {
  13114. //Input needs to be handled very carefully.....
  13115. //We don't want to call onStart on the input unless it is actually used, so don't use the base CRoxieServerActivity implementation.
  13116. //This activity's input needs to be started with (parentExtractSize, parentExtract), but the elements in the graph need to be started with the
  13117. //GraphExtractBuilder parent extract. So we need to wrap the input in a pseudo-input (inputExtractMapper) that passes through a different
  13118. //parentExtract. Something very similar will be needed for query library calls with streaming inputs when they are implemented.
  13119. assertex(idx == 0);
  13120. inputExtractMapper->setInput(_in);
  13121. }
  13122. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13123. {
  13124. CRoxieServerGraphLoopActivity::start(parentExtractSize, parentExtract, paused); // initialises GraphExtractBuilder
  13125. inputExtractMapper->setParentExtract(parentExtractSize, parentExtract);
  13126. createExpandedGraph(GraphExtractBuilder.size(), GraphExtractBuilder.getbytes(), probeManager);
  13127. resultInput->start(GraphExtractBuilder.size(), GraphExtractBuilder.getbytes(), paused);
  13128. }
  13129. virtual void stop(bool aborting)
  13130. {
  13131. if (resultInput)
  13132. resultInput->stop(aborting);
  13133. CRoxieServerGraphLoopActivity::stop(aborting);
  13134. }
  13135. virtual void reset()
  13136. {
  13137. if (resultInput)
  13138. resultInput->reset();
  13139. resultInput = NULL;
  13140. iterationGraphs.kill();
  13141. outputs.kill();
  13142. if (probeManager)
  13143. {
  13144. probeManager->deleteGraph(NULL, (IArrayOf<IInputBase>*)&probes);
  13145. probes.kill();
  13146. }
  13147. CRoxieServerGraphLoopActivity::reset();
  13148. }
  13149. virtual const void * nextInGroup()
  13150. {
  13151. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  13152. const void * ret = resultInput->nextInGroup();
  13153. if (ret)
  13154. processed++;
  13155. return ret;
  13156. }
  13157. void createExpandedGraph(unsigned parentExtractSize, const byte *parentExtract, IProbeManager *probeManager)
  13158. {
  13159. //result(0) is the input to the graph.
  13160. resultInput = inputExtractMapper;
  13161. outputs.append(* new CGraphIterationInfo(resultInput->queryActivity(), resultInput, 0, 1));
  13162. for (createLoopCounter=1; createLoopCounter <= maxIterations; createLoopCounter++)
  13163. {
  13164. IRoxieServerChildGraph * graph = childGraph->createGraphLoopInstance(createLoopCounter, parentExtractSize, parentExtract, *this);
  13165. graph->beforeExecute();
  13166. iterationGraphs.append(*graph);
  13167. graph->gatherIterationUsage(*this);
  13168. CGraphIterationInfo *iteration = graph->selectGraphLoopOutput();
  13169. outputs.append(*iteration);
  13170. }
  13171. createLoopCounter = 0;
  13172. createSplitters(probeManager);
  13173. ForEachItemIn(i2, iterationGraphs)
  13174. iterationGraphs.item(i2).associateIterationOutputs(*this);
  13175. resultInput = outputs.tos().connectOutput(probeManager, probes, this, 0);
  13176. }
  13177. void createSplitters(IProbeManager *probeManager)
  13178. {
  13179. ForEachItemIn(i, outputs)
  13180. {
  13181. CGraphIterationInfo & next = outputs.item(i);
  13182. next.createSplitter(ctx, probeManager);
  13183. }
  13184. }
  13185. //IRoxieServerLoopResultProcessor
  13186. virtual void noteUseIteration(unsigned _whichIteration)
  13187. {
  13188. int whichIteration = (int) _whichIteration; // May go negative - API is unsigned for historical reasons
  13189. if (whichIteration >= 0)
  13190. {
  13191. if (!outputs.isItem(whichIteration))
  13192. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Error reading graph result %d from iteration %d", whichIteration, createLoopCounter);
  13193. outputs.item(whichIteration).noteUsed();
  13194. }
  13195. }
  13196. virtual IRoxieInput * connectIterationOutput(unsigned whichIteration, IProbeManager *probeManager, IArrayOf<IRoxieInput> &probes, IRoxieServerActivity *targetAct, unsigned targetIdx)
  13197. {
  13198. if (outputs.isItem(whichIteration))
  13199. {
  13200. CGraphIterationInfo & next = outputs.item(whichIteration);
  13201. return next.connectOutput(probeManager, probes, targetAct, targetIdx);
  13202. }
  13203. return NULL;
  13204. }
  13205. };
  13206. //=================================================================================
  13207. class CRoxieServerGraphLoopActivityFactory : public CRoxieServerActivityFactory
  13208. {
  13209. unsigned loopGraphId;
  13210. unsigned flags;
  13211. Linked<IOutputMetaData> counterMeta;
  13212. public:
  13213. CRoxieServerGraphLoopActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _loopGraphId)
  13214. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), loopGraphId(_loopGraphId)
  13215. {
  13216. Owned<IHThorGraphLoopArg> helper = (IHThorGraphLoopArg *) helperFactory();
  13217. flags = helper->getFlags();
  13218. counterMeta.setown(new CCounterRowMetaData);
  13219. }
  13220. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  13221. {
  13222. if (kind == TAKparallelgraphloop)
  13223. return new CRoxieServerParallelGraphLoopActivity(this, _probeManager, loopGraphId, counterMeta);
  13224. else
  13225. return new CRoxieServerSequentialGraphLoopActivity(this, _probeManager, loopGraphId, counterMeta);
  13226. }
  13227. };
  13228. IRoxieServerActivityFactory *createRoxieServerGraphLoopActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _loopGraphId)
  13229. {
  13230. return new CRoxieServerGraphLoopActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _loopGraphId);
  13231. }
  13232. //=====================================================================================================
  13233. class CRoxieServerLibraryCallActivity : public CRoxieServerActivity
  13234. {
  13235. class OutputAdaptor : public CExtractMapperInput
  13236. {
  13237. bool stopped;
  13238. public:
  13239. CRoxieServerLibraryCallActivity *parent;
  13240. unsigned oid;
  13241. unsigned processed;
  13242. public:
  13243. IMPLEMENT_IINTERFACE;
  13244. OutputAdaptor() : CExtractMapperInput(NULL)
  13245. {
  13246. parent = NULL;
  13247. oid = 0;
  13248. init();
  13249. }
  13250. void init()
  13251. {
  13252. processed = 0;
  13253. stopped = false;
  13254. }
  13255. virtual unsigned queryId() const
  13256. {
  13257. return parent->queryId();
  13258. }
  13259. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13260. {
  13261. parent->start(oid, parentExtractSize, parentExtract, paused);
  13262. CExtractMapperInput::start(parentExtractSize, parentExtract, paused);
  13263. }
  13264. virtual void stop(bool aborting)
  13265. {
  13266. if (!stopped)
  13267. {
  13268. stopped = true;
  13269. parent->stop(oid, aborting); // parent code relies on stop being called exactly once per adaptor, so make sure it is!
  13270. CExtractMapperInput::stop(aborting);
  13271. }
  13272. };
  13273. virtual void reset()
  13274. {
  13275. parent->reset(oid, processed);
  13276. CExtractMapperInput::reset();
  13277. init();
  13278. };
  13279. virtual void checkAbort()
  13280. {
  13281. parent->checkAbort();
  13282. }
  13283. };
  13284. IHThorLibraryCallArg &helper;
  13285. unsigned numInputs;
  13286. unsigned numOutputs;
  13287. unsigned numActiveOutputs;
  13288. bool started;
  13289. OutputAdaptor* outputAdaptors;
  13290. CExtractMapperInput * * inputAdaptors;
  13291. bool * inputUsed;
  13292. bool * outputUsed;
  13293. Owned<IException> error;
  13294. CriticalSection crit;
  13295. rtlRowBuilder libraryExtractBuilder;
  13296. Owned<IActivityGraph> libraryGraph;
  13297. const LibraryCallFactoryExtra & extra;
  13298. public:
  13299. CRoxieServerLibraryCallActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs, unsigned _numOutputs, const LibraryCallFactoryExtra & _extra)
  13300. : CRoxieServerActivity(_factory, _probeManager),
  13301. helper((IHThorLibraryCallArg &)basehelper), extra(_extra)
  13302. {
  13303. numInputs = _numInputs;
  13304. numOutputs = _numOutputs;
  13305. numActiveOutputs = numOutputs;
  13306. inputAdaptors = new CExtractMapperInput*[numInputs];
  13307. inputUsed = new bool[numInputs];
  13308. for (unsigned i1 = 0; i1 < numInputs; i1++)
  13309. {
  13310. inputAdaptors[i1] = new CExtractMapperInput;
  13311. inputUsed[i1] = false;
  13312. }
  13313. outputAdaptors = new OutputAdaptor[numOutputs];
  13314. outputUsed = new bool[numOutputs];
  13315. for (unsigned i2 = 0; i2 < numOutputs; i2++)
  13316. {
  13317. outputAdaptors[i2].parent = this;
  13318. outputAdaptors[i2].oid = i2;
  13319. outputUsed[i2] = false;
  13320. }
  13321. started = false;
  13322. }
  13323. ~CRoxieServerLibraryCallActivity()
  13324. {
  13325. for (unsigned i1 = 0; i1 < numInputs; i1++)
  13326. ::Release(inputAdaptors[i1]);
  13327. delete [] inputAdaptors;
  13328. delete [] inputUsed;
  13329. delete [] outputAdaptors;
  13330. delete [] outputUsed;
  13331. }
  13332. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  13333. {
  13334. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  13335. libraryGraph.setown(_ctx->getLibraryGraph(extra, this));
  13336. libraryGraph->onCreate(_ctx, _colocalParent);
  13337. //Now map the inputs and outputs to the adapters
  13338. IRoxieServerChildGraph * graph = libraryGraph->queryLoopGraph();
  13339. for (unsigned i1=0; i1<numInputs; i1++)
  13340. inputUsed[i1] = graph->querySetInputResult(i1, inputAdaptors[i1]);
  13341. for (unsigned i2=0; i2<numOutputs; i2++)
  13342. {
  13343. unsigned outputIndex = extra.outputs.item(i2);
  13344. Owned<IRoxieInput> output = graph->selectOutput(numInputs+outputIndex);
  13345. outputAdaptors[i2].setInput(output);
  13346. }
  13347. }
  13348. virtual void start(unsigned oid, unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13349. {
  13350. CriticalBlock b(crit);
  13351. if (error)
  13352. throw error.getLink();
  13353. if (factory)
  13354. factory->noteStarted(oid);
  13355. if (!started)
  13356. {
  13357. // even though it is not complete, we don't want to run this again if it fails.
  13358. started = true;
  13359. //see notes on splitter above
  13360. try
  13361. {
  13362. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  13363. }
  13364. catch (IException *E)
  13365. {
  13366. #ifdef TRACE_SPLIT
  13367. CTXLOG("spill %d caught exception in start", activityId);
  13368. #endif
  13369. error.set(E);
  13370. throw;
  13371. }
  13372. catch (...)
  13373. {
  13374. IException *E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught in CRoxieServerLibraryCallActivity::start");
  13375. error.set(E);
  13376. throw E;
  13377. }
  13378. //recreate the parent extract, and use it to reinitialize the graphs...
  13379. libraryExtractBuilder.clear();
  13380. helper.createParentExtract(libraryExtractBuilder);
  13381. // NOTE - do NOT set activeOutputs = numOutputs here - we must rely on the value set in reset and constructor. This is because we can see stop on
  13382. // some inputs before we see start on others.
  13383. for (unsigned i1 = 0; i1 < numInputs; i1++)
  13384. {
  13385. if (inputUsed[i1])
  13386. inputAdaptors[i1]->setParentExtract(parentExtractSize, parentExtract);
  13387. else
  13388. inputAdaptors[i1]->stop(false);
  13389. }
  13390. for (unsigned i2 = 0; i2 < numOutputs; i2++)
  13391. outputAdaptors[i2].setParentExtract(libraryExtractBuilder.size(), libraryExtractBuilder.getbytes());
  13392. //call stop on all the unused inputs.
  13393. IRoxieServerChildGraph * graph = libraryGraph->queryLoopGraph();
  13394. graph->beforeExecute();
  13395. ForEachItemIn(i3, extra.unusedOutputs)
  13396. {
  13397. Owned<IRoxieInput> output = graph->selectOutput(numInputs+extra.unusedOutputs.item(i3));
  13398. output->stop(false);
  13399. }
  13400. }
  13401. }
  13402. virtual void stop(unsigned oid, bool aborting)
  13403. {
  13404. CriticalBlock b(crit);
  13405. if (--numActiveOutputs == 0)
  13406. {
  13407. //call stop on all the unused inputs.
  13408. IRoxieServerChildGraph * graph = libraryGraph->queryLoopGraph();
  13409. graph->beforeExecute();
  13410. ForEachItemIn(i3, extra.unusedOutputs)
  13411. {
  13412. Owned<IRoxieInput> output = graph->selectOutput(numInputs+extra.unusedOutputs.item(i3));
  13413. output->stop(false);
  13414. }
  13415. CRoxieServerActivity::stop(aborting);
  13416. }
  13417. }
  13418. void reset(unsigned oid, unsigned _processed)
  13419. {
  13420. noteProcessed(oid, _processed, 0, 0);
  13421. started = false;
  13422. error.clear();
  13423. numActiveOutputs = numOutputs;
  13424. if (state != STATEreset) // make sure input is only reset once
  13425. {
  13426. CRoxieServerActivity::reset();
  13427. libraryGraph->reset();
  13428. //Call reset on all unused outputs from the graph - no one else will.
  13429. IRoxieServerChildGraph * graph = libraryGraph->queryLoopGraph();
  13430. ForEachItemIn(i3, extra.unusedOutputs)
  13431. {
  13432. Owned<IRoxieInput> output = graph->selectOutput(numInputs+extra.unusedOutputs.item(i3));
  13433. output->reset();
  13434. }
  13435. }
  13436. };
  13437. virtual void setInput(unsigned idx, IRoxieInput *_in)
  13438. {
  13439. inputAdaptors[idx]->setInput(_in);
  13440. }
  13441. public:
  13442. virtual const void *nextInGroup()
  13443. {
  13444. throwUnexpected(); // Internal logic error - we are not anybody's input
  13445. }
  13446. virtual IOutputMetaData * queryOutputMeta() const
  13447. {
  13448. throwUnexpected(); // should be called on outputs instead
  13449. }
  13450. virtual IRoxieInput *queryOutput(unsigned idx)
  13451. {
  13452. assertex(idx!=(unsigned)-1);
  13453. assertex(!outputUsed[idx]);
  13454. outputUsed[idx] = true;
  13455. return &outputAdaptors[idx];
  13456. }
  13457. };
  13458. void LibraryCallFactoryExtra::set(const LibraryCallFactoryExtra & _other)
  13459. {
  13460. ForEachItemIn(i1, _other.outputs)
  13461. outputs.append(_other.outputs.item(i1));
  13462. ForEachItemIn(i2, _other.unusedOutputs)
  13463. unusedOutputs.append(_other.unusedOutputs.item(i2));
  13464. maxOutputs = _other.maxOutputs;
  13465. graphid = _other.graphid;
  13466. libraryName.set(_other.libraryName);
  13467. interfaceHash = _other.interfaceHash;
  13468. embedded = _other.embedded;
  13469. }
  13470. void LibraryCallFactoryExtra::calcUnused()
  13471. {
  13472. for (unsigned i=0; i < maxOutputs; i++)
  13473. if (!outputs.contains(i))
  13474. unusedOutputs.append(i);
  13475. }
  13476. class CRoxieServerLibraryCallActivityFactory : public CRoxieServerMultiOutputFactory
  13477. {
  13478. private:
  13479. CRoxieServerMultiInputInfo inputs;
  13480. LibraryCallFactoryExtra extra;
  13481. public:
  13482. CRoxieServerLibraryCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, LibraryCallFactoryExtra & _extra)
  13483. : CRoxieServerMultiOutputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  13484. {
  13485. extra.set(_extra);
  13486. extra.calcUnused();
  13487. setNumOutputs(extra.outputs.ordinality());
  13488. }
  13489. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  13490. {
  13491. return new CRoxieServerLibraryCallActivity(this, _probeManager, numInputs(), numOutputs, extra);
  13492. }
  13493. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  13494. {
  13495. inputs.set(idx, source, sourceidx);
  13496. }
  13497. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  13498. {
  13499. return inputs.get(idx, sourceidx);
  13500. }
  13501. inline unsigned numInputs() const { return inputs.ordinality(); }
  13502. };
  13503. IRoxieServerActivityFactory *createRoxieServerLibraryCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, LibraryCallFactoryExtra & _extra)
  13504. {
  13505. return new CRoxieServerLibraryCallActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _extra);
  13506. }
  13507. //=====================================================================================================
  13508. class CRoxieServerNWayInputActivity : public CRoxieServerActivity
  13509. {
  13510. IHThorNWayInputArg & helper;
  13511. IRoxieInput ** inputs;
  13512. PointerArrayOf<IRoxieInput> selectedInputs;
  13513. unsigned numInputs;
  13514. public:
  13515. CRoxieServerNWayInputActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  13516. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorNWayInputArg &)basehelper), numInputs(_numInputs)
  13517. {
  13518. inputs = new IRoxieInput*[numInputs];
  13519. for (unsigned i = 0; i < numInputs; i++)
  13520. inputs[i] = NULL;
  13521. }
  13522. ~CRoxieServerNWayInputActivity()
  13523. {
  13524. delete [] inputs;
  13525. }
  13526. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13527. {
  13528. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  13529. bool selectionIsAll;
  13530. size32_t selectionLen;
  13531. rtlDataAttr selection;
  13532. helper.getInputSelection(selectionIsAll, selectionLen, selection.refdata());
  13533. selectedInputs.kill();
  13534. if (selectionIsAll)
  13535. {
  13536. for (unsigned i=0; i < numInputs; i++)
  13537. selectedInputs.append(inputs[i]);
  13538. }
  13539. else
  13540. {
  13541. const size32_t * selections = (const size32_t *)selection.getdata();
  13542. unsigned max = selectionLen/sizeof(size32_t);
  13543. for (unsigned i = 0; i < max; i++)
  13544. {
  13545. unsigned nextIndex = selections[i];
  13546. //Check there are no duplicates..... Assumes there are a fairly small number of inputs, so n^2 search is ok.
  13547. for (unsigned j=i+1; j < max; j++)
  13548. {
  13549. if (nextIndex == selections[j])
  13550. throw MakeStringException(ROXIE_NWAY_INPUT_ERROR, "Selection list for nway input can not contain duplicates");
  13551. }
  13552. if (nextIndex > numInputs)
  13553. throw MakeStringException(ROXIE_NWAY_INPUT_ERROR, "Index %d in RANGE selection list is out of range", nextIndex);
  13554. selectedInputs.append(inputs[nextIndex-1]);
  13555. }
  13556. }
  13557. ForEachItemIn(i2, selectedInputs)
  13558. selectedInputs.item(i2)->start(parentExtractSize, parentExtract, paused);
  13559. }
  13560. virtual void stop(bool aborting)
  13561. {
  13562. ForEachItemIn(i2, selectedInputs)
  13563. selectedInputs.item(i2)->stop(aborting);
  13564. CRoxieServerActivity::stop(aborting);
  13565. }
  13566. virtual unsigned __int64 queryLocalCycles() const
  13567. {
  13568. __int64 localCycles = totalCycles;
  13569. ForEachItemIn(i, selectedInputs)
  13570. {
  13571. localCycles -= selectedInputs.item(i)->queryTotalCycles();
  13572. }
  13573. if (localCycles < 0)
  13574. localCycles = 0;
  13575. return localCycles;
  13576. }
  13577. virtual IRoxieInput *queryInput(unsigned idx) const
  13578. {
  13579. if (selectedInputs.isItem(idx))
  13580. return selectedInputs.item(idx);
  13581. else
  13582. return NULL;
  13583. }
  13584. virtual void reset()
  13585. {
  13586. ForEachItemIn(i, selectedInputs)
  13587. selectedInputs.item(i)->reset();
  13588. selectedInputs.kill();
  13589. CRoxieServerActivity::reset();
  13590. }
  13591. virtual void setInput(unsigned idx, IRoxieInput *_in)
  13592. {
  13593. assertex(idx < numInputs);
  13594. inputs[idx] = _in;
  13595. }
  13596. virtual const void * nextInGroup()
  13597. {
  13598. throwUnexpected();
  13599. }
  13600. virtual unsigned numConcreteOutputs() const
  13601. {
  13602. return selectedInputs.ordinality();
  13603. }
  13604. virtual IRoxieInput * queryConcreteInput(unsigned idx)
  13605. {
  13606. if (selectedInputs.isItem(idx))
  13607. return selectedInputs.item(idx);
  13608. return NULL;
  13609. }
  13610. };
  13611. class CRoxieServerNWayInputActivityFactory : public CRoxieServerMultiInputFactory
  13612. {
  13613. // bool ordered;
  13614. public:
  13615. CRoxieServerNWayInputActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  13616. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  13617. {
  13618. }
  13619. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  13620. {
  13621. return new CRoxieServerNWayInputActivity(this, _probeManager, numInputs());
  13622. }
  13623. };
  13624. IRoxieServerActivityFactory *createRoxieServerNWayInputActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  13625. {
  13626. return new CRoxieServerNWayInputActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  13627. }
  13628. //=====================================================================================================
  13629. class CRoxieServerNWayGraphLoopResultReadActivity : public CRoxieServerActivity
  13630. {
  13631. IHThorNWayGraphLoopResultReadArg & helper;
  13632. CIArrayOf<CRoxieServerActivity> resultReaders;
  13633. PointerArrayOf<IRoxieInput> inputs;
  13634. unsigned graphId;
  13635. bool grouped;
  13636. bool selectionIsAll;
  13637. size32_t selectionLen;
  13638. rtlDataAttr selection;
  13639. public:
  13640. CRoxieServerNWayGraphLoopResultReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _graphId)
  13641. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorNWayGraphLoopResultReadArg &)basehelper)
  13642. {
  13643. grouped = helper.isGrouped();
  13644. graphId = _graphId;
  13645. selectionIsAll = false;
  13646. }
  13647. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13648. {
  13649. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  13650. if (inputs.ordinality() == 0)
  13651. {
  13652. initInputSelection();
  13653. unsigned max = selectionLen / sizeof(size32_t);
  13654. const size32_t * selections = (const size32_t *)selection.getdata();
  13655. IProbeManager * probeManager = NULL; // MORE!!
  13656. for (unsigned i = 0; i < max; i++)
  13657. {
  13658. CRoxieServerActivity * resultInput = new CRoxieServerInternalGraphLoopResultReadActivity(factory, probeManager, graphId, selections[i]);
  13659. resultReaders.append(*resultInput);
  13660. inputs.append(resultInput->queryOutput(0));
  13661. resultInput->onCreate(ctx, colocalParent);
  13662. resultInput->start(parentExtractSize, parentExtract, paused);
  13663. }
  13664. }
  13665. else
  13666. {
  13667. ForEachItemIn(i, inputs)
  13668. inputs.item(i)->start(parentExtractSize, parentExtract, paused);
  13669. }
  13670. }
  13671. virtual void stop(bool aborting)
  13672. {
  13673. ForEachItemIn(i, inputs)
  13674. inputs.item(i)->stop(aborting);
  13675. CRoxieServerActivity::stop(aborting);
  13676. }
  13677. virtual void reset()
  13678. {
  13679. ForEachItemIn(i, inputs)
  13680. inputs.item(i)->reset();
  13681. inputs.kill();
  13682. resultReaders.kill();
  13683. CRoxieServerActivity::reset();
  13684. }
  13685. virtual void setInput(unsigned idx, IRoxieInput *_in)
  13686. {
  13687. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for nway graph result read");
  13688. }
  13689. virtual const void * nextInGroup()
  13690. {
  13691. throwUnexpected();
  13692. }
  13693. virtual unsigned numConcreteOutputs() const
  13694. {
  13695. return inputs.ordinality();
  13696. }
  13697. virtual IRoxieInput * queryConcreteInput(unsigned idx)
  13698. {
  13699. if (inputs.isItem(idx))
  13700. return inputs.item(idx);
  13701. return NULL;
  13702. }
  13703. virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract)
  13704. {
  13705. ensureCreated();
  13706. basehelper.onStart(parentExtract, NULL);
  13707. initInputSelection();
  13708. unsigned max = selectionLen / sizeof(size32_t);
  13709. const size32_t * selections = (const size32_t *)selection.getdata();
  13710. for (unsigned i = 0; i < max; i++)
  13711. processor.noteUseIteration(selections[i]);
  13712. }
  13713. virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor, unsigned parentExtractSize, const byte * parentExtract, IProbeManager *probeManager, IArrayOf<IRoxieInput> &probes)
  13714. {
  13715. //selection etc. already initialised from the gratherIterationUsage() call.
  13716. unsigned max = selectionLen / sizeof(size32_t);
  13717. const size32_t * selections = (const size32_t *)selection.getdata();
  13718. for (unsigned i = 0; i < max; i++)
  13719. inputs.append(processor.connectIterationOutput(selections[i], probeManager, probes, this, i));
  13720. }
  13721. protected:
  13722. void initInputSelection()
  13723. {
  13724. helper.getInputSelection(selectionIsAll, selectionLen, selection.refdata());
  13725. if (selectionIsAll)
  13726. throw MakeStringException(ROXIE_NWAY_INPUT_ERROR, "ALL not yet supported for NWay graph inputs");
  13727. }
  13728. };
  13729. class CRoxieServerNWayGraphLoopResultReadActivityFactory : public CRoxieServerActivityFactory
  13730. {
  13731. unsigned graphId;
  13732. public:
  13733. CRoxieServerNWayGraphLoopResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _graphId)
  13734. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), graphId(_graphId)
  13735. {
  13736. }
  13737. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  13738. {
  13739. return new CRoxieServerNWayGraphLoopResultReadActivity(this, _probeManager, graphId);
  13740. }
  13741. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  13742. {
  13743. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for NWay GraphLoopResultRead activity");
  13744. }
  13745. };
  13746. IRoxieServerActivityFactory *createRoxieServerNWayGraphLoopResultReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned graphId)
  13747. {
  13748. return new CRoxieServerNWayGraphLoopResultReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, graphId);
  13749. }
  13750. //=================================================================================
  13751. class RoxieSteppedInput : public CInterface, implements ISteppedInput
  13752. {
  13753. public:
  13754. RoxieSteppedInput(IRoxieInput * _input) { input = _input; }
  13755. IMPLEMENT_IINTERFACE
  13756. protected:
  13757. virtual const void * nextInputRow()
  13758. {
  13759. #ifdef TRACE_SEEK_REQUESTS
  13760. IRoxieContextLogger * logger = input->queryActivity();
  13761. const void * ret = doNextInputRow();
  13762. {
  13763. CommonXmlWriter xmlwrite(XWFtrim|XWFopt|XWFnoindent);
  13764. if (!ret)
  13765. xmlwrite.outputBool(true,"eof");
  13766. else if (input->queryOutputMeta()->hasXML())
  13767. input->queryOutputMeta()->toXML((byte *) ret, xmlwrite);
  13768. logger->CTXLOG("next() returns (%s)", xmlwrite.str());
  13769. }
  13770. return ret;
  13771. #else
  13772. return doNextInputRow();
  13773. #endif
  13774. }
  13775. virtual const void * nextInputRowGE(const void * seek, unsigned numFields, bool & wasCompleteMatch, const SmartStepExtra & stepExtra)
  13776. {
  13777. #ifdef TRACE_SEEK_REQUESTS
  13778. IRoxieContextLogger * logger = input->queryActivity();
  13779. {
  13780. CommonXmlWriter xmlwrite(XWFtrim|XWFopt|XWFnoindent);
  13781. if (input->queryOutputMeta()->hasXML())
  13782. input->queryOutputMeta()->toXML((byte *) seek, xmlwrite);
  13783. logger->CTXLOG("nextInputRowGE(%d, %s%s%s, %s) seek(%s)",
  13784. numFields,
  13785. stepExtra.readAheadManyResults() ? "readahead " : "",
  13786. stepExtra.returnMismatches() ? "mismatch" : "exact",
  13787. stepExtra.onlyReturnFirstSeekMatch() ? " single-match" : "",
  13788. stepExtra.queryExtraSeeks() ? "multi-seek":"",
  13789. xmlwrite.str());
  13790. }
  13791. const void * ret = doNextInputRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  13792. {
  13793. CommonXmlWriter xmlwrite(XWFtrim|XWFopt|XWFnoindent);
  13794. if (!ret)
  13795. xmlwrite.outputBool(true,"eof");
  13796. else if (input->queryOutputMeta()->hasXML())
  13797. input->queryOutputMeta()->toXML((byte *) ret, xmlwrite);
  13798. logger->CTXLOG("nextInputRowGE(%d, %s%s%s, %s) result(%s)",
  13799. numFields,
  13800. stepExtra.readAheadManyResults() ? "readahead " : "",
  13801. stepExtra.returnMismatches() ? "mismatch" : "exact",
  13802. stepExtra.onlyReturnFirstSeekMatch() ? " single-match" : "",
  13803. stepExtra.queryExtraSeeks() ? "multi-seek":"",
  13804. xmlwrite.str());
  13805. }
  13806. return ret;
  13807. #else
  13808. return doNextInputRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  13809. #endif
  13810. }
  13811. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  13812. {
  13813. return input->gatherConjunctions(collector);
  13814. }
  13815. virtual void resetEOF()
  13816. {
  13817. input->resetEOF();
  13818. }
  13819. virtual IInputSteppingMeta * queryInputSteppingMeta()
  13820. {
  13821. return input->querySteppingMeta();
  13822. }
  13823. inline const void * doNextInputRow()
  13824. {
  13825. const void * ret = input->nextInGroup();
  13826. if (!ret)
  13827. ret = input->nextInGroup();
  13828. return ret;
  13829. }
  13830. inline const void * doNextInputRowGE(const void * seek, unsigned numFields, bool & wasCompleteMatch, const SmartStepExtra & stepExtra)
  13831. {
  13832. assertex(wasCompleteMatch);
  13833. return input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  13834. }
  13835. protected:
  13836. IRoxieInput * input;
  13837. };
  13838. //=================================================================================
  13839. class CRoxieServerNaryActivity : public CRoxieServerMultiInputActivity
  13840. {
  13841. public:
  13842. CRoxieServerNaryActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  13843. : CRoxieServerMultiInputActivity(_factory, _probeManager, _numInputs)
  13844. {
  13845. }
  13846. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13847. {
  13848. CRoxieServerMultiInputActivity::start(parentExtractSize, parentExtract, paused);
  13849. for (unsigned i=0; i < numInputs; i++)
  13850. {
  13851. IRoxieInput * cur = inputArray[i];
  13852. unsigned numRealInputs = cur->numConcreteOutputs();
  13853. for (unsigned j = 0; j < numRealInputs; j++)
  13854. {
  13855. IRoxieInput * curReal = cur->queryConcreteInput(j);
  13856. expandedInputs.append(curReal);
  13857. }
  13858. }
  13859. }
  13860. virtual void reset()
  13861. {
  13862. expandedInputs.kill();
  13863. CRoxieServerMultiInputActivity::reset();
  13864. }
  13865. protected:
  13866. PointerArrayOf<IRoxieInput> expandedInputs;
  13867. };
  13868. //=================================================================================
  13869. class CRoxieStreamMerger : public CStreamMerger
  13870. {
  13871. public:
  13872. CRoxieStreamMerger() : CStreamMerger(true) {}
  13873. void initInputs(unsigned _numInputs, IRoxieInput ** _inputArray)
  13874. {
  13875. CStreamMerger::initInputs(_numInputs);
  13876. inputArray = _inputArray;
  13877. }
  13878. virtual bool pullInput(unsigned i, const void * seek, unsigned numFields, const SmartStepExtra * stepExtra)
  13879. {
  13880. const void * next;
  13881. bool matches = true;
  13882. if (seek)
  13883. next = inputArray[i]->nextSteppedGE(seek, numFields, matches, *stepExtra);
  13884. else
  13885. next = nextUngrouped(inputArray[i]);
  13886. pending[i] = next;
  13887. pendingMatches[i] = matches;
  13888. return (next != NULL);
  13889. }
  13890. virtual void releaseRow(const void * row)
  13891. {
  13892. ReleaseRoxieRow(row);
  13893. }
  13894. protected:
  13895. IRoxieInput **inputArray;
  13896. };
  13897. class CRoxieServerNWayMergeActivity : public CRoxieServerNaryActivity
  13898. {
  13899. public:
  13900. CRoxieServerNWayMergeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  13901. : CRoxieServerNaryActivity(_factory, _probeManager, _numInputs),
  13902. helper((IHThorNWayMergeArg &)basehelper)
  13903. {
  13904. initializedMeta = false;
  13905. }
  13906. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13907. {
  13908. CRoxieServerNaryActivity::start(parentExtractSize, parentExtract, paused);
  13909. merger.init(helper.queryCompare(), helper.dedup(), helper.querySteppingMeta()->queryCompare());
  13910. merger.initInputs(expandedInputs.length(), expandedInputs.getArray());
  13911. }
  13912. virtual void stop(bool aborting)
  13913. {
  13914. merger.done();
  13915. CRoxieServerNaryActivity::stop(aborting);
  13916. }
  13917. virtual void reset()
  13918. {
  13919. merger.cleanup();
  13920. CRoxieServerNaryActivity::reset();
  13921. initializedMeta = false;
  13922. }
  13923. virtual const void * nextInGroup()
  13924. {
  13925. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  13926. const void * next = merger.nextRow();
  13927. if (next)
  13928. processed++;
  13929. return next;
  13930. }
  13931. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool & wasCompleteMatch, const SmartStepExtra & stepExtra)
  13932. {
  13933. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  13934. const void * next = merger.nextRowGE(seek, numFields, wasCompleteMatch, stepExtra);
  13935. if (next)
  13936. processed++;
  13937. return next;
  13938. }
  13939. virtual IInputSteppingMeta * querySteppingMeta()
  13940. {
  13941. if (expandedInputs.ordinality() == 0)
  13942. return NULL;
  13943. if (!initializedMeta)
  13944. {
  13945. meta.init(helper.querySteppingMeta(), false);
  13946. ForEachItemIn(i, expandedInputs)
  13947. {
  13948. if (meta.getNumFields() == 0)
  13949. break;
  13950. IInputSteppingMeta * inputMeta = expandedInputs.item(i)->querySteppingMeta();
  13951. meta.intersect(inputMeta);
  13952. }
  13953. initializedMeta = true;
  13954. }
  13955. if (meta.getNumFields() == 0)
  13956. return NULL;
  13957. return &meta;
  13958. }
  13959. protected:
  13960. IHThorNWayMergeArg &helper;
  13961. CRoxieStreamMerger merger;
  13962. CSteppingMeta meta;
  13963. bool initializedMeta;
  13964. };
  13965. class CRoxieServerNWayMergeActivityFactory : public CRoxieServerMultiInputFactory
  13966. {
  13967. public:
  13968. CRoxieServerNWayMergeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  13969. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  13970. {
  13971. }
  13972. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  13973. {
  13974. return new CRoxieServerNWayMergeActivity(this, _probeManager, numInputs());
  13975. }
  13976. };
  13977. IRoxieServerActivityFactory *createRoxieServerNWayMergeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  13978. {
  13979. return new CRoxieServerNWayMergeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  13980. }
  13981. //=================================================================================
  13982. class CRoxieServerNWayMergeJoinActivity : public CRoxieServerNaryActivity
  13983. {
  13984. public:
  13985. CRoxieServerNWayMergeJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs, CMergeJoinProcessor & _processor)
  13986. : CRoxieServerNaryActivity(_factory, _probeManager, _numInputs),processor(_processor),
  13987. helper((IHThorNWayMergeJoinArg &)basehelper)
  13988. {
  13989. }
  13990. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  13991. {
  13992. CRoxieServerNaryActivity::start(parentExtractSize, parentExtract, paused);
  13993. ForEachItemIn(i1, expandedInputs)
  13994. {
  13995. IRoxieInput * cur = expandedInputs.item(i1);
  13996. Owned<RoxieSteppedInput> stepInput = new RoxieSteppedInput(cur);
  13997. processor.addInput(stepInput);
  13998. }
  13999. ICodeContext * codectx = ctx->queryCodeContext();
  14000. Owned<IEngineRowAllocator> inputAllocator = codectx->getRowAllocator(helper.queryInputMeta(), activityId);
  14001. Owned<IEngineRowAllocator> outputAllocator = codectx->getRowAllocator(helper.queryOutputMeta(), activityId);
  14002. processor.beforeProcessing(inputAllocator, outputAllocator);
  14003. }
  14004. virtual void stop(bool aborting)
  14005. {
  14006. processor.afterProcessing();
  14007. CRoxieServerNaryActivity::stop(aborting);
  14008. }
  14009. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  14010. {
  14011. return processor.gatherConjunctions(collector);
  14012. }
  14013. virtual void resetEOF()
  14014. {
  14015. processor.queryResetEOF();
  14016. }
  14017. virtual const void * nextInGroup()
  14018. {
  14019. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14020. const void * next = processor.nextInGroup();
  14021. if (next)
  14022. processed++;
  14023. return next;
  14024. }
  14025. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  14026. {
  14027. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14028. const void * next = processor.nextGE(seek, numFields, wasCompleteMatch, stepExtra);
  14029. if (next)
  14030. processed++;
  14031. return next;
  14032. }
  14033. virtual IInputSteppingMeta * querySteppingMeta()
  14034. {
  14035. return processor.queryInputSteppingMeta();
  14036. }
  14037. protected:
  14038. IHThorNWayMergeJoinArg & helper;
  14039. CMergeJoinProcessor & processor;
  14040. };
  14041. class CRoxieServerAndMergeJoinActivity : public CRoxieServerNWayMergeJoinActivity
  14042. {
  14043. public:
  14044. CRoxieServerAndMergeJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  14045. : CRoxieServerNWayMergeJoinActivity(_factory, _probeManager, _numInputs, andProcessor), andProcessor(helper)
  14046. {
  14047. }
  14048. protected:
  14049. CAndMergeJoinProcessor andProcessor;
  14050. };
  14051. class CRoxieServerAndLeftMergeJoinActivity : public CRoxieServerNWayMergeJoinActivity
  14052. {
  14053. public:
  14054. CRoxieServerAndLeftMergeJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  14055. : CRoxieServerNWayMergeJoinActivity(_factory, _probeManager, _numInputs, andLeftProcessor), andLeftProcessor(helper)
  14056. {
  14057. }
  14058. protected:
  14059. CAndLeftMergeJoinProcessor andLeftProcessor;
  14060. };
  14061. class CRoxieServerMofNMergeJoinActivity : public CRoxieServerNWayMergeJoinActivity
  14062. {
  14063. public:
  14064. CRoxieServerMofNMergeJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  14065. : CRoxieServerNWayMergeJoinActivity(_factory, _probeManager, _numInputs, mofnProcessor), mofnProcessor(helper)
  14066. {
  14067. }
  14068. protected:
  14069. CMofNMergeJoinProcessor mofnProcessor;
  14070. };
  14071. class CRoxieServerProximityJoinActivity : public CRoxieServerNWayMergeJoinActivity
  14072. {
  14073. public:
  14074. CRoxieServerProximityJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  14075. : CRoxieServerNWayMergeJoinActivity(_factory, _probeManager, _numInputs, proximityProcessor), proximityProcessor(helper)
  14076. {
  14077. }
  14078. protected:
  14079. CProximityJoinProcessor proximityProcessor;
  14080. };
  14081. class CRoxieServerNWayMergeJoinActivityFactory : public CRoxieServerMultiInputFactory
  14082. {
  14083. unsigned flags;
  14084. public:
  14085. CRoxieServerNWayMergeJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14086. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  14087. {
  14088. Owned<IHThorNWayMergeJoinArg> helper = (IHThorNWayMergeJoinArg *) helperFactory();
  14089. flags = helper->getJoinFlags();
  14090. }
  14091. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14092. {
  14093. if (flags & IHThorNWayMergeJoinArg::MJFhasrange)
  14094. return new CRoxieServerProximityJoinActivity(this, _probeManager, numInputs());
  14095. switch (flags & IHThorNWayMergeJoinArg::MJFkindmask)
  14096. {
  14097. case IHThorNWayMergeJoinArg::MJFinner:
  14098. return new CRoxieServerAndMergeJoinActivity(this, _probeManager, numInputs());
  14099. case IHThorNWayMergeJoinArg::MJFleftonly:
  14100. case IHThorNWayMergeJoinArg::MJFleftouter:
  14101. return new CRoxieServerAndLeftMergeJoinActivity(this, _probeManager, numInputs());
  14102. case IHThorNWayMergeJoinArg::MJFmofn:
  14103. return new CRoxieServerMofNMergeJoinActivity(this, _probeManager, numInputs());
  14104. default:
  14105. throwUnexpected();
  14106. }
  14107. }
  14108. };
  14109. IRoxieServerActivityFactory *createRoxieServerNWayMergeJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14110. {
  14111. return new CRoxieServerNWayMergeJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  14112. }
  14113. //=================================================================================
  14114. class CRoxieServerNWaySelectActivity : public CRoxieServerMultiInputActivity
  14115. {
  14116. IHThorNWaySelectArg &helper;
  14117. public:
  14118. CRoxieServerNWaySelectActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  14119. : CRoxieServerMultiInputActivity(_factory, _probeManager, _numInputs),
  14120. helper((IHThorNWaySelectArg &)basehelper)
  14121. {
  14122. }
  14123. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14124. {
  14125. CRoxieServerMultiInputActivity::start(parentExtractSize, parentExtract, paused);
  14126. unsigned whichInput = helper.getInputIndex();
  14127. selectedInput = NULL;
  14128. if (whichInput--)
  14129. {
  14130. for (unsigned i=0; i < numInputs; i++)
  14131. {
  14132. IRoxieInput * cur = inputArray[i];
  14133. unsigned numRealInputs = cur->numConcreteOutputs();
  14134. if (whichInput < numRealInputs)
  14135. {
  14136. selectedInput = cur->queryConcreteInput(whichInput);
  14137. break;
  14138. }
  14139. whichInput -= numRealInputs;
  14140. }
  14141. }
  14142. }
  14143. virtual void reset()
  14144. {
  14145. selectedInput = NULL;
  14146. CRoxieServerMultiInputActivity::reset();
  14147. }
  14148. const void * nextInGroup()
  14149. {
  14150. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14151. if (!selectedInput)
  14152. return NULL;
  14153. return selectedInput->nextInGroup();
  14154. }
  14155. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  14156. {
  14157. if (!selectedInput)
  14158. return false;
  14159. return selectedInput->gatherConjunctions(collector);
  14160. }
  14161. virtual void resetEOF()
  14162. {
  14163. if (selectedInput)
  14164. selectedInput->resetEOF();
  14165. }
  14166. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  14167. {
  14168. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14169. if (!selectedInput)
  14170. return NULL;
  14171. return selectedInput->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  14172. }
  14173. IInputSteppingMeta * querySteppingMeta()
  14174. {
  14175. if (selectedInput)
  14176. return selectedInput->querySteppingMeta();
  14177. return NULL;
  14178. }
  14179. protected:
  14180. IRoxieInput * selectedInput;
  14181. };
  14182. class CRoxieServerNWaySelectActivityFactory : public CRoxieServerMultiInputFactory
  14183. {
  14184. public:
  14185. CRoxieServerNWaySelectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14186. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  14187. {
  14188. }
  14189. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14190. {
  14191. return new CRoxieServerNWaySelectActivity(this, _probeManager, numInputs());
  14192. }
  14193. };
  14194. IRoxieServerActivityFactory *createRoxieServerNWaySelectActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14195. {
  14196. return new CRoxieServerNWaySelectActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  14197. }
  14198. //=================================================================================
  14199. class CRoxieServerRemoteActivity : public CRoxieServerActivity, implements IRoxieServerErrorHandler
  14200. {
  14201. protected:
  14202. IHThorRemoteArg &helper;
  14203. CRemoteResultAdaptor remote;
  14204. public:
  14205. CRoxieServerRemoteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteID)
  14206. : CRoxieServerActivity(_factory, _probeManager),
  14207. helper((IHThorRemoteArg &)basehelper),
  14208. remote(_remoteID, meta.queryOriginal(), helper, *this, false, false) // MORE - if they need it stable we'll have to think!
  14209. {
  14210. }
  14211. virtual const IResolvedFile *queryVarFileInfo() const
  14212. {
  14213. return NULL;
  14214. }
  14215. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  14216. {
  14217. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  14218. remote.onCreate(this, this, _ctx, _colocalParent);
  14219. }
  14220. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14221. {
  14222. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  14223. remote.onStart(parentExtractSize, parentExtract);
  14224. remote.setLimits(helper.getRowLimit(), (unsigned __int64) -1, I64C(0x7FFFFFFFFFFFFFFF));
  14225. unsigned fileNo = 0; // MORE - superfiles require us to do this per file part... maybe (needs thought)
  14226. remote.getMem(0, fileNo, 0); // the cached context is all we need to send
  14227. remote.flush();
  14228. remote.senddone();
  14229. }
  14230. virtual void setInput(unsigned idx, IRoxieInput *_in)
  14231. {
  14232. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  14233. }
  14234. virtual IRoxieInput *queryOutput(unsigned idx)
  14235. {
  14236. if (idx==(unsigned)-1)
  14237. idx = 0;
  14238. return idx ? NULL: &remote;
  14239. }
  14240. virtual void reset()
  14241. {
  14242. processed = remote.processed;
  14243. remote.processed = 0;
  14244. CRoxieServerActivity::reset();
  14245. }
  14246. virtual void onLimitExceeded(bool isKeyed)
  14247. {
  14248. if (traceLevel > 4)
  14249. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  14250. helper.onLimitExceeded();
  14251. }
  14252. virtual const void *createLimitFailRow(bool isKeyed)
  14253. {
  14254. UNIMPLEMENTED; // MORE - is there an ONFAIL for a limit folded into a remote?
  14255. }
  14256. virtual const void *nextInGroup()
  14257. {
  14258. throwUnexpected(); // I am nobody's input
  14259. }
  14260. };
  14261. class CRoxieServerRemoteActivityFactory : public CRoxieServerActivityFactory
  14262. {
  14263. public:
  14264. RemoteActivityId remoteId;
  14265. bool isRoot;
  14266. CRoxieServerRemoteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, bool _isRoot)
  14267. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), remoteId(_remoteId), isRoot(_isRoot)
  14268. {
  14269. }
  14270. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14271. {
  14272. return new CRoxieServerRemoteActivity(this, _probeManager, remoteId);
  14273. }
  14274. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  14275. {
  14276. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for %s activity", getActivityText(kind));
  14277. }
  14278. virtual bool isSink() const
  14279. {
  14280. //I don't think the action version of this is implemented - but this would be the code
  14281. return isRoot && !meta.queryOriginal();
  14282. }
  14283. };
  14284. IRoxieServerActivityFactory *createRoxieServerRemoteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, bool _isRoot)
  14285. {
  14286. return new CRoxieServerRemoteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _isRoot);
  14287. }
  14288. //=================================================================================
  14289. class CRoxieServerIterateActivity : public CRoxieServerActivity
  14290. {
  14291. IHThorIterateArg &helper;
  14292. OwnedConstRoxieRow defaultRecord;
  14293. OwnedConstRoxieRow left;
  14294. OwnedConstRoxieRow right;
  14295. unsigned counter;
  14296. public:
  14297. CRoxieServerIterateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  14298. : CRoxieServerActivity(_factory, _probeManager),
  14299. helper((IHThorIterateArg &)basehelper)
  14300. {
  14301. counter = 0;
  14302. }
  14303. virtual bool needsAllocator() const { return true; }
  14304. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14305. {
  14306. counter = 0;
  14307. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  14308. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  14309. size32_t thisSize = helper.createDefault(rowBuilder);
  14310. defaultRecord.setown(rowBuilder.finalizeRowClear(thisSize));
  14311. }
  14312. virtual void reset()
  14313. {
  14314. defaultRecord.clear();
  14315. right.clear();
  14316. left.clear();
  14317. CRoxieServerActivity::reset();
  14318. }
  14319. virtual const void * nextInGroup()
  14320. {
  14321. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14322. loop
  14323. {
  14324. right.setown(input->nextInGroup());
  14325. if (!right)
  14326. {
  14327. bool skippedGroup = (left == NULL) && (counter > 0); //we have just skipped entire group, but shouldn't output a double null
  14328. left.clear();
  14329. counter = 0;
  14330. if (skippedGroup) continue;
  14331. return NULL;
  14332. }
  14333. try
  14334. {
  14335. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  14336. unsigned outSize = helper.transform(rowBuilder, left ? left : defaultRecord, right, ++counter);
  14337. if (outSize)
  14338. {
  14339. left.setown(rowBuilder.finalizeRowClear(outSize));
  14340. processed++;
  14341. return left.getLink();
  14342. }
  14343. }
  14344. catch (IException *E)
  14345. {
  14346. throw makeWrappedException(E);
  14347. }
  14348. }
  14349. }
  14350. };
  14351. class CRoxieServerIterateActivityFactory : public CRoxieServerActivityFactory
  14352. {
  14353. public:
  14354. CRoxieServerIterateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14355. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  14356. {
  14357. }
  14358. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14359. {
  14360. return new CRoxieServerIterateActivity(this, _probeManager);
  14361. }
  14362. };
  14363. IRoxieServerActivityFactory *createRoxieServerIterateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14364. {
  14365. return new CRoxieServerIterateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  14366. }
  14367. //=================================================================================
  14368. class CRoxieServerProcessActivity : public CRoxieServerActivity
  14369. {
  14370. IHThorProcessArg &helper;
  14371. OwnedConstRoxieRow curRight;
  14372. OwnedConstRoxieRow initialRight;
  14373. unsigned counter;
  14374. Owned<IEngineRowAllocator> rightRowAllocator;
  14375. public:
  14376. CRoxieServerProcessActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  14377. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorProcessArg &)basehelper)
  14378. {
  14379. counter = 0;
  14380. }
  14381. virtual bool needsAllocator() const { return true; }
  14382. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  14383. {
  14384. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  14385. rightRowAllocator.setown(ctx->queryCodeContext()->getRowAllocator(QUERYINTERFACE(helper.queryRightRecordSize(), IOutputMetaData), activityId));
  14386. }
  14387. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14388. {
  14389. counter = 0;
  14390. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  14391. RtlDynamicRowBuilder rowBuilder(rightRowAllocator);
  14392. size32_t thisSize = helper.createInitialRight(rowBuilder);
  14393. initialRight.setown(rowBuilder.finalizeRowClear(thisSize));
  14394. curRight.set(initialRight);
  14395. }
  14396. virtual const void * nextInGroup()
  14397. {
  14398. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14399. try
  14400. {
  14401. loop
  14402. {
  14403. const void * in = input->nextInGroup();
  14404. if (!in)
  14405. {
  14406. bool eog = (curRight != initialRight); // processed any records?
  14407. counter = 0;
  14408. curRight.set(initialRight);
  14409. if (eog)
  14410. return NULL;
  14411. in = input->nextInGroup();
  14412. if (!in)
  14413. return NULL;
  14414. }
  14415. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  14416. RtlDynamicRowBuilder rightRowBuilder(rightRowAllocator);
  14417. size32_t outSize = helper.transform(rowBuilder, rightRowBuilder, in, curRight, ++counter);
  14418. ReleaseRoxieRow(in);
  14419. if (outSize)
  14420. {
  14421. //MORE: This should be returned...
  14422. size32_t rightSize = rightRowAllocator->queryOutputMeta()->getRecordSize(rightRowBuilder.getSelf());
  14423. curRight.setown(rightRowBuilder.finalizeRowClear(rightSize));
  14424. processed++;
  14425. return rowBuilder.finalizeRowClear(outSize);
  14426. }
  14427. }
  14428. }
  14429. catch (IException *E)
  14430. {
  14431. throw makeWrappedException(E);
  14432. }
  14433. }
  14434. };
  14435. class CRoxieServerProcessActivityFactory : public CRoxieServerActivityFactory
  14436. {
  14437. public:
  14438. CRoxieServerProcessActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14439. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  14440. {
  14441. }
  14442. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14443. {
  14444. return new CRoxieServerProcessActivity(this, _probeManager);
  14445. }
  14446. };
  14447. IRoxieServerActivityFactory *createRoxieServerProcessActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14448. {
  14449. return new CRoxieServerProcessActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  14450. }
  14451. //=================================================================================
  14452. class CRoxieServerGroupActivity : public CRoxieServerActivity
  14453. {
  14454. IHThorGroupArg &helper;
  14455. bool endPending;
  14456. bool eof;
  14457. bool first;
  14458. const void *next;
  14459. public:
  14460. CRoxieServerGroupActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  14461. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorGroupArg &)basehelper)
  14462. {
  14463. next = NULL;
  14464. endPending = false;
  14465. eof = false;
  14466. first = true;
  14467. }
  14468. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14469. {
  14470. endPending = false;
  14471. eof = false;
  14472. first = true;
  14473. assertex(next == NULL);
  14474. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  14475. }
  14476. virtual void reset()
  14477. {
  14478. ReleaseClearRoxieRow(next);
  14479. CRoxieServerActivity::reset();
  14480. }
  14481. virtual const void * nextInGroup()
  14482. {
  14483. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14484. if (first)
  14485. {
  14486. next = input->nextInGroup();
  14487. first = false;
  14488. }
  14489. if (eof || endPending)
  14490. {
  14491. endPending = false;
  14492. return NULL;
  14493. }
  14494. const void * prev = next;
  14495. next = input->nextInGroup();
  14496. if (!next)
  14497. next = input->nextInGroup();
  14498. if (next)
  14499. {
  14500. assertex(prev);
  14501. if (!helper.isSameGroup(prev, next))
  14502. endPending = true;
  14503. }
  14504. else
  14505. eof = true;
  14506. if (prev)
  14507. processed++;
  14508. return prev;
  14509. }
  14510. };
  14511. class CRoxieServerGroupActivityFactory : public CRoxieServerActivityFactory
  14512. {
  14513. public:
  14514. CRoxieServerGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14515. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  14516. {
  14517. }
  14518. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14519. {
  14520. return new CRoxieServerGroupActivity(this, _probeManager);
  14521. }
  14522. };
  14523. IRoxieServerActivityFactory *createRoxieServerGroupActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14524. {
  14525. return new CRoxieServerGroupActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  14526. }
  14527. //=================================================================================
  14528. class CRoxieServerFirstNActivity : public CRoxieServerLateStartActivity
  14529. {
  14530. unsigned __int64 limit;
  14531. unsigned __int64 skip;
  14532. unsigned doneThisGroup;
  14533. IHThorFirstNArg &helper;
  14534. public:
  14535. CRoxieServerFirstNActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  14536. : CRoxieServerLateStartActivity(_factory, _probeManager), helper((IHThorFirstNArg &)basehelper)
  14537. {
  14538. doneThisGroup = 0;
  14539. limit = 0;
  14540. skip = 0;
  14541. }
  14542. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14543. {
  14544. doneThisGroup = 0;
  14545. CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
  14546. limit = helper.getLimit();
  14547. skip = helper.numToSkip();
  14548. lateStart(parentExtractSize, parentExtract, limit > 0);
  14549. if (limit + skip >= limit)
  14550. limit += skip;
  14551. }
  14552. const void * nextInGroup()
  14553. {
  14554. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14555. if (eof)
  14556. return NULL;
  14557. const void *ret;
  14558. loop
  14559. {
  14560. ret = input->nextInGroup();
  14561. if (!ret)
  14562. {
  14563. if (meta.isGrouped())
  14564. {
  14565. if (doneThisGroup > skip)
  14566. {
  14567. doneThisGroup = 0;
  14568. return NULL;
  14569. }
  14570. doneThisGroup = 0;
  14571. }
  14572. ret = input->nextInGroup();
  14573. if (!ret)
  14574. {
  14575. eof = true;
  14576. return NULL;
  14577. }
  14578. }
  14579. doneThisGroup++;
  14580. if (doneThisGroup > skip)
  14581. break;
  14582. ReleaseRoxieRow(ret);
  14583. }
  14584. if (doneThisGroup <= limit)
  14585. {
  14586. processed++;
  14587. return ret;
  14588. }
  14589. ReleaseRoxieRow(ret);
  14590. if (meta.isGrouped())
  14591. {
  14592. while ((ret = input->nextInGroup()) != NULL)
  14593. ReleaseRoxieRow(ret);
  14594. doneThisGroup = 0;
  14595. }
  14596. else
  14597. eof = true;
  14598. return NULL;
  14599. }
  14600. };
  14601. class CRoxieServerFirstNActivityFactory : public CRoxieServerActivityFactory
  14602. {
  14603. public:
  14604. CRoxieServerFirstNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14605. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  14606. {
  14607. }
  14608. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14609. {
  14610. return new CRoxieServerFirstNActivity(this, _probeManager);
  14611. }
  14612. };
  14613. IRoxieServerActivityFactory *createRoxieServerFirstNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14614. {
  14615. return new CRoxieServerFirstNActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  14616. }
  14617. //=================================================================================
  14618. class CRoxieServerSelectNActivity : public CRoxieServerActivity
  14619. {
  14620. bool done;
  14621. IHThorSelectNArg &helper;
  14622. public:
  14623. CRoxieServerSelectNActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  14624. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSelectNArg &)basehelper)
  14625. {
  14626. done = false;
  14627. }
  14628. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14629. {
  14630. done = false;
  14631. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  14632. }
  14633. const void *defaultRow()
  14634. {
  14635. if (!rowAllocator)
  14636. createRowAllocator(); // We delay as often not needed...
  14637. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  14638. size32_t thisSize = helper.createDefault(rowBuilder);
  14639. return rowBuilder.finalizeRowClear(thisSize);
  14640. }
  14641. virtual const void * nextInGroup()
  14642. {
  14643. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14644. if (done)
  14645. return NULL;
  14646. done = true;
  14647. processed++; // always going to return a row!
  14648. unsigned __int64 index = helper.getRowToSelect();
  14649. while (--index)
  14650. {
  14651. const void * next = input->nextInGroup();
  14652. if (!next)
  14653. next = input->nextInGroup();
  14654. if (!next)
  14655. return defaultRow();
  14656. ReleaseRoxieRow(next);
  14657. }
  14658. const void * next = input->nextInGroup();
  14659. if (!next)
  14660. next = input->nextInGroup();
  14661. if (!next)
  14662. next = defaultRow();
  14663. return next;
  14664. }
  14665. };
  14666. class CRoxieServerSelectNActivityFactory : public CRoxieServerActivityFactory
  14667. {
  14668. public:
  14669. CRoxieServerSelectNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14670. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  14671. {
  14672. }
  14673. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  14674. {
  14675. return new CRoxieServerSelectNActivity(this, _probeManager);
  14676. }
  14677. };
  14678. IRoxieServerActivityFactory *createRoxieServerSelectNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  14679. {
  14680. return new CRoxieServerSelectNActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  14681. }
  14682. //=================================================================================
  14683. class CRoxieServerSelfJoinActivity : public CRoxieServerActivity
  14684. {
  14685. IHThorJoinArg &helper;
  14686. ICompare *collate;
  14687. OwnedRowArray group;
  14688. bool matchedLeft;
  14689. BoolArray matchedRight;
  14690. bool eof;
  14691. bool first;
  14692. unsigned leftIndex;
  14693. unsigned rightIndex;
  14694. unsigned rightOuterIndex;
  14695. unsigned joinLimit;
  14696. unsigned atmostLimit;
  14697. unsigned abortLimit;
  14698. unsigned keepLimit;
  14699. bool leftOuterJoin;
  14700. bool rightOuterJoin;
  14701. bool exclude;
  14702. bool limitFail;
  14703. bool limitOnFail;
  14704. bool cloneLeft;
  14705. OwnedConstRoxieRow defaultLeft;
  14706. OwnedConstRoxieRow defaultRight;
  14707. OwnedConstRoxieRow lhs;
  14708. Owned<IException> failingLimit;
  14709. bool failingOuterAtmost;
  14710. Owned<IEngineRowAllocator> defaultAllocator;
  14711. Owned<IRHLimitedCompareHelper> limitedhelper;
  14712. Owned<CRHDualCache> dualcache;
  14713. IInputBase *dualCacheInput;
  14714. bool fillGroup()
  14715. {
  14716. group.clear();
  14717. matchedLeft = false;
  14718. matchedRight.kill();
  14719. failingOuterAtmost = false;
  14720. const void * next;
  14721. unsigned groupCount = 0;
  14722. while((next = input->nextInGroup()) != NULL)
  14723. {
  14724. if(groupCount==abortLimit)
  14725. {
  14726. if(limitFail)
  14727. failLimit(next);
  14728. if (ctx->queryDebugContext())
  14729. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  14730. if(limitOnFail)
  14731. {
  14732. assertex(!failingLimit);
  14733. try
  14734. {
  14735. failLimit(next);
  14736. }
  14737. catch(IException * except)
  14738. {
  14739. failingLimit.setown(except);
  14740. }
  14741. assertex(failingLimit != NULL);
  14742. group.append(next);
  14743. groupCount++;
  14744. break;
  14745. }
  14746. group.clear();
  14747. groupCount = 0;
  14748. while(next)
  14749. {
  14750. ReleaseRoxieRow(next);
  14751. next = input->nextInGroup();
  14752. }
  14753. }
  14754. else if(groupCount==atmostLimit)
  14755. {
  14756. if(leftOuterJoin)
  14757. {
  14758. group.append(next);
  14759. groupCount++;
  14760. failingOuterAtmost = true;
  14761. break;
  14762. }
  14763. else
  14764. {
  14765. group.clear();
  14766. groupCount = 0;
  14767. while (next)
  14768. {
  14769. ReleaseRoxieRow(next);
  14770. next = input->nextInGroup();
  14771. }
  14772. }
  14773. }
  14774. else
  14775. {
  14776. group.append(next);
  14777. groupCount++;
  14778. }
  14779. }
  14780. if(group.ordinality()==0)
  14781. {
  14782. eof = true;
  14783. return false;
  14784. }
  14785. leftIndex = 0;
  14786. rightIndex = 0;
  14787. rightOuterIndex = 0;
  14788. joinLimit = keepLimit;
  14789. ForEachItemIn(idx, group)
  14790. matchedRight.append(false);
  14791. return true;
  14792. }
  14793. void failLimit(const void * next)
  14794. {
  14795. helper.onMatchAbortLimitExceeded();
  14796. CommonXmlWriter xmlwrite(XWFtrim|XWFopt );
  14797. if (!ctx->isBlind() && input->queryOutputMeta() && input->queryOutputMeta()->hasXML())
  14798. {
  14799. input->queryOutputMeta()->toXML((byte *) next, xmlwrite);
  14800. }
  14801. throw MakeStringException(ROXIE_TOO_MANY_RESULTS, "More than %d match candidates in self-join %d for row %s", abortLimit, queryId(), xmlwrite.str());
  14802. }
  14803. virtual bool needsAllocator() const { return true; }
  14804. const void *joinRecords(const void * curLeft, const void * curRight, IException * except = NULL)
  14805. {
  14806. try
  14807. {
  14808. if (cloneLeft && !except)
  14809. {
  14810. LinkRoxieRow(curLeft);
  14811. return curLeft;
  14812. }
  14813. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  14814. size32_t outsize = except ? helper.onFailTransform(rowBuilder, curLeft, curRight, except) : helper.transform(rowBuilder, curLeft, curRight);
  14815. if (outsize)
  14816. return rowBuilder.finalizeRowClear(outsize);
  14817. else
  14818. return NULL;
  14819. }
  14820. catch (IException *E)
  14821. {
  14822. throw makeWrappedException(E);
  14823. }
  14824. }
  14825. void createDefaultLeft()
  14826. {
  14827. if (!defaultLeft)
  14828. {
  14829. if (!defaultAllocator)
  14830. defaultAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input->queryOutputMeta(), activityId));
  14831. RtlDynamicRowBuilder rowBuilder(defaultAllocator);
  14832. size32_t thisSize = helper.createDefaultLeft(rowBuilder);
  14833. defaultLeft.setown(rowBuilder.finalizeRowClear(thisSize));
  14834. }
  14835. }
  14836. void createDefaultRight()
  14837. {
  14838. if (!defaultRight)
  14839. {
  14840. if (!defaultAllocator)
  14841. defaultAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input->queryOutputMeta(), activityId));
  14842. RtlDynamicRowBuilder rowBuilder(defaultAllocator);
  14843. size32_t thisSize = helper.createDefaultRight(rowBuilder);
  14844. defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
  14845. }
  14846. }
  14847. public:
  14848. CRoxieServerSelfJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  14849. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorJoinArg &)basehelper)
  14850. {
  14851. collate = helper.queryCompareLeftRight();
  14852. eof = false;
  14853. first = true;
  14854. keepLimit = 0;
  14855. atmostLimit = 0;
  14856. unsigned joinFlags = helper.getJoinFlags();
  14857. leftOuterJoin = (joinFlags & JFleftouter) != 0;
  14858. rightOuterJoin = (joinFlags & JFrightouter) != 0;
  14859. cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
  14860. exclude = (joinFlags & JFexclude) != 0;
  14861. abortLimit = 0;
  14862. joinLimit = 0;
  14863. assertex((joinFlags & (JFfirst | JFfirstleft | JFfirstright)) == 0); // no longer supported
  14864. getLimitType(joinFlags, limitFail, limitOnFail);
  14865. if((joinFlags & JFslidingmatch) != 0)
  14866. throw MakeStringException(ROXIE_UNIMPLEMENTED_ERROR, "Internal Error: Sliding self join not supported");
  14867. failingOuterAtmost = false;
  14868. matchedLeft = false;
  14869. leftIndex = 0;
  14870. rightIndex = 0;
  14871. rightOuterIndex = 0;
  14872. dualCacheInput = NULL;
  14873. }
  14874. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  14875. {
  14876. eof = false;
  14877. first = true;
  14878. failingLimit.clear();
  14879. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  14880. keepLimit = helper.getKeepLimit();
  14881. if(keepLimit == 0)
  14882. keepLimit = (unsigned)-1;
  14883. atmostLimit = helper.getJoinLimit();
  14884. if(atmostLimit == 0)
  14885. atmostLimit = (unsigned)-1;
  14886. else
  14887. assertex(!rightOuterJoin);
  14888. abortLimit = helper.getMatchAbortLimit();
  14889. if (abortLimit == 0)
  14890. abortLimit = (unsigned)-1;
  14891. if (rightOuterJoin)
  14892. createDefaultLeft();
  14893. if (leftOuterJoin || limitOnFail)
  14894. createDefaultRight();
  14895. if ((helper.getJoinFlags() & JFlimitedprefixjoin) && helper.getJoinLimit())
  14896. { //limited match join (s[1..n])
  14897. dualcache.setown(new CRHDualCache());
  14898. dualcache->init(CRoxieServerActivity::input);
  14899. dualCacheInput = dualcache->queryOut1();
  14900. failingOuterAtmost = false;
  14901. matchedLeft = false;
  14902. leftIndex = 0;
  14903. rightOuterIndex = 0;
  14904. limitedhelper.setown(createRHLimitedCompareHelper());
  14905. limitedhelper->init( helper.getJoinLimit(), dualcache->queryOut2(), collate, helper.queryPrefixCompare() );
  14906. }
  14907. }
  14908. virtual void reset()
  14909. {
  14910. group.clear();
  14911. CRoxieServerActivity::reset();
  14912. defaultLeft.clear();
  14913. defaultRight.clear();
  14914. }
  14915. virtual const void * nextInGroup()
  14916. {
  14917. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  14918. if (limitedhelper)
  14919. {
  14920. while(!eof) //limited match join
  14921. {
  14922. if (!group.isItem(rightIndex))
  14923. {
  14924. lhs.setown(dualCacheInput->nextInGroup());
  14925. if (lhs)
  14926. {
  14927. rightIndex = 0;
  14928. group.clear();
  14929. limitedhelper->getGroup(group,lhs);
  14930. }
  14931. else
  14932. {
  14933. eof = true;
  14934. }
  14935. }
  14936. if (group.isItem(rightIndex))
  14937. {
  14938. const void * rhs = group.item(rightIndex++);
  14939. if(helper.match(lhs, rhs))
  14940. {
  14941. const void * ret = joinRecords(lhs, rhs);
  14942. return ret;
  14943. }
  14944. }
  14945. }
  14946. return NULL;
  14947. }
  14948. else
  14949. {
  14950. if (first)
  14951. {
  14952. first = false;
  14953. fillGroup();
  14954. }
  14955. while(!eof)
  14956. {
  14957. if(failingOuterAtmost)
  14958. while(group.isItem(leftIndex))
  14959. {
  14960. const void * ret = joinRecords(group.item(leftIndex++), defaultRight);
  14961. if(ret)
  14962. {
  14963. processed++;
  14964. return ret;
  14965. }
  14966. }
  14967. if((joinLimit == 0) || !group.isItem(rightIndex))
  14968. {
  14969. if(leftOuterJoin && !matchedLeft && !failingLimit)
  14970. {
  14971. const void * ret = joinRecords(group.item(leftIndex), defaultRight);
  14972. if(ret)
  14973. {
  14974. matchedLeft = true;
  14975. processed++;
  14976. return ret;
  14977. }
  14978. }
  14979. leftIndex++;
  14980. matchedLeft = false;
  14981. rightIndex = 0;
  14982. joinLimit = keepLimit;
  14983. }
  14984. if(!group.isItem(leftIndex))
  14985. {
  14986. if(failingLimit || failingOuterAtmost)
  14987. {
  14988. const void * lhs;
  14989. while((lhs = input->nextInGroup()) != NULL) // dualCache never active here
  14990. {
  14991. const void * ret = joinRecords(lhs, defaultRight, failingLimit);
  14992. ReleaseRoxieRow(lhs);
  14993. if(ret)
  14994. {
  14995. processed++;
  14996. return ret;
  14997. }
  14998. }
  14999. failingLimit.clear();
  15000. }
  15001. if(rightOuterJoin && !failingLimit)
  15002. while(group.isItem(rightOuterIndex))
  15003. if(!matchedRight.item(rightOuterIndex++))
  15004. {
  15005. const void * ret = joinRecords(defaultLeft, group.item(rightOuterIndex-1));
  15006. if(ret)
  15007. {
  15008. processed++;
  15009. return ret;
  15010. }
  15011. }
  15012. if(!fillGroup())
  15013. return NULL;
  15014. continue;
  15015. }
  15016. const void * lhs = group.item(leftIndex);
  15017. if(failingLimit)
  15018. {
  15019. leftIndex++;
  15020. const void * ret = joinRecords(lhs, defaultRight, failingLimit);
  15021. if(ret)
  15022. {
  15023. processed++;
  15024. return ret;
  15025. }
  15026. }
  15027. else
  15028. {
  15029. const void * rhs = group.item(rightIndex++);
  15030. if(helper.match(lhs, rhs))
  15031. {
  15032. matchedLeft = true;
  15033. matchedRight.replace(true, rightIndex-1);
  15034. if(!exclude)
  15035. {
  15036. const void * ret = joinRecords(lhs, rhs);
  15037. if(ret)
  15038. {
  15039. processed++;
  15040. joinLimit--;
  15041. return ret;
  15042. }
  15043. }
  15044. }
  15045. }
  15046. }
  15047. return NULL;
  15048. }
  15049. }
  15050. };
  15051. class CRoxieServerSelfJoinActivityFactory : public CRoxieServerActivityFactory
  15052. {
  15053. public:
  15054. CRoxieServerSelfJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  15055. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  15056. {
  15057. }
  15058. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  15059. {
  15060. return new CRoxieServerSelfJoinActivity(this, _probeManager);
  15061. }
  15062. };
  15063. IRoxieServerActivityFactory *createRoxieServerSelfJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  15064. {
  15065. return new CRoxieServerSelfJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  15066. }
  15067. //=====================================================================================================
  15068. class CRoxieServerLookupJoinActivity : public CRoxieServerTwoInputActivity
  15069. {
  15070. private:
  15071. class LookupTable : public CInterface
  15072. {
  15073. public:
  15074. LookupTable(unsigned _size, ICompare * _leftRightCompare, ICompare * _rightCompare, IHash * _leftHash, IHash * _rightHash, bool _dedupOnAdd)
  15075. : leftRightCompare(_leftRightCompare), rightCompare(_rightCompare), leftHash(_leftHash), rightHash(_rightHash), dedupOnAdd(_dedupOnAdd)
  15076. {
  15077. unsigned minsize = (4*_size)/3;
  15078. size = 2;
  15079. while((minsize >>= 1) > 0)
  15080. size <<= 1;
  15081. mask = size - 1;
  15082. table = (const void * *)calloc(size, sizeof(void *));
  15083. findex = BadIndex;
  15084. }
  15085. ~LookupTable()
  15086. {
  15087. unsigned i;
  15088. for(i=0; i<size; i++)
  15089. ReleaseRoxieRow(table[i]);
  15090. free(table);
  15091. }
  15092. void add(const void * right)
  15093. {
  15094. findex = BadIndex;
  15095. unsigned start = rightHash->hash(right) & mask;
  15096. unsigned index = start;
  15097. while(table[index])
  15098. {
  15099. if(dedupOnAdd && (rightCompare->docompare(table[index], right) == 0))
  15100. {
  15101. ReleaseRoxieRow(right);
  15102. return;
  15103. }
  15104. index++;
  15105. if(index==size)
  15106. index = 0;
  15107. if(index==start)
  15108. throwUnexpected(); //table is full, should never happen
  15109. }
  15110. table[index] = right;
  15111. }
  15112. const void *find(const void * left) const
  15113. {
  15114. fstart = leftHash->hash(left) & mask;
  15115. findex = fstart;
  15116. return doFind(left);
  15117. }
  15118. const void *findNext(const void * left) const
  15119. {
  15120. if(findex == BadIndex)
  15121. return NULL;
  15122. advance();
  15123. return doFind(left);
  15124. }
  15125. void advance() const
  15126. {
  15127. findex++;
  15128. if(findex==size)
  15129. findex = 0;
  15130. if(findex==fstart)
  15131. throw MakeStringException(ROXIE_JOIN_ERROR, "Internal error hthor lookup join activity (hash table full on lookup)");
  15132. }
  15133. const void *doFind(const void * left) const
  15134. {
  15135. while(table[findex])
  15136. {
  15137. if(leftRightCompare->docompare(left, table[findex]) == 0)
  15138. return table[findex];
  15139. advance();
  15140. }
  15141. findex = BadIndex;
  15142. return NULL;
  15143. }
  15144. private:
  15145. ICompare * leftRightCompare;
  15146. ICompare * rightCompare;
  15147. IHash * leftHash;
  15148. IHash * rightHash;
  15149. unsigned size;
  15150. unsigned mask;
  15151. const void * * table;
  15152. bool dedupOnAdd;
  15153. unsigned mutable fstart;
  15154. unsigned mutable findex;
  15155. static unsigned const BadIndex;
  15156. };
  15157. IHThorHashJoinArg &helper;
  15158. bool leftOuterJoin;
  15159. bool exclude;
  15160. bool eog;
  15161. bool many;
  15162. bool dedupRHS;
  15163. bool matchedGroup;
  15164. const void *left;
  15165. OwnedConstRoxieRow defaultRight;
  15166. Owned<LookupTable> table;
  15167. unsigned keepLimit;
  15168. unsigned atmostLimit;
  15169. unsigned limitLimit;
  15170. bool limitFail;
  15171. bool limitOnFail;
  15172. bool hasGroupLimit;
  15173. unsigned keepCount;
  15174. bool gotMatch;
  15175. bool cloneLeft;
  15176. ConstPointerArray rightGroup;
  15177. aindex_t rightGroupIndex;
  15178. Owned<IException> failingLimit;
  15179. ConstPointerArray filteredRight;
  15180. ThorActivityKind activityKind;
  15181. Owned<IEngineRowAllocator> defaultRightAllocator;
  15182. void createDefaultRight()
  15183. {
  15184. if (!defaultRight)
  15185. {
  15186. if (!defaultRightAllocator)
  15187. defaultRightAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input1->queryOutputMeta(), activityId));
  15188. RtlDynamicRowBuilder rowBuilder(defaultRightAllocator);
  15189. size32_t thisSize = helper.createDefaultRight(rowBuilder);
  15190. defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
  15191. }
  15192. }
  15193. public:
  15194. CRoxieServerLookupJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  15195. : CRoxieServerTwoInputActivity(_factory, _probeManager), helper((IHThorHashJoinArg &)basehelper)
  15196. {
  15197. unsigned joinFlags = helper.getJoinFlags();
  15198. leftOuterJoin = (joinFlags & JFleftouter) != 0;
  15199. assertex((joinFlags & JFrightouter) == 0);
  15200. exclude = (joinFlags & JFexclude) != 0;
  15201. many = (joinFlags & JFmanylookup) != 0;
  15202. cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
  15203. dedupRHS = (joinFlags & (JFmanylookup | JFmatchrequired | JFtransformMaySkip)) == 0; // optimisation: can implicitly dedup RHS unless is many lookup, or match required, or transform may skip
  15204. left = NULL;
  15205. activityKind = factory->getKind();
  15206. eog = false;
  15207. matchedGroup = false;
  15208. gotMatch = false;
  15209. keepLimit = 0;
  15210. keepCount = 0;
  15211. atmostLimit = 0;
  15212. limitLimit = 0;
  15213. hasGroupLimit = false;
  15214. getLimitType(helper.getJoinFlags(), limitFail, limitOnFail);
  15215. }
  15216. void loadRight()
  15217. {
  15218. ConstPointerArray rightset;
  15219. unsigned i = 0;
  15220. try
  15221. {
  15222. const void * next;
  15223. while(true)
  15224. {
  15225. next = input1->nextInGroup();
  15226. if(!next)
  15227. next = input1->nextInGroup();
  15228. if(!next)
  15229. break;
  15230. rightset.append(next);
  15231. }
  15232. unsigned rightord = rightset.ordinality();
  15233. table.setown(new LookupTable(rightord, helper.queryCompareLeftRight(), helper.queryCompareRight(), helper.queryHashLeft(), helper.queryHashRight(), dedupRHS));
  15234. for(i=0; i<rightord; i++)
  15235. table->add(rightset.item(i));
  15236. }
  15237. catch (...)
  15238. {
  15239. unsigned rightord = rightset.ordinality();
  15240. for ( ; i<rightord; i++)
  15241. ReleaseRoxieRow(rightset.item(i));
  15242. throw;
  15243. }
  15244. };
  15245. virtual void reset()
  15246. {
  15247. CRoxieServerTwoInputActivity::reset();
  15248. ReleaseClearRoxieRow(left);
  15249. defaultRight.clear();
  15250. table.clear();
  15251. }
  15252. virtual bool needsAllocator() const { return true; }
  15253. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  15254. {
  15255. eog = false;
  15256. matchedGroup = false;
  15257. left = NULL;
  15258. CRoxieServerTwoInputActivity::start(parentExtractSize, parentExtract, paused);
  15259. keepLimit = helper.getKeepLimit();
  15260. if(keepLimit==0) keepLimit = static_cast<unsigned>(-1);
  15261. atmostLimit = helper.getJoinLimit();
  15262. limitLimit = helper.getMatchAbortLimit();
  15263. hasGroupLimit = ((atmostLimit > 0) || (limitLimit > 0));
  15264. if(atmostLimit==0) atmostLimit = static_cast<unsigned>(-1);
  15265. if(limitLimit==0) limitLimit = static_cast<unsigned>(-1);
  15266. getLimitType(helper.getJoinFlags(), limitFail, limitOnFail);
  15267. if (((activityKind==TAKlookupjoin || activityKind==TAKlookupdenormalizegroup) && leftOuterJoin) || limitOnFail)
  15268. createDefaultRight();
  15269. }
  15270. virtual void setInput(unsigned idx, IRoxieInput *_in)
  15271. {
  15272. if (idx==1)
  15273. input1 = _in;
  15274. else
  15275. {
  15276. if ((helper.getJoinFlags() & JFparallel) != 0)
  15277. {
  15278. puller.setown(new CRoxieServerReadAheadInput(0)); // MORE - cant ask context for parallelJoinPreload as context is not yet set up.
  15279. puller->setInput(0, _in);
  15280. _in = puller;
  15281. }
  15282. CRoxieServerActivity::setInput(idx, _in);
  15283. }
  15284. }
  15285. virtual const void * nextInGroup()
  15286. {
  15287. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  15288. if(!table)
  15289. loadRight();
  15290. switch (activityKind)
  15291. {
  15292. case TAKlookupjoin:
  15293. return nextInGroupJoin();
  15294. case TAKlookupdenormalize:
  15295. case TAKlookupdenormalizegroup:
  15296. return nextInGroupDenormalize();
  15297. }
  15298. throwUnexpected();
  15299. }
  15300. private:
  15301. const void * nextInGroupJoin()
  15302. {
  15303. if(!table)
  15304. loadRight();
  15305. while(true)
  15306. {
  15307. const void * right = NULL;
  15308. if(!left)
  15309. {
  15310. left = input->nextInGroup();
  15311. keepCount = keepLimit;
  15312. if(!left)
  15313. {
  15314. if(matchedGroup || eog)
  15315. {
  15316. matchedGroup = false;
  15317. eog = true;
  15318. return NULL;
  15319. }
  15320. eog = true;
  15321. continue;
  15322. }
  15323. eog = false;
  15324. gotMatch = false;
  15325. right = getRightFirst();
  15326. }
  15327. else
  15328. right = getRightNext();
  15329. const void * ret = NULL;
  15330. if(failingLimit)
  15331. {
  15332. ret = joinException(left, failingLimit);
  15333. }
  15334. else
  15335. {
  15336. while(right)
  15337. {
  15338. if(helper.match(left, right))
  15339. {
  15340. gotMatch = true;
  15341. if(exclude)
  15342. break;
  15343. ret = joinRecords(left, right);
  15344. if(ret)
  15345. break;
  15346. }
  15347. right = getRightNext();
  15348. ret = NULL;
  15349. }
  15350. if(leftOuterJoin && !gotMatch)
  15351. {
  15352. ret = joinRecords(left, defaultRight);
  15353. gotMatch = true;
  15354. }
  15355. }
  15356. if(ret)
  15357. {
  15358. matchedGroup = true;
  15359. processed++;
  15360. if(!many || (--keepCount == 0) || failingLimit)
  15361. {
  15362. ReleaseClearRoxieRow(left);
  15363. failingLimit.clear();
  15364. }
  15365. return ret;
  15366. }
  15367. ReleaseClearRoxieRow(left);
  15368. }
  15369. }
  15370. const void * nextInGroupDenormalize()
  15371. {
  15372. while(true)
  15373. {
  15374. left = input->nextInGroup();
  15375. if(!left)
  15376. {
  15377. if (!matchedGroup)
  15378. left = input->nextInGroup();
  15379. if (!left)
  15380. {
  15381. matchedGroup = false;
  15382. return NULL;
  15383. }
  15384. }
  15385. gotMatch = false;
  15386. const void * right = getRightFirst();
  15387. const void * ret = NULL;
  15388. if (failingLimit)
  15389. ret = joinException(left, failingLimit);
  15390. else if (activityKind == TAKlookupdenormalize)
  15391. {
  15392. OwnedConstRoxieRow newLeft;
  15393. newLeft.set(left);
  15394. unsigned rowSize = 0;
  15395. unsigned leftCount = 0;
  15396. keepCount = keepLimit;
  15397. while (right)
  15398. {
  15399. try
  15400. {
  15401. if (helper.match(left, right))
  15402. {
  15403. gotMatch = true;
  15404. if (exclude)
  15405. break;
  15406. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  15407. unsigned thisSize = helper.transform(rowBuilder, newLeft, right, ++leftCount);
  15408. if (thisSize)
  15409. {
  15410. rowSize = thisSize;
  15411. newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
  15412. }
  15413. if(!many || (--keepCount == 0))
  15414. break;
  15415. }
  15416. right = getRightNext();
  15417. }
  15418. catch (IException *E)
  15419. {
  15420. throw makeWrappedException(E);
  15421. }
  15422. }
  15423. if (rowSize)
  15424. ret = newLeft.getClear();
  15425. else if (leftOuterJoin && !gotMatch)
  15426. {
  15427. ret = left;
  15428. left = NULL;
  15429. }
  15430. }
  15431. else
  15432. {
  15433. filteredRight.kill();
  15434. keepCount = keepLimit;
  15435. while (right)
  15436. {
  15437. if (helper.match(left, right))
  15438. {
  15439. gotMatch = true;
  15440. if(exclude)
  15441. break;
  15442. filteredRight.append(right);
  15443. if(!many || (--keepCount == 0))
  15444. break;
  15445. }
  15446. right = getRightNext();
  15447. }
  15448. if((filteredRight.ordinality() > 0) || (leftOuterJoin && !gotMatch))
  15449. ret = denormalizeRecords(left, filteredRight);
  15450. filteredRight.kill();
  15451. }
  15452. ReleaseRoxieRow(left);
  15453. left = NULL;
  15454. failingLimit.clear();
  15455. if(ret)
  15456. {
  15457. matchedGroup = true;
  15458. processed++;
  15459. return ret;
  15460. }
  15461. }
  15462. }
  15463. const void * joinRecords(const void * left, const void * right)
  15464. {
  15465. if (cloneLeft)
  15466. {
  15467. LinkRoxieRow(left);
  15468. return left;
  15469. }
  15470. try
  15471. {
  15472. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  15473. unsigned outSize = helper.transform(rowBuilder, left, right);
  15474. if (outSize)
  15475. return rowBuilder.finalizeRowClear(outSize);
  15476. else
  15477. return NULL;
  15478. }
  15479. catch (IException *E)
  15480. {
  15481. throw makeWrappedException(E);
  15482. }
  15483. }
  15484. const void * joinException(const void * left, IException * except)
  15485. {
  15486. try
  15487. {
  15488. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  15489. unsigned outSize = helper.onFailTransform(rowBuilder, left, defaultRight, except);
  15490. if (outSize)
  15491. return rowBuilder.finalizeRowClear(outSize);
  15492. else
  15493. return NULL;
  15494. }
  15495. catch (IException *E)
  15496. {
  15497. throw makeWrappedException(E);
  15498. }
  15499. }
  15500. const void * denormalizeRecords(const void * left, ConstPointerArray & rows)
  15501. {
  15502. try
  15503. {
  15504. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  15505. unsigned numRows = rows.ordinality();
  15506. const void * right = numRows ? rows.item(0) : defaultRight.get();
  15507. unsigned outSize = helper.transform(rowBuilder, left, right, numRows, (const void * *)rows.getArray());
  15508. if (outSize)
  15509. return rowBuilder.finalizeRowClear(outSize);
  15510. else
  15511. return NULL;
  15512. }
  15513. catch (IException *E)
  15514. {
  15515. throw makeWrappedException(E);
  15516. }
  15517. }
  15518. const void * getRightFirst() { if(hasGroupLimit) return fillRightGroup(); else return table->find(left); }
  15519. const void * getRightNext() { if(hasGroupLimit) return readRightGroup(); else return table->findNext(left); }
  15520. const void * readRightGroup() { if(rightGroup.isItem(rightGroupIndex)) return rightGroup.item(rightGroupIndex++); else return NULL; }
  15521. const void *fillRightGroup()
  15522. {
  15523. rightGroup.kill();
  15524. for(const void * right = table->find(left); right; right = table->findNext(left))
  15525. {
  15526. rightGroup.append(right);
  15527. if(rightGroup.ordinality() > limitLimit)
  15528. {
  15529. if(limitFail)
  15530. failLimit();
  15531. gotMatch = true;
  15532. if (ctx->queryDebugContext())
  15533. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  15534. if(limitOnFail)
  15535. {
  15536. assertex(!failingLimit);
  15537. try
  15538. {
  15539. failLimit();
  15540. }
  15541. catch(IException * e)
  15542. {
  15543. failingLimit.setown(e);
  15544. }
  15545. assertex(failingLimit != NULL);
  15546. }
  15547. else
  15548. {
  15549. rightGroup.kill();
  15550. }
  15551. break;
  15552. }
  15553. if(rightGroup.ordinality() > atmostLimit)
  15554. {
  15555. rightGroup.kill();
  15556. break;
  15557. }
  15558. }
  15559. rightGroupIndex = 0;
  15560. return readRightGroup();
  15561. }
  15562. void failLimit()
  15563. {
  15564. helper.onMatchAbortLimitExceeded();
  15565. CommonXmlWriter xmlwrite(XWFtrim|XWFopt );
  15566. if(!ctx->isBlind() && input->queryOutputMeta() && input->queryOutputMeta()->hasXML())
  15567. {
  15568. input->queryOutputMeta()->toXML(static_cast<const unsigned char *>(left), xmlwrite);
  15569. }
  15570. throw MakeStringException(ROXIE_TOO_MANY_RESULTS, "More than %u match candidates in join %d for row %s", limitLimit, queryId(), xmlwrite.str());
  15571. }
  15572. };
  15573. unsigned const CRoxieServerLookupJoinActivity::LookupTable::BadIndex(static_cast<unsigned>(-1));
  15574. class CRoxieServerLookupJoinActivityFactory : public CRoxieServerJoinActivityFactory
  15575. {
  15576. public:
  15577. CRoxieServerLookupJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  15578. : CRoxieServerJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  15579. {
  15580. Owned<IHThorHashJoinArg> helper = (IHThorHashJoinArg *) helperFactory();
  15581. if((helper->getJoinFlags() & (JFfirst | JFfirstleft | JFfirstright | JFslidingmatch)) != 0)
  15582. throw MakeStringException(ROXIE_INVALID_FLAGS, "Invalid flags for lookup join activity"); // code generator should never create such an activity
  15583. }
  15584. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  15585. {
  15586. return new CRoxieServerLookupJoinActivity(this, _probeManager);
  15587. }
  15588. };
  15589. IRoxieServerActivityFactory *createRoxieServerLookupJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  15590. {
  15591. return new CRoxieServerLookupJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  15592. }
  15593. //=====================================================================================================
  15594. class CRoxieServerAllJoinActivity : public CRoxieServerTwoInputActivity
  15595. {
  15596. private:
  15597. IHThorAllJoinArg &helper;
  15598. bool leftOuterJoin;
  15599. bool rightOuterJoin;
  15600. bool exclude;
  15601. OwnedConstRoxieRow defaultRight;
  15602. OwnedConstRoxieRow defaultLeft;
  15603. Owned<IEngineRowAllocator> defaultRightAllocator;
  15604. Owned<IEngineRowAllocator> defaultLeftAllocator;
  15605. const void *left;
  15606. unsigned countForLeft;
  15607. ConstPointerArray rightset;
  15608. BoolArray matchedRight; // MORE - could use a bitset...
  15609. unsigned keepLimit;
  15610. bool started;
  15611. bool eog;
  15612. bool eos;
  15613. bool matchedLeft;
  15614. bool matchedGroup;
  15615. bool leftIsGrouped;
  15616. bool cloneLeft;
  15617. unsigned rightIndex;
  15618. unsigned rightOrdinality;
  15619. ThorActivityKind activityKind;
  15620. ConstPointerArray filteredRight;
  15621. void createDefaultLeft()
  15622. {
  15623. if (!defaultLeft)
  15624. {
  15625. if (!defaultLeftAllocator)
  15626. defaultLeftAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input->queryOutputMeta(), activityId));
  15627. RtlDynamicRowBuilder rowBuilder(defaultLeftAllocator);
  15628. size32_t thisSize = helper.createDefaultLeft(rowBuilder);
  15629. defaultLeft.setown(rowBuilder.finalizeRowClear(thisSize));
  15630. }
  15631. }
  15632. void createDefaultRight()
  15633. {
  15634. if (!defaultRight)
  15635. {
  15636. if (!defaultRightAllocator)
  15637. defaultRightAllocator.setown(ctx->queryCodeContext()->getRowAllocator(input1->queryOutputMeta(), activityId));
  15638. RtlDynamicRowBuilder rowBuilder(defaultRightAllocator);
  15639. size32_t thisSize = helper.createDefaultRight(rowBuilder);
  15640. defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
  15641. }
  15642. }
  15643. public:
  15644. CRoxieServerAllJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  15645. : CRoxieServerTwoInputActivity(_factory, _probeManager), helper((IHThorAllJoinArg &)basehelper)
  15646. {
  15647. unsigned joinFlags = helper.getJoinFlags();
  15648. leftOuterJoin = (joinFlags & JFleftouter) != 0;
  15649. rightOuterJoin = (joinFlags & JFrightouter) != 0;
  15650. cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
  15651. keepLimit = (unsigned) -1;
  15652. exclude = (joinFlags & JFexclude) != 0;
  15653. left = NULL;
  15654. started = true;
  15655. eog = false;
  15656. eos = false;
  15657. matchedLeft = false;
  15658. matchedGroup = false;
  15659. activityKind = factory->getKind();
  15660. rightIndex = 0;
  15661. rightOrdinality = 0;
  15662. leftIsGrouped = false;
  15663. countForLeft = 0;
  15664. }
  15665. virtual void reset()
  15666. {
  15667. defaultRight.clear();
  15668. defaultLeft.clear();
  15669. ReleaseRoxieRowSet(rightset);
  15670. matchedRight.kill();
  15671. CRoxieServerTwoInputActivity::reset();
  15672. }
  15673. virtual bool needsAllocator() const { return true; }
  15674. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  15675. {
  15676. eog = false;
  15677. eos = false;
  15678. matchedLeft = false;
  15679. matchedGroup = false;
  15680. started = false;
  15681. left = NULL;
  15682. CRoxieServerTwoInputActivity::start(parentExtractSize, parentExtract, paused);
  15683. keepLimit = helper.getKeepLimit();
  15684. if(keepLimit==0)
  15685. keepLimit = (unsigned) -1;
  15686. countForLeft = keepLimit;
  15687. leftIsGrouped = input->queryOutputMeta()->isGrouped();
  15688. if((activityKind==TAKalljoin || activityKind==TAKalldenormalizegroup) && leftOuterJoin)
  15689. createDefaultRight();
  15690. if(rightOuterJoin)
  15691. createDefaultLeft();
  15692. }
  15693. void loadRight()
  15694. {
  15695. const void * next;
  15696. while(true)
  15697. {
  15698. next = input1->nextInGroup();
  15699. if(!next)
  15700. next = input1->nextInGroup();
  15701. if(!next)
  15702. break;
  15703. rightset.append(next);
  15704. matchedRight.append(false);
  15705. }
  15706. rightIndex = 0;
  15707. rightOrdinality = rightset.ordinality();
  15708. }
  15709. virtual void setInput(unsigned idx, IRoxieInput *_in)
  15710. {
  15711. if (idx==1)
  15712. input1 = _in;
  15713. else
  15714. {
  15715. if ((helper.getJoinFlags() & JFparallel) != 0)
  15716. {
  15717. puller.setown(new CRoxieServerReadAheadInput(0)); // MORE - cant ask context for parallelJoinPreload as context is not yet set up.
  15718. puller->setInput(0, _in);
  15719. _in = puller;
  15720. }
  15721. CRoxieServerActivity::setInput(idx, _in);
  15722. }
  15723. }
  15724. const void * joinRecords(const void * left, const void * right)
  15725. {
  15726. // MORE - could share some code with lookup join
  15727. if (cloneLeft)
  15728. {
  15729. LinkRoxieRow(left);
  15730. return left;
  15731. }
  15732. try
  15733. {
  15734. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  15735. unsigned outSize = helper.transform(rowBuilder, left, right);
  15736. if (outSize)
  15737. return rowBuilder.finalizeRowClear(outSize);
  15738. else
  15739. return NULL;
  15740. }
  15741. catch (IException *E)
  15742. {
  15743. throw makeWrappedException(E);
  15744. }
  15745. }
  15746. const void * denormalizeRecords(const void * curLeft, ConstPointerArray & rows)
  15747. {
  15748. try
  15749. {
  15750. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  15751. unsigned numRows = rows.ordinality();
  15752. const void * right = numRows ? rows.item(0) : defaultRight.get();
  15753. unsigned outSize = helper.transform(rowBuilder, curLeft, right, numRows, rows.getArray());
  15754. if (outSize)
  15755. return rowBuilder.finalizeRowClear(outSize);
  15756. else
  15757. return NULL;
  15758. }
  15759. catch (IException *E)
  15760. {
  15761. throw makeWrappedException(E);
  15762. }
  15763. }
  15764. virtual const void *nextInGroup()
  15765. {
  15766. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  15767. if(!started)
  15768. {
  15769. started = true;
  15770. left = input->nextInGroup();
  15771. matchedLeft = false;
  15772. countForLeft = keepLimit;
  15773. if((left == NULL))
  15774. {
  15775. eos = true;
  15776. return NULL;
  15777. }
  15778. loadRight();
  15779. }
  15780. const void * ret;
  15781. const void * right;
  15782. if(eos)
  15783. return NULL;
  15784. while(true)
  15785. {
  15786. ret = NULL;
  15787. if((rightIndex == rightOrdinality) || (countForLeft==0))
  15788. {
  15789. if(leftOuterJoin && left && !matchedLeft)
  15790. {
  15791. switch(activityKind)
  15792. {
  15793. case TAKalljoin:
  15794. ret = joinRecords(left, defaultRight);
  15795. break;
  15796. case TAKalldenormalize:
  15797. ret = left;
  15798. left = NULL;
  15799. break;
  15800. case TAKalldenormalizegroup:
  15801. filteredRight.kill();
  15802. ret = denormalizeRecords(left, filteredRight);
  15803. break;
  15804. default:
  15805. throwUnexpected();
  15806. }
  15807. }
  15808. rightIndex = 0;
  15809. ReleaseRoxieRow(left);
  15810. left = NULL;
  15811. if(ret)
  15812. {
  15813. matchedGroup = true;
  15814. processed++;
  15815. return ret;
  15816. }
  15817. }
  15818. if(!left)
  15819. {
  15820. left = input->nextInGroup();
  15821. matchedLeft = false;
  15822. countForLeft = keepLimit;
  15823. }
  15824. if(!left)
  15825. {
  15826. if(eog)
  15827. {
  15828. eos = true;
  15829. matchedGroup = false;
  15830. return NULL;
  15831. }
  15832. eog = true;
  15833. if (matchedGroup && leftIsGrouped)
  15834. {
  15835. matchedGroup = false;
  15836. return NULL;
  15837. }
  15838. matchedGroup = false;
  15839. continue;
  15840. }
  15841. eog = false;
  15842. switch(activityKind)
  15843. {
  15844. case TAKalljoin:
  15845. while(rightIndex < rightOrdinality)
  15846. {
  15847. right = rightset.item(rightIndex);
  15848. if(helper.match(left, right))
  15849. {
  15850. matchedLeft = true;
  15851. matchedRight.replace(true, rightIndex);
  15852. if(!exclude)
  15853. ret = joinRecords(left, right);
  15854. }
  15855. rightIndex++;
  15856. if(ret)
  15857. {
  15858. countForLeft--;
  15859. matchedGroup = true;
  15860. processed++;
  15861. return ret;
  15862. }
  15863. }
  15864. break;
  15865. case TAKalldenormalize:
  15866. {
  15867. OwnedConstRoxieRow newLeft;
  15868. newLeft.set(left);
  15869. unsigned rowSize = 0;
  15870. unsigned leftCount = 0;
  15871. while((rightIndex < rightOrdinality) && countForLeft)
  15872. {
  15873. right = rightset.item(rightIndex);
  15874. if(helper.match(left, right))
  15875. {
  15876. matchedLeft = true;
  15877. matchedRight.replace(true, rightIndex);
  15878. if(!exclude)
  15879. {
  15880. try
  15881. {
  15882. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  15883. unsigned thisSize = helper.transform(rowBuilder, newLeft, right, ++leftCount);
  15884. if(thisSize)
  15885. {
  15886. rowSize = thisSize;
  15887. newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
  15888. --countForLeft;
  15889. }
  15890. }
  15891. catch (IException *e)
  15892. {
  15893. throw makeWrappedException(e);
  15894. }
  15895. }
  15896. }
  15897. rightIndex++;
  15898. }
  15899. if(rowSize)
  15900. {
  15901. processed++;
  15902. return newLeft.getClear();
  15903. }
  15904. }
  15905. break;
  15906. case TAKalldenormalizegroup:
  15907. filteredRight.kill();
  15908. while((rightIndex < rightOrdinality) && countForLeft)
  15909. {
  15910. right = rightset.item(rightIndex);
  15911. if(helper.match(left, right))
  15912. {
  15913. matchedLeft = true;
  15914. matchedRight.replace(true, rightIndex);
  15915. filteredRight.append(right);
  15916. --countForLeft;
  15917. }
  15918. ++rightIndex;
  15919. }
  15920. if(!exclude && filteredRight.ordinality())
  15921. {
  15922. ret = denormalizeRecords(left, filteredRight);
  15923. filteredRight.kill();
  15924. if(ret)
  15925. {
  15926. processed++;
  15927. return ret;
  15928. }
  15929. }
  15930. break;
  15931. default:
  15932. throwUnexpected();
  15933. }
  15934. }
  15935. }
  15936. };
  15937. class CRoxieServerAllJoinActivityFactory : public CRoxieServerJoinActivityFactory
  15938. {
  15939. public:
  15940. CRoxieServerAllJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  15941. : CRoxieServerJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  15942. {
  15943. Owned<IHThorAllJoinArg> helper = (IHThorAllJoinArg *) helperFactory();
  15944. if((helper->getJoinFlags() & (JFfirst | JFfirstleft | JFfirstright)) != 0)
  15945. throw MakeStringException(ROXIE_INVALID_FLAGS, "Invalid flags for join all activity"); // code generator should never create such an activity
  15946. }
  15947. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  15948. {
  15949. return new CRoxieServerAllJoinActivity(this, _probeManager);
  15950. }
  15951. };
  15952. IRoxieServerActivityFactory *createRoxieServerAllJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  15953. {
  15954. return new CRoxieServerAllJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  15955. }
  15956. //=====================================================================================================
  15957. class CRoxieServerTopNActivity : public CRoxieServerLateStartActivity
  15958. {
  15959. unsigned limit;
  15960. bool hasBest;
  15961. bool eoi;
  15962. const void **sorted;
  15963. unsigned sortedCount;
  15964. unsigned curIndex;
  15965. IHThorTopNArg &helper;
  15966. ICompare &compare;
  15967. public:
  15968. CRoxieServerTopNActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  15969. : CRoxieServerLateStartActivity(_factory, _probeManager), helper((IHThorTopNArg &)basehelper), compare(*helper.queryCompare())
  15970. {
  15971. sorted = NULL;
  15972. sortedCount = 0;
  15973. curIndex = 0;
  15974. limit = 0;
  15975. eoi = false;
  15976. hasBest = false;
  15977. }
  15978. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  15979. {
  15980. assertex(sorted == NULL);
  15981. sortedCount = 0;
  15982. curIndex = 0;
  15983. eoi = false;
  15984. CRoxieServerLateStartActivity::start(parentExtractSize, parentExtract, paused);
  15985. limit = (unsigned) helper.getLimit();
  15986. hasBest = helper.hasBest();
  15987. lateStart(parentExtractSize, parentExtract, limit > 0);
  15988. // MORE - should we use an expanding array instead?
  15989. if (limit > 0)
  15990. sorted = (const void **) ctx->queryRowManager().allocate((limit+1) * sizeof(const void *), activityId);
  15991. }
  15992. virtual void reset()
  15993. {
  15994. if (sorted)
  15995. {
  15996. while(curIndex < sortedCount)
  15997. ReleaseRoxieRow(sorted[curIndex++]);
  15998. ReleaseRoxieRow(sorted);
  15999. }
  16000. sorted = NULL;
  16001. CRoxieServerLateStartActivity::reset();
  16002. }
  16003. bool abortEarly()
  16004. {
  16005. if (hasBest && (sortedCount == limit))
  16006. {
  16007. int compare = helper.compareBest(sorted[sortedCount-1]);
  16008. if (compare == 0)
  16009. {
  16010. if (meta.isGrouped())
  16011. {
  16012. //MORE: This would be more efficient if we had a away of skipping to the end of the incoming group.
  16013. const void * next;
  16014. while ((next = input->nextInGroup()) != NULL)
  16015. ReleaseRoxieRow(next);
  16016. }
  16017. else
  16018. eoi = true;
  16019. return true;
  16020. }
  16021. //This only checks the lowest element - we could check all elements inserted, but it would increase the number of compares
  16022. if (compare < 0)
  16023. throw MakeStringException(ROXIE_TOPN_ROW_ERROR, "TOPN: row found that exceeds the best value");
  16024. }
  16025. return false;
  16026. }
  16027. void getSorted()
  16028. {
  16029. curIndex = 0;
  16030. sortedCount = 0;
  16031. if(eoi)
  16032. return;
  16033. const void * next;
  16034. while ((next = input->nextInGroup()) != NULL)
  16035. {
  16036. if (sortedCount < limit)
  16037. {
  16038. binary_vec_insert_stable(next, sorted, sortedCount, compare);
  16039. sortedCount++;
  16040. if(abortEarly())
  16041. return;
  16042. }
  16043. else
  16044. {
  16045. if(limit && compare.docompare(sorted[sortedCount-1], next) > 0) // MORE - if stability is an issue, need to consider whether this should be > or >=
  16046. {
  16047. binary_vec_insert_stable(next, sorted, sortedCount, compare); // MORE - not sure this is stable!
  16048. ReleaseRoxieRow(sorted[sortedCount]);
  16049. if(abortEarly())
  16050. return;
  16051. }
  16052. else
  16053. {
  16054. ReleaseRoxieRow(next); // do not bother with insertion sort if we know next will fall off the end
  16055. }
  16056. }
  16057. }
  16058. }
  16059. virtual const void * nextInGroup()
  16060. {
  16061. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16062. if (eof)
  16063. return NULL;
  16064. if (curIndex >= sortedCount)
  16065. {
  16066. bool eog = sortedCount != 0;
  16067. getSorted();
  16068. if(sortedCount == 0)
  16069. {
  16070. eof = true;
  16071. return NULL;
  16072. }
  16073. if (eog)
  16074. return NULL;
  16075. }
  16076. processed++;
  16077. return sorted[curIndex++];
  16078. }
  16079. };
  16080. class CRoxieServerTopNActivityFactory : public CRoxieServerActivityFactory
  16081. {
  16082. public:
  16083. CRoxieServerTopNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16084. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  16085. {
  16086. }
  16087. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  16088. {
  16089. return new CRoxieServerTopNActivity(this, _probeManager);
  16090. }
  16091. };
  16092. IRoxieServerActivityFactory *createRoxieServerTopNActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16093. {
  16094. return new CRoxieServerTopNActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  16095. }
  16096. //=================================================================================
  16097. class CRoxieServerLimitActivity : public CRoxieServerActivity
  16098. {
  16099. protected:
  16100. unsigned __int64 rowLimit;
  16101. IHThorLimitArg &helper;
  16102. public:
  16103. CRoxieServerLimitActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  16104. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorLimitArg &)basehelper)
  16105. {
  16106. rowLimit = 0;
  16107. }
  16108. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  16109. {
  16110. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  16111. rowLimit = helper.getRowLimit(); // could conceivably depend on context so should not compute any earlier than this
  16112. }
  16113. virtual const void *nextInGroup()
  16114. {
  16115. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16116. const void * ret = input->nextInGroup();
  16117. if (ret)
  16118. {
  16119. processed++;
  16120. if (processed > rowLimit)
  16121. {
  16122. ReleaseRoxieRow(ret);
  16123. if (traceLevel > 4)
  16124. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  16125. helper.onLimitExceeded();
  16126. }
  16127. }
  16128. return ret;
  16129. }
  16130. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  16131. {
  16132. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16133. const void * ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  16134. if (ret)
  16135. {
  16136. if (wasCompleteMatch)
  16137. processed++;
  16138. if (processed > rowLimit)
  16139. {
  16140. ReleaseRoxieRow(ret);
  16141. if (traceLevel > 4)
  16142. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  16143. helper.onLimitExceeded();
  16144. }
  16145. }
  16146. return ret;
  16147. }
  16148. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  16149. {
  16150. return input->gatherConjunctions(collector);
  16151. }
  16152. virtual void resetEOF()
  16153. {
  16154. //Do not reset the rowLimit
  16155. input->resetEOF();
  16156. }
  16157. IInputSteppingMeta * querySteppingMeta()
  16158. {
  16159. return input->querySteppingMeta();
  16160. }
  16161. };
  16162. class CRoxieServerLimitActivityFactory : public CRoxieServerActivityFactory
  16163. {
  16164. public:
  16165. CRoxieServerLimitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16166. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  16167. {
  16168. }
  16169. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  16170. {
  16171. return new CRoxieServerLimitActivity(this, _probeManager);
  16172. }
  16173. };
  16174. IRoxieServerActivityFactory *createRoxieServerLimitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16175. {
  16176. return new CRoxieServerLimitActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  16177. }
  16178. //=====================================================================================================
  16179. class CRoxieServerSkipLimitActivity : public CRoxieServerLimitActivity
  16180. {
  16181. ConstPointerArray buff;
  16182. bool started;
  16183. unsigned index;
  16184. IHThorLimitTransformExtra * transformExtra;
  16185. public:
  16186. CRoxieServerSkipLimitActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _onFail)
  16187. : CRoxieServerLimitActivity(_factory, _probeManager)
  16188. {
  16189. transformExtra = NULL;
  16190. started = false;
  16191. index = 0;
  16192. if (_onFail)
  16193. transformExtra = static_cast<IHThorLimitTransformExtra *>(helper.selectInterface(TAIlimittransformextra_1));
  16194. }
  16195. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  16196. {
  16197. started = false;
  16198. index = 0;
  16199. CRoxieServerLimitActivity::start(parentExtractSize, parentExtract, paused);
  16200. }
  16201. virtual void reset()
  16202. {
  16203. while (buff.isItem(index))
  16204. ReleaseRoxieRow(buff.item(index++));
  16205. buff.kill();
  16206. started = false;
  16207. CRoxieServerLimitActivity::reset();
  16208. }
  16209. virtual const void *nextInGroup()
  16210. {
  16211. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16212. if (!started)
  16213. pullInput();
  16214. if (buff.isItem(index))
  16215. {
  16216. const void * next = buff.item(index++);
  16217. if(next)
  16218. processed++;
  16219. return next;
  16220. }
  16221. return NULL;
  16222. }
  16223. protected:
  16224. void pullInput()
  16225. {
  16226. unsigned count = 0;
  16227. loop
  16228. {
  16229. const void * next = input->nextInGroup();
  16230. if (next == NULL)
  16231. {
  16232. next = input->nextInGroup();
  16233. if(next == NULL)
  16234. break;
  16235. buff.append(NULL);
  16236. }
  16237. count++;
  16238. if (count > rowLimit)
  16239. {
  16240. ReleaseRoxieRow(next);
  16241. ReleaseRoxieRowSet(buff);
  16242. if (ctx->queryDebugContext())
  16243. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  16244. if (transformExtra)
  16245. {
  16246. createRowAllocator();
  16247. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  16248. size32_t outSize = transformExtra->transformOnLimitExceeded(rowBuilder);
  16249. if (outSize)
  16250. buff.append(rowBuilder.finalizeRowClear(outSize));
  16251. }
  16252. break;
  16253. }
  16254. buff.append(next);
  16255. }
  16256. started = true;
  16257. }
  16258. };
  16259. class CRoxieServerSkipLimitActivityFactory : public CRoxieServerActivityFactory
  16260. {
  16261. public:
  16262. CRoxieServerSkipLimitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16263. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  16264. {
  16265. }
  16266. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  16267. {
  16268. return new CRoxieServerSkipLimitActivity(this, _probeManager, kind==TAKcreaterowlimit);
  16269. }
  16270. };
  16271. IRoxieServerActivityFactory *createRoxieServerSkipLimitActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16272. {
  16273. return new CRoxieServerSkipLimitActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  16274. }
  16275. //=================================================================================
  16276. class CRoxieServerCatchActivity : public CRoxieServerActivity
  16277. {
  16278. IHThorCatchArg &helper;
  16279. public:
  16280. CRoxieServerCatchActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  16281. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorCatchArg &)basehelper)
  16282. {
  16283. }
  16284. virtual const void *nextInGroup()
  16285. {
  16286. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16287. try
  16288. {
  16289. const void *ret = input->nextInGroup();
  16290. if (ret)
  16291. processed++;
  16292. return ret;
  16293. }
  16294. catch (IException *E)
  16295. {
  16296. E->Release();
  16297. helper.onExceptionCaught();
  16298. }
  16299. catch (...)
  16300. {
  16301. helper.onExceptionCaught();
  16302. }
  16303. throwUnexpected(); // onExceptionCaught should have thrown something
  16304. }
  16305. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  16306. {
  16307. try
  16308. {
  16309. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16310. const void * ret = input->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  16311. if (ret && wasCompleteMatch)
  16312. processed++;
  16313. return ret;
  16314. }
  16315. catch (IException *E)
  16316. {
  16317. E->Release();
  16318. helper.onExceptionCaught();
  16319. }
  16320. catch (...)
  16321. {
  16322. helper.onExceptionCaught();
  16323. }
  16324. throwUnexpected(); // onExceptionCaught should have thrown something
  16325. }
  16326. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  16327. {
  16328. return input->gatherConjunctions(collector);
  16329. }
  16330. virtual void resetEOF()
  16331. {
  16332. input->resetEOF(); // MORE - why not in base class?
  16333. }
  16334. IInputSteppingMeta * querySteppingMeta()
  16335. {
  16336. return input->querySteppingMeta();
  16337. }
  16338. };
  16339. class CRoxieServerSkipCatchActivity : public CRoxieServerActivity
  16340. {
  16341. ConstPointerArray buff;
  16342. bool started;
  16343. unsigned index;
  16344. IHThorCatchArg &helper;
  16345. bool createRow;
  16346. public:
  16347. CRoxieServerSkipCatchActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _createRow)
  16348. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorCatchArg &)basehelper), createRow(_createRow)
  16349. {
  16350. started = false;
  16351. index = 0;
  16352. }
  16353. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  16354. {
  16355. started = false;
  16356. index = 0;
  16357. try
  16358. {
  16359. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  16360. }
  16361. catch (IException *E)
  16362. {
  16363. onException(E);
  16364. started = true;
  16365. }
  16366. catch (...)
  16367. {
  16368. onException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught"));
  16369. started = true;
  16370. }
  16371. }
  16372. virtual void reset()
  16373. {
  16374. while (buff.isItem(index))
  16375. ReleaseRoxieRow(buff.item(index++));
  16376. buff.kill();
  16377. started = false;
  16378. CRoxieServerActivity::reset();
  16379. }
  16380. virtual const void *nextInGroup()
  16381. {
  16382. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16383. if (!started)
  16384. pullInput();
  16385. if (buff.isItem(index))
  16386. {
  16387. const void * next = buff.item(index++);
  16388. if(next)
  16389. processed++;
  16390. return next;
  16391. }
  16392. return NULL;
  16393. }
  16394. protected:
  16395. void onException(IException *E)
  16396. {
  16397. input->stop(true);
  16398. ReleaseRoxieRowSet(buff);
  16399. if (createRow)
  16400. {
  16401. createRowAllocator();
  16402. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  16403. size32_t outSize = helper.transformOnExceptionCaught(rowBuilder, E);
  16404. if (outSize)
  16405. buff.append(rowBuilder.finalizeRowClear(outSize));
  16406. }
  16407. E->Release();
  16408. }
  16409. void pullInput()
  16410. {
  16411. try
  16412. {
  16413. bool EOGseen = false;
  16414. loop
  16415. {
  16416. const void * next = input->nextInGroup();
  16417. buff.append(next);
  16418. if (next == NULL)
  16419. {
  16420. if (EOGseen)
  16421. break;
  16422. EOGseen = true;
  16423. }
  16424. else
  16425. EOGseen = false;
  16426. }
  16427. }
  16428. catch (IException *E)
  16429. {
  16430. onException(E);
  16431. }
  16432. catch (...)
  16433. {
  16434. onException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught"));
  16435. }
  16436. started = true;
  16437. }
  16438. };
  16439. class CRoxieServerCatchActivityFactory : public CRoxieServerActivityFactory
  16440. {
  16441. public:
  16442. CRoxieServerCatchActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16443. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  16444. {
  16445. }
  16446. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  16447. {
  16448. switch (kind)
  16449. {
  16450. case TAKcatch:
  16451. return new CRoxieServerCatchActivity(this, _probeManager);
  16452. case TAKskipcatch:
  16453. return new CRoxieServerSkipCatchActivity(this, _probeManager, false);
  16454. case TAKcreaterowcatch:
  16455. return new CRoxieServerSkipCatchActivity(this, _probeManager, true);
  16456. default:
  16457. throwUnexpected();
  16458. }
  16459. }
  16460. };
  16461. IRoxieServerActivityFactory *createRoxieServerCatchActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16462. {
  16463. return new CRoxieServerCatchActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  16464. }
  16465. //=================================================================================
  16466. class CRoxieServerCaseActivity : public CRoxieServerActivity
  16467. {
  16468. IHThorCaseArg &helper;
  16469. IRoxieInput **inputs;
  16470. unsigned cond;
  16471. bool unusedStopped;
  16472. IRoxieInput *in;
  16473. unsigned numInputs;
  16474. public:
  16475. CRoxieServerCaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _numInputs)
  16476. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorCaseArg &)basehelper), numInputs(_numInputs)
  16477. {
  16478. unusedStopped = false;
  16479. cond = 0;
  16480. inputs = new IRoxieInput*[numInputs];
  16481. for (unsigned i = 0; i < numInputs; i++)
  16482. inputs[i] = NULL;
  16483. in = NULL;
  16484. }
  16485. ~CRoxieServerCaseActivity()
  16486. {
  16487. delete [] inputs;
  16488. }
  16489. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  16490. {
  16491. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  16492. cond = helper.getBranch();
  16493. assertex(cond < numInputs);
  16494. inputs[cond]->start(parentExtractSize, parentExtract, paused);
  16495. for (unsigned idx = 0; idx < numInputs; idx++)
  16496. {
  16497. if (idx!=cond)
  16498. inputs[idx]->stop(false); // Note: stopping unused branches early helps us avoid buffering splits too long.
  16499. }
  16500. in = inputs[cond];
  16501. unusedStopped = true;
  16502. }
  16503. virtual void stop(bool aborting)
  16504. {
  16505. for (unsigned idx = 0; idx < numInputs; idx++)
  16506. {
  16507. if (idx==cond || !unusedStopped)
  16508. inputs[idx]->stop(aborting);
  16509. }
  16510. CRoxieServerActivity::stop(aborting);
  16511. }
  16512. virtual void reset()
  16513. {
  16514. for (unsigned idx = 0; idx < numInputs; idx++)
  16515. {
  16516. inputs[idx]->reset();
  16517. }
  16518. unusedStopped = false;
  16519. in = NULL;
  16520. CRoxieServerActivity::reset();
  16521. }
  16522. virtual void setInput(unsigned idx, IRoxieInput *_in)
  16523. {
  16524. assertex(idx < numInputs);
  16525. inputs[idx] = _in;
  16526. }
  16527. virtual const void *nextInGroup()
  16528. {
  16529. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16530. if (in)
  16531. {
  16532. const void *ret = in->nextInGroup();
  16533. if (ret)
  16534. processed++;
  16535. return ret;
  16536. }
  16537. return NULL;
  16538. }
  16539. };
  16540. class CRoxieServerCaseActivityFactory : public CRoxieServerMultiInputFactory
  16541. {
  16542. bool graphInvariant;
  16543. public:
  16544. CRoxieServerCaseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _graphInvariant)
  16545. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  16546. {
  16547. graphInvariant = _graphInvariant;
  16548. }
  16549. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  16550. {
  16551. return new CRoxieServerCaseActivity(this, _probeManager, numInputs());
  16552. }
  16553. virtual bool isGraphInvariant() const
  16554. {
  16555. return graphInvariant;
  16556. }
  16557. };
  16558. IRoxieServerActivityFactory *createRoxieServerCaseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _graphInvariant)
  16559. {
  16560. return new CRoxieServerCaseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphInvariant);
  16561. }
  16562. //=================================================================================
  16563. class CRoxieServerIfActivity : public CRoxieServerActivity
  16564. {
  16565. IHThorIfArg &helper;
  16566. IRoxieInput *inputTrue;
  16567. IRoxieInput *inputFalse;
  16568. bool cond;
  16569. bool unusedStopped;
  16570. public:
  16571. CRoxieServerIfActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  16572. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorIfArg &)basehelper)
  16573. {
  16574. inputFalse = NULL;
  16575. inputTrue = NULL;
  16576. unusedStopped = false;
  16577. cond = false;
  16578. }
  16579. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  16580. {
  16581. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  16582. cond = helper.getCondition();
  16583. if (cond)
  16584. {
  16585. inputTrue->start(parentExtractSize, parentExtract, paused);
  16586. if (inputFalse)
  16587. inputFalse->stop(false); // Note: stopping unused branches early helps us avoid buffering splits too long.
  16588. }
  16589. else
  16590. {
  16591. if (inputFalse)
  16592. inputFalse->start(parentExtractSize, parentExtract, paused);
  16593. inputTrue->stop(false);
  16594. }
  16595. unusedStopped = true;
  16596. }
  16597. virtual void stop(bool aborting)
  16598. {
  16599. if (!unusedStopped || cond)
  16600. inputTrue->stop(aborting);
  16601. if (inputFalse && (!unusedStopped || !cond))
  16602. inputFalse->stop(aborting);
  16603. CRoxieServerActivity::stop(aborting);
  16604. }
  16605. virtual unsigned __int64 queryLocalCycles() const
  16606. {
  16607. __int64 localCycles = totalCycles;
  16608. localCycles -= inputTrue->queryTotalCycles();
  16609. if (inputFalse)
  16610. localCycles -= inputFalse->queryTotalCycles();
  16611. if (localCycles < 0)
  16612. localCycles = 0;
  16613. return localCycles;
  16614. }
  16615. virtual IRoxieInput *queryInput(unsigned idx) const
  16616. {
  16617. switch (idx)
  16618. {
  16619. case 0:
  16620. return inputTrue;
  16621. case 1:
  16622. return inputFalse;
  16623. default:
  16624. return NULL;
  16625. }
  16626. }
  16627. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  16628. {
  16629. IRoxieInput *in = cond ? inputTrue : inputFalse;
  16630. if (in)
  16631. return in->queryIndexReadActivity();
  16632. return NULL;
  16633. }
  16634. virtual void reset()
  16635. {
  16636. CRoxieServerActivity::reset();
  16637. inputTrue->reset();
  16638. if (inputFalse)
  16639. inputFalse->reset();
  16640. unusedStopped = false;
  16641. }
  16642. virtual void setInput(unsigned idx, IRoxieInput *_in)
  16643. {
  16644. if (idx==1)
  16645. inputFalse = _in;
  16646. else
  16647. {
  16648. assertex(!idx);
  16649. inputTrue = _in;
  16650. }
  16651. }
  16652. virtual const void *nextInGroup()
  16653. {
  16654. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16655. IRoxieInput *in = cond ? inputTrue : inputFalse;
  16656. if (in)
  16657. {
  16658. const void * ret;
  16659. if ((ret = in->nextInGroup()) != NULL)
  16660. processed++;
  16661. return ret;
  16662. }
  16663. return NULL;
  16664. }
  16665. };
  16666. class CRoxieServerIfActivityFactory : public CRoxieServerActivityFactory
  16667. {
  16668. unsigned input2;
  16669. unsigned input2idx;
  16670. bool graphInvariant;
  16671. public:
  16672. CRoxieServerIfActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _graphInvariant)
  16673. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  16674. {
  16675. graphInvariant = _graphInvariant;
  16676. input2 = (unsigned)-1;
  16677. input2idx = (unsigned)-1;
  16678. }
  16679. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  16680. {
  16681. return new CRoxieServerIfActivity(this, _probeManager);
  16682. }
  16683. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  16684. {
  16685. if (idx==1)
  16686. {
  16687. input2 = source;
  16688. input2idx = sourceidx;
  16689. }
  16690. else
  16691. CRoxieServerActivityFactory::setInput(idx, source, sourceidx);
  16692. }
  16693. virtual unsigned getInput(unsigned idx, unsigned &sourceidx) const
  16694. {
  16695. switch (idx)
  16696. {
  16697. case 1:
  16698. sourceidx = input2idx;
  16699. return input2;
  16700. case 0:
  16701. return CRoxieServerActivityFactory::getInput(idx, sourceidx);
  16702. default:
  16703. return (unsigned) -1;
  16704. }
  16705. }
  16706. virtual bool isGraphInvariant() const
  16707. {
  16708. return graphInvariant;
  16709. }
  16710. };
  16711. IRoxieServerActivityFactory *createRoxieServerIfActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _graphInvariant)
  16712. {
  16713. return new CRoxieServerIfActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphInvariant);
  16714. }
  16715. //=================================================================================
  16716. class CRoxieServerActionBaseActivity : public CRoxieServerActivity
  16717. {
  16718. CriticalSection ecrit;
  16719. Owned<IException> exception;
  16720. bool executed;
  16721. public:
  16722. CRoxieServerActionBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  16723. : CRoxieServerActivity(_factory, _probeManager)
  16724. {
  16725. executed = false;
  16726. }
  16727. virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract) = 0;
  16728. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  16729. {
  16730. CriticalBlock b(ecrit);
  16731. if (exception)
  16732. throw(exception.getLink());
  16733. if (!executed)
  16734. {
  16735. try
  16736. {
  16737. executed = true;
  16738. start(parentExtractSize, parentExtract, false);
  16739. doExecuteAction(parentExtractSize, parentExtract);
  16740. stop(false);
  16741. }
  16742. catch (IException * E)
  16743. {
  16744. ctx->notifyAbort(E);
  16745. stop(true);
  16746. exception.set(E);
  16747. throw;
  16748. }
  16749. }
  16750. }
  16751. virtual void reset()
  16752. {
  16753. executed = false;
  16754. exception.clear();
  16755. CRoxieServerActivity::reset();
  16756. }
  16757. virtual unsigned __int64 queryLocalCycles() const
  16758. {
  16759. return totalCycles;
  16760. }
  16761. virtual const void *nextInGroup()
  16762. {
  16763. throwUnexpected(); // I am nobody's input
  16764. }
  16765. virtual IRoxieInput *queryInput(unsigned idx) const
  16766. {
  16767. throwUnexpected(); // I am nobody's input
  16768. }
  16769. };
  16770. class CRoxieServerIfActionActivity : public CRoxieServerActionBaseActivity
  16771. {
  16772. IHThorIfArg &helper;
  16773. public:
  16774. CRoxieServerIfActionActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  16775. : CRoxieServerActionBaseActivity(_factory, _probeManager), helper((IHThorIfArg &)basehelper)
  16776. {
  16777. }
  16778. virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract)
  16779. {
  16780. int controlId;
  16781. {
  16782. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  16783. controlId = helper.getCondition() ? 1 : 2;
  16784. }
  16785. executeDependencies(parentExtractSize, parentExtract, controlId);
  16786. }
  16787. };
  16788. class CRoxieServerIfActionActivityFactory : public CRoxieServerActivityFactory
  16789. {
  16790. bool isRoot;
  16791. public:
  16792. CRoxieServerIfActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  16793. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  16794. {
  16795. }
  16796. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  16797. {
  16798. return new CRoxieServerIfActionActivity(this, _probeManager);
  16799. }
  16800. virtual bool isSink() const
  16801. {
  16802. return isRoot;
  16803. }
  16804. };
  16805. IRoxieServerActivityFactory *createRoxieServerIfActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  16806. {
  16807. return new CRoxieServerIfActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  16808. }
  16809. //=================================================================================
  16810. class CRoxieServerParallelActionActivity : public CRoxieServerActionBaseActivity
  16811. {
  16812. public:
  16813. CRoxieServerParallelActionActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  16814. : CRoxieServerActionBaseActivity(_factory, _probeManager)
  16815. {
  16816. }
  16817. virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract)
  16818. {
  16819. #ifdef PARALLEL_EXECUTE
  16820. CParallelActivityExecutor afor(dependencies, parentExtractSize, parentExtract);
  16821. afor.For(dependencies.ordinality(), dependencies.ordinality(), true);
  16822. #else
  16823. ForEachItemIn(idx, dependencies)
  16824. {
  16825. dependencies.item(idx).execute(parentExtractSize, parentExtract);
  16826. }
  16827. #endif
  16828. }
  16829. };
  16830. class CRoxieServerParallelActionActivityFactory : public CRoxieServerActivityFactory
  16831. {
  16832. bool isRoot;
  16833. public:
  16834. CRoxieServerParallelActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  16835. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  16836. {
  16837. assertex(!isRoot); // non-internal should be expanded out..
  16838. }
  16839. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  16840. {
  16841. return new CRoxieServerParallelActionActivity(this, _probeManager);
  16842. }
  16843. virtual bool isSink() const
  16844. {
  16845. return isRoot;
  16846. }
  16847. };
  16848. IRoxieServerActivityFactory *createRoxieServerParallelActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  16849. {
  16850. return new CRoxieServerParallelActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  16851. }
  16852. //=================================================================================
  16853. class CRoxieServerSequentialActionActivity : public CRoxieServerActionBaseActivity
  16854. {
  16855. IHThorSequentialArg &helper;
  16856. public:
  16857. CRoxieServerSequentialActionActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  16858. : CRoxieServerActionBaseActivity(_factory, _probeManager), helper((IHThorSequentialArg &)basehelper)
  16859. {
  16860. }
  16861. virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract)
  16862. {
  16863. unsigned numBranches = helper.numBranches();
  16864. for (unsigned branch=1; branch <= numBranches; branch++)
  16865. executeDependencies(parentExtractSize, parentExtract, branch);
  16866. }
  16867. };
  16868. class CRoxieServerSequentialActionActivityFactory : public CRoxieServerActivityFactory
  16869. {
  16870. bool isRoot;
  16871. public:
  16872. CRoxieServerSequentialActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  16873. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  16874. {
  16875. }
  16876. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  16877. {
  16878. return new CRoxieServerSequentialActionActivity(this, _probeManager);
  16879. }
  16880. virtual bool isSink() const
  16881. {
  16882. return isRoot;
  16883. }
  16884. };
  16885. IRoxieServerActivityFactory *createRoxieServerSequentialActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  16886. {
  16887. return new CRoxieServerSequentialActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  16888. }
  16889. //=================================================================================
  16890. class CRoxieServerWhenActivity : public CRoxieServerActivity
  16891. {
  16892. public:
  16893. CRoxieServerWhenActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  16894. : CRoxieServerActivity(_factory, _probeManager)
  16895. {
  16896. savedExtractSize = 0;
  16897. savedExtract = NULL;
  16898. }
  16899. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  16900. {
  16901. savedExtractSize = parentExtractSize;
  16902. savedExtract = parentExtract;
  16903. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  16904. executeDependencies(parentExtractSize, parentExtract, WhenParallelId); // MORE: This should probably be done in parallel!
  16905. }
  16906. virtual void stop(bool aborting)
  16907. {
  16908. if (state != STATEstopped)
  16909. executeDependencies(savedExtractSize, savedExtract, aborting ? WhenFailureId : WhenSuccessId);
  16910. CRoxieServerActivity::stop(aborting);
  16911. }
  16912. virtual const void *nextInGroup()
  16913. {
  16914. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext()); // bit of a waste of time....
  16915. return input->nextInGroup();
  16916. }
  16917. protected:
  16918. unsigned savedExtractSize;
  16919. const byte *savedExtract;
  16920. };
  16921. class CRoxieServerWhenActivityFactory : public CRoxieServerActivityFactory
  16922. {
  16923. public:
  16924. CRoxieServerWhenActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16925. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  16926. {
  16927. }
  16928. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  16929. {
  16930. return new CRoxieServerWhenActivity(this, _probeManager);
  16931. }
  16932. };
  16933. extern IRoxieServerActivityFactory *createRoxieServerWhenActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  16934. {
  16935. return new CRoxieServerWhenActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  16936. }
  16937. //=================================================================================
  16938. class CRoxieServerWhenActionActivity : public CRoxieServerActionBaseActivity
  16939. {
  16940. public:
  16941. CRoxieServerWhenActionActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  16942. : CRoxieServerActionBaseActivity(_factory, _probeManager)
  16943. {
  16944. savedExtractSize = 0;
  16945. savedExtract = NULL;
  16946. }
  16947. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  16948. {
  16949. savedExtractSize = parentExtractSize;
  16950. savedExtract = parentExtract;
  16951. CRoxieServerActionBaseActivity::start(parentExtractSize, parentExtract, paused);
  16952. executeDependencies(parentExtractSize, parentExtract, WhenParallelId); // MORE: This should probably be done in parallel!
  16953. }
  16954. virtual void stop(bool aborting)
  16955. {
  16956. if (state != STATEstopped)
  16957. executeDependencies(savedExtractSize, savedExtract, aborting ? WhenFailureId : WhenSuccessId);
  16958. CRoxieServerActionBaseActivity::stop(aborting);
  16959. }
  16960. virtual void doExecuteAction(unsigned parentExtractSize, const byte * parentExtract)
  16961. {
  16962. executeDependencies(parentExtractSize, parentExtract, 1);
  16963. }
  16964. protected:
  16965. unsigned savedExtractSize;
  16966. const byte *savedExtract;
  16967. };
  16968. class CRoxieServerWhenActionActivityFactory : public CRoxieServerActivityFactory
  16969. {
  16970. public:
  16971. CRoxieServerWhenActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  16972. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  16973. {
  16974. }
  16975. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  16976. {
  16977. return new CRoxieServerWhenActionActivity(this, _probeManager);
  16978. }
  16979. virtual bool isSink() const
  16980. {
  16981. return isRoot;
  16982. }
  16983. private:
  16984. bool isRoot;
  16985. };
  16986. extern IRoxieServerActivityFactory *createRoxieServerWhenActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  16987. {
  16988. return new CRoxieServerWhenActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  16989. }
  16990. //=================================================================================
  16991. class CRoxieServerParseActivity : public CRoxieServerActivity, implements IMatchedAction
  16992. {
  16993. IHThorParseArg &helper;
  16994. INlpParser * parser;
  16995. INlpResultIterator * rowIter;
  16996. const void * in;
  16997. char * curSearchText;
  16998. INlpParseAlgorithm * algorithm;
  16999. size32_t curSearchTextLen;
  17000. bool anyThisGroup;
  17001. bool processRecord(const void * inRec)
  17002. {
  17003. if (helper.searchTextNeedsFree())
  17004. rtlFree(curSearchText);
  17005. curSearchTextLen = 0;
  17006. curSearchText = NULL;
  17007. helper.getSearchText(curSearchTextLen, curSearchText, inRec);
  17008. return parser->performMatch(*this, in, curSearchTextLen, curSearchText);
  17009. }
  17010. public:
  17011. CRoxieServerParseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, INlpParseAlgorithm * _algorithm)
  17012. : CRoxieServerActivity(_factory, _probeManager),
  17013. helper((IHThorParseArg &)basehelper), algorithm(_algorithm)
  17014. {
  17015. parser = NULL;
  17016. rowIter = NULL;
  17017. in = NULL;
  17018. curSearchText = NULL;
  17019. anyThisGroup = false;
  17020. curSearchTextLen = 0;
  17021. }
  17022. ~CRoxieServerParseActivity()
  17023. {
  17024. ::Release(parser);
  17025. }
  17026. virtual bool needsAllocator() const { return true; }
  17027. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  17028. {
  17029. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  17030. parser = algorithm->createParser(_ctx->queryCodeContext(), activityId, helper.queryHelper(), &helper);
  17031. rowIter = parser->queryResultIter();
  17032. }
  17033. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17034. {
  17035. anyThisGroup = false;
  17036. curSearchTextLen = 0;
  17037. curSearchText = NULL;
  17038. in = NULL;
  17039. parser->reset();
  17040. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  17041. }
  17042. virtual void reset()
  17043. {
  17044. if (helper.searchTextNeedsFree())
  17045. rtlFree(curSearchText);
  17046. curSearchText = NULL;
  17047. ReleaseClearRoxieRow(in);
  17048. CRoxieServerActivity::reset();
  17049. }
  17050. virtual unsigned onMatch(ARowBuilder & self, const void * curRecord, IMatchedResults * results, IMatchWalker * walker)
  17051. {
  17052. try
  17053. {
  17054. return helper.transform(self, curRecord, results, walker);
  17055. }
  17056. catch (IException *E)
  17057. {
  17058. throw makeWrappedException(E);
  17059. }
  17060. }
  17061. virtual const void * nextInGroup()
  17062. {
  17063. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  17064. loop
  17065. {
  17066. if (rowIter->isValid())
  17067. {
  17068. anyThisGroup = true;
  17069. OwnedConstRoxieRow out = rowIter->getRow();
  17070. rowIter->next();
  17071. processed++;
  17072. return out.getClear();
  17073. }
  17074. ReleaseClearRoxieRow(in);
  17075. in = input->nextInGroup();
  17076. if (!in)
  17077. {
  17078. if (anyThisGroup)
  17079. {
  17080. anyThisGroup = false;
  17081. return NULL;
  17082. }
  17083. in = input->nextInGroup();
  17084. if (!in)
  17085. return NULL;
  17086. }
  17087. processRecord(in);
  17088. rowIter->first();
  17089. }
  17090. }
  17091. };
  17092. class CRoxieServerParseActivityFactory : public CRoxieServerActivityFactory
  17093. {
  17094. Owned<INlpParseAlgorithm> algorithm;
  17095. Owned<IHThorParseArg> helper;
  17096. public:
  17097. CRoxieServerParseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IResourceContext *rc)
  17098. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  17099. {
  17100. helper.setown((IHThorParseArg *) helperFactory());
  17101. algorithm.setown(createThorParser(rc, *helper));
  17102. }
  17103. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  17104. {
  17105. return new CRoxieServerParseActivity(this, _probeManager, algorithm);
  17106. }
  17107. };
  17108. IRoxieServerActivityFactory *createRoxieServerParseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IResourceContext *rc)
  17109. {
  17110. return new CRoxieServerParseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, rc);
  17111. }
  17112. //=====================================================================================================
  17113. class CRoxieServerWorkUnitWriteActivity : public CRoxieServerInternalSinkActivity
  17114. {
  17115. IHThorWorkUnitWriteArg &helper;
  17116. bool isReread;
  17117. bool grouped;
  17118. IRoxieServerContext *serverContext;
  17119. public:
  17120. CRoxieServerWorkUnitWriteActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, bool _isReread)
  17121. : CRoxieServerInternalSinkActivity(_factory, _probeManager), helper((IHThorWorkUnitWriteArg &)basehelper), isReread(_isReread)
  17122. {
  17123. grouped = (helper.getFlags() & POFgrouped) != 0;
  17124. serverContext = NULL;
  17125. }
  17126. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  17127. {
  17128. CRoxieServerInternalSinkActivity::onCreate(_ctx, _colocalParent);
  17129. serverContext = ctx->queryServerContext();
  17130. if (!serverContext)
  17131. {
  17132. throw MakeStringException(ROXIE_PIPE_ERROR, "Pipe output activity cannot be executed in slave context");
  17133. }
  17134. }
  17135. virtual void onExecute()
  17136. {
  17137. int sequence = helper.getSequence();
  17138. const char *storedName = helper.queryName();
  17139. if (!storedName)
  17140. storedName = "Dataset";
  17141. MemoryBuffer result;
  17142. FlushingStringBuffer *response = NULL;
  17143. bool saveInContext = (int) sequence < 0 || isReread;
  17144. if (!meta.queryOriginal()) // this is a bit of a hack - don't know why no meta on an output....
  17145. meta.set(input->queryOutputMeta());
  17146. Owned<IOutputRowSerializer> rowSerializer;
  17147. if ((int) sequence >= 0)
  17148. {
  17149. response = serverContext->queryResult(sequence);
  17150. if (response)
  17151. response->startDataset("Dataset", helper.queryName(), sequence, (helper.getFlags() & POFextend) != 0);
  17152. }
  17153. if (serverContext->outputResultsToWorkUnit()||(response && response->isRaw))
  17154. {
  17155. createRowAllocator();
  17156. rowSerializer.setown(rowAllocator->createRowSerializer(ctx->queryCodeContext()));
  17157. }
  17158. __int64 initialProcessed = processed;
  17159. ConstPointerArray *lResult = NULL;
  17160. if (saveInContext)
  17161. lResult = new ConstPointerArray;
  17162. loop
  17163. {
  17164. const void *row = input->nextInGroup();
  17165. if (lResult)
  17166. {
  17167. if (row)
  17168. LinkRoxieRow(row);
  17169. if (row || grouped)
  17170. lResult->append(row);
  17171. }
  17172. if (grouped && (processed != initialProcessed))
  17173. {
  17174. if (serverContext->outputResultsToWorkUnit())
  17175. result.append(row == NULL);
  17176. if (response)
  17177. {
  17178. if (response->isRaw)
  17179. response->append(row == NULL);
  17180. else
  17181. {
  17182. response->append("<Row __GroupBreak__=\"1\"/>"); // sensible, but need to handle on input
  17183. }
  17184. }
  17185. }
  17186. if (!row)
  17187. {
  17188. row = input->nextInGroup();
  17189. if (!row)
  17190. break;
  17191. if (lResult)
  17192. {
  17193. if (row)
  17194. LinkRoxieRow(row);
  17195. lResult->append(row);
  17196. }
  17197. }
  17198. processed++;
  17199. if (serverContext->outputResultsToWorkUnit())
  17200. {
  17201. CThorDemoRowSerializer serializerTarget(result);
  17202. rowSerializer->serialize(serializerTarget, (const byte *) row);
  17203. }
  17204. if (response)
  17205. {
  17206. if (response->isRaw)
  17207. {
  17208. // MORE - should be able to serialize straight to the response...
  17209. MemoryBuffer rowbuff;
  17210. CThorDemoRowSerializer serializerTarget(rowbuff);
  17211. rowSerializer->serialize(serializerTarget, (const byte *) row);
  17212. response->append(rowbuff.length(), rowbuff.toByteArray());
  17213. }
  17214. else if (response->isXml)
  17215. {
  17216. CommonXmlWriter xmlwrite(serverContext->getXmlFlags(), 1, response);
  17217. xmlwrite.outputBeginNested("Row", false);
  17218. helper.serializeXml((byte *) row, xmlwrite);
  17219. xmlwrite.outputEndNested("Row");
  17220. }
  17221. else
  17222. {
  17223. SimpleOutputWriter x;
  17224. helper.serializeXml((byte *) row, x);
  17225. x.newline();
  17226. response->append(x.str());
  17227. }
  17228. response->incrementRowCount();
  17229. response->flush(false);
  17230. }
  17231. ReleaseRoxieRow(row);
  17232. }
  17233. if (lResult)
  17234. serverContext->appendResultDeserialized(storedName, sequence, lResult, (helper.getFlags() & POFextend) != 0, LINK(meta.queryOriginal()));
  17235. if (serverContext->outputResultsToWorkUnit())
  17236. serverContext->appendResultRawContext(storedName, sequence, result.length(), result.toByteArray(), processed, (helper.getFlags() & POFextend) != 0, false); // MORE - shame to do extra copy...
  17237. }
  17238. };
  17239. class CRoxieServerWorkUnitWriteActivityFactory : public CRoxieServerInternalSinkFactory
  17240. {
  17241. bool isReread;
  17242. public:
  17243. CRoxieServerWorkUnitWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  17244. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot)
  17245. {
  17246. isReread = usageCount > 0;
  17247. Owned<IHThorWorkUnitWriteArg> helper = (IHThorWorkUnitWriteArg *) helperFactory();
  17248. isInternal = (helper->getSequence()==-3);
  17249. }
  17250. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  17251. {
  17252. return new CRoxieServerWorkUnitWriteActivity(this, _probeManager, isReread);
  17253. }
  17254. };
  17255. IRoxieServerActivityFactory *createRoxieServerWorkUnitWriteActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  17256. {
  17257. return new CRoxieServerWorkUnitWriteActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot);
  17258. }
  17259. //=================================================================================
  17260. class CRoxieServerRemoteResultActivity : public CRoxieServerInternalSinkActivity
  17261. {
  17262. IHThorRemoteResultArg &helper;
  17263. public:
  17264. CRoxieServerRemoteResultActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  17265. : CRoxieServerInternalSinkActivity(_factory, _probeManager), helper((IHThorRemoteResultArg &)basehelper)
  17266. {
  17267. }
  17268. virtual void onExecute()
  17269. {
  17270. OwnedConstRoxieRow row = input->nextInGroup();
  17271. helper.sendResult(row); // should be only one row or something has gone wrong!
  17272. }
  17273. };
  17274. class CRoxieServerRemoteResultActivityFactory : public CRoxieServerInternalSinkFactory
  17275. {
  17276. public:
  17277. CRoxieServerRemoteResultActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  17278. : CRoxieServerInternalSinkFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot)
  17279. {
  17280. Owned<IHThorRemoteResultArg> helper = (IHThorRemoteResultArg *) helperFactory();
  17281. isInternal = (helper->getSequence()==-3);
  17282. }
  17283. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  17284. {
  17285. return new CRoxieServerRemoteResultActivity(this, _probeManager);
  17286. }
  17287. };
  17288. IRoxieServerActivityFactory *createRoxieServerRemoteResultActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, unsigned _usageCount, bool _isRoot)
  17289. {
  17290. return new CRoxieServerRemoteResultActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _usageCount, _isRoot);
  17291. }
  17292. //=================================================================================
  17293. class CRoxieServerXmlParseActivity : public CRoxieServerActivity, implements IXMLSelect
  17294. {
  17295. IHThorXmlParseArg &helper;
  17296. Owned<IXMLParse> xmlParser;
  17297. const void * in;
  17298. char * srchStr;
  17299. unsigned numProcessedLastGroup;
  17300. bool srchStrNeedsFree;
  17301. Owned<IColumnProvider> lastMatch;
  17302. public:
  17303. IMPLEMENT_IINTERFACE;
  17304. CRoxieServerXmlParseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  17305. : CRoxieServerActivity(_factory, _probeManager),
  17306. helper((IHThorXmlParseArg &)basehelper)
  17307. {
  17308. srchStrNeedsFree = helper.searchTextNeedsFree();
  17309. numProcessedLastGroup = 0;
  17310. srchStr = NULL;
  17311. in = NULL;
  17312. }
  17313. ~CRoxieServerXmlParseActivity()
  17314. {
  17315. }
  17316. virtual bool needsAllocator() const { return true; }
  17317. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17318. {
  17319. numProcessedLastGroup = 0;
  17320. srchStr = NULL;
  17321. in = NULL;
  17322. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  17323. }
  17324. virtual void reset()
  17325. {
  17326. if (helper.searchTextNeedsFree())
  17327. rtlFree(srchStr);
  17328. srchStr = NULL;
  17329. ReleaseClearRoxieRow(in);
  17330. xmlParser.clear();
  17331. CRoxieServerActivity::reset();
  17332. }
  17333. virtual void match(IColumnProvider &entry, offset_t startOffset, offset_t endOffset)
  17334. {
  17335. lastMatch.set(&entry);
  17336. }
  17337. virtual const void *nextInGroup()
  17338. {
  17339. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  17340. loop
  17341. {
  17342. if(xmlParser)
  17343. {
  17344. loop
  17345. {
  17346. if(!xmlParser->next())
  17347. {
  17348. if (srchStrNeedsFree)
  17349. {
  17350. rtlFree(srchStr);
  17351. srchStr = NULL;
  17352. }
  17353. xmlParser.clear();
  17354. break;
  17355. }
  17356. if(lastMatch)
  17357. {
  17358. try
  17359. {
  17360. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  17361. size32_t outSize = helper.transform(rowBuilder, in, lastMatch);
  17362. lastMatch.clear();
  17363. if (outSize)
  17364. {
  17365. processed++;
  17366. return rowBuilder.finalizeRowClear(outSize);
  17367. }
  17368. }
  17369. catch (IException *E)
  17370. {
  17371. throw makeWrappedException(E);
  17372. }
  17373. }
  17374. }
  17375. }
  17376. ReleaseClearRoxieRow(in);
  17377. in = input->nextInGroup();
  17378. if(!in)
  17379. {
  17380. if(numProcessedLastGroup == processed)
  17381. in = input->nextInGroup();
  17382. if(!in)
  17383. {
  17384. numProcessedLastGroup = processed;
  17385. return NULL;
  17386. }
  17387. }
  17388. size32_t srchLen;
  17389. helper.getSearchText(srchLen, srchStr, in);
  17390. xmlParser.setown(createXMLParse(srchStr, srchLen, helper.queryIteratorPath(), *this));
  17391. }
  17392. }
  17393. };
  17394. class CRoxieServerXmlParseActivityFactory : public CRoxieServerActivityFactory
  17395. {
  17396. public:
  17397. CRoxieServerXmlParseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  17398. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  17399. {
  17400. }
  17401. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  17402. {
  17403. return new CRoxieServerXmlParseActivity(this, _probeManager);
  17404. }
  17405. };
  17406. IRoxieServerActivityFactory *createRoxieServerXmlParseActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  17407. {
  17408. return new CRoxieServerXmlParseActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  17409. }
  17410. //=====================================================================================================
  17411. class CRoxieServerDiskReadBaseActivity : public CRoxieServerActivity, implements IRoxieServerErrorHandler, implements IIndexReadContext
  17412. {
  17413. protected:
  17414. IHThorDiskReadBaseArg &helper;
  17415. IHThorCompoundExtra * compoundHelper;
  17416. RemoteActivityId remoteId; // Note we copy it rather than reference
  17417. Owned<CSkippableRemoteResultAdaptor> remote;
  17418. unsigned numParts;
  17419. unsigned __int64 rowLimit;
  17420. unsigned __int64 stopAfter;
  17421. Linked<IInMemoryIndexManager> manager;
  17422. Owned<IInMemoryIndexCursor> cursor;
  17423. Owned<IDirectReader> reader;
  17424. CThorContiguousRowBuffer deserializeSource;
  17425. Owned<ISourceRowPrefetcher> prefetcher;
  17426. bool eof;
  17427. bool isKeyed;
  17428. bool variableFileName;
  17429. bool isOpt;
  17430. bool maySkip;
  17431. bool isLocal;
  17432. CachedOutputMetaData diskSize;
  17433. Owned<const IResolvedFile> varFileInfo;
  17434. Owned<IFileIOArray> varFiles;
  17435. public:
  17436. IMPLEMENT_IINTERFACE;
  17437. CRoxieServerDiskReadBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, bool sorted, bool _maySkip, IInMemoryIndexManager *_manager)
  17438. : CRoxieServerActivity(_factory, _probeManager),
  17439. helper((IHThorDiskReadBaseArg &)basehelper),
  17440. numParts(_numParts),
  17441. remoteId(_remoteId),
  17442. manager(_manager),
  17443. isLocal(_isLocal),
  17444. maySkip(_maySkip),
  17445. deserializeSource(NULL)
  17446. {
  17447. if (numParts != 1 && !isLocal)
  17448. remote.setown(new CSkippableRemoteResultAdaptor(remoteId, meta.queryOriginal(), helper, *this, sorted, false, _maySkip));
  17449. compoundHelper = NULL;
  17450. eof = false;
  17451. rowLimit = (unsigned __int64) -1;
  17452. isKeyed = false;
  17453. stopAfter = I64C(0x7FFFFFFFFFFFFFFF);
  17454. diskSize.set(helper.queryDiskRecordSize());
  17455. variableFileName = (helper.getFlags() & (TDXvarfilename|TDXdynamicfilename)) != 0;
  17456. isOpt = (helper.getFlags() & TDRoptional) != 0;
  17457. }
  17458. virtual const IResolvedFile *queryVarFileInfo() const
  17459. {
  17460. return varFileInfo;
  17461. }
  17462. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  17463. {
  17464. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  17465. if (remote)
  17466. remote->onCreate(this, this, _ctx, _colocalParent);
  17467. }
  17468. virtual bool needsAllocator() const { return true; }
  17469. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17470. {
  17471. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  17472. if (compoundHelper)
  17473. {
  17474. rowLimit = compoundHelper->getRowLimit();
  17475. stopAfter = compoundHelper->getChooseNLimit();
  17476. }
  17477. if (remote)
  17478. {
  17479. remote->onStart(parentExtractSize, parentExtract);
  17480. remote->setLimits(rowLimit, (unsigned __int64) -1, stopAfter);
  17481. if (helper.canMatchAny())
  17482. {
  17483. if (variableFileName)
  17484. varFileInfo.setown(resolveLFN(helper.getFileName(), isOpt));
  17485. unsigned fileNo = 0; // MORE - superfiles require us to do this per file part... maybe (needs thought)
  17486. // Translation into a message per channel done elsewhere....
  17487. remote->getMem(0, fileNo, 0);
  17488. }
  17489. remote->flush();
  17490. remote->senddone();
  17491. }
  17492. else
  17493. {
  17494. if (!helper.canMatchAny())
  17495. eof = true;
  17496. else
  17497. {
  17498. if (variableFileName)
  17499. {
  17500. varFileInfo.setown(resolveLFN(helper.getFileName(), isOpt));
  17501. unsigned channel = isLocal ? factory->queryQueryFactory().queryChannel() : 0;
  17502. varFiles.setown(varFileInfo->getIFileIOArray(isOpt, channel));
  17503. manager.setown(varFileInfo->getIndexManager(isOpt, channel, varFiles, diskSize, false, 0));
  17504. }
  17505. assertex(manager != NULL);
  17506. helper.createSegmentMonitors(this);
  17507. if (cursor)
  17508. {
  17509. isKeyed = cursor->selectKey();
  17510. cursor->reset();
  17511. }
  17512. if (!isKeyed)
  17513. {
  17514. reader.setown(manager->createReader(0, 0, 1));
  17515. deserializeSource.setStream(reader);
  17516. prefetcher.setown(diskSize.queryOriginal()->createRowPrefetcher(ctx->queryCodeContext(), activityId));
  17517. }
  17518. helper.setCallback(reader ? reader->queryThorDiskCallback() : cursor);
  17519. }
  17520. }
  17521. }
  17522. virtual void append(IKeySegmentMonitor *segment)
  17523. {
  17524. if (!segment->isWild())
  17525. {
  17526. if (!cursor)
  17527. cursor.setown(manager->createCursor());
  17528. cursor->append(segment);
  17529. }
  17530. }
  17531. virtual unsigned ordinality() const
  17532. {
  17533. return cursor ? cursor->ordinality() : 0;
  17534. }
  17535. virtual IKeySegmentMonitor *item(unsigned idx) const
  17536. {
  17537. return cursor ? cursor->item(idx) : 0;
  17538. }
  17539. virtual void setMergeBarrier(unsigned barrierOffset)
  17540. {
  17541. // no merging so no issue...
  17542. }
  17543. virtual void stop(bool aborting)
  17544. {
  17545. if (remote)
  17546. remote->onStop(aborting);
  17547. CRoxieServerActivity::stop(aborting);
  17548. }
  17549. virtual void reset()
  17550. {
  17551. if (remote)
  17552. {
  17553. processed = remote->processed;
  17554. remote->processed = 0;
  17555. remote->onReset();
  17556. }
  17557. varFileInfo.clear();
  17558. eof = false;
  17559. if (cursor)
  17560. cursor->reset();
  17561. deserializeSource.clearStream();
  17562. CRoxieServerActivity::reset();
  17563. }
  17564. virtual void setInput(unsigned idx, IRoxieInput *_in)
  17565. {
  17566. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  17567. }
  17568. virtual IRoxieInput *queryOutput(unsigned idx)
  17569. {
  17570. if (idx==(unsigned)-1)
  17571. idx = 0;
  17572. if (idx == 0)
  17573. {
  17574. if (remote)
  17575. return remote;
  17576. else
  17577. return this;
  17578. }
  17579. else
  17580. return NULL;
  17581. }
  17582. virtual void onLimitExceeded(bool isKeyed)
  17583. {
  17584. if (traceLevel > 4)
  17585. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  17586. assertex(compoundHelper);
  17587. if (isKeyed) // MORE does this exist for diskread? should it?
  17588. {
  17589. if (helper.getFlags() & (TDRkeyedlimitskips|TDRkeyedlimitcreates))
  17590. {
  17591. if (ctx->queryDebugContext())
  17592. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  17593. throw makeLimitSkipException(true);
  17594. }
  17595. else
  17596. {
  17597. UNIMPLEMENTED;
  17598. //compoundHelper->onKeyedLimitExceeded(); Doesn't exist - though the flags do... interesting...
  17599. }
  17600. }
  17601. else
  17602. {
  17603. if (helper.getFlags() & (TDRlimitskips|TDRlimitcreates))
  17604. {
  17605. if (ctx->queryDebugContext())
  17606. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  17607. throw makeLimitSkipException(false);
  17608. }
  17609. else
  17610. compoundHelper->onLimitExceeded();
  17611. }
  17612. }
  17613. virtual const void * createLimitFailRow(bool isKeyed)
  17614. {
  17615. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  17616. IHThorSourceLimitTransformExtra *limitTransformExtra = static_cast<IHThorSourceLimitTransformExtra *>(helper.selectInterface(TAIsourcelimittransformextra_1));
  17617. assertex(limitTransformExtra);
  17618. size32_t outSize = isKeyed ? limitTransformExtra->transformOnKeyedLimitExceeded(rowBuilder) : limitTransformExtra->transformOnLimitExceeded(rowBuilder);
  17619. if (outSize)
  17620. return rowBuilder.finalizeRowClear(outSize);
  17621. return NULL;
  17622. }
  17623. };
  17624. class CRoxieServerDiskReadActivity : public CRoxieServerDiskReadBaseActivity
  17625. {
  17626. IHThorCompoundReadExtra * readHelper;
  17627. ConstPointerArray readrows;
  17628. bool readAheadDone;
  17629. unsigned readIndex;
  17630. public:
  17631. CRoxieServerDiskReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, bool _sorted, bool _maySkip, IInMemoryIndexManager *_manager)
  17632. : CRoxieServerDiskReadBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _sorted, _maySkip, _manager)
  17633. {
  17634. compoundHelper = (IHThorDiskReadArg *)&helper;
  17635. readHelper = (IHThorDiskReadArg *)&helper;
  17636. readAheadDone = false;
  17637. readIndex = 0;
  17638. }
  17639. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17640. {
  17641. rowLimit = compoundHelper->getRowLimit();
  17642. stopAfter = compoundHelper->getChooseNLimit();
  17643. CRoxieServerDiskReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  17644. readAheadDone = false;
  17645. readIndex = 0;
  17646. }
  17647. virtual void reset()
  17648. {
  17649. while (readrows.isItem(readIndex))
  17650. ReleaseRoxieRow(readrows.item(readIndex++));
  17651. readrows.kill();
  17652. readAheadDone = false;
  17653. readIndex = 0;
  17654. CRoxieServerDiskReadBaseActivity::reset();
  17655. }
  17656. virtual const void *nextInGroup()
  17657. {
  17658. // Note - in remote case this never gets called as input chain is routed to remoteResultAdaptor
  17659. if (eof)
  17660. return NULL;
  17661. if (maySkip)
  17662. {
  17663. if (!readAheadDone)
  17664. {
  17665. unsigned preprocessed = 0;
  17666. while (!eof)
  17667. {
  17668. const void *row = _nextInGroup();
  17669. if (row)
  17670. preprocessed++;
  17671. if (preprocessed > rowLimit)
  17672. {
  17673. ReleaseRoxieRow(row);
  17674. while (readrows.isItem(readIndex))
  17675. ReleaseRoxieRow(readrows.item(readIndex++));
  17676. readrows.kill();
  17677. eof = true;
  17678. if (ctx->queryDebugContext())
  17679. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  17680. if (helper.getFlags() & TDRlimitskips)
  17681. return NULL;
  17682. else if (helper.getFlags() & TDRlimitcreates)
  17683. return createLimitFailRow(false);
  17684. else
  17685. throwUnexpected();
  17686. }
  17687. if (preprocessed > stopAfter) // MORE - bit of a strange place to check
  17688. {
  17689. eof = true;
  17690. ReleaseRoxieRow(row);
  17691. break;
  17692. }
  17693. readrows.append(row);
  17694. }
  17695. readAheadDone = true;
  17696. }
  17697. if (readrows.isItem(readIndex))
  17698. {
  17699. const void *ret = readrows.item(readIndex++);
  17700. if (ret)
  17701. processed++;
  17702. return ret;
  17703. }
  17704. else
  17705. {
  17706. eof = true;
  17707. return NULL;
  17708. }
  17709. }
  17710. else
  17711. {
  17712. const void *ret = _nextInGroup();
  17713. if (ret)
  17714. {
  17715. processed++;
  17716. if (processed > rowLimit)
  17717. {
  17718. if (traceLevel > 4)
  17719. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  17720. ReleaseRoxieRow(ret);
  17721. compoundHelper->onLimitExceeded();
  17722. throwUnexpected(); // onLimitExceeded is not supposed to return
  17723. }
  17724. if (processed > stopAfter) // MORE - bit of a strange place to check
  17725. {
  17726. eof = true;
  17727. ReleaseRoxieRow(ret);
  17728. return NULL;
  17729. }
  17730. }
  17731. return ret;
  17732. }
  17733. }
  17734. const void *_nextInGroup()
  17735. {
  17736. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  17737. unsigned transformedSize = 0;
  17738. if (isKeyed)
  17739. {
  17740. loop
  17741. {
  17742. const void *nextCandidate = cursor->nextMatch();
  17743. if (!nextCandidate)
  17744. {
  17745. eof = true;
  17746. return NULL;
  17747. }
  17748. transformedSize = readHelper->transform(rowBuilder, nextCandidate);
  17749. if (transformedSize)
  17750. break;
  17751. }
  17752. }
  17753. else // use reader...
  17754. {
  17755. assertex(reader != NULL);
  17756. loop
  17757. {
  17758. if (deserializeSource.eos())
  17759. {
  17760. eof = true;
  17761. return NULL;
  17762. }
  17763. prefetcher->readAhead(deserializeSource);
  17764. const byte *nextRec = deserializeSource.queryRow();
  17765. if (cursor && cursor->isFiltered(nextRec))
  17766. transformedSize = 0;
  17767. else
  17768. transformedSize = readHelper->transform(rowBuilder, nextRec);
  17769. deserializeSource.finishedRow();
  17770. if (transformedSize)
  17771. break;
  17772. }
  17773. }
  17774. return rowBuilder.finalizeRowClear(transformedSize);
  17775. }
  17776. };
  17777. class CRoxieServerXmlReadActivity : public CRoxieServerDiskReadBaseActivity, implements IXMLSelect
  17778. {
  17779. IHThorXmlReadArg * readHelper;
  17780. Owned<IXmlToRowTransformer> rowTransformer;
  17781. Owned<IXMLParse> xmlParser;
  17782. Owned<IColumnProvider> lastMatch;
  17783. unsigned __int64 localOffset;
  17784. public:
  17785. IMPLEMENT_IINTERFACE;
  17786. CRoxieServerXmlReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, bool _sorted, bool _maySkip, IInMemoryIndexManager *_manager)
  17787. : CRoxieServerDiskReadBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _sorted, _maySkip, _manager)
  17788. {
  17789. compoundHelper = NULL;
  17790. readHelper = (IHThorXmlReadArg *)&helper;
  17791. localOffset = 0;
  17792. }
  17793. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17794. {
  17795. rowLimit = readHelper->getRowLimit();
  17796. stopAfter = readHelper->getChooseNLimit();
  17797. CRoxieServerDiskReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  17798. if (!remote)
  17799. {
  17800. rowTransformer.set(readHelper->queryTransformer());
  17801. assertex(reader != NULL);
  17802. xmlParser.setown(createXMLParse(*reader->querySimpleStream(), readHelper->queryIteratorPath(), *this, (0 != (TDRxmlnoroot & readHelper->getFlags()))?xr_noRoot:xr_none, (readHelper->getFlags() & TDRusexmlcontents) != 0));
  17803. }
  17804. }
  17805. virtual void reset()
  17806. {
  17807. CRoxieServerDiskReadBaseActivity::reset();
  17808. rowTransformer.clear();
  17809. xmlParser.clear();
  17810. }
  17811. virtual void match(IColumnProvider &entry, offset_t startOffset, offset_t endOffset)
  17812. {
  17813. localOffset = startOffset;
  17814. lastMatch.set(&entry);
  17815. }
  17816. virtual const void *nextInGroup()
  17817. {
  17818. // Note - in remote case this never gets called as input chain is routed to remoteResultAdaptor
  17819. assertex(xmlParser != NULL);
  17820. try
  17821. {
  17822. while (!eof)
  17823. {
  17824. //call to next() will callback on the IXmlSelect interface
  17825. bool gotNext = false;
  17826. gotNext = xmlParser->next();
  17827. if(!gotNext)
  17828. eof = true;
  17829. else if (lastMatch)
  17830. {
  17831. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  17832. unsigned sizeGot = rowTransformer->transform(rowBuilder, lastMatch, reader->queryThorDiskCallback());
  17833. lastMatch.clear();
  17834. localOffset = 0;
  17835. if (sizeGot)
  17836. {
  17837. OwnedConstRoxieRow ret = rowBuilder.finalizeRowClear(sizeGot);
  17838. if (processed > rowLimit)
  17839. {
  17840. if (traceLevel > 4)
  17841. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  17842. readHelper->onLimitExceeded();
  17843. throwUnexpected(); // onLimitExceeded is not supposed to return
  17844. }
  17845. processed++;
  17846. if (processed > stopAfter) // MORE - bit of a strange place to check
  17847. {
  17848. eof = true;
  17849. return NULL;
  17850. }
  17851. return ret.getClear();
  17852. }
  17853. }
  17854. }
  17855. return NULL;
  17856. }
  17857. catch(IException *E)
  17858. {
  17859. throw makeWrappedException(E);
  17860. }
  17861. }
  17862. };
  17863. class CRoxieServerCsvReadActivity : public CRoxieServerDiskReadBaseActivity
  17864. {
  17865. IHThorCsvReadArg *readHelper;
  17866. ICsvParameters * csvInfo;
  17867. unsigned headerLines;
  17868. unsigned maxDiskSize;
  17869. CSVSplitter csvSplitter;
  17870. unsigned __int64 localOffset;
  17871. const char *quotes;
  17872. const char *separators;
  17873. const char *terminators;
  17874. public:
  17875. CRoxieServerCsvReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  17876. unsigned _numParts, bool _isLocal, bool _sorted, bool _maySkip, IInMemoryIndexManager *_manager,
  17877. const char *_quotes, const char *_separators, const char *_terminators)
  17878. : CRoxieServerDiskReadBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _sorted, _maySkip, _manager),
  17879. quotes(_quotes), separators(_separators), terminators(_terminators)
  17880. {
  17881. compoundHelper = NULL;
  17882. readHelper = (IHThorCsvReadArg *)&helper;
  17883. rowLimit = readHelper->getRowLimit();
  17884. stopAfter = readHelper->getChooseNLimit();
  17885. csvInfo = readHelper->queryCsvParameters();
  17886. maxDiskSize = csvInfo->queryMaxSize();
  17887. localOffset = 0;
  17888. headerLines = 0;
  17889. }
  17890. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  17891. {
  17892. rowLimit = readHelper->getRowLimit();
  17893. stopAfter = readHelper->getChooseNLimit();
  17894. CRoxieServerDiskReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  17895. if (!remote)
  17896. {
  17897. headerLines = csvInfo->queryHeaderLen();
  17898. if (headerLines && isLocal && reader->queryFilePart() != 1)
  17899. headerLines = 0; // MORE - you could argue that if SINGLE not specified, should skip from all parts. But it would be painful since we have already concatenated and no-one else does...
  17900. if (!eof)
  17901. {
  17902. if (varFileInfo)
  17903. {
  17904. const IPropertyTree *options = varFileInfo->queryProperties();
  17905. if (options)
  17906. {
  17907. quotes = options->queryProp("@csvQuote");
  17908. separators = options->queryProp("@csvSeparate");
  17909. terminators = options->queryProp("@csvTerminate");
  17910. }
  17911. }
  17912. csvSplitter.init(readHelper->getMaxColumns(), csvInfo, quotes, separators, terminators);
  17913. }
  17914. }
  17915. }
  17916. virtual const void *nextInGroup()
  17917. {
  17918. // Note - in remote case this never gets called as input chain is routed to remoteResultAdaptor
  17919. try
  17920. {
  17921. while (!eof)
  17922. {
  17923. if (reader->eos())
  17924. {
  17925. eof = true;
  17926. break;
  17927. }
  17928. // MORE - there are rumours of a csvSplitter that operates on a stream... if/when it exists, this should use it
  17929. size32_t rowSize = 4096; // MORE - make configurable
  17930. size32_t maxRowSize = 10*1024*1024; // MORE - make configurable
  17931. size32_t thisLineLength;
  17932. loop
  17933. {
  17934. size32_t avail;
  17935. const void *peek = reader->peek(rowSize, avail);
  17936. thisLineLength = csvSplitter.splitLine(avail, (const byte *)peek);
  17937. if (thisLineLength < rowSize || avail < rowSize)
  17938. break;
  17939. if (rowSize == maxRowSize)
  17940. throw MakeStringException(0, "Row too big");
  17941. if (rowSize >= maxRowSize/2)
  17942. rowSize = maxRowSize;
  17943. else
  17944. rowSize += rowSize;
  17945. }
  17946. if (headerLines)
  17947. {
  17948. headerLines--;
  17949. reader->skip(thisLineLength);
  17950. }
  17951. else
  17952. {
  17953. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  17954. unsigned transformedSize = readHelper->transform(rowBuilder, csvSplitter.queryLengths(), (const char * *)csvSplitter.queryData());
  17955. reader->skip(thisLineLength);
  17956. if (transformedSize)
  17957. {
  17958. OwnedConstRoxieRow ret = rowBuilder.finalizeRowClear(transformedSize);
  17959. if (processed > rowLimit)
  17960. {
  17961. readHelper->onLimitExceeded();
  17962. throwUnexpected(); // onLimitExceeded is not supposed to return
  17963. }
  17964. processed++;
  17965. if (processed > stopAfter) // MORE - bit of a strange place to check
  17966. {
  17967. eof = true;
  17968. return NULL;
  17969. }
  17970. return ret.getClear();
  17971. }
  17972. }
  17973. }
  17974. return NULL;
  17975. }
  17976. catch(IException *E)
  17977. {
  17978. throw makeWrappedException(E);
  17979. }
  17980. }
  17981. virtual void reset()
  17982. {
  17983. CRoxieServerDiskReadBaseActivity::reset();
  17984. csvSplitter.reset();
  17985. localOffset = 0;
  17986. }
  17987. virtual unsigned __int64 getFilePosition(const void * row)
  17988. {
  17989. UNIMPLEMENTED; // we know offset in the reader but not sure it helps us much
  17990. }
  17991. virtual unsigned __int64 getLocalFilePosition(const void * row)
  17992. {
  17993. UNIMPLEMENTED;
  17994. }
  17995. };
  17996. class CRoxieServerDiskNormalizeActivity : public CRoxieServerDiskReadBaseActivity
  17997. {
  17998. IHThorDiskNormalizeArg *normalizeHelper;
  17999. bool firstPending;
  18000. public:
  18001. CRoxieServerDiskNormalizeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, bool _sorted, IInMemoryIndexManager *_manager)
  18002. : CRoxieServerDiskReadBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _sorted, false, _manager)
  18003. {
  18004. compoundHelper = (IHThorDiskNormalizeArg *)&helper;
  18005. normalizeHelper = (IHThorDiskNormalizeArg *)&helper;
  18006. firstPending = true;
  18007. }
  18008. virtual void reset()
  18009. {
  18010. firstPending = true;
  18011. CRoxieServerDiskReadBaseActivity::reset();
  18012. }
  18013. virtual const void *nextInGroup()
  18014. {
  18015. if (eof)
  18016. return NULL;
  18017. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  18018. unsigned transformedSize = 0;
  18019. if (isKeyed)
  18020. {
  18021. loop
  18022. {
  18023. while (firstPending)
  18024. {
  18025. const void *nextCandidate = cursor->nextMatch();
  18026. if (!nextCandidate)
  18027. {
  18028. eof = true;
  18029. return NULL;
  18030. }
  18031. if (normalizeHelper->first(nextCandidate))
  18032. {
  18033. firstPending = false;
  18034. break;
  18035. }
  18036. }
  18037. transformedSize = normalizeHelper->transform(rowBuilder);
  18038. firstPending = !normalizeHelper->next();
  18039. if (transformedSize)
  18040. break;
  18041. }
  18042. }
  18043. else
  18044. {
  18045. assertex(reader != NULL);
  18046. loop
  18047. {
  18048. while (firstPending)
  18049. {
  18050. if (deserializeSource.eos())
  18051. {
  18052. eof = true;
  18053. return NULL;
  18054. }
  18055. prefetcher->readAhead(deserializeSource);
  18056. const byte *nextRec = deserializeSource.queryRow();
  18057. if (!cursor || !cursor->isFiltered(nextRec))
  18058. {
  18059. if (normalizeHelper->first(nextRec))
  18060. firstPending = false;
  18061. }
  18062. deserializeSource.finishedRow();
  18063. }
  18064. transformedSize = normalizeHelper->transform(rowBuilder);
  18065. firstPending = !normalizeHelper->next();
  18066. if (transformedSize)
  18067. break;
  18068. }
  18069. }
  18070. OwnedConstRoxieRow recBuffer = rowBuilder.finalizeRowClear(transformedSize);
  18071. processed++;
  18072. if (processed > rowLimit)
  18073. {
  18074. compoundHelper->onLimitExceeded();
  18075. throwUnexpected(); // onLimitExceeded is not supposed to return
  18076. }
  18077. if (processed > stopAfter) // MORE - bit of a strange place to check
  18078. {
  18079. eof = true;
  18080. return NULL;
  18081. }
  18082. return recBuffer.getClear();
  18083. }
  18084. };
  18085. class CRoxieServerDiskAggregateBaseActivity : public CRoxieServerDiskReadBaseActivity
  18086. {
  18087. protected:
  18088. bool done;
  18089. public:
  18090. CRoxieServerDiskAggregateBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, IInMemoryIndexManager *_manager)
  18091. : CRoxieServerDiskReadBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, false, false, _manager),
  18092. done(false)
  18093. {
  18094. }
  18095. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  18096. {
  18097. done = false;
  18098. CRoxieServerDiskReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  18099. }
  18100. virtual IRoxieInput *queryOutput(unsigned idx)
  18101. {
  18102. if (idx==(unsigned)-1)
  18103. idx = 0;
  18104. return idx ? NULL: this;
  18105. }
  18106. };
  18107. class CRoxieServerDiskCountActivity : public CRoxieServerDiskAggregateBaseActivity
  18108. {
  18109. IHThorDiskCountArg & countHelper;
  18110. unsigned __int64 choosenLimit;
  18111. IHThorSourceCountLimit *limitHelper;
  18112. unsigned __int64 getSkippedCount()
  18113. {
  18114. unsigned flags = countHelper.getFlags();
  18115. if (flags & TDRlimitskips)
  18116. return 0;
  18117. else if (flags & TDRlimitcreates)
  18118. return 1;
  18119. else
  18120. {
  18121. assertex(limitHelper);
  18122. if (traceLevel > 4)
  18123. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  18124. limitHelper->onLimitExceeded();
  18125. throwUnexpected(); // onLimitExceeded should always throw exception
  18126. }
  18127. }
  18128. public:
  18129. CRoxieServerDiskCountActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, IInMemoryIndexManager *_manager)
  18130. : CRoxieServerDiskAggregateBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _manager),
  18131. countHelper((IHThorDiskCountArg &)basehelper)
  18132. {
  18133. limitHelper = static_cast<IHThorSourceCountLimit *>(basehelper.selectInterface(TAIsourcecountlimit_1));
  18134. choosenLimit = 0;
  18135. }
  18136. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  18137. {
  18138. choosenLimit = countHelper.getChooseNLimit();
  18139. if (limitHelper)
  18140. {
  18141. rowLimit = limitHelper->getRowLimit();
  18142. // keyedLimit = limitHelper->getKeyedLimit(); // more - should there be one?
  18143. }
  18144. CRoxieServerDiskAggregateBaseActivity::start(parentExtractSize, parentExtract, paused);
  18145. }
  18146. virtual const void *nextInGroup()
  18147. {
  18148. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  18149. if (done) return NULL;
  18150. done = true;
  18151. unsigned __int64 totalCount = 0;
  18152. if (helper.canMatchAny())
  18153. {
  18154. if (remote)
  18155. {
  18156. loop
  18157. {
  18158. const void * next = remote->nextInGroup();
  18159. if (!next)
  18160. break;
  18161. if (meta.getFixedSize() == 1)
  18162. totalCount += *(byte *)next;
  18163. else
  18164. totalCount += *(unsigned __int64 *)next;
  18165. ReleaseRoxieRow(next);
  18166. if (totalCount > rowLimit)
  18167. {
  18168. totalCount = getSkippedCount();
  18169. break;
  18170. }
  18171. else if (totalCount >= choosenLimit)
  18172. {
  18173. totalCount = choosenLimit;
  18174. break;
  18175. }
  18176. }
  18177. }
  18178. else
  18179. {
  18180. if (isKeyed)
  18181. {
  18182. loop
  18183. {
  18184. const void *nextCandidate = cursor->nextMatch();
  18185. if (!nextCandidate)
  18186. break;
  18187. totalCount += countHelper.numValid(nextCandidate);
  18188. if (totalCount > rowLimit)
  18189. {
  18190. totalCount = getSkippedCount();
  18191. break;
  18192. }
  18193. else if (totalCount >= choosenLimit)
  18194. {
  18195. totalCount = choosenLimit;
  18196. break;
  18197. }
  18198. }
  18199. }
  18200. else
  18201. {
  18202. assertex(reader != NULL);
  18203. while (!deserializeSource.eos())
  18204. {
  18205. prefetcher->readAhead(deserializeSource);
  18206. const byte *nextRec = deserializeSource.queryRow();
  18207. if (!cursor || !cursor->isFiltered(nextRec))
  18208. {
  18209. totalCount += countHelper.numValid(nextRec);
  18210. }
  18211. deserializeSource.finishedRow();
  18212. if (totalCount > rowLimit)
  18213. {
  18214. totalCount = getSkippedCount();
  18215. break;
  18216. }
  18217. else if (totalCount >= choosenLimit)
  18218. {
  18219. totalCount = choosenLimit;
  18220. break;
  18221. }
  18222. }
  18223. }
  18224. }
  18225. }
  18226. size32_t rowSize = meta.getFixedSize();
  18227. void * result = rowAllocator->createRow();
  18228. if (rowSize == 1)
  18229. *(byte *)result = (byte)totalCount;
  18230. else
  18231. {
  18232. assertex(rowSize == sizeof(unsigned __int64));
  18233. *(unsigned __int64 *)result = totalCount;
  18234. }
  18235. return rowAllocator->finalizeRow(rowSize, result, rowSize);
  18236. }
  18237. };
  18238. class CRoxieServerDiskAggregateActivity : public CRoxieServerDiskAggregateBaseActivity
  18239. {
  18240. IHThorCompoundAggregateExtra & aggregateHelper;
  18241. public:
  18242. CRoxieServerDiskAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  18243. unsigned _numParts, bool _isLocal, IInMemoryIndexManager *_manager)
  18244. : CRoxieServerDiskAggregateBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _manager),
  18245. aggregateHelper((IHThorDiskAggregateArg &)basehelper)
  18246. {
  18247. }
  18248. const void * gatherMerged()
  18249. {
  18250. RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
  18251. size32_t finalSize = 0;
  18252. if (remote)
  18253. {
  18254. const void * firstRow = remote->nextInGroup();
  18255. if (!firstRow)
  18256. {
  18257. rowBuilder.ensureRow();
  18258. finalSize = aggregateHelper.clearAggregate(rowBuilder);
  18259. }
  18260. else
  18261. {
  18262. // NOTE need to clone this because going to modify below, could special case 1 row only
  18263. finalSize = cloneRow(rowBuilder, firstRow, meta);
  18264. ReleaseRoxieRow(firstRow);
  18265. }
  18266. loop
  18267. {
  18268. const void * next = remote->nextInGroup();
  18269. if (!next)
  18270. break;
  18271. finalSize = aggregateHelper.mergeAggregate(rowBuilder, next);
  18272. ReleaseRoxieRow(next);
  18273. }
  18274. }
  18275. else
  18276. {
  18277. aggregateHelper.clearAggregate(rowBuilder);
  18278. if (isKeyed)
  18279. {
  18280. loop
  18281. {
  18282. const void *next = cursor->nextMatch();
  18283. if (!next)
  18284. break;
  18285. aggregateHelper.processRow(rowBuilder, next);
  18286. }
  18287. }
  18288. else
  18289. {
  18290. assertex(reader != NULL);
  18291. while (!deserializeSource.eos())
  18292. {
  18293. prefetcher->readAhead(deserializeSource);
  18294. const byte *nextRec = deserializeSource.queryRow();
  18295. if (!cursor || !cursor->isFiltered(nextRec))
  18296. {
  18297. aggregateHelper.processRow(rowBuilder, nextRec);
  18298. }
  18299. deserializeSource.finishedRow();
  18300. }
  18301. }
  18302. finalSize = meta.getRecordSize(rowBuilder.getSelf());
  18303. }
  18304. return rowBuilder.finalizeRowClear(finalSize);
  18305. }
  18306. virtual const void *nextInGroup()
  18307. {
  18308. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  18309. if (done) return NULL;
  18310. const void * ret = gatherMerged();
  18311. done = true;
  18312. return ret;
  18313. }
  18314. };
  18315. class CRoxieServerDiskGroupAggregateActivity : public CRoxieServerDiskAggregateBaseActivity
  18316. {
  18317. IHThorDiskGroupAggregateArg & aggregateHelper;
  18318. RowAggregator resultAggregator;
  18319. bool gathered;
  18320. public:
  18321. IMPLEMENT_IINTERFACE;
  18322. CRoxieServerDiskGroupAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _numParts, bool _isLocal, IInMemoryIndexManager *_manager)
  18323. : CRoxieServerDiskAggregateBaseActivity(_factory, _probeManager, _remoteId, _numParts, _isLocal, _manager),
  18324. aggregateHelper((IHThorDiskGroupAggregateArg &)basehelper),
  18325. resultAggregator(aggregateHelper, aggregateHelper),
  18326. gathered(false)
  18327. {
  18328. }
  18329. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  18330. {
  18331. gathered= false;
  18332. CRoxieServerDiskAggregateBaseActivity::start(parentExtractSize, parentExtract, paused);
  18333. resultAggregator.start(rowAllocator);
  18334. }
  18335. virtual void reset()
  18336. {
  18337. resultAggregator.reset();
  18338. CRoxieServerDiskAggregateBaseActivity::reset();
  18339. }
  18340. void gatherMerged()
  18341. {
  18342. if (remote)
  18343. {
  18344. loop
  18345. {
  18346. const void * next = remote->nextInGroup();
  18347. if (!next)
  18348. break;
  18349. resultAggregator.mergeElement(next);
  18350. ReleaseRoxieRow(next);
  18351. }
  18352. }
  18353. else
  18354. {
  18355. Owned<IInMemoryFileProcessor> processor = isKeyed ?
  18356. createKeyedGroupAggregateRecordProcessor(cursor, resultAggregator, aggregateHelper) :
  18357. createUnkeyedGroupAggregateRecordProcessor(cursor, resultAggregator, aggregateHelper, manager->createReader(0, 0, 1),
  18358. ctx->queryCodeContext(), activityId);
  18359. processor->doQuery(NULL, 0, 0, 0);
  18360. }
  18361. gathered = true;
  18362. }
  18363. virtual const void *nextInGroup()
  18364. {
  18365. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  18366. if (done)
  18367. return NULL;
  18368. if (!gathered)
  18369. gatherMerged();
  18370. Owned<AggregateRowBuilder> next = resultAggregator.nextResult();
  18371. if (next)
  18372. {
  18373. processed++;
  18374. return next->finalizeRowClear();
  18375. }
  18376. done = true;
  18377. return NULL;
  18378. }
  18379. };
  18380. class CRoxieServerDiskReadActivityFactory : public CRoxieServerActivityFactory
  18381. {
  18382. public:
  18383. RemoteActivityId remoteId;
  18384. bool isLocal;
  18385. bool sorted;
  18386. bool maySkip;
  18387. bool variableFileName;
  18388. Owned<IFilePartMap> map;
  18389. Owned<IFileIOArray> files;
  18390. Owned<IInMemoryIndexManager> manager;
  18391. Owned<const IResolvedFile> datafile;
  18392. const char *quotes;
  18393. const char *separators;
  18394. const char *terminators;
  18395. CRoxieServerDiskReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  18396. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), remoteId(_remoteId)
  18397. {
  18398. isLocal = _graphNode.getPropBool("att[@name='local']/@value");
  18399. Owned<IHThorDiskReadBaseArg> helper = (IHThorDiskReadBaseArg *) helperFactory();
  18400. sorted = (helper->getFlags() & TDRunsorted) == 0;
  18401. variableFileName = (helper->getFlags() & (TDXvarfilename|TDXdynamicfilename)) != 0;
  18402. maySkip = (helper->getFlags() & (TDRkeyedlimitskips|TDRkeyedlimitcreates|TDRlimitskips|TDRlimitcreates)) != 0;
  18403. quotes = separators = terminators = NULL;
  18404. if (!variableFileName)
  18405. {
  18406. bool isOpt = (helper->getFlags() & TDRoptional) != 0;
  18407. const char *fileName = helper->getFileName();
  18408. datafile.setown(_queryFactory.queryPackage().lookupFileName(fileName, isOpt, true));
  18409. if (datafile)
  18410. map.setown(datafile->getFileMap());
  18411. bool isSimple = (map && map->getNumParts()==1);
  18412. if (isLocal || isSimple)
  18413. {
  18414. if (datafile)
  18415. {
  18416. unsigned channel = isLocal ? queryFactory.queryChannel() : 0;
  18417. files.setown(datafile->getIFileIOArray(isOpt, channel));
  18418. manager.setown(datafile->getIndexManager(isOpt, channel, files, helper->queryDiskRecordSize(), _graphNode.getPropBool("att[@name=\"preload\"]/@value", false), _graphNode.getPropInt("att[@name=\"_preloadSize\"]/@value", 0)));
  18419. const IPropertyTree *options = datafile->queryProperties();
  18420. if (options)
  18421. {
  18422. quotes = options->queryProp("@csvQuote");
  18423. separators = options->queryProp("@csvSeparate");
  18424. terminators = options->queryProp("@csvTerminate");
  18425. }
  18426. }
  18427. else
  18428. manager.setown(getEmptyIndexManager());
  18429. }
  18430. }
  18431. }
  18432. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  18433. {
  18434. unsigned numParts = map ? map->getNumParts() : 0;
  18435. switch (kind)
  18436. {
  18437. case TAKcsvread:
  18438. return new CRoxieServerCsvReadActivity(this, _probeManager, remoteId, numParts, isLocal, sorted, maySkip, manager,
  18439. quotes, separators, terminators);
  18440. case TAKxmlread:
  18441. return new CRoxieServerXmlReadActivity(this, _probeManager, remoteId, numParts, isLocal, sorted, maySkip, manager);
  18442. case TAKdiskread:
  18443. return new CRoxieServerDiskReadActivity(this, _probeManager, remoteId, numParts, isLocal, sorted, maySkip, manager);
  18444. case TAKdisknormalize:
  18445. return new CRoxieServerDiskNormalizeActivity(this, _probeManager, remoteId, numParts, isLocal, sorted, manager);
  18446. case TAKdiskcount:
  18447. return new CRoxieServerDiskCountActivity(this, _probeManager, remoteId, numParts, isLocal, manager);
  18448. case TAKdiskaggregate:
  18449. return new CRoxieServerDiskAggregateActivity(this, _probeManager, remoteId, numParts, isLocal, manager);
  18450. case TAKdiskgroupaggregate:
  18451. return new CRoxieServerDiskGroupAggregateActivity(this, _probeManager, remoteId, numParts, isLocal, manager);
  18452. }
  18453. throwUnexpected();
  18454. }
  18455. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  18456. {
  18457. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for %s activity", getActivityText(kind));
  18458. }
  18459. };
  18460. IRoxieServerActivityFactory *createRoxieServerDiskReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  18461. {
  18462. return new CRoxieServerDiskReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
  18463. }
  18464. //=================================================================================
  18465. class CRoxieServerIndexActivity : public CRoxieServerActivity, implements IRoxieServerErrorHandler
  18466. {
  18467. protected:
  18468. IHThorIndexReadBaseArg &indexHelper;
  18469. IHThorSteppedSourceExtra * steppedExtra;
  18470. Linked<IKeyArray> keySet;
  18471. Linked<TranslatorArray> translators;
  18472. unsigned rawSize;
  18473. CSkippableRemoteResultAdaptor remote;
  18474. CIndexTransformCallback callback;
  18475. bool sorted;
  18476. bool variableFileName;
  18477. bool variableInfoPending;
  18478. bool isOpt;
  18479. bool isLocal;
  18480. unsigned __int64 rowLimit;
  18481. unsigned __int64 keyedLimit;
  18482. unsigned __int64 choosenLimit;
  18483. unsigned accepted;
  18484. unsigned rejected;
  18485. unsigned seekGEOffset;
  18486. Owned<IKeyManager> tlk;
  18487. Owned<const IResolvedFile> varFileInfo;
  18488. const RemoteActivityId &remoteId;
  18489. void setVariableFileInfo()
  18490. {
  18491. varFileInfo.setown(resolveLFN(indexHelper.getFileName(), isOpt));
  18492. translators.setown(new TranslatorArray) ;
  18493. keySet.setown(varFileInfo->getKeyArray(factory->queryActivityMeta(), translators, isOpt, isLocal ? factory->queryQueryFactory().queryChannel() : 0, factory->queryQueryFactory().getEnableFieldTranslation()));
  18494. variableInfoPending = false;
  18495. }
  18496. public:
  18497. CRoxieServerIndexActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  18498. IKeyArray * _keySet, TranslatorArray *_translators, unsigned _rawSize, bool _sorted, bool _isLocal, bool _maySkip)
  18499. : CRoxieServerActivity(_factory, _probeManager),
  18500. keySet(_keySet),
  18501. translators(_translators),
  18502. rawSize(_rawSize),
  18503. indexHelper((IHThorIndexReadBaseArg &)basehelper),
  18504. remote(_remoteId, meta.queryOriginal(), indexHelper, *this, _sorted, false, _maySkip),
  18505. remoteId(_remoteId),
  18506. sorted(_sorted),
  18507. isLocal(_isLocal)
  18508. {
  18509. indexHelper.setCallback(&callback);
  18510. steppedExtra = static_cast<IHThorSteppedSourceExtra *>(indexHelper.selectInterface(TAIsteppedsourceextra_1));
  18511. variableFileName = (indexHelper.getFlags() & (TIRvarfilename|TIRdynamicfilename)) != 0;
  18512. variableInfoPending = false;
  18513. isOpt = (indexHelper.getFlags() & TIRoptional) != 0;
  18514. seekGEOffset = 0;
  18515. // started = false;
  18516. rejected = accepted = 0;
  18517. rowLimit = choosenLimit = keyedLimit = 0;
  18518. }
  18519. virtual const IResolvedFile *queryVarFileInfo() const
  18520. {
  18521. return varFileInfo;
  18522. }
  18523. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  18524. {
  18525. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  18526. remote.onCreate(this, this, _ctx, _colocalParent);
  18527. }
  18528. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  18529. {
  18530. accepted = 0;
  18531. rejected = 0;
  18532. rowLimit = (unsigned __int64) -1;
  18533. keyedLimit = (unsigned __int64 ) -1;
  18534. choosenLimit = I64C(0x7fffffffffffffff);
  18535. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  18536. remote.onStart(parentExtractSize, parentExtract);
  18537. variableInfoPending = variableFileName;
  18538. }
  18539. void processAllKeys()
  18540. {
  18541. try
  18542. {
  18543. if (indexHelper.canMatchAny())
  18544. {
  18545. if (variableInfoPending)
  18546. setVariableFileInfo();
  18547. remote.setLimits(rowLimit, keyedLimit, choosenLimit);
  18548. if (keySet)
  18549. {
  18550. // MORE - this recreates the segmonitors per part but not per fileno (which is a little backwards).
  18551. // With soft layout support may need to recreate per fileno too (i.e. different keys in a superkey have different layout) but never per partno
  18552. // However order is probably better to iterate fileno's inside partnos
  18553. // MORE - also not properly supporting STEPPED I fear.
  18554. // A superkey that mixes single and multipart or tlk and roroot keys might be hard
  18555. for (unsigned partNo = 0; partNo < keySet->length(); partNo++)
  18556. {
  18557. IKeyIndexBase *thisBase = keySet->queryKeyPart(partNo);
  18558. if (thisBase)
  18559. {
  18560. unsigned fileNo = 0;
  18561. IKeyIndex *thisKey = thisBase->queryPart(fileNo);
  18562. if (seekGEOffset && !thisKey->isTopLevelKey())
  18563. {
  18564. tlk.setown(createSingleKeyMerger(thisKey, 0, seekGEOffset, this));
  18565. }
  18566. else
  18567. {
  18568. tlk.setown(createKeyManager(thisKey, 0, this));
  18569. tlk->setLayoutTranslator(translators->item(fileNo));
  18570. }
  18571. createSegmentMonitors(tlk);
  18572. if (queryTraceLevel() > 3 || ctx->queryProbeManager())
  18573. {
  18574. StringBuffer out;
  18575. printKeyedValues(out, tlk, indexHelper.queryDiskRecordSize());
  18576. CTXLOG("Using filter %s", out.str());
  18577. if (ctx->queryProbeManager())
  18578. ctx->queryProbeManager()->setNodeProperty(this, "filter", out.str());
  18579. }
  18580. tlk->reset();
  18581. loop // for each file part
  18582. {
  18583. //block for TransformCallbackAssociation
  18584. {
  18585. TransformCallbackAssociation associate(callback, tlk);
  18586. if (thisKey->isTopLevelKey())
  18587. {
  18588. if (thisKey->isFullySorted())
  18589. {
  18590. while (tlk->lookup(false))
  18591. {
  18592. unsigned slavePart = (unsigned) tlk->queryFpos();
  18593. if (slavePart)
  18594. {
  18595. accepted++;
  18596. remote.getMem(slavePart, fileNo, 0); // the cached context is all we need to send
  18597. if (sorted && numChannels>1)
  18598. remote.flush(); // don't combine parts if we need result sorted, except on a 1-way
  18599. }
  18600. }
  18601. }
  18602. else
  18603. {
  18604. // MORE - we could check whether there are any matching parts if we wanted.
  18605. // If people are in the habit of sending null values that would be worthwhile
  18606. remote.getMem(0, fileNo, 0);
  18607. }
  18608. }
  18609. else
  18610. {
  18611. if (keyedLimit != (unsigned __int64) -1)
  18612. {
  18613. if ((indexHelper.getFlags() & TIRcountkeyedlimit) != 0)
  18614. {
  18615. unsigned __int64 count = tlk->checkCount(keyedLimit);
  18616. if (count > keyedLimit)
  18617. {
  18618. if (traceLevel > 4)
  18619. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  18620. onLimitExceeded(true);
  18621. }
  18622. tlk->reset();
  18623. }
  18624. }
  18625. if (processSingleKey(thisKey, translators->item(fileNo)))
  18626. break;
  18627. }
  18628. }
  18629. if (++fileNo < thisBase->numParts())
  18630. {
  18631. thisKey = thisBase->queryPart(fileNo);
  18632. tlk->setKey(thisKey);
  18633. tlk->setLayoutTranslator(translators->item(fileNo));
  18634. tlk->reset();
  18635. }
  18636. else
  18637. break;
  18638. }
  18639. tlk->releaseSegmentMonitors();
  18640. tlk->setKey(NULL);
  18641. }
  18642. }
  18643. }
  18644. }
  18645. remote.flush();
  18646. remote.senddone();
  18647. }
  18648. catch (IException *E)
  18649. {
  18650. remote.setException(E);
  18651. }
  18652. }
  18653. virtual void createSegmentMonitors(IKeyManager *key)
  18654. {
  18655. indexHelper.createSegmentMonitors(key);
  18656. key->finishSegmentMonitors();
  18657. }
  18658. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans) = 0;
  18659. virtual void reset()
  18660. {
  18661. if (accepted)
  18662. noteStatistic(STATS_ACCEPTED, accepted, 1);
  18663. if (rejected)
  18664. noteStatistic(STATS_REJECTED, rejected, 1);
  18665. remote.onReset();
  18666. CRoxieServerActivity::reset();
  18667. if (varFileInfo)
  18668. {
  18669. keySet.clear();
  18670. varFileInfo.clear();
  18671. }
  18672. variableInfoPending = false;
  18673. }
  18674. virtual void stop(bool aborting)
  18675. {
  18676. remote.onStop(aborting);
  18677. CRoxieServerActivity::stop(aborting);
  18678. }
  18679. virtual void setInput(unsigned idx, IRoxieInput *_in)
  18680. {
  18681. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  18682. }
  18683. };
  18684. class CRoxieServerIndexReadBaseActivity : public CRoxieServerIndexActivity
  18685. {
  18686. IHThorSourceLimitTransformExtra * limitTransformExtra;
  18687. public:
  18688. CRoxieServerIndexReadBaseActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  18689. IKeyArray * _keySet, TranslatorArray *_translators, unsigned _rawSize, unsigned _maxRecordSize, bool _sorted, bool _isLocal, bool _maySkip)
  18690. : CRoxieServerIndexActivity(_factory, _probeManager, _remoteId, _keySet, _translators, _rawSize, _sorted, _isLocal, _maySkip)
  18691. {
  18692. limitTransformExtra = static_cast<IHThorSourceLimitTransformExtra *>(indexHelper.selectInterface(TAIsourcelimittransformextra_1));
  18693. }
  18694. virtual void reset()
  18695. {
  18696. remote.onReset();
  18697. CRoxieServerIndexActivity::reset();
  18698. }
  18699. virtual const void *nextInGroup()
  18700. {
  18701. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  18702. try
  18703. {
  18704. const void *ret = remote.nextInGroup();
  18705. if (ret)
  18706. processed++;
  18707. return ret;
  18708. }
  18709. catch (IException *E)
  18710. {
  18711. throw makeWrappedException(E);
  18712. }
  18713. }
  18714. protected:
  18715. virtual const void * createLimitFailRow(bool isKeyed)
  18716. {
  18717. createRowAllocator();
  18718. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  18719. size32_t outSize = isKeyed ? limitTransformExtra->transformOnKeyedLimitExceeded(rowBuilder) : limitTransformExtra->transformOnLimitExceeded(rowBuilder);
  18720. if (outSize)
  18721. return rowBuilder.finalizeRowClear(outSize);
  18722. return NULL;
  18723. }
  18724. };
  18725. class CRoxieServerIndexReadActivity : public CRoxieServerIndexReadBaseActivity, implements IIndexReadActivityInfo
  18726. {
  18727. protected:
  18728. IHThorCompoundReadExtra & readHelper;
  18729. ISteppingMeta *rawMeta;
  18730. CSteppingMeta steppingMeta;
  18731. unsigned * seekSizes;
  18732. bool optimizeSteppedPostFilter;
  18733. ISteppingMeta * projectedMeta;
  18734. unsigned maxSeekLookahead;
  18735. public:
  18736. CRoxieServerIndexReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  18737. IKeyArray * _keySet, TranslatorArray *_translators, unsigned _rawSize, unsigned _maxRecordSize, bool _sorted, bool _isLocal, bool _maySkip, unsigned _maxSeekLookahead)
  18738. : CRoxieServerIndexReadBaseActivity(_factory, _probeManager, _remoteId, _keySet, _translators, _rawSize, _maxRecordSize, _sorted, _isLocal, _maySkip),
  18739. readHelper((IHThorIndexReadArg &)basehelper)
  18740. {
  18741. rawMeta = readHelper.queryRawSteppingMeta();
  18742. unsigned flags = indexHelper.getFlags();
  18743. optimizeSteppedPostFilter = (flags & TIRunfilteredtransform) != 0;
  18744. seekSizes = NULL;
  18745. maxSeekLookahead = _maxSeekLookahead;
  18746. if (rawMeta)
  18747. {
  18748. const CFieldOffsetSize * fields = rawMeta->queryFields();
  18749. unsigned maxFields = rawMeta->getNumFields();
  18750. seekGEOffset = fields[0].offset;
  18751. seekSizes = new unsigned[maxFields];
  18752. seekSizes[0] = fields[0].size;
  18753. for (unsigned i=1; i < maxFields; i++)
  18754. seekSizes[i] = seekSizes[i-1] + fields[i].size;
  18755. projectedMeta = readHelper.queryProjectedSteppingMeta();
  18756. ISteppingMeta *useMeta = projectedMeta ? projectedMeta : rawMeta;
  18757. remote.setMergeInfo(useMeta); // also need to consider superfile case where there is a mix of multiway and singleparts.. ?
  18758. bool hasPostFilter = readHelper.transformMayFilter() && optimizeSteppedPostFilter;
  18759. steppingMeta.init(useMeta, hasPostFilter);
  18760. }
  18761. }
  18762. ~CRoxieServerIndexReadActivity()
  18763. {
  18764. delete [] seekSizes;
  18765. }
  18766. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  18767. {
  18768. CRoxieServerIndexReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  18769. steppingMeta.setDistributed();
  18770. if (steppedExtra)
  18771. steppingMeta.setExtra(steppedExtra);
  18772. rowLimit = readHelper.getRowLimit();
  18773. keyedLimit = readHelper.getKeyedLimit();
  18774. choosenLimit = readHelper.getChooseNLimit();
  18775. if (!paused)
  18776. processAllKeys();
  18777. }
  18778. class LazyLocalKeyReader : public CInterface, implements IMessageResult, implements IMessageUnpackCursor
  18779. {
  18780. public:
  18781. IMPLEMENT_IINTERFACE;
  18782. virtual IMessageUnpackCursor *getCursor(roxiemem::IRowManager *rowMgr) const
  18783. {
  18784. Link();
  18785. return const_cast<LazyLocalKeyReader*> (this);
  18786. }
  18787. virtual const void *getMessageHeader(unsigned &length) const
  18788. {
  18789. length = 0;
  18790. return NULL;
  18791. }
  18792. virtual const void *getMessageMetadata(unsigned &length) const
  18793. {
  18794. length = 0;
  18795. return NULL;
  18796. }
  18797. virtual void discard() const
  18798. {
  18799. // nothing to do.
  18800. }
  18801. unsigned keyedCount;
  18802. unsigned matched;
  18803. bool EOFseen;
  18804. Owned<IKeyIndexSet> keySet;
  18805. Owned<IKeyManager> tlk;
  18806. CRoxieServerIndexReadActivity &owner;
  18807. LazyLocalKeyReader(CRoxieServerIndexReadActivity &_owner, IKeyIndex *key, IRecordLayoutTranslator * trans)
  18808. : owner(_owner)
  18809. {
  18810. keyedCount = 0;
  18811. matched = 0;
  18812. EOFseen = false;
  18813. keySet.setown(createKeyIndexSet());
  18814. keySet->addIndex(LINK(key));
  18815. if (owner.seekGEOffset)
  18816. tlk.setown(createKeyMerger(keySet, owner.rawSize, owner.seekGEOffset, &owner));
  18817. else
  18818. tlk.setown(createKeyManager(keySet->queryPart(0), 0, &owner));
  18819. tlk->setLayoutTranslator(trans);
  18820. owner.indexHelper.createSegmentMonitors(tlk);
  18821. tlk->finishSegmentMonitors();
  18822. tlk->reset();
  18823. }
  18824. virtual const void *getNext(int length)
  18825. {
  18826. TransformCallbackAssociation associate(owner.callback, tlk);
  18827. while (tlk->lookup(true))
  18828. {
  18829. keyedCount++;
  18830. if (keyedCount > owner.keyedLimit)
  18831. {
  18832. owner.onLimitExceeded(true); // Should throw exception
  18833. throwUnexpected();
  18834. }
  18835. size32_t transformedSize;
  18836. RtlDynamicRowBuilder rowBuilder(owner.rowAllocator);
  18837. byte const * keyRow = tlk->queryKeyBuffer(owner.callback.getFPosRef());
  18838. try
  18839. {
  18840. transformedSize = owner.readHelper.transform(rowBuilder, keyRow);
  18841. owner.callback.finishedRow();
  18842. }
  18843. catch (IException *E)
  18844. {
  18845. throw owner.makeWrappedException(E);
  18846. }
  18847. if (transformedSize)
  18848. {
  18849. OwnedConstRoxieRow result = rowBuilder.finalizeRowClear(transformedSize);
  18850. matched++;
  18851. if (matched > owner.rowLimit)
  18852. {
  18853. owner.onLimitExceeded(false); // Should throw exception
  18854. throwUnexpected();
  18855. }
  18856. if (matched > owner.choosenLimit) // MORE - bit of a strange place to check
  18857. {
  18858. break;
  18859. }
  18860. owner.accepted++;
  18861. return result.getClear();
  18862. }
  18863. else
  18864. owner.rejected++;
  18865. }
  18866. EOFseen = true;
  18867. return NULL;
  18868. }
  18869. virtual bool atEOF() const
  18870. {
  18871. return EOFseen;
  18872. }
  18873. virtual bool isSerialized() const
  18874. {
  18875. return false;
  18876. }
  18877. };
  18878. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
  18879. {
  18880. createRowAllocator();
  18881. remote.injectResult(new LazyLocalKeyReader(*this, key, trans));
  18882. return false;
  18883. }
  18884. virtual void onLimitExceeded(bool isKeyed)
  18885. {
  18886. if (traceLevel > 4)
  18887. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  18888. if (isKeyed)
  18889. {
  18890. if (indexHelper.getFlags() & (TIRkeyedlimitskips|TIRkeyedlimitcreates))
  18891. {
  18892. if (ctx->queryDebugContext())
  18893. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  18894. throw makeLimitSkipException(true);
  18895. }
  18896. else
  18897. readHelper.onKeyedLimitExceeded();
  18898. }
  18899. else
  18900. {
  18901. if (indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates))
  18902. {
  18903. if (ctx->queryDebugContext())
  18904. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  18905. throw makeLimitSkipException(false);
  18906. }
  18907. else
  18908. readHelper.onLimitExceeded();
  18909. }
  18910. }
  18911. virtual void serializeSkipInfo(MemoryBuffer &out, unsigned seekLen, const void *rawSeek, unsigned numFields, const void * seek, const SmartStepExtra &stepExtra) const
  18912. {
  18913. out.append((unsigned short) numFields);
  18914. out.append((unsigned short) seekLen);
  18915. out.append((unsigned short) stepExtra.queryFlags());
  18916. IMultipleStepSeekInfo *seeks = stepExtra.queryExtraSeeks();
  18917. if (seeks)
  18918. {
  18919. unsigned lookahead = 40000/seekLen;
  18920. if (maxSeekLookahead && (lookahead > maxSeekLookahead))
  18921. lookahead = maxSeekLookahead;
  18922. seeks->ensureFilled(seek, numFields, lookahead);
  18923. unsigned serialized = 1; // rawseek is always serialized...
  18924. unsigned patchLength = out.length();
  18925. out.append(serialized); // NOTE - we come back and patch with the actual value...
  18926. out.append(seekLen, rawSeek);
  18927. if (seeks->ordinality())
  18928. {
  18929. const void *lastSeek = rawSeek;
  18930. byte *nextSeek = NULL;
  18931. if (projectedMeta)
  18932. nextSeek = (byte *) alloca(seekLen);
  18933. for (unsigned i = 0; i < seeks->ordinality(); i++)
  18934. {
  18935. if (projectedMeta)
  18936. {
  18937. RtlStaticRowBuilder rowBuilder(nextSeek-seekGEOffset, seekGEOffset+seekLen);
  18938. readHelper.mapOutputToInput(rowBuilder, seeks->querySeek(i), numFields); // NOTE - weird interface to mapOutputToInput means that it STARTS writing at seekGEOffset...
  18939. }
  18940. else
  18941. nextSeek = (byte *) seeks->querySeek(i)+seekGEOffset;
  18942. int diff = memcmp(nextSeek, lastSeek, seekLen);
  18943. if (diff > 0)
  18944. {
  18945. serialized++;
  18946. out.append(seekLen, nextSeek);
  18947. lastSeek = (const byte *) out.reserve(0) - seekLen;
  18948. }
  18949. }
  18950. unsigned length = out.length();
  18951. out.setWritePos(patchLength);
  18952. out.append(serialized);
  18953. out.setWritePos(length);
  18954. }
  18955. }
  18956. else
  18957. {
  18958. out.append(1);
  18959. out.append(seekLen, rawSeek);
  18960. }
  18961. }
  18962. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  18963. {
  18964. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  18965. try
  18966. {
  18967. unsigned seeklen = 0;
  18968. const void *rawSeek = NULL;
  18969. if (seek && numFields)
  18970. {
  18971. seeklen = seekSizes[numFields-1];
  18972. rawSeek = (const byte *)seek + seekGEOffset;
  18973. if (projectedMeta)
  18974. {
  18975. byte * temp = (byte *) alloca(seeklen);
  18976. RtlStaticRowBuilder rawBuilder(temp-seekGEOffset, seekGEOffset+seeklen);
  18977. readHelper.mapOutputToInput(rawBuilder, seek, numFields); // NOTE - weird interface to mapOutputToInput means that it STARTS writing at seekGEOffset...
  18978. rawSeek = (byte *)temp;
  18979. }
  18980. }
  18981. const void *ret = remote.nextSteppedGE(seek, rawSeek, numFields, seeklen, wasCompleteMatch, stepExtra);
  18982. if (ret && wasCompleteMatch) // GH pleas confirm the wasCompleteMatch I just added here is right
  18983. processed++;
  18984. return ret;
  18985. }
  18986. catch (IException *E)
  18987. {
  18988. throw makeWrappedException(E);
  18989. }
  18990. }
  18991. virtual IInputSteppingMeta * querySteppingMeta()
  18992. {
  18993. if (rawMeta && steppingEnabled && ((indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates|TIRkeyedlimitskips|TIRkeyedlimitcreates)) == 0))
  18994. return &steppingMeta;
  18995. return NULL;
  18996. }
  18997. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  18998. {
  18999. if (variableInfoPending)
  19000. setVariableFileInfo();
  19001. return this;
  19002. }
  19003. virtual IKeyArray *getKeySet() const
  19004. {
  19005. return keySet.getLink();
  19006. }
  19007. virtual const IResolvedFile *getVarFileInfo() const
  19008. {
  19009. return varFileInfo.getLink();
  19010. }
  19011. virtual TranslatorArray *getTranslators() const
  19012. {
  19013. return translators.getLink();
  19014. }
  19015. virtual void mergeSegmentMonitors(IIndexReadContext *irc) const
  19016. {
  19017. indexHelper.createSegmentMonitors(irc); // NOTE: they will merge
  19018. }
  19019. virtual IRoxieServerActivity *queryActivity() { return this; }
  19020. virtual const RemoteActivityId& queryRemoteId() const
  19021. {
  19022. return remoteId;
  19023. }
  19024. };
  19025. class CRoxieServerSimpleIndexReadActivity : public CRoxieServerActivity, implements IIndexReadActivityInfo
  19026. {
  19027. IHThorCompoundReadExtra & readHelper;
  19028. IHThorIndexReadBaseArg & indexHelper;
  19029. IHThorSourceLimitTransformExtra * limitTransformExtra;
  19030. IHThorSteppedSourceExtra * steppedExtra;
  19031. bool eof;
  19032. Linked<IKeyArray>keySet;
  19033. Owned<IKeyIndexSet>keyIndexSet;
  19034. Owned<IKeyManager> tlk;
  19035. Linked<TranslatorArray> translators;
  19036. CIndexTransformCallback callback;
  19037. unsigned __int64 keyedLimit;
  19038. unsigned rowLimit;
  19039. unsigned chooseNLimit;
  19040. unsigned accepted;
  19041. unsigned rejected;
  19042. unsigned keyedCount;
  19043. unsigned rawSize;
  19044. ISteppingMeta * rawMeta;
  19045. ISteppingMeta * projectedMeta;
  19046. size32_t seekGEOffset;
  19047. unsigned * seekSizes;
  19048. size32_t eclKeySize;
  19049. CSteppingMeta steppingMeta;
  19050. Owned<const IResolvedFile> varFileInfo;
  19051. const RemoteActivityId &remoteId;
  19052. bool firstRead;
  19053. bool variableFileName;
  19054. bool variableInfoPending;
  19055. bool isOpt;
  19056. bool isLocal;
  19057. bool optimizeSteppedPostFilter;
  19058. // MORE there may be enough in common between this and CRoxieServerIndexActivity to warrant some refactoring
  19059. void initKeySet()
  19060. {
  19061. if ((keySet->length() > 1 || rawMeta != NULL) && translators->needsTranslation())
  19062. {
  19063. throw MakeStringException(ROXIE_UNIMPLEMENTED_ERROR, "Layout translation is not available when merging key parts or smart-stepping, as it may change record order");
  19064. }
  19065. keyIndexSet.setown(createKeyIndexSet());
  19066. for (unsigned part = 0; part < keySet->length(); part++)
  19067. {
  19068. IKeyIndexBase *kib = keySet->queryKeyPart(part);
  19069. if (kib)
  19070. {
  19071. for (unsigned subpart = 0; subpart < kib->numParts(); subpart++)
  19072. {
  19073. IKeyIndex *k = kib->queryPart(subpart);
  19074. if (k)
  19075. {
  19076. assertex(!k->isTopLevelKey());
  19077. keyIndexSet->addIndex(LINK(k));
  19078. }
  19079. }
  19080. }
  19081. }
  19082. }
  19083. void setVariableFileInfo()
  19084. {
  19085. varFileInfo.setown(resolveLFN(indexHelper.getFileName(), isOpt));
  19086. translators.setown(new TranslatorArray) ;
  19087. keySet.setown(varFileInfo->getKeyArray(factory->queryActivityMeta(), translators, isOpt, isLocal ? factory->queryQueryFactory().queryChannel() : 0, factory->queryQueryFactory().getEnableFieldTranslation()));
  19088. initKeySet();
  19089. variableInfoPending = false;
  19090. }
  19091. void onEOF()
  19092. {
  19093. callback.setManager(NULL);
  19094. eof = true;
  19095. tlk.clear();
  19096. }
  19097. public:
  19098. CRoxieServerSimpleIndexReadActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  19099. IKeyArray *_keyArray, TranslatorArray *_translatorArray, unsigned _rawSize, unsigned _maxRecordSize, bool _isLocal)
  19100. : CRoxieServerActivity(_factory, _probeManager),
  19101. readHelper((IHThorIndexReadArg &)basehelper),
  19102. indexHelper((IHThorIndexReadArg &)basehelper),
  19103. translators(_translatorArray),
  19104. rawSize(_rawSize),
  19105. keySet(_keyArray),
  19106. isLocal(_isLocal),
  19107. remoteId(_remoteId)
  19108. {
  19109. rowLimit = 0;
  19110. keyedLimit = 0;
  19111. chooseNLimit = 0;
  19112. indexHelper.setCallback(&callback);
  19113. steppedExtra = static_cast<IHThorSteppedSourceExtra *>(indexHelper.selectInterface(TAIsteppedsourceextra_1));
  19114. limitTransformExtra = static_cast<IHThorSourceLimitTransformExtra *>(indexHelper.selectInterface(TAIsourcelimittransformextra_1));
  19115. unsigned flags = indexHelper.getFlags();
  19116. variableFileName = (flags & (TIRvarfilename|TIRdynamicfilename)) != 0;
  19117. variableInfoPending = false;
  19118. isOpt = (flags & TIRoptional) != 0;
  19119. optimizeSteppedPostFilter = (flags & TIRunfilteredtransform) != 0;
  19120. firstRead = true;
  19121. accepted = 0;
  19122. rejected = 0;
  19123. keyedCount = 0;
  19124. eof = false;
  19125. rawMeta = readHelper.queryRawSteppingMeta();
  19126. projectedMeta = readHelper.queryProjectedSteppingMeta();
  19127. eclKeySize = indexHelper.queryDiskRecordSize()->getRecordSize(NULL);
  19128. seekGEOffset = 0;
  19129. seekSizes = NULL;
  19130. if (rawMeta)
  19131. {
  19132. // MORE - should check all keys in maxFields list can actually be keyed.
  19133. const CFieldOffsetSize * fields = rawMeta->queryFields();
  19134. unsigned maxFields = rawMeta->getNumFields();
  19135. seekGEOffset = fields[0].offset;
  19136. seekSizes = new unsigned[maxFields];
  19137. seekSizes[0] = fields[0].size;
  19138. for (unsigned i=1; i < maxFields; i++)
  19139. seekSizes[i] = seekSizes[i-1] + fields[i].size;
  19140. bool hasPostFilter = readHelper.transformMayFilter() && optimizeSteppedPostFilter;
  19141. if (projectedMeta)
  19142. steppingMeta.init(projectedMeta, hasPostFilter);
  19143. else
  19144. steppingMeta.init(rawMeta, hasPostFilter);
  19145. }
  19146. }
  19147. virtual const IResolvedFile *queryVarFileInfo() const
  19148. {
  19149. return varFileInfo;
  19150. }
  19151. ~CRoxieServerSimpleIndexReadActivity()
  19152. {
  19153. delete [] seekSizes;
  19154. }
  19155. virtual bool needsAllocator() const { return true; }
  19156. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  19157. {
  19158. firstRead = true;
  19159. accepted = 0;
  19160. rejected = 0;
  19161. keyedCount = 0;
  19162. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  19163. if (steppedExtra)
  19164. steppingMeta.setExtra(steppedExtra);
  19165. eof = !indexHelper.canMatchAny();
  19166. if (variableFileName)
  19167. variableInfoPending = true;
  19168. else
  19169. {
  19170. variableInfoPending = false;
  19171. if (!keyIndexSet)
  19172. initKeySet();
  19173. }
  19174. }
  19175. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  19176. {
  19177. if (variableInfoPending)
  19178. setVariableFileInfo();
  19179. return this;
  19180. }
  19181. virtual IKeyArray *getKeySet() const
  19182. {
  19183. return keySet.getLink();
  19184. }
  19185. virtual const IResolvedFile *getVarFileInfo() const
  19186. {
  19187. return varFileInfo.getLink();
  19188. }
  19189. virtual TranslatorArray *getTranslators() const
  19190. {
  19191. return translators.getLink();
  19192. }
  19193. virtual void mergeSegmentMonitors(IIndexReadContext *irc) const
  19194. {
  19195. indexHelper.createSegmentMonitors(irc); // NOTE: they will merge
  19196. }
  19197. virtual IRoxieServerActivity *queryActivity() { return this; }
  19198. virtual const RemoteActivityId& queryRemoteId() const
  19199. {
  19200. return remoteId;
  19201. }
  19202. const void *nextInGroup()
  19203. {
  19204. bool matched = true;
  19205. return nextSteppedGE(NULL, 0, matched, dummySmartStepExtra);
  19206. }
  19207. virtual const void *nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  19208. {
  19209. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  19210. if (eof)
  19211. return NULL;
  19212. if (firstRead)
  19213. {
  19214. if (variableInfoPending)
  19215. setVariableFileInfo();
  19216. rowLimit = (unsigned) readHelper.getRowLimit();
  19217. chooseNLimit = (unsigned) readHelper.getChooseNLimit();
  19218. unsigned numParts = keyIndexSet->numParts();
  19219. if (!numParts)
  19220. {
  19221. onEOF();
  19222. return NULL;
  19223. }
  19224. if (numParts > 1 || seekGEOffset)
  19225. {
  19226. tlk.setown(createKeyMerger(keyIndexSet, rawSize, seekGEOffset, this));
  19227. // note that we don't set up translator because we don't support it. If that ever changes...
  19228. }
  19229. else
  19230. {
  19231. tlk.setown(createKeyManager(keyIndexSet->queryPart(0), 0, this));
  19232. tlk->setLayoutTranslator(translators->item(0));
  19233. }
  19234. indexHelper.createSegmentMonitors(tlk);
  19235. tlk->finishSegmentMonitors();
  19236. if (queryTraceLevel() > 3 || ctx->queryProbeManager())
  19237. {
  19238. StringBuffer out;
  19239. printKeyedValues(out, tlk, indexHelper.queryDiskRecordSize());
  19240. CTXLOG("Using filter %s", out.str());
  19241. if (ctx->queryProbeManager())
  19242. ctx->queryProbeManager()->setNodeProperty(this, "filter", out.str());
  19243. }
  19244. tlk->reset();
  19245. callback.setManager(tlk);
  19246. keyedLimit = readHelper.getKeyedLimit();
  19247. if (keyedLimit != (unsigned __int64) -1)
  19248. {
  19249. if ((indexHelper.getFlags() & TIRcountkeyedlimit) != 0)
  19250. {
  19251. unsigned __int64 count = tlk->checkCount(keyedLimit);
  19252. if (count > keyedLimit)
  19253. {
  19254. if ((indexHelper.getFlags() & (TIRkeyedlimitskips|TIRkeyedlimitcreates)) == 0)
  19255. readHelper.onKeyedLimitExceeded();
  19256. const void * ret = NULL;
  19257. if (indexHelper.getFlags() & TIRkeyedlimitcreates)
  19258. ret = createKeyedLimitOnFailRow();
  19259. onEOF();
  19260. return ret;
  19261. }
  19262. tlk->reset();
  19263. keyedLimit = (unsigned __int64) -1;
  19264. }
  19265. }
  19266. firstRead = false;
  19267. }
  19268. if (accepted == chooseNLimit)
  19269. {
  19270. onEOF();
  19271. return NULL;
  19272. }
  19273. const byte * rawSeek = NULL;
  19274. unsigned seekSize = 0;
  19275. if (seek)
  19276. {
  19277. seekSize = seekSizes[numFields-1];
  19278. rawSeek = (const byte *)seek + seekGEOffset;
  19279. if (projectedMeta)
  19280. {
  19281. byte *temp = (byte *) alloca(seekSize);
  19282. RtlStaticRowBuilder rawBuilder(temp-seekGEOffset, seekGEOffset+seekSize);
  19283. readHelper.mapOutputToInput(rawBuilder, seek, numFields);// NOTE - weird interface to mapOutputToInput means that it STARTS writing at seekGEOffset...
  19284. rawSeek = (byte *)temp;
  19285. }
  19286. #ifdef _DEBUG
  19287. // StringBuffer seekStr;
  19288. // for (unsigned i = 0; i < seekSize; i++)
  19289. // {
  19290. // seekStr.appendf("%02x ", ((unsigned char *) rawSeek)[i]);
  19291. // }
  19292. // DBGLOG("nextSteppedGE can skip offset %d size %d value %s", seekGEOffset, seekSize, seekStr.str());
  19293. #endif
  19294. }
  19295. const byte * originalRawSeek = rawSeek;
  19296. RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
  19297. while (rawSeek ? tlk->lookupSkip(rawSeek, seekGEOffset, seekSize) : tlk->lookup(true))
  19298. {
  19299. checkAbort();
  19300. keyedCount++;
  19301. if (keyedCount > keyedLimit)
  19302. {
  19303. readHelper.onKeyedLimitExceeded();
  19304. break;
  19305. }
  19306. byte const * keyRow = tlk->queryKeyBuffer(callback.getFPosRef());
  19307. #ifdef _DEBUG
  19308. // StringBuffer recstr;
  19309. // unsigned size = (tlk->queryRecordSize()<80) ? tlk->queryRecordSize() : 80;
  19310. // for (unsigned i = 0; i < size; i++)
  19311. // {
  19312. // recstr.appendf("%02x ", ((unsigned char *) keyRow)[i]);
  19313. // }
  19314. // DBGLOG("nextSteppedGE Got %s", recstr.str());
  19315. if (originalRawSeek && memcmp(keyRow + seekGEOffset, originalRawSeek, seekSize) < 0)
  19316. assertex(!"smart seek failure");
  19317. #endif
  19318. size32_t transformedSize;
  19319. rowBuilder.ensureRow();
  19320. try
  19321. {
  19322. transformedSize = readHelper.transform(rowBuilder, keyRow);
  19323. //if the post filter causes a mismatch, and the stepping condition no longer matches
  19324. //then return a mismatch record - so the join code can start seeking on the other input.
  19325. if (transformedSize == 0 && optimizeSteppedPostFilter && stepExtra.returnMismatches())
  19326. {
  19327. if (memcmp(keyRow + seekGEOffset, originalRawSeek, seekSize) != 0)
  19328. {
  19329. transformedSize = readHelper.unfilteredTransform(rowBuilder, keyRow);
  19330. if (transformedSize != 0)
  19331. wasCompleteMatch = false;
  19332. }
  19333. }
  19334. callback.finishedRow();
  19335. }
  19336. catch (IException *E)
  19337. {
  19338. throw makeWrappedException(E);
  19339. }
  19340. if (transformedSize)
  19341. {
  19342. accepted++;
  19343. if (accepted > rowLimit)
  19344. {
  19345. if ((indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates)) != 0)
  19346. {
  19347. throwUnexpected(); // should not have used simple variant if maySkip set...
  19348. }
  19349. if (traceLevel > 4)
  19350. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  19351. readHelper.onLimitExceeded();
  19352. break;
  19353. }
  19354. processed++;
  19355. #ifdef _DEBUG
  19356. // const byte *ret = (const byte *) out.get();
  19357. // CommonXmlWriter xmlwrite(XWFnoindent|XWFtrim|XWFopt);
  19358. // queryOutputMeta()->toXML(ret, xmlwrite);
  19359. // DBGLOG("ROW: {%p} %s", ret, xmlwrite.str());
  19360. #endif
  19361. return rowBuilder.finalizeRowClear(transformedSize);
  19362. }
  19363. else
  19364. rejected++;
  19365. rawSeek = NULL;
  19366. }
  19367. onEOF();
  19368. return NULL;
  19369. }
  19370. virtual void reset()
  19371. {
  19372. onEOF();
  19373. if (accepted)
  19374. noteStatistic(STATS_ACCEPTED, accepted, 1);
  19375. if (rejected)
  19376. noteStatistic(STATS_REJECTED, rejected, 1);
  19377. if (variableFileName)
  19378. {
  19379. varFileInfo.clear();
  19380. translators.clear();
  19381. }
  19382. variableInfoPending = false;
  19383. CRoxieServerActivity::reset();
  19384. }
  19385. virtual void setInput(unsigned idx, IRoxieInput *_in)
  19386. {
  19387. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  19388. }
  19389. virtual IInputSteppingMeta * querySteppingMeta()
  19390. {
  19391. if (rawMeta && steppingEnabled && ((indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates|TIRkeyedlimitskips|TIRkeyedlimitcreates)) == 0))
  19392. return &steppingMeta;
  19393. return NULL;
  19394. }
  19395. protected:
  19396. const void * createKeyedLimitOnFailRow()
  19397. {
  19398. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  19399. size32_t outSize = limitTransformExtra->transformOnKeyedLimitExceeded(rowBuilder);
  19400. if (outSize)
  19401. return rowBuilder.finalizeRowClear(outSize);
  19402. return NULL;
  19403. }
  19404. };
  19405. class CRoxieServerBaseIndexActivityFactory : public CRoxieServerActivityFactory
  19406. {
  19407. public:
  19408. Owned<IKeyArray> keySet;
  19409. Owned<TranslatorArray> translatorArray;
  19410. Owned<IDefRecordMeta> activityMeta;
  19411. unsigned maxRecordSize;
  19412. RemoteActivityId remoteId;
  19413. bool isSimple;
  19414. bool isLocal;
  19415. bool maySkip;
  19416. bool sorted;
  19417. bool variableFileName;
  19418. bool enableFieldTranslation;
  19419. unsigned rawSize;
  19420. unsigned maxSeekLookahead;
  19421. Owned<const IResolvedFile> indexfile;
  19422. CRoxieServerSideCache *cache;
  19423. CRoxieServerBaseIndexActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  19424. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), remoteId(_remoteId)
  19425. {
  19426. Owned<IHThorIndexReadBaseArg> indexHelper = (IHThorIndexReadBaseArg *) helperFactory();
  19427. unsigned flags = indexHelper->getFlags();
  19428. sorted = (flags & TIRsorted) != 0;
  19429. isLocal = _graphNode.getPropBool("att[@name='local']/@value");
  19430. rtlDataAttr indexLayoutMeta;
  19431. size32_t indexLayoutSize;
  19432. if(!indexHelper->getIndexLayout(indexLayoutSize, indexLayoutMeta.refdata()))
  19433. assertex(indexLayoutSize==0);
  19434. MemoryBuffer m;
  19435. m.setBuffer(indexLayoutSize, indexLayoutMeta.getdata());
  19436. activityMeta.setown(deserializeRecordMeta(m, true));
  19437. enableFieldTranslation = queryFactory.getEnableFieldTranslation();
  19438. translatorArray.setown(new TranslatorArray);
  19439. variableFileName = (flags & (TIRvarfilename|TIRdynamicfilename)) != 0;
  19440. if (!variableFileName)
  19441. {
  19442. bool isOpt = (flags & TIRoptional) != 0;
  19443. indexfile.setown(queryFactory.queryPackage().lookupFileName(indexHelper->getFileName(), isOpt, true));
  19444. if (indexfile)
  19445. keySet.setown(indexfile->getKeyArray(activityMeta, translatorArray, isOpt, isLocal ? queryFactory.queryChannel() : 0, enableFieldTranslation));
  19446. }
  19447. maxRecordSize = meta.getRecordSize(NULL);
  19448. rawSize = indexHelper->queryDiskRecordSize()->getRecordSize(NULL);
  19449. isSimple = isLocal;
  19450. maySkip = (flags & (TIRkeyedlimitskips|TIRlimitskips|TIRlimitcreates|TIRkeyedlimitcreates)) != 0;
  19451. if (keySet && keySet->length()==1 && !isLocal && (flags & (TIRlimitskips|TIRlimitcreates|TIRkeyedlimitskips|TIRkeyedlimitcreates))==0)
  19452. {
  19453. IKeyIndexBase *thisBase = keySet->queryKeyPart(0);
  19454. if (thisBase->numParts()==1 && !thisBase->queryPart(0)->isTopLevelKey())
  19455. isSimple = true;
  19456. }
  19457. int cacheSize = _graphNode.getPropInt("hint[@name='cachehits']/@value", serverSideCacheSize);
  19458. cache = cacheSize ? new CRoxieServerSideCache(cacheSize) : NULL;
  19459. maxSeekLookahead = _graphNode.getPropInt("hint[@name='maxseeklookahead']/@value", 0);
  19460. }
  19461. ~CRoxieServerBaseIndexActivityFactory()
  19462. {
  19463. delete cache;
  19464. }
  19465. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  19466. {
  19467. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for indexread activity");
  19468. }
  19469. virtual IRoxieServerSideCache *queryServerSideCache() const
  19470. {
  19471. return cache;
  19472. }
  19473. virtual bool getEnableFieldTranslation() const
  19474. {
  19475. return enableFieldTranslation;
  19476. }
  19477. virtual IDefRecordMeta *queryActivityMeta() const
  19478. {
  19479. return activityMeta;
  19480. }
  19481. };
  19482. class CRoxieServerIndexReadActivityFactory : public CRoxieServerBaseIndexActivityFactory
  19483. {
  19484. public:
  19485. CRoxieServerIndexReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  19486. : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode)
  19487. {
  19488. }
  19489. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  19490. {
  19491. if (!variableFileName && (keySet==NULL || keySet->length()==0))
  19492. return new CRoxieServerNullActivity(this, _probeManager);
  19493. else if (isSimple && !maySkip)
  19494. return new CRoxieServerSimpleIndexReadActivity(this, _probeManager, remoteId, keySet, translatorArray, rawSize, maxRecordSize, isLocal);
  19495. else
  19496. return new CRoxieServerIndexReadActivity(this, _probeManager, remoteId, keySet, translatorArray, rawSize, maxRecordSize, sorted, isLocal, maySkip, maxSeekLookahead);
  19497. }
  19498. };
  19499. IRoxieServerActivityFactory *createRoxieServerIndexReadActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  19500. {
  19501. return new CRoxieServerIndexReadActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
  19502. }
  19503. //--------------------------------------------------------------------------------------------------------------------------
  19504. class CRoxieServerNullCountActivity : public CRoxieServerActivity
  19505. {
  19506. bool done;
  19507. public:
  19508. CRoxieServerNullCountActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  19509. : CRoxieServerActivity(_factory, _probeManager)
  19510. {
  19511. done = false;
  19512. }
  19513. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  19514. {
  19515. done = false;
  19516. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  19517. }
  19518. virtual bool needsAllocator() const { return true; }
  19519. virtual const void *nextInGroup()
  19520. {
  19521. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  19522. if (done) return NULL;
  19523. done = true;
  19524. size32_t rowSize = meta.getFixedSize();
  19525. void * nullRow = rowAllocator->createRow();
  19526. if (rowSize == 1)
  19527. *(byte *)nullRow = 0;
  19528. else
  19529. {
  19530. assertex(rowSize == sizeof(unsigned __int64));
  19531. *(unsigned __int64 *)nullRow = 0;
  19532. }
  19533. return rowAllocator->finalizeRow(rowSize, nullRow, rowSize);
  19534. }
  19535. };
  19536. class CRoxieServerIndexCountActivity : public CRoxieServerIndexActivity
  19537. {
  19538. IHThorCompoundCountExtra & countHelper;
  19539. IHThorSourceCountLimit * limitHelper;
  19540. bool done;
  19541. public:
  19542. CRoxieServerIndexCountActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, IKeyArray * _keySet, TranslatorArray *_translators, unsigned _rawSize, bool _isLocal)
  19543. : CRoxieServerIndexActivity(_factory, _probeManager, _remoteId, _keySet, _translators, _rawSize, false, _isLocal, false),
  19544. countHelper((IHThorIndexCountArg &)basehelper),
  19545. done(false)
  19546. {
  19547. limitHelper = static_cast<IHThorSourceCountLimit *>(basehelper.selectInterface(TAIsourcecountlimit_1));
  19548. }
  19549. virtual bool needsAllocator() const { return true; }
  19550. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  19551. {
  19552. done = false;
  19553. CRoxieServerIndexActivity::start(parentExtractSize, parentExtract, paused);
  19554. choosenLimit = countHelper.getChooseNLimit();
  19555. if (limitHelper)
  19556. {
  19557. rowLimit = limitHelper->getRowLimit();
  19558. keyedLimit = limitHelper->getKeyedLimit();
  19559. }
  19560. if (!paused)
  19561. processAllKeys();
  19562. }
  19563. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
  19564. {
  19565. unsigned __int64 count = 0;
  19566. if (countHelper.hasFilter())
  19567. {
  19568. while (tlk->lookup(true))
  19569. {
  19570. try
  19571. {
  19572. count += countHelper.numValid(tlk->queryKeyBuffer(callback.getFPosRef()));
  19573. callback.finishedRow();
  19574. }
  19575. catch (IException *E)
  19576. {
  19577. throw makeWrappedException(E);
  19578. }
  19579. accepted++;
  19580. if (count >= choosenLimit) // MORE - what about limit?
  19581. break;
  19582. }
  19583. }
  19584. else
  19585. count = tlk->getCount(); //MORE: GH->RKC There should be value in providing a max limit to getCount()
  19586. if (count)
  19587. {
  19588. Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), false);
  19589. if (count > choosenLimit)
  19590. count = choosenLimit;
  19591. void * recBuffer = rowAllocator->createRow();
  19592. if (meta.getFixedSize() == 1)
  19593. *(byte *)recBuffer = (byte)count;
  19594. else
  19595. {
  19596. assertex(meta.getFixedSize() == sizeof(unsigned __int64));
  19597. *(unsigned __int64 *)recBuffer = count;
  19598. }
  19599. recBuffer = rowAllocator->finalizeRow(meta.getFixedSize(), recBuffer, meta.getFixedSize());
  19600. result->append(recBuffer);
  19601. remote.injectResult(result.getClear());
  19602. //GH->RKC for count(,choosen)/exists passing in the previous count would short-circuit this much earlier
  19603. if (count >= choosenLimit)
  19604. return true;
  19605. }
  19606. return false;
  19607. }
  19608. virtual void onLimitExceeded(bool isKeyed)
  19609. {
  19610. if (traceLevel > 4)
  19611. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  19612. if (isKeyed)
  19613. {
  19614. if (indexHelper.getFlags() & (TIRkeyedlimitskips|TIRkeyedlimitcreates))
  19615. {
  19616. if (ctx->queryDebugContext())
  19617. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  19618. throw makeLimitSkipException(true);
  19619. }
  19620. else
  19621. {
  19622. assertex(limitHelper); // Should not be able to generate exception if there was not one...
  19623. limitHelper->onKeyedLimitExceeded();
  19624. }
  19625. }
  19626. else
  19627. {
  19628. if (indexHelper.getFlags() & (TIRlimitskips|TIRlimitcreates))
  19629. {
  19630. if (ctx->queryDebugContext())
  19631. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  19632. throw makeLimitSkipException(false);
  19633. }
  19634. else
  19635. {
  19636. assertex(limitHelper);
  19637. limitHelper->onLimitExceeded();
  19638. }
  19639. }
  19640. }
  19641. virtual const void *createLimitFailRow(bool isKeyed)
  19642. {
  19643. throwUnexpected();
  19644. }
  19645. virtual const void *nextInGroup()
  19646. {
  19647. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  19648. if (done) return NULL;
  19649. done = true;
  19650. unsigned __int64 totalCount = 0;
  19651. bool hasLimit = rowLimit != (unsigned __int64) -1;
  19652. try
  19653. {
  19654. loop
  19655. {
  19656. const void * next = remote.nextInGroup();
  19657. if (!next)
  19658. break;
  19659. if (meta.getFixedSize() == 1)
  19660. totalCount += *(byte *)next;
  19661. else
  19662. totalCount += *(unsigned __int64 *) next;
  19663. ReleaseRoxieRow(next);
  19664. if (totalCount > rowLimit || (totalCount > choosenLimit && !hasLimit)) // can't break out early if there is a possibility of later slave throwing limit exception
  19665. break;
  19666. }
  19667. if (totalCount > rowLimit)
  19668. {
  19669. unsigned flags = indexHelper.getFlags();
  19670. if (flags & TIRlimitskips)
  19671. totalCount = 0;
  19672. else if (flags & TIRlimitcreates)
  19673. totalCount = 1;
  19674. else
  19675. {
  19676. assertex(limitHelper);
  19677. limitHelper->onLimitExceeded();
  19678. }
  19679. }
  19680. else if (totalCount > choosenLimit)
  19681. totalCount = choosenLimit;
  19682. }
  19683. catch (IException *E)
  19684. {
  19685. if (QUERYINTERFACE(E, LimitSkipException))
  19686. {
  19687. totalCount = 0;
  19688. unsigned flags = indexHelper.getFlags();
  19689. if (E->errorCode() == KeyedLimitSkipErrorCode)
  19690. {
  19691. if (flags & TIRkeyedlimitcreates)
  19692. totalCount++;
  19693. }
  19694. else
  19695. {
  19696. if (flags & TIRlimitcreates)
  19697. totalCount++;
  19698. }
  19699. if (totalCount > choosenLimit)
  19700. totalCount = choosenLimit; // would have to be weird code (and escape the optimizer...)
  19701. E->Release();
  19702. }
  19703. else
  19704. throw ;
  19705. }
  19706. void * result = rowAllocator->createRow();
  19707. if (meta.getFixedSize() == 1)
  19708. *(byte *)result = (byte)totalCount;
  19709. else
  19710. {
  19711. assertex(meta.getFixedSize() == sizeof(unsigned __int64));
  19712. *(unsigned __int64 *)result = totalCount;
  19713. }
  19714. return rowAllocator->finalizeRow(meta.getFixedSize(), result, meta.getFixedSize());
  19715. }
  19716. };
  19717. class CRoxieServerIndexCountActivityFactory : public CRoxieServerBaseIndexActivityFactory
  19718. {
  19719. public:
  19720. CRoxieServerIndexCountActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  19721. : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode)
  19722. {
  19723. }
  19724. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  19725. {
  19726. if (!variableFileName && (keySet==NULL || keySet->length()==0))
  19727. return new CRoxieServerNullCountActivity(this, _probeManager);
  19728. // else if (isSimple)
  19729. // return new CRoxieServerSimpleIndexCountActivity(this, keySet->queryKeyPart(0)->queryPart(0), rawSize, maxRecordSize);
  19730. else
  19731. return new CRoxieServerIndexCountActivity(this, _probeManager, remoteId, keySet, translatorArray, rawSize, isLocal);
  19732. }
  19733. };
  19734. IRoxieServerActivityFactory *createRoxieServerIndexCountActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  19735. {
  19736. return new CRoxieServerIndexCountActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
  19737. }
  19738. //--------------------------------------------------------------------------------------------------------------------------
  19739. class CRoxieServerNullIndexAggregateActivity : public CRoxieServerActivity
  19740. {
  19741. IHThorIndexAggregateArg &aggregateHelper;
  19742. unsigned maxRecordSize;
  19743. bool done;
  19744. public:
  19745. CRoxieServerNullIndexAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned _maxRecordSize)
  19746. : CRoxieServerActivity(_factory, _probeManager),
  19747. aggregateHelper((IHThorIndexAggregateArg &)basehelper)
  19748. {
  19749. maxRecordSize = _maxRecordSize;
  19750. done = false;
  19751. }
  19752. virtual bool needsAllocator() const { return true; }
  19753. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  19754. {
  19755. done = false;
  19756. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  19757. }
  19758. virtual const void *nextInGroup()
  19759. {
  19760. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  19761. if (done) return NULL;
  19762. done = true;
  19763. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  19764. size32_t thisSize = aggregateHelper.clearAggregate(rowBuilder);
  19765. return rowBuilder.finalizeRowClear(thisSize);
  19766. }
  19767. };
  19768. class CRoxieServerIndexAggregateActivity : public CRoxieServerIndexActivity
  19769. {
  19770. IHThorCompoundAggregateExtra & aggregateHelper;
  19771. bool done;
  19772. public:
  19773. CRoxieServerIndexAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  19774. IKeyArray * _keySet, TranslatorArray *_translators, unsigned _rawSize, bool _isLocal)
  19775. : CRoxieServerIndexActivity(_factory, _probeManager, _remoteId, _keySet, _translators, _rawSize, false, _isLocal, false),
  19776. aggregateHelper((IHThorIndexAggregateArg &)basehelper),
  19777. done(false)
  19778. {
  19779. }
  19780. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  19781. {
  19782. done = false;
  19783. CRoxieServerIndexActivity::start(parentExtractSize, parentExtract, paused);
  19784. if (!paused)
  19785. processAllKeys();
  19786. }
  19787. virtual bool needsAllocator() const { return true; }
  19788. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
  19789. {
  19790. RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
  19791. while (tlk->lookup(true))
  19792. {
  19793. if (!rowBuilder.exists())
  19794. {
  19795. rowBuilder.ensureRow();
  19796. aggregateHelper.clearAggregate(rowBuilder);
  19797. }
  19798. try
  19799. {
  19800. aggregateHelper.processRow(rowBuilder, tlk->queryKeyBuffer(callback.getFPosRef()));
  19801. callback.finishedRow();
  19802. }
  19803. catch (IException *E)
  19804. {
  19805. throw makeWrappedException(E);
  19806. }
  19807. accepted++;
  19808. }
  19809. if (aggregateHelper.processedAnyRows())
  19810. {
  19811. size32_t size = meta.getRecordSize(rowBuilder.getSelf());
  19812. const void * recBuffer = rowBuilder.finalizeRowClear(size);
  19813. Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), meta.isVariableSize());
  19814. result->append(recBuffer);
  19815. remote.injectResult(result.getClear());
  19816. }
  19817. return false;
  19818. }
  19819. virtual void onLimitExceeded(bool isKeyed)
  19820. {
  19821. if (traceLevel > 4)
  19822. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  19823. throwUnexpected();
  19824. }
  19825. virtual const void *createLimitFailRow(bool isKeyed)
  19826. {
  19827. throwUnexpected();
  19828. }
  19829. const void * gatherMerged()
  19830. {
  19831. RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
  19832. const void * firstRow = remote.nextInGroup();
  19833. size32_t finalSize = 0;
  19834. if (!firstRow)
  19835. {
  19836. rowBuilder.ensureRow();
  19837. finalSize = aggregateHelper.clearAggregate(rowBuilder);
  19838. }
  19839. else
  19840. {
  19841. // NOTE need to clone this because going to modify below, could special case 1 row only
  19842. finalSize = cloneRow(rowBuilder, firstRow, meta);
  19843. ReleaseRoxieRow(firstRow);
  19844. }
  19845. loop
  19846. {
  19847. const void * next = remote.nextInGroup();
  19848. if (!next)
  19849. break;
  19850. finalSize = aggregateHelper.mergeAggregate(rowBuilder, next);
  19851. ReleaseRoxieRow(next);
  19852. }
  19853. return rowBuilder.finalizeRowClear(finalSize);
  19854. }
  19855. virtual const void *nextInGroup()
  19856. {
  19857. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  19858. if (done) return NULL;
  19859. const void * ret = gatherMerged();
  19860. done = true;
  19861. return ret;
  19862. }
  19863. };
  19864. class CRoxieServerIndexAggregateActivityFactory : public CRoxieServerBaseIndexActivityFactory
  19865. {
  19866. public:
  19867. CRoxieServerIndexAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  19868. : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode)
  19869. {
  19870. }
  19871. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  19872. {
  19873. if (!variableFileName && (keySet==NULL || keySet->length()==0))
  19874. return new CRoxieServerNullIndexAggregateActivity(this, _probeManager, maxRecordSize);
  19875. // else if (isSimple)
  19876. // return new CRoxieServerSimpleIndexAggregateActivity(this, keySet->queryKeyPart(0)->queryPart(0), rawSize, maxRecordSize);
  19877. else
  19878. return new CRoxieServerIndexAggregateActivity(this, _probeManager, remoteId, keySet, translatorArray, rawSize, isLocal);
  19879. }
  19880. };
  19881. IRoxieServerActivityFactory *createRoxieServerIndexAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  19882. {
  19883. return new CRoxieServerIndexAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
  19884. }
  19885. //--------------------------------------------------------------------------------------------------------------------------
  19886. class CRoxieServerIndexGroupAggregateActivity : public CRoxieServerIndexActivity, implements IHThorGroupAggregateCallback
  19887. {
  19888. IHThorCompoundGroupAggregateExtra & aggregateHelper;
  19889. RowAggregator singleAggregator;
  19890. RowAggregator resultAggregator;
  19891. unsigned groupSegCount;
  19892. bool gathered;
  19893. bool eof;
  19894. public:
  19895. CRoxieServerIndexGroupAggregateActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  19896. IKeyArray * _keySet, TranslatorArray *_translators, unsigned _rawSize, bool _isLocal)
  19897. : CRoxieServerIndexActivity(_factory, _probeManager, _remoteId, _keySet, _translators, _rawSize, false, _isLocal, false),
  19898. aggregateHelper((IHThorIndexGroupAggregateArg &)basehelper),
  19899. singleAggregator(aggregateHelper, aggregateHelper),
  19900. resultAggregator(aggregateHelper, aggregateHelper),
  19901. gathered(false), eof(true)
  19902. {
  19903. groupSegCount = 0;
  19904. }
  19905. IMPLEMENT_IINTERFACE
  19906. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  19907. {
  19908. eof = false;
  19909. gathered= false;
  19910. CRoxieServerIndexActivity::start(parentExtractSize, parentExtract, paused);
  19911. groupSegCount = 0;
  19912. if (!paused)
  19913. processAllKeys();
  19914. resultAggregator.start(rowAllocator);
  19915. }
  19916. virtual bool needsAllocator() const { return true; }
  19917. virtual void reset()
  19918. {
  19919. resultAggregator.reset();
  19920. CRoxieServerIndexActivity::reset();
  19921. }
  19922. virtual void processRow(const void * next)
  19923. {
  19924. singleAggregator.addRow(next);
  19925. }
  19926. virtual void createSegmentMonitors(IKeyManager *key)
  19927. {
  19928. unsigned groupSegSize;
  19929. ThorActivityKind kind = factory->getKind();
  19930. if ((kind==TAKindexgroupcount || kind==TAKindexgroupexists))
  19931. groupSegSize = aggregateHelper.getGroupSegmentMonitorsSize();
  19932. else
  19933. groupSegSize = 0;
  19934. if (groupSegSize)
  19935. {
  19936. key->setMergeBarrier(groupSegSize);
  19937. CRoxieServerIndexActivity::createSegmentMonitors(key);
  19938. unsigned numSegs = tlk->ordinality();
  19939. for (unsigned segNo = 0; segNo < numSegs; segNo++)
  19940. {
  19941. IKeySegmentMonitor *seg = tlk->item(segNo);
  19942. if (seg->getOffset()+seg->getSize()==groupSegSize)
  19943. {
  19944. groupSegCount = segNo+1;
  19945. break;
  19946. }
  19947. }
  19948. assertex(groupSegCount);
  19949. }
  19950. else
  19951. CRoxieServerIndexActivity::createSegmentMonitors(key);
  19952. }
  19953. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
  19954. {
  19955. Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), meta.isVariableSize());
  19956. singleAggregator.start(rowAllocator);
  19957. ThorActivityKind kind = factory->getKind();
  19958. while (tlk->lookup(true))
  19959. {
  19960. try
  19961. {
  19962. if (groupSegCount && !trans)
  19963. {
  19964. AggregateRowBuilder &rowBuilder = singleAggregator.addRow(tlk->queryKeyBuffer(callback.getFPosRef()));
  19965. callback.finishedRow();
  19966. if (kind==TAKindexgroupcount)
  19967. {
  19968. unsigned __int64 count = tlk->getCurrentRangeCount(groupSegCount);
  19969. aggregateHelper.processCountGrouping(rowBuilder, count-1);
  19970. }
  19971. if (!tlk->nextRange(groupSegCount))
  19972. break;
  19973. }
  19974. else
  19975. {
  19976. aggregateHelper.processRow(tlk->queryKeyBuffer(callback.getFPosRef()), this);
  19977. callback.finishedRow();
  19978. }
  19979. }
  19980. catch (IException *E)
  19981. {
  19982. throw makeWrappedException(E);
  19983. }
  19984. accepted++;
  19985. }
  19986. loop
  19987. {
  19988. Owned<AggregateRowBuilder> next = singleAggregator.nextResult();
  19989. if (!next)
  19990. break;
  19991. size32_t size = next->querySize();
  19992. result->append(next->finalizeRowClear());
  19993. }
  19994. remote.injectResult(result.getClear());
  19995. singleAggregator.reset();
  19996. return false;
  19997. }
  19998. virtual void onLimitExceeded(bool isKeyed)
  19999. {
  20000. if (traceLevel > 4)
  20001. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);DBGLOG("%d activityid = %d", __LINE__, activityId);
  20002. throwUnexpected();
  20003. }
  20004. virtual const void *createLimitFailRow(bool isKeyed)
  20005. {
  20006. throwUnexpected();
  20007. }
  20008. void gatherMerged()
  20009. {
  20010. gathered = true;
  20011. loop
  20012. {
  20013. const void * next = remote.nextInGroup();
  20014. if (!next)
  20015. break;
  20016. resultAggregator.mergeElement(next);
  20017. ReleaseRoxieRow(next);
  20018. }
  20019. }
  20020. virtual const void *nextInGroup()
  20021. {
  20022. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  20023. if (eof)
  20024. return NULL;
  20025. if (!gathered)
  20026. gatherMerged();
  20027. Owned<AggregateRowBuilder> next = resultAggregator.nextResult();
  20028. if (next)
  20029. {
  20030. processed++;
  20031. return next->finalizeRowClear();
  20032. }
  20033. eof = true;
  20034. return NULL;
  20035. }
  20036. };
  20037. class CRoxieServerIndexGroupAggregateActivityFactory : public CRoxieServerBaseIndexActivityFactory
  20038. {
  20039. public:
  20040. CRoxieServerIndexGroupAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  20041. : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode)
  20042. {
  20043. }
  20044. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  20045. {
  20046. if (!variableFileName && (keySet==NULL || keySet->length()==0))
  20047. return new CRoxieServerNullActivity(this, _probeManager);
  20048. // else if (isSimple)
  20049. // return new CRoxieServerSimpleIndexGroupAggregateActivity(this, keySet->queryKeyPart(0)->queryPart(0), rawSize, maxRecordSize);
  20050. else
  20051. return new CRoxieServerIndexGroupAggregateActivity(this, _probeManager, remoteId, keySet, translatorArray, rawSize, isLocal);
  20052. }
  20053. };
  20054. IRoxieServerActivityFactory *createRoxieServerIndexGroupAggregateActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  20055. {
  20056. return new CRoxieServerIndexGroupAggregateActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
  20057. }
  20058. //--------------------------------------------------------------------------------------------------------------------------
  20059. class CRoxieServerIndexNormalizeActivity : public CRoxieServerIndexReadBaseActivity
  20060. {
  20061. IHThorCompoundNormalizeExtra & readHelper;
  20062. public:
  20063. CRoxieServerIndexNormalizeActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId,
  20064. IKeyArray * _keySet, TranslatorArray *_translators, unsigned _rawSize, unsigned _maxRecordSize, bool _sorted, bool _isLocal)
  20065. : CRoxieServerIndexReadBaseActivity(_factory, _probeManager, _remoteId, _keySet, _translators, _rawSize, _maxRecordSize, _sorted, _isLocal, false),
  20066. readHelper((IHThorIndexNormalizeArg &)basehelper)
  20067. {
  20068. }
  20069. virtual bool needsAllocator() const { return true; }
  20070. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  20071. {
  20072. CRoxieServerIndexReadBaseActivity::start(parentExtractSize, parentExtract, paused);
  20073. rowLimit = readHelper.getRowLimit();
  20074. keyedLimit = readHelper.getKeyedLimit();
  20075. if (!paused)
  20076. processAllKeys();
  20077. }
  20078. virtual bool processSingleKey(IKeyIndex *key, IRecordLayoutTranslator * trans)
  20079. {
  20080. unsigned keyedCount = 0;
  20081. RtlDynamicRowBuilder rowBuilder(rowAllocator, false);
  20082. while (tlk->lookup(true))
  20083. {
  20084. keyedCount++;
  20085. if (keyedCount > keyedLimit)
  20086. {
  20087. if (traceLevel > 4)
  20088. DBGLOG("activityid = %d line = %d", activityId, __LINE__);
  20089. onLimitExceeded(true);
  20090. break;
  20091. }
  20092. size32_t transformedSize;
  20093. if (readHelper.first(tlk->queryKeyBuffer(callback.getFPosRef())))
  20094. {
  20095. Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), meta.isVariableSize());
  20096. do
  20097. {
  20098. rowBuilder.ensureRow();
  20099. try
  20100. {
  20101. transformedSize = readHelper.transform(rowBuilder);
  20102. }
  20103. catch (IException *E)
  20104. {
  20105. throw makeWrappedException(E);
  20106. }
  20107. if (transformedSize)
  20108. {
  20109. // MORE - would be a good idea to stop these asap if rowlimit exceeded
  20110. result->append(rowBuilder.finalizeRowClear(transformedSize));
  20111. accepted++;
  20112. }
  20113. else
  20114. rejected++;
  20115. } while (readHelper.next());
  20116. remote.injectResult(result.getClear());
  20117. callback.finishedRow();
  20118. }
  20119. }
  20120. return false;
  20121. }
  20122. virtual void onLimitExceeded(bool isKeyed)
  20123. {
  20124. if (traceLevel > 4)
  20125. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  20126. if (isKeyed)
  20127. {
  20128. if (indexHelper.getFlags() & (TIRkeyedlimitskips|TIRkeyedlimitcreates))
  20129. {
  20130. if (ctx->queryDebugContext())
  20131. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  20132. throw makeLimitSkipException(true);
  20133. }
  20134. else
  20135. readHelper.onKeyedLimitExceeded();
  20136. }
  20137. else
  20138. {
  20139. if (indexHelper.getFlags() & (TIRlimitskips||TIRlimitcreates))
  20140. {
  20141. if (ctx->queryDebugContext())
  20142. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  20143. throw makeLimitSkipException(false);
  20144. }
  20145. else
  20146. readHelper.onLimitExceeded();
  20147. }
  20148. }
  20149. virtual const void *createLimitFailRow(bool isKeyed)
  20150. {
  20151. UNIMPLEMENTED;
  20152. }
  20153. };
  20154. class CRoxieServerIndexNormalizeActivityFactory : public CRoxieServerBaseIndexActivityFactory
  20155. {
  20156. public:
  20157. CRoxieServerIndexNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  20158. : CRoxieServerBaseIndexActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode)
  20159. {
  20160. }
  20161. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  20162. {
  20163. if (!variableFileName && (keySet==NULL || keySet->length()==0))
  20164. return new CRoxieServerNullActivity(this, _probeManager);
  20165. else
  20166. return new CRoxieServerIndexNormalizeActivity(this, _probeManager, remoteId, keySet, translatorArray, rawSize, maxRecordSize, sorted, isLocal);
  20167. }
  20168. };
  20169. IRoxieServerActivityFactory *createRoxieServerIndexNormalizeActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  20170. {
  20171. return new CRoxieServerIndexNormalizeActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
  20172. }
  20173. //=================================================================================
  20174. class CRoxieServerCountDiskActivity : public CRoxieServerActivity, implements IRoxieServerErrorHandler
  20175. {
  20176. unsigned __int64 answer;
  20177. public:
  20178. CRoxieServerCountDiskActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, unsigned __int64 _answer)
  20179. : CRoxieServerActivity(_factory, _probeManager),
  20180. answer(_answer)
  20181. {
  20182. }
  20183. virtual const void *nextInGroup()
  20184. {
  20185. throwUnexpected();
  20186. }
  20187. virtual void setInput(unsigned idx, IRoxieInput *_in)
  20188. {
  20189. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  20190. }
  20191. virtual __int64 evaluate()
  20192. {
  20193. return answer;
  20194. }
  20195. virtual void onLimitExceeded(bool isKeyed)
  20196. {
  20197. if (traceLevel > 4)
  20198. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  20199. throwUnexpected();
  20200. }
  20201. virtual const void *createLimitFailRow(bool isKeyed)
  20202. {
  20203. throwUnexpected();
  20204. }
  20205. };
  20206. class CRoxieServerVariableCountDiskActivity : public CRoxieServerActivity, implements IRoxieServerErrorHandler
  20207. {
  20208. public:
  20209. CRoxieServerVariableCountDiskActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  20210. : CRoxieServerActivity(_factory, _probeManager)
  20211. {
  20212. }
  20213. virtual const void *nextInGroup()
  20214. {
  20215. throwUnexpected();
  20216. }
  20217. virtual void setInput(unsigned idx, IRoxieInput *_in)
  20218. {
  20219. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() called for source activity");
  20220. }
  20221. virtual __int64 evaluate()
  20222. {
  20223. IHThorCountFileArg &helper = (IHThorCountFileArg &) basehelper;
  20224. bool isOpt = (helper.getFlags() & TDRoptional) != 0;
  20225. unsigned recsize = helper.queryRecordSize()->getFixedSize();
  20226. assertex(recsize);
  20227. Owned<const IResolvedFile> varFileInfo = resolveLFN(helper.getFileName(), isOpt);
  20228. return varFileInfo->getFileSize() / recsize;
  20229. }
  20230. virtual void onLimitExceeded(bool isKeyed)
  20231. {
  20232. if (traceLevel > 4)
  20233. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  20234. throwUnexpected();
  20235. }
  20236. virtual const void *createLimitFailRow(bool isKeyed)
  20237. {
  20238. throwUnexpected();
  20239. }
  20240. };
  20241. class CRoxieServerCountDiskActivityFactory : public CRoxieServerActivityFactory
  20242. {
  20243. public:
  20244. unsigned __int64 answer;
  20245. bool variableFileName;
  20246. Owned<const IResolvedFile> datafile;
  20247. CRoxieServerCountDiskActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  20248. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  20249. {
  20250. Owned<IHThorCountFileArg> helper = (IHThorCountFileArg *) helperFactory();
  20251. variableFileName = (helper->getFlags() & (TDXvarfilename|TDXdynamicfilename)) != 0;
  20252. assertex(helper->queryRecordSize()->isFixedSize());
  20253. if (!variableFileName)
  20254. {
  20255. unsigned recsize = helper->queryRecordSize()->getFixedSize();
  20256. assertex(recsize);
  20257. const char *fileName = helper->getFileName();
  20258. bool isOpt = (helper->getFlags() & TDRoptional) != 0;
  20259. datafile.setown(queryFactory.queryPackage().lookupFileName(fileName, isOpt, true));
  20260. offset_t filesize = datafile ? datafile->getFileSize() : 0;
  20261. if (filesize % recsize != 0)
  20262. throw MakeStringException(ROXIE_MISMATCH, "Record size mismatch for file %s - %"I64F"d is not a multiple of fixed record size %d", fileName, filesize, recsize);
  20263. answer = filesize / recsize;
  20264. }
  20265. else
  20266. answer = 0;
  20267. }
  20268. virtual IRoxieServerActivity *createFunction(IHThorArg &arg, IProbeManager *_probeManager) const
  20269. {
  20270. arg.Release();
  20271. if (variableFileName)
  20272. return new CRoxieServerVariableCountDiskActivity(this, _probeManager);
  20273. else
  20274. return new CRoxieServerCountDiskActivity(this, _probeManager, answer);
  20275. }
  20276. virtual void setInput(unsigned idx, unsigned source, unsigned sourceidx)
  20277. {
  20278. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() should not be called for CountDisk activity");
  20279. }
  20280. virtual bool isFunction() const
  20281. {
  20282. return true;
  20283. }
  20284. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  20285. {
  20286. return NULL;
  20287. }
  20288. };
  20289. IRoxieServerActivityFactory *createRoxieServerDiskCountActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode)
  20290. {
  20291. return new CRoxieServerCountDiskActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode);
  20292. }
  20293. //=================================================================================
  20294. class CRoxieServerFetchActivity : public CRoxieServerActivity, implements IRecordPullerCallback, implements IRoxieServerErrorHandler
  20295. {
  20296. IHThorFetchBaseArg &helper;
  20297. IHThorFetchContext * fetchContext;
  20298. Linked<IFilePartMap> map;
  20299. CRemoteResultAdaptor remote;
  20300. RecordPullerThread puller;
  20301. bool needsRHS;
  20302. bool variableFileName;
  20303. bool isOpt;
  20304. Owned<const IResolvedFile> varFileInfo;
  20305. public:
  20306. CRoxieServerFetchActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, IFilePartMap *_map)
  20307. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorFetchBaseArg &)basehelper), map(_map), remote(_remoteId, meta.queryOriginal(), helper, *this, true, true), puller(false)
  20308. {
  20309. fetchContext = static_cast<IHThorFetchContext *>(helper.selectInterface(TAIfetchcontext_1));
  20310. needsRHS = helper.transformNeedsRhs();
  20311. variableFileName = (fetchContext->getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0;
  20312. isOpt = (fetchContext->getFetchFlags() & FFdatafileoptional) != 0;
  20313. }
  20314. virtual const IResolvedFile *queryVarFileInfo() const
  20315. {
  20316. return varFileInfo;
  20317. }
  20318. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  20319. {
  20320. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  20321. remote.onCreate(this, this, _ctx, _colocalParent);
  20322. }
  20323. virtual void setInput(unsigned idx, IRoxieInput *_in)
  20324. {
  20325. if (idx)
  20326. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  20327. puller.setInput(this, _in);
  20328. }
  20329. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  20330. {
  20331. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  20332. remote.onStart(parentExtractSize, parentExtract);
  20333. remote.setLimits(helper.getRowLimit(), (unsigned __int64) -1, I64C(0x7FFFFFFFFFFFFFFF));
  20334. if (variableFileName)
  20335. {
  20336. varFileInfo.setown(resolveLFN(fetchContext->getFileName(), isOpt));
  20337. map.setown(varFileInfo->getFileMap());
  20338. }
  20339. puller.start(parentExtractSize, parentExtract, paused, ctx->fetchPreload(), false, ctx);
  20340. }
  20341. virtual void stop(bool aborting)
  20342. {
  20343. // Called from remote, so no need to call back to it....
  20344. puller.stop(aborting);
  20345. CRoxieServerActivity::stop(aborting);
  20346. }
  20347. virtual void reset()
  20348. {
  20349. processed = remote.processed;
  20350. remote.processed = 0;
  20351. puller.reset();
  20352. if (variableFileName)
  20353. {
  20354. varFileInfo.clear();
  20355. map.clear();
  20356. }
  20357. CRoxieServerActivity::reset();
  20358. }
  20359. virtual IRoxieInput *queryOutput(unsigned idx)
  20360. {
  20361. if (idx==(unsigned)-1)
  20362. idx = 0;
  20363. return idx ? NULL : &remote;
  20364. }
  20365. virtual void processRow(const void *row)
  20366. {
  20367. // called from puller thread
  20368. offset_t rp = fetchContext->extractPosition(row);
  20369. unsigned partNo;
  20370. if (isLocalFpos(rp))
  20371. partNo = getLocalFposPart(rp) + 1;
  20372. else
  20373. partNo = map->mapOffset(rp);
  20374. if (needsRHS)
  20375. {
  20376. Owned<IEngineRowAllocator> extractAllocator = ctx->queryCodeContext()->getRowAllocator(helper.queryExtractedSize(), activityId);
  20377. RtlDynamicRowBuilder rb(extractAllocator, true);
  20378. unsigned rhsSize = helper.extractJoinFields(rb, row);
  20379. char * block = (char *) remote.getMem(partNo, 0, sizeof(rp) + sizeof(rhsSize) + rhsSize); // MORE - superfiles
  20380. *(offset_t *) block = rp;
  20381. block += sizeof(rp);
  20382. *(unsigned *) block = rhsSize;
  20383. block += sizeof(rhsSize);
  20384. memcpy(block, rb.row(), rhsSize);
  20385. }
  20386. else
  20387. *(offset_t *) remote.getMem(partNo, 0, sizeof(rp)) = rp; // MORE - superfiles
  20388. ReleaseRoxieRow(row);
  20389. }
  20390. void processEOG()
  20391. {
  20392. #ifdef FETCH_PRESERVES_GROUPING
  20393. UNIMPLEMENTED;
  20394. #endif
  20395. // else discard is correct
  20396. }
  20397. void processGroup(const ConstPointerArray &)
  20398. {
  20399. throwUnexpected();
  20400. }
  20401. void processDone()
  20402. {
  20403. // called from puller thread
  20404. remote.flush();
  20405. remote.senddone();
  20406. }
  20407. virtual bool fireException(IException *e)
  20408. {
  20409. return remote.fireException(e);
  20410. }
  20411. virtual void onLimitExceeded(bool isKeyed)
  20412. {
  20413. if (traceLevel > 4)
  20414. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  20415. if (isKeyed)
  20416. throwUnexpected();
  20417. helper.onLimitExceeded();
  20418. }
  20419. virtual const void *createLimitFailRow(bool isKeyed)
  20420. {
  20421. UNIMPLEMENTED;
  20422. }
  20423. virtual const void *nextInGroup()
  20424. {
  20425. throwUnexpected(); // I am nobody's input
  20426. }
  20427. };
  20428. class CRoxieServerFetchActivityFactory : public CRoxieServerActivityFactory
  20429. {
  20430. RemoteActivityId remoteId;
  20431. Owned<IFilePartMap> map;
  20432. bool variableFileName;
  20433. Owned<const IResolvedFile> datafile;
  20434. public:
  20435. CRoxieServerFetchActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  20436. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), remoteId(_remoteId)
  20437. {
  20438. Owned<IHThorFetchBaseArg> helper = (IHThorFetchBaseArg *) helperFactory();
  20439. IHThorFetchContext *fetchContext = static_cast<IHThorFetchContext *>(helper->selectInterface(TAIfetchcontext_1));
  20440. variableFileName = (fetchContext->getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0;
  20441. if (!variableFileName)
  20442. {
  20443. datafile.setown(_queryFactory.queryPackage().lookupFileName(fetchContext->getFileName(), (fetchContext->getFetchFlags() & FFdatafileoptional) != 0, true));
  20444. if (datafile)
  20445. map.setown(datafile->getFileMap());
  20446. }
  20447. }
  20448. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  20449. {
  20450. return new CRoxieServerFetchActivity(this, _probeManager, remoteId, map);
  20451. }
  20452. };
  20453. IRoxieServerActivityFactory *createRoxieServerFetchActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, IPropertyTree &_graphNode)
  20454. {
  20455. return new CRoxieServerFetchActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _graphNode);
  20456. }
  20457. // MORE - is there any point keeping this now?
  20458. class CRoxieServerDummyActivityFactory : public CRoxieServerActivityFactory // not a real activity - just used to properly link files
  20459. {
  20460. public:
  20461. Owned<const IResolvedFile> indexfile;
  20462. Owned<const IResolvedFile> datafile;
  20463. Owned<IKeyArray> keySet;
  20464. Owned<IFileIOArray> files;
  20465. Owned<IFilePartMap> map;
  20466. TranslatorArray layoutTranslators;
  20467. CRoxieServerDummyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool isLoadDataOnly)
  20468. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  20469. {
  20470. try // does not want any missing file errors to be fatal, or throw traps - just log it
  20471. {
  20472. if (_graphNode.getPropBool("att[@name='_isSpill']/@value", false) || _graphNode.getPropBool("att[@name='_isSpillGlobal']/@value", false))
  20473. return; // ignore 'spills'
  20474. bool isLocal = _graphNode.getPropBool("att[@name='local']/@value");
  20475. bool isOpt = _graphNode.getPropBool("att[@name='_isOpt']/@value") || pretendAllOpt;
  20476. if (queryNodeIndexName(_graphNode))
  20477. {
  20478. indexfile.setown(queryFactory.queryPackage().lookupFileName(queryNodeIndexName(_graphNode), isOpt, true));
  20479. if (indexfile)
  20480. keySet.setown(indexfile->getKeyArray(NULL, &layoutTranslators, isOpt, isLocal ? queryFactory.queryChannel() : 0, false));
  20481. }
  20482. if (queryNodeFileName(_graphNode))
  20483. {
  20484. datafile.setown(_queryFactory.queryPackage().lookupFileName(queryNodeFileName(_graphNode), isOpt, true));
  20485. if (datafile)
  20486. {
  20487. if (isLocal)
  20488. files.setown(datafile->getIFileIOArray(isOpt, queryFactory.queryChannel()));
  20489. else
  20490. map.setown(datafile->getFileMap());
  20491. }
  20492. }
  20493. }
  20494. catch(IException *E)
  20495. {
  20496. StringBuffer errors;
  20497. E->errorMessage(errors);
  20498. DBGLOG("%s File error = %s", (isLoadDataOnly) ? "LOADDATAONLY" : "SUSPENDED QUERY", errors.str());
  20499. E->Release();
  20500. }
  20501. }
  20502. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const { throw MakeStringException(ROXIE_INTERNAL_ERROR, "%s query %s is suspended and cannot be executed - error occurred at %s(%d)", (queryFactory.isQueryLibrary()) ? "Library" : " ", queryFactory.queryQueryName(), __FILE__, __LINE__); }
  20503. };
  20504. IRoxieServerActivityFactory *createRoxieServerDummyActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, IPropertyTree &_graphNode, bool isLoadDataOnly)
  20505. {
  20506. return new CRoxieServerDummyActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _graphNode, isLoadDataOnly);
  20507. }
  20508. //=====================================================================================================
  20509. // Keyed joins...
  20510. //
  20511. // Input records are pulled by a puller thread, which checks each LHS record to determine which (if any) channels it
  20512. // may have RHS matches on, and sends the relevant fields to the relevant slaves.
  20513. // A separate thread (the caller's thread) is waiting on slave replies, and once it has all replies for a given LHS record or group of records, calls
  20514. // the transform and returns rows that are created.
  20515. // For a full-keyed join, there is a third thread that is pulling replies from index part and passing them to fetch part (check this is true)
  20516. //
  20517. //=====================================================================================================
  20518. class CJoinGroup;
  20519. interface IJoinProcessor
  20520. {
  20521. virtual void processEOG() = 0;
  20522. virtual CJoinGroup *createJoinGroup(const void *row) = 0;
  20523. virtual void noteEndReceived(CJoinGroup *jg, unsigned candidateCount) = 0;
  20524. virtual bool fireException(IException *E) = 0;
  20525. virtual void processCompletedGroups() = 0;
  20526. };
  20527. //------------------------------------------------------------------------------------------------------
  20528. // Class CJoinGroup has a record per LHS row, plus (if preserving grouping) a 'head of group' record
  20529. // It gathers all the corresponding RHS rows, keeping track of how may slave transactions are pending in endMarkersPending
  20530. // If preserving groups, the 'head of group' record keeps track of how many LHS records in the group are still incomplete.
  20531. // CJoinGroup records are allocated out of the Roxie row memory manager by overloading operator new, so that they are included in the
  20532. // per-query limits etc (Note that the pointer array block is not though).
  20533. // Because of that, the exact size is significant - especially whether fit just under or just over a chunking threshold...
  20534. //
  20535. // There are two phases to the life of a JoinGroup - it is created by the puller thread that is also firing off slave requests
  20536. // notePending will be called once for every slave request. Puller thread calls noteEndReceived(0) once when done - this corresponds to the
  20537. // initial count when created.
  20538. // Slave replies and are noted by the consumer thread calling addRightMatch() and noteEndReceived(n).
  20539. // Once endMarkersPending reaches 0, JoinGroup is complete. Last thread to call noteEndReceived will process the rows and destroy the group.
  20540. // There is no need for a critsec because although multiple threads will access at different times, only the consumer thread will
  20541. // access any modifiable member variables while endMarkersPending != 0 (i.e. complete() is false). Once complete returns true there is a single
  20542. // remaining reference and the JoinGroup will be processed and destroyed.
  20543. //
  20544. //------------------------------------------------------------------------------------------------------
  20545. class CJoinGroup : public CInterface, implements IInterface
  20546. {
  20547. protected:
  20548. const void *left; // LHS row
  20549. PointerArrayOf<KeyedJoinHeader> rows; // matching RHS rows
  20550. atomic_t endMarkersPending; // How many slave responses still waiting for
  20551. CJoinGroup *groupStart; // Head of group, or NULL if not grouping
  20552. unsigned lastPartNo;
  20553. unsigned pos;
  20554. unsigned candidates; // Number of RHS keyed candidates - note this may not be the same as rows.ordinality()
  20555. public:
  20556. #undef new
  20557. void *operator new(size_t size, IRowManager *a, unsigned activityId)
  20558. {
  20559. return a->allocate(size, activityId);
  20560. }
  20561. #if defined(_DEBUG) && defined(_WIN32) && !defined(USING_MPATROL)
  20562. #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
  20563. #endif
  20564. void operator delete(void *ptr, IRowManager *a, unsigned activityId)
  20565. {
  20566. ReleaseRoxieRow(ptr);
  20567. }
  20568. void operator delete(void *ptr)
  20569. {
  20570. ReleaseRoxieRow(ptr);
  20571. }
  20572. public:
  20573. IMPLEMENT_IINTERFACE;
  20574. CJoinGroup(const void *_left, CJoinGroup *_groupStart)
  20575. {
  20576. #ifdef TRACE_JOINGROUPS
  20577. DBGLOG("Creating joinGroup %p, groupstart %p", this, _groupStart);
  20578. #endif
  20579. candidates = 0;
  20580. lastPartNo = 0;
  20581. pos = 0;
  20582. left = _left;
  20583. groupStart = _groupStart;
  20584. if (_groupStart)
  20585. {
  20586. atomic_inc(&_groupStart->endMarkersPending);
  20587. }
  20588. atomic_set(&endMarkersPending, 1);
  20589. }
  20590. ~CJoinGroup()
  20591. {
  20592. #ifdef TRACE_JOINGROUPS
  20593. DBGLOG("Destroying joinGroup %p", this);
  20594. #endif
  20595. if (left)
  20596. {
  20597. ReleaseRoxieRow(left);
  20598. ForEachItemIn(idx, rows)
  20599. ReleaseRoxieRow(rows.item(idx));
  20600. rows.kill();
  20601. }
  20602. }
  20603. inline bool isHeadRecord() const
  20604. {
  20605. return left==NULL;
  20606. }
  20607. inline bool complete() const
  20608. {
  20609. return atomic_read(&endMarkersPending) == 0;
  20610. }
  20611. #ifdef TRACE_JOINGROUPS
  20612. inline void notePending(unsigned lineNo)
  20613. #else
  20614. inline void notePending()
  20615. #endif
  20616. {
  20617. assert(!complete());
  20618. atomic_inc(&endMarkersPending);
  20619. #ifdef TRACE_JOINGROUPS
  20620. DBGLOG("CJoinGroup::notePending %p from %d, count became %d group count %d", this, lineNo, atomic_read(&endMarkersPending), groupStart ? atomic_read(&groupStart->endMarkersPending) : 0);
  20621. #endif
  20622. }
  20623. inline bool inGroup(CJoinGroup *leader) const
  20624. {
  20625. return groupStart==leader;
  20626. }
  20627. inline const KeyedJoinHeader *queryRow(unsigned idx) const
  20628. {
  20629. // Single threaded by now
  20630. assert(complete());
  20631. return rows.item(idx);
  20632. }
  20633. #ifdef TRACE_JOINGROUPS
  20634. bool noteEndReceived(unsigned candidateCount, unsigned lineNo)
  20635. #else
  20636. bool noteEndReceived(unsigned candidateCount)
  20637. #endif
  20638. {
  20639. assert(!complete());
  20640. if (candidateCount)
  20641. {
  20642. candidates += candidateCount;
  20643. }
  20644. #ifdef TRACE_JOINGROUPS
  20645. DBGLOG("CJoinGroup::noteEndReceived %p from %d, candidates %d + %d, my count was %d, group count was %d", this, lineNo, candidates, candidateCount, atomic_read(&endMarkersPending), groupStart ? atomic_read(&groupStart->endMarkersPending) : 0);
  20646. #endif
  20647. // NOTE - as soon as endMarkersPending and groupStart->endMarkersPending are decremented to zero this object may get released asynchronously by other threads
  20648. // There must therefore be nothing in this method after them that acceses member variables. Think of it as a delete this...
  20649. // In particular, we can't safely reference groupStart after the dec_and_test of endMarkersPending, hence copy local first
  20650. CJoinGroup *localGroupStart = groupStart;
  20651. if (atomic_dec_and_test(&endMarkersPending))
  20652. {
  20653. if (localGroupStart)
  20654. return atomic_dec_and_test(&localGroupStart->endMarkersPending);
  20655. else
  20656. return true;
  20657. }
  20658. else
  20659. return false;
  20660. }
  20661. inline const void *queryLeft() const
  20662. {
  20663. return left;
  20664. }
  20665. void addRightMatch(KeyedJoinHeader *right)
  20666. {
  20667. assert(!complete());
  20668. unsigned short partNo = right->partNo;
  20669. if (partNo != lastPartNo)
  20670. {
  20671. // MORE - should we binchop? If we did we would need to be careful to find LAST match
  20672. if (partNo > lastPartNo)
  20673. pos = rows.length();
  20674. while (pos>0)
  20675. {
  20676. if (rows.item(pos-1)->partNo <= partNo)
  20677. break;
  20678. pos--;
  20679. }
  20680. lastPartNo = partNo;
  20681. }
  20682. rows.add(right, pos);
  20683. pos++;
  20684. }
  20685. inline unsigned rowsSeen() const
  20686. {
  20687. assert(complete());
  20688. return rows.length();
  20689. }
  20690. inline unsigned candidateCount() const
  20691. {
  20692. assert(complete());
  20693. return candidates;
  20694. }
  20695. };
  20696. #ifdef TRACE_JOINGROUPS
  20697. #define notePending() notePending(__LINE__)
  20698. #define noteEndReceived(a) noteEndReceived(a, __LINE__)
  20699. #endif
  20700. class KeyedJoinRemoteAdaptor : public CRemoteResultAdaptor // MORE - not sure it should be derived from this - makes processed all wrong, for example
  20701. {
  20702. private:
  20703. SafeQueueOf<const void, true> ready;
  20704. public:
  20705. IHThorKeyedJoinArg &helper;
  20706. unsigned joinProcessed;
  20707. bool isFullKey;
  20708. bool eof;
  20709. bool isSimple;
  20710. bool allPulled;
  20711. unsigned __int64 totalCycles;
  20712. unsigned activityId;
  20713. RecordPullerThread &puller;
  20714. SafeQueueOf<const void, true> injected; // Used in isSimple mode
  20715. Owned<IEngineRowAllocator> ccdRecordAllocator;
  20716. IJoinProcessor &processor;
  20717. KeyedJoinRemoteAdaptor(const RemoteActivityId &_remoteId, IHThorKeyedJoinArg &_helper, IRoxieServerActivity &_activity, bool _isFullKey, bool _isSimple,
  20718. RecordPullerThread &_puller, IJoinProcessor &_processor)
  20719. : helper(_helper),
  20720. CRemoteResultAdaptor(_remoteId, 0, _helper, _activity, true, true),
  20721. isFullKey(_isFullKey),
  20722. isSimple(_isSimple),
  20723. puller(_puller),
  20724. processor(_processor),
  20725. activityId(_activity.queryId())
  20726. {
  20727. joinProcessed = 0;
  20728. totalCycles = 0;
  20729. allPulled = false;
  20730. eof = false;
  20731. }
  20732. virtual void onCreate(IRoxieInput *_owner, IRoxieServerErrorHandler *_errorHandler, IRoxieSlaveContext *_ctx, IHThorArg *_colocalArg)
  20733. {
  20734. CRemoteResultAdaptor::onCreate(_owner, _errorHandler, _ctx, _colocalArg);
  20735. ccdRecordAllocator.setown(ctx->queryCodeContext()->getRowAllocator(QUERYINTERFACE(helper.queryJoinFieldsRecordSize(), IOutputMetaData), activityId));
  20736. }
  20737. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  20738. {
  20739. eof = false;
  20740. joinProcessed = 0;
  20741. totalCycles = 0;
  20742. allPulled = false;
  20743. assertex(ready.ordinality()==0);
  20744. CRemoteResultAdaptor::start(parentExtractSize, parentExtract, paused);
  20745. }
  20746. virtual void reset()
  20747. {
  20748. CRemoteResultAdaptor::reset();
  20749. while (ready.ordinality())
  20750. {
  20751. const void *goer = ready.dequeue();
  20752. if (goer)
  20753. ReleaseRoxieRow(goer);
  20754. }
  20755. while (injected.ordinality())
  20756. {
  20757. const void *goer = injected.dequeue();
  20758. if (goer)
  20759. ReleaseRoxieRow(goer);
  20760. }
  20761. }
  20762. inline void addResult(const void *row)
  20763. {
  20764. ready.enqueue(row);
  20765. }
  20766. virtual unsigned __int64 queryTotalCycles() const
  20767. {
  20768. return totalCycles;
  20769. }
  20770. virtual IOutputMetaData * queryOutputMeta() const
  20771. {
  20772. return owner->queryOutputMeta();
  20773. }
  20774. virtual const void *nextInGroup()
  20775. {
  20776. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  20777. loop
  20778. {
  20779. if (eof)
  20780. return NULL;
  20781. processSlaveResults();
  20782. if (ready.ordinality())
  20783. {
  20784. const void *result = ready.dequeue();
  20785. if (result)
  20786. joinProcessed++;
  20787. return result;
  20788. }
  20789. else
  20790. eof = true;
  20791. }
  20792. }
  20793. private:
  20794. void processSlaveResults()
  20795. {
  20796. while (!ready.ordinality())
  20797. {
  20798. KeyedJoinHeader *fetchedData;
  20799. if (isSimple)
  20800. {
  20801. while (!allPulled && !injected.ordinality())
  20802. {
  20803. if (!puller.pullRecords(1))
  20804. {
  20805. puller.done();
  20806. allPulled = true;
  20807. }
  20808. }
  20809. fetchedData = (KeyedJoinHeader *) injected.dequeue();
  20810. }
  20811. else
  20812. fetchedData = (KeyedJoinHeader *) CRemoteResultAdaptor::nextInGroup();
  20813. if (fetchedData)
  20814. {
  20815. CJoinGroup *thisGroup = fetchedData->thisGroup;
  20816. if (fetchedData->partNo == (unsigned short) -1)
  20817. {
  20818. #ifdef TRACE_JOINGROUPS
  20819. CTXLOG("Got end for group %p", thisGroup);
  20820. #endif
  20821. unsigned candidateCount = (unsigned) fetchedData->fpos;
  20822. ReleaseRoxieRow(fetchedData);
  20823. processor.noteEndReceived(thisGroup, candidateCount); // note - this can throw exception. So release fetchdata before calling
  20824. }
  20825. else
  20826. {
  20827. #ifdef TRACE_JOINGROUPS
  20828. CTXLOG("Reading another %d bytes for group %p data", ccdRecordSize, thisGroup);
  20829. #endif
  20830. thisGroup->addRightMatch(fetchedData);
  20831. if (isFullKey)
  20832. {
  20833. #ifdef TRACE_JOINGROUPS
  20834. CTXLOG("Calling noteEndReceived for record returned from FETCH of full keyed join");
  20835. #endif
  20836. processor.noteEndReceived(thisGroup, 0); // note - this can throw exception. So release fetchdata before calling
  20837. }
  20838. }
  20839. }
  20840. else
  20841. break;
  20842. }
  20843. }
  20844. };
  20845. class CRoxieServerFullKeyedJoinHead: public CRoxieServerActivity, implements IRecordPullerCallback, implements IRoxieServerErrorHandler
  20846. {
  20847. IHThorKeyedJoinArg &helper;
  20848. Owned<IKeyManager> tlk;
  20849. Linked<IKeyArray> keySet;
  20850. Linked<TranslatorArray> translators;
  20851. CRemoteResultAdaptor remote;
  20852. RecordPullerThread puller;
  20853. IOutputMetaData *indexReadMeta;
  20854. IJoinProcessor *joinHandler;
  20855. bool variableIndexFileName;
  20856. bool indexReadInputRecordVariable;
  20857. bool isLocal;
  20858. Owned<IEngineRowAllocator> indexReadAllocator;
  20859. Owned<const IResolvedFile> varFileInfo;
  20860. IRoxieInput *indexReadInput;
  20861. IIndexReadActivityInfo *rootIndex;
  20862. public:
  20863. CRoxieServerFullKeyedJoinHead(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, IKeyArray * _keySet, TranslatorArray *_translators, IOutputMetaData *_indexReadMeta, IJoinProcessor *_joinHandler, bool _isLocal)
  20864. : CRoxieServerActivity(_factory, _probeManager),
  20865. helper((IHThorKeyedJoinArg &)basehelper),
  20866. tlk(createKeyManager(NULL, 0, this)),
  20867. translators(_translators),
  20868. keySet(_keySet),
  20869. remote(_remoteId, 0, helper, *this, true, true),
  20870. indexReadMeta(_indexReadMeta),
  20871. joinHandler(_joinHandler),
  20872. puller(false),
  20873. isLocal(_isLocal)
  20874. {
  20875. variableIndexFileName = (helper.getJoinFlags() & (JFvarindexfilename|JFdynamicindexfilename)) != 0;
  20876. indexReadInputRecordVariable = indexReadMeta->isVariableSize();
  20877. indexReadInput = NULL;
  20878. rootIndex = NULL;
  20879. }
  20880. virtual const IResolvedFile *queryVarFileInfo() const
  20881. {
  20882. return varFileInfo;
  20883. }
  20884. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  20885. {
  20886. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  20887. remote.onCreate(this, this, _ctx, _colocalParent);
  20888. indexReadAllocator.setown(ctx->queryCodeContext()->getRowAllocator(indexReadMeta, activityId));
  20889. }
  20890. virtual void setInput(unsigned idx, IRoxieInput *_in)
  20891. {
  20892. if (!idx)
  20893. puller.setInput(this, _in);
  20894. else if (idx==1)
  20895. indexReadInput = _in;
  20896. else
  20897. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  20898. }
  20899. virtual void serializeExtra(MemoryBuffer &out)
  20900. {
  20901. if (helper.getJoinFlags() & JFindexfromactivity)
  20902. {
  20903. assertex(rootIndex);
  20904. const RemoteActivityId& indexId = rootIndex->queryRemoteId();
  20905. indexId.serialize(out);
  20906. // could mess about reserving space for length then patching it again, to avoid copy, but probably not worth it
  20907. MemoryBuffer tmp;
  20908. rootIndex->queryActivity()->serializeCreateStartContext(tmp);
  20909. if (rootIndex->queryActivity()->queryVarFileInfo())
  20910. rootIndex->queryActivity()->queryVarFileInfo()->queryTimeStamp().serialize(tmp);
  20911. unsigned ctxlen = tmp.length();
  20912. out.append(ctxlen).append(tmp);
  20913. }
  20914. }
  20915. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  20916. {
  20917. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  20918. if (indexReadInput)
  20919. {
  20920. indexReadInput->start(parentExtractSize, parentExtract, true); // paused=true because we don't want to actually run the index read
  20921. rootIndex = indexReadInput->queryIndexReadActivity();
  20922. if (!rootIndex)
  20923. throw MakeStringException(ROXIE_INTERNAL_ERROR,"Index in keyed join %d could not be resolved", queryId());
  20924. }
  20925. remote.onStart(parentExtractSize, parentExtract);
  20926. remote.setLimits(helper.getRowLimit(), (unsigned __int64) -1, I64C(0x7FFFFFFFFFFFFFFF));
  20927. if (rootIndex)
  20928. {
  20929. varFileInfo.setown(rootIndex->getVarFileInfo());
  20930. translators.setown(rootIndex->getTranslators());
  20931. keySet.setown(rootIndex->getKeySet());
  20932. }
  20933. else if (variableIndexFileName)
  20934. {
  20935. varFileInfo.setown(resolveLFN(helper.getIndexFileName(), false));
  20936. translators.setown(new TranslatorArray);
  20937. keySet.setown(varFileInfo->getKeyArray(factory->queryActivityMeta(), translators, false, isLocal ? factory->queryQueryFactory().queryChannel() : 0, factory->queryQueryFactory().getEnableFieldTranslation())); // MORE - isLocal?
  20938. }
  20939. puller.start(parentExtractSize, parentExtract, paused, ctx->fullKeyedJoinPreload(), false, ctx);
  20940. }
  20941. virtual void stop(bool aborting)
  20942. {
  20943. puller.stop(aborting);
  20944. CRoxieServerActivity::stop(aborting);
  20945. }
  20946. virtual void reset()
  20947. {
  20948. CRoxieServerActivity::reset();
  20949. puller.reset();
  20950. if (varFileInfo)
  20951. {
  20952. keySet.clear();
  20953. varFileInfo.clear();
  20954. }
  20955. }
  20956. virtual IRoxieInput *queryOutput(unsigned idx)
  20957. {
  20958. if (idx==(unsigned)-1)
  20959. idx = 0;
  20960. return idx ? NULL : &remote;
  20961. }
  20962. virtual void processRow(const void *row)
  20963. {
  20964. // MORE - this code seems to be pretty much duplicated below in half-keyed....
  20965. // called from front puller thread
  20966. // buffer up an IndexRead request
  20967. if (helper.leftCanMatch(row))
  20968. {
  20969. RtlDynamicRowBuilder extractedBuilder(indexReadAllocator);
  20970. unsigned indexReadSize = helper.extractIndexReadFields(extractedBuilder, row);
  20971. OwnedConstRoxieRow extracted;
  20972. if (indexReadSize)
  20973. extracted.setown(extractedBuilder.finalizeRowClear(indexReadSize));
  20974. CJoinGroup *jg = joinHandler->createJoinGroup(row);
  20975. for (unsigned partNo = 0; partNo < keySet->length(); partNo++)
  20976. {
  20977. IKeyIndexBase *thisBase = keySet->queryKeyPart(partNo);
  20978. if (thisBase)
  20979. {
  20980. unsigned fileNo = 0;
  20981. IKeyIndex *thisKey = thisBase->queryPart(fileNo);
  20982. try
  20983. {
  20984. tlk->setKey(thisKey);
  20985. tlk->setLayoutTranslator(translators->item(fileNo));
  20986. helper.createSegmentMonitors(tlk, extracted);
  20987. if (rootIndex)
  20988. rootIndex->mergeSegmentMonitors(tlk);
  20989. tlk->finishSegmentMonitors();
  20990. tlk->reset();
  20991. loop
  20992. {
  20993. typedef const void * cvp;
  20994. if (thisKey->isTopLevelKey())
  20995. {
  20996. bool locallySorted = !thisKey->isFullySorted();
  20997. while (locallySorted || tlk->lookup(false))
  20998. {
  20999. unsigned slavePart = locallySorted ? 0 : (unsigned) tlk->queryFpos();
  21000. if (locallySorted || slavePart)
  21001. {
  21002. cvp *outputBuffer = (cvp *) remote.getMem(slavePart, fileNo, indexReadSize + sizeof(cvp) + (indexReadInputRecordVariable ? sizeof(unsigned) : 0));
  21003. *outputBuffer++ = jg;
  21004. if (indexReadInputRecordVariable)
  21005. {
  21006. *(unsigned *) outputBuffer = indexReadSize;
  21007. outputBuffer = (cvp*) (((unsigned *) outputBuffer) + 1);
  21008. }
  21009. jg->notePending();
  21010. memcpy(outputBuffer, extracted, indexReadSize);
  21011. if (locallySorted)
  21012. {
  21013. for (unsigned i = 1; i < numChannels; i++)
  21014. jg->notePending();
  21015. break;
  21016. }
  21017. }
  21018. }
  21019. }
  21020. else
  21021. {
  21022. // MORE - this code seems to be duplicated in half keyed
  21023. unsigned accepted = 0;
  21024. unsigned rejected = 0;
  21025. Owned<CRowArrayMessageResult> result = new CRowArrayMessageResult(ctx->queryRowManager(), true);
  21026. jg->notePending();
  21027. unsigned candidateCount = 0;
  21028. while (tlk->lookup(true))
  21029. {
  21030. candidateCount++;
  21031. atomic_inc(&indexRecordsRead);
  21032. KLBlobProviderAdapter adapter(tlk);
  21033. offset_t recptr;
  21034. const byte *indexRow = tlk->queryKeyBuffer(recptr);
  21035. if (helper.indexReadMatch(extracted, indexRow, recptr, &adapter))
  21036. {
  21037. KeyedJoinHeader *rhs = (KeyedJoinHeader *) ctx->queryRowManager().allocate(KEYEDJOIN_RECORD_SIZE(0), activityId);
  21038. rhs->fpos = recptr;
  21039. rhs->thisGroup = jg;
  21040. rhs->partNo = partNo;
  21041. result->append(rhs);
  21042. }
  21043. else
  21044. {
  21045. rejected++;
  21046. atomic_inc(&postFiltered);
  21047. }
  21048. }
  21049. // output an end marker for the matches to this group
  21050. KeyedJoinHeader *endMarker = (KeyedJoinHeader *) ctx->queryRowManager().allocate(KEYEDJOIN_RECORD_SIZE(0), activityId);
  21051. endMarker->fpos = (offset_t) candidateCount;
  21052. endMarker->thisGroup = jg;
  21053. endMarker->partNo = (unsigned short) -1;
  21054. result->append(endMarker);
  21055. remote.injectResult(result.getClear());
  21056. if (accepted)
  21057. noteStatistic(STATS_ACCEPTED, accepted, 1);
  21058. if (rejected)
  21059. noteStatistic(STATS_REJECTED, rejected, 1);
  21060. }
  21061. if (++fileNo < thisBase->numParts())
  21062. {
  21063. thisKey = thisBase->queryPart(fileNo);
  21064. tlk->setKey(thisKey);
  21065. tlk->setLayoutTranslator(translators->item(fileNo));
  21066. tlk->reset();
  21067. }
  21068. else
  21069. break;
  21070. }
  21071. tlk->releaseSegmentMonitors();
  21072. tlk->setKey(NULL);
  21073. }
  21074. catch (...)
  21075. {
  21076. tlk->releaseSegmentMonitors();
  21077. tlk->setKey(NULL);
  21078. throw;
  21079. }
  21080. }
  21081. }
  21082. joinHandler->noteEndReceived(jg, 0);
  21083. }
  21084. else
  21085. {
  21086. joinHandler->noteEndReceived(joinHandler->createJoinGroup(row), 0);
  21087. }
  21088. }
  21089. void processGroup(const ConstPointerArray &)
  21090. {
  21091. throwUnexpected();
  21092. }
  21093. virtual void processEOG()
  21094. {
  21095. joinHandler->processEOG();
  21096. }
  21097. virtual void processDone()
  21098. {
  21099. // called from puller thread
  21100. remote.flush();
  21101. remote.senddone();
  21102. }
  21103. virtual void onLimitExceeded(bool isKeyed)
  21104. {
  21105. if (traceLevel > 4)
  21106. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  21107. if (isKeyed)
  21108. throwUnexpected();
  21109. helper.onLimitExceeded();
  21110. }
  21111. virtual const void *createLimitFailRow(bool isKeyed)
  21112. {
  21113. throwUnexpected();
  21114. }
  21115. virtual bool fireException(IException *e)
  21116. {
  21117. // called from puller thread on failure
  21118. remote.fireException(LINK(e));
  21119. return joinHandler->fireException(e);
  21120. }
  21121. virtual const void *nextInGroup()
  21122. {
  21123. throwUnexpected(); // I am nobody's input
  21124. }
  21125. };
  21126. class CRoxieServerKeyedJoinBase : public CRoxieServerActivity, implements IRecordPullerCallback, implements IRoxieServerErrorHandler, implements IJoinProcessor
  21127. {
  21128. protected:
  21129. IHThorKeyedJoinArg &helper;
  21130. KeyedJoinRemoteAdaptor remote;
  21131. RecordPullerThread puller;
  21132. OwnedConstRoxieRow defaultRight;
  21133. Owned<IEngineRowAllocator> defaultRightAllocator;
  21134. unsigned joinFlags;
  21135. unsigned atMost;
  21136. unsigned abortLimit;
  21137. unsigned keepLimit;
  21138. bool limitFail;
  21139. bool limitOnFail;
  21140. bool preserveGroups;
  21141. bool cloneLeft;
  21142. bool isSimple;
  21143. bool isLocal;
  21144. ThorActivityKind activityKind;
  21145. CJoinGroup *groupStart;
  21146. CriticalSection groupsCrit;
  21147. QueueOf<CJoinGroup, false> groups;
  21148. IRoxieInput *indexReadInput;
  21149. IIndexReadActivityInfo *rootIndex;
  21150. void createDefaultRight()
  21151. {
  21152. if (!defaultRight)
  21153. {
  21154. if (!defaultRightAllocator)
  21155. defaultRightAllocator.setown(ctx->queryCodeContext()->getRowAllocator(helper.queryJoinFieldsRecordSize(), activityId));
  21156. RtlDynamicRowBuilder rowBuilder(defaultRightAllocator);
  21157. size32_t thisSize = helper.createDefaultRight(rowBuilder);
  21158. defaultRight.setown(rowBuilder.finalizeRowClear(thisSize));
  21159. }
  21160. }
  21161. public:
  21162. CRoxieServerKeyedJoinBase(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, unsigned _joinFlags
  21163. , bool isFull, bool _isSimple, bool _isLocal)
  21164. : CRoxieServerActivity(_factory, _probeManager),
  21165. helper((IHThorKeyedJoinArg &)basehelper),
  21166. remote(_remoteId, helper, *this, isFull, _isSimple, puller, *this),
  21167. joinFlags(_joinFlags),
  21168. preserveGroups(meta.isGrouped()),
  21169. puller(false),
  21170. isSimple(_isSimple),
  21171. isLocal(_isLocal),
  21172. abortLimit(0),
  21173. keepLimit(0),
  21174. atMost(0),
  21175. limitFail(false),
  21176. limitOnFail(false),
  21177. cloneLeft(false)
  21178. {
  21179. groupStart = NULL;
  21180. activityKind = _factory->getKind();
  21181. indexReadInput = NULL;
  21182. rootIndex = NULL;
  21183. // MORE - code would be easier to read if I got more values from helper rather than passing from factory
  21184. }
  21185. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  21186. {
  21187. CRoxieServerActivity::onCreate(_ctx, _colocalParent);
  21188. remote.onCreate(this, this, _ctx, _colocalParent);
  21189. }
  21190. virtual void setInput(unsigned idx, IRoxieInput *_in)
  21191. {
  21192. if (!idx)
  21193. puller.setInput(this, _in);
  21194. else if (idx==1)
  21195. indexReadInput = _in;
  21196. else
  21197. throw MakeStringException(ROXIE_SET_INPUT, "Internal error: setInput() parameter out of bounds at %s(%d)", __FILE__, __LINE__);
  21198. }
  21199. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  21200. {
  21201. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  21202. if (indexReadInput)
  21203. {
  21204. indexReadInput->start(parentExtractSize, parentExtract, true); // paused=true because we don't want to actually run the index read
  21205. rootIndex = indexReadInput->queryIndexReadActivity();
  21206. if (!rootIndex)
  21207. throw MakeStringException(ROXIE_INTERNAL_ERROR,"Index in keyed join %d could not be resolved", queryId());
  21208. }
  21209. remote.onStart(parentExtractSize, parentExtract);
  21210. remote.setLimits(helper.getRowLimit(), (unsigned __int64) -1, I64C(0x7FFFFFFFFFFFFFFF));
  21211. atMost = helper.getJoinLimit();
  21212. if (atMost == 0) atMost = (unsigned)-1;
  21213. abortLimit = helper.getMatchAbortLimit();
  21214. if (abortLimit == 0 || atMost != (unsigned) -1) abortLimit = (unsigned)-1;
  21215. keepLimit = helper.getKeepLimit();
  21216. if (keepLimit == 0) keepLimit = (unsigned)-1;
  21217. getLimitType(joinFlags, limitFail, limitOnFail);
  21218. cloneLeft = (joinFlags & JFtransformmatchesleft) != 0;
  21219. if (joinFlags & JFleftouter)
  21220. createDefaultRight();
  21221. }
  21222. virtual void stop(bool aborting)
  21223. {
  21224. puller.stop(aborting);
  21225. if (indexReadInput)
  21226. indexReadInput->stop(aborting);
  21227. CRoxieServerActivity::stop(aborting);
  21228. }
  21229. virtual unsigned __int64 queryLocalCycles() const
  21230. {
  21231. __int64 localCycles = remote.totalCycles;
  21232. localCycles -= puller.queryTotalCycles(); // MORE - debatable... but probably fair.
  21233. if (localCycles < 0)
  21234. localCycles = 0;
  21235. return localCycles;
  21236. }
  21237. virtual IRoxieInput *queryInput(unsigned idx)
  21238. {
  21239. if (idx==0)
  21240. return puller.queryInput();
  21241. else if (idx==1)
  21242. return indexReadInput;
  21243. else
  21244. return NULL;
  21245. }
  21246. virtual void reset()
  21247. {
  21248. totalCycles = remote.totalCycles;
  21249. remote.totalCycles = 0;
  21250. processed = remote.joinProcessed;
  21251. remote.joinProcessed = 0;
  21252. defaultRight.clear();
  21253. if (indexReadInput)
  21254. indexReadInput->reset();
  21255. CRoxieServerActivity::reset();
  21256. puller.reset();
  21257. while (groups.ordinality())
  21258. {
  21259. ::Release(groups.dequeue());
  21260. }
  21261. }
  21262. virtual IRoxieInput *queryOutput(unsigned idx)
  21263. {
  21264. if (idx==(unsigned)-1)
  21265. idx = 0;
  21266. return idx ? NULL : &remote;
  21267. }
  21268. #undef new
  21269. virtual CJoinGroup *createJoinGroup(const void *row)
  21270. {
  21271. // NOTE - we need to protect access to queue, since it's also modified by consumer thread. Groupstart is only modified by puller thread.
  21272. CriticalBlock c(groupsCrit);
  21273. if (preserveGroups && !groupStart)
  21274. {
  21275. groupStart = new (&ctx->queryRowManager(), activityId) CJoinGroup(NULL, NULL);
  21276. groups.enqueue(groupStart);
  21277. }
  21278. CJoinGroup *jg = new (&ctx->queryRowManager(), activityId) CJoinGroup(row, groupStart);
  21279. groups.enqueue(jg);
  21280. return jg;
  21281. }
  21282. #if defined(_DEBUG) && defined(_WIN32) && !defined(USING_MPATROL)
  21283. #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
  21284. #endif
  21285. void endGroup()
  21286. {
  21287. CriticalBlock c(groupsCrit);
  21288. if (groupStart)
  21289. noteEndReceived(groupStart, 0);
  21290. groupStart = NULL;
  21291. }
  21292. virtual void noteEndReceived(CJoinGroup *jg, unsigned candidateCount)
  21293. {
  21294. if (jg->noteEndReceived(candidateCount))
  21295. processCompletedGroups();
  21296. }
  21297. void processCompletedGroups()
  21298. {
  21299. loop
  21300. {
  21301. CriticalBlock c(groupsCrit);
  21302. if (!groups.head()->complete())
  21303. break;
  21304. Owned<CJoinGroup> head = groups.dequeue();
  21305. if (preserveGroups)
  21306. {
  21307. assert(head->isHeadRecord());
  21308. assert(groups.head()->inGroup(head));
  21309. unsigned joinGroupSize = 0;
  21310. while (groups.ordinality() && groups.head()->inGroup(head))
  21311. {
  21312. Owned<CJoinGroup> finger = groups.dequeue();
  21313. joinGroupSize += doJoinGroup(finger);
  21314. }
  21315. if (joinGroupSize)
  21316. remote.addResult(NULL);
  21317. }
  21318. else
  21319. doJoinGroup(head);
  21320. if (!groups.ordinality())
  21321. break;
  21322. }
  21323. }
  21324. void failLimit(const void * left)
  21325. {
  21326. helper.onMatchAbortLimitExceeded();
  21327. CommonXmlWriter xmlwrite(0);
  21328. if (input && input->queryOutputMeta() && input->queryOutputMeta()->hasXML())
  21329. {
  21330. input->queryOutputMeta()->toXML((byte *) left, xmlwrite);
  21331. }
  21332. throw MakeStringException(ROXIE_JOIN_ERROR, "More than %d match candidates in keyed join %d for row %s", abortLimit, queryId(), xmlwrite.str());
  21333. }
  21334. virtual bool needsAllocator() const { return true; }
  21335. unsigned doTransform(const void *left, const void *right, offset_t fpos_or_count, IException *except, const void **group)
  21336. {
  21337. if (cloneLeft && !except)
  21338. {
  21339. LinkRoxieRow(left);
  21340. remote.addResult((void *) left);
  21341. return 1;
  21342. }
  21343. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  21344. unsigned outSize;
  21345. try
  21346. {
  21347. outSize = except ? helper.onFailTransform(rowBuilder, left, right, fpos_or_count, except) :
  21348. (activityKind == TAKkeyeddenormalizegroup) ? helper.transform(rowBuilder, left, right, (unsigned) fpos_or_count, group) :
  21349. helper.transform(rowBuilder, left, right, fpos_or_count);
  21350. }
  21351. catch (IException *E)
  21352. {
  21353. throw makeWrappedException(E);
  21354. }
  21355. if (outSize)
  21356. {
  21357. const void *shrunk = rowBuilder.finalizeRowClear(outSize);
  21358. remote.addResult(shrunk);
  21359. return 1;
  21360. }
  21361. else
  21362. return 0;
  21363. }
  21364. unsigned doJoinGroup(CJoinGroup *jg)
  21365. {
  21366. unsigned matched = jg->rowsSeen();
  21367. unsigned added = 0;
  21368. const void *left = jg->queryLeft();
  21369. if (jg->candidateCount() > abortLimit)
  21370. {
  21371. if (limitFail)
  21372. failLimit(left);
  21373. if (ctx->queryDebugContext())
  21374. ctx->queryDebugContext()->checkBreakpoint(DebugStateLimit, NULL, static_cast<IActivityBase *>(this));
  21375. if (limitOnFail)
  21376. {
  21377. Owned<IException> except;
  21378. try
  21379. {
  21380. failLimit(left);
  21381. }
  21382. catch(IException * e)
  21383. {
  21384. except.setown(e);
  21385. }
  21386. added = doTransform(left, defaultRight, 0, except, NULL);
  21387. }
  21388. }
  21389. else if (!matched || jg->candidateCount() > atMost)
  21390. {
  21391. switch (joinFlags & JFtypemask)
  21392. {
  21393. case JFleftouter:
  21394. case JFleftonly:
  21395. switch (activityKind)
  21396. {
  21397. case TAKkeyedjoin:
  21398. case TAKkeyeddenormalizegroup:
  21399. added = doTransform(left, defaultRight, 0, NULL, NULL);
  21400. break;
  21401. case TAKkeyeddenormalize:
  21402. LinkRoxieRow(left);
  21403. remote.addResult((void *) left);
  21404. added++;
  21405. break;
  21406. }
  21407. break;
  21408. }
  21409. }
  21410. else if (!(joinFlags & JFexclude))
  21411. {
  21412. unsigned idx = 0;
  21413. switch (activityKind)
  21414. {
  21415. case TAKkeyedjoin:
  21416. while (idx < matched)
  21417. {
  21418. const KeyedJoinHeader *rhs = jg->queryRow(idx);
  21419. added += doTransform(left, &rhs->rhsdata, rhs->fpos, NULL, NULL);
  21420. if (added==keepLimit)
  21421. break;
  21422. idx++;
  21423. }
  21424. break;
  21425. case TAKkeyeddenormalize:
  21426. {
  21427. OwnedConstRoxieRow newLeft;
  21428. newLeft.set(left);
  21429. unsigned rowSize = 0;
  21430. unsigned rightAdded = 0;
  21431. while (idx < matched)
  21432. {
  21433. const KeyedJoinHeader *rhs = jg->queryRow(idx);
  21434. try
  21435. {
  21436. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  21437. size32_t transformedSize = helper.transform(rowBuilder, newLeft, &rhs->rhsdata, rhs->fpos, idx+1);
  21438. if (transformedSize)
  21439. {
  21440. rowSize = transformedSize;
  21441. newLeft.setown(rowBuilder.finalizeRowClear(rowSize));
  21442. rightAdded++;
  21443. if (rightAdded==keepLimit)
  21444. break;
  21445. }
  21446. idx++;
  21447. }
  21448. catch (IException *E)
  21449. {
  21450. throw makeWrappedException(E);
  21451. }
  21452. }
  21453. if (rowSize)
  21454. {
  21455. remote.addResult(newLeft.getClear());
  21456. added++;
  21457. }
  21458. }
  21459. break;
  21460. case TAKkeyeddenormalizegroup:
  21461. {
  21462. ConstPointerArray extractedRows;
  21463. while (idx < matched && idx < keepLimit)
  21464. {
  21465. const KeyedJoinHeader *rhs = jg->queryRow(idx);
  21466. extractedRows.append((void *) &rhs->rhsdata);
  21467. idx++;
  21468. }
  21469. added += doTransform(left, extractedRows.item(0), extractedRows.ordinality(), NULL, (const void * *)extractedRows.getArray());
  21470. }
  21471. break;
  21472. }
  21473. }
  21474. return added;
  21475. }
  21476. virtual void processDone()
  21477. {
  21478. // called from puller thread
  21479. remote.flush();
  21480. remote.senddone();
  21481. }
  21482. virtual void onLimitExceeded(bool isKeyed)
  21483. {
  21484. if (traceLevel > 4)
  21485. DBGLOG("activityid = %d isKeyed = %d line = %d", activityId, isKeyed, __LINE__);
  21486. if (isKeyed)
  21487. throwUnexpected();
  21488. helper.onLimitExceeded();
  21489. }
  21490. virtual const void *createLimitFailRow(bool isKeyed)
  21491. {
  21492. throwUnexpected();
  21493. }
  21494. virtual bool fireException(IException *e)
  21495. {
  21496. // called from puller thread on failure
  21497. return remote.fireException(e);
  21498. }
  21499. virtual const void *nextInGroup()
  21500. {
  21501. throwUnexpected(); // I am nobody's input
  21502. }
  21503. };
  21504. #ifdef _MSC_VER
  21505. #pragma warning ( push )
  21506. #pragma warning ( disable: 4355 )
  21507. #endif
  21508. class CRoxieServerKeyedJoinActivity : public CRoxieServerKeyedJoinBase
  21509. {
  21510. CRoxieServerFullKeyedJoinHead head;
  21511. Owned<IEngineRowAllocator> fetchInputAllocator;
  21512. Linked<IFilePartMap> map;
  21513. bool variableFetchFileName;
  21514. Owned<const IResolvedFile> varFetchFileInfo;
  21515. CachedOutputMetaData fetchInputFields;
  21516. public:
  21517. CRoxieServerKeyedJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_headId, IKeyArray * _key, TranslatorArray *_translators, IOutputMetaData *_indexReadMeta,
  21518. const RemoteActivityId &_tailId, IFilePartMap *_map, unsigned _joinFlags, bool _isLocal)
  21519. : CRoxieServerKeyedJoinBase(_factory, _probeManager, _tailId, _joinFlags, true, false, _isLocal),
  21520. head(_factory, _probeManager, _headId, _key, _translators, _indexReadMeta, this, _isLocal),
  21521. map(_map)
  21522. {
  21523. CRoxieServerKeyedJoinBase::setInput(0, head.queryOutput(0));
  21524. variableFetchFileName = (helper.getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0;
  21525. }
  21526. virtual const IResolvedFile *queryVarFileInfo() const
  21527. {
  21528. return varFetchFileInfo;
  21529. }
  21530. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  21531. {
  21532. CRoxieServerKeyedJoinBase::onCreate(_ctx, _colocalParent);
  21533. head.onCreate(_ctx, _colocalParent);
  21534. fetchInputFields.set(helper.queryFetchInputRecordSize());
  21535. fetchInputAllocator.setown(ctx->queryCodeContext()->getRowAllocator(helper.queryFetchInputRecordSize(), activityId));
  21536. }
  21537. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  21538. {
  21539. CRoxieServerKeyedJoinBase::start(parentExtractSize, parentExtract, paused);
  21540. if (variableFetchFileName)
  21541. {
  21542. varFetchFileInfo.setown(resolveLFN(helper.getFileName(), false));
  21543. map.setown(varFetchFileInfo->getFileMap());
  21544. }
  21545. puller.start(parentExtractSize, parentExtract, paused, ctx->keyedJoinPreload(), false, ctx);
  21546. }
  21547. virtual void setInput(unsigned idx, IRoxieInput *in)
  21548. {
  21549. head.setInput(idx, in);
  21550. }
  21551. virtual void processRow(const void *_rhs)
  21552. {
  21553. // called from puller thread
  21554. KeyedJoinHeader *rhs = (KeyedJoinHeader *) _rhs;
  21555. CJoinGroup *jg = rhs->thisGroup;
  21556. if (rhs->partNo != (unsigned short) -1)
  21557. {
  21558. unsigned partNo = map->mapOffset(rhs->fpos);
  21559. RtlDynamicRowBuilder fetchBuilder(fetchInputAllocator, true);
  21560. size32_t fisize = helper.extractFetchFields(fetchBuilder, jg->queryLeft());
  21561. if (fetchInputFields.isVariableSize())
  21562. {
  21563. KeyedJoinHeader *outRow = (KeyedJoinHeader *) remote.getMem(partNo, 0, KEYEDJOIN_RECORD_SIZE(fisize + sizeof(fisize)));
  21564. memcpy(outRow, rhs, KEYEDJOIN_RECORD_SIZE(0)); // MORE - copy constructor might be more appropriate....
  21565. ReleaseRoxieRow(rhs);
  21566. jg->notePending();
  21567. memcpy(&outRow->rhsdata, &fisize, sizeof(fisize));
  21568. memcpy((&outRow->rhsdata)+sizeof(fisize), fetchBuilder.row(), fisize);
  21569. }
  21570. else
  21571. {
  21572. KeyedJoinHeader *outRow = (KeyedJoinHeader *) remote.getMem(partNo, 0, KEYEDJOIN_RECORD_SIZE(fisize));
  21573. memcpy(outRow, rhs, KEYEDJOIN_RECORD_SIZE(0)); // MORE - copy constructor might be more appropriate....
  21574. ReleaseRoxieRow(rhs);
  21575. jg->notePending();
  21576. memcpy(&outRow->rhsdata, fetchBuilder.row(), fisize);
  21577. }
  21578. }
  21579. else
  21580. {
  21581. unsigned candidateCount = (unsigned) rhs->fpos;
  21582. // CTXLOG("Full keyed join - all results back from index");
  21583. ReleaseRoxieRow(rhs);
  21584. noteEndReceived(jg, candidateCount); // may throw exception - so release row before calling
  21585. }
  21586. }
  21587. virtual void processEOG()
  21588. {
  21589. // called from front puller thread
  21590. if (preserveGroups)
  21591. endGroup();
  21592. }
  21593. void processGroup(const ConstPointerArray &)
  21594. {
  21595. throwUnexpected();
  21596. }
  21597. };
  21598. #ifdef _MSC_VER
  21599. #pragma warning ( pop )
  21600. #endif
  21601. class CRoxieServerHalfKeyedJoinActivity : public CRoxieServerKeyedJoinBase
  21602. {
  21603. IOutputMetaData *indexReadMeta;
  21604. Owned<IEngineRowAllocator> indexReadAllocator;
  21605. Owned<IKeyManager> tlk;
  21606. bool variableIndexFileName;
  21607. bool indexReadInputRecordVariable;
  21608. Owned<const IResolvedFile> varFileInfo;
  21609. Linked<TranslatorArray> translators;
  21610. Linked<IKeyArray> keySet;
  21611. Owned<IOutputMetaData> joinPrefixedMeta;
  21612. Owned<IEngineRowAllocator> joinFieldsAllocator;
  21613. public:
  21614. CRoxieServerHalfKeyedJoinActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager, const RemoteActivityId &_remoteId, IKeyArray * _keySet, TranslatorArray *_translators,
  21615. IOutputMetaData *_indexReadMeta, unsigned _joinFlags, bool _isSimple, bool _isLocal)
  21616. : CRoxieServerKeyedJoinBase(_factory, _probeManager, _remoteId, _joinFlags, false, _isSimple, _isLocal),
  21617. indexReadMeta(_indexReadMeta),
  21618. tlk(createKeyManager(NULL, 0, this)),
  21619. keySet(_keySet),
  21620. translators(_translators)
  21621. {
  21622. variableIndexFileName = (helper.getJoinFlags() & (JFvarindexfilename|JFdynamicindexfilename)) != 0;
  21623. indexReadInputRecordVariable = indexReadMeta->isVariableSize();
  21624. }
  21625. virtual void serializeExtra(MemoryBuffer &out)
  21626. {
  21627. if (helper.getJoinFlags() & JFindexfromactivity)
  21628. {
  21629. assertex(rootIndex);
  21630. const RemoteActivityId& indexId = rootIndex->queryRemoteId();
  21631. indexId.serialize(out);
  21632. // could mess about reserving space for length then patching it again, to avoid copy, but probably not worth it
  21633. MemoryBuffer tmp;
  21634. rootIndex->queryActivity()->serializeCreateStartContext(tmp);
  21635. if (rootIndex->queryActivity()->queryVarFileInfo())
  21636. rootIndex->queryActivity()->queryVarFileInfo()->queryTimeStamp().serialize(tmp);
  21637. unsigned ctxlen = tmp.length();
  21638. out.append(ctxlen).append(tmp);
  21639. }
  21640. }
  21641. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  21642. {
  21643. CRoxieServerKeyedJoinBase::onCreate(_ctx, _colocalParent);
  21644. indexReadAllocator.setown(ctx->queryCodeContext()->getRowAllocator(indexReadMeta, activityId));
  21645. IOutputMetaData *joinFieldsMeta = helper.queryJoinFieldsRecordSize();
  21646. joinPrefixedMeta.setown(new CPrefixedOutputMeta(KEYEDJOIN_RECORD_SIZE(0), joinFieldsMeta)); // MORE - not sure if we really need this
  21647. joinFieldsAllocator.setown(ctx->queryCodeContext()->getRowAllocator(joinPrefixedMeta, activityId));
  21648. }
  21649. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  21650. {
  21651. CRoxieServerKeyedJoinBase::start(parentExtractSize, parentExtract, paused);
  21652. if (rootIndex)
  21653. {
  21654. varFileInfo.setown(rootIndex->getVarFileInfo());
  21655. translators.setown(rootIndex->getTranslators());
  21656. keySet.setown(rootIndex->getKeySet());
  21657. }
  21658. else if (variableIndexFileName)
  21659. {
  21660. varFileInfo.setown(resolveLFN(helper.getIndexFileName(), false));
  21661. translators.setown(new TranslatorArray);
  21662. keySet.setown(varFileInfo->getKeyArray(factory->queryActivityMeta(), translators, false, isLocal ? factory->queryQueryFactory().queryChannel() : 0, factory->queryQueryFactory().getEnableFieldTranslation()));
  21663. }
  21664. puller.start(parentExtractSize, parentExtract, paused, ctx->keyedJoinPreload(), isSimple, ctx);
  21665. }
  21666. virtual const IResolvedFile *queryVarFileInfo() const
  21667. {
  21668. return varFileInfo;
  21669. }
  21670. virtual void reset()
  21671. {
  21672. CRoxieServerKeyedJoinBase::reset();
  21673. if (varFileInfo)
  21674. {
  21675. keySet.clear();
  21676. varFileInfo.clear();
  21677. }
  21678. }
  21679. virtual void processRow(const void *row)
  21680. {
  21681. // called from front puller thread
  21682. // buffer up an IndexRead request
  21683. if (helper.leftCanMatch(row) && keySet)
  21684. {
  21685. RtlDynamicRowBuilder extractBuilder(indexReadAllocator);
  21686. unsigned indexReadRecordSize = helper.extractIndexReadFields(extractBuilder, row);
  21687. OwnedConstRoxieRow extracted;
  21688. if (indexReadRecordSize)
  21689. extracted.setown(extractBuilder.finalizeRowClear(indexReadRecordSize));
  21690. CJoinGroup *jg = createJoinGroup(row);
  21691. for (unsigned partNo = 0; partNo < keySet->length(); partNo++)
  21692. {
  21693. IKeyIndexBase *thisBase = keySet->queryKeyPart(partNo);
  21694. if (thisBase)
  21695. {
  21696. unsigned fileNo = 0;
  21697. IKeyIndex *thisKey = thisBase->queryPart(fileNo);
  21698. tlk->setKey(thisKey);
  21699. tlk->setLayoutTranslator(translators->item(fileNo));
  21700. helper.createSegmentMonitors(tlk, extracted);
  21701. if (rootIndex)
  21702. rootIndex->mergeSegmentMonitors(tlk);
  21703. tlk->finishSegmentMonitors();
  21704. try
  21705. {
  21706. tlk->reset();
  21707. loop
  21708. {
  21709. typedef const void * cvp;
  21710. if (thisKey && thisKey->isTopLevelKey())
  21711. {
  21712. bool locallySorted = (!thisKey->isFullySorted());
  21713. while (locallySorted || tlk->lookup(false))
  21714. {
  21715. unsigned slavePart = locallySorted ? 0 : (unsigned) tlk->queryFpos();
  21716. if (locallySorted || slavePart)
  21717. {
  21718. cvp *outputBuffer = (cvp *) remote.getMem(slavePart, fileNo, indexReadRecordSize + sizeof(cvp) + (indexReadInputRecordVariable ? sizeof(unsigned) : 0));
  21719. *outputBuffer++ = jg;
  21720. if (indexReadInputRecordVariable)
  21721. {
  21722. *(unsigned *) outputBuffer = indexReadRecordSize;
  21723. outputBuffer = (cvp *) (((unsigned *) outputBuffer) + 1);
  21724. }
  21725. jg->notePending();
  21726. memcpy(outputBuffer, extracted, indexReadRecordSize);
  21727. if (locallySorted)
  21728. {
  21729. for (unsigned i = 1; i < numChannels; i++)
  21730. jg->notePending();
  21731. break;
  21732. }
  21733. }
  21734. }
  21735. }
  21736. else
  21737. {
  21738. unsigned accepted = 0;
  21739. unsigned rejected = 0;
  21740. Owned<CRowArrayMessageResult> result;
  21741. if (!isSimple)
  21742. result.setown(new CRowArrayMessageResult(ctx->queryRowManager(), true));
  21743. // MORE - This code seems to be duplicated in keyedJoinHead
  21744. jg->notePending();
  21745. unsigned candidateCount = 0;
  21746. while (tlk->lookup(true))
  21747. {
  21748. candidateCount++;
  21749. atomic_inc(&indexRecordsRead);
  21750. KLBlobProviderAdapter adapter(tlk);
  21751. offset_t recptr;
  21752. const byte *indexRow = tlk->queryKeyBuffer(recptr);
  21753. if (helper.indexReadMatch(extracted, indexRow, recptr, &adapter))
  21754. {
  21755. RtlDynamicRowBuilder rb(joinFieldsAllocator, true);
  21756. CPrefixedRowBuilder pb(KEYEDJOIN_RECORD_SIZE(0), rb);
  21757. accepted++;
  21758. KLBlobProviderAdapter adapter(tlk);
  21759. size32_t joinFieldsSize = helper.extractJoinFields(pb, indexRow, recptr, &adapter);
  21760. KeyedJoinHeader *rec = (KeyedJoinHeader *) rb.getUnfinalizedClear(); // lack of finalize ok as unserialized data here.
  21761. rec->fpos = recptr;
  21762. rec->thisGroup = jg;
  21763. rec->partNo = partNo;
  21764. if (isSimple)
  21765. remote.injected.enqueue(rec);
  21766. else
  21767. result->append(rec);
  21768. }
  21769. else
  21770. {
  21771. rejected++;
  21772. atomic_inc(&postFiltered);
  21773. }
  21774. }
  21775. // output an end marker for the matches to this group
  21776. KeyedJoinHeader *rec = (KeyedJoinHeader *) ctx->queryRowManager().allocate(KEYEDJOIN_RECORD_SIZE(0), activityId);
  21777. rec->fpos = (offset_t) candidateCount;
  21778. rec->thisGroup = jg;
  21779. rec->partNo = (unsigned short) -1;
  21780. if (isSimple)
  21781. remote.injected.enqueue(rec);
  21782. else
  21783. {
  21784. result->append(rec);
  21785. remote.injectResult(result.getClear());
  21786. }
  21787. if (accepted)
  21788. noteStatistic(STATS_ACCEPTED, accepted, 1);
  21789. if (rejected)
  21790. noteStatistic(STATS_REJECTED, rejected, 1);
  21791. }
  21792. if (++fileNo < thisBase->numParts())
  21793. {
  21794. thisKey = thisBase->queryPart(fileNo);
  21795. tlk->setKey(thisKey);
  21796. tlk->setLayoutTranslator(translators->item(fileNo));
  21797. tlk->reset();
  21798. }
  21799. else
  21800. break;
  21801. }
  21802. tlk->releaseSegmentMonitors();
  21803. tlk->setKey(NULL);
  21804. }
  21805. catch (...)
  21806. {
  21807. tlk->releaseSegmentMonitors();
  21808. tlk->setKey(NULL);
  21809. throw;
  21810. }
  21811. }
  21812. }
  21813. noteEndReceived(jg, 0);
  21814. }
  21815. else
  21816. {
  21817. noteEndReceived(createJoinGroup(row), 0);
  21818. }
  21819. }
  21820. virtual void processEOG()
  21821. {
  21822. // called from front puller thread
  21823. if (preserveGroups)
  21824. endGroup();
  21825. }
  21826. void processGroup(const ConstPointerArray &)
  21827. {
  21828. throwUnexpected();
  21829. }
  21830. };
  21831. class CRoxieServerKeyedJoinActivityFactory : public CRoxieServerMultiInputFactory
  21832. {
  21833. Owned<const IResolvedFile> indexfile;
  21834. Owned<const IResolvedFile> datafile;
  21835. Owned<IKeyArray> keySet;
  21836. Owned<TranslatorArray> translatorArray;
  21837. Owned<IDefRecordMeta> activityMeta;
  21838. RemoteActivityId headId;
  21839. RemoteActivityId tailId;
  21840. IOutputMetaData *indexReadMeta;
  21841. Owned<IFilePartMap> map;
  21842. Owned<IFileIOArray> files;
  21843. unsigned joinFlags;
  21844. bool isHalfKeyed;
  21845. bool isLocal;
  21846. bool enableFieldTranslation;
  21847. bool variableFetchFileName;
  21848. bool variableIndexFileName;
  21849. bool isSimple;
  21850. public:
  21851. CRoxieServerKeyedJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_headId, const RemoteActivityId &_tailId, IPropertyTree &_graphNode)
  21852. : CRoxieServerMultiInputFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), headId(_headId), tailId(_tailId)
  21853. {
  21854. Owned<IHThorKeyedJoinArg> helper = (IHThorKeyedJoinArg *) helperFactory();
  21855. isLocal = _graphNode.getPropBool("att[@name='local']/@value");
  21856. isSimple = isLocal;
  21857. rtlDataAttr indexLayoutMeta;
  21858. size32_t indexLayoutSize;
  21859. if(!helper->getIndexLayout(indexLayoutSize, indexLayoutMeta.refdata()))
  21860. assertex(indexLayoutSize== 0);
  21861. MemoryBuffer m;
  21862. m.setBuffer(indexLayoutSize, indexLayoutMeta.getdata());
  21863. activityMeta.setown(deserializeRecordMeta(m, true));
  21864. enableFieldTranslation = queryFactory.getEnableFieldTranslation();
  21865. translatorArray.setown(new TranslatorArray);
  21866. joinFlags = helper->getJoinFlags();
  21867. variableIndexFileName = (joinFlags & (JFvarindexfilename|JFdynamicindexfilename)) != 0;
  21868. variableFetchFileName = (helper->getFetchFlags() & (FFvarfilename|FFdynamicfilename)) != 0;
  21869. if (!variableIndexFileName)
  21870. {
  21871. bool isOpt = (joinFlags & JFindexoptional) != 0;
  21872. indexfile.setown(queryFactory.queryPackage().lookupFileName(helper->getIndexFileName(), isOpt, true));
  21873. if (indexfile)
  21874. keySet.setown(indexfile->getKeyArray(activityMeta, translatorArray, isOpt, isLocal ? queryFactory.queryChannel() : 0, enableFieldTranslation));
  21875. }
  21876. if (keySet && keySet->length()==1 && !isSimple)
  21877. {
  21878. IKeyIndexBase *thisBase = keySet->queryKeyPart(0);
  21879. if (thisBase->numParts()==1 && !thisBase->queryPart(0)->isTopLevelKey())
  21880. isSimple = true;
  21881. // MORE - if it's a variable filename then it MAY be simple, we don't know. Tough.
  21882. }
  21883. if (!simpleLocalKeyedJoins)
  21884. isSimple = false;
  21885. isHalfKeyed = !helper->diskAccessRequired();
  21886. indexReadMeta = QUERYINTERFACE(helper->queryIndexReadInputRecordSize(), IOutputMetaData);
  21887. if (!isHalfKeyed && !variableFetchFileName)
  21888. {
  21889. bool isFetchOpt = (helper->getFetchFlags() & FFdatafileoptional) != 0;
  21890. datafile.setown(_queryFactory.queryPackage().lookupFileName(queryNodeFileName(_graphNode), isFetchOpt, true));
  21891. if (datafile)
  21892. {
  21893. if (isLocal)
  21894. files.setown(datafile->getIFileIOArray(isFetchOpt, queryFactory.queryChannel()));
  21895. else
  21896. map.setown(datafile->getFileMap());
  21897. }
  21898. }
  21899. }
  21900. virtual bool getEnableFieldTranslation() const
  21901. {
  21902. return enableFieldTranslation;
  21903. }
  21904. virtual IDefRecordMeta *queryActivityMeta() const
  21905. {
  21906. return activityMeta;
  21907. }
  21908. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  21909. {
  21910. if (isHalfKeyed)
  21911. return new CRoxieServerHalfKeyedJoinActivity(this, _probeManager,
  21912. headId, keySet, translatorArray, indexReadMeta, joinFlags, isSimple, isLocal);
  21913. else
  21914. return new CRoxieServerKeyedJoinActivity(this, _probeManager,
  21915. headId, keySet, translatorArray, indexReadMeta,
  21916. tailId, map, joinFlags, isLocal);
  21917. }
  21918. };
  21919. IRoxieServerActivityFactory *createRoxieServerKeyedJoinActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, const RemoteActivityId &_remoteId, const RemoteActivityId &_remoteId2, IPropertyTree &_graphNode)
  21920. {
  21921. return new CRoxieServerKeyedJoinActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _remoteId, _remoteId2, _graphNode);
  21922. }
  21923. //=================================================================================
  21924. class CRoxieServerSoapActivityBase : public CRoxieServerActivity, implements ISoapCallRowProvider, implements IRoxieAbortMonitor
  21925. {
  21926. protected:
  21927. Owned<ISoapCallHelper> soaphelper;
  21928. IHThorSoapActionArg & helper;
  21929. StringBuffer authToken;
  21930. bool eof;
  21931. CriticalSection crit;
  21932. ClientCertificate *pClientCert;
  21933. public:
  21934. IMPLEMENT_IINTERFACE;
  21935. CRoxieServerSoapActivityBase(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  21936. : CRoxieServerActivity(_factory, _probeManager), helper((IHThorSoapActionArg &)basehelper)
  21937. {
  21938. eof = false;
  21939. if (clientCert.certificate.length() > 0 && clientCert.privateKey.length() > 0 && clientCert.passphrase.length() > 0)
  21940. pClientCert = &clientCert;
  21941. else
  21942. pClientCert = NULL;
  21943. }
  21944. // ISoapCallRowProvider
  21945. virtual IHThorSoapActionArg * queryActionHelper() { return &helper; };
  21946. virtual IHThorSoapCallArg * queryCallHelper() { return NULL; };
  21947. virtual const void * getNextRow() { return NULL; };
  21948. virtual void releaseRow(const void * r) { ReleaseRoxieRow(r); };
  21949. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  21950. {
  21951. eof = false;
  21952. CRoxieServerActivity::start(parentExtractSize, parentExtract, paused);
  21953. authToken.append(ctx->queryAuthToken());
  21954. }
  21955. virtual void reset()
  21956. {
  21957. // MORE - Shouldn't we make sure thread is stopped etc???
  21958. soaphelper.clear();
  21959. CRoxieServerActivity::reset();
  21960. }
  21961. // IRoxieAbortMonitor
  21962. virtual void checkForAbort() { checkAbort(); }
  21963. };
  21964. //---------------------------------------------------------------------------
  21965. class CRoxieServerSoapRowCallActivity : public CRoxieServerSoapActivityBase
  21966. {
  21967. IHThorSoapCallArg & callHelper;
  21968. public:
  21969. CRoxieServerSoapRowCallActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  21970. : CRoxieServerSoapActivityBase(_factory, _probeManager), callHelper((IHThorSoapCallArg &)basehelper)
  21971. {
  21972. }
  21973. virtual IHThorSoapCallArg * queryCallHelper()
  21974. {
  21975. return &callHelper;
  21976. }
  21977. virtual bool needsAllocator() const { return true; }
  21978. virtual const void *nextInGroup()
  21979. {
  21980. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  21981. if(eof) return NULL;
  21982. if (soaphelper == NULL)
  21983. {
  21984. soaphelper.setown(createSoapCallHelper(this, rowAllocator, authToken.str(), SCrow, pClientCert, *ctx, this));
  21985. soaphelper->start();
  21986. }
  21987. OwnedConstRoxieRow ret = soaphelper->getRow();
  21988. if (!ret)
  21989. {
  21990. eof = true;
  21991. return NULL;
  21992. }
  21993. ++processed;
  21994. return ret.getClear();
  21995. }
  21996. };
  21997. class CRoxieServerSoapRowCallActivityFactory : public CRoxieServerActivityFactory
  21998. {
  21999. public:
  22000. CRoxieServerSoapRowCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  22001. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  22002. {
  22003. }
  22004. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  22005. {
  22006. return new CRoxieServerSoapRowCallActivity(this, _probeManager);
  22007. }
  22008. };
  22009. IRoxieServerActivityFactory *createRoxieServerSoapRowCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  22010. {
  22011. return new CRoxieServerSoapRowCallActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  22012. }
  22013. //---------------------------------------------------------------------------
  22014. class CRoxieServerSoapRowActionActivity : public CRoxieServerSoapActivityBase
  22015. {
  22016. public:
  22017. CRoxieServerSoapRowActionActivity (const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  22018. : CRoxieServerSoapActivityBase(_factory, _probeManager)
  22019. {}
  22020. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  22021. {
  22022. //MORE: parentExtract not passed to start - although shouldn't be a problem.
  22023. soaphelper.setown(createSoapCallHelper(this, NULL, ctx->queryAuthToken(), SCrow, pClientCert, *ctx, this));
  22024. soaphelper->start();
  22025. soaphelper->waitUntilDone();
  22026. IException *e = soaphelper->getError();
  22027. soaphelper.clear();
  22028. if (e)
  22029. throw e;
  22030. }
  22031. virtual IRoxieInput *queryOutput(unsigned idx)
  22032. {
  22033. return NULL;
  22034. }
  22035. virtual const void *nextInGroup()
  22036. {
  22037. throwUnexpected(); // I am nobody's input
  22038. }
  22039. };
  22040. class CRoxieServerSoapRowActionActivityFactory : public CRoxieServerActivityFactory
  22041. {
  22042. bool isRoot;
  22043. public:
  22044. CRoxieServerSoapRowActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  22045. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  22046. {
  22047. }
  22048. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  22049. {
  22050. return new CRoxieServerSoapRowActionActivity(this, _probeManager);
  22051. }
  22052. virtual bool isSink() const
  22053. {
  22054. return isRoot;
  22055. }
  22056. };
  22057. IRoxieServerActivityFactory *createRoxieServerSoapRowActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  22058. {
  22059. return new CRoxieServerSoapRowActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  22060. }
  22061. //---------------------------------------------------------------------------
  22062. class CRoxieServerSoapDatasetCallActivity : public CRoxieServerSoapActivityBase
  22063. {
  22064. IHThorSoapCallArg & callHelper;
  22065. public:
  22066. CRoxieServerSoapDatasetCallActivity(const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  22067. : CRoxieServerSoapActivityBase(_factory, _probeManager), callHelper((IHThorSoapCallArg &)basehelper)
  22068. {
  22069. }
  22070. virtual IHThorSoapCallArg * queryCallHelper()
  22071. {
  22072. return &callHelper;
  22073. }
  22074. virtual const void *getNextRow()
  22075. {
  22076. CriticalBlock b(crit);
  22077. const void *nextrec = input->nextInGroup();
  22078. if (!nextrec)
  22079. {
  22080. nextrec = input->nextInGroup();
  22081. }
  22082. return nextrec;
  22083. }
  22084. virtual bool needsAllocator() const { return true; }
  22085. virtual const void *nextInGroup()
  22086. {
  22087. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  22088. if(eof) return NULL;
  22089. if (soaphelper == NULL)
  22090. {
  22091. soaphelper.setown(createSoapCallHelper(this, rowAllocator, authToken.str(), SCdataset, pClientCert, *ctx, this));
  22092. soaphelper->start();
  22093. }
  22094. OwnedConstRoxieRow ret = soaphelper->getRow();
  22095. if (!ret)
  22096. {
  22097. eof = true;
  22098. return NULL;
  22099. }
  22100. ++processed;
  22101. return ret.getClear();
  22102. }
  22103. };
  22104. class CRoxieServerSoapDatasetCallActivityFactory : public CRoxieServerActivityFactory
  22105. {
  22106. public:
  22107. CRoxieServerSoapDatasetCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  22108. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind)
  22109. {
  22110. }
  22111. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  22112. {
  22113. return new CRoxieServerSoapDatasetCallActivity(this, _probeManager);
  22114. }
  22115. };
  22116. IRoxieServerActivityFactory *createRoxieServerSoapDatasetCallActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind)
  22117. {
  22118. return new CRoxieServerSoapDatasetCallActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind);
  22119. }
  22120. //---------------------------------------------------------------------------
  22121. class CRoxieServerSoapDatasetActionActivity : public CRoxieServerSoapActivityBase
  22122. {
  22123. public:
  22124. CRoxieServerSoapDatasetActionActivity (const IRoxieServerActivityFactory *_factory, IProbeManager *_probeManager)
  22125. : CRoxieServerSoapActivityBase(_factory, _probeManager)
  22126. {}
  22127. virtual const void *getNextRow()
  22128. {
  22129. CriticalBlock b(crit);
  22130. const void *nextrec = input->nextInGroup();
  22131. if (!nextrec)
  22132. {
  22133. nextrec = input->nextInGroup();
  22134. }
  22135. if (nextrec)
  22136. processed++;
  22137. return nextrec;
  22138. }
  22139. virtual void execute(unsigned parentExtractSize, const byte * parentExtract)
  22140. {
  22141. try
  22142. {
  22143. start(parentExtractSize, parentExtract, false);
  22144. soaphelper.setown(createSoapCallHelper(this, NULL, ctx->queryAuthToken(), SCdataset, pClientCert, *ctx, this));
  22145. soaphelper->start();
  22146. soaphelper->waitUntilDone();
  22147. IException *e = soaphelper->getError();
  22148. soaphelper.clear();
  22149. if (e)
  22150. throw e;
  22151. stop(false);
  22152. }
  22153. catch (IException *E)
  22154. {
  22155. ctx->notifyAbort(E);
  22156. stop(true);
  22157. throw;
  22158. }
  22159. catch(...)
  22160. {
  22161. Owned<IException> E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught at %s:%d", __FILE__, __LINE__);
  22162. ctx->notifyAbort(E);
  22163. stop(true);
  22164. throw;
  22165. }
  22166. }
  22167. virtual IRoxieInput *queryOutput(unsigned idx)
  22168. {
  22169. return NULL;
  22170. }
  22171. virtual const void *nextInGroup()
  22172. {
  22173. throwUnexpected(); // I am nobody's input
  22174. }
  22175. };
  22176. class CRoxieServerSoapDatasetActionActivityFactory : public CRoxieServerActivityFactory
  22177. {
  22178. bool isRoot;
  22179. public:
  22180. CRoxieServerSoapDatasetActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  22181. : CRoxieServerActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind), isRoot(_isRoot)
  22182. {
  22183. }
  22184. virtual IRoxieServerActivity *createActivity(IProbeManager *_probeManager) const
  22185. {
  22186. return new CRoxieServerSoapDatasetActionActivity(this, _probeManager);
  22187. }
  22188. virtual bool isSink() const
  22189. {
  22190. return isRoot;
  22191. }
  22192. };
  22193. IRoxieServerActivityFactory *createRoxieServerSoapDatasetActionActivityFactory(unsigned _id, unsigned _subgraphId, IQueryFactory &_queryFactory, HelperFactory *_helperFactory, ThorActivityKind _kind, bool _isRoot)
  22194. {
  22195. return new CRoxieServerSoapDatasetActionActivityFactory(_id, _subgraphId, _queryFactory, _helperFactory, _kind, _isRoot);
  22196. }
  22197. //=====================================================================================================
  22198. #ifdef TRACE_RESULTS
  22199. IArrayOf<CResultRoxiePacket> badpackets;
  22200. CriticalSection bpcrit;
  22201. void notegoodpacket(CResultRoxiePacket *p)
  22202. {
  22203. CriticalBlock c(bpcrit);
  22204. p->good = true;
  22205. badpackets.append(*LINK(p));
  22206. }
  22207. void notebadpacket(CResultRoxiePacket *p)
  22208. {
  22209. CriticalBlock c(bpcrit);
  22210. p->good = false;
  22211. badpackets.append(*LINK(p));
  22212. }
  22213. void dumpresults()
  22214. {
  22215. CriticalBlock c(bpcrit);
  22216. ForEachItemIn(idx, badpackets)
  22217. {
  22218. badpackets.item(idx).dump();
  22219. }
  22220. }
  22221. #else
  22222. #define notebadpacket(a)
  22223. #define notegoodpacket(a)
  22224. inline void dumpresults(){}
  22225. #endif
  22226. //======================================================================================================================
  22227. // The Roxie server context is created per query. It is owned by a thread in the threadpool
  22228. // We don't bother linking any object that is given to us by our owner, for efficiency.
  22229. // I need to think about that though as it may impact the ability to bring channels up/down
  22230. class TempStore : public CInterface, implements IInterface
  22231. {
  22232. public:
  22233. IMPLEMENT_IINTERFACE;
  22234. ConstPointerArray p;
  22235. };
  22236. //copied to eclagent, needs to be made common
  22237. class InputProbe : public CInterface, implements IRoxieInput // base class for the edge probes used for tracing and debugging....
  22238. {
  22239. protected:
  22240. IRoxieInput *in;
  22241. unsigned sourceId;
  22242. unsigned sourceIdx;
  22243. unsigned targetId;
  22244. unsigned targetIdx;
  22245. unsigned iteration;
  22246. unsigned channel;
  22247. IOutputMetaData *inMeta;
  22248. IDebuggableContext *debugContext;
  22249. unsigned rowCount;
  22250. unsigned totalRowCount;
  22251. size32_t maxRowSize;
  22252. bool everStarted;
  22253. bool hasStarted;
  22254. bool hasStopped;
  22255. public:
  22256. InputProbe(IRoxieInput *_in, IDebuggableContext *_debugContext,
  22257. unsigned _sourceId, unsigned _sourceIdx, unsigned _targetId, unsigned _targetIdx, unsigned _iteration, unsigned _channel)
  22258. : in(_in), debugContext(_debugContext),
  22259. sourceId(_sourceId), sourceIdx(_sourceIdx), targetId(_targetId), targetIdx(_targetIdx), iteration(_iteration), channel(_channel)
  22260. {
  22261. hasStarted = false;
  22262. everStarted = false;
  22263. hasStopped = false;
  22264. rowCount = 0;
  22265. totalRowCount = 0;
  22266. maxRowSize = 0;
  22267. inMeta = NULL;
  22268. }
  22269. virtual IInputSteppingMeta * querySteppingMeta()
  22270. {
  22271. return in->querySteppingMeta();
  22272. }
  22273. virtual bool gatherConjunctions(ISteppedConjunctionCollector & collector)
  22274. {
  22275. return in->gatherConjunctions(collector);
  22276. }
  22277. virtual void resetEOF()
  22278. {
  22279. in->resetEOF();
  22280. }
  22281. virtual unsigned numConcreteOutputs() const
  22282. {
  22283. return in->numConcreteOutputs();
  22284. }
  22285. virtual IRoxieInput * queryConcreteInput(unsigned idx)
  22286. {
  22287. // MORE - not sure what is right here!
  22288. if (in->queryConcreteInput(idx) == in)
  22289. {
  22290. assertex(idx==0);
  22291. return this;
  22292. }
  22293. else
  22294. return in->queryConcreteInput(idx);
  22295. }
  22296. virtual IRoxieServerActivity *queryActivity()
  22297. {
  22298. return in->queryActivity();
  22299. }
  22300. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  22301. {
  22302. return in->queryIndexReadActivity();
  22303. }
  22304. virtual IOutputMetaData * queryOutputMeta() const
  22305. {
  22306. return in->queryOutputMeta();
  22307. }
  22308. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  22309. {
  22310. // NOTE: totalRowCount/maxRowSize not reset, as we want them cumulative when working in a child query.
  22311. rowCount = 0;
  22312. hasStarted = true;
  22313. hasStopped = false;
  22314. everStarted = true;
  22315. in->start(parentExtractSize, parentExtract, paused);
  22316. inMeta = in->queryOutputMeta();
  22317. assertex(inMeta);
  22318. }
  22319. virtual void stop(bool aborting)
  22320. {
  22321. hasStopped = true;
  22322. in->stop(aborting);
  22323. }
  22324. virtual void reset()
  22325. {
  22326. hasStarted = false;
  22327. in->reset();
  22328. }
  22329. virtual void checkAbort()
  22330. {
  22331. in->checkAbort();
  22332. }
  22333. virtual unsigned queryId() const
  22334. {
  22335. return in->queryId();
  22336. }
  22337. virtual unsigned __int64 queryTotalCycles() const
  22338. {
  22339. return in->queryTotalCycles();
  22340. }
  22341. virtual unsigned __int64 queryLocalCycles() const
  22342. {
  22343. return in->queryLocalCycles();
  22344. }
  22345. virtual IRoxieInput *queryInput(unsigned idx) const
  22346. {
  22347. if (!idx)
  22348. return in;
  22349. else
  22350. return NULL;
  22351. }
  22352. virtual const void *nextInGroup()
  22353. {
  22354. const void *ret = in->nextInGroup();
  22355. if (ret)
  22356. {
  22357. size32_t size = inMeta->getRecordSize(ret);
  22358. if (size > maxRowSize)
  22359. maxRowSize = size;
  22360. rowCount++;
  22361. totalRowCount++;
  22362. }
  22363. return ret;
  22364. }
  22365. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  22366. {
  22367. const void *ret = in->nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  22368. if (ret && wasCompleteMatch) // GH is this test right?
  22369. {
  22370. size32_t size = inMeta->getRecordSize(ret);
  22371. if (size > maxRowSize)
  22372. maxRowSize = size;
  22373. rowCount++;
  22374. totalRowCount++;
  22375. }
  22376. return ret;
  22377. }
  22378. };
  22379. class TraceProbe : public InputProbe
  22380. {
  22381. public:
  22382. IMPLEMENT_IINTERFACE;
  22383. TraceProbe(IRoxieInput *_in, unsigned _sourceId, unsigned _targetId, unsigned _sourceIdx, unsigned _targetIdx, unsigned _iteration, unsigned _channel)
  22384. : InputProbe(_in, NULL, _sourceId, _sourceIdx, _targetId, _targetIdx, _iteration, _channel)
  22385. {
  22386. }
  22387. bool matches(IPropertyTree &edge, bool forNode)
  22388. {
  22389. if (forNode)
  22390. {
  22391. unsigned id = edge.getPropInt("@id", 0);
  22392. if (id && (id == sourceId || id == targetId))
  22393. {
  22394. return true;
  22395. }
  22396. }
  22397. else
  22398. {
  22399. unsigned id = edge.getPropInt("@source", 0);
  22400. if (id && id == sourceId)
  22401. {
  22402. id = edge.getPropInt("@target", 0);
  22403. if (id && id == targetId)
  22404. {
  22405. unsigned idx = edge.getPropInt("att[@name=\"_sourceIndex\"]/@value", 0);
  22406. if (idx == sourceIdx)
  22407. return true;
  22408. }
  22409. }
  22410. id = edge.getPropInt("att[@name=\"_sourceActivity\"]/@value");
  22411. if (id && id == sourceId)
  22412. {
  22413. id = edge.getPropInt("att[@name=\"_targetActivity\"]/@value");
  22414. if (id && id == targetId)
  22415. {
  22416. unsigned idx = edge.getPropInt("att[@name=\"_sourceIndex\"]/@value", 0);
  22417. if (idx == sourceIdx)
  22418. return true;
  22419. }
  22420. }
  22421. }
  22422. return false;
  22423. }
  22424. const void * _next(const void *inputRow)
  22425. {
  22426. const byte *ret = (const byte *) inputRow;
  22427. if (ret && probeAllRows)
  22428. {
  22429. CommonXmlWriter xmlwrite(XWFnoindent|XWFtrim|XWFopt);
  22430. if (inMeta && inMeta->hasXML())
  22431. inMeta->toXML(ret, xmlwrite);
  22432. DBGLOG("ROW: [%d->%d] {%p} %s", sourceId, targetId, ret, xmlwrite.str());
  22433. }
  22434. return ret;
  22435. }
  22436. virtual const void * nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  22437. {
  22438. // MORE - should probably only note them when wasCompleteMatch is true?
  22439. return _next(InputProbe::nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra));
  22440. }
  22441. virtual const void *nextInGroup()
  22442. {
  22443. return _next(InputProbe::nextInGroup());
  22444. }
  22445. void getNodeProgressInfo(IPropertyTree &node)
  22446. {
  22447. // node is the input (or possibly output) of this probe edge
  22448. unsigned started = everStarted;
  22449. putStatsValue(&node, "_roxieStarted", "sum", started);
  22450. unsigned id = node.getPropInt("@id", 0);
  22451. bool isOutput = (id != 0) && (id != sourceId);
  22452. unsigned totalTime = (unsigned) (cycle_to_nanosec(in->queryTotalCycles())/1000);
  22453. if (isOutput)
  22454. totalTime += 10; // Fudge factor - I don't really know the times but this makes the graph more useable than not supplying a totalTime value
  22455. if (totalTime)
  22456. putStatsValue(&node, "totalTime", "sum", totalTime);
  22457. unsigned localTime = isOutput ? 10 : (unsigned) (cycle_to_nanosec(in->queryLocalCycles())/1000); // Fudge factor - I don't really know the times but this makes the graph more useable than not supplying a localTime value
  22458. if (localTime)
  22459. putStatsValue(&node, "localTime", "sum", localTime);
  22460. }
  22461. void getEdgeProgressInfo(IPropertyTree &edge)
  22462. {
  22463. putStatsValue(&edge, "_roxieStarted", "sum", hasStarted);
  22464. if (hasStarted)
  22465. {
  22466. putStatsValue(&edge, "count", "sum", totalRowCount);
  22467. putStatsValue(&edge, "maxrowsize", "max", maxRowSize);
  22468. }
  22469. }
  22470. };
  22471. class CGraphResults : public CInterface, implements IRoxieGraphResults
  22472. {
  22473. IArrayOf<IGraphResult> results;
  22474. CriticalSection cs;
  22475. IGraphResult & select(unsigned idx)
  22476. {
  22477. CriticalBlock procedure(cs);
  22478. if (idx >= results.ordinality())
  22479. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Error reading graph result %d before it is calculated", idx);
  22480. return results.item(idx);
  22481. }
  22482. public:
  22483. IMPLEMENT_IINTERFACE
  22484. void clear()
  22485. {
  22486. CriticalBlock procedure(cs);
  22487. results.kill();
  22488. }
  22489. IRoxieInput * createIterator(unsigned id)
  22490. {
  22491. return select(id).createIterator();
  22492. }
  22493. virtual void getResult(unsigned & lenResult, void * & result, unsigned id)
  22494. {
  22495. select(id).getResult(lenResult, result);
  22496. }
  22497. virtual void getLinkedResult(unsigned & count, byte * * & ret, unsigned id)
  22498. {
  22499. select(id).getLinkedResult(count, ret);
  22500. }
  22501. void setResult(unsigned id, IGraphResult * result)
  22502. {
  22503. CriticalBlock procedure(cs);
  22504. if (results.ordinality() <= id)
  22505. {
  22506. while (results.ordinality() < id)
  22507. results.append(*new CGraphResult);
  22508. results.append(*LINK(result));
  22509. }
  22510. else
  22511. results.replace(*LINK(result), id);
  22512. }
  22513. void appendResult(IGraphResult * result)
  22514. {
  22515. CriticalBlock procedure(cs);
  22516. results.append(*LINK(result));
  22517. }
  22518. };
  22519. class CProbeManager : public CInterface, implements IProbeManager
  22520. {
  22521. IArrayOf<TraceProbe> probes; // May want to replace with hash table at some point....
  22522. public:
  22523. IMPLEMENT_IINTERFACE;
  22524. IInputBase *createProbe(IInputBase *in, IActivityBase *inAct, IActivityBase *outAct, unsigned sourceIdx, unsigned targetIdx, unsigned iteration)
  22525. {
  22526. unsigned idIn = inAct->queryId();
  22527. unsigned idOut = outAct->queryId();
  22528. TraceProbe *probe = new TraceProbe(static_cast<IRoxieInput*>(in), idIn, idOut, sourceIdx, targetIdx, iteration, 0);
  22529. probes.append(*probe);
  22530. return probe;
  22531. }
  22532. TraceProbe *findProbe(IPropertyTree &edge, bool forNode, unsigned &startat)
  22533. {
  22534. // MORE - this is n-squared on number of edges in the graph. Could get painful - recode if needed
  22535. // However I think that the "startat" cache probably prevents the pain
  22536. unsigned probeCount = probes.ordinality();
  22537. unsigned search = probeCount;
  22538. unsigned idx = startat;
  22539. while (search--)
  22540. {
  22541. idx++;
  22542. if (idx>=probeCount) idx = 0;
  22543. TraceProbe &p = probes.item(idx);
  22544. if (p.matches(edge, forNode))
  22545. {
  22546. startat = idx;
  22547. return &p;
  22548. }
  22549. }
  22550. return NULL;
  22551. }
  22552. virtual void noteSink(IActivityBase *)
  22553. {
  22554. }
  22555. virtual IDebugGraphManager *queryDebugManager()
  22556. {
  22557. return NULL;
  22558. }
  22559. virtual void noteDependency(IActivityBase *sourceActivity, unsigned sourceIndex, unsigned controlId, const char *edgeId, IActivityBase *targetActivity)
  22560. {
  22561. }
  22562. virtual IProbeManager *startChildGraph(unsigned childGraphId, IActivityBase *parent)
  22563. {
  22564. return LINK(this);
  22565. }
  22566. virtual void endChildGraph(IProbeManager *child, IActivityBase *parent)
  22567. {
  22568. }
  22569. virtual void deleteGraph(IArrayOf<IActivityBase> *activities, IArrayOf<IInputBase> *goers)
  22570. {
  22571. if (goers)
  22572. {
  22573. ForEachItemIn(probeIdx, *goers)
  22574. {
  22575. TraceProbe &probe = (TraceProbe &) goers->item(probeIdx);
  22576. probes.zap(probe);
  22577. }
  22578. }
  22579. }
  22580. virtual void setNodeProperty(IActivityBase *node, const char *propName, const char *propVvalue)
  22581. {
  22582. // MORE - we could note these in probe mode too...
  22583. }
  22584. virtual void setNodePropertyInt(IActivityBase *node, const char *propName, unsigned __int64 propVvalue)
  22585. {
  22586. // MORE - we could note these in probe mode too...
  22587. }
  22588. virtual void getProbeResponse(IPropertyTree *query)
  22589. {
  22590. Owned<IPropertyTreeIterator> graphs = query->getElements("Graph");
  22591. ForEach(*graphs)
  22592. {
  22593. IPropertyTree &graph = graphs->query();
  22594. Owned<IPropertyTreeIterator> subgraphs = graph.getElements("xgmml/graph");
  22595. ForEach(*subgraphs)
  22596. {
  22597. IPropertyTree &subgraph = subgraphs->query();
  22598. Owned<IPropertyTreeIterator> nodes = subgraph.getElements(".//node");
  22599. unsigned startat = 0;
  22600. ForEach(*nodes)
  22601. {
  22602. IPropertyTree &node = nodes->query();
  22603. TraceProbe *currentProbe = findProbe(node, true, startat);
  22604. if (currentProbe)
  22605. {
  22606. currentProbe->getNodeProgressInfo(node);
  22607. }
  22608. }
  22609. Owned<IPropertyTreeIterator> edges = subgraph.getElements(".//edge");
  22610. startat = 0;
  22611. ForEach(*edges)
  22612. {
  22613. IPropertyTree &edge = edges->query();
  22614. if (edge.getPropInt("att[@name='_dependsOn']/@value", 0) != 0)
  22615. {
  22616. const char *targetNode = edge.queryProp("att[@name='_targetActivity']/@value");
  22617. if (targetNode)
  22618. {
  22619. StringBuffer xpath;
  22620. IPropertyTree *target = query->queryPropTree(xpath.append(".//node[@id='").append(targetNode).append("']"));
  22621. if (target)
  22622. {
  22623. unsigned started = target->getPropInt("att[@name='_roxieStarted']/@value", 0);
  22624. IPropertyTree *att = edge.queryPropTree("att[@name=\"_roxieStarted\"]");
  22625. if (!att)
  22626. {
  22627. att = edge.addPropTree("att", createPTree());
  22628. att->setProp("@name", "_roxieStarted");
  22629. }
  22630. else
  22631. started += att->getPropInt("@value");
  22632. att->setPropInt("@value", started);
  22633. }
  22634. }
  22635. }
  22636. else
  22637. {
  22638. TraceProbe *currentProbe = findProbe(edge, false, startat);
  22639. if (currentProbe)
  22640. {
  22641. currentProbe->getEdgeProgressInfo(edge);
  22642. }
  22643. else
  22644. {
  22645. const char *targetNode = edge.queryProp("att[@name='_targetActivity']/@value");
  22646. if (targetNode)
  22647. {
  22648. StringBuffer xpath;
  22649. IPropertyTree *target = query->queryPropTree(xpath.append(".//node[@id='").append(targetNode).append("']"));
  22650. if (target)
  22651. {
  22652. unsigned started = target->getPropInt("att[@name='_roxieStarted']/@value", 0);
  22653. IPropertyTree *att = edge.queryPropTree("att[@name=\"_roxieStarted\"]");
  22654. if (!att)
  22655. {
  22656. att = edge.addPropTree("att", createPTree());
  22657. att->setProp("@name", "_roxieStarted");
  22658. }
  22659. else
  22660. started += att->getPropInt("@value");
  22661. att->setPropInt("@value", started);
  22662. }
  22663. }
  22664. }
  22665. }
  22666. }
  22667. }
  22668. }
  22669. }
  22670. };
  22671. typedef const IInterface *CIptr;
  22672. typedef MapBetween<unsigned, unsigned, CIptr, CIptr> ProxyMap;
  22673. static ProxyMap *registeredProxies;
  22674. static CriticalSection proxyLock;
  22675. static memsize_t nextProxyId = 1;
  22676. static memsize_t registerProxyId(const IInterface * object)
  22677. {
  22678. CriticalBlock b(proxyLock);
  22679. if (!registeredProxies)
  22680. registeredProxies = new ProxyMap;
  22681. registeredProxies->setValue(nextProxyId, object);
  22682. return nextProxyId++;
  22683. }
  22684. static void unregisterProxyId(memsize_t id)
  22685. {
  22686. // CriticalBlock b(proxyLock); done by caller
  22687. if (registeredProxies)
  22688. {
  22689. registeredProxies->remove(id);
  22690. if (!registeredProxies->count())
  22691. {
  22692. delete registeredProxies;
  22693. registeredProxies = NULL;
  22694. }
  22695. }
  22696. }
  22697. static const IInterface *getProxy(memsize_t id)
  22698. {
  22699. CriticalBlock b(proxyLock);
  22700. if (registeredProxies)
  22701. {
  22702. CIptr *proxy = registeredProxies->getValue(id);
  22703. if (proxy)
  22704. return LINK(*proxy);
  22705. }
  22706. return NULL;
  22707. }
  22708. //copied to eclagent, needs to be made common
  22709. class DebugProbe : public InputProbe, implements IActivityDebugContext
  22710. {
  22711. Owned<IGlobalEdgeRecord> edgeRecord;
  22712. ICopyArrayOf<IBreakpointInfo> breakpoints;
  22713. HistoryRow *history;
  22714. unsigned lastSequence;
  22715. unsigned historySize;
  22716. unsigned historyCapacity;
  22717. unsigned nextHistorySlot;
  22718. unsigned childGraphId;
  22719. mutable memsize_t proxyId; // MORE - do we need a critsec to protect too?
  22720. DebugActivityRecord *sourceAct;
  22721. DebugActivityRecord *targetAct;
  22722. StringAttr edgeId;
  22723. bool forceEOF;
  22724. bool EOGseen;
  22725. bool EOGsent;
  22726. static void putAttributeUInt(IXmlWriter *output, const char *name, unsigned value)
  22727. {
  22728. output->outputBeginNested("att", false);
  22729. output->outputCString(name, "@name");
  22730. output->outputInt(value, "@value");
  22731. output->outputEndNested("att");
  22732. }
  22733. void rowToXML(IXmlWriter *output, const void *row, unsigned sequence, unsigned rowCount, bool skipped, bool limited, bool eof, bool eog) const
  22734. {
  22735. output->outputBeginNested("Row", true);
  22736. output->outputInt(sequence, "@seq");
  22737. if (skipped)
  22738. output->outputBool(true, "@skip");
  22739. if (limited)
  22740. output->outputBool(true, "@limit");
  22741. if (eof)
  22742. output->outputBool(true, "@eof");
  22743. if (eog)
  22744. output->outputBool(true, "@eog");
  22745. if (row)
  22746. {
  22747. output->outputInt(rowCount, "@count");
  22748. IOutputMetaData *meta = queryOutputMeta();
  22749. output->outputInt(meta->getRecordSize(row), "@size");
  22750. meta->toXML((const byte *) row, *output);
  22751. }
  22752. output->outputEndNested("Row");
  22753. }
  22754. public:
  22755. DebugProbe(IInputBase *_in, unsigned _sourceId, unsigned _sourceIdx, DebugActivityRecord *_sourceAct, unsigned _targetId, unsigned _targetIdx, DebugActivityRecord *_targetAct, unsigned _iteration, unsigned _channel, IDebuggableContext *_debugContext)
  22756. : InputProbe(static_cast<IRoxieInput*>(_in), _debugContext, _sourceId, _sourceIdx, _targetId, _targetIdx, _iteration, _channel),
  22757. sourceAct(_sourceAct), targetAct(_targetAct)
  22758. {
  22759. historyCapacity = debugContext->getDefaultHistoryCapacity();
  22760. nextHistorySlot = 0;
  22761. if (historyCapacity)
  22762. history = new HistoryRow [historyCapacity];
  22763. else
  22764. history = NULL;
  22765. historySize = 0;
  22766. lastSequence = 0;
  22767. StringBuffer idText;
  22768. idText.appendf("%d_%d", sourceId, sourceIdx);
  22769. edgeRecord.setown(debugContext->getEdgeRecord(idText));
  22770. if (iteration || channel)
  22771. idText.appendf(".%d", iteration);
  22772. if (channel)
  22773. idText.appendf("#%d", channel);
  22774. edgeId.set(idText);
  22775. debugContext->checkDelayedBreakpoints(this);
  22776. forceEOF = false;
  22777. EOGseen = false;
  22778. EOGsent = false;
  22779. proxyId = 0;
  22780. }
  22781. ~DebugProbe()
  22782. {
  22783. if (history)
  22784. {
  22785. for (unsigned idx = 0; idx < historyCapacity; idx++)
  22786. ReleaseRoxieRow(history[idx].row);
  22787. delete [] history;
  22788. }
  22789. ForEachItemIn(bpIdx, breakpoints)
  22790. {
  22791. breakpoints.item(bpIdx).removeEdge(*this);
  22792. }
  22793. }
  22794. virtual void Link() const
  22795. {
  22796. CInterface::Link();
  22797. }
  22798. virtual bool Release() const
  22799. {
  22800. CriticalBlock b(proxyLock);
  22801. if (!IsShared())
  22802. {
  22803. if (proxyId)
  22804. unregisterProxyId(proxyId);
  22805. }
  22806. return CInterface::Release();
  22807. }
  22808. virtual memsize_t queryProxyId() const
  22809. {
  22810. if (!proxyId)
  22811. proxyId = registerProxyId((const IActivityDebugContext *) this);
  22812. return proxyId;
  22813. }
  22814. virtual unsigned queryChildGraphId() const
  22815. {
  22816. return childGraphId;
  22817. }
  22818. virtual void resetEOF()
  22819. {
  22820. forceEOF = false;
  22821. EOGseen = false;
  22822. EOGsent = false;
  22823. InputProbe::resetEOF();
  22824. }
  22825. #if 0
  22826. virtual unsigned queryId() const
  22827. {
  22828. return sourceId;
  22829. }
  22830. #endif
  22831. virtual const char *queryEdgeId() const
  22832. {
  22833. return edgeId.get();
  22834. }
  22835. virtual const char *querySourceId() const
  22836. {
  22837. UNIMPLEMENTED;
  22838. }
  22839. virtual void printEdge(IXmlWriter *output, unsigned startRow, unsigned numRows) const
  22840. {
  22841. output->outputBeginNested("edge", true);
  22842. output->outputString(edgeId.length(), edgeId.get(), "@edgeId");
  22843. if (startRow < historySize)
  22844. {
  22845. if (numRows > historySize - startRow)
  22846. numRows = historySize - startRow;
  22847. while (numRows)
  22848. {
  22849. IHistoryRow *rowData = queryHistoryRow(startRow+numRows-1);
  22850. assertex(rowData);
  22851. rowToXML(output, rowData->queryRow(), rowData->querySequence(), rowData->queryRowCount(), rowData->wasSkipped(), rowData->wasLimited(), rowData->wasEof(), rowData->wasEog());
  22852. numRows--;
  22853. }
  22854. }
  22855. output->outputEndNested("edge");
  22856. }
  22857. virtual void searchHistories(IXmlWriter *output, IRowMatcher *matcher, bool fullRows)
  22858. {
  22859. IOutputMetaData *meta = queryOutputMeta();
  22860. bool anyMatchedYet = false;
  22861. if (matcher->canMatchAny(meta))
  22862. {
  22863. for (unsigned i = 0; i < historySize; i++)
  22864. {
  22865. IHistoryRow *rowData = queryHistoryRow(i);
  22866. assertex(rowData);
  22867. const void *row = rowData->queryRow();
  22868. if (row)
  22869. {
  22870. matcher->reset();
  22871. meta->toXML((const byte *) rowData->queryRow(), *matcher);
  22872. if (matcher->matched())
  22873. {
  22874. if (!anyMatchedYet)
  22875. {
  22876. output->outputBeginNested("edge", true);
  22877. output->outputString(edgeId.length(), edgeId.get(), "@edgeId");
  22878. anyMatchedYet = true;
  22879. }
  22880. if (fullRows)
  22881. rowToXML(output, rowData->queryRow(), rowData->querySequence(), rowData->queryRowCount(), rowData->wasSkipped(), rowData->wasLimited(), rowData->wasEof(), rowData->wasEog());
  22882. else
  22883. {
  22884. output->outputBeginNested("Row", true);
  22885. output->outputInt(rowData->querySequence(), "@sequence");
  22886. output->outputInt(rowData->queryRowCount(), "@count");
  22887. output->outputEndNested("Row");
  22888. }
  22889. }
  22890. }
  22891. }
  22892. if (anyMatchedYet)
  22893. output->outputEndNested("edge");
  22894. }
  22895. }
  22896. virtual void getXGMML(IXmlWriter *output) const
  22897. {
  22898. output->outputBeginNested("edge", false);
  22899. sourceAct->outputId(output, "@source");
  22900. targetAct->outputId(output, "@target");
  22901. output->outputString(edgeId.length(), edgeId.get(), "@id");
  22902. if (sourceIdx)
  22903. putAttributeUInt(output, "_sourceIndex", sourceIdx);
  22904. putAttributeUInt(output, "count", rowCount); //changed from totalRowCount
  22905. putAttributeUInt(output, "maxRowSize", maxRowSize);
  22906. putAttributeUInt(output, "_roxieStarted", everStarted);
  22907. putAttributeUInt(output, "_started", hasStarted);
  22908. putAttributeUInt(output, "_stopped", hasStopped);
  22909. putAttributeUInt(output, "_eofSeen", forceEOF);
  22910. if (breakpoints.ordinality())
  22911. putAttributeUInt(output, "_breakpoints", breakpoints.ordinality());
  22912. output->outputEndNested("edge");
  22913. }
  22914. virtual IOutputMetaData *queryOutputMeta() const
  22915. {
  22916. return InputProbe::queryOutputMeta();
  22917. }
  22918. virtual IActivityDebugContext *queryInputActivity() const
  22919. {
  22920. IRoxieInput *x = in;
  22921. while (x && QUERYINTERFACE(x->queryConcreteInput(0), IActivityDebugContext)==NULL)
  22922. x = x->queryConcreteInput(0)->queryInput(0);
  22923. return x ? QUERYINTERFACE(x->queryConcreteInput(0), IActivityDebugContext) : NULL;
  22924. }
  22925. // NOTE - these functions are threadsafe because only called when query locked by debugger.
  22926. // Even though this thread may not yet be blocked on the debugger's critsec, because all manipulation (including setting history rows) is from
  22927. // within debugger it is ok.
  22928. virtual unsigned queryHistorySize() const
  22929. {
  22930. return historySize;
  22931. }
  22932. virtual IHistoryRow *queryHistoryRow(unsigned idx) const
  22933. {
  22934. assertex(idx < historySize);
  22935. int slotNo = nextHistorySlot - idx - 1;
  22936. if (slotNo < 0)
  22937. slotNo += historyCapacity;
  22938. return &history[slotNo];
  22939. }
  22940. virtual unsigned queryHistoryCapacity() const
  22941. {
  22942. return historyCapacity;
  22943. }
  22944. virtual unsigned queryLastSequence() const
  22945. {
  22946. return lastSequence;
  22947. }
  22948. virtual IBreakpointInfo *debuggerCallback(unsigned sequence, const void *row)
  22949. {
  22950. // First put the row into the history buffer...
  22951. lastSequence = sequence;
  22952. if (historyCapacity)
  22953. {
  22954. ReleaseClearRoxieRow(history[nextHistorySlot].row);
  22955. if (row) LinkRoxieRow(row);
  22956. history[nextHistorySlot].sequence = sequence; // MORE - timing might be interesting too, but would need to exclude debug wait time somehow...
  22957. history[nextHistorySlot].row = row;
  22958. history[nextHistorySlot].rowCount = rowCount;
  22959. if (!row)
  22960. {
  22961. if (forceEOF)
  22962. history[nextHistorySlot].setEof();
  22963. else
  22964. history[nextHistorySlot].setEog();
  22965. }
  22966. if (historySize < historyCapacity)
  22967. historySize++;
  22968. nextHistorySlot++;
  22969. if (nextHistorySlot==historyCapacity)
  22970. nextHistorySlot = 0;
  22971. }
  22972. // Now check breakpoints...
  22973. ForEachItemIn(idx, breakpoints)
  22974. {
  22975. IBreakpointInfo &bp = breakpoints.item(idx);
  22976. if (bp.matches(row, forceEOF, rowCount, queryOutputMeta())) // should optimize to only call queryOutputMeta once - but not that common to have multiple breakpoints
  22977. return &bp;
  22978. }
  22979. return NULL;
  22980. }
  22981. virtual void setHistoryCapacity(unsigned newCapacity)
  22982. {
  22983. if (newCapacity != historyCapacity)
  22984. {
  22985. HistoryRow *newHistory;
  22986. if (newCapacity)
  22987. {
  22988. unsigned copyCount = historySize;
  22989. if (copyCount > newCapacity)
  22990. copyCount = newCapacity;
  22991. newHistory = new HistoryRow [newCapacity];
  22992. unsigned slot = 0;
  22993. while (copyCount--)
  22994. {
  22995. IHistoryRow *oldrow = queryHistoryRow(copyCount);
  22996. newHistory[slot].sequence = oldrow->querySequence();
  22997. newHistory[slot].row = oldrow->queryRow();
  22998. newHistory[slot].rowCount = oldrow->queryRowCount();
  22999. if (newHistory[slot].row)
  23000. LinkRoxieRow(newHistory[slot].row);
  23001. slot++;
  23002. }
  23003. historySize = slot;
  23004. nextHistorySlot = slot;
  23005. if (nextHistorySlot==historyCapacity)
  23006. nextHistorySlot = 0;
  23007. }
  23008. else
  23009. {
  23010. newHistory = NULL;
  23011. historySize = 0;
  23012. nextHistorySlot = 0;
  23013. }
  23014. for (unsigned idx = 0; idx < historyCapacity; idx++)
  23015. ReleaseRoxieRow(history[idx].row);
  23016. delete [] history;
  23017. history = newHistory;
  23018. historyCapacity = newCapacity;
  23019. }
  23020. }
  23021. virtual void clearHistory()
  23022. {
  23023. for (unsigned idx = 0; idx < historyCapacity; idx++)
  23024. ReleaseClearRoxieRow(history[idx].row);
  23025. historySize = 0;
  23026. nextHistorySlot = 0;
  23027. }
  23028. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  23029. {
  23030. forceEOF = false;
  23031. EOGseen = false;
  23032. EOGsent = false;
  23033. if (!hasStarted)
  23034. {
  23035. lastSequence = debugContext->querySequence();
  23036. edgeRecord->incrementCount(0, lastSequence);
  23037. }
  23038. InputProbe::start(parentExtractSize, parentExtract, paused);
  23039. }
  23040. virtual void reset()
  23041. {
  23042. InputProbe::reset();
  23043. sourceAct->updateTimes(debugContext->querySequence());
  23044. targetAct->updateTimes(debugContext->querySequence());
  23045. }
  23046. virtual void stop(bool aborting)
  23047. {
  23048. InputProbe::stop(aborting);
  23049. sourceAct->updateTimes(debugContext->querySequence());
  23050. targetAct->updateTimes(debugContext->querySequence());
  23051. }
  23052. virtual const void *nextInGroup()
  23053. {
  23054. // Code is a little complex to avoid interpreting a skip on all rows in a group as EOF
  23055. try
  23056. {
  23057. if (forceEOF)
  23058. return NULL;
  23059. loop
  23060. {
  23061. const void *ret = InputProbe::nextInGroup();
  23062. if (!ret)
  23063. {
  23064. if (EOGseen)
  23065. forceEOF = true;
  23066. else
  23067. EOGseen = true;
  23068. }
  23069. else
  23070. EOGseen = false;
  23071. if (ret)
  23072. edgeRecord->incrementCount(1, debugContext->querySequence());
  23073. BreakpointActionMode action = debugContext->checkBreakpoint(DebugStateEdge, this, ret);
  23074. if (action == BreakpointActionSkip && !forceEOF)
  23075. {
  23076. if (historyCapacity)
  23077. queryHistoryRow(0)->setSkipped();
  23078. if (ret)
  23079. {
  23080. edgeRecord->incrementCount(-1, debugContext->querySequence());
  23081. ReleaseClearRoxieRow(ret);
  23082. rowCount--;
  23083. }
  23084. continue;
  23085. }
  23086. else if (action == BreakpointActionLimit)
  23087. {
  23088. // This return value implies that we should not return the current row NOR should we return any more...
  23089. forceEOF = true;
  23090. if (ret)
  23091. edgeRecord->incrementCount(-1, debugContext->querySequence());
  23092. ReleaseClearRoxieRow(ret);
  23093. if (historyCapacity)
  23094. queryHistoryRow(0)->setLimited();
  23095. rowCount--;
  23096. }
  23097. if (forceEOF || ret || !EOGsent)
  23098. {
  23099. EOGsent = (ret == NULL);
  23100. sourceAct->updateTimes(debugContext->querySequence());
  23101. targetAct->updateTimes(debugContext->querySequence());
  23102. return ret;
  23103. }
  23104. }
  23105. }
  23106. catch (IException *E)
  23107. {
  23108. debugContext->checkBreakpoint(DebugStateException, this, E);
  23109. throw;
  23110. }
  23111. }
  23112. virtual const void *nextSteppedGE(const void * seek, unsigned numFields, bool &wasCompleteMatch, const SmartStepExtra & stepExtra)
  23113. {
  23114. // MORE - not sure that skip is safe here? Should the incomplete matches even be returned?
  23115. // Code is a little complex to avoid interpreting a skip on all rows in a group as EOF
  23116. // MORE - should probably only note them when wasCompleteMatch is true?
  23117. try
  23118. {
  23119. if (forceEOF)
  23120. return NULL;
  23121. loop
  23122. {
  23123. const void *ret = InputProbe::nextSteppedGE(seek, numFields, wasCompleteMatch, stepExtra);
  23124. if (!ret)
  23125. {
  23126. if (EOGseen)
  23127. forceEOF = true;
  23128. else
  23129. EOGseen = true;
  23130. }
  23131. else
  23132. EOGseen = false;
  23133. if (ret)
  23134. edgeRecord->incrementCount(1, debugContext->querySequence());
  23135. BreakpointActionMode action = debugContext->checkBreakpoint(DebugStateEdge, this, ret);
  23136. if (action == BreakpointActionSkip && !forceEOF)
  23137. {
  23138. if (ret)
  23139. edgeRecord->incrementCount(-1, debugContext->querySequence());
  23140. ReleaseClearRoxieRow(ret);
  23141. if (historyCapacity)
  23142. queryHistoryRow(0)->setSkipped();
  23143. rowCount--;
  23144. continue;
  23145. }
  23146. else if (action == BreakpointActionLimit)
  23147. {
  23148. // This return value implies that we should not return the current row NOR should we return any more...
  23149. forceEOF = true;
  23150. if (ret)
  23151. edgeRecord->incrementCount(-1, debugContext->querySequence());
  23152. ReleaseClearRoxieRow(ret);
  23153. if (historyCapacity)
  23154. queryHistoryRow(0)->setLimited();
  23155. rowCount--;
  23156. }
  23157. if (forceEOF || ret || !EOGsent)
  23158. {
  23159. EOGsent = (ret == NULL);
  23160. sourceAct->updateTimes(debugContext->querySequence());
  23161. targetAct->updateTimes(debugContext->querySequence());
  23162. return ret;
  23163. }
  23164. }
  23165. }
  23166. catch (IException *E)
  23167. {
  23168. debugContext->checkBreakpoint(DebugStateException, this, E);
  23169. throw;
  23170. }
  23171. }
  23172. virtual void setBreakpoint(IBreakpointInfo &bp)
  23173. {
  23174. if (bp.canMatchAny(queryOutputMeta()))
  23175. {
  23176. breakpoints.append(bp);
  23177. bp.noteEdge(*this);
  23178. }
  23179. }
  23180. virtual void removeBreakpoint(IBreakpointInfo &bp)
  23181. {
  23182. breakpoints.zap(bp);
  23183. bp.removeEdge(*this);
  23184. }
  23185. };
  23186. extern IProbeManager *createProbeManager()
  23187. {
  23188. return new CProbeManager;
  23189. }
  23190. IDebugGraphManager *createProxyDebugGraphManager(unsigned graphId, unsigned channel, memsize_t remoteGraphId);
  23191. class CRoxieDebugGraphManager : extends CBaseDebugGraphManager
  23192. {
  23193. unsigned subId;
  23194. public:
  23195. CRoxieDebugGraphManager(IDebuggableContext *_debugContext, unsigned _id, const char *_graphName, unsigned _subId)
  23196. : CBaseDebugGraphManager(_debugContext, _id, _graphName), subId(_subId)
  23197. {
  23198. }
  23199. bool Release() const
  23200. {
  23201. CriticalBlock b(proxyLock);
  23202. if (!IsShared())
  23203. {
  23204. if (!id)
  23205. debugContext->releaseManager(const_cast<CRoxieDebugGraphManager*> (this));
  23206. if (proxyId)
  23207. unregisterProxyId(proxyId);
  23208. }
  23209. return CInterface::Release();
  23210. }
  23211. virtual IInputBase *createProbe(IInputBase *in, IActivityBase *sourceAct, IActivityBase *targetAct, unsigned sourceIdx, unsigned targetIdx, unsigned iteration)
  23212. {
  23213. CriticalBlock b(crit);
  23214. if (!iteration)
  23215. iteration = subId;
  23216. unsigned channel = debugContext->queryChannel();
  23217. unsigned sourceId = sourceAct->queryId();
  23218. unsigned targetId = targetAct->queryId();
  23219. DebugActivityRecord *sourceActRecord = noteActivity(sourceAct, iteration, channel, debugContext->querySequence());
  23220. DebugActivityRecord *targetActRecord = noteActivity(targetAct, iteration, channel, debugContext->querySequence());
  23221. DebugProbe *probe = new DebugProbe(in, sourceId, sourceIdx, sourceActRecord, targetId, targetIdx, targetActRecord, iteration, channel, debugContext);
  23222. #ifdef _DEBUG
  23223. DBGLOG("Creating probe for edge id %s in graphManager %p", probe->queryEdgeId(), this);
  23224. #endif
  23225. assertex(!allProbes.getValue(probe->queryEdgeId()));
  23226. allProbes.setValue(probe->queryEdgeId(), (IActivityDebugContext *) probe);
  23227. probe->Release(); // the allProbes map will have linked, and is enough to ensure lifespan...
  23228. return probe;
  23229. }
  23230. virtual memsize_t queryProxyId() const
  23231. {
  23232. if (!proxyId)
  23233. proxyId = registerProxyId((const IDebugGraphManager *) this);
  23234. return proxyId;
  23235. }
  23236. virtual void deserializeProxyGraphs(DebugState state, MemoryBuffer &buff, IActivityBase *parentActivity, unsigned channel)
  23237. {
  23238. Linked<DebugActivityRecord> parentNode = allActivities.getValue(parentActivity);
  23239. assertex(parentNode != NULL);
  23240. unsigned numChildren;
  23241. buff.read(numChildren);
  23242. while (numChildren--)
  23243. {
  23244. unsigned remoteId;
  23245. memsize_t proxyId;
  23246. buff.read(remoteId);
  23247. __uint64 tmp;
  23248. buff.read(tmp);
  23249. proxyId = (memsize_t)tmp; // can't serialize memsize_t
  23250. bool found = false;
  23251. ForEachItemIn(idx, parentNode->childGraphs)
  23252. {
  23253. IDebugGraphManager &child = parentNode->childGraphs.item(idx);
  23254. if (child.queryProxyId() == proxyId)
  23255. {
  23256. found = true;
  23257. if (state == DebugStateGraphFinished)
  23258. {
  23259. parentNode->childGraphs.remove(idx);
  23260. debugContext->noteGraphChanged();
  23261. }
  23262. break;
  23263. }
  23264. }
  23265. if (!found && state != DebugStateGraphFinished)
  23266. {
  23267. IDebugGraphManager *proxy = createProxyDebugGraphManager(remoteId, channel, proxyId);
  23268. childGraphs.append(*LINK(proxy));
  23269. parentNode->childGraphs.append(*proxy);
  23270. debugContext->noteGraphChanged();
  23271. }
  23272. }
  23273. }
  23274. virtual IProbeManager *startChildGraph(unsigned childGraphId, IActivityBase *parent)
  23275. {
  23276. CriticalBlock b(crit);
  23277. if (childGraphId || parent)
  23278. {
  23279. CRoxieDebugGraphManager *childManager = new CRoxieDebugGraphManager(debugContext, childGraphId, NULL, parent ? parent->queryId() : 0);
  23280. IDebugGraphManager *graph = childManager;
  23281. childGraphs.append(*LINK(graph));
  23282. debugContext->noteGraphChanged();
  23283. return childManager;
  23284. }
  23285. else
  23286. return LINK(this);
  23287. }
  23288. virtual void deleteGraph(IArrayOf<IActivityBase> *activities, IArrayOf<IInputBase> *probes)
  23289. {
  23290. CriticalBlock b(crit);
  23291. if (activities)
  23292. {
  23293. ForEachItemIn(idx, *activities)
  23294. {
  23295. IActivityBase &activity = activities->item(idx);
  23296. if (activity.isSink())
  23297. sinks.zap(activity);
  23298. Linked<DebugActivityRecord> node = allActivities.getValue(&activity);
  23299. if (node)
  23300. allActivities.remove(&activity);
  23301. }
  23302. }
  23303. if (probes)
  23304. {
  23305. IArrayOf<IRoxieInput>* fprobes = (IArrayOf<IRoxieInput>*)(probes);
  23306. ForEachItemIn(probeIdx, *fprobes)
  23307. {
  23308. DebugProbe &probe = (DebugProbe &) fprobes->item(probeIdx);
  23309. #ifdef _DEBUG
  23310. DBGLOG("removing probe for edge id %s in graphManager %p", probe.queryEdgeId(), this);
  23311. #endif
  23312. allProbes.remove(probe.queryEdgeId());
  23313. }
  23314. }
  23315. debugContext->noteGraphChanged();
  23316. }
  23317. };
  23318. extern IProbeManager *createDebugManager(IDebuggableContext *debugContext, const char *graphName)
  23319. {
  23320. return new CRoxieDebugGraphManager(debugContext, 0, graphName, 0);
  23321. }
  23322. enum DebugRequestType
  23323. {
  23324. DEBUGREQUEST_OUTPUTCHILDGRAPH,
  23325. DEBUGREQUEST_OUTPUTLINKSFORCHILDGRAPH,
  23326. DEBUGREQUEST_LOOKUPACTIVITYBYEDGEID,
  23327. DEBUGREQUEST_PRINTEDGE,
  23328. DEBUGREQUEST_SETBREAKPOINT,
  23329. DEBUGREQUEST_SEARCHHISTORIES,
  23330. DEBUGREQUEST_GETRESETGLOBALCOUNTS
  23331. };
  23332. struct DebugRequestBase : public CInterface, implements IInterface
  23333. {
  23334. protected:
  23335. DebugRequestType function;
  23336. memsize_t proxyId; // MORE - at some point should really make this an int instead - but need to look into whether ever used to represent a pointer
  23337. public:
  23338. IMPLEMENT_IINTERFACE;
  23339. DebugRequestBase(DebugRequestType _function, memsize_t _proxyId) : function(_function), proxyId(_proxyId) {}
  23340. DebugRequestBase(MemoryBuffer &serialized)
  23341. {
  23342. byte fval;
  23343. serialized.read(fval); function = (DebugRequestType) fval;
  23344. unsigned __int64 tmp;
  23345. serialized.read(tmp); // can't serilalize memsize_t
  23346. proxyId = (memsize_t) tmp;
  23347. }
  23348. virtual void serialize(MemoryBuffer &buf)
  23349. {
  23350. buf.append((byte) function);
  23351. buf.append((unsigned __int64) proxyId); // can't serialize memsize_t
  23352. }
  23353. virtual void executeRequest(IXmlWriter *output) = 0;
  23354. inline IDebugGraphManager *getManager()
  23355. {
  23356. return (IDebugGraphManager *) getProxy(proxyId);
  23357. }
  23358. inline IActivityDebugContext *getActivity()
  23359. {
  23360. return (IActivityDebugContext *) getProxy(proxyId);
  23361. }
  23362. void inactive(IXmlWriter *output)
  23363. {
  23364. // MORE - what should I do here?
  23365. }
  23366. };
  23367. struct DebugRequestOutputChildGraph : public DebugRequestBase
  23368. {
  23369. private:
  23370. unsigned sequence;
  23371. public:
  23372. DebugRequestOutputChildGraph(memsize_t _proxyId, unsigned _sequence) : DebugRequestBase(DEBUGREQUEST_OUTPUTCHILDGRAPH, _proxyId), sequence(_sequence)
  23373. {
  23374. }
  23375. DebugRequestOutputChildGraph(MemoryBuffer &serialized) : DebugRequestBase(serialized)
  23376. {
  23377. serialized.read(sequence);
  23378. }
  23379. virtual void serialize(MemoryBuffer &buf)
  23380. {
  23381. DebugRequestBase::serialize(buf);
  23382. buf.append(sequence);
  23383. }
  23384. virtual void executeRequest(IXmlWriter *output)
  23385. {
  23386. Owned<IDebugGraphManager> manager = getManager();
  23387. if (manager)
  23388. manager->outputChildGraph(output, sequence);
  23389. else
  23390. inactive(output);
  23391. }
  23392. };
  23393. struct DebugRequestWithId : public DebugRequestBase
  23394. {
  23395. StringAttr id;
  23396. public:
  23397. DebugRequestWithId(DebugRequestType _function, memsize_t _proxyId, const char *_id) : DebugRequestBase(_function, _proxyId), id(_id)
  23398. {
  23399. }
  23400. DebugRequestWithId(MemoryBuffer &serialized) : DebugRequestBase(serialized)
  23401. {
  23402. serialized.read(id);
  23403. }
  23404. virtual void serialize(MemoryBuffer &buf)
  23405. {
  23406. DebugRequestBase::serialize(buf);
  23407. buf.append(id);
  23408. }
  23409. };
  23410. struct DebugRequestOutputLinksForChildGraph : public DebugRequestWithId
  23411. {
  23412. public:
  23413. DebugRequestOutputLinksForChildGraph(memsize_t _proxyId, const char *_id) : DebugRequestWithId(DEBUGREQUEST_OUTPUTLINKSFORCHILDGRAPH, _proxyId, _id) {}
  23414. DebugRequestOutputLinksForChildGraph(MemoryBuffer &serialized) : DebugRequestWithId(serialized)
  23415. {
  23416. }
  23417. virtual void executeRequest(IXmlWriter *output)
  23418. {
  23419. Owned<IDebugGraphManager> manager = getManager();
  23420. if (manager)
  23421. manager->outputLinksForChildGraph(output, id);
  23422. else
  23423. inactive(output);
  23424. }
  23425. };
  23426. struct DebugRequestLookupActivityByEdgeId : public DebugRequestWithId
  23427. {
  23428. public:
  23429. DebugRequestLookupActivityByEdgeId(memsize_t _proxyId, const char *_id) : DebugRequestWithId(DEBUGREQUEST_LOOKUPACTIVITYBYEDGEID, _proxyId, _id) {}
  23430. DebugRequestLookupActivityByEdgeId(MemoryBuffer &serialized) : DebugRequestWithId(serialized)
  23431. {
  23432. }
  23433. virtual void executeRequest(IXmlWriter *output)
  23434. {
  23435. Owned<IDebugGraphManager> manager = getManager();
  23436. if (manager)
  23437. {
  23438. output->outputBeginNested("Result", true);
  23439. IActivityDebugContext *edge = manager->lookupActivityByEdgeId(id);
  23440. if (edge)
  23441. output->outputInt(edge->queryProxyId(), "@proxyId");
  23442. output->outputEndNested("Result");
  23443. }
  23444. else
  23445. inactive(output);
  23446. }
  23447. };
  23448. struct DebugRequestPrintEdge : public DebugRequestBase
  23449. {
  23450. private:
  23451. unsigned startRow;
  23452. unsigned numRows;
  23453. public:
  23454. DebugRequestPrintEdge(memsize_t _proxyId, unsigned _startRow, unsigned _numRows)
  23455. : DebugRequestBase(DEBUGREQUEST_PRINTEDGE, _proxyId), startRow(_startRow), numRows(_numRows)
  23456. {
  23457. }
  23458. DebugRequestPrintEdge(MemoryBuffer &serialized) : DebugRequestBase(serialized)
  23459. {
  23460. serialized.read(startRow);
  23461. serialized.read(numRows);
  23462. }
  23463. virtual void serialize(MemoryBuffer &buf)
  23464. {
  23465. DebugRequestBase::serialize(buf);
  23466. buf.append(startRow);
  23467. buf.append(numRows);
  23468. }
  23469. virtual void executeRequest(IXmlWriter *output)
  23470. {
  23471. Owned<IActivityDebugContext> activity = getActivity();
  23472. if (activity)
  23473. activity->printEdge(output, startRow, numRows);
  23474. else
  23475. inactive(output);
  23476. }
  23477. };
  23478. struct DebugRequestSetRemoveBreakpoint : public DebugRequestBase
  23479. {
  23480. private:
  23481. Linked<IBreakpointInfo> bp;
  23482. bool isRemove;
  23483. public:
  23484. inline DebugRequestSetRemoveBreakpoint(memsize_t _proxyId, IBreakpointInfo &_bp, bool _isRemove)
  23485. : DebugRequestBase(DEBUGREQUEST_SETBREAKPOINT, _proxyId), bp(&_bp), isRemove(_isRemove)
  23486. {
  23487. }
  23488. DebugRequestSetRemoveBreakpoint(MemoryBuffer &serialized) : DebugRequestBase(serialized)
  23489. {
  23490. bp.setown(new CBreakpointInfo(serialized));
  23491. serialized.read(isRemove);
  23492. }
  23493. virtual void serialize(MemoryBuffer &buf)
  23494. {
  23495. DebugRequestBase::serialize(buf);
  23496. bp->serialize(buf);
  23497. buf.append(isRemove);
  23498. }
  23499. virtual void executeRequest(IXmlWriter *output)
  23500. {
  23501. Owned<IDebugGraphManager> manager = getManager();
  23502. if (manager)
  23503. {
  23504. if (isRemove)
  23505. manager->queryContext()->removeBreakpoint(*bp);
  23506. else
  23507. manager->queryContext()->addBreakpoint(*bp.getLink());
  23508. }
  23509. else
  23510. inactive(output);
  23511. }
  23512. };
  23513. struct DebugRequestSearchHistories : public DebugRequestBase
  23514. {
  23515. private:
  23516. Linked<IRowMatcher> matcher;
  23517. bool fullRows;
  23518. public:
  23519. inline DebugRequestSearchHistories(memsize_t _proxyId, IRowMatcher *_matcher, bool _fullRows)
  23520. : DebugRequestBase(DEBUGREQUEST_SEARCHHISTORIES, _proxyId), matcher(_matcher), fullRows(_fullRows)
  23521. {
  23522. }
  23523. DebugRequestSearchHistories(MemoryBuffer &serialized) : DebugRequestBase(serialized)
  23524. {
  23525. matcher.setown(createRowMatcher(serialized));
  23526. serialized.read(fullRows);
  23527. }
  23528. virtual void serialize(MemoryBuffer &buf)
  23529. {
  23530. DebugRequestBase::serialize(buf);
  23531. matcher->serialize(buf);
  23532. buf.append(fullRows);
  23533. }
  23534. virtual void executeRequest(IXmlWriter *output)
  23535. {
  23536. Owned<IDebugGraphManager> manager = getManager();
  23537. if (manager)
  23538. manager->searchHistories(output, matcher, fullRows);
  23539. else
  23540. inactive(output);
  23541. }
  23542. };
  23543. class DebugRequestGetResetGlobalCounts : public DebugRequestBase
  23544. {
  23545. public:
  23546. inline DebugRequestGetResetGlobalCounts(memsize_t _proxyId)
  23547. : DebugRequestBase(DEBUGREQUEST_GETRESETGLOBALCOUNTS, _proxyId)
  23548. {
  23549. }
  23550. DebugRequestGetResetGlobalCounts(MemoryBuffer &serialized) : DebugRequestBase(serialized)
  23551. {
  23552. }
  23553. virtual void executeRequest(IXmlWriter *output)
  23554. {
  23555. Owned<IDebugGraphManager> manager = getManager();
  23556. if (manager)
  23557. manager->queryContext()->debugCounts(output, 0, true);
  23558. else
  23559. inactive(output);
  23560. }
  23561. };
  23562. void doDebugRequest(IRoxieQueryPacket *packet, const IRoxieContextLogger &logctx)
  23563. {
  23564. RoxiePacketHeader newHeader(packet->queryHeader(), ROXIE_DEBUGREQUEST);
  23565. Owned<IMessagePacker> output = ROQ->createOutputStream(newHeader, true, logctx);
  23566. unsigned contextLength = packet->getContextLength();
  23567. Owned<DebugRequestBase> request;
  23568. MemoryBuffer serialized;
  23569. serialized.setBuffer(contextLength, (void*) packet->queryContextData(), false);
  23570. byte fval;
  23571. serialized.read(fval);
  23572. serialized.reset();
  23573. CommonXmlWriter xml(0);
  23574. switch ((DebugRequestType) fval)
  23575. {
  23576. case DEBUGREQUEST_OUTPUTCHILDGRAPH:
  23577. request.setown(new DebugRequestOutputChildGraph(serialized));
  23578. break;
  23579. case DEBUGREQUEST_OUTPUTLINKSFORCHILDGRAPH:
  23580. request.setown(new DebugRequestOutputLinksForChildGraph(serialized));
  23581. break;
  23582. case DEBUGREQUEST_LOOKUPACTIVITYBYEDGEID:
  23583. request.setown(new DebugRequestLookupActivityByEdgeId(serialized));
  23584. break;
  23585. case DEBUGREQUEST_PRINTEDGE:
  23586. request.setown(new DebugRequestPrintEdge(serialized));
  23587. break;
  23588. case DEBUGREQUEST_SETBREAKPOINT:
  23589. request.setown(new DebugRequestSetRemoveBreakpoint(serialized));
  23590. break;
  23591. case DEBUGREQUEST_SEARCHHISTORIES:
  23592. request.setown(new DebugRequestSearchHistories(serialized));
  23593. break;
  23594. case DEBUGREQUEST_GETRESETGLOBALCOUNTS:
  23595. request.setown(new DebugRequestGetResetGlobalCounts(serialized));
  23596. break;
  23597. default: throwUnexpected();
  23598. }
  23599. request->executeRequest(&xml);
  23600. void *ret = output->getBuffer(xml.length()+1, true);
  23601. memcpy(ret, xml.str(), xml.length()+1);
  23602. output->putBuffer(ret, xml.length()+1, true);
  23603. output->flush(true);
  23604. }
  23605. class CProxyDebugContext : public CInterface
  23606. {
  23607. protected:
  23608. memsize_t proxyId;
  23609. unsigned channel;
  23610. Owned<StringContextLogger> logctx;
  23611. void sendProxyRequest(IXmlWriter *output, DebugRequestBase &request) const
  23612. {
  23613. RemoteActivityId id(ROXIE_DEBUGREQUEST, 0);
  23614. ruid_t ruid = getNextRuid();
  23615. RoxiePacketHeader header(id, ruid, channel, 0);
  23616. MemoryBuffer b;
  23617. b.append(sizeof(header), &header);
  23618. b.append ((char) LOGGING_FLAGSPRESENT);
  23619. b.append("PROXY"); // MORE - a better log prefix might be good...
  23620. request.serialize(b);
  23621. Owned<IRowManager> rowManager = roxiemem::createRowManager(1, NULL, *logctx, NULL);
  23622. Owned<IMessageCollator> mc = ROQ->queryReceiveManager()->createMessageCollator(rowManager, ruid);
  23623. Owned<IRoxieQueryPacket> packet = createRoxiePacket(b);
  23624. ROQ->sendPacket(packet, *logctx);
  23625. for (unsigned retries = 1; retries <= MAX_DEBUGREQUEST_RETRIES; retries++)
  23626. {
  23627. bool anyActivity = false;
  23628. Owned<IMessageResult> mr = mc->getNextResult(DEBUGREQUEST_TIMEOUT, anyActivity);
  23629. if (mr)
  23630. {
  23631. unsigned roxieHeaderLen;
  23632. const RoxiePacketHeader *header = (const RoxiePacketHeader *) mr->getMessageHeader(roxieHeaderLen);
  23633. Owned<IMessageUnpackCursor> mu = mr->getCursor(rowManager);
  23634. if (header->activityId == ROXIE_EXCEPTION)
  23635. throwRemoteException(mu);
  23636. assertex(header->activityId == ROXIE_DEBUGREQUEST);
  23637. RecordLengthType *rowlen = (RecordLengthType *) mu->getNext(sizeof(RecordLengthType));
  23638. assertex(rowlen);
  23639. RecordLengthType len = *rowlen;
  23640. ReleaseRoxieRow(rowlen);
  23641. const char * reply = (const char *) mu->getNext(len);
  23642. if (output)
  23643. {
  23644. output->outputString(0, NULL, NULL);
  23645. output->outputQuoted(reply);
  23646. }
  23647. ReleaseRoxieRow(reply);
  23648. ROQ->queryReceiveManager()->detachCollator(mc);
  23649. mc.clear();
  23650. return;
  23651. }
  23652. else if (!anyActivity)
  23653. {
  23654. DBGLOG("Retrying debug request");
  23655. ROQ->sendPacket(packet, *logctx);
  23656. }
  23657. }
  23658. ROQ->queryReceiveManager()->detachCollator(mc);
  23659. mc.clear();
  23660. throwUnexpected(); // MORE - better error
  23661. }
  23662. public:
  23663. CProxyDebugContext(unsigned _channel, memsize_t _proxyId) : channel(_channel), proxyId(_proxyId)
  23664. {
  23665. logctx.setown(new StringContextLogger("CProxyDebugContext"));
  23666. }
  23667. };
  23668. class CProxyActivityDebugContext : public CProxyDebugContext, implements IActivityDebugContext
  23669. {
  23670. StringAttr edgeId;
  23671. public:
  23672. IMPLEMENT_IINTERFACE;
  23673. CProxyActivityDebugContext(unsigned _channel, memsize_t _proxyId, const char *_edgeId)
  23674. : CProxyDebugContext(_channel, _proxyId), edgeId(_edgeId)
  23675. {
  23676. }
  23677. virtual unsigned queryLastSequence() const { UNIMPLEMENTED; };
  23678. virtual IActivityDebugContext *queryInputActivity() const { UNIMPLEMENTED; };
  23679. virtual void getXGMML(IXmlWriter *output) const { UNIMPLEMENTED; };
  23680. virtual void searchHistories(IXmlWriter *output, IRowMatcher *matcher, bool fullRows) { UNIMPLEMENTED; }
  23681. virtual unsigned queryHistorySize() const { UNIMPLEMENTED; };
  23682. virtual IHistoryRow *queryHistoryRow(unsigned idx) const { UNIMPLEMENTED; };
  23683. virtual unsigned queryHistoryCapacity() const { UNIMPLEMENTED; };
  23684. virtual IBreakpointInfo *debuggerCallback(unsigned sequence, const void *row)
  23685. {
  23686. // was done on slave, don't do here too
  23687. return NULL;
  23688. };
  23689. virtual void setHistoryCapacity(unsigned newCapacity) { UNIMPLEMENTED; };
  23690. virtual void clearHistory() { UNIMPLEMENTED; };
  23691. virtual void printEdge(IXmlWriter *output, unsigned startRow, unsigned numRows) const
  23692. {
  23693. DebugRequestPrintEdge request(proxyId, startRow, numRows);
  23694. sendProxyRequest(output, request);
  23695. };
  23696. virtual void setBreakpoint(IBreakpointInfo &bp) { throwUnexpected(); }
  23697. virtual void removeBreakpoint(IBreakpointInfo &bp) { throwUnexpected(); };
  23698. virtual const char *queryEdgeId() const
  23699. {
  23700. return edgeId;
  23701. };
  23702. virtual const char *querySourceId() const { UNIMPLEMENTED; };
  23703. virtual unsigned queryChildGraphId() const { UNIMPLEMENTED; };
  23704. virtual memsize_t queryProxyId() const { UNIMPLEMENTED; };
  23705. };
  23706. class CProxyDebugGraphManager : public CProxyDebugContext, implements IDebugGraphManager
  23707. {
  23708. unsigned id;
  23709. StringBuffer idString;
  23710. MapStringToMyClass<IActivityDebugContext> edgeProxies;
  23711. public:
  23712. IMPLEMENT_IINTERFACE;
  23713. CProxyDebugGraphManager(unsigned _id, unsigned _channel, memsize_t _proxyId)
  23714. : CProxyDebugContext(_channel, _proxyId), id(_id)
  23715. {
  23716. idString.append(_id).append('#').append(channel);
  23717. }
  23718. virtual IActivityDebugContext *lookupActivityByEdgeId(const char *edgeId)
  23719. {
  23720. IActivityDebugContext *edge = edgeProxies.getValue(edgeId);
  23721. if (!edge)
  23722. {
  23723. const char *channelTail = strrchr(edgeId, '#');
  23724. if (channelTail && atoi(channelTail+1)==channel)
  23725. {
  23726. DebugRequestLookupActivityByEdgeId request(proxyId, edgeId);
  23727. CommonXmlWriter reply(0);
  23728. sendProxyRequest(&reply, request);
  23729. Owned<IPropertyTree> response = createPTreeFromXMLString(reply.str());
  23730. if (response)
  23731. {
  23732. memsize_t proxyId = (memsize_t) response->getPropInt64("@proxyId", 0);
  23733. if (proxyId)
  23734. {
  23735. edge = new CProxyActivityDebugContext(channel, proxyId, edgeId);
  23736. edgeProxies.setValue(edgeId, edge);
  23737. ::Release(edge);
  23738. }
  23739. }
  23740. }
  23741. }
  23742. return edge;
  23743. }
  23744. virtual const char *queryGraphName() const { UNIMPLEMENTED; }
  23745. virtual void getXGMML(IXmlWriter *output, unsigned sequence, bool isActive)
  23746. {
  23747. throwUnexpected();
  23748. }
  23749. virtual void setBreakpoint(IBreakpointInfo &bp)
  23750. {
  23751. DebugRequestSetRemoveBreakpoint request(proxyId, bp, false);
  23752. sendProxyRequest(NULL, request);
  23753. }
  23754. virtual void removeBreakpoint(IBreakpointInfo &bp)
  23755. {
  23756. DebugRequestSetRemoveBreakpoint request(proxyId, bp, true);
  23757. sendProxyRequest(NULL, request);
  23758. }
  23759. virtual void setHistoryCapacity(unsigned newCapacity) { UNIMPLEMENTED; }
  23760. virtual void clearHistories() { UNIMPLEMENTED; }
  23761. virtual void searchHistories(IXmlWriter *output, IRowMatcher *matcher, bool fullRows)
  23762. {
  23763. DebugRequestSearchHistories request(proxyId, matcher, fullRows);
  23764. sendProxyRequest(output, request);
  23765. }
  23766. virtual void setNodeProperty(IActivityBase *node, const char *propName, const char *propVvalue)
  23767. {
  23768. // MORE - should I do anything here?
  23769. }
  23770. virtual DebugActivityRecord *getNodeByActivityBase(IActivityBase *activity) const
  23771. {
  23772. // MORE - should I do anything here?
  23773. return NULL;
  23774. }
  23775. virtual void noteSlaveGraph(IActivityBase *parentActivity, unsigned graphId, unsigned channel, memsize_t remoteGraphId)
  23776. {
  23777. UNIMPLEMENTED; // MORE - can this happen? nested graphs?
  23778. }
  23779. virtual memsize_t queryProxyId() const
  23780. {
  23781. return proxyId;
  23782. }
  23783. virtual const char *queryIdString() const
  23784. {
  23785. return idString.str();
  23786. }
  23787. virtual unsigned queryId() const
  23788. {
  23789. return id;
  23790. }
  23791. virtual void outputChildGraph(IXmlWriter *output, unsigned sequence)
  23792. {
  23793. DebugRequestOutputChildGraph request(proxyId, sequence);
  23794. sendProxyRequest(output, request);
  23795. }
  23796. virtual void outputLinksForChildGraph(IXmlWriter *output, const char *parentId)
  23797. {
  23798. DebugRequestOutputLinksForChildGraph request(proxyId, parentId);
  23799. sendProxyRequest(output, request);
  23800. }
  23801. virtual void serializeProxyGraphs(MemoryBuffer &buff)
  23802. {
  23803. UNIMPLEMENTED;
  23804. }
  23805. virtual void deserializeProxyGraphs(DebugState state, MemoryBuffer &buff, IActivityBase *parentActivity, unsigned channel)
  23806. {
  23807. UNIMPLEMENTED;
  23808. }
  23809. virtual IDebuggableContext *queryContext() const
  23810. {
  23811. UNIMPLEMENTED;
  23812. }
  23813. virtual void mergeRemoteCounts(IDebuggableContext *into) const
  23814. {
  23815. DebugRequestGetResetGlobalCounts request(proxyId);
  23816. CommonXmlWriter reply(0);
  23817. reply.outputBeginNested("Counts", true);
  23818. sendProxyRequest(&reply, request);
  23819. reply.outputEndNested("Counts"); // strange way to do it...
  23820. Owned<IPropertyTree> response = createPTreeFromXMLString(reply.str());
  23821. if (response)
  23822. {
  23823. Owned<IPropertyTreeIterator> edges = response->getElements("edge");
  23824. ForEach(*edges)
  23825. {
  23826. IPropertyTree &edge = edges->query();
  23827. const char *edgeId = edge.queryProp("@edgeId");
  23828. unsigned edgeCount = edge.getPropInt("@count");
  23829. Owned<IGlobalEdgeRecord> thisEdge = into->getEdgeRecord(edgeId);
  23830. thisEdge->incrementCount(edgeCount, into->querySequence());
  23831. }
  23832. }
  23833. }
  23834. };
  23835. IDebugGraphManager *createProxyDebugGraphManager(unsigned graphId, unsigned channel, memsize_t remoteGraphId)
  23836. {
  23837. return new CProxyDebugGraphManager(graphId, channel, remoteGraphId);
  23838. }
  23839. //===================================================================================================================
  23840. class CPseudoArg : public CInterface, implements IHThorArg
  23841. {
  23842. public:
  23843. IMPLEMENT_IINTERFACE
  23844. virtual IOutputMetaData * queryOutputMeta() { return NULL; }
  23845. };
  23846. class CPseudoActivity : public CRoxieServerActivity
  23847. {
  23848. public:
  23849. CPseudoActivity(IHThorArg & _helper) : CRoxieServerActivity(_helper) {}
  23850. virtual const void *nextInGroup()
  23851. {
  23852. throwUnexpected(); // I am nobody's input
  23853. }
  23854. };
  23855. class CActivityGraph : public CInterface, implements IActivityGraph, implements IThorChildGraph, implements ILocalGraphEx, implements IRoxieServerChildGraph
  23856. {
  23857. protected:
  23858. IArrayOf<IRoxieServerActivity> activities;
  23859. IArrayOf<IRoxieInput> probes;
  23860. IRoxieServerActivityCopyArray sinks;
  23861. StringAttr graphName;
  23862. Owned<CGraphResults> results;
  23863. CGraphResults graphLoopResults;
  23864. ActivityArray & graphDefinition;
  23865. CriticalSection evaluateCrit;
  23866. IProbeManager *probeManager;
  23867. unsigned id;
  23868. unsigned loopCounter;
  23869. class ActivityGraphSlaveContext : public IndirectSlaveContext
  23870. {
  23871. SpinLock abortLock;
  23872. bool aborted;
  23873. Owned<IException> exception;
  23874. public:
  23875. ActivityGraphSlaveContext(const IRoxieContextLogger &_logctx) : logctx(_logctx), loopCounter(0), codeContext(NULL)
  23876. {
  23877. aborted = false;
  23878. }
  23879. // Note - we must track exceptions at the child level in case there is a CATCH in parent
  23880. virtual void notifyAbort(IException *E)
  23881. {
  23882. SpinBlock b(abortLock);
  23883. if (!aborted && QUERYINTERFACE(E, InterruptedSemaphoreException) == NULL)
  23884. {
  23885. aborted = true;
  23886. exception.set(E);
  23887. }
  23888. }
  23889. virtual void checkAbort()
  23890. {
  23891. if (aborted) // NOTE - don't bother getting lock before reading this (for speed) - a false read is very unlikely and not a problem
  23892. {
  23893. SpinBlock b(abortLock);
  23894. if (!exception)
  23895. exception.setown(MakeStringException(ROXIE_INTERNAL_ERROR, "Query was aborted"));
  23896. throw exception.getLink();
  23897. }
  23898. IndirectSlaveContext::checkAbort();
  23899. }
  23900. virtual ICodeContext *queryCodeContext()
  23901. {
  23902. return codeContext;
  23903. }
  23904. void setCodeContext(ICodeContext * _codeContext)
  23905. {
  23906. codeContext = _codeContext;
  23907. }
  23908. void setLoopCounter(unsigned _loopCounter)
  23909. {
  23910. loopCounter = _loopCounter;
  23911. }
  23912. virtual void noteChildGraph(unsigned id, IActivityGraph *childGraph)
  23913. {
  23914. childGraphs.setValue(id, childGraph);
  23915. }
  23916. virtual IActivityGraph * queryChildGraph(unsigned id)
  23917. {
  23918. if (queryTraceLevel() > 10)
  23919. CTXLOG("resolveChildGraph %d", id);
  23920. IActivityGraph *childGraph = childGraphs.getValue(id);
  23921. assertex(childGraph);
  23922. return childGraph;
  23923. }
  23924. // MORE should really redirect the other log context ones too (though mostly doesn't matter). Really should refactor to have a queryLogContext() method in IRoxieSlaveContext I think
  23925. virtual StringBuffer &getLogPrefix(StringBuffer &ret) const
  23926. {
  23927. logctx.getLogPrefix(ret);
  23928. if (loopCounter)
  23929. ret.appendf("{%u}", loopCounter);
  23930. return ret;
  23931. }
  23932. protected:
  23933. const IRoxieContextLogger &logctx;
  23934. unsigned loopCounter;
  23935. ICodeContext * codeContext;
  23936. MapXToMyClass<unsigned, unsigned, IActivityGraph> childGraphs;
  23937. } graphSlaveContext;
  23938. class ActivityGraphCodeContext : public IndirectCodeContext
  23939. {
  23940. public:
  23941. virtual ILocalGraph * resolveLocalQuery(__int64 activityId)
  23942. {
  23943. if ((unsigned) activityId == container->queryId())
  23944. return container;
  23945. IActivityGraph * match = slaveContext->queryChildGraph((unsigned) activityId);
  23946. if (match)
  23947. return match->queryLocalGraph();
  23948. return IndirectCodeContext::resolveLocalQuery(activityId);
  23949. }
  23950. virtual IThorChildGraph * resolveChildQuery(__int64 activityId, IHThorArg * colocal)
  23951. {
  23952. IActivityGraph * match = slaveContext->queryChildGraph((unsigned) activityId);
  23953. return LINK(match->queryChildGraph());
  23954. }
  23955. virtual unsigned getGraphLoopCounter() const
  23956. {
  23957. return container->queryLoopCounter(); // only called if value is valid
  23958. }
  23959. void setContainer(IRoxieSlaveContext * _slaveContext, CActivityGraph * _container)
  23960. {
  23961. slaveContext = _slaveContext;
  23962. container = _container;
  23963. }
  23964. protected:
  23965. IRoxieSlaveContext * slaveContext;
  23966. CActivityGraph * container;
  23967. } graphCodeContext;
  23968. public:
  23969. IMPLEMENT_IINTERFACE;
  23970. CActivityGraph(const char *_graphName, unsigned _id, ActivityArray &x, IProbeManager *_probeManager, const IRoxieContextLogger &_logctx)
  23971. : probeManager(_probeManager), graphDefinition(x), graphName(_graphName), graphSlaveContext(_logctx)
  23972. {
  23973. id = x.getLibraryGraphId();
  23974. if (!id)
  23975. id = _id;
  23976. loopCounter = 0;
  23977. graphSlaveContext.setCodeContext(&graphCodeContext);
  23978. graphCodeContext.setContainer(&graphSlaveContext, this);
  23979. }
  23980. ~CActivityGraph()
  23981. {
  23982. if (probeManager)
  23983. probeManager->deleteGraph((IArrayOf<IActivityBase>*)&activities, (IArrayOf<IInputBase>*)&probes);
  23984. }
  23985. virtual const char *queryName() const
  23986. {
  23987. return graphName.get();
  23988. }
  23989. void createGraph()
  23990. {
  23991. ForEachItemIn(idx, graphDefinition)
  23992. {
  23993. IRoxieServerActivityFactory &donor = graphDefinition.serverItem(idx);
  23994. IRoxieServerActivity &activity = *donor.createActivity(probeManager);
  23995. activities.append(activity);
  23996. if (donor.isSink())
  23997. {
  23998. sinks.append(activity);
  23999. if (probeManager)
  24000. probeManager->noteSink(&activity);
  24001. }
  24002. }
  24003. ForEachItemIn(idx1, graphDefinition)
  24004. {
  24005. IRoxieServerActivityFactory &donor = graphDefinition.serverItem(idx1);
  24006. IRoxieServerActivity &activity = activities.item(idx1);
  24007. unsigned inputidx = 0;
  24008. loop
  24009. {
  24010. unsigned outputidx;
  24011. unsigned source = donor.getInput(inputidx, outputidx);
  24012. if (source==(unsigned) -1)
  24013. break;
  24014. connectInput(idx1, inputidx, source, outputidx, 0);
  24015. inputidx++;
  24016. }
  24017. IntArray &dependencies = donor.queryDependencies();
  24018. IntArray &dependencyIndexes = donor.queryDependencyIndexes();
  24019. IntArray &dependencyControlIds = donor.queryDependencyControlIds();
  24020. StringArray &dependencyEdgeIds = donor.queryDependencyEdgeIds();
  24021. ForEachItemIn(idx2, dependencies)
  24022. {
  24023. IRoxieServerActivity &dependencySourceActivity = activities.item(dependencies.item(idx2));
  24024. unsigned dependencySourceIndex = dependencyIndexes.item(idx2);
  24025. unsigned dependencyControlId = dependencyControlIds.item(idx2);
  24026. activity.addDependency(dependencySourceActivity, dependencySourceIndex, dependencyControlId);
  24027. if (probeManager)
  24028. probeManager->noteDependency( &dependencySourceActivity, dependencySourceIndex, dependencyControlId, dependencyEdgeIds.item(idx2), &activity);
  24029. }
  24030. }
  24031. }
  24032. void connectInput(unsigned target, unsigned targetIdx, unsigned source, unsigned sourceIdx, unsigned iteration)
  24033. {
  24034. IRoxieServerActivity &targetActivity = activities.item(target);
  24035. IRoxieServerActivity &sourceActivity = activities.item(source);
  24036. IRoxieInput * output = sourceActivity.queryOutput(sourceIdx);
  24037. if (probeManager)
  24038. {
  24039. IInputBase * inputBase = probeManager->createProbe(static_cast<IInputBase*>(output), &sourceActivity, &targetActivity, sourceIdx, targetIdx, iteration);
  24040. output = static_cast<IRoxieInput*>(inputBase);
  24041. probes.append(*LINK(output));
  24042. }
  24043. targetActivity.setInput(targetIdx, output);
  24044. }
  24045. virtual void onCreate(IRoxieSlaveContext *ctx, IHThorArg *_colocalParent)
  24046. {
  24047. graphSlaveContext.set(ctx);
  24048. if (graphDefinition.isMultiInstance())
  24049. {
  24050. graphCodeContext.set(ctx->queryCodeContext());
  24051. ctx = &graphSlaveContext;
  24052. }
  24053. ForEachItemIn(idx, activities)
  24054. {
  24055. IRoxieServerActivity *activity = &activities.item(idx);
  24056. if (activity)
  24057. activity->onCreate(ctx, _colocalParent);
  24058. }
  24059. }
  24060. virtual void abort()
  24061. {
  24062. ForEachItemIn(idx, sinks)
  24063. {
  24064. IRoxieServerActivity &sink = sinks.item(idx);
  24065. sink.stop(true);
  24066. }
  24067. }
  24068. virtual void reset()
  24069. {
  24070. ForEachItemIn(idx, sinks)
  24071. {
  24072. IRoxieServerActivity &sink = sinks.item(idx);
  24073. sink.reset();
  24074. }
  24075. }
  24076. Linked<IException> exception;
  24077. CriticalSection eCrit;
  24078. virtual void noteException(IException *E)
  24079. {
  24080. CriticalBlock b(eCrit);
  24081. if (!exception)
  24082. {
  24083. if (graphSlaveContext.queryDebugContext())
  24084. {
  24085. graphSlaveContext.queryDebugContext()->checkBreakpoint(DebugStateException, NULL, exception);
  24086. }
  24087. exception.set(E);
  24088. }
  24089. }
  24090. virtual void checkAbort()
  24091. {
  24092. CriticalBlock b(eCrit);
  24093. if (exception)
  24094. throw exception.getLink();
  24095. }
  24096. virtual void execute()
  24097. {
  24098. doExecute(0, NULL);
  24099. }
  24100. //New child query code...
  24101. virtual IThorChildGraph * queryChildGraph()
  24102. {
  24103. return this;
  24104. }
  24105. virtual ILocalGraph * queryLocalGraph()
  24106. {
  24107. return this;
  24108. }
  24109. virtual IRoxieServerChildGraph * queryLoopGraph()
  24110. {
  24111. return this;
  24112. }
  24113. inline unsigned queryId() const
  24114. {
  24115. return id;
  24116. }
  24117. inline unsigned queryLoopCounter() const
  24118. {
  24119. return loopCounter;
  24120. }
  24121. void doExecute(unsigned parentExtractSize, const byte * parentExtract)
  24122. {
  24123. if (sinks.ordinality()==1)
  24124. sinks.item(0).execute(parentExtractSize, parentExtract);
  24125. #ifdef PARALLEL_EXECUTE
  24126. else if (!probeManager)
  24127. {
  24128. class casyncfor: public CAsyncFor
  24129. {
  24130. public:
  24131. IActivityGraph &parent;
  24132. unsigned parentExtractSize;
  24133. const byte * parentExtract;
  24134. casyncfor(IRoxieServerActivityCopyArray &_sinks, IActivityGraph &_parent, unsigned _parentExtractSize, const byte * _parentExtract) :
  24135. sinks(_sinks), parent(_parent), parentExtractSize(_parentExtractSize), parentExtract(_parentExtract) { }
  24136. void Do(unsigned i)
  24137. {
  24138. try
  24139. {
  24140. sinks.item(i).execute(parentExtractSize, parentExtract);
  24141. }
  24142. catch (IException *E)
  24143. {
  24144. parent.noteException(E);
  24145. throw;
  24146. }
  24147. }
  24148. private:
  24149. IRoxieServerActivityCopyArray &sinks;
  24150. } afor(sinks, *this, parentExtractSize, parentExtract);
  24151. afor.For(sinks.ordinality(), sinks.ordinality());
  24152. }
  24153. #endif
  24154. else
  24155. {
  24156. ForEachItemIn(idx, sinks)
  24157. {
  24158. IRoxieServerActivity &sink = sinks.item(idx);
  24159. sink.execute(parentExtractSize, parentExtract);
  24160. }
  24161. }
  24162. }
  24163. virtual IEclGraphResults *evaluate(unsigned parentExtractSize, const byte * parentExtract)
  24164. {
  24165. CriticalBlock block(evaluateCrit);
  24166. results.setown(new CGraphResults);
  24167. try
  24168. {
  24169. doExecute(parentExtractSize, parentExtract);
  24170. }
  24171. catch (...)
  24172. {
  24173. DBGLOG("Exception thrown in child query - cleaning up");
  24174. reset();
  24175. throw;
  24176. }
  24177. reset();
  24178. return results.getClear();
  24179. }
  24180. //interface IRoxieServerChildGraph
  24181. virtual void beforeExecute()
  24182. {
  24183. results.setown(new CGraphResults);
  24184. }
  24185. virtual IRoxieInput * startOutput(unsigned id, unsigned parentExtractSize, const byte *parentExtract, bool paused)
  24186. {
  24187. IRoxieInput * ret = selectOutput(id);
  24188. ret->start(parentExtractSize, parentExtract, paused);
  24189. return ret;
  24190. }
  24191. virtual IRoxieInput * selectOutput(unsigned id)
  24192. {
  24193. ForEachItemIn(i, sinks)
  24194. {
  24195. IRoxieInput * ret = sinks.item(i).querySelectOutput(id);
  24196. if (ret)
  24197. return ret;
  24198. }
  24199. throwUnexpected();
  24200. return NULL;
  24201. }
  24202. virtual void setInputResult(unsigned id, IGraphResult * result)
  24203. {
  24204. results->setResult(id, result);
  24205. }
  24206. virtual bool querySetInputResult(unsigned id, IRoxieInput * input)
  24207. {
  24208. ForEachItemIn(i, activities)
  24209. {
  24210. if (activities.item(i).querySetStreamInput(id, input))
  24211. return true;
  24212. }
  24213. return false;
  24214. }
  24215. virtual void stopUnusedOutputs()
  24216. {
  24217. //Hmm not sure how to do this...
  24218. }
  24219. virtual void afterExecute()
  24220. {
  24221. ForEachItemIn(i, sinks)
  24222. {
  24223. sinks.item(i).stop(false);
  24224. }
  24225. if (graphSlaveContext.queryDebugContext())
  24226. {
  24227. graphSlaveContext.queryDebugContext()->checkBreakpoint(DebugStateGraphFinished, NULL, NULL);
  24228. }
  24229. reset();
  24230. }
  24231. virtual IRoxieGraphResults * execute(size32_t parentExtractSize, const byte *parentExtract)
  24232. {
  24233. doExecute(parentExtractSize, parentExtract);
  24234. return LINK(results);
  24235. }
  24236. virtual void getResult(size32_t & retSize, void * & ret, unsigned id)
  24237. {
  24238. results->getResult(retSize, ret, id);
  24239. }
  24240. virtual void getLinkedResult(unsigned & count, byte * * & ret, unsigned id)
  24241. {
  24242. results->getLinkedResult(count, ret, id);
  24243. }
  24244. virtual void setResult(unsigned id, IGraphResult * result)
  24245. {
  24246. results->setResult(id, result);
  24247. }
  24248. virtual IRoxieInput * createResultIterator(unsigned id)
  24249. {
  24250. return results->createIterator(id);
  24251. }
  24252. virtual void setGraphLoopResult(IGraphResult * result)
  24253. {
  24254. graphLoopResults.appendResult(result);
  24255. }
  24256. virtual IRoxieInput * createGraphLoopResultIterator(unsigned id)
  24257. {
  24258. try
  24259. {
  24260. return graphLoopResults.createIterator(id);
  24261. }
  24262. catch (IException * e)
  24263. {
  24264. e->Release();
  24265. throw MakeStringException(ROXIE_GRAPH_PROCESSING_ERROR, "Error reading graph result %d before it is calculated", id);
  24266. }
  24267. }
  24268. virtual void clearGraphLoopResults()
  24269. {
  24270. graphLoopResults.clear();
  24271. }
  24272. virtual void executeGraphLoop(size32_t parentExtractSize, const byte *parentExtract)
  24273. {
  24274. doExecute(parentExtractSize, parentExtract);
  24275. }
  24276. virtual void setGraphLoopResult(unsigned id, IGraphResult * result)
  24277. {
  24278. graphLoopResults.setResult(id, result);
  24279. }
  24280. virtual IRoxieInput * getGraphLoopResult(unsigned id)
  24281. {
  24282. return graphLoopResults.createIterator(id);
  24283. }
  24284. virtual void getProbeResponse(IPropertyTree *query)
  24285. {
  24286. if (probeManager)
  24287. probeManager->getProbeResponse(query);
  24288. }
  24289. virtual IRoxieServerChildGraph * createGraphLoopInstance(unsigned loopCounter, unsigned parentExtractSize, const byte * parentExtract, const IRoxieContextLogger &logctx)
  24290. {
  24291. throwUnexpected();
  24292. }
  24293. virtual CGraphIterationInfo *selectGraphLoopOutput()
  24294. {
  24295. return NULL;
  24296. }
  24297. virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor)
  24298. {
  24299. throwUnexpected();
  24300. }
  24301. virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor)
  24302. {
  24303. throwUnexpected();
  24304. }
  24305. };
  24306. class CIterationActivityGraph : public CActivityGraph
  24307. {
  24308. IHThorArg * colocalParent;
  24309. unsigned fixedParentExtractSize;
  24310. const byte * fixedParentExtract;
  24311. unsigned graphOutputActivityIndex;
  24312. public:
  24313. CIterationActivityGraph(const char *_graphName, unsigned _id, ActivityArray &x, IProbeManager *_probeManager,
  24314. unsigned _loopCounter, IRoxieSlaveContext *ctx, IHThorArg * _colocalParent, unsigned parentExtractSize, const byte * parentExtract, const IRoxieContextLogger &_logctx)
  24315. : CActivityGraph(_graphName, _id, x, _probeManager, _logctx)
  24316. {
  24317. graphOutputActivityIndex = 0;
  24318. loopCounter = _loopCounter;
  24319. colocalParent = _colocalParent;
  24320. graphSlaveContext.set(ctx);
  24321. graphSlaveContext.setLoopCounter(loopCounter);
  24322. graphCodeContext.set(ctx->queryCodeContext());
  24323. fixedParentExtractSize = parentExtractSize;
  24324. fixedParentExtract = parentExtract;
  24325. }
  24326. void createIterationGraph()
  24327. {
  24328. Owned<IRoxieServerActivity> pseudoActivity = new CPseudoActivity(*new CPseudoArg);
  24329. ForEachItemIn(idx1, graphDefinition)
  24330. activities.append(*LINK(pseudoActivity));
  24331. graphOutputActivityIndex = queryGraphOutputIndex();
  24332. recursiveCreateGraph(graphOutputActivityIndex);
  24333. }
  24334. unsigned queryGraphOutputIndex() const
  24335. {
  24336. ForEachItemIn(i, graphDefinition)
  24337. if (graphDefinition.serverItem(i).getKind() == TAKgraphloopresultwrite)
  24338. return i;
  24339. throwUnexpected();
  24340. }
  24341. void recursiveCreateGraph(unsigned whichActivity)
  24342. {
  24343. //Check to see if already created
  24344. IRoxieServerActivity & prevActivity = activities.item(whichActivity);
  24345. if (prevActivity.queryId() != 0)
  24346. {
  24347. prevActivity.noteOutputUsed(); //We need to patch up the number of outputs for splitters.
  24348. return;
  24349. }
  24350. IRoxieServerActivityFactory &donor = graphDefinition.serverItem(whichActivity);
  24351. IRoxieServerActivity * activity = NULL;
  24352. if (donor.isGraphInvariant())
  24353. {
  24354. ThorActivityKind kind = donor.getKind();
  24355. switch (kind)
  24356. {
  24357. case TAKif:
  24358. case TAKchildif:
  24359. case TAKcase:
  24360. case TAKchildcase: // MORE RKC->GH - what about FILTER with a graph-invariant condition and other latestart activities?
  24361. {
  24362. Owned<IHThorArg> helper = &donor.getHelper();
  24363. helper->onCreate(&graphCodeContext, colocalParent, NULL);
  24364. helper->onStart(fixedParentExtract, NULL);
  24365. unsigned branch;
  24366. switch (kind)
  24367. {
  24368. case TAKif: case TAKchildif:
  24369. branch = static_cast<IHThorIfArg *>(helper.get())->getCondition() ? 0 : 1;
  24370. break;
  24371. case TAKcase: case TAKchildcase:
  24372. branch = static_cast<IHThorCaseArg *>(helper.get())->getBranch();
  24373. break;
  24374. default:
  24375. throwUnexpected();
  24376. }
  24377. helper.clear();
  24378. unsigned outputidx;
  24379. unsigned source = donor.getInput(branch, outputidx);
  24380. if (source ==(unsigned) -1)
  24381. activity = createRoxieServerNullActivity(&donor, probeManager);
  24382. else
  24383. activity = createRoxieServerPassThroughActivity(&donor, probeManager);
  24384. activities.replace(*activity, whichActivity);
  24385. activity->onCreate(&graphSlaveContext, colocalParent);
  24386. if (source ==(unsigned) -1)
  24387. return;
  24388. recursiveCreateGraph(source);
  24389. connectInput(whichActivity, 0, source, outputidx, loopCounter);
  24390. break;
  24391. }
  24392. }
  24393. }
  24394. if (!activity)
  24395. {
  24396. activity = donor.createActivity(probeManager);
  24397. activities.replace(*activity, whichActivity);
  24398. activity->onCreate(&graphSlaveContext, colocalParent);
  24399. activity->resetOutputsUsed();
  24400. unsigned inputidx = 0;
  24401. loop
  24402. {
  24403. unsigned outputidx;
  24404. unsigned source = donor.getInput(inputidx, outputidx);
  24405. if (source==(unsigned) -1)
  24406. break;
  24407. recursiveCreateGraph(source);
  24408. connectInput(whichActivity, inputidx, source, outputidx, loopCounter);
  24409. inputidx++;
  24410. }
  24411. }
  24412. IntArray &dependencies = donor.queryDependencies();
  24413. IntArray &dependencyIndexes = donor.queryDependencyIndexes();
  24414. IntArray &dependencyControlIds = donor.queryDependencyControlIds();
  24415. ForEachItemIn(idx2, dependencies)
  24416. {
  24417. unsigned input = dependencies.item(idx2);
  24418. recursiveCreateGraph(input);
  24419. activity->addDependency(activities.item(input),dependencyIndexes.item(idx2),dependencyControlIds.item(idx2));
  24420. }
  24421. }
  24422. virtual CGraphIterationInfo *selectGraphLoopOutput()
  24423. {
  24424. IRoxieServerActivity &sourceActivity = activities.item(graphOutputActivityIndex);
  24425. return new CGraphIterationInfo(&sourceActivity, sourceActivity.queryOutput(0), 0, loopCounter);
  24426. }
  24427. virtual void gatherIterationUsage(IRoxieServerLoopResultProcessor & processor)
  24428. {
  24429. ForEachItemIn(i, activities)
  24430. activities.item(i).gatherIterationUsage(processor, fixedParentExtractSize, fixedParentExtract);
  24431. }
  24432. virtual void associateIterationOutputs(IRoxieServerLoopResultProcessor & processor)
  24433. {
  24434. ForEachItemIn(i, activities)
  24435. activities.item(i).associateIterationOutputs(processor, fixedParentExtractSize, fixedParentExtract, probeManager, probes);
  24436. }
  24437. };
  24438. class CDelayedActivityGraph : public CInterface, implements IActivityGraph
  24439. {
  24440. StringAttr graphName;
  24441. ActivityArray & graphDefinition;
  24442. IProbeManager *probeManager;
  24443. unsigned id;
  24444. IRoxieSlaveContext * ctx;
  24445. IHThorArg * colocalParent;
  24446. public:
  24447. IMPLEMENT_IINTERFACE;
  24448. CDelayedActivityGraph(const char *_graphName, unsigned _id, ActivityArray &x, IProbeManager *_probeManager)
  24449. : probeManager(_probeManager), graphDefinition(x)
  24450. {
  24451. graphName.set(_graphName);
  24452. id = _id;
  24453. ctx = NULL;
  24454. colocalParent = NULL;
  24455. }
  24456. virtual const char *queryName() const { return graphName.get(); }
  24457. virtual void abort() { throwUnexpected(); }
  24458. virtual void reset() { }
  24459. virtual void execute() { throwUnexpected(); }
  24460. virtual void getProbeResponse(IPropertyTree *query) { throwUnexpected(); }
  24461. virtual void noteException(IException *E) { throwUnexpected(); }
  24462. virtual void checkAbort() { throwUnexpected(); }
  24463. virtual IThorChildGraph * queryChildGraph() { throwUnexpected(); }
  24464. virtual ILocalGraph * queryLocalGraph() { throwUnexpected(); }
  24465. virtual IRoxieServerChildGraph * queryLoopGraph() { throwUnexpected(); }
  24466. virtual void onCreate(IRoxieSlaveContext *_ctx, IHThorArg *_colocalParent)
  24467. {
  24468. ctx = _ctx;
  24469. colocalParent = _colocalParent;
  24470. }
  24471. virtual IRoxieServerChildGraph * createGraphLoopInstance(unsigned loopCounter, unsigned parentExtractSize, const byte * parentExtract, const IRoxieContextLogger &logctx)
  24472. {
  24473. Owned<CIterationActivityGraph> ret = new CIterationActivityGraph(graphName, id, graphDefinition, probeManager, loopCounter, ctx, colocalParent, parentExtractSize, parentExtract, logctx);
  24474. ret->createIterationGraph();
  24475. return ret.getClear();
  24476. }
  24477. };
  24478. IActivityGraph *createActivityGraph(const char *_graphName, unsigned id, ActivityArray &childFactories, IRoxieServerActivity *parentActivity, IProbeManager *_probeManager, const IRoxieContextLogger &_logctx)
  24479. {
  24480. if (childFactories.isDelayed())
  24481. {
  24482. return new CDelayedActivityGraph(_graphName, id, childFactories, _probeManager);
  24483. }
  24484. else
  24485. {
  24486. Owned<IProbeManager> childProbe;
  24487. if (_probeManager)
  24488. childProbe.setown(_probeManager->startChildGraph(id, parentActivity));
  24489. Owned<CActivityGraph> ret = new CActivityGraph(_graphName, id, childFactories, childProbe, _logctx);
  24490. ret->createGraph();
  24491. if (_probeManager)
  24492. _probeManager->endChildGraph(childProbe, parentActivity);
  24493. return ret.getClear();
  24494. }
  24495. }
  24496. class CRoxieWorkflowMachine : public WorkflowMachine
  24497. {
  24498. public:
  24499. CRoxieWorkflowMachine(IPropertyTree *_workflowInfo, bool _doOnce, const IRoxieContextLogger &_logctx) : WorkflowMachine(_logctx)
  24500. {
  24501. workflowInfo = _workflowInfo;
  24502. doOnce = _doOnce;
  24503. }
  24504. protected:
  24505. virtual void begin()
  24506. {
  24507. // MORE - should pre-do more of this work
  24508. unsigned count = 0;
  24509. Owned<IConstWorkflowItemIterator> iter = createWorkflowItemIterator(workflowInfo);
  24510. for(iter->first(); iter->isValid(); iter->next())
  24511. count++;
  24512. workflow.setown(createWorkflowItemArray(count));
  24513. for(iter->first(); iter->isValid(); iter->next())
  24514. {
  24515. IConstWorkflowItem *item = iter->query();
  24516. bool isOnce = (item->queryMode() == WFModeOnce);
  24517. workflow->addClone(item);
  24518. if (isOnce != doOnce)
  24519. workflow->queryWfid(item->queryWfid()).setState(WFStateDone);
  24520. }
  24521. }
  24522. virtual void end()
  24523. {
  24524. workflow.clear();
  24525. }
  24526. virtual void schedulingStart() { throw MakeStringException(ROXIE_UNIMPLEMENTED_ERROR, "Scheduling not supported in roxie"); }
  24527. virtual bool schedulingPull() { throw MakeStringException(ROXIE_UNIMPLEMENTED_ERROR, "Scheduling not supported in roxie"); }
  24528. virtual bool schedulingPullStop() { throw MakeStringException(ROXIE_UNIMPLEMENTED_ERROR, "Scheduling not supported in roxie"); }
  24529. virtual void reportContingencyFailure(char const * type, IException * e) {}
  24530. virtual void checkForAbort(unsigned wfid, IException * handling) {}
  24531. virtual void doExecutePersistItem(IRuntimeWorkflowItem & item) { throw MakeStringException(ROXIE_UNIMPLEMENTED_ERROR, "Persists not supported in roxie"); }
  24532. private:
  24533. IPropertyTree *workflowInfo;
  24534. bool doOnce;
  24535. };
  24536. WorkflowMachine *createRoxieWorkflowMachine(IPropertyTree *_workflowInfo, bool _doOnce, const IRoxieContextLogger &_logctx)
  24537. {
  24538. return new CRoxieWorkflowMachine(_workflowInfo, _doOnce, _logctx);
  24539. }
  24540. //=======================================================================================================================
  24541. #define DEBUGEE_TIMEOUT 10000
  24542. class CSlaveDebugContext : public CBaseDebugContext
  24543. {
  24544. /*
  24545. Some thoughts on slave debugging
  24546. 1. Something like a ping can be used to get data from slave when needed
  24547. 2. Should disable IBYTI processing (always use primary) - DONE
  24548. and server-side caching - DONE
  24549. 3. Roxie server can know what slave transactions are pending by intercepting the sends - no need for slave to call back just to indicate start of slave subgraph
  24550. 4. There is a problem when a slave hits a breakpoint in that the breakpoint cound have been deleted by the time it gets a chance to tell the Roxie server - can't
  24551. happen in local case because of the critical block at the head of checkBreakpoint but the local copy of BPs out on slave CAN get out of date. Should we care?
  24552. Should there be a "Sorry, your breakpoints are out of date, here's the new set" response?
  24553. Actually what we do is recheck the BP on the server, and ensure that breakpoint indexes are persistant. DONE
  24554. 5. We need to serialize over our graph info if changed since last time.
  24555. 6. I think we need to change implementation of debugGraph to support children. Then we have a place to put a proxy for a remote one.
  24556. - id's should probably be structured so we can use a hash table at each level
  24557. */
  24558. const RoxiePacketHeader &header;
  24559. memsize_t parentActivity;
  24560. unsigned channel;
  24561. int debugSequence;
  24562. CriticalSection crit;
  24563. const IRoxieContextLogger &logctx; // hides base class definition with more derived class pointer
  24564. public:
  24565. CSlaveDebugContext(IRoxieSlaveContext *_ctx, const IRoxieContextLogger &_logctx, RoxiePacketHeader &_header)
  24566. : CBaseDebugContext(_logctx), header(_header), logctx(_logctx)
  24567. {
  24568. channel = header.channel;
  24569. debugSequence = 0;
  24570. parentActivity = 0;
  24571. }
  24572. void init(const IRoxieQueryPacket *_packet)
  24573. {
  24574. unsigned traceLength = _packet->getTraceLength();
  24575. assertex(traceLength);
  24576. const byte *traceInfo = _packet->queryTraceInfo();
  24577. assertex((*traceInfo & LOGGING_DEBUGGERACTIVE) != 0);
  24578. unsigned debugLen = *(unsigned short *) (traceInfo + 1);
  24579. MemoryBuffer b;
  24580. b.setBuffer(debugLen, (char *) (traceInfo + 1 + sizeof(unsigned short)), false);
  24581. deserialize(b);
  24582. __uint64 tmp; // can't serialize memsize_t
  24583. b.read(tmp); // note - this is written by the RemoteAdaptor not by the serialize....
  24584. parentActivity = (memsize_t)tmp;
  24585. }
  24586. virtual unsigned queryChannel() const
  24587. {
  24588. return channel;
  24589. }
  24590. virtual BreakpointActionMode checkBreakpoint(DebugState state, IActivityDebugContext *probe, const void *extra)
  24591. {
  24592. return CBaseDebugContext::checkBreakpoint(state, probe, extra);
  24593. }
  24594. virtual void waitForDebugger(DebugState state, IActivityDebugContext *probe)
  24595. {
  24596. StringBuffer debugIdString;
  24597. CriticalBlock b(crit); // Make sure send sequentially - don't know if this is strictly needed...
  24598. debugSequence++;
  24599. debugIdString.appendf(".debug.%x", debugSequence);
  24600. IPendingCallback *callback = ROQ->notePendingCallback(header, debugIdString.str()); // note that we register before the send to avoid a race.
  24601. try
  24602. {
  24603. RoxiePacketHeader newHeader(header, ROXIE_DEBUGCALLBACK);
  24604. loop // retry indefinately, as more than likely Roxie server is waiting for user input ...
  24605. {
  24606. Owned<IMessagePacker> output = ROQ->createOutputStream(newHeader, true, logctx);
  24607. // These are deserialized in onDebugCallback..
  24608. MemoryBuffer debugInfo;
  24609. debugInfo.append(debugSequence);
  24610. debugInfo.append((char) state);
  24611. if (state==DebugStateGraphFinished)
  24612. {
  24613. debugInfo.append(globalCounts.count());
  24614. HashIterator edges(globalCounts);
  24615. ForEach(edges)
  24616. {
  24617. IGlobalEdgeRecord *edge = globalCounts.mapToValue(&edges.query());
  24618. debugInfo.append((const char *) edges.query().getKey());
  24619. debugInfo.append(edge->queryCount());
  24620. }
  24621. }
  24622. debugInfo.append(currentBreakpointUID);
  24623. debugInfo.append((__uint64)parentActivity); // can't serialize memsize_t
  24624. debugInfo.append(channel);
  24625. assertex (currentGraph); // otherwise what am I remote debugging?
  24626. currentGraph->serializeProxyGraphs(debugInfo);
  24627. debugInfo.append(probe ? probe->queryEdgeId() : "");
  24628. char *buf = (char *) output->getBuffer(debugInfo.length(), true);
  24629. memcpy(buf, debugInfo.toByteArray(), debugInfo.length());
  24630. output->putBuffer(buf, debugInfo.length(), true);
  24631. output->flush(true);
  24632. output.clear();
  24633. if (callback->wait(5000))
  24634. break;
  24635. }
  24636. if (traceLevel > 6)
  24637. { StringBuffer s; DBGLOG("Processing information from Roxie server in response to %s", newHeader.toString(s).str()); }
  24638. MemoryBuffer &serverData = callback->queryData();
  24639. deserialize(serverData);
  24640. }
  24641. catch (...)
  24642. {
  24643. ROQ->removePendingCallback(callback);
  24644. throw;
  24645. }
  24646. ROQ->removePendingCallback(callback);
  24647. }
  24648. virtual IRoxieQueryPacket *onDebugCallback(const RoxiePacketHeader &header, size32_t len, char *data)
  24649. {
  24650. // MORE - Implies a server -> slave child -> slave grandchild type situation - need to pass call on to Roxie server (rather as I do for file callback)
  24651. UNIMPLEMENTED;
  24652. }
  24653. virtual bool onDebuggerTimeout()
  24654. {
  24655. throwUnexpected();
  24656. }
  24657. virtual void debugCounts(IXmlWriter *output, unsigned sinceSequence, bool reset)
  24658. {
  24659. // This gives info for the global view - accumulated counts for all instances, plus the graph as fetched from the workunit
  24660. HashIterator edges(globalCounts);
  24661. ForEach(edges)
  24662. {
  24663. IGlobalEdgeRecord *edge = globalCounts.mapToValue(&edges.query());
  24664. if (edge->queryLastSequence() && (!sinceSequence || edge->queryLastSequence() > sinceSequence))
  24665. {
  24666. output->outputBeginNested("edge", true);
  24667. output->outputCString((const char *) edges.query().getKey(), "@edgeId");
  24668. output->outputUInt(edge->queryCount(), "@count");
  24669. output->outputEndNested("edge");
  24670. }
  24671. if (reset)
  24672. edge->reset();
  24673. }
  24674. }
  24675. };
  24676. class CSlaveContext : public CInterface, implements IRoxieSlaveContext, implements ICodeContext, implements roxiemem::ITimeLimiter, implements roxiemem::IRowAllocatorCache
  24677. {
  24678. protected:
  24679. mutable IArrayOf<IEngineRowAllocator> allAllocators;
  24680. mutable SpinLock allAllocatorsLock;
  24681. Owned<IRowManager> rowManager; // NOTE: the order of destruction here is significant. For leak check to work destroy this BEFORE allAllocators, but after most other things
  24682. Owned <IDebuggableContext> debugContext;
  24683. const IQueryFactory *factory;
  24684. Owned<IProbeManager> probeManager; // must be destroyed after childGraphs
  24685. MapXToMyClass<unsigned, unsigned, IActivityGraph> childGraphs;
  24686. Owned<IActivityGraph> graph;
  24687. unsigned priority;
  24688. StringBuffer authToken;
  24689. Owned<IPropertyTree> probeQuery;
  24690. RoxiePacketHeader *header;
  24691. unsigned lastWuAbortCheck;
  24692. unsigned startTime;
  24693. unsigned timeLimit;
  24694. unsigned totSlavesReplyLen;
  24695. unsigned ctxParallelJoinPreload;
  24696. unsigned ctxFullKeyedJoinPreload;
  24697. unsigned ctxKeyedJoinPreload;
  24698. unsigned ctxConcatPreload;
  24699. unsigned ctxFetchPreload;
  24700. unsigned ctxPrefetchProjectPreload;
  24701. bool traceActivityTimes;
  24702. Owned<IConstWorkUnit> workUnit;
  24703. Owned<IRoxieDaliHelper> daliHelperLink;
  24704. CriticalSection statsCrit;
  24705. const IRoxieContextLogger &logctx;
  24706. protected:
  24707. CriticalSection resultsCrit;
  24708. PointerIArrayOf<FlushingStringBuffer> resultMap;
  24709. bool exceptionLogged;
  24710. bool aborted;
  24711. CriticalSection abortLock; // NOTE: we don't bother to get lock when just reading to see whether to abort
  24712. Owned<IException> exception;
  24713. static void _toXML(IPropertyTree *tree, StringBuffer &xgmml, unsigned indent)
  24714. {
  24715. if (tree->getPropInt("att[@name='_roxieStarted']/@value", 1) == 0)
  24716. return;
  24717. if (0 && tree->getPropInt("att[@name='_kind']/@value", 0) == 496)
  24718. {
  24719. Owned<IPropertyTreeIterator> sub = tree->getElements(".//att[@name='_roxieStarted']");
  24720. bool foundOne = false;
  24721. ForEach(*sub)
  24722. {
  24723. if (sub->query().getPropInt("@value", 1)==0)
  24724. {
  24725. foundOne = true;
  24726. break;
  24727. }
  24728. }
  24729. if (!foundOne)
  24730. return;
  24731. }
  24732. const char *name = tree->queryName();
  24733. xgmml.pad(indent).append('<').append(name);
  24734. Owned<IAttributeIterator> it = tree->getAttributes(true);
  24735. if (it->first())
  24736. {
  24737. do
  24738. {
  24739. const char *key = it->queryName();
  24740. xgmml.append(' ').append(key+1).append("=\"");
  24741. encodeXML(it->queryValue(), xgmml, ENCODE_NEWLINES);
  24742. xgmml.append("\"");
  24743. }
  24744. while (it->next());
  24745. }
  24746. Owned<IPropertyTreeIterator> sub = tree->getElements("*", iptiter_sort);
  24747. if (!sub->first())
  24748. {
  24749. xgmml.append("/>\n");
  24750. }
  24751. else
  24752. {
  24753. xgmml.append(">\n");
  24754. for(; sub->isValid(); sub->next())
  24755. _toXML(&sub->query(), xgmml, indent+1);
  24756. xgmml.pad(indent).append("</").append(name).append(">\n");
  24757. }
  24758. }
  24759. public:
  24760. IMPLEMENT_IINTERFACE;
  24761. CSlaveContext(const IQueryFactory *_factory, const IRoxieContextLogger &_logctx, unsigned _timeLimit, memsize_t _memoryLimit, IRoxieQueryPacket *_packet, bool _traceActivityTimes, bool _debuggerActive)
  24762. : factory(_factory), logctx(_logctx)
  24763. {
  24764. if (_packet)
  24765. header = &_packet->queryHeader();
  24766. else
  24767. header = NULL;
  24768. timeLimit = _timeLimit;
  24769. startTime = lastWuAbortCheck = msTick();
  24770. ctxParallelJoinPreload = 0;
  24771. ctxFullKeyedJoinPreload = 0;
  24772. ctxKeyedJoinPreload = 0;
  24773. ctxConcatPreload = 0;
  24774. ctxFetchPreload = 0;
  24775. ctxPrefetchProjectPreload = 0;
  24776. traceActivityTimes = _traceActivityTimes;
  24777. if (_debuggerActive)
  24778. {
  24779. CSlaveDebugContext *slaveDebugContext = new CSlaveDebugContext(this, logctx, *header);
  24780. slaveDebugContext->init(_packet);
  24781. debugContext.setown(slaveDebugContext);
  24782. probeManager.setown(createDebugManager(debugContext, "slaveDebugger"));
  24783. }
  24784. aborted = false;
  24785. rowManager.setown(roxiemem::createRowManager(_memoryLimit, this, logctx, this, false));
  24786. //MORE: If checking heap required then should have
  24787. //rowManager.setown(createCheckingHeap(rowManager)) or something similar.
  24788. }
  24789. // interface IRoxieServerContext
  24790. virtual void noteStatistic(unsigned statCode, unsigned __int64 value, unsigned count) const
  24791. {
  24792. logctx.noteStatistic(statCode, value, count);
  24793. }
  24794. virtual void CTXLOG(const char *format, ...) const
  24795. {
  24796. va_list args;
  24797. va_start(args, format);
  24798. logctx.CTXLOGva(format, args);
  24799. va_end(args);
  24800. }
  24801. virtual void CTXLOGva(const char *format, va_list args) const
  24802. {
  24803. logctx.CTXLOGva(format, args);
  24804. }
  24805. virtual void CTXLOGa(TracingCategory category, const char *prefix, const char *text) const
  24806. {
  24807. logctx.CTXLOGa(category, prefix, text);
  24808. }
  24809. virtual void logOperatorException(IException *E, const char *file, unsigned line, const char *format, ...) const
  24810. {
  24811. va_list args;
  24812. va_start(args, format);
  24813. logctx.logOperatorExceptionVA(E, file, line, format, args);
  24814. va_end(args);
  24815. }
  24816. virtual void logOperatorExceptionVA(IException *E, const char *file, unsigned line, const char *format, va_list args) const
  24817. {
  24818. logctx.logOperatorExceptionVA(E, file, line, format, args);
  24819. }
  24820. virtual void CTXLOGae(IException *E, const char *file, unsigned line, const char *prefix, const char *format, ...) const
  24821. {
  24822. va_list args;
  24823. va_start(args, format);
  24824. logctx.CTXLOGaeva(E, file, line, prefix, format, args);
  24825. va_end(args);
  24826. }
  24827. virtual void CTXLOGaeva(IException *E, const char *file, unsigned line, const char *prefix, const char *format, va_list args) const
  24828. {
  24829. logctx.CTXLOGaeva(E, file, line, prefix, format, args);
  24830. }
  24831. virtual void CTXLOGl(LogItem *log) const
  24832. {
  24833. if (log->isStatistics())
  24834. {
  24835. logctx.noteStatistic(log->getStatCode(), log->getStatValue(), (unsigned)log->getStatCount());
  24836. log->Release();
  24837. }
  24838. else
  24839. logctx.CTXLOGl(log);
  24840. }
  24841. virtual unsigned logString(const char *text) const
  24842. {
  24843. if (text && *text)
  24844. {
  24845. CTXLOG("USER: %s", text);
  24846. return strlen(text);
  24847. }
  24848. else
  24849. return 0;
  24850. }
  24851. virtual const IContextLogger &queryContextLogger() const
  24852. {
  24853. return logctx;
  24854. }
  24855. virtual StringBuffer &getLogPrefix(StringBuffer &ret) const
  24856. {
  24857. return logctx.getLogPrefix(ret);
  24858. }
  24859. virtual bool isIntercepted() const
  24860. {
  24861. return logctx.isIntercepted();
  24862. }
  24863. virtual bool isBlind() const
  24864. {
  24865. return logctx.isBlind();
  24866. }
  24867. virtual unsigned queryTraceLevel() const
  24868. {
  24869. return logctx.queryTraceLevel();
  24870. }
  24871. virtual void noteProcessed(const IRoxieContextLogger &activityContext, const IRoxieServerActivity *activity, unsigned _idx, unsigned _processed, unsigned __int64 _totalCycles, unsigned __int64 _localCycles) const
  24872. {
  24873. if (traceActivityTimes)
  24874. {
  24875. StringBuffer text, prefix;
  24876. text.appendf("%s outputIdx %d processed %d total %d us local %d us",
  24877. getActivityText(activity->getKind()), _idx, _processed, (unsigned) (cycle_to_nanosec(_totalCycles)/1000), (unsigned)(cycle_to_nanosec(_localCycles)/1000));
  24878. activityContext.getLogPrefix(prefix);
  24879. CTXLOGa(LOG_TIMING, prefix.str(), text.str());
  24880. }
  24881. if (graphProgress)
  24882. {
  24883. IPropertyTree& nodeProgress = graphProgress->updateNode(activity->querySubgraphId(), activity->queryId());
  24884. nodeProgress.setPropInt64("@totalTime", (unsigned) (cycle_to_nanosec(_totalCycles)/1000));
  24885. nodeProgress.setPropInt64("@localTime", (unsigned) (cycle_to_nanosec(_localCycles)/1000));
  24886. if (_processed)
  24887. {
  24888. StringBuffer edgeId;
  24889. edgeId.append(activity->queryId()).append('_').append(_idx);
  24890. IPropertyTree& edgeProgress = graphProgress->updateEdge(activity->querySubgraphId(), edgeId.str());
  24891. edgeProgress.setPropInt64("@count", _processed);
  24892. }
  24893. }
  24894. }
  24895. virtual bool queryTimeActivities() const
  24896. {
  24897. return traceActivityTimes;
  24898. }
  24899. virtual void checkAbort()
  24900. {
  24901. // MORE - really should try to apply limits at slave end too
  24902. #ifdef __linux__
  24903. if (linuxYield)
  24904. sched_yield();
  24905. #endif
  24906. #ifdef _DEBUG
  24907. if (shuttingDown)
  24908. throw MakeStringException(ROXIE_FORCE_SHUTDOWN, "Roxie is shutting down");
  24909. #endif
  24910. if (aborted) // NOTE - don't bother getting lock before reading this (for speed) - a false read is very unlikely and not a problem
  24911. {
  24912. CriticalBlock b(abortLock);
  24913. if (!exception)
  24914. exception.setown(MakeStringException(ROXIE_INTERNAL_ERROR, "Query was aborted"));
  24915. throw exception.getLink();
  24916. }
  24917. if (graph)
  24918. graph->checkAbort();
  24919. if (timeLimit && (msTick() - startTime > timeLimit))
  24920. {
  24921. unsigned oldLimit = timeLimit;
  24922. //timeLimit = 0; // to prevent exceptions in cleanup - this means only one arm gets stopped!
  24923. CriticalBlock b(abortLock);
  24924. IException *E = MakeStringException(ROXIE_TIMEOUT, "Query %s exceeded time limit (%d ms) - terminated", factory->queryQueryName(), oldLimit);
  24925. if (!exceptionLogged)
  24926. {
  24927. logOperatorException(E, NULL, 0, NULL);
  24928. exceptionLogged = true;
  24929. }
  24930. throw E;
  24931. }
  24932. if (workUnit && (msTick() - lastWuAbortCheck > 5000))
  24933. {
  24934. CriticalBlock b(abortLock);
  24935. if (workUnit->aborting())
  24936. {
  24937. if (!exception)
  24938. exception.setown(MakeStringException(ROXIE_INTERNAL_ERROR, "Query was aborted"));
  24939. throw exception.getLink();
  24940. }
  24941. lastWuAbortCheck = msTick();
  24942. }
  24943. }
  24944. virtual void notifyAbort(IException *E)
  24945. {
  24946. CriticalBlock b(abortLock);
  24947. if (!aborted && QUERYINTERFACE(E, InterruptedSemaphoreException) == NULL)
  24948. {
  24949. aborted = true;
  24950. exception.set(E);
  24951. setWUState(WUStateAborting);
  24952. }
  24953. }
  24954. virtual void setWUState(WUState state)
  24955. {
  24956. if (workUnit)
  24957. {
  24958. WorkunitUpdate w(&workUnit->lock());
  24959. w->setState(state);
  24960. }
  24961. }
  24962. virtual bool checkWuAborted()
  24963. {
  24964. return workUnit && workUnit->aborting();
  24965. }
  24966. virtual unsigned parallelJoinPreload()
  24967. {
  24968. return ctxParallelJoinPreload;
  24969. }
  24970. virtual unsigned concatPreload()
  24971. {
  24972. return ctxConcatPreload;
  24973. }
  24974. virtual unsigned fetchPreload()
  24975. {
  24976. return ctxFetchPreload;
  24977. }
  24978. virtual unsigned fullKeyedJoinPreload()
  24979. {
  24980. return ctxFullKeyedJoinPreload;
  24981. }
  24982. virtual unsigned keyedJoinPreload()
  24983. {
  24984. return ctxKeyedJoinPreload;
  24985. }
  24986. virtual unsigned prefetchProjectPreload()
  24987. {
  24988. return ctxPrefetchProjectPreload;
  24989. }
  24990. const char *queryAuthToken()
  24991. {
  24992. return authToken.str();
  24993. }
  24994. virtual void noteChildGraph(unsigned id, IActivityGraph *childGraph)
  24995. {
  24996. if (queryTraceLevel() > 10)
  24997. CTXLOG("CSlaveContext %p noteChildGraph %d=%p", this, id, childGraph);
  24998. childGraphs.setValue(id, childGraph);
  24999. }
  25000. virtual IActivityGraph *getLibraryGraph(const LibraryCallFactoryExtra &extra, IRoxieServerActivity *parentActivity)
  25001. {
  25002. if (extra.embedded)
  25003. {
  25004. return factory->lookupGraph(extra.libraryName, probeManager, *this, parentActivity);
  25005. }
  25006. else
  25007. {
  25008. Owned<IQueryFactory> libraryQuery = globalPackageSetManager->lookupLibrary(extra.libraryName, extra.interfaceHash, *this);
  25009. return libraryQuery->lookupGraph("graph1", probeManager, *this, parentActivity);
  25010. }
  25011. }
  25012. void beginGraph(const char *graphName)
  25013. {
  25014. if (debugContext)
  25015. {
  25016. probeManager.clear(); // Hack!
  25017. probeManager.setown(createDebugManager(debugContext, graphName));
  25018. debugContext->checkBreakpoint(DebugStateGraphCreate, NULL, graphName);
  25019. }
  25020. else if (probeAllRows || probeQuery != NULL)
  25021. probeManager.setown(createProbeManager());
  25022. graph.setown(factory->lookupGraph(graphName, probeManager, *this, NULL));
  25023. graph->onCreate(this, NULL); // MORE - is that right
  25024. if (debugContext)
  25025. debugContext->checkBreakpoint(DebugStateGraphStart, NULL, graphName);
  25026. }
  25027. Owned<IWUGraphProgress> graphProgress; // could make local to endGraph and pass to reset - might be cleaner
  25028. void endGraph(bool aborting)
  25029. {
  25030. if (graph)
  25031. {
  25032. if (debugContext)
  25033. debugContext->checkBreakpoint(aborting ? DebugStateGraphAbort : DebugStateGraphEnd, NULL, graph->queryName());
  25034. if (aborting)
  25035. graph->abort();
  25036. WorkunitUpdate progressWorkUnit(NULL);
  25037. Owned<IConstWUGraphProgress> progress;
  25038. if (workUnit)
  25039. {
  25040. progressWorkUnit.setown(&workUnit->lock());
  25041. progress.setown(progressWorkUnit->getGraphProgress(graph->queryName()));
  25042. graphProgress.setown(progress->update());
  25043. }
  25044. graph->reset();
  25045. if (graphProgress)
  25046. {
  25047. graphProgress.clear();
  25048. progress.clear();
  25049. }
  25050. graph.clear();
  25051. childGraphs.kill();
  25052. }
  25053. }
  25054. void runGraph()
  25055. {
  25056. try
  25057. {
  25058. graph->execute();
  25059. if (probeQuery)
  25060. graph->getProbeResponse(probeQuery);
  25061. }
  25062. catch(...)
  25063. {
  25064. if (probeQuery)
  25065. graph->getProbeResponse(probeQuery);
  25066. throw;
  25067. }
  25068. }
  25069. virtual void executeGraph(const char * name, bool realThor, size32_t parentExtractSize, const void * parentExtract)
  25070. {
  25071. assertex(parentExtractSize == 0);
  25072. if (queryTraceLevel() > 8)
  25073. CTXLOG("Executing graph %s", name);
  25074. assertex(!realThor);
  25075. bool created = false;
  25076. try
  25077. {
  25078. beginGraph(name);
  25079. created = true;
  25080. runGraph();
  25081. }
  25082. catch (IException *e)
  25083. {
  25084. if (e->errorAudience() == MSGAUD_operator)
  25085. EXCLOG(e, "Exception thrown in query - cleaning up"); // if an IException is throw let EXCLOG determine if a trap should be generated
  25086. else
  25087. {
  25088. StringBuffer s;
  25089. CTXLOG("Exception thrown in query - cleaning up: %d: %s", e->errorCode(), e->errorMessage(s).str());
  25090. }
  25091. if (created)
  25092. endGraph(true);
  25093. CTXLOG("Done cleaning up");
  25094. throw;
  25095. }
  25096. catch (...)
  25097. {
  25098. CTXLOG("Exception thrown in query - cleaning up");
  25099. if (created)
  25100. endGraph(true);
  25101. CTXLOG("Done cleaning up");
  25102. throw;
  25103. }
  25104. endGraph(false);
  25105. }
  25106. virtual IActivityGraph * queryChildGraph(unsigned id)
  25107. {
  25108. if (queryTraceLevel() > 10)
  25109. CTXLOG("CSlaveContext %p resolveChildGraph %d", this, id);
  25110. IActivityGraph *childGraph = childGraphs.getValue(id);
  25111. assertex(childGraph);
  25112. return childGraph;
  25113. }
  25114. virtual IThorChildGraph * resolveChildQuery(__int64 activityId, IHThorArg * colocal)
  25115. {
  25116. // NOTE - part of ICodeContext interface
  25117. return LINK(queryChildGraph((unsigned) activityId)->queryChildGraph());
  25118. }
  25119. virtual ILocalGraph * resolveLocalQuery(__int64 id)
  25120. {
  25121. return queryChildGraph((unsigned) id)->queryLocalGraph();
  25122. }
  25123. virtual IRowManager &queryRowManager()
  25124. {
  25125. return *rowManager;
  25126. }
  25127. virtual void addSlavesReplyLen(unsigned len)
  25128. {
  25129. CriticalBlock b(statsCrit); // MORE: change to atomic_add, or may not need it at all?
  25130. totSlavesReplyLen += len;
  25131. }
  25132. virtual __int64 countIndex(__int64 activityId, IHThorCountIndexArg & arg)
  25133. {
  25134. throwUnexpected();
  25135. }
  25136. virtual __int64 countDiskFile(__int64 activityId, IHThorCountFileArg & arg)
  25137. {
  25138. Owned<IHThorCountFileArg> a = &arg; // to make sure it gets released when I am done....
  25139. Owned<IRoxieServerActivityFactory> f = factory->getRoxieServerActivityFactory((unsigned) activityId);
  25140. if (f)
  25141. {
  25142. Owned<IRoxieServerActivity> fa = f->createFunction(*a.getClear(), NULL);
  25143. fa->onCreate(this, NULL);
  25144. fa->start(0, NULL, false);
  25145. __int64 ret = fa->evaluate();
  25146. fa->stop(false);
  25147. fa->reset();
  25148. return ret;
  25149. }
  25150. throwUnexpected();
  25151. }
  25152. virtual const char *loadResource(unsigned id)
  25153. {
  25154. ILoadedDllEntry *dll = factory->queryDll();
  25155. return (const char *) dll->getResource(id);
  25156. }
  25157. virtual const IResolvedFile *resolveLFN(const char *filename, bool isOpt)
  25158. {
  25159. CDateTime cacheDate; // Note - this is empty meaning we don't know...
  25160. return querySlaveDynamicFileCache()->lookupDynamicFile(*this, filename, cacheDate, header, isOpt, false);
  25161. }
  25162. virtual IRoxieWriteHandler *createLFN(const char *filename, bool overwrite, bool extend, const StringArray &clusters)
  25163. {
  25164. throwUnexpected(); // only support writing on the server
  25165. }
  25166. virtual void onFileCallback(const RoxiePacketHeader &header, const char *lfn, bool isOpt, bool isLocal)
  25167. {
  25168. // On a slave, we need to request info using our own header (not the one passed in) and need to get global rather than just local info
  25169. // (possibly we could get just local if the channel matches but not sure there is any point)
  25170. Owned<const IResolvedFile> dFile = resolveLFN(lfn, isOpt);
  25171. if (dFile)
  25172. {
  25173. MemoryBuffer mb;
  25174. mb.append(sizeof(RoxiePacketHeader), &header);
  25175. mb.append(lfn);
  25176. dFile->serializePartial(mb, header.channel, isLocal);
  25177. ((RoxiePacketHeader *) mb.toByteArray())->activityId = ROXIE_FILECALLBACK;
  25178. Owned<IRoxieQueryPacket> reply = createRoxiePacket(mb);
  25179. reply->queryHeader().retries = 0;
  25180. ROQ->sendPacket(reply, *this); // MORE - the caller's log context might be better? Should we unicast? Note that this does not release the packet
  25181. return;
  25182. }
  25183. ROQ->sendAbortCallback(header, lfn, *this);
  25184. throwUnexpected();
  25185. }
  25186. virtual ICodeContext *queryCodeContext()
  25187. {
  25188. return this;
  25189. }
  25190. virtual IRoxieServerContext *queryServerContext()
  25191. {
  25192. return NULL;
  25193. }
  25194. virtual IProbeManager *queryProbeManager() const
  25195. {
  25196. return probeManager;
  25197. }
  25198. virtual IDebuggableContext *queryDebugContext() const
  25199. {
  25200. return debugContext;
  25201. }
  25202. virtual char *getOS()
  25203. {
  25204. #ifdef _WIN32
  25205. return strdup("windows");
  25206. #else
  25207. return strdup("linux");
  25208. #endif
  25209. }
  25210. virtual const void * fromXml(IEngineRowAllocator * rowAllocator, size32_t len, const char * utf8, IXmlToRowTransformer * xmlTransformer, bool stripWhitespace)
  25211. {
  25212. return createRowFromXml(rowAllocator, len, utf8, xmlTransformer, stripWhitespace);
  25213. }
  25214. // The following from ICodeContext should never be executed in slave activity. If we are on Roxie server (or in child query on slave), they will be implemented by more derived CRoxieServerContext class
  25215. virtual void setResultBool(const char *name, unsigned sequence, bool value) { throwUnexpected(); }
  25216. virtual void setResultData(const char *name, unsigned sequence, int len, const void * data) { throwUnexpected(); }
  25217. virtual void setResultDecimal(const char * stepname, unsigned sequence, int len, int precision, bool isSigned, const void *val) { throwUnexpected(); }
  25218. virtual void setResultInt(const char *name, unsigned sequence, __int64 value) { throwUnexpected(); }
  25219. virtual void setResultRaw(const char *name, unsigned sequence, int len, const void * data) { throwUnexpected(); }
  25220. virtual void setResultReal(const char * stepname, unsigned sequence, double value) { throwUnexpected(); }
  25221. virtual void setResultSet(const char *name, unsigned sequence, bool isAll, size32_t len, const void * data, ISetToXmlTransformer * transformer) { throwUnexpected(); }
  25222. virtual void setResultString(const char *name, unsigned sequence, int len, const char * str) { throwUnexpected(); }
  25223. virtual void setResultUInt(const char *name, unsigned sequence, unsigned __int64 value) { throwUnexpected(); }
  25224. virtual void setResultUnicode(const char *name, unsigned sequence, int len, UChar const * str) { throwUnexpected(); }
  25225. virtual void setResultVarString(const char * name, unsigned sequence, const char * value) { throwUnexpected(); }
  25226. virtual void setResultVarUnicode(const char * name, unsigned sequence, UChar const * value) { throwUnexpected(); }
  25227. virtual bool getResultBool(const char * name, unsigned sequence) { throwUnexpected(); }
  25228. virtual void getResultData(unsigned & tlen, void * & tgt, const char * name, unsigned sequence) { throwUnexpected(); }
  25229. virtual void getResultDecimal(unsigned tlen, int precision, bool isSigned, void * tgt, const char * stepname, unsigned sequence) { throwUnexpected(); }
  25230. virtual void getResultRaw(unsigned & tlen, void * & tgt, const char * name, unsigned sequence, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer) { throwUnexpected(); }
  25231. virtual void getResultSet(bool & isAll, size32_t & tlen, void * & tgt, const char * name, unsigned sequence, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer) { throwUnexpected(); }
  25232. virtual __int64 getResultInt(const char * name, unsigned sequence) { throwUnexpected(); }
  25233. virtual double getResultReal(const char * name, unsigned sequence) { throwUnexpected(); }
  25234. virtual void getResultString(unsigned & tlen, char * & tgt, const char * name, unsigned sequence) { throwUnexpected(); }
  25235. virtual void getResultStringF(unsigned tlen, char * tgt, const char * name, unsigned sequence) { throwUnexpected(); }
  25236. virtual void getResultUnicode(unsigned & tlen, UChar * & tgt, const char * name, unsigned sequence) { throwUnexpected(); }
  25237. virtual char *getResultVarString(const char * name, unsigned sequence) { throwUnexpected(); }
  25238. virtual UChar *getResultVarUnicode(const char * name, unsigned sequence) { throwUnexpected(); }
  25239. virtual unsigned getResultHash(const char * name, unsigned sequence) { throwUnexpected(); }
  25240. virtual void getResultRowset(size32_t & tcount, byte * * & tgt, const char * name, unsigned sequence, IEngineRowAllocator * _rowAllocator, IOutputRowDeserializer * deserializer, bool isGrouped, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer) { throwUnexpected(); }
  25241. virtual void printResults(IXmlWriter *output, const char *name, unsigned sequence) { throwUnexpected(); }
  25242. virtual char *getWuid() { throwUnexpected(); }
  25243. virtual void getExternalResultRaw(unsigned & tlen, void * & tgt, const char * wuid, const char * stepname, unsigned sequence, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer) { throwUnexpected(); }
  25244. virtual char *getDaliServers() { throwUnexpected(); }
  25245. virtual __int64 countDiskFile(const char * lfn, unsigned recordSize) { throwUnexpected(); }
  25246. virtual char * getExpandLogicalName(const char * logicalName) { throwUnexpected(); }
  25247. virtual void addWuException(const char * text, unsigned code, unsigned severity) { throwUnexpected(); }
  25248. virtual void addWuAssertFailure(unsigned code, const char * text, const char * filename, unsigned lineno, unsigned column, bool isAbort) { throwUnexpected(); }
  25249. virtual IUserDescriptor *queryUserDescriptor() { throwUnexpected(); }
  25250. virtual unsigned __int64 getDatasetHash(const char * name, unsigned __int64 hash) { throwUnexpected(); }
  25251. virtual unsigned getRecoveringCount() { throwUnexpected(); }
  25252. virtual unsigned getNodes() { throwUnexpected(); }
  25253. virtual unsigned getNodeNum() { throwUnexpected(); }
  25254. virtual char *getFilePart(const char *logicalPart, bool create=false) { throwUnexpected(); }
  25255. virtual unsigned __int64 getFileOffset(const char *logicalPart) { throwUnexpected(); }
  25256. virtual IDistributedFileTransaction *querySuperFileTransaction() { throwUnexpected(); }
  25257. virtual char *getJobName() { throwUnexpected(); }
  25258. virtual char *getJobOwner() { throwUnexpected(); }
  25259. virtual char *getClusterName() { throwUnexpected(); }
  25260. virtual char *getGroupName() { throwUnexpected(); }
  25261. virtual char * queryIndexMetaData(char const * lfn, char const * xpath) { throwUnexpected(); }
  25262. virtual unsigned getPriority() const { throwUnexpected(); }
  25263. virtual char *getPlatform() { throwUnexpected(); }
  25264. virtual char *getEnv(const char *name, const char *defaultValue) const { throwUnexpected(); }
  25265. virtual IEngineRowAllocator * getRowAllocator(IOutputMetaData * meta, unsigned activityId) const
  25266. {
  25267. // MORE - may need to do some caching/commoning up here otherwise GRAPH in a child query may use too many
  25268. SpinBlock b(allAllocatorsLock);
  25269. IEngineRowAllocator * ret = createRoxieRowAllocator(*rowManager, meta, activityId, allAllocators.ordinality(), false);
  25270. LINK(ret);
  25271. allAllocators.append(*ret);
  25272. return ret;
  25273. }
  25274. virtual void getRowXML(size32_t & lenResult, char * & result, IOutputMetaData & info, const void * row, unsigned flags)
  25275. {
  25276. convertRowToXML(lenResult, result, info, row, flags);
  25277. }
  25278. // interface IRowAllocatorCache
  25279. virtual unsigned getActivityId(unsigned cacheId) const
  25280. {
  25281. unsigned allocatorIndex = (cacheId & ALLOCATORID_MASK);
  25282. SpinBlock b(allAllocatorsLock);
  25283. if (allAllocators.isItem(allocatorIndex))
  25284. return allAllocators.item(allocatorIndex).queryActivityId();
  25285. else
  25286. {
  25287. //assert(false);
  25288. return 12345678; // Used for tracing, better than a crash...
  25289. }
  25290. }
  25291. virtual StringBuffer &getActivityDescriptor(unsigned cacheId, StringBuffer &out) const
  25292. {
  25293. unsigned allocatorIndex = (cacheId & ALLOCATORID_MASK);
  25294. SpinBlock b(allAllocatorsLock);
  25295. if (allAllocators.isItem(allocatorIndex))
  25296. return allAllocators.item(allocatorIndex).getId(out);
  25297. else
  25298. {
  25299. assert(false);
  25300. return out.append("unknown"); // Used for tracing, better than a crash...
  25301. }
  25302. }
  25303. virtual void onDestroy(unsigned cacheId, void *row) const
  25304. {
  25305. IEngineRowAllocator *allocator;
  25306. unsigned allocatorIndex = (cacheId & ALLOCATORID_MASK);
  25307. {
  25308. SpinBlock b(allAllocatorsLock); // just protect the access to the array - don't keep locked for the call of destruct or may deadlock
  25309. if (allAllocators.isItem(allocatorIndex))
  25310. allocator = &allAllocators.item(allocatorIndex);
  25311. else
  25312. {
  25313. assert(false);
  25314. return;
  25315. }
  25316. }
  25317. if (!RoxieRowCheckValid(cacheId, row))
  25318. {
  25319. //MORE: Give an error, but don't throw an exception!
  25320. }
  25321. allocator->queryOutputMeta()->destruct((byte *) row);
  25322. }
  25323. virtual void checkValid(unsigned cacheId, const void *row) const
  25324. {
  25325. if (!RoxieRowCheckValid(cacheId, row))
  25326. {
  25327. //MORE: Throw an exception?
  25328. }
  25329. }
  25330. virtual IWorkUnit *updateWorkUnit() const
  25331. {
  25332. if (workUnit)
  25333. return &workUnit->lock();
  25334. else
  25335. return NULL;
  25336. }
  25337. virtual IConstWorkUnit *queryWorkUnit() const
  25338. {
  25339. return workUnit;
  25340. }
  25341. };
  25342. IRoxieSlaveContext *createSlaveContext(const IQueryFactory *_factory, const SlaveContextLogger &_logctx, unsigned _timeLimit, memsize_t _memoryLimit, IRoxieQueryPacket *packet)
  25343. {
  25344. return new CSlaveContext(_factory, _logctx, _timeLimit, _memoryLimit, packet, _logctx.queryTraceActivityTimes(), _logctx.queryDebuggerActive());
  25345. }
  25346. class CRoxieServerDebugContext : extends CBaseServerDebugContext
  25347. {
  25348. // Some questions:
  25349. // 1. Do we let all threads go even when say step? Probably... (may allow a thread to be suspended at some point)
  25350. // 2. Doesn't that then make a bit of a mockery of step (when there are multiple threads active)... I _think_ it actually means we DON'T try to wait for all
  25351. // threads to hit a stop, but allow any that hit stop while we are paused to be queued up to be returned by step.... perhaps actually stop them in critsec rather than
  25352. // semaphore and it all becomes easier to code... Anything calling checkBreakPoint while program state is "in debugger" will block on that critSec.
  25353. // 3. I think we need to recheck breakpoints on Roxie server but just check not deleted
  25354. public:
  25355. IRoxieSlaveContext *ctx;
  25356. CRoxieServerDebugContext(IRoxieSlaveContext *_ctx, const IContextLogger &_logctx, IPropertyTree *_queryXGMML, SafeSocket &_client)
  25357. : CBaseServerDebugContext(_logctx, _queryXGMML, _client), ctx(_ctx)
  25358. {
  25359. }
  25360. void debugCounts(IXmlWriter *output, unsigned sinceSequence, bool reset)
  25361. {
  25362. CriticalBlock b(debugCrit);
  25363. if (running)
  25364. throw MakeStringException(ROXIE_DEBUG_ERROR, "Command not available while query is running");
  25365. if (currentGraph)
  25366. currentGraph->mergeRemoteCounts(this);
  25367. CBaseServerDebugContext::debugCounts(output, sinceSequence, reset);
  25368. }
  25369. virtual void waitForDebugger(DebugState state, IActivityDebugContext *probe)
  25370. {
  25371. ctx->setWUState(WUStateDebugPaused);
  25372. CBaseServerDebugContext::waitForDebugger(state, probe);
  25373. ctx->setWUState(WUStateDebugRunning);
  25374. }
  25375. virtual bool onDebuggerTimeout()
  25376. {
  25377. return ctx->checkWuAborted();
  25378. }
  25379. virtual void debugInitialize(const char *id, const char *_queryName, bool _breakAtStart)
  25380. {
  25381. CBaseServerDebugContext::debugInitialize(id, _queryName, _breakAtStart);
  25382. Owned<IRoxieDebugSessionManager> QM = globalPackageSetManager->getRoxieDebugSessionManager();
  25383. QM->registerDebugId(id, this);
  25384. }
  25385. virtual void debugTerminate()
  25386. {
  25387. CriticalBlock b(debugCrit);
  25388. assertex(running);
  25389. currentState = DebugStateUnloaded;
  25390. running = false;
  25391. Owned<IRoxieDebugSessionManager> QM = globalPackageSetManager->getRoxieDebugSessionManager();
  25392. QM->deregisterDebugId(debugId);
  25393. if (debuggerActive)
  25394. {
  25395. debuggerSem.signal(debuggerActive);
  25396. debuggerActive = 0;
  25397. }
  25398. }
  25399. virtual IRoxieQueryPacket *onDebugCallback(const RoxiePacketHeader &header, size32_t len, char *data)
  25400. {
  25401. MemoryBuffer slaveInfo;
  25402. slaveInfo.setBuffer(len, data, false);
  25403. unsigned debugSequence;
  25404. slaveInfo.read(debugSequence);
  25405. {
  25406. CriticalBlock b(breakCrit); // we want to wait until it's our turn before updating the graph info or the counts get ahead of the current row and life is confusing
  25407. char slaveStateChar;
  25408. slaveInfo.read(slaveStateChar);
  25409. DebugState slaveState = (DebugState) slaveStateChar;
  25410. if (slaveState==DebugStateGraphFinished)
  25411. {
  25412. unsigned numCounts;
  25413. slaveInfo.read(numCounts);
  25414. while (numCounts)
  25415. {
  25416. StringAttr edgeId;
  25417. unsigned edgeCount;
  25418. slaveInfo.read(edgeId);
  25419. slaveInfo.read(edgeCount);
  25420. Owned<IGlobalEdgeRecord> thisEdge = getEdgeRecord(edgeId);
  25421. thisEdge->incrementCount(edgeCount, sequence);
  25422. numCounts--;
  25423. }
  25424. }
  25425. slaveInfo.read(currentBreakpointUID);
  25426. memsize_t slaveActivity;
  25427. unsigned channel;
  25428. __uint64 tmp;
  25429. slaveInfo.read(tmp);
  25430. slaveActivity = (memsize_t)tmp;
  25431. slaveInfo.read(channel);
  25432. assertex(currentGraph);
  25433. currentGraph->deserializeProxyGraphs(slaveState, slaveInfo, (IActivityBase *) slaveActivity, channel);
  25434. if (slaveState != DebugStateGraphFinished) // MORE - this is debatable - may (at least sometimes) want a child graph finished to be a notified event...
  25435. {
  25436. StringBuffer slaveActivityId;
  25437. slaveInfo.read(slaveActivityId);
  25438. IActivityDebugContext *slaveActivityCtx = slaveActivityId.length() ? currentGraph->lookupActivityByEdgeId(slaveActivityId.str()) : NULL;
  25439. BreakpointActionMode action = checkBreakpoint(slaveState, slaveActivityCtx , NULL);
  25440. }
  25441. }
  25442. MemoryBuffer mb;
  25443. mb.append(sizeof(RoxiePacketHeader), &header);
  25444. StringBuffer debugIdString;
  25445. debugIdString.appendf(".debug.%x", debugSequence);
  25446. mb.append(debugIdString.str());
  25447. serialize(mb);
  25448. Owned<IRoxieQueryPacket> reply = createRoxiePacket(mb);
  25449. reply->queryHeader().activityId = ROXIE_DEBUGCALLBACK;;
  25450. reply->queryHeader().retries = 0;
  25451. return reply.getClear();
  25452. }
  25453. virtual void debugPrintVariable(IXmlWriter *output, const char *name, const char *type) const
  25454. {
  25455. CriticalBlock b(debugCrit);
  25456. if (running)
  25457. throw MakeStringException(ROXIE_DEBUG_ERROR, "Command not available while query is running");
  25458. output->outputBeginNested("Variables", true);
  25459. if (!type || stricmp(type, "temporary"))
  25460. {
  25461. output->outputBeginNested("Temporary", true);
  25462. ctx->printResults(output, name, (unsigned) -3);
  25463. output->outputEndNested("Temporary");
  25464. }
  25465. if (!type || stricmp(type, "global"))
  25466. {
  25467. output->outputBeginNested("Global", true);
  25468. ctx->printResults(output, name, (unsigned) -1);
  25469. output->outputEndNested("Global");
  25470. }
  25471. output->outputEndNested("Variables");
  25472. }
  25473. };
  25474. class DeserializedDataReader : public CInterface, implements IWorkUnitRowReader
  25475. {
  25476. const ConstPointerArray &data;
  25477. unsigned idx;
  25478. public:
  25479. IMPLEMENT_IINTERFACE;
  25480. DeserializedDataReader(const ConstPointerArray &_data) : data(_data)
  25481. {
  25482. idx = 0;
  25483. }
  25484. virtual const void * nextInGroup()
  25485. {
  25486. if (data.isItem(idx))
  25487. {
  25488. const void *row = data.item(idx);
  25489. if (row)
  25490. LinkRoxieRow(row);
  25491. idx++;
  25492. return row;
  25493. }
  25494. return NULL;
  25495. }
  25496. };
  25497. class CDeserializedResultStore : public CInterface, implements IDeserializedResultStore
  25498. {
  25499. PointerArrayOf<ConstPointerArray> stored;
  25500. PointerIArrayOf<IOutputMetaData> metas;
  25501. mutable SpinLock lock;
  25502. public:
  25503. IMPLEMENT_IINTERFACE;
  25504. ~CDeserializedResultStore()
  25505. {
  25506. ForEachItemIn(idx, stored)
  25507. {
  25508. ConstPointerArray *rows = stored.item(idx);
  25509. if (rows)
  25510. {
  25511. ReleaseRoxieRowSet(*rows);
  25512. delete rows;
  25513. }
  25514. }
  25515. }
  25516. virtual int addResult(ConstPointerArray *data, IOutputMetaData *meta)
  25517. {
  25518. SpinBlock b(lock);
  25519. stored.append(data);
  25520. metas.append(meta);
  25521. return stored.ordinality()-1;
  25522. }
  25523. virtual int appendResult(int oldId, ConstPointerArray *data, IOutputMetaData *meta)
  25524. {
  25525. SpinBlock b(lock);
  25526. ConstPointerArray *oldData = stored.item(oldId);
  25527. ConstPointerArray *newData = new ConstPointerArray;
  25528. ForEachItemIn(idx, *oldData)
  25529. {
  25530. const void * row = oldData->item(idx);
  25531. if (row)
  25532. LinkRoxieRow(row);
  25533. newData->append(row);
  25534. }
  25535. ForEachItemIn(idx2, *data)
  25536. {
  25537. const void * row = data->item(idx2);
  25538. newData->append(row); // don't link these rows, because...
  25539. }
  25540. delete data; // ...then we don't need to release them when we delete this array
  25541. // Note that we don't delete the previons ConstPointerArray yet, as it could be in use.
  25542. return addResult(newData, meta);
  25543. }
  25544. virtual IWorkUnitRowReader *createDeserializedReader(int id) const
  25545. {
  25546. return new DeserializedDataReader(*stored.item(id));
  25547. }
  25548. virtual void serialize(unsigned & tlen, void * & tgt, int id, ICodeContext *codectx) const
  25549. {
  25550. IOutputMetaData *meta = metas.item(id);
  25551. ConstPointerArray *data = stored.item(id);
  25552. MemoryBuffer result;
  25553. Owned<IOutputRowSerializer> rowSerializer = meta->createRowSerializer(codectx, 0); // NOTE - we don't have a maningful activity id. Only used for error reporting.
  25554. bool grouped = meta->isGrouped();
  25555. ForEachItemIn(idx, *data)
  25556. {
  25557. const void *row = data->item(idx);
  25558. if (grouped && idx)
  25559. result.append(row == NULL);
  25560. if (row)
  25561. {
  25562. CThorDemoRowSerializer serializerTarget(result);
  25563. rowSerializer->serialize(serializerTarget, (const byte *) row);
  25564. }
  25565. }
  25566. tlen = result.length();
  25567. tgt= result.detach();
  25568. }
  25569. };
  25570. extern IDeserializedResultStore *createDeserializedResultStore()
  25571. {
  25572. return new CDeserializedResultStore;
  25573. }
  25574. class CRoxieServerContext : public CSlaveContext, implements IRoxieServerContext, implements IGlobalCodeContext
  25575. {
  25576. const IQueryFactory *serverQueryFactory;
  25577. mutable CriticalSection contextCrit;
  25578. CriticalSection daliUpdateCrit;
  25579. Owned<IPropertyTree> context;
  25580. IPropertyTree *temporaries;
  25581. CDeserializedResultStore *deserializedResultStore;
  25582. IPropertyTree *rereadResults;
  25583. Owned<IRoxiePackage> dynamicPackage;
  25584. bool isXml;
  25585. bool isRaw;
  25586. bool isBlocked;
  25587. bool isHttp;
  25588. bool sendHeartBeats;
  25589. bool trim;
  25590. XmlReaderOptions xmlStoredDatasetReadFlags;
  25591. unsigned warnTimeLimit;
  25592. unsigned lastSocketCheckTime;
  25593. unsigned lastHeartBeat;
  25594. protected:
  25595. Owned<WorkflowMachine> workflow;
  25596. SafeSocket *client;
  25597. void doPostProcess()
  25598. {
  25599. CriticalBlock b(resultsCrit); // Probably not needed
  25600. if (!isRaw && !isBlocked)
  25601. {
  25602. ForEachItemIn(seq, resultMap)
  25603. {
  25604. FlushingStringBuffer *result = resultMap.item(seq);
  25605. if (result)
  25606. result->flush(true);
  25607. }
  25608. }
  25609. if (probeQuery)
  25610. {
  25611. FlushingStringBuffer response(client, isBlocked, true, false, isHttp, *this);
  25612. // create output stream
  25613. response.startDataset("_Probe", NULL, (unsigned) -1); // initialize it
  25614. // loop through all of the graphs and create a _Probe to output each xgmml
  25615. Owned<IPropertyTreeIterator> graphs = probeQuery->getElements("Graph");
  25616. ForEach(*graphs)
  25617. {
  25618. IPropertyTree &graph = graphs->query();
  25619. StringBuffer xgmml;
  25620. _toXML(&graph, xgmml, 0);
  25621. response.append("\n");
  25622. response.append(xgmml.str());
  25623. }
  25624. }
  25625. }
  25626. IDeserializedResultStore &useResultStore(unsigned sequence)
  25627. {
  25628. checkAbort();
  25629. switch (sequence)
  25630. {
  25631. case ResultSequenceOnce:
  25632. return factory->queryOnceResultStore();
  25633. default:
  25634. // No need to have separate stores for other temporaries...
  25635. CriticalBlock b(contextCrit);
  25636. if (!deserializedResultStore)
  25637. deserializedResultStore = new CDeserializedResultStore;
  25638. return *deserializedResultStore;
  25639. }
  25640. }
  25641. IPropertyTree &useContext(unsigned sequence)
  25642. {
  25643. checkAbort();
  25644. switch (sequence)
  25645. {
  25646. case ResultSequenceStored:
  25647. if (context)
  25648. return *context;
  25649. else
  25650. throw MakeStringException(ROXIE_CODEGEN_ERROR, "Code generation error - attempting to access stored variable on slave");
  25651. case ResultSequencePersist:
  25652. throwUnexpected(); // Do not expect to see in Roxie
  25653. case ResultSequenceInternal:
  25654. {
  25655. CriticalBlock b(contextCrit);
  25656. if (!temporaries)
  25657. temporaries = createPTree();
  25658. return *temporaries;
  25659. }
  25660. case ResultSequenceOnce:
  25661. {
  25662. return factory->queryOnceContext();
  25663. }
  25664. default:
  25665. {
  25666. CriticalBlock b(contextCrit);
  25667. if (!rereadResults)
  25668. rereadResults = createPTree();
  25669. return *rereadResults;
  25670. }
  25671. }
  25672. }
  25673. void addWuException(IException *E)
  25674. {
  25675. if (workUnit)
  25676. ::addWuException(workUnit, E);
  25677. }
  25678. void init()
  25679. {
  25680. client = NULL;
  25681. totSlavesReplyLen = 0;
  25682. temporaries = NULL;
  25683. deserializedResultStore = NULL;
  25684. rereadResults = NULL;
  25685. isXml = true;
  25686. isRaw = false;
  25687. isBlocked = false;
  25688. isHttp = false;
  25689. trim = false;
  25690. priority = 0;
  25691. sendHeartBeats = false;
  25692. timeLimit = serverQueryFactory->getTimeLimit();
  25693. if (!timeLimit)
  25694. timeLimit = defaultTimeLimit[priority];
  25695. warnTimeLimit = serverQueryFactory->getWarnTimeLimit();
  25696. if (!warnTimeLimit)
  25697. warnTimeLimit = defaultWarnTimeLimit[priority];
  25698. lastSocketCheckTime = startTime;
  25699. lastHeartBeat = startTime;
  25700. ctxParallelJoinPreload = defaultParallelJoinPreload;
  25701. ctxFullKeyedJoinPreload = defaultFullKeyedJoinPreload;
  25702. ctxKeyedJoinPreload = defaultKeyedJoinPreload;
  25703. ctxConcatPreload = defaultConcatPreload;
  25704. ctxFetchPreload = defaultFetchPreload;
  25705. ctxPrefetchProjectPreload = defaultPrefetchProjectPreload;
  25706. xmlStoredDatasetReadFlags = xr_none;
  25707. traceActivityTimes = false;
  25708. }
  25709. void startWorkUnit()
  25710. {
  25711. WorkunitUpdate wu(&workUnit->lock());
  25712. if (!context->getPropBool("@outputToSocket", false))
  25713. client = NULL;
  25714. SCMStringBuffer wuParams;
  25715. if (workUnit->getXmlParams(wuParams).length())
  25716. {
  25717. // Merge in params from WU. Ones on command line take precedence though...
  25718. Owned<IPropertyTree> wuParamTree = createPTreeFromXMLString(wuParams.str(), ipt_caseInsensitive);
  25719. Owned<IPropertyTreeIterator> params = wuParamTree ->getElements("*");
  25720. ForEach(*params)
  25721. {
  25722. IPropertyTree &param = params->query();
  25723. if (!context->hasProp(param.queryName()))
  25724. context->addPropTree(param.queryName(), LINK(&param));
  25725. }
  25726. }
  25727. if (workUnit->getDebugValueBool("Debug", false))
  25728. {
  25729. bool breakAtStart = workUnit->getDebugValueBool("BreakAtStart", true);
  25730. wu->setState(WUStateDebugRunning);
  25731. SCMStringBuffer wuid;
  25732. initDebugMode(breakAtStart, workUnit->getWuid(wuid).str());
  25733. }
  25734. else
  25735. wu->setState(WUStateRunning);
  25736. }
  25737. void initDebugMode(bool breakAtStart, const char *debugUID)
  25738. {
  25739. if (!debugPermitted || !ownEP.port)
  25740. throw MakeStringException(ROXIE_ACCESS_ERROR, "Debug queries are not permitted on this system");
  25741. debugContext.setown(new CRoxieServerDebugContext(this, logctx, factory->cloneQueryXGMML(), *client));
  25742. debugContext->debugInitialize(debugUID, factory->queryQueryName(), breakAtStart);
  25743. if (workUnit)
  25744. {
  25745. WorkunitUpdate wu(&workUnit->lock());
  25746. wu->setDebugAgentListenerPort(ownEP.port); //tells debugger what port to write commands to
  25747. StringBuffer sb;
  25748. ownEP.getIpText(sb);
  25749. wu->setDebugAgentListenerIP(sb); //tells debugger what IP to write commands to
  25750. }
  25751. timeLimit = 0;
  25752. warnTimeLimit = 0;
  25753. }
  25754. public:
  25755. IMPLEMENT_IINTERFACE;
  25756. CRoxieServerContext(const IQueryFactory *_factory, const IRoxieContextLogger &_logctx)
  25757. : CSlaveContext(_factory, _logctx, 0, 0, NULL, false, false), serverQueryFactory(_factory)
  25758. {
  25759. init();
  25760. rowManager->setMemoryLimit(serverQueryFactory->getMemoryLimit());
  25761. workflow.setown(_factory->createWorkflowMachine(true, logctx));
  25762. context.setown(createPTree(ipt_caseInsensitive));
  25763. }
  25764. CRoxieServerContext(IConstWorkUnit *_workUnit, const IQueryFactory *_factory, const IRoxieContextLogger &_logctx)
  25765. : CSlaveContext(_factory, _logctx, 0, 0, NULL, false, false), serverQueryFactory(_factory)
  25766. {
  25767. init();
  25768. workUnit.set(_workUnit);
  25769. rowManager->setMemoryLimit(serverQueryFactory->getMemoryLimit());
  25770. workflow.setown(_factory->createWorkflowMachine(false, logctx));
  25771. context.setown(createPTree(ipt_caseInsensitive));
  25772. startWorkUnit();
  25773. }
  25774. CRoxieServerContext(IPropertyTree *_context, const IQueryFactory *_factory, SafeSocket &_client, bool _isXml, bool _isRaw, bool _isBlocked, HttpHelper &httpHelper, bool _trim, unsigned _priority, const IRoxieContextLogger &_logctx, XmlReaderOptions _xmlReadFlags)
  25775. : CSlaveContext(_factory, _logctx, 0, 0, NULL, false, false), serverQueryFactory(_factory)
  25776. {
  25777. init();
  25778. context.set(_context);
  25779. client = &_client;
  25780. isXml = _isXml;
  25781. isRaw = _isRaw;
  25782. isBlocked = _isBlocked;
  25783. isHttp = httpHelper.isHttp();
  25784. trim = _trim;
  25785. priority = _priority;
  25786. xmlStoredDatasetReadFlags = _xmlReadFlags;
  25787. sendHeartBeats = enableHeartBeat && isRaw && isBlocked && priority==0;
  25788. timeLimit = context->getPropInt("_TimeLimit", timeLimit);
  25789. warnTimeLimit = context->getPropInt("_warnTimeLimit", warnTimeLimit);
  25790. const char *wuid = context->queryProp("@wuid");
  25791. if (wuid)
  25792. {
  25793. IRoxieDaliHelper *daliHelper = checkDaliConnection();
  25794. assertex(daliHelper );
  25795. workUnit.setown(daliHelper->attachWorkunit(wuid, _factory->queryDll()));
  25796. if (!workUnit)
  25797. throw MakeStringException(ROXIE_DALI_ERROR, "Failed to open workunit %s", wuid);
  25798. startWorkUnit();
  25799. }
  25800. else if (context->getPropBool("@debug", false))
  25801. {
  25802. bool breakAtStart = context->getPropBool("@break", true);
  25803. const char *debugUID = context->queryProp("@uid");
  25804. if (debugUID && *debugUID)
  25805. initDebugMode(breakAtStart, debugUID);
  25806. }
  25807. else if (context->getPropBool("_Probe", false))
  25808. probeQuery.setown(_factory->cloneQueryXGMML());
  25809. // MORE some of these might be appropriate in wu case too?
  25810. rowManager->setActivityTracking(context->getPropBool("_TraceMemory", false));
  25811. rowManager->setMemoryLimit((memsize_t) context->getPropInt64("_MemoryLimit", _factory->getMemoryLimit()));
  25812. authToken.append(httpHelper.queryAuthToken());
  25813. workflow.setown(_factory->createWorkflowMachine(false, logctx));
  25814. ctxParallelJoinPreload = context->getPropInt("_ParallelJoinPreload", defaultParallelJoinPreload);
  25815. ctxFullKeyedJoinPreload = context->getPropInt("_FullKeyedJoinPreload", defaultFullKeyedJoinPreload);
  25816. ctxKeyedJoinPreload = context->getPropInt("_KeyedJoinPreload", defaultKeyedJoinPreload);
  25817. ctxConcatPreload = context->getPropInt("_ConcatPreload", defaultConcatPreload);
  25818. ctxFetchPreload = context->getPropInt("_FetchPreload", defaultFetchPreload);
  25819. ctxPrefetchProjectPreload = context->getPropInt("_PrefetchProjectPreload", defaultPrefetchProjectPreload);
  25820. traceActivityTimes = context->getPropBool("_TraceActivityTimes", false) || context->getPropBool("@timing", false);
  25821. }
  25822. ~CRoxieServerContext()
  25823. {
  25824. dynamicPackage.clear(); // do this before disconnect from dali
  25825. ::Release(rereadResults);
  25826. ::Release(temporaries);
  25827. ::Release(deserializedResultStore);
  25828. }
  25829. virtual roxiemem::IRowManager &queryRowManager()
  25830. {
  25831. return *rowManager;
  25832. }
  25833. virtual IRoxieDaliHelper *checkDaliConnection()
  25834. {
  25835. CriticalBlock b(daliUpdateCrit);
  25836. if (!daliHelperLink)
  25837. daliHelperLink.setown(::connectToDali());
  25838. return daliHelperLink;
  25839. }
  25840. virtual void checkAbort()
  25841. {
  25842. CSlaveContext::checkAbort();
  25843. unsigned ticksNow = msTick();
  25844. if (warnTimeLimit)
  25845. {
  25846. unsigned elapsed = ticksNow - startTime;
  25847. if (elapsed > warnTimeLimit)
  25848. {
  25849. CriticalBlock b(abortLock);
  25850. if (elapsed > warnTimeLimit) // we don't want critsec on the first check (for efficiency) but check again inside the critsec
  25851. {
  25852. logOperatorException(NULL, NULL, 0, "SLOW (%d ms): %s", elapsed, factory->queryQueryName());
  25853. warnTimeLimit = elapsed + warnTimeLimit;
  25854. }
  25855. }
  25856. }
  25857. if (client)
  25858. {
  25859. if (socketCheckInterval)
  25860. {
  25861. if (ticksNow - lastSocketCheckTime > socketCheckInterval)
  25862. {
  25863. CriticalBlock b(abortLock);
  25864. if (!client->checkConnection())
  25865. throw MakeStringException(ROXIE_CLIENT_CLOSED, "Client socket closed");
  25866. lastSocketCheckTime = ticksNow;
  25867. }
  25868. }
  25869. if (sendHeartBeats)
  25870. {
  25871. unsigned hb = ticksNow - lastHeartBeat;
  25872. if (hb > 30000)
  25873. {
  25874. lastHeartBeat = msTick();
  25875. client->sendHeartBeat(*this);
  25876. }
  25877. }
  25878. }
  25879. }
  25880. virtual unsigned getXmlFlags() const
  25881. {
  25882. return trim ? XWFtrim|XWFopt : XWFexpandempty;
  25883. }
  25884. virtual unsigned getMemoryUsage()
  25885. {
  25886. return rowManager->getMemoryUsage();
  25887. }
  25888. virtual unsigned getSlavesReplyLen()
  25889. {
  25890. return totSlavesReplyLen;
  25891. }
  25892. virtual void process()
  25893. {
  25894. EclProcessFactory pf = (EclProcessFactory) factory->queryDll()->getEntry("createProcess");
  25895. Owned<IEclProcess> p = pf();
  25896. try
  25897. {
  25898. if (debugContext)
  25899. debugContext->checkBreakpoint(DebugStateReady, NULL, NULL);
  25900. if (workflow)
  25901. workflow->perform(this, p);
  25902. else
  25903. p->perform(this, 0);
  25904. }
  25905. catch(WorkflowException *E)
  25906. {
  25907. if (debugContext)
  25908. debugContext->checkBreakpoint(DebugStateException, NULL, static_cast<IException *>(E));
  25909. addWuException(E);
  25910. doPostProcess();
  25911. throw;
  25912. }
  25913. catch(IException *E)
  25914. {
  25915. if (debugContext)
  25916. debugContext->checkBreakpoint(DebugStateException, NULL, E);
  25917. addWuException(E);
  25918. doPostProcess();
  25919. throw;
  25920. }
  25921. catch(...)
  25922. {
  25923. if (debugContext)
  25924. debugContext->checkBreakpoint(DebugStateFailed, NULL, NULL);
  25925. if (workUnit)
  25926. {
  25927. Owned<IException> E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception caught in CRoxieServerContext::process");
  25928. addWuException(E);
  25929. }
  25930. doPostProcess();
  25931. throw;
  25932. }
  25933. if (debugContext)
  25934. debugContext->checkBreakpoint(DebugStateFinished, NULL, NULL);
  25935. doPostProcess();
  25936. }
  25937. virtual void done(bool failed)
  25938. {
  25939. if (debugContext)
  25940. debugContext->debugTerminate();
  25941. setWUState(aborted ? WUStateAborted : (failed ? WUStateFailed : WUStateCompleted));
  25942. }
  25943. virtual ICodeContext *queryCodeContext()
  25944. {
  25945. return this;
  25946. }
  25947. virtual IRoxieServerContext *queryServerContext()
  25948. {
  25949. return this;
  25950. }
  25951. virtual IGlobalCodeContext *queryGlobalCodeContext()
  25952. {
  25953. return this;
  25954. }
  25955. // interface ICodeContext
  25956. virtual FlushingStringBuffer *queryResult(unsigned sequence)
  25957. {
  25958. if (!client && workUnit)
  25959. return NULL; // when outputting to workunit only, don't output anything to stdout
  25960. CriticalBlock procedure(resultsCrit);
  25961. while (!resultMap.isItem(sequence))
  25962. resultMap.append(NULL);
  25963. FlushingStringBuffer *result = resultMap.item(sequence);
  25964. if (!result)
  25965. {
  25966. result = new FlushingStringBuffer(client, isBlocked, isXml, isRaw, isHttp, *this);
  25967. result->isSoap = isHttp;
  25968. result->trim = trim;
  25969. result->queryName.set(context->queryName());
  25970. resultMap.replace(result, sequence);
  25971. }
  25972. return result;
  25973. }
  25974. virtual void setResultBool(const char *name, unsigned sequence, bool value)
  25975. {
  25976. if (isSpecialResultSequence(sequence))
  25977. {
  25978. CriticalBlock b(contextCrit);
  25979. useContext(sequence).setPropBool(name, value);
  25980. }
  25981. else
  25982. {
  25983. FlushingStringBuffer *r = queryResult(sequence);
  25984. if (r)
  25985. {
  25986. r->startScalar(name, sequence);
  25987. if (isRaw)
  25988. r->append(sizeof(value), (char *)&value);
  25989. else
  25990. r->append(value ? "true" : "false");
  25991. }
  25992. }
  25993. if (workUnit)
  25994. {
  25995. try
  25996. {
  25997. WorkunitUpdate wu(&workUnit->lock());
  25998. CriticalBlock b(daliUpdateCrit); // MORE - do we really need these locks?
  25999. wu->setResultBool(name, sequence, value);
  26000. }
  26001. catch(IException *e)
  26002. {
  26003. StringBuffer text;
  26004. e->errorMessage(text);
  26005. CTXLOG("Error trying to update dali: %s", text.str());
  26006. e->Release();
  26007. }
  26008. catch(...)
  26009. {
  26010. CTXLOG("Unknown exception trying to update dali");
  26011. }
  26012. }
  26013. }
  26014. virtual void setResultData(const char *name, unsigned sequence, int len, const void * data)
  26015. {
  26016. static char hexchar[] = "0123456789ABCDEF";
  26017. if (isSpecialResultSequence(sequence))
  26018. {
  26019. StringBuffer s;
  26020. const byte *field = (const byte *) data;
  26021. for (int i = 0; i < len; i++)
  26022. s.append(hexchar[field[i] >> 4]).append(hexchar[field[i] & 0x0f]);
  26023. CriticalBlock b(contextCrit);
  26024. IPropertyTree &ctx = useContext(sequence);
  26025. ctx.setProp(name, s.str());
  26026. }
  26027. else
  26028. {
  26029. FlushingStringBuffer *r = queryResult(sequence);
  26030. if (r)
  26031. {
  26032. r->startScalar(name, sequence);
  26033. if (isRaw)
  26034. r->append(len, (const char *) data);
  26035. else
  26036. {
  26037. const byte *field = (const byte *) data;
  26038. for (int i = 0; i < len; i++)
  26039. {
  26040. r->append(hexchar[field[i] >> 4]);
  26041. r->append(hexchar[field[i] & 0x0f]);
  26042. }
  26043. }
  26044. }
  26045. }
  26046. if (workUnit)
  26047. {
  26048. try
  26049. {
  26050. WorkunitUpdate wu(&workUnit->lock());
  26051. CriticalBlock b(daliUpdateCrit);
  26052. wu->setResultData(name, sequence, len, data);
  26053. }
  26054. catch(IException *e)
  26055. {
  26056. StringBuffer text;
  26057. e->errorMessage(text);
  26058. CTXLOG("Error trying to update dali: %s", text.str());
  26059. e->Release();
  26060. }
  26061. catch(...)
  26062. {
  26063. CTXLOG("Unknown exception trying to update dali");
  26064. }
  26065. }
  26066. }
  26067. virtual void appendResultDeserialized(const char *name, unsigned sequence, ConstPointerArray *data, bool extend, IOutputMetaData *meta)
  26068. {
  26069. CriticalBlock b(contextCrit);
  26070. IPropertyTree &ctx = useContext(sequence);
  26071. IDeserializedResultStore &resultStore = useResultStore(sequence);
  26072. IPropertyTree *val = ctx.queryPropTree(name);
  26073. if (extend && val)
  26074. {
  26075. int old = val->getPropInt("@id", -1);
  26076. assertex(old!=-1);
  26077. val->setPropInt("@id", resultStore.appendResult(old, data, meta));
  26078. }
  26079. else
  26080. {
  26081. if (!val)
  26082. val = ctx.addPropTree(name, createPTree());
  26083. val->setProp("@format", "deserialized");
  26084. val->setPropInt("@id", resultStore.addResult(data, meta));
  26085. }
  26086. }
  26087. virtual void appendResultRawContext(const char *name, unsigned sequence, int len, const void * data, int numRows, bool extend, bool saveInContext)
  26088. {
  26089. if (saveInContext)
  26090. {
  26091. CriticalBlock b(contextCrit);
  26092. IPropertyTree &ctx = useContext(sequence);
  26093. ctx.appendPropBin(name, len, data);
  26094. ctx.queryPropTree(name)->setProp("@format", "raw");
  26095. }
  26096. if (workUnit)
  26097. {
  26098. try
  26099. {
  26100. WorkunitUpdate wu(&workUnit->lock());
  26101. CriticalBlock b(daliUpdateCrit);
  26102. wu->setResultDataset(name, sequence, len, data, numRows, extend);
  26103. }
  26104. catch(IException *e)
  26105. {
  26106. StringBuffer text;
  26107. e->errorMessage(text);
  26108. CTXLOG("Error trying to update dali: %s", text.str());
  26109. e->Release();
  26110. }
  26111. catch(...)
  26112. {
  26113. CTXLOG("Unknown exception trying to update dali");
  26114. }
  26115. }
  26116. }
  26117. virtual void setResultRaw(const char *name, unsigned sequence, int len, const void * data)
  26118. {
  26119. if (isSpecialResultSequence(sequence))
  26120. {
  26121. CriticalBlock b(contextCrit);
  26122. IPropertyTree &ctx = useContext(sequence);
  26123. ctx.setPropBin(name, len, data);
  26124. ctx.queryPropTree(name)->setProp("@format", "raw");
  26125. }
  26126. else
  26127. {
  26128. FlushingStringBuffer *r = queryResult(sequence);
  26129. if (r)
  26130. {
  26131. r->startScalar(name, sequence);
  26132. if (isRaw)
  26133. r->append(len, (const char *) data);
  26134. else
  26135. UNIMPLEMENTED;
  26136. }
  26137. }
  26138. if (workUnit)
  26139. {
  26140. try
  26141. {
  26142. WorkunitUpdate wu(&workUnit->lock());
  26143. CriticalBlock b(daliUpdateCrit);
  26144. wu->setResultRaw(name, sequence, len, data);
  26145. }
  26146. catch(IException *e)
  26147. {
  26148. StringBuffer text;
  26149. e->errorMessage(text);
  26150. CTXLOG("Error trying to update dali: %s", text.str());
  26151. e->Release();
  26152. }
  26153. catch(...)
  26154. {
  26155. CTXLOG("Unknown exception trying to update dali");
  26156. }
  26157. }
  26158. }
  26159. virtual void setResultSet(const char *name, unsigned sequence, bool isAll, size32_t len, const void * data, ISetToXmlTransformer * transformer)
  26160. {
  26161. if (isSpecialResultSequence(sequence))
  26162. {
  26163. CriticalBlock b(contextCrit);
  26164. IPropertyTree &ctx = useContext(sequence);
  26165. ctx.setPropBin(name, len, data);
  26166. ctx.queryPropTree(name)->setProp("@format", "raw");
  26167. ctx.queryPropTree(name)->setPropBool("@isAll", isAll);
  26168. }
  26169. else
  26170. {
  26171. FlushingStringBuffer *r = queryResult(sequence);
  26172. if (r)
  26173. {
  26174. r->startScalar(name, sequence);
  26175. if (isRaw)
  26176. r->append(len, (char *)data);
  26177. else if (isXml)
  26178. {
  26179. assertex(transformer);
  26180. CommonXmlWriter xmlwrite(getXmlFlags()|XWFnoindent, 0);
  26181. transformer->toXML(isAll, len, (byte *)data, xmlwrite);
  26182. r->append(xmlwrite.str());
  26183. }
  26184. else
  26185. {
  26186. assertex(transformer);
  26187. r->append('[');
  26188. if (isAll)
  26189. r->appendf("*]");
  26190. else
  26191. {
  26192. SimpleOutputWriter x;
  26193. transformer->toXML(isAll, len, (const byte *) data, x);
  26194. r->appendf("%s]", x.str());
  26195. }
  26196. }
  26197. }
  26198. }
  26199. if (workUnit)
  26200. {
  26201. try
  26202. {
  26203. WorkunitUpdate wu(&workUnit->lock());
  26204. CriticalBlock b(daliUpdateCrit);
  26205. wu->setResultSet(name, sequence, isAll, len, data, transformer);
  26206. }
  26207. catch(IException *e)
  26208. {
  26209. StringBuffer text;
  26210. e->errorMessage(text);
  26211. CTXLOG("Error trying to update dali: %s", text.str());
  26212. e->Release();
  26213. }
  26214. catch(...)
  26215. {
  26216. CTXLOG("Unknown exception trying to update dali");
  26217. }
  26218. }
  26219. }
  26220. virtual void setResultXml(const char *name, unsigned sequence, const char *xml)
  26221. {
  26222. CriticalBlock b(contextCrit);
  26223. useContext(sequence).setPropTree(name, createPTreeFromXMLString(xml, ipt_caseInsensitive));
  26224. }
  26225. virtual void setResultDecimal(const char *name, unsigned sequence, int len, int precision, bool isSigned, const void *val)
  26226. {
  26227. if (isSpecialResultSequence(sequence))
  26228. {
  26229. MemoryBuffer m;
  26230. serializeFixedData(len, val, m);
  26231. CriticalBlock b(contextCrit);
  26232. useContext(sequence).setPropBin(name, m.length(), m.toByteArray());
  26233. }
  26234. else
  26235. {
  26236. FlushingStringBuffer *r = queryResult(sequence);
  26237. if (r)
  26238. {
  26239. r->startScalar(name, sequence);
  26240. if (isRaw)
  26241. r->append(len, (char *)val);
  26242. else
  26243. {
  26244. StringBuffer s;
  26245. if (isSigned)
  26246. outputXmlDecimal(val, len, precision, NULL, s);
  26247. else
  26248. outputXmlUDecimal(val, len, precision, NULL, s);
  26249. r->append(s);
  26250. }
  26251. }
  26252. }
  26253. if (workUnit)
  26254. {
  26255. try
  26256. {
  26257. WorkunitUpdate wu(&workUnit->lock());
  26258. CriticalBlock b(daliUpdateCrit);
  26259. wu->setResultDecimal(name, sequence, len, precision, isSigned, val);
  26260. }
  26261. catch(IException *e)
  26262. {
  26263. StringBuffer text;
  26264. e->errorMessage(text);
  26265. CTXLOG("Error trying to update dali: %s", text.str());
  26266. e->Release();
  26267. }
  26268. catch(...)
  26269. {
  26270. CTXLOG("Unknown exception trying to update dali");
  26271. }
  26272. }
  26273. }
  26274. virtual void setResultInt(const char *name, unsigned sequence, __int64 value)
  26275. {
  26276. if (isSpecialResultSequence(sequence))
  26277. {
  26278. CriticalBlock b(contextCrit);
  26279. useContext(sequence).setPropInt64(name, value);
  26280. }
  26281. else
  26282. {
  26283. FlushingStringBuffer *r = queryResult(sequence);
  26284. if (r)
  26285. {
  26286. r->startScalar(name, sequence);
  26287. if (isRaw)
  26288. r->append(sizeof(value), (char *)&value);
  26289. else
  26290. r->appendf("%"I64F"d", value);
  26291. }
  26292. }
  26293. if (workUnit)
  26294. {
  26295. try
  26296. {
  26297. WorkunitUpdate wu(&workUnit->lock());
  26298. CriticalBlock b(daliUpdateCrit);
  26299. wu->setResultInt(name, sequence, value);
  26300. }
  26301. catch(IException *e)
  26302. {
  26303. StringBuffer text;
  26304. e->errorMessage(text);
  26305. CTXLOG("Error trying to update dali: %s", text.str());
  26306. e->Release();
  26307. }
  26308. catch(...)
  26309. {
  26310. CTXLOG("Unknown exception trying to update dali");
  26311. }
  26312. }
  26313. }
  26314. virtual void setResultUInt(const char *name, unsigned sequence, unsigned __int64 value)
  26315. {
  26316. if (isSpecialResultSequence(sequence))
  26317. {
  26318. CriticalBlock b(contextCrit);
  26319. useContext(sequence).setPropInt64(name, value);
  26320. }
  26321. else
  26322. {
  26323. FlushingStringBuffer *r = queryResult(sequence);
  26324. if (r)
  26325. {
  26326. r->startScalar(name, sequence);
  26327. if (isRaw)
  26328. r->append(sizeof(value), (char *)&value);
  26329. else
  26330. r->appendf("%"I64F"u", value);
  26331. }
  26332. }
  26333. if (workUnit)
  26334. {
  26335. try
  26336. {
  26337. WorkunitUpdate wu(&workUnit->lock());
  26338. CriticalBlock b(daliUpdateCrit);
  26339. wu->setResultUInt(name, sequence, value);
  26340. }
  26341. catch(IException *e)
  26342. {
  26343. StringBuffer text;
  26344. e->errorMessage(text);
  26345. CTXLOG("Error trying to update dali: %s", text.str());
  26346. e->Release();
  26347. }
  26348. catch(...)
  26349. {
  26350. CTXLOG("Unknown exception trying to update dali");
  26351. }
  26352. }
  26353. }
  26354. virtual void setResultReal(const char *name, unsigned sequence, double value)
  26355. {
  26356. if (isSpecialResultSequence(sequence))
  26357. {
  26358. CriticalBlock b(contextCrit);
  26359. useContext(sequence).setPropBin(name, sizeof(value), &value);
  26360. }
  26361. else
  26362. {
  26363. StringBuffer v;
  26364. v.append(value);
  26365. FlushingStringBuffer *r = queryResult(sequence);
  26366. if (r)
  26367. {
  26368. r->startScalar(name, sequence);
  26369. if (r->isRaw)
  26370. r->append(sizeof(value), (char *)&value);
  26371. else
  26372. r->appendf("%s", v.str());
  26373. }
  26374. }
  26375. if (workUnit)
  26376. {
  26377. try
  26378. {
  26379. WorkunitUpdate wu(&workUnit->lock());
  26380. CriticalBlock b(daliUpdateCrit);
  26381. wu->setResultReal(name, sequence, value);
  26382. }
  26383. catch(IException *e)
  26384. {
  26385. StringBuffer text;
  26386. e->errorMessage(text);
  26387. CTXLOG("Error trying to update dali: %s", text.str());
  26388. e->Release();
  26389. }
  26390. catch(...)
  26391. {
  26392. CTXLOG("Unknown exception trying to update dali");
  26393. }
  26394. }
  26395. }
  26396. virtual void setResultString(const char *name, unsigned sequence, int len, const char * str)
  26397. {
  26398. if (isSpecialResultSequence(sequence))
  26399. {
  26400. CriticalBlock b(contextCrit);
  26401. useContext(sequence).setPropBin(name, len, str);
  26402. }
  26403. else
  26404. {
  26405. FlushingStringBuffer *r = queryResult(sequence);
  26406. if (r)
  26407. {
  26408. r->startScalar(name, sequence);
  26409. if (r->isRaw)
  26410. {
  26411. r->append(len, str);
  26412. }
  26413. else
  26414. {
  26415. r->encodeXML(str, 0, len);
  26416. }
  26417. }
  26418. }
  26419. if (workUnit)
  26420. {
  26421. try
  26422. {
  26423. WorkunitUpdate wu(&workUnit->lock());
  26424. CriticalBlock b(daliUpdateCrit);
  26425. wu->setResultString(name, sequence, len, str);
  26426. }
  26427. catch(IException *e)
  26428. {
  26429. StringBuffer text;
  26430. e->errorMessage(text);
  26431. CTXLOG("Error trying to update dali: %s", text.str());
  26432. e->Release();
  26433. }
  26434. catch(...)
  26435. {
  26436. CTXLOG("Unknown exception trying to update dali");
  26437. }
  26438. }
  26439. }
  26440. virtual void setResultUnicode(const char *name, unsigned sequence, int len, UChar const * str)
  26441. {
  26442. if (isSpecialResultSequence(sequence))
  26443. {
  26444. rtlDataAttr buff;
  26445. unsigned bufflen = 0;
  26446. rtlUnicodeToCodepageX(bufflen, buff.refstr(), len, str, "utf-8");
  26447. CriticalBlock b(contextCrit);
  26448. useContext(sequence).setPropBin(name, bufflen, buff.getstr());
  26449. }
  26450. else
  26451. {
  26452. FlushingStringBuffer *r = queryResult(sequence);
  26453. if (r)
  26454. {
  26455. r->startScalar(name, sequence);
  26456. if (r->isRaw)
  26457. {
  26458. r->append(len*2, (const char *) str);
  26459. }
  26460. else
  26461. {
  26462. rtlDataAttr buff;
  26463. unsigned bufflen = 0;
  26464. rtlUnicodeToCodepageX(bufflen, buff.refstr(), len, str, "utf-8");
  26465. r->encodeXML(buff.getstr(), 0, bufflen, true); // output as UTF-8
  26466. }
  26467. }
  26468. }
  26469. if (workUnit)
  26470. {
  26471. try
  26472. {
  26473. WorkunitUpdate wu(&workUnit->lock());
  26474. CriticalBlock b(daliUpdateCrit);
  26475. wu->setResultUnicode(name, sequence, len, str);
  26476. }
  26477. catch(IException *e)
  26478. {
  26479. StringBuffer text;
  26480. e->errorMessage(text);
  26481. CTXLOG("Error trying to update dali: %s", text.str());
  26482. e->Release();
  26483. }
  26484. catch(...)
  26485. {
  26486. CTXLOG("Unknown exception trying to update dali");
  26487. }
  26488. }
  26489. }
  26490. virtual void setResultVarString(const char * name, unsigned sequence, const char * value)
  26491. {
  26492. setResultString(name, sequence, strlen(value), value);
  26493. }
  26494. virtual void setResultVarUnicode(const char * name, unsigned sequence, UChar const * value)
  26495. {
  26496. setResultUnicode(name, sequence, rtlUnicodeStrlen(value), value);
  26497. }
  26498. virtual void setResultDataset(const char * name, unsigned sequence, size32_t len, const void *data, unsigned numRows, bool extend)
  26499. {
  26500. appendResultRawContext(name, sequence, len, data, numRows, extend, true);
  26501. }
  26502. virtual void getResultDecimal(unsigned tlen, int precision, bool isSigned, void * tgt, const char * stepname, unsigned sequence)
  26503. {
  26504. if (isSpecialResultSequence(sequence))
  26505. {
  26506. MemoryBuffer m;
  26507. CriticalBlock b(contextCrit);
  26508. useContext(sequence).getPropBin(stepname, m);
  26509. if (m.length())
  26510. {
  26511. assertex(m.length() == tlen);
  26512. m.read(tlen, tgt);
  26513. }
  26514. else
  26515. memset(tgt, 0, tlen);
  26516. }
  26517. else
  26518. {
  26519. StringBuffer x;
  26520. {
  26521. CriticalBlock b(contextCrit);
  26522. useContext(sequence).getProp(stepname, x);
  26523. }
  26524. TempDecimal d;
  26525. d.setString(x.length(), x.str());
  26526. if (isSigned)
  26527. d.getDecimal(tlen, precision, tgt);
  26528. else
  26529. d.getUDecimal(tlen, precision, tgt);
  26530. }
  26531. }
  26532. virtual bool getResultBool(const char * name, unsigned sequence)
  26533. {
  26534. CriticalBlock b(contextCrit);
  26535. return useContext(sequence).getPropBool(name);
  26536. }
  26537. static unsigned hex2digit(char c)
  26538. {
  26539. // MORE - what about error cases?
  26540. if (c >= 'a')
  26541. return (c - 'a' + 10);
  26542. else if (c >= 'A')
  26543. return (c - 'A' + 10);
  26544. return (c - '0');
  26545. }
  26546. virtual void getResultData(unsigned & tlen, void * & tgt, const char * name, unsigned sequence)
  26547. {
  26548. MemoryBuffer result;
  26549. CriticalBlock b(contextCrit);
  26550. const char *val = useContext(sequence).queryProp(name);
  26551. if (val)
  26552. {
  26553. loop
  26554. {
  26555. char c0 = *val++;
  26556. if (!c0)
  26557. break;
  26558. char c1 = *val++;
  26559. if (!c1)
  26560. break; // Shouldn't really happen - we expect even length
  26561. unsigned c2 = (hex2digit(c0) << 4) | hex2digit(c1);
  26562. result.append((unsigned char) c2);
  26563. }
  26564. }
  26565. tlen = result.length();
  26566. tgt = result.detach();
  26567. }
  26568. void doExtractRawResultX(unsigned & tlen, void * & tgt, IPropertyTree *val, unsigned sequence, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer, bool isSet)
  26569. {
  26570. tgt = NULL;
  26571. tlen = 0;
  26572. if (val)
  26573. {
  26574. if (val->isBinary())
  26575. {
  26576. MemoryBuffer m;
  26577. val->getPropBin(NULL, m);
  26578. tlen = m.length();
  26579. tgt= m.detach();
  26580. }
  26581. else
  26582. {
  26583. const char *format = val->queryProp("@format");
  26584. if (!format || strcmp(format, "xml")==0)
  26585. {
  26586. assertex(xmlTransformer);
  26587. Variable2IDataVal result(&tlen, &tgt);
  26588. CXmlToRawTransformer rawTransformer(*xmlTransformer, xmlStoredDatasetReadFlags);
  26589. rawTransformer.transformTree(result, *val, !isSet);
  26590. }
  26591. else if (strcmp(format, "deserialized")==0)
  26592. {
  26593. IDeserializedResultStore &resultStore = useResultStore(sequence);
  26594. resultStore.serialize(tlen, tgt, val->getPropInt("@id", -1), queryCodeContext());
  26595. }
  26596. else if (strcmp(format, "csv")==0)
  26597. {
  26598. // MORE - never tested this code.....
  26599. assertex(csvTransformer);
  26600. Variable2IDataVal result(&tlen, &tgt);
  26601. MemoryBuffer m;
  26602. val->getPropBin(NULL, m);
  26603. CCsvToRawTransformer rawCsvTransformer(*csvTransformer);
  26604. rawCsvTransformer.transform(result, m.length(), m.toByteArray(), !isSet);
  26605. }
  26606. else
  26607. throw MakeStringException(ROXIE_UNIMPLEMENTED_ERROR, "no transform function available");
  26608. }
  26609. }
  26610. }
  26611. void doExtractRawResultF(unsigned tlen, void * tgt, IPropertyTree *val, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer, bool isSet)
  26612. {
  26613. if (!val)
  26614. throw MakeStringException(ROXIE_UNIMPLEMENTED_ERROR, "no value for result");
  26615. if (val->isBinary())
  26616. {
  26617. try
  26618. {
  26619. //Slightly weird usage - provide the buffer to MemoryBuffer to avoid an allocation and extra copy
  26620. MemoryBuffer m;
  26621. m.setBuffer(tlen, tgt, false);
  26622. m.setLength(0);
  26623. val->getPropBin(NULL, m);
  26624. }
  26625. catch (IException * e)
  26626. {
  26627. e->Release();
  26628. throw MakeStringException(ROXIE_UNIMPLEMENTED_ERROR, "result larger that expected");
  26629. }
  26630. }
  26631. else if (xmlTransformer)
  26632. {
  26633. Fixed2IDataVal result(tlen, tgt);
  26634. CXmlToRawTransformer rawTransformer(*xmlTransformer, xmlStoredDatasetReadFlags);
  26635. rawTransformer.transformTree(result, *val, !isSet);
  26636. }
  26637. else if (csvTransformer)
  26638. {
  26639. // MORE - never tested this code.....
  26640. Fixed2IDataVal result(tlen, tgt);
  26641. MemoryBuffer m;
  26642. val->getPropBin(NULL, m);
  26643. CCsvToRawTransformer rawCsvTransformer(*csvTransformer);
  26644. rawCsvTransformer.transform(result, m.length(), m.toByteArray(), !isSet);
  26645. }
  26646. else
  26647. throw MakeStringException(ROXIE_UNIMPLEMENTED_ERROR, "no transform function available");
  26648. }
  26649. virtual void getResultRaw(unsigned & tlen, void * & tgt, const char *stepname, unsigned sequence, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer)
  26650. {
  26651. try
  26652. {
  26653. CriticalBlock b(contextCrit);
  26654. IPropertyTree &ctx = useContext(sequence);
  26655. IPropertyTree *val = ctx.queryPropTree(stepname);
  26656. doExtractRawResultX(tlen, tgt, val, sequence, xmlTransformer, csvTransformer, false);
  26657. }
  26658. catch (IException * e)
  26659. {
  26660. StringBuffer text;
  26661. e->errorMessage(text);
  26662. e->Release();
  26663. throw MakeStringException(ROXIE_DATA_ERROR, "Failed to retrieve data value \"%s\". [%s]", stepname, text.str());
  26664. }
  26665. catch (...)
  26666. {
  26667. throw MakeStringException(ROXIE_DATA_ERROR, "Failed to retrieve data value \"%s\"", stepname);
  26668. }
  26669. }
  26670. virtual void getResultRowset(size32_t & tcount, byte * * & tgt, const char * stepname, unsigned sequence, IEngineRowAllocator * _rowAllocator, IOutputRowDeserializer * deserializer, bool isGrouped, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer)
  26671. {
  26672. try
  26673. {
  26674. bool atEOG = true;
  26675. Owned<IWorkUnitRowReader> wuReader = getWorkunitRowReader(stepname, sequence, xmlTransformer, _rowAllocator, isGrouped);
  26676. RtlLinkedDatasetBuilder builder(_rowAllocator);
  26677. loop
  26678. {
  26679. const void *ret = wuReader->nextInGroup();
  26680. if (!ret)
  26681. {
  26682. if (atEOG || !isGrouped)
  26683. break;
  26684. atEOG = true;
  26685. }
  26686. else
  26687. atEOG = false;
  26688. builder.appendOwn(ret);
  26689. }
  26690. tcount = builder.getcount();
  26691. tgt = builder.linkrows();
  26692. }
  26693. catch (IException * e)
  26694. {
  26695. StringBuffer text;
  26696. e->errorMessage(text);
  26697. e->Release();
  26698. throw MakeStringException(ROXIE_DATA_ERROR, "Failed to retrieve data value \"%s\". [%s]", stepname, text.str());
  26699. }
  26700. catch (...)
  26701. {
  26702. throw MakeStringException(ROXIE_DATA_ERROR, "Failed to retrieve data value \"%s\"", stepname);
  26703. }
  26704. }
  26705. virtual void getResultSet(bool & tisAll, unsigned & tlen, void * & tgt, const char *stepname, unsigned sequence, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer)
  26706. {
  26707. try
  26708. {
  26709. CriticalBlock b(contextCrit);
  26710. IPropertyTree &ctx = useContext(sequence);
  26711. IPropertyTree *val = ctx.queryPropTree(stepname);
  26712. doExtractRawResultX(tlen, tgt, val, sequence, xmlTransformer, csvTransformer, true);
  26713. tisAll = val ? val->getPropBool("@isAll", false) : false;
  26714. }
  26715. catch (IException * e)
  26716. {
  26717. StringBuffer text;
  26718. e->errorMessage(text);
  26719. e->Release();
  26720. throw MakeStringException(ROXIE_DATA_ERROR, "Failed to retrieve set \"%s\". [%s]", stepname, text.str());
  26721. }
  26722. catch (...)
  26723. {
  26724. throw MakeStringException(ROXIE_DATA_ERROR, "Failed to retrieve set \"%s\"", stepname);
  26725. }
  26726. }
  26727. virtual void printResults(IXmlWriter *output, const char *name, unsigned sequence)
  26728. {
  26729. CriticalBlock b(contextCrit);
  26730. IPropertyTree &tree = useContext(sequence);
  26731. if (name)
  26732. {
  26733. const char *val = tree.queryProp(name);
  26734. if (val)
  26735. output->outputCString(val, name);
  26736. }
  26737. else
  26738. {
  26739. StringBuffer hack;
  26740. toXML(&tree, hack);
  26741. output->outputString(0, NULL, NULL); // Hack upon hack...
  26742. output->outputQuoted(hack.str());
  26743. }
  26744. }
  26745. class RawDataReader : public CInterface, implements IWorkUnitRowReader
  26746. {
  26747. protected:
  26748. const IRoxieContextLogger &logctx;
  26749. byte *bufferBase;
  26750. MemoryBuffer blockBuffer;
  26751. Owned<ISerialStream> bufferStream;
  26752. CThorStreamDeserializerSource rowSource;
  26753. bool eof;
  26754. bool eogPending;
  26755. bool isGrouped;
  26756. Linked<IEngineRowAllocator> rowAllocator;
  26757. Owned<IOutputRowDeserializer> rowDeserializer;
  26758. virtual bool nextBlock(unsigned & tlen, void * & tgt, void * & base) = 0;
  26759. bool reload()
  26760. {
  26761. free(bufferBase);
  26762. size32_t lenData;
  26763. bufferBase = NULL;
  26764. void *tempData, *base;
  26765. eof = !nextBlock(lenData, tempData, base);
  26766. bufferBase = (byte *) base;
  26767. blockBuffer.setBuffer(lenData, tempData, false);
  26768. return !eof;
  26769. }
  26770. public:
  26771. IMPLEMENT_IINTERFACE;
  26772. RawDataReader(CRoxieServerContext *parent, IEngineRowAllocator *_rowAllocator, bool _isGrouped)
  26773. : logctx(*parent), rowAllocator(_rowAllocator), isGrouped(_isGrouped)
  26774. {
  26775. eof = false;
  26776. eogPending = false;
  26777. bufferBase = NULL;
  26778. rowDeserializer.setown(rowAllocator->createRowDeserializer(parent->queryCodeContext()));
  26779. bufferStream.setown(createMemoryBufferSerialStream(blockBuffer));
  26780. rowSource.setStream(bufferStream);
  26781. }
  26782. ~RawDataReader()
  26783. {
  26784. if (bufferBase)
  26785. free(bufferBase);
  26786. }
  26787. virtual const void *nextInGroup()
  26788. {
  26789. if (eof)
  26790. return NULL;
  26791. if (rowSource.eos() && !reload())
  26792. return NULL;
  26793. if (eogPending)
  26794. {
  26795. eogPending = false;
  26796. return NULL;
  26797. }
  26798. #if 0
  26799. // MORE - think a bit about what happens on incomplete rows - I think deserializer will throw an exception?
  26800. unsigned thisSize = meta.getRecordSize(data+cursor);
  26801. if (thisSize > lenData-cursor)
  26802. {
  26803. CTXLOG("invalid stored dataset - incomplete row at end");
  26804. throw MakeStringException(ROXIE_DATA_ERROR, "invalid stored dataset - incomplete row at end");
  26805. }
  26806. #endif
  26807. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  26808. size32_t size = rowDeserializer->deserialize(rowBuilder, rowSource);
  26809. if (isGrouped)
  26810. rowSource.read(sizeof(bool), &eogPending);
  26811. atomic_inc(&rowsIn);
  26812. return rowBuilder.finalizeRowClear(size);
  26813. }
  26814. };
  26815. class InlineRawDataReader : public RawDataReader
  26816. {
  26817. Linked<IPropertyTree> xml;
  26818. public:
  26819. InlineRawDataReader(CRoxieServerContext *parent, IEngineRowAllocator *_rowAllocator, bool _isGrouped, IPropertyTree *_xml)
  26820. : RawDataReader(parent, _rowAllocator, _isGrouped), xml(_xml)
  26821. {
  26822. }
  26823. virtual bool nextBlock(unsigned & tlen, void * & tgt, void * & base)
  26824. {
  26825. base = tgt = NULL;
  26826. if (xml)
  26827. {
  26828. MemoryBuffer result;
  26829. xml->getPropBin(NULL, result);
  26830. tlen = result.length();
  26831. base = tgt = result.detach();
  26832. xml.clear();
  26833. return tlen != 0;
  26834. }
  26835. else
  26836. {
  26837. tlen = 0;
  26838. return false;
  26839. }
  26840. }
  26841. };
  26842. class StreamedRawDataReader : public RawDataReader
  26843. {
  26844. SafeSocket &client;
  26845. StringAttr id;
  26846. offset_t offset;
  26847. public:
  26848. StreamedRawDataReader(CRoxieServerContext *parent, IEngineRowAllocator *_rowAllocator, bool _isGrouped, SafeSocket &_client, const char *_id)
  26849. : RawDataReader(parent, _rowAllocator, _isGrouped), client(_client), id(_id)
  26850. {
  26851. offset = 0;
  26852. }
  26853. virtual bool nextBlock(unsigned & tlen, void * & tgt, void * & base)
  26854. {
  26855. try
  26856. {
  26857. #ifdef FAKE_EXCEPTIONS
  26858. if (offset > 0x10000)
  26859. throw MakeStringException(ROXIE_INTERNAL_ERROR, "TEST EXCEPTION");
  26860. #endif
  26861. // Go request from the socket
  26862. MemoryBuffer request;
  26863. request.reserve(sizeof(size32_t));
  26864. request.append('D');
  26865. offset_t loffset = offset;
  26866. _WINREV(loffset);
  26867. request.append(sizeof(loffset), &loffset);
  26868. request.append(strlen(id)+1, id);
  26869. size32_t len = request.length() - sizeof(size32_t);
  26870. len |= 0x80000000;
  26871. _WINREV(len);
  26872. *(size32_t *) request.toByteArray() = len;
  26873. client.write(request.toByteArray(), request.length());
  26874. // Note: I am the only thread reading (we only support a single input dataset in roxiepipe mode)
  26875. MemoryBuffer reply;
  26876. client.readBlock(reply, readTimeout);
  26877. tlen = reply.length();
  26878. // MORE - not very robust!
  26879. // skip past block header
  26880. if (tlen > 0)
  26881. {
  26882. tgt = base = reply.detach();
  26883. tgt = ((char *)base) + 9;
  26884. tgt = strchr((char *)tgt, '\0') + 1;
  26885. tlen -= ((char *)tgt - (char *)base);
  26886. offset += tlen;
  26887. }
  26888. else
  26889. tgt = base = NULL;
  26890. return tlen != 0;
  26891. }
  26892. catch (IException *E)
  26893. {
  26894. StringBuffer text;
  26895. E->errorMessage(text);
  26896. int errCode = E->errorCode();
  26897. E->Release();
  26898. IException *ee = MakeStringException(MSGAUD_internal, errCode, "%s", text.str());
  26899. logctx.logOperatorException(ee, __FILE__, __LINE__, "Exception caught in RawDataReader::nextBlock");
  26900. throw ee;
  26901. }
  26902. catch (...)
  26903. {
  26904. logctx.logOperatorException(NULL, __FILE__, __LINE__, "Unknown exception caught in RawDataReader::nextBlock");
  26905. throw;
  26906. }
  26907. }
  26908. };
  26909. class InlineXmlDataReader : public CInterface, implements IWorkUnitRowReader
  26910. {
  26911. Linked<IPropertyTree> xml;
  26912. Owned <XmlColumnProvider> columns;
  26913. Owned<IPropertyTreeIterator> rows;
  26914. IXmlToRowTransformer &rowTransformer;
  26915. Linked<IEngineRowAllocator> rowAllocator;
  26916. public:
  26917. IMPLEMENT_IINTERFACE;
  26918. InlineXmlDataReader(IXmlToRowTransformer &_rowTransformer, IPropertyTree *_xml, IEngineRowAllocator *_rowAllocator)
  26919. : xml(_xml), rowTransformer(_rowTransformer), rowAllocator(_rowAllocator)
  26920. {
  26921. columns.setown(new XmlDatasetColumnProvider);
  26922. rows.setown(xml->getElements("Row")); // NOTE - the 'hack for Gordon' as found in thorxmlread is not implemented here. Does it need to be ?
  26923. rows->first();
  26924. }
  26925. virtual const void *nextInGroup()
  26926. {
  26927. if (rows->isValid())
  26928. {
  26929. columns->setRow(&rows->query());
  26930. rows->next();
  26931. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  26932. NullDiskCallback callback;
  26933. size_t outSize = rowTransformer.transform(rowBuilder, columns, &callback);
  26934. return rowBuilder.finalizeRowClear(outSize);
  26935. }
  26936. return NULL;
  26937. }
  26938. };
  26939. virtual IWorkUnitRowReader *getWorkunitRowReader(const char *stepname, unsigned sequence, IXmlToRowTransformer * xmlTransformer, IEngineRowAllocator *rowAllocator, bool isGrouped)
  26940. {
  26941. try
  26942. {
  26943. CriticalBlock b(contextCrit);
  26944. IPropertyTree &ctx = useContext(sequence);
  26945. IPropertyTree *val = ctx.queryPropTree(stepname);
  26946. if (val)
  26947. {
  26948. const char *id = val->queryProp("@id");
  26949. const char *format = val->queryProp("@format");
  26950. if (id)
  26951. {
  26952. if (!format || strcmp(format, "raw") == 0)
  26953. return new StreamedRawDataReader(this, rowAllocator, isGrouped, *client, id);
  26954. else if (strcmp(format, "deserialized") == 0)
  26955. {
  26956. IDeserializedResultStore &resultStore = useResultStore(sequence);
  26957. return resultStore.createDeserializedReader(atoi(id));
  26958. }
  26959. else
  26960. throwUnexpected();
  26961. }
  26962. else
  26963. {
  26964. if (!format || strcmp(format, "xml") == 0)
  26965. {
  26966. if (xmlTransformer)
  26967. return new InlineXmlDataReader(*xmlTransformer, val, rowAllocator);
  26968. }
  26969. else if (strcmp(format, "raw") == 0)
  26970. {
  26971. return new InlineRawDataReader(this, rowAllocator, isGrouped, val);
  26972. }
  26973. else
  26974. throwUnexpected();
  26975. }
  26976. }
  26977. }
  26978. catch (IException * e)
  26979. {
  26980. StringBuffer text;
  26981. e->errorMessage(text);
  26982. e->Release();
  26983. throw MakeStringException(ROXIE_DATA_ERROR, "Failed to retrieve data value %s. [%s]", stepname, text.str());
  26984. }
  26985. catch (...)
  26986. {
  26987. throw MakeStringException(ROXIE_DATA_ERROR, "Failed to retrieve data value %s", stepname);
  26988. }
  26989. throw MakeStringException(ROXIE_DATA_ERROR, "Failed to retrieve data value %s", stepname);
  26990. }
  26991. virtual const IResolvedFile *resolveLFN(const char *filename, bool isOpt)
  26992. {
  26993. CriticalBlock b(daliUpdateCrit);
  26994. if (!dynamicPackage)
  26995. {
  26996. dynamicPackage.setown(createPackage(NULL));
  26997. }
  26998. return dynamicPackage->lookupFileName(filename, isOpt, true);
  26999. }
  27000. virtual IRoxieWriteHandler *createLFN(const char *filename, bool overwrite, bool extend, const StringArray &clusters)
  27001. {
  27002. CriticalBlock b(daliUpdateCrit);
  27003. if (!dynamicPackage)
  27004. {
  27005. dynamicPackage.setown(createPackage(NULL));
  27006. }
  27007. return dynamicPackage->createFileName(filename, overwrite, extend, clusters);
  27008. }
  27009. virtual void onFileCallback(const RoxiePacketHeader &header, const char *lfn, bool isOpt, bool isLocal)
  27010. {
  27011. Owned<const IResolvedFile> dFile = resolveLFN(lfn, isOpt);
  27012. if (dFile)
  27013. {
  27014. MemoryBuffer mb;
  27015. mb.append(sizeof(RoxiePacketHeader), &header);
  27016. mb.append(lfn);
  27017. dFile->serializePartial(mb, header.channel, isLocal);
  27018. ((RoxiePacketHeader *) mb.toByteArray())->activityId = ROXIE_FILECALLBACK;
  27019. Owned<IRoxieQueryPacket> reply = createRoxiePacket(mb);
  27020. reply->queryHeader().retries = 0;
  27021. ROQ->sendPacket(reply, *this); // MORE - the caller's log context might be better? Should we unicast? Note that this does not release the packet
  27022. return;
  27023. }
  27024. ROQ->sendAbortCallback(header, lfn, *this);
  27025. throwUnexpected();
  27026. }
  27027. virtual void getExternalResultRaw(unsigned & tlen, void * & tgt, const char * wuid, const char * stepname, unsigned sequence, IXmlToRowTransformer * xmlTransformer, ICsvToRowTransformer * csvTransformer)
  27028. {
  27029. UNIMPLEMENTED;
  27030. }
  27031. virtual void addWuException(const char * text, unsigned code, unsigned _severity)
  27032. {
  27033. WUExceptionSeverity severity = (WUExceptionSeverity) _severity;
  27034. CTXLOG("%s", text);
  27035. if (severity > ExceptionSeverityInformation)
  27036. OERRLOG("%d - %s", code, text);
  27037. if (workUnit)
  27038. {
  27039. WorkunitUpdate wu(&workUnit->lock());
  27040. addExceptionToWorkunit(wu, severity, "user", code, text, NULL, 0 ,0);
  27041. }
  27042. }
  27043. virtual void addWuAssertFailure(unsigned code, const char * text, const char * filename, unsigned lineno, unsigned column, bool isAbort)
  27044. {
  27045. CTXLOG("%s", text);
  27046. OERRLOG("%d - %s", code, text);
  27047. if (workUnit)
  27048. {
  27049. WorkunitUpdate wu(&workUnit->lock());
  27050. addExceptionToWorkunit(wu, ExceptionSeverityError, "user", code, text, filename, lineno, column);
  27051. }
  27052. if (isAbort)
  27053. rtlFailOnAssert(); // minimal implementation
  27054. }
  27055. IUserDescriptor *queryUserDescriptor()
  27056. {
  27057. return NULL; // TBD - Richard, where do user credentials for a roxie query come from
  27058. }
  27059. virtual __int64 getResultInt(const char * name, unsigned sequence)
  27060. {
  27061. CriticalBlock b(contextCrit);
  27062. const char *val = useContext(sequence).queryProp(name);
  27063. if (val)
  27064. {
  27065. // NOTE - we use this rather than getPropInt64 since it handles uint64 values up to MAX_UINT better (for our purposes)
  27066. return rtlStrToInt8(strlen(val), val);
  27067. }
  27068. else
  27069. return 0;
  27070. }
  27071. virtual double getResultReal(const char * name, unsigned sequence)
  27072. {
  27073. CriticalBlock b(contextCrit);
  27074. IPropertyTree &ctx = useContext(sequence);
  27075. double ret = 0;
  27076. if (ctx.hasProp(name))
  27077. {
  27078. if (ctx.isBinary(name))
  27079. {
  27080. MemoryBuffer buf;
  27081. ctx.getPropBin(name, buf);
  27082. buf.read(ret);
  27083. }
  27084. else
  27085. {
  27086. const char *val = ctx.queryProp(name);
  27087. if (val)
  27088. ret = atof(val);
  27089. }
  27090. }
  27091. return ret;
  27092. }
  27093. virtual void getResultString(unsigned & tlen, char * & tgt, const char * name, unsigned sequence)
  27094. {
  27095. MemoryBuffer x;
  27096. bool isBinary;
  27097. {
  27098. CriticalBlock b(contextCrit);
  27099. IPropertyTree &ctx = useContext(sequence);
  27100. isBinary = ctx.isBinary(name);
  27101. ctx.getPropBin(name, x);
  27102. }
  27103. if (isBinary) // No utf8 translation if previously set via setResultString
  27104. {
  27105. tlen = x.length();
  27106. tgt = (char *) x.detach();
  27107. }
  27108. else
  27109. rtlUtf8ToStrX(tlen, tgt, rtlUtf8Length(x.length(), x.toByteArray()), x.toByteArray());
  27110. }
  27111. virtual void getResultStringF(unsigned tlen, char * tgt, const char * name, unsigned sequence)
  27112. {
  27113. MemoryBuffer x;
  27114. bool isBinary;
  27115. {
  27116. CriticalBlock b(contextCrit);
  27117. IPropertyTree &ctx = useContext(sequence);
  27118. isBinary = ctx.isBinary(name);
  27119. ctx.getPropBin(name, x);
  27120. }
  27121. if (isBinary)
  27122. rtlStrToStr(tlen, tgt, x.length(), x.toByteArray());
  27123. else
  27124. rtlUtf8ToStr(tlen, tgt, rtlUtf8Length(x.length(), x.toByteArray()), x.toByteArray());
  27125. }
  27126. virtual void getResultUnicode(unsigned & tlen, UChar * & tgt, const char * name, unsigned sequence)
  27127. {
  27128. StringBuffer x;
  27129. {
  27130. CriticalBlock b(contextCrit);
  27131. useContext(sequence).getProp(name, x);
  27132. }
  27133. tgt = rtlCodepageToVUnicodeX(x.length(), x.str(), "utf-8");
  27134. tlen = rtlUnicodeStrlen(tgt);
  27135. }
  27136. virtual char *getResultVarString(const char * name, unsigned sequence)
  27137. {
  27138. CriticalBlock b(contextCrit);
  27139. IPropertyTree &ctx = useContext(sequence);
  27140. bool isBinary = ctx.isBinary(name);
  27141. if (isBinary)
  27142. {
  27143. StringBuffer s;
  27144. ctx.getProp(name, s);
  27145. return s.detach();
  27146. }
  27147. else
  27148. {
  27149. MemoryBuffer x;
  27150. ctx.getPropBin(name, x);
  27151. return rtlUtf8ToVStr(rtlUtf8Length(x.length(), x.toByteArray()), x.toByteArray());
  27152. }
  27153. }
  27154. virtual UChar *getResultVarUnicode(const char * name, unsigned sequence)
  27155. {
  27156. StringBuffer x;
  27157. CriticalBlock b(contextCrit);
  27158. useContext(sequence).getProp(name, x);
  27159. return rtlVCodepageToVUnicodeX(x.str(), "utf-8");
  27160. }
  27161. virtual bool isResult(const char * name, unsigned sequence)
  27162. {
  27163. CriticalBlock b(contextCrit);
  27164. return useContext(sequence).hasProp(name);
  27165. }
  27166. virtual char *getClusterName() { throwUnexpected(); }
  27167. virtual char *getGroupName() { throwUnexpected(); }
  27168. virtual char * queryIndexMetaData(char const * lfn, char const * xpath) { throwUnexpected(); }
  27169. virtual char *getDaliServers() { throwUnexpected(); }
  27170. virtual char *getEnv(const char *name, const char *defaultValue) const
  27171. {
  27172. return serverQueryFactory->getEnv(name, defaultValue);
  27173. }
  27174. virtual char *getJobName()
  27175. {
  27176. return strdup(factory->queryQueryName());
  27177. }
  27178. virtual char *getJobOwner() { throwUnexpected(); }
  27179. virtual char *getPlatform()
  27180. {
  27181. return strdup("roxie");
  27182. }
  27183. virtual char *getWuid()
  27184. {
  27185. if (workUnit)
  27186. {
  27187. SCMStringBuffer wuid;
  27188. workUnit->getWuid(wuid);
  27189. return strdup(wuid.str());
  27190. }
  27191. else
  27192. {
  27193. throw MakeStringException(ROXIE_INVALID_ACTION, "No workunit associated with this context");
  27194. }
  27195. }
  27196. // persist-related code - usage of persist should have been caught and rejected at codegen time
  27197. virtual char * getExpandLogicalName(const char * logicalName) { throwUnexpected(); }
  27198. virtual void startPersist(const char * name) { throwUnexpected(); }
  27199. virtual void finishPersist() { throwUnexpected(); }
  27200. virtual void clearPersist(const char * logicalName) { throwUnexpected(); }
  27201. virtual void updatePersist(const char * logicalName, unsigned eclCRC, unsigned __int64 allCRC) { throwUnexpected(); }
  27202. virtual unsigned getResultHash(const char * name, unsigned sequence) { throwUnexpected(); }
  27203. virtual void checkPersistMatches(const char * logicalName, unsigned eclCRC) { throwUnexpected(); }
  27204. virtual unsigned getRecoveringCount() { throwUnexpected(); }
  27205. virtual void setWorkflowCondition(bool value) { if(workflow) workflow->setCondition(value); }
  27206. virtual void returnPersistVersion(const char * logicalName, unsigned eclCRC, unsigned __int64 allCRC, bool isFile) { throwUnexpected(); }
  27207. virtual __int64 countDiskFile(const char * lfn, unsigned recordSize)
  27208. {
  27209. throwUnexpected();
  27210. }
  27211. virtual void fail(int code, const char *text)
  27212. {
  27213. addWuException(text, code, 2);
  27214. }
  27215. virtual unsigned getWorkflowId() { return workflow->queryCurrentWfid(); }
  27216. virtual void doNotify(char const * code, char const * extra) { UNIMPLEMENTED; }
  27217. virtual void doNotify(char const * code, char const * extra, const char * target) { UNIMPLEMENTED; }
  27218. virtual void doWait(unsigned code, char const * extra) { UNIMPLEMENTED; }
  27219. virtual void doWaitCond(unsigned code, char const * extra, int sequence, char const * alias, unsigned wfid) { UNIMPLEMENTED; }
  27220. virtual unsigned __int64 getDatasetHash(const char * name, unsigned __int64 hash) { throwUnexpected(); }
  27221. virtual int queryLastFailCode() { UNIMPLEMENTED; }
  27222. virtual void getLastFailMessage(size32_t & outLen, char * &outStr, const char * tag) { UNIMPLEMENTED; }
  27223. virtual void getEventName(size32_t & outLen, char * & outStr) { UNIMPLEMENTED; }
  27224. virtual void getEventExtra(size32_t & outLen, char * & outStr, const char * tag) { UNIMPLEMENTED; }
  27225. virtual bool fileExists(const char * filename) { throwUnexpected(); }
  27226. virtual void deleteFile(const char * logicalName) { throwUnexpected(); }
  27227. virtual unsigned getNodes() { return numChannels; }
  27228. virtual unsigned getNodeNum() { return 1; }
  27229. virtual char *getFilePart(const char *logicalPart, bool create=false) { UNIMPLEMENTED; }
  27230. virtual unsigned __int64 getFileOffset(const char *logicalPart) { throwUnexpected(); }
  27231. virtual IDistributedFileTransaction *querySuperFileTransaction() { UNIMPLEMENTED; }
  27232. virtual void flush(unsigned seqNo) { throwUnexpected(); }
  27233. virtual unsigned getPriority() const { return priority; }
  27234. virtual bool outputResultsToWorkUnit() const { return workUnit != NULL; }
  27235. virtual bool outputResultsToSocket() const { return client != NULL; }
  27236. virtual void selectCluster(const char * cluster) { throwUnexpected(); }
  27237. virtual void restoreCluster() { throwUnexpected(); }
  27238. };
  27239. //================================================================================================
  27240. class CSoapRoxieServerContext : public CRoxieServerContext
  27241. {
  27242. private:
  27243. StringAttr queryName;
  27244. public:
  27245. CSoapRoxieServerContext(IPropertyTree *_context, const IQueryFactory *_factory, SafeSocket &_client, HttpHelper &httpHelper, unsigned _priority, const IRoxieContextLogger &_logctx, XmlReaderOptions xmlReadFlags)
  27246. : CRoxieServerContext(_context, _factory, _client, true, false, false, httpHelper, true, _priority, _logctx, xmlReadFlags)
  27247. {
  27248. queryName.set(_context->queryName());
  27249. }
  27250. virtual void process()
  27251. {
  27252. EclProcessFactory pf = (EclProcessFactory) factory->queryDll()->getEntry("createProcess");
  27253. Owned<IEclProcess> p = pf();
  27254. if (workflow)
  27255. workflow->perform(this, p);
  27256. else
  27257. p->perform(this, 0);
  27258. }
  27259. virtual void flush(unsigned seqNo)
  27260. {
  27261. CriticalBlock b(resultsCrit);
  27262. CriticalBlock b1(client->queryCrit());
  27263. StringBuffer responseHead, responseTail;
  27264. responseHead.append("<").append(queryName).append("Response");
  27265. responseHead.append(" sequence=\"").append(seqNo).append("\"");
  27266. responseHead.append(" xmlns=\"urn:hpccsystems:ecl:").appendLower(queryName.length(), queryName.sget()).append("\">");
  27267. responseHead.append("<Results><Result>");
  27268. unsigned len = responseHead.length();
  27269. client->write(responseHead.detach(), len, true);
  27270. ForEachItemIn(seq, resultMap)
  27271. {
  27272. FlushingStringBuffer *result = resultMap.item(seq);
  27273. if (result)
  27274. {
  27275. result->flush(true);
  27276. for(;;)
  27277. {
  27278. size32_t length;
  27279. void *payload = result->getPayload(length);
  27280. if (!length)
  27281. break;
  27282. client->write(payload, length, true);
  27283. }
  27284. }
  27285. }
  27286. responseTail.append("</Result></Results>");
  27287. responseTail.append("</").append(queryName).append("Response>");
  27288. len = responseTail.length();
  27289. client->write(responseTail.detach(), len, true);
  27290. }
  27291. };
  27292. IRoxieServerContext *createRoxieServerContext(IPropertyTree *context, const IQueryFactory *factory, SafeSocket &client, bool isXml, bool isRaw, bool isBlocked, HttpHelper &httpHelper, bool trim, unsigned priority, const IRoxieContextLogger &_logctx, XmlReaderOptions xmlReadFlags)
  27293. {
  27294. if (httpHelper.isHttp())
  27295. return new CSoapRoxieServerContext(context, factory, client, httpHelper, priority, _logctx, xmlReadFlags);
  27296. else
  27297. return new CRoxieServerContext(context, factory, client, isXml, isRaw, isBlocked, httpHelper, trim, priority, _logctx, xmlReadFlags);
  27298. }
  27299. IRoxieServerContext *createOnceServerContext(const IQueryFactory *factory, const IRoxieContextLogger &_logctx)
  27300. {
  27301. return new CRoxieServerContext(factory, _logctx);
  27302. }
  27303. IRoxieServerContext *createWorkUnitServerContext(IConstWorkUnit *wu, const IQueryFactory *factory, const IRoxieContextLogger &_logctx)
  27304. {
  27305. return new CRoxieServerContext(wu, factory, _logctx);
  27306. }
  27307. //======================================================================================================================
  27308. static void controlException(StringBuffer &response, IException *E, const IRoxieContextLogger &logctx)
  27309. {
  27310. try
  27311. {
  27312. if (traceLevel)
  27313. logctx.logOperatorException(E, __FILE__, __LINE__, "controlException");
  27314. response.appendf("<Exception><Source>Roxie</Source><Code>%d</Code><Message>", E->errorCode());
  27315. StringBuffer s;
  27316. E->errorMessage(s);
  27317. encodeXML(s.str(), response);
  27318. response.append("</Message></Exception>");
  27319. E->Release();
  27320. }
  27321. catch(IException *EE)
  27322. {
  27323. logctx.logOperatorException(EE, __FILE__, __LINE__, "controlException - While reporting exception");
  27324. EE->Release();
  27325. }
  27326. #ifndef _DEBUG
  27327. catch(...) {}
  27328. #endif
  27329. }
  27330. class CascadeManager : public CInterface
  27331. {
  27332. static Semaphore globalLock;
  27333. StringBuffer errors;
  27334. IArrayOf<ISocket> activeChildren;
  27335. UnsignedArray activeIdxes;
  27336. bool entered;
  27337. bool connected;
  27338. bool isMaster;
  27339. CriticalSection revisionCrit;
  27340. int myEndpoint;
  27341. const IRoxieContextLogger &logctx;
  27342. void unlockChildren()
  27343. {
  27344. try
  27345. {
  27346. class casyncfor: public CAsyncFor
  27347. {
  27348. public:
  27349. casyncfor(CascadeManager *_parent) : parent(_parent) { }
  27350. void Do(unsigned i)
  27351. {
  27352. parent->unlockChild(i);
  27353. }
  27354. private:
  27355. CascadeManager *parent;
  27356. } afor(this);
  27357. afor.For(activeChildren.length(), activeChildren.length());
  27358. }
  27359. catch (IException *E)
  27360. {
  27361. if (traceLevel)
  27362. logctx.logOperatorException(E, __FILE__, __LINE__, "In unlockChildren");
  27363. E->Release();
  27364. }
  27365. }
  27366. void unlockAll()
  27367. {
  27368. if (entered)
  27369. {
  27370. unlockChildren();
  27371. entered = false;
  27372. if (traceLevel > 5)
  27373. DBGLOG("globalLock released");
  27374. globalLock.signal();
  27375. atomic_inc(&globalSignals);
  27376. }
  27377. }
  27378. SocketEndpoint &queryEndpoint(unsigned idx)
  27379. {
  27380. return allRoxieServers.item(idx);
  27381. }
  27382. void connectChild(unsigned idx)
  27383. {
  27384. if (allRoxieServers.isItem(idx))
  27385. {
  27386. SocketEndpoint &ep = queryEndpoint(idx);
  27387. try
  27388. {
  27389. if (traceLevel)
  27390. {
  27391. StringBuffer epStr;
  27392. ep.getUrlStr(epStr);
  27393. DBGLOG("connectChild connecting to %s", epStr.str());
  27394. }
  27395. ISocket *sock = ISocket::connect_timeout(ep, 2000);
  27396. assertex(sock);
  27397. activeChildren.append(*sock);
  27398. activeIdxes.append(idx);
  27399. if (traceLevel)
  27400. {
  27401. StringBuffer epStr;
  27402. ep.getUrlStr(epStr);
  27403. DBGLOG("connectChild connected to %s", epStr.str());
  27404. }
  27405. }
  27406. catch(IException *E)
  27407. {
  27408. logctx.logOperatorException(E, __FILE__, __LINE__, "CascadeManager connection failed");
  27409. connectChild((idx+1) * 2 - 1);
  27410. connectChild((idx+1) * 2);
  27411. errors.append("<Endpoint ep='");
  27412. ep.getUrlStr(errors);
  27413. errors.append("'><Exception><Code>").append(E->errorCode()).append("</Code><Message>");
  27414. E->errorMessage(errors).append("</Message></Exception></Endpoint>");
  27415. logctx.CTXLOG("Connection failed - %s", errors.str());
  27416. E->Release();
  27417. }
  27418. }
  27419. }
  27420. public:
  27421. void doChildQuery(unsigned idx, const char *queryText, StringBuffer &reply)
  27422. {
  27423. ISocket &sock = activeChildren.item(idx);
  27424. CSafeSocket ss(LINK(&sock));
  27425. unsigned txtlen = queryText ? strlen(queryText) : 0;
  27426. unsigned revlen = txtlen;
  27427. _WINREV(revlen);
  27428. ss.write(&revlen, sizeof(revlen));
  27429. if (txtlen)
  27430. {
  27431. ss.write(queryText, txtlen);
  27432. bool dummy;
  27433. while (ss.readBlock(reply, WAIT_FOREVER, NULL, dummy, dummy, maxBlockSize)) {}
  27434. }
  27435. }
  27436. int lockChild(unsigned idx)
  27437. {
  27438. StringBuffer lockReply;
  27439. StringBuffer lockQuery;
  27440. lockQuery.appendf("<control:childlock thisEndpoint='%d' parent='%d'/>", activeIdxes.item(idx), myEndpoint);
  27441. doChildQuery(idx, lockQuery.str(), lockReply);
  27442. Owned<IPropertyTree> lockResult = createPTreeFromXMLString(lockReply.str(), ipt_caseInsensitive);
  27443. int lockCount = lockResult->getPropInt("Lock", 0);
  27444. if (lockCount)
  27445. {
  27446. return lockCount;
  27447. }
  27448. else
  27449. throw MakeStringException(ROXIE_LOCK_ERROR, "Did not get lock for child %d (%s)", idx, lockReply.str());
  27450. }
  27451. void unlockChild(unsigned idx)
  27452. {
  27453. try
  27454. {
  27455. StringBuffer dummy;
  27456. doChildQuery(idx, "<control:childlock unlock='1'/>", dummy);
  27457. if (traceLevel)
  27458. DBGLOG("UnlockChild %d returned %s", idx, dummy.str());
  27459. }
  27460. catch (IException *E)
  27461. {
  27462. if (traceLevel)
  27463. logctx.logOperatorException(E, __FILE__, __LINE__, "In unlockChild");
  27464. E->Release();
  27465. }
  27466. }
  27467. private:
  27468. unsigned lockChildren()
  27469. {
  27470. loop
  27471. {
  27472. int got = 1;
  27473. CriticalSection cs;
  27474. try
  27475. {
  27476. class casyncfor: public CAsyncFor
  27477. {
  27478. public:
  27479. casyncfor(CascadeManager *_parent, int &_got, CriticalSection &_cs)
  27480. : parent(_parent), got(_got), cs(_cs){ }
  27481. void Do(unsigned i)
  27482. {
  27483. int childLocks = parent->lockChild(i);
  27484. CriticalBlock b(cs);
  27485. if (childLocks <= 0)
  27486. got = childLocks;
  27487. else if (got > 0)
  27488. got += childLocks;
  27489. }
  27490. private:
  27491. CascadeManager *parent;
  27492. int &got;
  27493. CriticalSection &cs;
  27494. } afor(this, got, cs);
  27495. afor.For(activeChildren.length(), activeChildren.length());
  27496. }
  27497. catch (IException *E)
  27498. {
  27499. if (traceLevel)
  27500. logctx.logOperatorException(E, __FILE__, __LINE__, "In lockChildren");
  27501. E->Release();
  27502. got = 0; // Something went wrong - abandon this attempt
  27503. }
  27504. if (got <= 0)
  27505. {
  27506. unlockChildren();
  27507. if (!got)
  27508. throw MakeStringException(ROXIE_LOCK_ERROR, "lock failed");
  27509. if (traceLevel)
  27510. DBGLOG("Lock succeeded but revision updated - go around again");
  27511. }
  27512. else
  27513. return got-1;
  27514. }
  27515. }
  27516. void getGlobalLock()
  27517. {
  27518. if (traceLevel > 5)
  27519. DBGLOG("in getGlobalLock");
  27520. if (!globalLock.wait(2000)) // since all lock in the same order it's ok to block for a bit here
  27521. throw MakeStringException(ROXIE_LOCK_ERROR, "lock failed");
  27522. atomic_inc(&globalLocks);
  27523. entered = true;
  27524. if (traceLevel > 5)
  27525. DBGLOG("globalLock locked");
  27526. }
  27527. unsigned lockAll()
  27528. {
  27529. try
  27530. {
  27531. return lockChildren() + 1;
  27532. }
  27533. catch(...)
  27534. {
  27535. if (traceLevel>5)
  27536. DBGLOG("Failed to get child locks - unlocking");
  27537. assertex(entered);
  27538. entered = false;
  27539. globalLock.signal();
  27540. atomic_inc(&globalSignals);
  27541. if (traceLevel > 5)
  27542. DBGLOG("globalLock released");
  27543. throw;
  27544. }
  27545. }
  27546. public:
  27547. IMPLEMENT_IINTERFACE;
  27548. CascadeManager(const IRoxieContextLogger &_logctx) : logctx(_logctx)
  27549. {
  27550. entered = false;
  27551. connected = false;
  27552. isMaster = false;
  27553. myEndpoint = -1;
  27554. logctx.Link();
  27555. }
  27556. ~CascadeManager()
  27557. {
  27558. unlockAll();
  27559. logctx.Release();
  27560. }
  27561. void doLockChild(const char *queryText, StringBuffer &reply)
  27562. {
  27563. if (traceLevel > 5)
  27564. DBGLOG("doLockChild: %s", queryText);
  27565. isMaster = false;
  27566. Owned<IPropertyTree> xml = createPTreeFromXMLString(queryText);
  27567. bool unlock = xml->getPropBool("@unlock", false);
  27568. if (unlock)
  27569. {
  27570. unlockAll();
  27571. reply.append("<Lock>0</Lock>");
  27572. }
  27573. else
  27574. {
  27575. assertex(!entered);
  27576. myEndpoint = xml->getPropInt("@thisEndpoint", 0);
  27577. if (!connected)
  27578. {
  27579. connectChild((myEndpoint+1) * 2 - 1);
  27580. connectChild((myEndpoint+1) * 2);
  27581. connected = true;
  27582. }
  27583. try
  27584. {
  27585. getGlobalLock();
  27586. unsigned locksGot = lockAll();
  27587. reply.append("<Lock>").append(locksGot).append("</Lock>");
  27588. assertex(entered);
  27589. }
  27590. catch (IException *E)
  27591. {
  27592. if (traceLevel > 5)
  27593. logctx.logOperatorException(E, __FILE__, __LINE__, "Trying to get global lock");
  27594. E->Release();
  27595. reply.append("<Lock>0</Lock>");
  27596. }
  27597. }
  27598. }
  27599. bool doLockGlobal(StringBuffer &reply, bool lockAll)
  27600. {
  27601. assertex(!entered);
  27602. assertex(!connected);
  27603. isMaster = true;
  27604. myEndpoint = -1;
  27605. unsigned attemptsLeft = maxLockAttempts;
  27606. connectChild(0);
  27607. connected = true;
  27608. unsigned lockDelay = 0;
  27609. unsigned locksGot = 0;
  27610. Owned<IRandomNumberGenerator> randomizer;
  27611. loop
  27612. {
  27613. try
  27614. {
  27615. locksGot = lockChildren();
  27616. break;
  27617. }
  27618. catch (IException *E)
  27619. {
  27620. unsigned errCode = E->errorCode();
  27621. if (traceLevel > 5)
  27622. logctx.logOperatorException(E, __FILE__, __LINE__, "In doLockGlobal()");
  27623. E->Release();
  27624. if ( (!--attemptsLeft) || (errCode == ROXIE_CLUSTER_SYNC_ERROR))
  27625. {
  27626. reply.append("<Lock>0</Lock>");
  27627. return false;
  27628. }
  27629. if (!randomizer) randomizer.setown(createRandomNumberGenerator());
  27630. lockDelay += 1000 + randomizer->next() % 1000;
  27631. Sleep(lockDelay);
  27632. }
  27633. }
  27634. if (traceLevel > 5)
  27635. DBGLOG("doLockGlobal got %d locks", locksGot);
  27636. reply.append("<Lock>").append(locksGot).append("</Lock>");
  27637. reply.append("<NumServers>").append(allRoxieServers.ordinality()).append("</NumServers>");
  27638. if (lockAll)
  27639. return locksGot == allRoxieServers.ordinality();
  27640. else
  27641. return locksGot > allRoxieServers.ordinality()/2;
  27642. }
  27643. void doControlQuery(SocketEndpoint &ep, const char *queryText, StringBuffer &reply)
  27644. {
  27645. if (logctx.queryTraceLevel() > 5)
  27646. logctx.CTXLOG("doControlQuery (%d): %.80s", isMaster, queryText);
  27647. // By this point we should have cascade-connected thanks to a prior <control:lock>
  27648. // So do the query ourselves and in all child threads;
  27649. Owned<IPropertyTree> mergedStats;
  27650. if (strstr(queryText, "querystats"))
  27651. mergedStats.setown(createPTree("Endpoint"));
  27652. class casyncfor: public CAsyncFor
  27653. {
  27654. const char *queryText;
  27655. CascadeManager *parent;
  27656. IPropertyTree *mergedStats;
  27657. StringBuffer &reply;
  27658. CriticalSection crit;
  27659. SocketEndpoint &ep;
  27660. unsigned numChildren;
  27661. const IRoxieContextLogger &logctx;
  27662. public:
  27663. casyncfor(const char *_queryText, CascadeManager *_parent, IPropertyTree *_mergedStats,
  27664. StringBuffer &_reply, SocketEndpoint &_ep, unsigned _numChildren, const IRoxieContextLogger &_logctx)
  27665. : queryText(_queryText), parent(_parent), mergedStats(_mergedStats), reply(_reply), ep(_ep), numChildren(_numChildren), logctx(_logctx)
  27666. {
  27667. }
  27668. void Do(unsigned i)
  27669. {
  27670. if (logctx.queryTraceLevel() > 5)
  27671. logctx.CTXLOG("doControlQuery::do (%d of %d): %.80s", i, numChildren, queryText);
  27672. if (i == numChildren)
  27673. doMe();
  27674. else
  27675. {
  27676. StringBuffer childReply;
  27677. parent->doChildQuery(i, queryText, childReply);
  27678. Owned<IPropertyTree> xml = createPTreeFromXMLString(childReply);
  27679. if (!xml)
  27680. {
  27681. StringBuffer err;
  27682. err.appendf("doControlQuery::do (%d of %d): %.80s received invalid response %s", i, numChildren, queryText, childReply.str());
  27683. logctx.CTXLOG("%s", err.str());
  27684. throw MakeStringException(ROXIE_INTERNAL_ERROR, "%s", err.str());
  27685. }
  27686. Owned<IPropertyTreeIterator> meat = xml->getElements("Endpoint");
  27687. ForEach(*meat)
  27688. {
  27689. CriticalBlock cb(crit);
  27690. if (mergedStats)
  27691. {
  27692. mergeStats(mergedStats, &meat->query(), 0);
  27693. }
  27694. else
  27695. toXML(&meat->query(), reply);
  27696. }
  27697. }
  27698. }
  27699. void doMe()
  27700. {
  27701. StringBuffer myReply;
  27702. myReply.append("<Endpoint ep='");
  27703. ep.getUrlStr(myReply);
  27704. myReply.append("'>\n");
  27705. try
  27706. {
  27707. Owned<IPropertyTree> xml = createPTreeFromXMLString(queryText); // control queries are case sensitive
  27708. globalPackageSetManager->doControlMessage(xml, myReply, logctx);
  27709. }
  27710. catch(IException *E)
  27711. {
  27712. controlException(myReply, E, logctx);
  27713. }
  27714. catch(...)
  27715. {
  27716. controlException(myReply, MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception"), logctx);
  27717. }
  27718. myReply.append("</Endpoint>\n");
  27719. CriticalBlock cb(crit);
  27720. if (mergedStats)
  27721. {
  27722. Owned<IPropertyTree> xml = createPTreeFromXMLString(myReply);
  27723. mergeStats(mergedStats, xml, 0);
  27724. }
  27725. else
  27726. reply.append(myReply);
  27727. }
  27728. } afor(queryText, this, mergedStats, reply, ep, activeChildren.ordinality(), logctx);
  27729. afor.For(activeChildren.ordinality()+(isMaster ? 0 : 1), 10);
  27730. activeChildren.kill();
  27731. if (mergedStats)
  27732. toXML(mergedStats, reply);
  27733. if (logctx.queryTraceLevel() > 5)
  27734. logctx.CTXLOG("doControlQuery (%d) finished: %.80s", isMaster, queryText);
  27735. }
  27736. };
  27737. Semaphore CascadeManager::globalLock(1);
  27738. //================================================================================================================
  27739. static void sendSoapException(SafeSocket &client, IException *E, const char *queryName)
  27740. {
  27741. try
  27742. {
  27743. if (!queryName)
  27744. queryName = "Unknown"; // Exceptions when parsing query XML can leave queryName unset/unknowable....
  27745. StringBuffer response;
  27746. response.append("<").append(queryName).append("Response");
  27747. response.append(" xmlns=\"urn:hpccsystems:ecl:").appendLower(strlen(queryName), queryName).append("\">");
  27748. response.appendf("<Results><Result><Exception><Source>Roxie</Source><Code>%d</Code>", E->errorCode());
  27749. response.append("<Message>");
  27750. StringBuffer s;
  27751. E->errorMessage(s);
  27752. encodeXML(s.str(), response);
  27753. response.append("</Message></Exception></Result></Results>");
  27754. response.append("</").append(queryName).append("Response>");
  27755. client.write(response.str(), response.length());
  27756. }
  27757. catch(IException *EE)
  27758. {
  27759. StringBuffer error("While reporting exception: ");
  27760. EE->errorMessage(error);
  27761. DBGLOG("%s", error.str());
  27762. EE->Release();
  27763. }
  27764. #ifndef _DEBUG
  27765. catch(...) {}
  27766. #endif
  27767. }
  27768. class CSoapRequestAsyncFor : public CInterface, public CAsyncFor
  27769. {
  27770. private:
  27771. const char *queryName, *queryText;
  27772. const IRoxieContextLogger &logctx;
  27773. IArrayOf<IPropertyTree> &requestArray;
  27774. Linked<IQueryFactory> f;
  27775. SafeSocket &client;
  27776. HttpHelper &httpHelper;
  27777. XmlReaderOptions xmlReadFlags;
  27778. unsigned &memused;
  27779. unsigned &slaveReplyLen;
  27780. CriticalSection crit;
  27781. public:
  27782. CSoapRequestAsyncFor(const char *_queryName, IQueryFactory *_f, IArrayOf<IPropertyTree> &_requestArray, SafeSocket &_client, HttpHelper &_httpHelper, unsigned &_memused, unsigned &_slaveReplyLen, const char *_queryText, const IRoxieContextLogger &_logctx, XmlReaderOptions _xmlReadFlags) :
  27783. f(_f), requestArray(_requestArray), client(_client), httpHelper(_httpHelper), memused(_memused), slaveReplyLen(_slaveReplyLen), logctx(_logctx), xmlReadFlags(_xmlReadFlags)
  27784. {
  27785. queryName = _queryName;
  27786. queryText = _queryText;
  27787. }
  27788. IMPLEMENT_IINTERFACE;
  27789. void onException(IException *E)
  27790. {
  27791. if (!logctx.isBlind())
  27792. logctx.CTXLOG("FAILED: %s", queryText);
  27793. StringBuffer error("EXCEPTION: ");
  27794. E->errorMessage(error);
  27795. DBGLOG("%s", error.str());
  27796. sendSoapException(client, E, queryName);
  27797. E->Release();
  27798. }
  27799. void Do(unsigned idx)
  27800. {
  27801. try
  27802. {
  27803. IPropertyTree &request = requestArray.item(idx);
  27804. Owned<IRoxieServerContext> ctx = f->createContext(&request, client, true, false, false, httpHelper, true, logctx, xmlReadFlags);
  27805. ctx->process();
  27806. ctx->flush(idx);
  27807. CriticalBlock b(crit);
  27808. memused += ctx->getMemoryUsage();
  27809. slaveReplyLen += ctx->getSlavesReplyLen();
  27810. }
  27811. catch (WorkflowException * E)
  27812. {
  27813. onException(E);
  27814. }
  27815. catch (IException * E)
  27816. {
  27817. onException(E);
  27818. }
  27819. catch (...)
  27820. {
  27821. onException(MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception"));
  27822. }
  27823. }
  27824. };
  27825. //================================================================================================================
  27826. class AccessTableEntry : public CInterface
  27827. {
  27828. bool allow[2];
  27829. IpSubNet subnet;
  27830. RegExpr queries;
  27831. StringBuffer errorMsg;
  27832. int errorCode;
  27833. StringBuffer queryText;
  27834. SpinLock crappyUnsafeRegexLock;
  27835. public:
  27836. AccessTableEntry(bool _allow, bool _allowBlind, const char *_base, const char *_mask, const char *_queries, const char *_errorMsg, int _errorCode)
  27837. {
  27838. // TBD IPv6 (not sure exactly what needs doing here)
  27839. allow[false] = _allow;
  27840. allow[true] = _allowBlind;
  27841. errorMsg.append(_errorMsg);
  27842. errorCode = _errorCode;
  27843. if (!_base)
  27844. {
  27845. if (_mask)
  27846. throw MakeStringException(ROXIE_ACL_ERROR, "ip not specified");
  27847. _base = _mask = "0.0.0.0";
  27848. }
  27849. else if (!_mask)
  27850. _mask = "255.255.255.255";
  27851. if (!subnet.set(_base,_mask))
  27852. throw MakeStringException(ROXIE_ACL_ERROR, "Invalid mask");
  27853. if (!_queries)
  27854. _queries=".*";
  27855. queries.init(_queries, true);
  27856. queryText.append(_queries);
  27857. }
  27858. bool match(IpAddress &peer, const char *query, bool isBlind, bool &access, StringBuffer &errMsg, int &errCode)
  27859. {
  27860. {
  27861. SpinBlock b(crappyUnsafeRegexLock);
  27862. if (!queries.find(query))
  27863. return false;
  27864. }
  27865. if (!subnet.test(peer))
  27866. return false;
  27867. access = allow[isBlind];
  27868. errMsg.clear().append(errorMsg.str());
  27869. errCode = errorCode;
  27870. return true;
  27871. }
  27872. const char * queryAccessTableEntryInfo(StringBuffer &info)
  27873. {
  27874. info.append("<AccessInfo ");
  27875. info.appendf(" allow='%d'", allow[false]);
  27876. info.appendf(" allowBlind='%d'", allow[true]);
  27877. info.append(" base='");
  27878. subnet.getNetText(info);
  27879. info.append("' mask='");
  27880. subnet.getMaskText(info);
  27881. info.appendf("' filter='%s'", queryText.str());
  27882. info.appendf(" errorMsg='%s'", errorMsg.str());
  27883. info.appendf(" errorCode='%d'", errorCode);
  27884. info.append("/>\n");
  27885. return info.str();
  27886. }
  27887. };
  27888. //================================================================================================================
  27889. class RoxieListener : public Thread, implements IRoxieListener, implements IThreadFactory
  27890. {
  27891. public:
  27892. IMPLEMENT_IINTERFACE;
  27893. RoxieListener(unsigned _poolSize, bool _suspended) : Thread("RoxieListener")
  27894. {
  27895. running = false;
  27896. suspended = _suspended;
  27897. poolSize = _poolSize;
  27898. threadsActive = 0;
  27899. maxThreadsActive = 0;
  27900. }
  27901. virtual void start()
  27902. {
  27903. // Note we allow a few additional threads than requested - these are the threads that return "Too many active queries" responses
  27904. pool.setown(createThreadPool("RoxieSocketWorkerPool", this, NULL, poolSize+5, INFINITE));
  27905. assertex(!running);
  27906. Thread::start();
  27907. started.wait();
  27908. }
  27909. virtual bool stop(unsigned timeout)
  27910. {
  27911. if (running)
  27912. {
  27913. running = false;
  27914. join();
  27915. Release();
  27916. }
  27917. return pool->joinAll(false, timeout);
  27918. }
  27919. void reportBadQuery(const char *name, const IRoxieContextLogger &logctx)
  27920. {
  27921. // MORE - may want to put in a mechanism to avoid swamping SNMP with bad query reports if someone kicks off a thor job with a typo....
  27922. logctx.logOperatorException(NULL, NULL, 0, "Unknown query %s", name);
  27923. }
  27924. void checkWuAccess(bool isBlind)
  27925. {
  27926. // Could do some LDAP access checking here (via Dali?)
  27927. }
  27928. void checkAccess(IpAddress &peer, const char *queryName, const char *queryText, bool isBlind)
  27929. {
  27930. bool allowed = true;
  27931. StringBuffer errorMsg;
  27932. int errorCode;
  27933. ForEachItemIn(idx, accessTable)
  27934. {
  27935. AccessTableEntry &item = accessTable.item(idx);
  27936. item.match(peer, queryName, isBlind, allowed, errorMsg, errorCode);
  27937. item.match(peer, queryText, isBlind, allowed, errorMsg, errorCode);
  27938. }
  27939. if (!allowed)
  27940. {
  27941. StringBuffer peerStr;
  27942. peer.getIpText(peerStr);
  27943. StringBuffer qText;
  27944. if (queryText && *queryText)
  27945. decodeXML(queryText, qText);
  27946. StringBuffer errText;
  27947. if (errorCode != -1)
  27948. errText.appendf("errorCode = %d : ", errorCode);
  27949. else
  27950. errorCode = ROXIE_ACCESS_ERROR;
  27951. if (errorMsg.length())
  27952. throw MakeStringException(errorCode, "Cannot run %s : %s from host %s because %s %s", queryName, qText.str(), peerStr.str(), errText.str(), errorMsg.str());
  27953. else
  27954. throw MakeStringException(errorCode, "Access to %s : %s from host %s is not allowed %s", queryName, qText.str(), peerStr.str(), errText.str());
  27955. }
  27956. }
  27957. virtual bool suspend(bool suspendIt)
  27958. {
  27959. CriticalBlock b(activeCrit);
  27960. bool ret = suspended;
  27961. suspended = suspendIt;
  27962. return ret;
  27963. }
  27964. virtual void addAccess(bool allow, bool allowBlind, const char *ip, const char *mask, const char *query, const char *errorMsg, int errorCode)
  27965. {
  27966. accessTable.append(*new AccessTableEntry(allow, allowBlind, ip, mask, query, errorMsg, errorCode));
  27967. }
  27968. void queryAccessInfo(StringBuffer &info)
  27969. {
  27970. info.append("<ACCESSINFO>\n");
  27971. ForEachItemIn(idx, accessTable)
  27972. {
  27973. AccessTableEntry &item = accessTable.item(idx);
  27974. item.queryAccessTableEntryInfo(info);
  27975. }
  27976. info.append("</ACCESSINFO>\n");
  27977. }
  27978. protected:
  27979. unsigned poolSize;
  27980. bool running;
  27981. bool suspended;
  27982. Semaphore started;
  27983. Owned<IThreadPool> pool;
  27984. unsigned threadsActive;
  27985. unsigned maxThreadsActive;
  27986. CriticalSection activeCrit;
  27987. friend class ActiveQueryLimiter;
  27988. private:
  27989. CIArrayOf<AccessTableEntry> accessTable;
  27990. };
  27991. class RoxieWorkUnitListener : public RoxieListener
  27992. {
  27993. public:
  27994. RoxieWorkUnitListener(unsigned _poolSize, bool _suspended)
  27995. : RoxieListener(_poolSize, _suspended)
  27996. {
  27997. }
  27998. virtual const SocketEndpoint& queryEndpoint() const
  27999. {
  28000. throwUnexpected(); // MORE get rid of this function altogether?
  28001. }
  28002. virtual unsigned int queryPort() const
  28003. {
  28004. return 0;
  28005. }
  28006. virtual void runOnce(const char*)
  28007. {
  28008. UNIMPLEMENTED;
  28009. }
  28010. virtual void stopListening()
  28011. {
  28012. // Nothing to do
  28013. }
  28014. virtual int run()
  28015. {
  28016. running = true;
  28017. started.signal();
  28018. Owned<IRoxieDaliHelper> daliHelper = connectToDali();
  28019. while (running)
  28020. {
  28021. if (daliHelper->connected())
  28022. {
  28023. SCMStringBuffer queueNames;
  28024. getRoxieQueueNames(queueNames, topology->queryProp("@name"));
  28025. if (queueNames.length())
  28026. {
  28027. if (traceLevel)
  28028. DBGLOG("roxie: Waiting on queue(s) '%s'", queueNames.str());
  28029. try
  28030. {
  28031. Owned<IJobQueue> queue = createJobQueue(queueNames.str());
  28032. queue->connect();
  28033. while (running)
  28034. {
  28035. Owned<IJobQueueItem> item = queue->dequeue(5000);
  28036. if (item.get())
  28037. {
  28038. if (traceLevel)
  28039. PROGLOG("roxie: Dequeued workunit request '%s'", item->queryWUID());
  28040. pool->start((void *) item->queryWUID());
  28041. }
  28042. }
  28043. }
  28044. catch (IDaliClient_Exception *E)
  28045. {
  28046. if (traceLevel)
  28047. EXCLOG(E, "roxie: Dali connection lost");
  28048. E->Release();
  28049. daliHelper->disconnect();
  28050. }
  28051. }
  28052. }
  28053. else
  28054. {
  28055. if (traceLevel)
  28056. DBGLOG("roxie: Waiting for dali connection before waiting for queue");
  28057. daliHelper->waitConnected();
  28058. }
  28059. }
  28060. return 0;
  28061. }
  28062. virtual IPooledThread* createNew();
  28063. };
  28064. class RoxieSocketListener : public RoxieListener
  28065. {
  28066. unsigned port;
  28067. unsigned listenQueue;
  28068. Owned<ISocket> socket;
  28069. SocketEndpoint ep;
  28070. public:
  28071. RoxieSocketListener(unsigned _port, unsigned _poolSize, unsigned _listenQueue, bool _suspended)
  28072. : RoxieListener(_poolSize, _suspended)
  28073. {
  28074. port = _port;
  28075. listenQueue = _listenQueue;
  28076. ep.set(port, queryHostIP());
  28077. }
  28078. virtual bool stop(unsigned timeout)
  28079. {
  28080. if (socket)
  28081. socket->cancel_accept();
  28082. return RoxieListener::stop(timeout);
  28083. }
  28084. virtual void stopListening()
  28085. {
  28086. // Not threadsafe, but we only call this when generating a core file... what's the worst that can happen?
  28087. try
  28088. {
  28089. DBGLOG("Closing listening socket %d", port);
  28090. socket.clear();
  28091. DBGLOG("Closed listening socket %d", port);
  28092. }
  28093. catch(...)
  28094. {
  28095. }
  28096. }
  28097. virtual void runOnce(const char *query);
  28098. virtual int run()
  28099. {
  28100. DBGLOG("RoxieSocketListener (%d threads) listening to socket on port %d", poolSize, port);
  28101. socket.setown(ISocket::create(port, listenQueue));
  28102. running = true;
  28103. started.signal();
  28104. while (running)
  28105. {
  28106. ISocket *client = socket->accept(true);
  28107. if (client)
  28108. {
  28109. client->set_linger(-1);
  28110. pool->start(client);
  28111. }
  28112. }
  28113. DBGLOG("RoxieSocketListener closed query socket");
  28114. return 0;
  28115. }
  28116. virtual IPooledThread *createNew();
  28117. virtual const SocketEndpoint &queryEndpoint() const
  28118. {
  28119. return ep;
  28120. }
  28121. virtual unsigned queryPort() const
  28122. {
  28123. return port;
  28124. }
  28125. };
  28126. class ActiveQueryLimiter
  28127. {
  28128. RoxieListener *parent;
  28129. public:
  28130. bool accepted;
  28131. ActiveQueryLimiter(RoxieListener *_parent) : parent(_parent)
  28132. {
  28133. CriticalBlock b(parent->activeCrit);
  28134. if (parent->suspended)
  28135. {
  28136. accepted = false;
  28137. if (traceLevel > 1)
  28138. DBGLOG("Rejecting query since Roxie server pool %d is suspended ", parent->queryPort());
  28139. }
  28140. else
  28141. {
  28142. accepted = (parent->threadsActive < parent->poolSize);
  28143. if (accepted && parent->threadsActive > parent->maxThreadsActive)
  28144. {
  28145. parent->maxThreadsActive = parent->threadsActive;
  28146. if (traceLevel > 1)
  28147. DBGLOG("Maximum queries active %d of %d for pool %d", parent->threadsActive, parent->poolSize, parent->queryPort());
  28148. }
  28149. if (!accepted && traceLevel > 5)
  28150. DBGLOG("Too many active queries (%d >= %d)", parent->threadsActive, parent->poolSize);
  28151. }
  28152. parent->threadsActive++;
  28153. }
  28154. ~ActiveQueryLimiter()
  28155. {
  28156. CriticalBlock b(parent->activeCrit);
  28157. parent->threadsActive--;
  28158. }
  28159. };
  28160. class RoxieQueryWorker : public CInterface, implements IPooledThread
  28161. {
  28162. public:
  28163. IMPLEMENT_IINTERFACE;
  28164. RoxieQueryWorker(RoxieListener *_pool)
  28165. {
  28166. pool = _pool;
  28167. qstart = msTick();
  28168. time(&startTime);
  28169. }
  28170. // interface IPooledThread
  28171. virtual void init(void *)
  28172. {
  28173. qstart = msTick();
  28174. time(&startTime);
  28175. }
  28176. virtual bool canReuse()
  28177. {
  28178. return true;
  28179. }
  28180. virtual bool stop()
  28181. {
  28182. ERRLOG("RoxieQueryWorker stopped with queries active");
  28183. return true;
  28184. }
  28185. protected:
  28186. RoxieListener *pool;
  28187. unsigned qstart;
  28188. time_t startTime;
  28189. inline RoxieQueryStats &getStats(unsigned priority)
  28190. {
  28191. switch(priority)
  28192. {
  28193. case 0: return loQueryStats;
  28194. case 1: return hiQueryStats;
  28195. case 2: return slaQueryStats;
  28196. default: return unknownQueryStats;
  28197. }
  28198. }
  28199. void noteQuery(bool failed, unsigned elapsedTime, unsigned priority)
  28200. {
  28201. Owned <IJlibDateTime> now = createDateTimeNow();
  28202. unsigned y,mo,d,h,m,s,n;
  28203. now->getLocalTime(h, m, s, n);
  28204. now->getLocalDate(y, mo, d);
  28205. lastQueryTime = h*10000 + m * 100 + s;
  28206. lastQueryDate = y*10000 + mo * 100 + d;
  28207. RoxieQueryStats &stats = getStats(priority);
  28208. stats.noteQuery(failed, elapsedTime);
  28209. }
  28210. };
  28211. /**
  28212. * RoxieWorkUnitWorker is the threadpool member that runs a query submitted as a
  28213. * workunit via a job queue. A temporary IQueryFactory object is created for the
  28214. * workunit and then executed.
  28215. *
  28216. * Any slaves that need to load the query do so using a lazy load mechanism, checking
  28217. * whether the wuid named in the logging prefix info can be loaded any time a query
  28218. * is received for which no factory exists. Any query that a slave loads as a
  28219. * result is added to a cache to ensure that it stays around until the server's query
  28220. * terminates - a ROXIE_UNLOAD message is broadcast at that time to allow the slaves
  28221. * to release any cached IQueryFactory objects.
  28222. *
  28223. **/
  28224. class RoxieWorkUnitWorker : public RoxieQueryWorker
  28225. {
  28226. public:
  28227. RoxieWorkUnitWorker(RoxieListener *_pool)
  28228. : RoxieQueryWorker(_pool)
  28229. {
  28230. }
  28231. virtual void init(void *_r)
  28232. {
  28233. wuid.set((const char *) _r);
  28234. RoxieQueryWorker::init(_r);
  28235. }
  28236. virtual void main()
  28237. {
  28238. Owned <IRoxieDaliHelper> daliHelper = connectToDali();
  28239. Owned<IConstWorkUnit> wu = daliHelper->attachWorkunit(wuid.get(), NULL);
  28240. if (!wu)
  28241. throw MakeStringException(ROXIE_DALI_ERROR, "Failed to open workunit %s", wuid.get());
  28242. Owned<IQueryFactory> queryFactory = createServerQueryFactoryFromWu(wuid.get());
  28243. Owned<StringContextLogger> logctx = new StringContextLogger(wuid.get());
  28244. doMain(wu, queryFactory, *logctx);
  28245. sendUnloadMessage(queryFactory->queryHash(), wuid.get(), *logctx);
  28246. }
  28247. void doMain(IConstWorkUnit *wu, IQueryFactory *queryFactory, StringContextLogger &logctx)
  28248. {
  28249. bool failed = true; // many paths to failure, only one to success...
  28250. unsigned memused = 0;
  28251. unsigned slavesReplyLen = 0;
  28252. unsigned priority = (unsigned) -2;
  28253. try
  28254. {
  28255. atomic_inc(&queryCount);
  28256. bool isBlind = wu->getDebugValueBool("blindLogging", false);
  28257. if (pool)
  28258. {
  28259. pool->checkWuAccess(isBlind);
  28260. ActiveQueryLimiter l(pool);
  28261. if (!l.accepted)
  28262. {
  28263. IException *e = MakeStringException(ROXIE_TOO_MANY_QUERIES, "Too many active queries");
  28264. if (trapTooManyActiveQueries)
  28265. logctx.logOperatorException(e, __FILE__, __LINE__, NULL);
  28266. throw e;
  28267. }
  28268. }
  28269. isBlind = isBlind || blindLogging;
  28270. logctx.setBlind(isBlind);
  28271. priority = queryFactory->getPriority();
  28272. switch (priority)
  28273. {
  28274. case 0: loQueryStats.noteActive(); break;
  28275. case 1: hiQueryStats.noteActive(); break;
  28276. case 2: slaQueryStats.noteActive(); break;
  28277. }
  28278. Owned<IRoxieServerContext> ctx = queryFactory->createContext(wu, logctx);
  28279. try
  28280. {
  28281. ctx->process();
  28282. memused = ctx->getMemoryUsage();
  28283. slavesReplyLen = ctx->getSlavesReplyLen();
  28284. ctx->done(false);
  28285. failed = false;
  28286. }
  28287. catch(...)
  28288. {
  28289. memused = ctx->getMemoryUsage();
  28290. slavesReplyLen = ctx->getSlavesReplyLen();
  28291. ctx->done(true);
  28292. throw;
  28293. }
  28294. }
  28295. catch (WorkflowException *E)
  28296. {
  28297. reportException(wu, E, logctx);
  28298. E->Release();
  28299. }
  28300. catch (IException *E)
  28301. {
  28302. reportException(wu, E, logctx);
  28303. E->Release();
  28304. }
  28305. #ifndef _DEBUG
  28306. catch(...)
  28307. {
  28308. IException *E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception");
  28309. reportException(wu, E, logctx);
  28310. E->Release();
  28311. }
  28312. #endif
  28313. unsigned elapsed = msTick() - qstart;
  28314. noteQuery(failed, elapsed, priority);
  28315. queryFactory->noteQuery(startTime, failed, elapsed, memused, slavesReplyLen, 0);
  28316. if (logctx.queryTraceLevel() > 2)
  28317. logctx.dumpStats();
  28318. if (logctx.queryTraceLevel() && (logctx.queryTraceLevel() > 2 || logFullQueries || logctx.intercept))
  28319. logctx.CTXLOG("COMPLETE: %s complete in %d msecs memory %d Mb priority %d slavesreply %d", wuid.get(), elapsed, memused, priority, slavesReplyLen);
  28320. logctx.flush(true, false);
  28321. }
  28322. private:
  28323. void reportException(IConstWorkUnit *wu, IException *E, const IRoxieContextLogger &logctx)
  28324. {
  28325. logctx.CTXLOG("FAILED: %s", wuid.get());
  28326. StringBuffer error;
  28327. E->errorMessage(error);
  28328. logctx.CTXLOG("EXCEPTION: %s", error.str());
  28329. addWuException(wu, E);
  28330. WorkunitUpdate w(&wu->lock());
  28331. w->setState(WUStateFailed);
  28332. }
  28333. StringAttr wuid;
  28334. };
  28335. class RoxieSocketWorker : public RoxieQueryWorker
  28336. {
  28337. Owned<SafeSocket> client;
  28338. Owned<CDebugCommandHandler> debugCmdHandler;
  28339. SocketEndpoint ep;
  28340. public:
  28341. RoxieSocketWorker(RoxieListener *_pool, SocketEndpoint &_ep)
  28342. : RoxieQueryWorker(_pool), ep(_ep)
  28343. {
  28344. }
  28345. // interface IPooledThread
  28346. virtual void init(void *_r)
  28347. {
  28348. client.setown(new CSafeSocket((ISocket *) _r));
  28349. RoxieQueryWorker::init(_r);
  28350. }
  28351. virtual void main()
  28352. {
  28353. doMain("");
  28354. }
  28355. virtual void runOnce(const char *query)
  28356. {
  28357. doMain(query);
  28358. }
  28359. private:
  28360. static void sendHttpServerTooBusy(SafeSocket &client, const IRoxieContextLogger &logctx)
  28361. {
  28362. StringBuffer message;
  28363. message.append("HTTP/1.0 503 Server Too Busy\r\n\r\n");
  28364. message.append("Server too busy, please try again later");
  28365. StringBuffer err("Too many active queries"); // write out Too many active queries - make searching for this error consistent
  28366. if (!trapTooManyActiveQueries)
  28367. {
  28368. err.appendf(" %s", message.str());
  28369. logctx.CTXLOG("%s", err.str());
  28370. }
  28371. else
  28372. {
  28373. IException *E = MakeStringException(ROXIE_TOO_MANY_QUERIES, "%s", err.str());
  28374. logctx.logOperatorException(E, __FILE__, __LINE__, "%s", message.str());
  28375. E->Release();
  28376. }
  28377. try
  28378. {
  28379. client.write(message.str(), message.length());
  28380. }
  28381. catch (IException *E)
  28382. {
  28383. logctx.logOperatorException(E, __FILE__, __LINE__, "Exception caught in sendHttpServerTooBusy");
  28384. E->Release();
  28385. }
  28386. catch (...)
  28387. {
  28388. logctx.logOperatorException(NULL, __FILE__, __LINE__, "sendHttpServerTooBusy write failed (Unknown exception)");
  28389. }
  28390. }
  28391. void sanitizeQuery(Owned<IPropertyTree> &queryXML, StringAttr &queryName, StringBuffer &saniText, bool isHTTP, const char *&uid, bool &isRequest, bool &isRequestArray, bool &isBlind, bool &isDebug)
  28392. {
  28393. if (queryXML)
  28394. {
  28395. queryName.set(queryXML->queryName());
  28396. isRequest = false;
  28397. isRequestArray = false;
  28398. if (isHTTP)
  28399. {
  28400. if (stricmp(queryName, "envelope") == 0)
  28401. {
  28402. queryXML.setown(queryXML->getPropTree("Body/*"));
  28403. if (!queryXML)
  28404. throw MakeStringException(ROXIE_DATA_ERROR, "Malformed SOAP request (missing Body)");
  28405. String reqName(queryXML->queryName());
  28406. queryXML->removeProp("@xmlns:m");
  28407. // following code is moved from main() - should be no performance hit
  28408. String requestString("Request");
  28409. String requestArrayString("RequestArray");
  28410. if (reqName.endsWith(requestArrayString))
  28411. {
  28412. isRequestArray = true;
  28413. queryName.set(reqName.toCharArray(), reqName.length() - requestArrayString.length());
  28414. }
  28415. else if (reqName.endsWith(requestString))
  28416. {
  28417. isRequest = true;
  28418. queryName.set(reqName.toCharArray(), reqName.length() - requestString.length());
  28419. }
  28420. else
  28421. queryName.set(reqName.toCharArray());
  28422. queryXML->renameProp("/", queryName.get()); // reset the name of the tree
  28423. }
  28424. else
  28425. throw MakeStringException(ROXIE_DATA_ERROR, "Malformed SOAP request");
  28426. }
  28427. // convert to XML with attribute values in single quotes - makes replaying queries easier
  28428. uid = queryXML->queryProp("@uid");
  28429. if (!uid)
  28430. uid = "-";
  28431. isBlind = queryXML->getPropBool("@blind", false) || queryXML->getPropBool("_blind", false);
  28432. isDebug = queryXML->getPropBool("@debug") || queryXML->getPropBool("_Probe", false);
  28433. toXML(queryXML, saniText, 0, isBlind ? (XML_SingleQuoteAttributeValues | XML_Sanitize) : XML_SingleQuoteAttributeValues);
  28434. }
  28435. else
  28436. throw MakeStringException(ROXIE_DATA_ERROR, "Malformed request");
  28437. }
  28438. void doMain(const char *runQuery)
  28439. {
  28440. StringBuffer rawText(runQuery);
  28441. unsigned priority = (unsigned) -2;
  28442. unsigned memused = 0;
  28443. Owned<CascadeManager> cascade;
  28444. IpAddress peer;
  28445. bool continuationNeeded = false;
  28446. bool isStatus = false;
  28447. readAnother:
  28448. Owned<IDebuggerContext> debuggerContext;
  28449. unsigned slavesReplyLen = 0;
  28450. HttpHelper httpHelper;
  28451. try
  28452. {
  28453. if (client)
  28454. {
  28455. client->querySocket()->getPeerAddress(peer);
  28456. if (!client->readBlock(rawText, WAIT_FOREVER, &httpHelper, continuationNeeded, isStatus, maxBlockSize))
  28457. {
  28458. if (traceLevel > 8)
  28459. {
  28460. StringBuffer b;
  28461. DBGLOG("No data reading query from socket");
  28462. }
  28463. client.clear();
  28464. return;
  28465. }
  28466. }
  28467. if (continuationNeeded)
  28468. {
  28469. qstart = msTick();
  28470. time(&startTime);
  28471. }
  28472. unknownQueryStats.noteActive();
  28473. atomic_inc(&queryCount);
  28474. }
  28475. catch (IException * E)
  28476. {
  28477. if (traceLevel > 0)
  28478. {
  28479. StringBuffer b;
  28480. DBGLOG("Error reading query from socket: %s", E->errorMessage(b).str());
  28481. }
  28482. E->Release();
  28483. client.clear();
  28484. return;
  28485. }
  28486. bool isXml = true;
  28487. bool isRaw = false;
  28488. bool isHTTP = httpHelper.isHttp();
  28489. bool isBlocked = false;
  28490. bool trim = false;
  28491. bool failed = false;
  28492. Owned<IPropertyTree> queryXml;
  28493. Owned<IQueryFactory> queryFactory;
  28494. StringBuffer sanitizedText;
  28495. StringAttr queryName;
  28496. StringBuffer peerStr;
  28497. peer.getIpText(peerStr);
  28498. const char *uid = "-";
  28499. unsigned instanceId = getNextInstanceId();
  28500. StringBuffer ctxstr;
  28501. Owned<StringContextLogger> _logctx = new StringContextLogger(ep.getIpText(ctxstr).appendf(":%u{%u}", ep.port, instanceId).str());
  28502. StringContextLogger &logctx = *_logctx.get();
  28503. try
  28504. {
  28505. // Note - control queries have to be formatted without spaces..
  28506. if (strnicmp(rawText.str(), "<control:lock", 13)==0 && !isalpha(rawText.charAt(13)))
  28507. {
  28508. if (logctx.queryTraceLevel() > 8)
  28509. logctx.CTXLOG("Got lock request %s", rawText.str());
  28510. FlushingStringBuffer response(client, false, true, false, false, logctx);
  28511. response.startDataset("Control", NULL, (unsigned) -1);
  28512. if (!cascade)
  28513. cascade.setown(new CascadeManager(logctx));
  28514. StringBuffer s;
  28515. cascade->doLockGlobal(s, false);
  28516. response.append(s);
  28517. if (logctx.queryTraceLevel() > 8)
  28518. logctx.CTXLOG("lock reply %s", s.str());
  28519. response.flush(true);
  28520. unsigned replyLen = 0;
  28521. client->write(&replyLen, sizeof(replyLen));
  28522. rawText.clear();
  28523. goto readAnother;
  28524. }
  28525. else if (strnicmp(rawText.str(), "<control:childlock", 18)==0 && !isalpha(rawText.charAt(18)))
  28526. {
  28527. if (logctx.queryTraceLevel() > 8)
  28528. logctx.CTXLOG("Got childlock request %s", rawText.str());
  28529. FlushingStringBuffer response(client, false, true, false, false, logctx);
  28530. response.startDataset("Control", NULL, (unsigned) -1);
  28531. if (!cascade)
  28532. cascade.setown(new CascadeManager(logctx));
  28533. StringBuffer s;
  28534. cascade->doLockChild(rawText.str(), s);
  28535. response.append(s);
  28536. if (logctx.queryTraceLevel() > 8)
  28537. logctx.CTXLOG("childlock reply %s", s.str());
  28538. response.flush(true);
  28539. unsigned replyLen = 0;
  28540. client->write(&replyLen, sizeof(replyLen));
  28541. rawText.clear();
  28542. unknownQueryStats.noteComplete();
  28543. goto readAnother;
  28544. }
  28545. else if (strnicmp(rawText.str(), "<control:", 9)==0)
  28546. {
  28547. Owned<IPropertyTree> queryXML = createPTreeFromXMLString(rawText.str()); // This is just done to check it is valid XML and make error reporting better...
  28548. queryXML.clear();
  28549. bool doControlQuery = true;
  28550. FlushingStringBuffer response(client, false, true, false, isHTTP, logctx);
  28551. response.startDataset("Control", NULL, (unsigned) -1);
  28552. if (strnicmp(rawText.str(), "<control:aclupdate", 18)==0 && !isalpha(rawText.charAt(18)))
  28553. {
  28554. queryXml.setown(createPTreeFromXMLString(rawText.str(), ipt_caseInsensitive, (XmlReaderOptions)(xr_ignoreWhiteSpace|xr_ignoreNameSpaces)));
  28555. IPropertyTree *aclTree = queryXml->queryPropTree("ACL");
  28556. if (aclTree)
  28557. {
  28558. Owned<IPropertyTreeIterator> accesses = aclTree->getElements("Access");
  28559. ForEach(*accesses)
  28560. {
  28561. IPropertyTree &access = accesses->query();
  28562. try
  28563. {
  28564. pool->addAccess(access.getPropBool("@allow", true), access.getPropBool("@allowBlind", true), access.queryProp("@ip"), access.queryProp("@mask"), access.queryProp("@query"), access.queryProp("@error"), access.getPropInt("@errorCode", -1));
  28565. }
  28566. catch (IException *E)
  28567. {
  28568. StringBuffer s, x;
  28569. E->errorMessage(s);
  28570. E->Release();
  28571. toXML(&access, x, 0, 0);
  28572. throw MakeStringException(ROXIE_ACL_ERROR, "Error in access statement %s: %s", x.str(), s.str());
  28573. }
  28574. }
  28575. }
  28576. }
  28577. else if (strnicmp(rawText.str(), "<control:queryaclinfo", 21)==0 && !isalpha(rawText.charAt(21)))
  28578. {
  28579. StringBuffer info;
  28580. info.append("<Endpoint ep='");
  28581. ep.getUrlStr(info);
  28582. info.append("'>\n");
  28583. pool->queryAccessInfo(info);
  28584. info.append("</Endpoint>\n");
  28585. response.append(info.str());
  28586. doControlQuery = false;
  28587. }
  28588. if (doControlQuery)
  28589. {
  28590. if(!cascade)
  28591. cascade.setown(new CascadeManager(logctx));
  28592. StringBuffer s;
  28593. cascade->doControlQuery(ep, rawText, s);
  28594. response.append(s);
  28595. }
  28596. }
  28597. else if (isStatus)
  28598. {
  28599. client->write("OK", 2);
  28600. }
  28601. else
  28602. {
  28603. try
  28604. {
  28605. queryXml.setown(createPTreeFromXMLString(rawText.str(), ipt_caseInsensitive, (XmlReaderOptions)(defaultXmlReadFlags | xr_ignoreNameSpaces)));
  28606. }
  28607. catch (IException *E)
  28608. {
  28609. logctx.logOperatorException(E, __FILE__, __LINE__, "Invalid XML received from %s:%d - %s", peerStr.str(), pool->queryPort(), rawText.str());
  28610. logctx.CTXLOG("ERROR: Invalid XML received from %s:%d - %s", peerStr.str(), pool->queryPort(), rawText.str());
  28611. throw;
  28612. }
  28613. bool isRequest = false;
  28614. bool isRequestArray = false;
  28615. bool isBlind = false;
  28616. bool isDebug = false;
  28617. sanitizeQuery(queryXml, queryName, sanitizedText, isHTTP, uid, isRequest, isRequestArray, isBlind, isDebug);
  28618. pool->checkAccess(peer, queryName, sanitizedText, isBlind);
  28619. if (isDebug)
  28620. {
  28621. if (!debugPermitted || !ownEP.port)
  28622. throw MakeStringException(ROXIE_ACCESS_ERROR, "Debug queries are not permitted on this system");
  28623. }
  28624. isBlind = isBlind || blindLogging;
  28625. logctx.setBlind(isBlind);
  28626. if (logFullQueries)
  28627. {
  28628. StringBuffer soapStr;
  28629. (isRequest) ? soapStr.append("SoapRequest") : (isRequestArray) ? soapStr.append("SoapRequest") : soapStr.clear();
  28630. logctx.CTXLOG("%s %s:%d %s %s %s", isBlind ? "BLIND:" : "QUERY:", peerStr.str(), pool->queryPort(), uid, soapStr.str(), sanitizedText.str());
  28631. }
  28632. if (strnicmp(rawText.str(), "<debug:", 7)==0)
  28633. {
  28634. if (!debugPermitted || !ownEP.port)
  28635. throw MakeStringException(ROXIE_ACCESS_ERROR, "Debug queries are not permitted on this system");
  28636. if (!debuggerContext)
  28637. {
  28638. if (!uid)
  28639. #ifdef _DEBUG
  28640. uid="*";
  28641. #else
  28642. throw MakeStringException(ROXIE_DEBUG_ERROR, "Debug id not specified");
  28643. #endif
  28644. Owned<IRoxieDebugSessionManager> QM = globalPackageSetManager->getRoxieDebugSessionManager();
  28645. debuggerContext.setown(QM->lookupDebuggerContext(uid));
  28646. if (!debuggerContext)
  28647. throw MakeStringException(ROXIE_DEBUG_ERROR, "No active query matching context %s found", uid);
  28648. if (!debugCmdHandler.get())
  28649. debugCmdHandler.setown(new CDebugCommandHandler);
  28650. }
  28651. FlushingStringBuffer response(client, false, true, false, isHTTP, logctx);
  28652. response.startDataset("Debug", NULL, (unsigned) -1);
  28653. debugCmdHandler->doDebugCommand(queryXml, debuggerContext, response);
  28654. }
  28655. else
  28656. {
  28657. ActiveQueryLimiter l(pool);
  28658. if (!l.accepted)
  28659. {
  28660. if (isHTTP)
  28661. {
  28662. sendHttpServerTooBusy(*client, logctx);
  28663. logctx.CTXLOG("FAILED: %s", sanitizedText.str());
  28664. logctx.CTXLOG("EXCEPTION: Too many active queries");
  28665. }
  28666. else
  28667. {
  28668. IException *e = MakeStringException(ROXIE_TOO_MANY_QUERIES, "Too many active queries");
  28669. if (trapTooManyActiveQueries)
  28670. logctx.logOperatorException(e, __FILE__, __LINE__, NULL);
  28671. throw e;
  28672. }
  28673. }
  28674. else
  28675. {
  28676. queryFactory.setown(globalPackageSetManager->getQuery(queryName, logctx));
  28677. if (isHTTP)
  28678. client->setHttpMode(queryName, isRequestArray);
  28679. if (queryFactory)
  28680. {
  28681. bool stripWhitespace = queryFactory->getDebugValueBool("stripWhitespaceFromStoredDataset", 0 != (xr_ignoreWhiteSpace & defaultXmlReadFlags));
  28682. stripWhitespace = queryXml->getPropBool("_stripWhitespaceFromStoredDataset", stripWhitespace);
  28683. XmlReaderOptions xmlReadFlags = (XmlReaderOptions)((defaultXmlReadFlags & ~xr_ignoreWhiteSpace) |
  28684. (stripWhitespace ? xr_ignoreWhiteSpace : xr_none));
  28685. if (xmlReadFlags != defaultXmlReadFlags)
  28686. {
  28687. // we need to reparse input xml, as global whitespace setting has been overridden
  28688. queryXml.setown(createPTreeFromXMLString(rawText.str(), ipt_caseInsensitive, (XmlReaderOptions)(xmlReadFlags|xr_ignoreNameSpaces)));
  28689. sanitizeQuery(queryXml, queryName, sanitizedText, isHTTP, uid, isRequest, isRequestArray, isBlind, isDebug);
  28690. }
  28691. IArrayOf<IPropertyTree> requestArray;
  28692. if (isHTTP)
  28693. {
  28694. if (isRequestArray)
  28695. {
  28696. StringBuffer reqIterString;
  28697. reqIterString.append(queryName).append("Request");
  28698. Owned<IPropertyTreeIterator> reqIter = queryXml->getElements(reqIterString.str());
  28699. ForEach(*reqIter)
  28700. {
  28701. IPropertyTree *fixedreq = createPTree(queryName, ipt_caseInsensitive);
  28702. Owned<IPropertyTreeIterator> iter = reqIter->query().getElements("*");
  28703. ForEach(*iter)
  28704. {
  28705. fixedreq->addPropTree(iter->query().queryName(), LINK(&iter->query()));
  28706. }
  28707. requestArray.append(*fixedreq);
  28708. }
  28709. }
  28710. else
  28711. {
  28712. IPropertyTree *fixedreq = createPTree(queryName, ipt_caseInsensitive);
  28713. Owned<IPropertyTreeIterator> iter = queryXml->getElements("*");
  28714. ForEach(*iter)
  28715. {
  28716. fixedreq->addPropTree(iter->query().queryName(), LINK(&iter->query()));
  28717. }
  28718. requestArray.append(*fixedreq);
  28719. }
  28720. trim = true;
  28721. }
  28722. else
  28723. {
  28724. const char *format = queryXml->queryProp("@format");
  28725. if (format)
  28726. {
  28727. if (stricmp(format, "raw") == 0)
  28728. {
  28729. isRaw = true;
  28730. isXml = false;
  28731. isBlocked = (client != NULL);
  28732. }
  28733. else if (stricmp(format, "bxml") == 0)
  28734. {
  28735. isBlocked = true;
  28736. }
  28737. else if (stricmp(format, "ascii") == 0)
  28738. {
  28739. isRaw = false;
  28740. isXml = false;
  28741. }
  28742. else if (stricmp(format, "xml") != 0) // xml is the default
  28743. throw MakeStringException(ROXIE_INVALID_INPUT, "Unsupported format specified: %s", format);
  28744. }
  28745. trim = queryXml->getPropBool("@trim", false);;
  28746. logctx.setIntercept(queryXml->getPropBool("@log", false));
  28747. logctx.setTraceLevel(queryXml->getPropInt("@traceLevel", traceLevel));
  28748. }
  28749. priority = queryFactory->getPriority();
  28750. switch (priority)
  28751. {
  28752. case 0: loQueryStats.noteActive(); break;
  28753. case 1: hiQueryStats.noteActive(); break;
  28754. case 2: slaQueryStats.noteActive(); break;
  28755. }
  28756. unknownQueryStats.noteComplete();
  28757. if (isHTTP)
  28758. {
  28759. CSoapRequestAsyncFor af(queryName, queryFactory, requestArray, *client, httpHelper, memused, slavesReplyLen, sanitizedText, logctx, xmlReadFlags);
  28760. af.For(requestArray.length(), numRequestArrayThreads);
  28761. }
  28762. else
  28763. {
  28764. Owned<IRoxieServerContext> ctx = queryFactory->createContext(queryXml, *client, isXml, isRaw, isBlocked, httpHelper, trim, logctx, xmlReadFlags);
  28765. if (client && !ctx->outputResultsToSocket())
  28766. {
  28767. unsigned replyLen = 0;
  28768. client->write(&replyLen, sizeof(replyLen));
  28769. client.clear();
  28770. }
  28771. try
  28772. {
  28773. ctx->process();
  28774. memused = ctx->getMemoryUsage();
  28775. slavesReplyLen = ctx->getSlavesReplyLen();
  28776. ctx->done(false);
  28777. }
  28778. catch(...)
  28779. {
  28780. memused = ctx->getMemoryUsage();
  28781. slavesReplyLen = ctx->getSlavesReplyLen();
  28782. ctx->done(true);
  28783. throw;
  28784. }
  28785. }
  28786. }
  28787. else
  28788. {
  28789. pool->reportBadQuery(queryName.get(), logctx);
  28790. throw MakeStringException(ROXIE_UNKNOWN_QUERY, "Unknown query %s", queryName.get());
  28791. }
  28792. }
  28793. }
  28794. }
  28795. }
  28796. catch (WorkflowException * E)
  28797. {
  28798. failed = true;
  28799. logctx.CTXLOG("FAILED: %s", sanitizedText.str());
  28800. StringBuffer error;
  28801. E->errorMessage(error);
  28802. logctx.CTXLOG("EXCEPTION: %s", error.str());
  28803. unsigned code = E->errorCode();
  28804. if (QUERYINTERFACE(E, ISEH_Exception))
  28805. code = ROXIE_INTERNAL_ERROR;
  28806. else if (QUERYINTERFACE(E, IOutOfMemException))
  28807. code = ROXIE_MEMORY_ERROR;
  28808. if (client)
  28809. {
  28810. if (isHTTP)
  28811. sendSoapException(*client, E, queryName);
  28812. else
  28813. client->sendException("Roxie", code, error.str(), isBlocked, logctx);
  28814. }
  28815. else
  28816. {
  28817. fprintf(stderr, "EXCEPTION: %s", error.str());
  28818. }
  28819. E->Release();
  28820. }
  28821. catch (IException * E)
  28822. {
  28823. failed = true;
  28824. logctx.CTXLOG("FAILED: %s", sanitizedText.str());
  28825. StringBuffer error;
  28826. E->errorMessage(error);
  28827. logctx.CTXLOG("EXCEPTION: %s", error.str());
  28828. unsigned code = E->errorCode();
  28829. if (QUERYINTERFACE(E, ISEH_Exception))
  28830. code = ROXIE_INTERNAL_ERROR;
  28831. else if (QUERYINTERFACE(E, IOutOfMemException))
  28832. code = ROXIE_MEMORY_ERROR;
  28833. if (client)
  28834. {
  28835. if (isHTTP)
  28836. sendSoapException(*client, E, queryName);
  28837. else
  28838. client->sendException("Roxie", code, error.str(), isBlocked, logctx);
  28839. }
  28840. else
  28841. {
  28842. fprintf(stderr, "EXCEPTION: %s", error.str());
  28843. }
  28844. E->Release();
  28845. }
  28846. #ifndef _DEBUG
  28847. catch(...)
  28848. {
  28849. failed = true;
  28850. logctx.CTXLOG("FAILED: %s", sanitizedText.str());
  28851. logctx.CTXLOG("EXCEPTION: Unknown exception");
  28852. {
  28853. if (isHTTP)
  28854. {
  28855. Owned<IException> E = MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown exception");
  28856. sendSoapException(*client, E, queryName);
  28857. }
  28858. else
  28859. client->sendException("Roxie", ROXIE_INTERNAL_ERROR, "Unknown exception", isBlocked, logctx);
  28860. }
  28861. }
  28862. #endif
  28863. if (isHTTP)
  28864. {
  28865. try
  28866. {
  28867. client->flush();
  28868. }
  28869. catch (IException * E)
  28870. {
  28871. StringBuffer error("RoxieSocketWorker failed to write to socket ");
  28872. E->errorMessage(error);
  28873. logctx.CTXLOG("%s", error.str());
  28874. E->Release();
  28875. }
  28876. //#ifndef _DEBUG
  28877. catch(...)
  28878. {
  28879. logctx.CTXLOG("RoxieSocketWorker failed to write to socket (Unknown exception)");
  28880. }
  28881. //#endif
  28882. }
  28883. unsigned bytesOut = client? client->bytesOut() : 0;
  28884. unsigned elapsed = msTick() - qstart;
  28885. noteQuery(failed, elapsed, priority);
  28886. if (queryFactory)
  28887. {
  28888. queryFactory->noteQuery(startTime, failed, elapsed, memused, slavesReplyLen, bytesOut);
  28889. queryFactory.clear();
  28890. }
  28891. if (logctx.queryTraceLevel() > 2)
  28892. logctx.dumpStats();
  28893. if (logctx.queryTraceLevel() && (logctx.queryTraceLevel() > 2 || logFullQueries || logctx.intercept))
  28894. if (queryName.get())
  28895. logctx.CTXLOG("COMPLETE: %s %s from %s complete in %d msecs memory %d Mb priority %d slavesreply %d resultsize %d continue %d", queryName.get(), uid, peerStr.str(), elapsed, memused, priority, slavesReplyLen, bytesOut, continuationNeeded);
  28896. if (continuationNeeded)
  28897. {
  28898. rawText.clear();
  28899. goto readAnother;
  28900. }
  28901. else
  28902. {
  28903. logctx.flush(true, false);
  28904. try
  28905. {
  28906. if (client && !isHTTP && !isStatus)
  28907. {
  28908. if (logctx.intercept)
  28909. {
  28910. FlushingStringBuffer response(client, isBlocked, isXml, isRaw, false, logctx);
  28911. response.startDataset("Tracing", NULL, (unsigned) -1);
  28912. logctx.outputXML(response);
  28913. }
  28914. unsigned replyLen = 0;
  28915. client->write(&replyLen, sizeof(replyLen));
  28916. }
  28917. client.clear();
  28918. }
  28919. catch (IException * E)
  28920. {
  28921. StringBuffer error("RoxieSocketWorker failed to close socket ");
  28922. E->errorMessage(error);
  28923. logctx.CTXLOG("%s", error.str()); // MORE - audience?
  28924. E->Release();
  28925. }
  28926. //#ifndef _DEBUG
  28927. catch(...)
  28928. {
  28929. logctx.CTXLOG("RoxieSocketWorker failed to close socket (Unknown exception)"); // MORE - audience?
  28930. }
  28931. //#endif
  28932. }
  28933. }
  28934. };
  28935. //=================================================================================
  28936. IArrayOf<IRoxieListener> socketListeners;
  28937. IPooledThread *RoxieWorkUnitListener::createNew()
  28938. {
  28939. return new RoxieWorkUnitWorker(this);
  28940. }
  28941. IPooledThread *RoxieSocketListener::createNew()
  28942. {
  28943. return new RoxieSocketWorker(this, ep);
  28944. }
  28945. void RoxieSocketListener::runOnce(const char *query)
  28946. {
  28947. Owned<RoxieSocketWorker> p = new RoxieSocketWorker(this, ep);
  28948. p->runOnce(query);
  28949. }
  28950. IRoxieListener *createRoxieSocketListener(unsigned port, unsigned poolSize, unsigned listenQueue, bool suspended)
  28951. {
  28952. if (traceLevel)
  28953. DBGLOG("Creating Roxie socket listener, pool size %d, listen queue %d%s", poolSize, listenQueue, suspended?" SUSPENDED":"");
  28954. return new RoxieSocketListener(port, poolSize, listenQueue, suspended);
  28955. }
  28956. IRoxieListener *createRoxieWorkUnitListener(unsigned poolSize, bool suspended)
  28957. {
  28958. if (traceLevel)
  28959. DBGLOG("Creating Roxie workunit listener, pool size %d%s", poolSize, suspended?" SUSPENDED":"");
  28960. return new RoxieWorkUnitListener(poolSize, suspended);
  28961. }
  28962. bool suspendRoxieListener(unsigned port, bool suspended)
  28963. {
  28964. ForEachItemIn(idx, socketListeners)
  28965. {
  28966. IRoxieListener &listener = socketListeners.item(idx);
  28967. if (listener.queryPort()==port)
  28968. return listener.suspend(suspended);
  28969. }
  28970. throw MakeStringException(ROXIE_INTERNAL_ERROR, "Unknown port %u specified in suspendRoxieListener", port);
  28971. }
  28972. //================================================================================================================================
  28973. #ifdef _USE_CPPUNIT
  28974. // There is a bug in VC6 implemetation of protected which prevents nested classes from accessing owner's data. It can be tricky to work around - hence...
  28975. #if _MSC_VER==1200
  28976. #undef protected
  28977. #endif
  28978. #include <cppunit/extensions/HelperMacros.h>
  28979. #define ASSERT(a) { if (!(a)) CPPUNIT_ASSERT(a); }
  28980. static const char *sortAlgorithm;
  28981. class TestMetaData : public CInterface, implements IOutputMetaData
  28982. {
  28983. public:
  28984. IMPLEMENT_IINTERFACE;
  28985. virtual size32_t getRecordSize(const void *) { return 10; }
  28986. virtual size32_t getMinRecordSize() const { return 10; }
  28987. virtual size32_t getFixedSize() const { return 10; }
  28988. virtual void toXML(const byte * self, IXmlWriter & out) {}
  28989. virtual unsigned getVersion() const { return OUTPUTMETADATA_VERSION; }
  28990. virtual unsigned getMetaFlags() { return 0; }
  28991. virtual void destruct(byte * self) {}
  28992. virtual IOutputRowSerializer * createRowSerializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  28993. virtual IOutputRowDeserializer * createRowDeserializer(ICodeContext * ctx, unsigned activityId) { return NULL; }
  28994. virtual ISourceRowPrefetcher * createRowPrefetcher(ICodeContext * ctx, unsigned activityId) { return NULL; }
  28995. virtual IOutputMetaData * querySerializedMeta() { return NULL; }
  28996. virtual void walkIndirectMembers(const byte * self, IIndirectMemberVisitor & visitor) {}
  28997. } testMeta;
  28998. class TestInput : public CInterface, implements IRoxieInput
  28999. {
  29000. char const * const *input;
  29001. IRoxieSlaveContext *ctx;
  29002. unsigned endSeen;
  29003. bool eof;
  29004. unsigned count;
  29005. unsigned __int64 totalCycles;
  29006. size32_t recordSize;
  29007. unsigned activityId;
  29008. public:
  29009. enum { STATEreset, STATEstarted, STATEstopped } state;
  29010. bool allRead;
  29011. IMPLEMENT_IINTERFACE;
  29012. TestInput(IRoxieSlaveContext *_ctx, char const * const *_input)
  29013. {
  29014. ctx = _ctx;
  29015. input = _input;
  29016. count = 0;
  29017. eof = false;
  29018. allRead = false;
  29019. endSeen = 0;
  29020. recordSize = testMeta.getFixedSize();
  29021. state = STATEreset;
  29022. totalCycles = 0;
  29023. activityId = 1;
  29024. }
  29025. virtual IOutputMetaData * queryOutputMeta() const { return &testMeta; }
  29026. virtual void prestart(unsigned parentExtractSize, const byte *parentExtract)
  29027. {
  29028. ASSERT(state == STATEreset);
  29029. }
  29030. virtual void start(unsigned parentExtractSize, const byte *parentExtract, bool paused)
  29031. {
  29032. ASSERT(state == STATEreset);
  29033. state = STATEstarted;
  29034. }
  29035. virtual IRoxieServerActivity *queryActivity()
  29036. {
  29037. throwUnexpected();
  29038. }
  29039. virtual IIndexReadActivityInfo *queryIndexReadActivity()
  29040. {
  29041. throwUnexpected();
  29042. }
  29043. virtual void stop(bool aborting)
  29044. {
  29045. state = STATEstopped;
  29046. }
  29047. virtual void reset()
  29048. {
  29049. ASSERT(state == STATEstopped);
  29050. eof = false; count = 0; endSeen = 0; allRead = false; state = STATEreset; totalCycles = 0;
  29051. }
  29052. virtual void resetEOF()
  29053. {
  29054. throwUnexpected();
  29055. }
  29056. virtual void checkAbort() {}
  29057. virtual unsigned queryId() const { return activityId; };
  29058. virtual const void *nextInGroup()
  29059. {
  29060. ActivityTimer t(totalCycles, timeActivities, ctx->queryDebugContext());
  29061. ASSERT(state == STATEstarted);
  29062. ASSERT(allRead || !eof);
  29063. if (eof)
  29064. return NULL;
  29065. const char *nextSource = input[count++];
  29066. if (nextSource)
  29067. {
  29068. endSeen = 0;
  29069. void *ret = ctx->queryRowManager().ALLOCATE(recordSize);
  29070. memset(ret, 0, recordSize);
  29071. strncpy((char *) ret, nextSource, recordSize);
  29072. return ret;
  29073. }
  29074. else
  29075. {
  29076. endSeen++;
  29077. if (endSeen==2)
  29078. eof = true;
  29079. return NULL;
  29080. }
  29081. }
  29082. virtual bool nextGroup(ConstPointerArray & group)
  29083. {
  29084. const void * next;
  29085. while ((next = nextInGroup()) != NULL)
  29086. group.append(next);
  29087. if (group.ordinality())
  29088. return true;
  29089. return false;
  29090. }
  29091. virtual unsigned __int64 queryTotalCycles() const { return totalCycles; }
  29092. virtual unsigned __int64 queryLocalCycles() const { return totalCycles; }
  29093. virtual IRoxieInput *queryInput(unsigned idx) const
  29094. {
  29095. return NULL;
  29096. }
  29097. };
  29098. struct SortActivityTest : public ccdserver_hqlhelper::CThorSortArg {
  29099. public:
  29100. struct CompareClass : public ICompare {
  29101. virtual int docompare(const void * _left, const void * _right) const {
  29102. return memcmp(_left, _right, 5);
  29103. }
  29104. } compare;
  29105. virtual ICompare * queryCompare() { return &compare; }
  29106. virtual IOutputMetaData * queryOutputMeta()
  29107. {
  29108. return &testMeta;
  29109. }
  29110. virtual unsigned getAlgorithmFlags() { return TAFunstable; }
  29111. virtual const char * queryAlgorithm() { return sortAlgorithm; }
  29112. };
  29113. extern "C" IHThorArg * sortActivityTestFactory() { return new SortActivityTest; }
  29114. struct MergeActivityTest : public ccdserver_hqlhelper::CThorMergeArg {
  29115. static bool isDedup;
  29116. public:
  29117. struct CompareClass : public ICompare {
  29118. virtual int docompare(const void * _left, const void * _right) const {
  29119. return memcmp(_left, _right, 5);
  29120. }
  29121. } compare;
  29122. virtual ICompare * queryCompare() { return &compare; }
  29123. virtual IOutputMetaData * queryOutputMeta()
  29124. {
  29125. return &testMeta;
  29126. }
  29127. virtual bool dedup() { return isDedup; }
  29128. };
  29129. bool MergeActivityTest::isDedup = false;
  29130. extern "C" IHThorArg * mergeActivityTestFactory() { return new MergeActivityTest; }
  29131. struct PrefetchProjectActivityTest : public ccdserver_hqlhelper::CThorPrefetchProjectArg {
  29132. virtual IOutputMetaData * queryOutputMeta()
  29133. {
  29134. return &testMeta;
  29135. }
  29136. virtual void onCreate(ICodeContext * _ctx, IHThorArg *, MemoryBuffer * in) {
  29137. ctx = _ctx;
  29138. child8.setown(ctx->resolveChildQuery(8,this));
  29139. }
  29140. // mutable rtlRowBuilder ex39R4;
  29141. Owned<IThorChildGraph> child8;
  29142. virtual IThorChildGraph *queryChild() { return child8; }
  29143. virtual bool preTransform(rtlRowBuilder & extract, const void * _left, unsigned __int64 count) {
  29144. const unsigned char * left = (const unsigned char *) _left;
  29145. extract.ensureAvailable(1);
  29146. memcpy((char *)(extract.getbytes() + 0),(char *)(left + 0),1);
  29147. // child8->execute(5,ex39R4.getbytes());
  29148. return true;
  29149. }
  29150. virtual size32_t transform(ARowBuilder & _self, const void * _left, IEclGraphResults * results, unsigned __int64 count) {
  29151. unsigned char * self = (unsigned char *) _self.getSelf();
  29152. const unsigned char * left = (const unsigned char *) _left;
  29153. memcpy((char *)(self + 0),(char *)(left + 0),10);
  29154. rtlDataAttr v79R4;
  29155. unsigned int v89R4;
  29156. results->getResult(v89R4,v79R4.refdata(),0);
  29157. memcpy(self + count - 1, ((unsigned char *)v79R4.getbytes() + count - 1), 1);
  29158. return 10;
  29159. }
  29160. };
  29161. extern "C" IHThorArg * prefetchProjectActivityTestFactory() { return new PrefetchProjectActivityTest; }
  29162. struct TempTableActivityTest : public ccdserver_hqlhelper::CThorTempTableArg {
  29163. virtual IOutputMetaData * queryOutputMeta()
  29164. {
  29165. return &testMeta;
  29166. }
  29167. virtual size32_t getRow(ARowBuilder & _self, unsigned row) {
  29168. unsigned char * self = (unsigned char *) _self.getSelf();
  29169. switch (row) {
  29170. case 0: {
  29171. memcpy((char *)(self + 0),"1234567890",10);
  29172. return 10;
  29173. }
  29174. }
  29175. return 0;
  29176. }
  29177. virtual unsigned numRows() {
  29178. return 1;
  29179. }
  29180. };
  29181. extern "C" IHThorArg * tempTableActivityTestFactory() { return new TempTableActivityTest; }
  29182. struct SelectNActivityTest : public ccdserver_hqlhelper::CThorSelectNArg {
  29183. virtual IOutputMetaData * queryOutputMeta()
  29184. {
  29185. return &testMeta;
  29186. }
  29187. virtual size32_t createDefault(ARowBuilder & _self) { memset(_self.getSelf(), ' ', 10); return 10; }
  29188. virtual unsigned __int64 getRowToSelect() { return 1; }
  29189. };
  29190. extern "C" IHThorArg * selectNActivityTestFactory() { return new SelectNActivityTest; }
  29191. struct LocalResultActivityTest : public ccdserver_hqlhelper::CThorLocalResultWriteArg {
  29192. virtual unsigned querySequence() { return 0; }
  29193. virtual bool usedOutsideGraph() { return true; }
  29194. };
  29195. extern "C" IHThorArg * localResultActivityTestFactory() { return new LocalResultActivityTest; }
  29196. class CcdServerTest : public CppUnit::TestFixture
  29197. {
  29198. CPPUNIT_TEST_SUITE(CcdServerTest);
  29199. CPPUNIT_TEST(testHeapSort);
  29200. CPPUNIT_TEST(testInsertionSort);
  29201. CPPUNIT_TEST(testQuickSort);
  29202. CPPUNIT_TEST(testMerge);
  29203. CPPUNIT_TEST(testMergeDedup);
  29204. CPPUNIT_TEST(testPrefetchProject);
  29205. CPPUNIT_TEST(testMiscellaneous);
  29206. CPPUNIT_TEST_SUITE_END();
  29207. protected:
  29208. SlaveContextLogger logctx;
  29209. Owned<const IQueryDll> queryDll;
  29210. Owned<IRoxiePackage> package;
  29211. Owned<IRoxieSlaveContext> ctx;
  29212. Owned<IQueryFactory> queryFactory;
  29213. void init()
  29214. {
  29215. static bool heapInitialized = false;
  29216. if (!heapInitialized)
  29217. {
  29218. roxiemem::setTotalMemoryLimit(100 * 1024 * 1024, 0, NULL);
  29219. heapInitialized = true;
  29220. }
  29221. package.setown(createPackage(NULL));
  29222. ctx.setown(createSlaveContext(NULL, logctx, 0, 50*1024*1024, NULL));
  29223. queryDll.setown(createExeQueryDll("roxie"));
  29224. queryFactory.setown(createServerQueryFactory("test", queryDll.getLink(), *package, NULL));
  29225. timer->reset();
  29226. }
  29227. void testActivity(IRoxieServerActivity *activity, char const * const *input, char const * const *output)
  29228. {
  29229. testActivity(activity, input, NULL, output);
  29230. }
  29231. void testActivity(IRoxieServerActivity *activity, char const * const *input, char const * const *input2, char const * const *output)
  29232. {
  29233. TestInput in(ctx, input);
  29234. TestInput in2(ctx, input2);
  29235. IRoxieInput *out = activity->queryOutput(0);
  29236. IOutputMetaData *meta = out->queryOutputMeta();
  29237. activity->setInput(0, &in);
  29238. if (input2)
  29239. activity->setInput(1, &in2);
  29240. void *buf = alloca(meta->getFixedSize());
  29241. for (unsigned iteration = 0; iteration < 8; iteration++)
  29242. {
  29243. // All activities should be able to be restarted multiple times in the same context (for child queries) or in a new context (for graph pooling, if we ever wanted it)
  29244. // This should be true whether we read all, some, or none of the data.
  29245. // Should not matter if an activity is not started
  29246. if (iteration % 4 == 0)
  29247. activity->onCreate(ctx, NULL);
  29248. unsigned count = 0;
  29249. if (iteration % 4 != 3)
  29250. {
  29251. activity->start(0, NULL, false);
  29252. ASSERT(in.state == TestInput::STATEstarted);
  29253. ASSERT(!input2 || in2.state == TestInput::STATEstarted);
  29254. loop
  29255. {
  29256. const void *next = out->nextInGroup();
  29257. if (!next)
  29258. {
  29259. ASSERT(output[count++] == NULL);
  29260. next = out->nextInGroup();
  29261. if (!next)
  29262. {
  29263. ASSERT(output[count++] == NULL);
  29264. break;
  29265. }
  29266. }
  29267. ASSERT(output[count] != NULL);
  29268. unsigned outsize = meta->getRecordSize(next);
  29269. memset(buf, 0, outsize);
  29270. strncpy((char *) buf, output[count++], outsize);
  29271. ASSERT(memcmp(next, buf, outsize) == 0);
  29272. ReleaseRoxieRow(next);
  29273. if (iteration % 4 == 2)
  29274. break;
  29275. }
  29276. if (iteration % 4 != 2)
  29277. {
  29278. // Check that reading after end is harmless
  29279. in.allRead = true;
  29280. const void *next = out->nextInGroup();
  29281. ASSERT(next == NULL);
  29282. }
  29283. }
  29284. activity->stop(false);
  29285. ASSERT(in.state == TestInput::STATEstopped);
  29286. ASSERT(!input2 || in2.state == TestInput::STATEstopped);
  29287. activity->reset();
  29288. ASSERT(in.state == TestInput::STATEreset);
  29289. ASSERT(!input2 || in2.state == TestInput::STATEreset);
  29290. ctx->queryRowManager().reportLeaks();
  29291. ASSERT(ctx->queryRowManager().numPagesAfterCleanup(true) == 0);
  29292. }
  29293. }
  29294. static int compareFunc(const void *l, const void *r)
  29295. {
  29296. return strcmp(*(char **) l, *(char **) r);
  29297. }
  29298. void testSort(unsigned type)
  29299. {
  29300. init();
  29301. sortAlgorithm = NULL;
  29302. if (type==2)
  29303. sortAlgorithm = "heapSort";
  29304. else if (type == 1)
  29305. sortAlgorithm = "insertionSort";
  29306. else
  29307. sortAlgorithm = "quickSort";
  29308. DBGLOG("Testing %s activity", sortAlgorithm);
  29309. Owned <IRoxieServerActivityFactory> factory = createRoxieServerSortActivityFactory(1, 1, *queryFactory, sortActivityTestFactory, TAKsort);
  29310. Owned <IRoxieServerActivity> activity = factory->createActivity(NULL);
  29311. const char * test[] = { NULL, NULL };
  29312. const char * test12345[] = { "1", "2", "3", "4", "5", NULL, NULL };
  29313. const char * test54321[] = { "5", "4", "3", "2", "1", NULL, NULL };
  29314. const char * test11111[] = { "1", "1", "1", "1", "1", NULL, NULL };
  29315. const char * test11111_12345[] = { "1", "1", "1", "1", "1", NULL, "1", "2", "3", "4", "5", NULL, NULL };
  29316. const char * test11111_54321[] = { "1", "1", "1", "1", "1", NULL, "5", "4", "3", "2", "1", NULL, NULL };
  29317. const char * test54321_54321[] = { "5", "4", "3", "2", "1", NULL, "5", "4", "3", "2", "1", NULL, NULL };
  29318. const char * test12345_12345[] = { "1", "2", "3", "4", "5", NULL, "1", "2", "3", "4", "5", NULL, NULL };
  29319. testActivity(activity, test, test);
  29320. testActivity(activity, test12345, test12345);
  29321. testActivity(activity, test54321, test12345);
  29322. testActivity(activity, test11111, test11111);
  29323. testActivity(activity, test11111_12345, test11111_12345);
  29324. testActivity(activity, test11111_54321, test11111_12345);
  29325. testActivity(activity, test54321_54321, test12345_12345);
  29326. // A few larger tests
  29327. char *input[2002];
  29328. char *output[2002];
  29329. input[2000] = input[2001] = output[2000] = output[2001] = NULL;
  29330. unsigned i;
  29331. // identical
  29332. for (i=0; i<2000; i++)
  29333. {
  29334. input[i] = new char[11];
  29335. output[i] = new char[11];
  29336. sprintf(input[i], "1");
  29337. sprintf(output[i], "1");
  29338. }
  29339. testActivity(activity, input, output);
  29340. // Ascending
  29341. for (i=0; i<2000; i++)
  29342. {
  29343. sprintf(input[i], "%04d", i);
  29344. sprintf(output[i], "%04d", i);
  29345. }
  29346. testActivity(activity, input, output);
  29347. // Almost sorted
  29348. for (i=0; i<20; i++)
  29349. {
  29350. unsigned h = i*100;
  29351. sprintf(input[h], "%04d", 1900-h);
  29352. }
  29353. testActivity(activity, input, output);
  29354. // Descending
  29355. for (i=0; i<2000; i++)
  29356. {
  29357. sprintf(input[i], "%04d", 1999-i);
  29358. sprintf(output[i], "%04d", i);
  29359. }
  29360. testActivity(activity, input, output);
  29361. // Random
  29362. for (i=0; i<2000; i++)
  29363. {
  29364. unsigned r = rand() % 1500;
  29365. sprintf(input[i], "%04d", r);
  29366. sprintf(output[i], "%04d", r);
  29367. }
  29368. qsort(output, 2000, sizeof(output[0]), compareFunc);
  29369. testActivity(activity, input, output);
  29370. #if 0
  29371. // Random
  29372. #define BIGSORTSIZE 1000000
  29373. char **linput = new char*[BIGSORTSIZE +2];
  29374. char **loutput = new char *[BIGSORTSIZE+2];
  29375. linput[BIGSORTSIZE] = linput[BIGSORTSIZE+1] = loutput[BIGSORTSIZE] = loutput[BIGSORTSIZE+1] = NULL;
  29376. for (i=0; i<BIGSORTSIZE; i++)
  29377. {
  29378. unsigned r = rand() % 15000;
  29379. linput[i] = loutput[i] = new char[11];
  29380. sprintf(linput[i], "%04d", r);
  29381. }
  29382. qsort(loutput, BIGSORTSIZE, 4, compareFunc);
  29383. testActivity(activity, linput, loutput);
  29384. for (i=0; i<BIGSORTSIZE; i++)
  29385. {
  29386. delete [] linput[i];
  29387. }
  29388. delete [] linput;
  29389. delete [] loutput;
  29390. #endif
  29391. unsigned __int64 us = cycle_to_nanosec(factory->queryLocalCycles()/1000);
  29392. DBGLOG("Simple %s sorts: activity time %u.%u ms", type==2?"Heap" : (type==1 ? "Insertion" : "Quick"), (int)(us/1000), (int)(us%1000));
  29393. factory->resetNodeProgressInfo();
  29394. if (type)
  29395. {
  29396. // Other than quicksort, it's supposed to be stable. Let's check that it is
  29397. // All sort identical
  29398. for (i=0; i<2000; i++)
  29399. {
  29400. sprintf(input[i], "1 %d", i);
  29401. sprintf(output[i], "1 %d", i);
  29402. }
  29403. testActivity(activity, input, output);
  29404. // Already sorted
  29405. for (i=0; i<2000; i++)
  29406. {
  29407. sprintf(input[i], "%04d %d", i / 10, i);
  29408. sprintf(output[i], "%04d %d", i / 10, i);
  29409. }
  29410. testActivity(activity, input, output);
  29411. // Reverse order
  29412. for (i=0; i<2000; i++)
  29413. {
  29414. sprintf(input[i], "%04d %d", 199 - (i / 10), i%10);
  29415. sprintf(output[i], "%04d %d", i / 10, i%10);
  29416. }
  29417. testActivity(activity, input, output);
  29418. }
  29419. for (i=0; i<2000; i++)
  29420. {
  29421. delete [] input[i];
  29422. delete [] output[i];
  29423. }
  29424. DBGLOG("Finished testing %s sort", type==2?"Heap" : (type==1 ? "Insertion" : "Quick"));
  29425. }
  29426. void testQuickSort()
  29427. {
  29428. testSort(0);
  29429. }
  29430. void testInsertionSort()
  29431. {
  29432. testSort(1);
  29433. }
  29434. void testHeapSort()
  29435. {
  29436. testSort(2);
  29437. }
  29438. void testMerge()
  29439. {
  29440. DBGLOG("testMerge");
  29441. init();
  29442. Owned <IRoxieServerActivityFactory> factory = createRoxieServerMergeActivityFactory(1, 1, *queryFactory, mergeActivityTestFactory, TAKmerge);
  29443. factory->setInput(0,0,0);
  29444. factory->setInput(1,0,0);
  29445. Owned <IRoxieServerActivity> activity = factory->createActivity(NULL);
  29446. const char * test[] = { NULL, NULL };
  29447. const char * test12345[] = { "1", "2", "3", "4", "5", NULL, NULL };
  29448. const char * test1122334455[] = { "1", "1", "2", "2", "3", "3", "4", "4", "5", "5", NULL, NULL };
  29449. const char * test11111[] = { "1", "1", "1", "1", "1", NULL, NULL };
  29450. const char * test1111111111[] = { "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", NULL, NULL };
  29451. const char * test11111_12345[] = { "1", "1", "1", "1", "1", NULL, "1", "2", "3", "4", "5", NULL, NULL };
  29452. const char * test1111112345[] = { "1", "1", "1", "1", "1", "1", "2", "3", "4", "5", NULL, NULL };
  29453. const char * test11111111111122334455[] = { "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "2", "2", "3", "3", "4", "4", "5", "5", NULL, NULL };
  29454. testActivity(activity, test, test, test);
  29455. testActivity(activity, test12345, test, test12345);
  29456. testActivity(activity, test, test12345, test12345);
  29457. testActivity(activity, test12345, test12345, test1122334455);
  29458. testActivity(activity, test11111, test, test11111);
  29459. testActivity(activity, test, test11111, test11111);
  29460. testActivity(activity, test11111, test11111, test1111111111);
  29461. testActivity(activity, test11111_12345, test, test1111112345);
  29462. testActivity(activity, test11111_12345, test11111_12345, test11111111111122334455);
  29463. // Should really test WHICH side gets kept...
  29464. // Should test with more than 2 inputs...
  29465. DBGLOG("testMerge done");
  29466. }
  29467. void testMergeDedup()
  29468. {
  29469. DBGLOG("testMergeDedup");
  29470. init();
  29471. MergeActivityTest::isDedup = true;
  29472. Owned <IRoxieServerActivityFactory> factory = createRoxieServerMergeActivityFactory(1, 1, *queryFactory, mergeActivityTestFactory, TAKmerge);
  29473. factory->setInput(0,0,0);
  29474. factory->setInput(1,0,0);
  29475. Owned <IRoxieServerActivity> activity = factory->createActivity(NULL);
  29476. const char * test[] = { NULL, NULL };
  29477. const char * test12345[] = { "1", "2", "3", "4", "5", NULL, NULL };
  29478. const char * test11111[] = { "1", "1", "1", "1", "1", NULL, NULL };
  29479. const char * test11111_12345[] = { "1", "1", "1", "1", "1", NULL, "1", "2", "3", "4", "5", NULL, NULL };
  29480. const char * test1111112345[] = { "1", "1", "1", "1", "1", "1", "2", "3", "4", "5", NULL, NULL };
  29481. testActivity(activity, test11111, test, test11111); // No dedup within a stream
  29482. testActivity(activity, test11111, test11111, test11111); // No dedup within a stream
  29483. testActivity(activity, test, test11111, test11111);
  29484. testActivity(activity, test, test, test);
  29485. testActivity(activity, test12345, test, test12345);
  29486. testActivity(activity, test, test12345, test12345);
  29487. testActivity(activity, test12345, test12345, test12345);
  29488. testActivity(activity, test11111_12345, test, test1111112345);
  29489. testActivity(activity, test11111_12345, test11111_12345, test1111112345);
  29490. // Should really test WHICH side gets kept...
  29491. // Should test with more than 2 inputs...
  29492. DBGLOG("testMergeDedup done");
  29493. }
  29494. void testPrefetchProject()
  29495. {
  29496. DBGLOG("testPrefetchProject");
  29497. init();
  29498. Owned <IRoxieServerActivityFactory> factory = createRoxieServerPrefetchProjectActivityFactory(1, 1, *queryFactory, prefetchProjectActivityTestFactory, TAKprefetchproject);
  29499. Owned<ActivityArray> childGraph = new ActivityArray(false, false, false);
  29500. IRoxieServerActivityFactory *ttf = createRoxieServerTempTableActivityFactory(2, 1, *queryFactory, tempTableActivityTestFactory, TAKtemptable);
  29501. IRoxieServerActivityFactory *snf = createRoxieServerSelectNActivityFactory(3, 1, *queryFactory, selectNActivityTestFactory, TAKselectn);
  29502. IRoxieServerActivityFactory *lrf = createRoxieServerLocalResultWriteActivityFactory(4, 1, *queryFactory, localResultActivityTestFactory, TAKlocalresultwrite, 0, 8, true);
  29503. childGraph->append(*ttf);
  29504. childGraph->append(*snf);
  29505. snf->setInput(0,0,0);
  29506. childGraph->append(*lrf);
  29507. lrf->setInput(0,1,0);
  29508. factory->addChildQuery(8, childGraph.getLink());
  29509. factory->setInput(0,0,0);
  29510. Owned <IRoxieServerActivity> activity = factory->createActivity(NULL);
  29511. const char * test[] = { NULL, NULL };
  29512. const char * test1in[] = { "aaaaaaaaaa", "aaaaaaaaaa", "aaaaaaaaaa","aaaaaaaaaa", "aaaaaaaaaa", NULL, NULL };
  29513. const char * test1out[] = { "1aaaaaaaaa", "a2aaaaaaaa", "aa3aaaaaaa", "aaa4aaaaaa", "aaaa5aaaaa", NULL, NULL };
  29514. testActivity(activity, test1in, NULL, test1out);
  29515. testActivity(activity, test, NULL, test);
  29516. DBGLOG("testPrefetchProject done");
  29517. }
  29518. void testMiscellaneous()
  29519. {
  29520. DBGLOG("sizeof(CriticalSection)=%u", (unsigned) sizeof(CriticalSection));
  29521. DBGLOG("sizeof(SpinLock)=%u", (unsigned) sizeof(SpinLock));
  29522. DBGLOG("sizeof(CJoinGroup)=%u", (unsigned) sizeof(CJoinGroup));
  29523. ASSERT(sizeof(CJoinGroup) <= 120);
  29524. }
  29525. };
  29526. CPPUNIT_TEST_SUITE_REGISTRATION( CcdServerTest );
  29527. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( CcdServerTest, "CcdServerTest" );
  29528. #endif